目次: 自宅サーバー
このブログ、フォント設定が2つほどおかしかったので直しました。今まで見づらくてすみません。
1つ目は一部の環境(Linux向けChromeなど)からこのサイトを見るとサンセリフ体(ゴシック体)ではなくセリフ体(明朝体)で表示される現象を直しました。セリフ体になってしまう現象は以前から認識していて不思議だな?とは思ったものの、原因が良くわからず放置していました。
Developer toolsでCSSを確認していたら、font-family: sans-serif, serifと指定していた箇所がありました。原因も何も、自分で指定してただけだったのか……。こんな単純なことに10年以上気づいていなかった。
2つ目はmonospace系の文字が表示されるpreタグなどの文字が小さかったのを直しました。今までfont-size: smallerにしていたんですが、monospaceは元々少し小さいサイズで表示されるブラウザが多くて、めちゃくちゃ字が小さくなっていました。
しかもこちらの現象は認識していませんでした。自分のFirefox環境はmonospaceのフォントサイズを少し大き目に指定している&そのことを忘れており、デフォルト設定のブラウザで見ると字が小さすぎることに気付いてなかったです。すまねぇ。
この記事にコメントする
目次: C言語とlibc
シグナルマスク(sigprocmaskのマニュアル)の「規定されていない」使い方をするとどうなるか?の続きです。5つのマルチスレッド(親スレッド+4つの子スレッド)で全員でsigwait()するのは共通で、誰がsigprocmask()を呼ぶか?を変えながら、下記4パターンを試します。
今回は結果3と4を紹介します。1〜3は定義されていない動作ですが、4は比較用に実施する「正しい方法」です。
全スレッドがsigprocmask()した場合です。ゆっくり5回シグナルを送ると、親スレッド(th 4)のsigwait()がシグナルを受け取り、子スレッド(th 0)のsigwait()はEINTRが返ります。
$ g++ -Wall -g -O2 -DUSE_SIGPROCMASK_ALL -DID_MAINTHREAD=1 signal_thread.cpp && ./a.out Use sigprocmask th 0: sub (child ) thread start th 0: sigprocmask(block) th 1: main (child ) thread start th 1: sigprocmask(block) th 2: sub (child ) thread start th 2: sigprocmask(block) th 4: sub (parent) thread start th 4: sigprocmask(block) th 3: sub (child ) thread start th 3: sigprocmask(block) th 3: loop start th 0: loop start th 2: loop start th 1: loop start th 4: loop start th 4: got SIGUSR1 th 0: sigwait failed (Interrupted system call) th 4: got SIGUSR1 th 0: sigwait failed (Interrupted system call) th 4: got SIGUSR1 th 0: sigwait failed (Interrupted system call) th 4: got SIGUSR1 th 0: sigwait failed (Interrupted system call) th 4: got SIGUSR1 th 0: sigwait failed (Interrupted system call)
良い感じです。また結果1(親スレッドがsigprocmask())と異なり、大量にシグナルを送りつけてもabortしないのも良いです。
$ g++ -Wall -g -O2 -DUSE_SIGPROCMASK_ALL -DID_MAINTHREAD=1 signal_thread.cpp && ./a.out Use sigprocmask th 0: sub (child ) thread start th 0: sigprocmask(block) th 1: main (child ) thread start th 1: sigprocmask(block) th 2: sub (child ) thread start th 2: sigprocmask(block) th 4: sub (parent) thread start th 4: sigprocmask(block) th 3: sub (child ) thread start th 3: sigprocmask(block) th 3: loop start th 0: loop start th 2: loop start th 1: loop start th 4: loop start (...略...) th 2: sigwait failed (Interrupted system call) th 0: sigwait failed (Interrupted system call) th 0: got SIGUSR1 th 1: got SIGUSR1 th 2: got SIGUSR1 th 2: got SIGUSR1 th 1: sigwait failed (Interrupted system call) th 0: got SIGUSR1 th 4: sigwait failed (Interrupted system call) th 3: sigwait failed (Interrupted system call) th 2: sigwait failed (Interrupted system call) th 1: got SIGUSR1 (別ターミナルから) $ while :; do kill -USR1 123450; if [ $? -ne 0 ]; then break; fi; done
良さそうですね。
正しい方法(全スレッドがpthread_sigmask())はどんな動きでしょうか?結果だけ先に書いてしまうと、全スレッドがsigprocmask()したときと同じ動きをするようです。
$ g++ -Wall -g -O2 -DUSE_PTHREADSIGMASK -DID_MAINTHREAD=1 signal_thread.cpp && ./a.out Use pthread_sigmask th 0: sub (child ) thread start th 0: pthread_sigmask(block) th 1: main (child ) thread start th 1: pthread_sigmask(block) th 2: sub (child ) thread start th 2: pthread_sigmask(block) th 4: sub (parent) thread start th 4: pthread_sigmask(block) th 3: sub (child ) thread start th 3: pthread_sigmask(block) th 3: loop start th 2: loop start th 0: loop start th 1: loop start th 4: loop start th 4: got SIGUSR1 th 0: sigwait failed (Interrupted system call) th 4: got SIGUSR1 th 0: sigwait failed (Interrupted system call) th 4: got SIGUSR1 th 0: sigwait failed (Interrupted system call) th 4: got SIGUSR1 th 0: sigwait failed (Interrupted system call) th 4: got SIGUSR1 th 0: sigwait failed (Interrupted system call)
結果3(全員sigprocmask())と同じ動きをしています。当然ながら、大量にシグナルを送りつけてもabortしません。
$ g++ -Wall -g -O2 -DUSE_PTHREADSIGMASK -DID_MAINTHREAD=1 signal_thread.cpp && ./a.out Use pthread_sigmask th 0: sub (child ) thread start th 0: pthread_sigmask(block) th 1: main (child ) thread start th 1: pthread_sigmask(block) th 2: sub (child ) thread start th 2: pthread_sigmask(block) th 4: sub (parent) thread start th 4: pthread_sigmask(block) th 3: sub (child ) thread start th 3: pthread_sigmask(block) th 3: loop start th 2: loop start th 0: loop start th 1: loop start th 4: loop start (...略...) th 2: got SIGUSR1 th 0: sigwait failed (Interrupted system call) th 1: sigwait failed (Interrupted system call) th 4: sigwait failed (Interrupted system call) th 0: got SIGUSR1 th 4: got SIGUSR1 th 0: got SIGUSR1 th 3: sigwait failed (Interrupted system call) th 3: got SIGUSR1 th 2: sigwait failed (Interrupted system call) th 2: got SIGUSR1 th 0: sigwait failed (Interrupted system call) th 0: got SIGUSR1 th 1: sigwait failed (Interrupted system call) th 3: sigwait failed (Interrupted system call) th 3: got SIGUSR1 th 0: got SIGUSR1 th 4: sigwait failed (Interrupted system call) th 2: sigwait failed (Interrupted system call) th 1: sigwait failed (Interrupted system call) (別ターミナルから) $ while :; do kill -USR1 123450; if [ $? -ne 0 ]; then break; fi; done
4つの結果から推測するにpthread_sigmask()とsigprocmask()は同じシステムコールを使っているかもしれません。libcのソースコードを見ればわかるはずなので、また今度に見ようと思います。
こちらからどうぞ。
この記事にコメントする
目次: C言語とlibc
シグナルマスクのマニュアル(sigprocmaskのマニュアル)を見ると下記のように「規定されていない」とあります。実際Linuxだとどうなるか気になります。
マルチスレッドのプロセスでsigprocmask()を使用した場合の動作は規定されていない。
実行環境は下記のとおりです。他のプラットフォームや過去/将来のバージョンのLinuxで今回の実験結果と同じ動作をするとは限りませんのでご注意ください。
実験内容は5つのマルチスレッド(親スレッド+4つの子スレッド)で全員でsigwait()するのは共通、誰がsigprocmask()を呼ぶか?を変えながら、下記4パターンを試します。
最後のパターンはマルチスレッドでsigwait()する場合の正しい方法(全スレッドがpthread_sigmask())で、他の3つと動作を比較するためのものです。
コードは長くなってしまったので最後にファイルへのリンクを張っておきます。
実験方法はコンパイル時にマクロを適宜切り替えて、生成された./a.outを起動し、別のターミナルからkillコマンドなどでSIGUSR1を送るだけです。
最初のスレッドがsigprocmask()した場合です。ゆっくり5回シグナルを送ると、親スレッド(th 4)のsigwait()がシグナルを受け取り、子スレッド(th 0)のsigwait()はEINTRが返ってきます。
$ g++ -Wall -g -O2 -DUSE_SIGPROCMASK -DID_MAINTHREAD=4 signal_thread.cpp && ./a.out Use sigprocmask th 0: sub (child ) thread start th 1: sub (child ) thread start th 2: sub (child ) thread start th 4: main (parent) thread start th 4: sigprocmask(block) th 3: sub (child ) thread start th 3: loop start th 2: loop start th 4: loop start th 0: loop start th 1: loop start th 4: got SIGUSR1 th 0: sigwait failed (Interrupted system call) th 4: got SIGUSR1 th 0: sigwait failed (Interrupted system call) th 4: got SIGUSR1 th 0: sigwait failed (Interrupted system call) th 4: got SIGUSR1 th 0: sigwait failed (Interrupted system call) th 4: got SIGUSR1 th 0: sigwait failed (Interrupted system call)
一見すると良い感じに動くように見えますが、大量にシグナルを送りつけるとabortします。ありゃりゃ。
$ g++ -Wall -g -O2 -DUSE_SIGPROCMASK -DID_MAINTHREAD=4 signal_thread.cpp && ./a.out Use sigprocmask th 0: sub (child ) thread start th 1: sub (child ) thread start th 2: sub (child ) thread start th 4: main (parent) thread start th 4: sigprocmask(block) th 3: sub (child ) thread start th 3: loop start th 1: loop start th 0: loop start th 2: loop start th 4: loop start ユーザー定義シグナル1 (別ターミナルから) $ while :; do kill -USR1 123450; if [ $? -ne 0 ]; then break; fi; done
一見動くように見えて、だめなパターンですね。
最初のスレッド「以外」の1スレッドがsigprocmask()した場合です。1回シグナルを送っただけでabortしました。
$ g++ -Wall -g -O2 -DUSE_SIGPROCMASK -DID_MAINTHREAD=0 signal_thread.cpp && ./a.out Use sigprocmask th 0: main (child ) thread start th 0: sigprocmask(block) th 1: sub (child ) thread start th 2: sub (child ) thread start th 4: sub (parent) thread start th 3: sub (child ) thread start th 3: loop start th 0: loop start th 2: loop start th 1: loop start th 4: loop start ユーザー定義シグナル1
結果1の動きを見る限り納得の結果と言えるでしょう。シグナルは常に親スレッドにも飛んでいたので、シグナルをマスクしてない親スレッドはabortするのはそりゃそうだなと思います。
続きはまた今度やります。
こちらからどうぞ。
この記事にコメントする
目次: Arduino
M5Stamp C3 + Raspberry Piを組み合わせて作った的あてゲーム、秋葉原のTarget-1(お店のサイト)で壊れることなく1年ほど安定稼働しているようです。良かった良かった。しかし最近、故障ではないもののタイトル画面に戻ってしまう頻度が増えているそうです。
以前に日記で紹介したとおり、的あてゲームのシステムはM5Stamp C3をBluetooth LEデバイスにして、Linux PCもしくはRaspberry PiなどのLinux SBCと通信しています。Bluetoothの接続が切れるとタイトル画面に戻って再接続する実装にしていますので、不意にタイトル画面に戻る = Bluetoothの接続が切断されていることを意味します。
お店での運用を見ていると、ゲームリザルト画面で放置されることが多いです。今の実装ではリザルト画面でBluetoothの通信を一切行いません。あまりにも長い間通信しないとBluetooth接続が切れてしまう?のかもしれません。
とりあえず今回は小手先の対処として、リザルト画面でM5Stamp C3本体のLEDを点滅させる指令を送り続け、Bluetooth接続を維持するようにしました。家でテストしてみたところ1日以上放置しても接続を維持できています。
代償として消費電力が0.1Wくらい増えますが、何度もタイトル画面に戻されるよりはマシでしょう……。
先代のTSS(ターゲットシューティングシステム、作者さんの紹介サイト)は5年位稼働していたらしい(すごい!)ので、追いつくにはあと4年ですか、長いな〜……。
4年後を考えてみると、Linux側のマシンROCK 3Cはほぼ確実にEOL(End Of Life、生産終了、販売終了)だと思います。Linux側のシステムはHW依存は少ないし、SWも枯れたやつが多いので、そのとき販売されているお買い得なARM SBCボード(Raspberry Pi 6とか7とか?ROCK 3C後継のボードとか)への乗り換えは容易だと思います。
困るのはM5Stamp C3ですね。EOLになると別ボードへのSW移植とドッキングするためのボード再設計が必要でしょう。M5Stampは安くて良いんですけど、世代ごとに形がガンガン変わって互換性ゼロなのが良くない点ですね。作り直すとしたら、今のM5Stamp C3の2枚使い設計はダサいので、I/Oピン数の多いボード1枚に改めると思います。
この記事にコメントする
目次: C言語とlibc
POSIXには時間を表す構造体が2つあります。マイクロ秒単位のstruct timevalと、ナノ秒単位のstruct timespecです。struct timespecの方が後発なのか、比較的新しいAPIはstruct timespecを使う傾向にありますが、基本的には混在しています。
struct timeval {
time_t tv_sec; /* 秒 */
suseconds_t tv_usec; /* マイクロ秒 */
};
struct timespec {
time_t tv_sec; /* 秒 */
long tv_nsec; /* ナノ秒 */
};
見てのとおり構造体ですから、足し算や引き算をするにも桁上がりを考える必要があって一苦労必要かと思いきや、POSIXはtimeradd/timersubなどのマクロを用意しており、struct timevalの加減算と比較などが比較的簡単に行えます。便利ですね。
ではstruct timespecにも同様にtimespecadd/timespecsubがあると思いますよね?ところが一部のlibc(BSD系やnewlib)以外は実装していません。なぜ……!?
#define timespecadd(a, b, res) \
do { \
(res)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
(res)->tv_nsec = (a)->tv_nsec + (b)->tv_nsec; \
if ((res)->tv_nsec >= 1000000000) { \
(res)->tv_sec++; \
(res)->tv_nsec -= 1000000000; \
} \
} while (0)
#define timespecsub(a, b, res) \
do { \
(res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
(res)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec; \
if ((res)->tv_nsec < 0) { \
(res)->tv_sec--; \
(res)->tv_nsec += 1000000000; \
} \
} while (0)
#define timespecclear(tsp) ((tsp)->tv_sec = (tsp)->tv_nsec = 0)
#define timespecisset(tsp) ((tsp)->tv_sec || (tsp)->tv_nsec)
#define timespeccmp(a, b, cmp) \
(((a)->tv_sec == (b)->tv_sec) ? \
((a)->tv_nsec cmp (b)->tv_nsec) : \
((a)->tv_sec cmp (b)->tv_sec))
いつもstruct timespecを要求するAPIを使うたびにtimespecadd/timespecsubがなくて演算しづらさにイライラするので、コピペで使い回せるように実装例をメモしておきます。この程度なら誰が書いてもほとんど同じコードになると思いますが、気になる方のためにもし著作権が発生する場合はBSD 3条項ライセンス扱いでお願いします。
この記事にコメントする
| < | 2025 | > | ||||
| << | < | 05 | > | >> | ||
| 日 | 月 | 火 | 水 | 木 | 金 | 土 |
| - | - | - | - | 1 | 2 | 3 |
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
25年10月6日
25年10月6日
25年9月29日
25年9月29日
20年8月24日
20年8月24日
16年2月14日
16年2月14日
25年7月20日
25年7月20日
25年7月20日
25年7月20日
25年7月20日
25年7月20日
20年8月16日
20年8月16日
20年8月16日
20年8月16日
24年6月17日
24年6月17日
wiki
Linux JM
Java API
2002年
2003年
2004年
2005年
2006年
2007年
2008年
2009年
2010年
2011年
2012年
2013年
2014年
2015年
2016年
2017年
2018年
2019年
2020年
2021年
2022年
2023年
2024年
2025年
過去日記について
アクセス統計
サーバ一覧
サイトの情報合計:
本日: