<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On 21 December 2016 at 01:35, Masayuki YAMAMOTO <span dir="ltr"><<a href="mailto:ma3yuki.8mamo10@gmail.com" target="_blank">ma3yuki.8mamo10@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><span class="gmail-"><div class="gmail_quote">2016-12-20 22:30 GMT+09:00 Erik Bray <span dir="ltr"><<a href="mailto:erik.m.bray@gmail.com" target="_blank">erik.m.bray@gmail.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">This is probably an implementation detail, but ISTM that even with<br>
PyThread_call_once, it will be necessary to reset any used once_flags<br>
manually in PyOS_AfterFork, essentially for the same reason the<br>
autoTLSkey is reset there currently...<br>
</blockquote></div><br></span>Deleting threads key is executed on *_Fini functions, but Py_FinalizeEx function that calls *_Fini functions doesn't terminate CPython interpreter. Furthermore, source comment and document have said description about reinitialization after calling Py_FinalizeEx. [1] [2] That is to say there is an implicit possible that is reinitialization contrary to name "call_once" on a process level. Therefore, if CPython interpreter continues to allow reinitialization, I'd suggest to rename the call_once API to avoid misreading semantics. (for example, safe_init, check_init)<br></div></div></blockquote><div><br></div></div>Ouch, I'd missed that, and I agree it's not a negligible implementation detail - there are definitely applications embedding CPython out there that rely on being able to run multiple Initialize/Finalize cycles in the same process and have everything "just work". It also means using the "PyThread_*" prefix for the initialisation tracking aspect would be misleading, since the life cycle details are:<br><br></div><div class="gmail_extra">1. Create the key for the first time if it has never been previously set in the process<br></div><div class="gmail_extra">2. Destroy and reinit if Py_Finalize gets called<br>3. Destroy and reinit if a new subprocess is forked<br><br></div><div class="gmail_extra">It also means we can't use pthread_once even in the pthread TLS implementation, since it doesn't provide those semantics.<br><br></div><div class="gmail_extra">So I see two main alternatives here.<br><br>Option 1: Modify the proposed PyThread_tss_create and PyThread_tss_delete APIs to accept a "bool *init_flag" pointer in addition to their current arguments.<br><br>If *init_flag is true, then PyThread_tss_create is a no-op, otherwise it sets the flag to true after creating the key.<br>If *init_flag is false, then PyThread_tss_delete is a no-op, otherwise it sets the flag to false after deleting the key.<br><br></div><div class="gmail_extra">Option 2: Similar to option 1, but using a custom type alias, rather than using a C99 bool directly<br></div><div class="gmail_extra"><br></div><div class="gmail_extra">The closest API we have to these semantics at the moment would be PyGILState_Ensure, so the following API naming might work for option 2:<br><br></div><div class="gmail_extra">    Py_ensure_t<br></div><div class="gmail_extra">    Py_ENSURE_NEEDS_INIT<br></div><div class="gmail_extra">    Py_ENSURE_INITIALIZED<br><br></div><div class="gmail_extra">Respectively, these would just be aliases for bool, false, and true.<br></div><div class="gmail_extra"><br></div><div class="gmail_extra">And then modify the proposed PyThread_tss_create and PyThread_tss_delete APIs to accept a "Py_ensure_t *init_flag" in addition to their current arguments.<br><br></div><div class="gmail_extra">Cheers,<br></div><div class="gmail_extra">Nick.<br></div><div class="gmail_extra"><br>-- <br><div class="gmail_signature">Nick Coghlan   |   <a href="mailto:ncoghlan@gmail.com" target="_blank">ncoghlan@gmail.com</a>   |   Brisbane, Australia</div>
</div></div>