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