簡単に説明すると、タスクAからタスクBにメッセージを送り、BからAにその返答を返すことができる機能。
ぱっと見便利な機能なのだが、タスクAからタスクBにメッセージを渡すときに、malloc()等で動的に確保したメモリのポインタを渡すことができないというワナがある。
このワナを知らないと、メモリリークを起こす。
以下、詳細。
タスクAからメッセージを送るときには、cal_por()またはtcal_por()というAPIを使う。
tcal_por(portid, 0x1, msg, msgsize, timeout);
これでタスクAは、タスクBにmsgを送ることができる。
タスクB側は、以下のようなコードになる。
acp_por(portid, 0x1, &retno, buf); /* tcal_porされるのを待つ */
...
rpl_rdv(retno, retmsg, sizeof(retmsg)); /* タスクAに返答を返す */
タスクBがrpl_rdv()を呼ぶと、タスクAのtcal_por()がリターンして、タスクAはタスクBから返答を受け取ることができる。(返答は、tcal_por()の第3引数msgの指すアドレスに上書きされる)
ここで問題となるのは、tcal_por()がタイムアウトした場合。
tcal_por()は、タスクBから一定時間内にrpl_rdv()が呼ばれなかった場合にタイムアウトする。タスクBがacp_por()でメッセージを受け取ったかどうかは関係が無い。
すなわちタスクAは、タスクBがacp_por()でAからのメッセージを受け取ったかどうかを判断することができない。
以下のように、malloc()で動的に確保したメモリをメッセージに含めて、tcal_por()に渡したとする。
msg.pointer = malloc(msgsize);
tcal_por(portid, 0x1, msg, msgsize, timeout);
tcal_por()がタイムアウトした場合、free()は一体誰が呼べば良いだろうか?
メッセージはタスクBに伝わっていればBがfree()し、伝わっていなければAがfree()すべきである。
しかし、タスクAは、メッセージが伝わっているのか否かを判断することができないのである。
---
タイトルがちょっと不正確なので、正しく書き直すと、
「ITRON4準拠のランデブ機能を使うときに、mallocで確保したアドレスを含むメッセージをtcal_por()に渡してはいけない。」
0 件のコメント:
コメントを投稿