<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<meta name="Generator" content="Microsoft Word 14 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0cm;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri","sans-serif";
mso-fareast-language:EN-US;}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
{mso-style-priority:99;
color:purple;
text-decoration:underline;}
span.EmailStyle17
{mso-style-type:personal-compose;
font-family:"Calibri","sans-serif";
color:windowtext;}
span.code
{mso-style-name:code;}
.MsoChpDefault
{mso-style-type:export-only;
font-family:"Calibri","sans-serif";
mso-fareast-language:EN-US;}
@page WordSection1
{size:612.0pt 792.0pt;
margin:2.0cm 42.5pt 2.0cm 3.0cm;}
div.WordSection1
{page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="RU" link="blue" vlink="purple">
<div class="WordSection1">
<p class="MsoNormal"><span lang="EN-US">Hello erlang gurus,<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">Currently I’ve faced with the following issue with termination of threads created in port drivers.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">I’m creating a separate thread in the erlang port driver that sends terms to some erlang process.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">--------------------------------------<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">The thread is created like this:<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">ErlDrvTid threadId;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">if(erl_drv_thread_create(“thread name”, &threadId, threadFunc, threadData, NULL)) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> // log error & exit<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">}<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">driverData->tid = threadId;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">Driver data looks like this:<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">struct DriverData {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> ErlDrvPort port;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> ErlDrvTid tid;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> int isRunning;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">}<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">--------------------------------------<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">Thread function looks like this<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">DriverData* data = (DriverData*) threadData<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">data. isRunning = 1;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">while(data.isRunning) {<br>
doSomething();<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">}<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">--------------------------------------<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">When I’d like to stop this thread from one of the driver callbacks I do something like this:<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">void handleInput(ErlDrvData handle, char * buf, ErlDrvSizeT len) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> DriverData* data = (DriverData*) handle;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> <o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> int command = parseBuf(buf, len);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> if (command == STOP) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> data.isRunning = 0;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> if(erl_drv_thread_join(data->tid, NULL)) { // here is the place where EDEADLK happens<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> // report error<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> } else {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> …<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">}<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">From time to time erl_drv_thread_join returns error EDEADLK=35, i.e. the current thread (scheduler thread) tries to join itself.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">According to the documentation “A Thread identifier may be reused very quickly after a thread has terminated. Therefore, if a thread corresponding to one of the involved thread identifiers has terminated since the thread
identifier was saved, the result of <span class="code">erl_drv_equal_tids()</span> might not give the expected result.”<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">I suppose that thread terminates earlier then erl_drv_thread_join call happens, so ErlDrvTid is already reused.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">So the question is how to use erl_drv_thread_join properly and how to guarantee that the saved ErlDrvTid value points to the same data that was returned from erl_drv_thread_create?<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span lang="EN-US" style="color:black;mso-fareast-language:RU">Best Regards,<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span lang="EN-US" style="color:black;mso-fareast-language:RU">Sergey<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
</div>
<p><span style="font-family:'Arial';font-size:8pt;">_______________________________________________________</span></p>
<p><span style="font-family:'Arial';font-size:8pt;">CONFIDENTIALITY NOTICE: This email and any files attached to it may be conf idential. If you are not the intended recipient you are notified that using, copying, distributing or taking any action in reliance on the contents of this information is strictly prohibited. If you have received this email in error please notify the sender and delete this email. </span></p></body>
</html>