Best way to kill an async thread in a linked in driver?
Mazen Harake
mazen.harake@REDACTED
Thu Aug 12 10:31:58 CEST 2010
It was late yesterday and despite 2 coffees and a nice breakfast I
still can't solve this one. Maybe a nudge in the right direction anyone?
Scenario:
I have a linked in driver; cecho [1], when ever I want to read input I
disable input to Erlang (-noinput) and use the getch() function in C
instead (never mind why ;)). This function is run in a seperate async
thread using driver_async() [2][3], and blocks at getch(). When a
character is read it sends a message back to Erlang (driver_output())
and then the thread exits, when the message comes back to Erlang the
character is sent to the requester and the thread is restarted (which
again blocks at getch()).
Later if I do an erlang:halt(0) ("graceful halt") the thread is still
lingering despite having closed the port[4] (which, Afaik should close
the thread as well) but it seems stay alive somehow. erlang:halt(1) kill
it immediately so it is not a problem.
Questions:
1) Is my "analysis" correct? Is this infact what is happening? Anyone
who can explain this behaviour (I.e. why it lingers on)?
2) If Question 1 then; what is the best way to kill the thread when I
exit? driver_async_cancel() only works for threads that are not
executing (according to Documentation) so what to do? I did an ugly
workaround which sets a global flag and then I timeout the getch()
operation and read for ERR. If I get an ERR I just read the abort flag
and if it is set I just die otherwise I try to getch() again. This
avoids hanging around for more then a tenth of a second but it is pretty
ugly in my oppinion and I'm forced to go into halfdelay mode which means
I can not allow this option outside of the driver because I become
dependent on it. I'd rather do it the "right way" if there is such a way.
References: (Links given as commit Ids so that if someone searches then
they get relevant code and not the latest)
[1]
http://github.com/mazenharake/cecho/tree/199fd342ba186e1154c32dbfdcf2d9222e25f9f4
[2]
http://github.com/mazenharake/cecho/blob/199fd342ba186e1154c32dbfdcf2d9222e25f9f4/c_src/cecho.c#L119
static void request(ErlDrvData drvstate, char *buf, int buflen) {
state *st = (state *)drvstate;
driver_async(st->drv_port, NULL, loop_getch, (void *)st, NULL);
}
[3]
http://github.com/mazenharake/cecho/blob/199fd342ba186e1154c32dbfdcf2d9222e25f9f4/c_src/cecho.c#L557
void loop_getch(void *arg) {
state *st = (state *)arg;
ei_x_buff eixb;
int keycode;
ei_x_new_with_version(&eixb);
keycode = getch();
integer(&eixb, keycode);
driver_output(st->drv_port, eixb.buff, eixb.index);
}
[4]
http://github.com/mazenharake/cecho/blob/199fd342ba186e1154c32dbfdcf2d9222e25f9f4/src/cecho_srv.erl#L76
terminate(_Reason, State) ->
do_call(State#state.port, ?ENDWIN),
do_call(State#state.port, ?CURS_SET, ?ceCURS_NORMAL),
erlang:port_close(State#state.port),
erl_ddll:unload("cecho").
More information about the erlang-questions
mailing list