091115

|


先週のMCFAJ最終戦筑波の写真です。ta-1さん、ありがとうございます。

これは予選出走。写真見るとやっぱり太ったかも。体重はこの時60kg。最悪で も58kgまでしないとだめかも。歳を追うごとに絞るのが辛くなる。身長は 173cm なので、56kg以上が標準体重なんだ。20あたりの頃から同じ身長だけど、 当時は体重50kg。あの頃は飯代を一日500円にして(これ、本当にキツい)ガス代 とタイヤ代にあててたからね〜。
レースやめてから後、ブクブク太って70kg越えた。これでも頑張って落とした んだ。
今日の体重は60kg。レース後の暴飲暴食をリカバリしました。

これは予選中。このビビッドな色合いが我ながら最高。

これは決勝中。肩のチェッカーの一番下のラインはない方がいいかも。

なんか自分のフォーム見るのも久しぶりだな。

ロガー続き。いつもなんとなくパパっと書いたコードになっていたのをちょっ と整理した。今回、スレッドのブロックに継続を使えるようにOSを変更した。 これを使ってみると、びっくりするほど書き易いの気付いた。スレッドとファ イバの合いの子のように組める。ので、状態遷移のあるスレッドが事の他書き やすい。とはいえ、使い所で、ファイバの方が確実にスイッチは速い。ファイ バなら呼出し先退避だけを退避して、継続の呼出し先退避を復帰するだけなの に対し、スレッドの継続だと、それに加えて待ち行列の走査、選択、そして全 部のレジスタの復帰がいる。さらにはスタックは巻き戻される(これがプログラミングにとても制限を課す)。
今のファイバではファイバそれぞれに局所記憶をスタックとしてもたせている。 これが空間的な制約をきつくしていて、そう簡単には使えなくなっている。こ れをファイバの局所記憶は16byte程度にして、実行時のスタック切り替えにで きないかと思っている。それにはfiber_yieldがスタックの底近くで呼ばれるこ とが前提で、想定される使い方において、なんとかなりそうだ。
OSの領域から自由自在に設計、実装できるというのは、桃源郷を自ら作るあげ る幸せ感がある。
スレッドの継続があることでこんな感じにすることができた。
これはルートのスレッドから呼ばれます。
thread_t
data_init ()
{
  thread_t th;
スタックなしで(スタックはスケジューリング時に割当てられる)スレッドを作成
  th = thread_create_no_stack (&data_tc, "data", data_thread, 0);
  thread_start (th);

準備完了まで待ちます。
  while (!data_thread_ready)
    thread_block (NULL);継続をNULLとしているので起こされた時はここから。

  return th;
}

void
data_thread (uint32_t arg __attribute__((unused)))
{
  data_th = current_thread;

  pin_init_speed ();
  pin_init_plap ();

  *VICIntSelect &= ~VIC_EINT3;	// IRQ
  *VICIntEnable |= VIC_EINT3;

  // Logger timer. Free count. 1msec.
  __timer_config (TIMER3, TIMER_COUNTER_RESET, TIMER_MSEC);
  timer_start_nointr (TIMER3);
  buf_intr = rbuf_nolock_init (__buf_intr, INTR_RBUF_SIZE);

  // Logger setting.
  iprintf ("display: %s, magnet=%d\n", dipsw_laptime ? "lap time" : "elapsed",
	   dipsw_nmagnet);
  memset (&__data, 0, sizeof __data);
  // Data buffer. directly write to DMA buffer.
  data_dma_buffer_setup ();

      // Now OK to log.
  data_thread_ready = TRUE;
  // Setuped. wakeup master.
  thread_wakeup (shell_th);準備ができたので親を起こします。
  // This thread resumed from data_main.
  thread_block (data_idle);そして、次に起こされた時にはdata_idleから。
ここには戻ってきません。
  // NOTREACHED
}

void
data_idle ()
{
上のthread_block (data_idle)から、次にスケジューリングされた時にはここから。
割り込みは禁止で入ってくるので割り込みを開けます。
  intr_enable ();

IDLE状態の間はここでブロックするとdata_idleの最初からはじまり、そうでな
ければdata_samplingからはじまります。
  thread_block (log_status_flag == LOG_STATUS_IDLE ? data_idle : data_sampling);
  // NOTREACHED
  while (/*CONSTCOND*/1)
    ;
}

void
data_stop ()
{
  intr_enable ();

  // Flush
  printf ("flush.\n");
  *__data.p = 0xffffffff;	// End marker.
  // Change current buffer to write buffer.
  dma.write_buffer_bank ^= 1;
  // For next logging.
  memset (&__data, 0, sizeof __data);
  current_speed = 0;
  assert (storage_th);
  // Write out remaining data.
  thread_wakeup (storage_th);

次にスケジューリングされた時はdata_idleからはじまります。
  thread_block (data_idle);
  // NOTREACHED
  while (/*CONSTCOND*/1)
    ;
}

void
data_sampling ()
{
  uint8_t buf[INTR_RBUF_SIZE];
  uint32_t *q;
  size_t sz, i;
  cpu_status_t s;

  // contination is called with interrupt disable. enable again.
  intr_enable ();
サンプリングが終了したら、後処理をして、ここには戻ってきません。
  if (log_status_flag != LOG_STATUS_SAMPLING)
    data_stop ();

  // Read from interrupt context buffer.
  s = intr_suspend ();
  sz = rbuf_nolock_read (buf_intr, buf, INTR_RBUF_SIZE);
  intr_resume (s);

  // Process data.
  for (i = 0, q = (uint32_t *)buf; i < sz; i += sizeof (uint32_t))
    {
      data_process (*q);
      *__data.p++ = *q++;
      printf ("sanacnt=%d\n", __data.cnt);
      __data.cnt += sizeof (uint32_t);
      if (__data.cnt == 512)
	{
	  // Flip data bank.
	  data_dma_buffer_setup ();
	  if (storage_thread_write_busy)
	    {
	      *__data.p++ = LOGGER_STATUS_ERROR | *T3TC;
	      __data.cnt += sizeof (uint32_t);
	    }
	  // Kick storage thread.
	  thread_wakeup (storage_th);
	}
    }
次はまたこの関数からスタックを巻き戻して実行されます。
  thread_block (data_sampling);
  // NOTREACHED
  while (/*CONSTCOND*/1)
    ;
}