@@ -103,7 +103,8 @@ typedef enum {
103103 THREAD_HANDLE_NOT_STARTED = 1 ,
104104 THREAD_HANDLE_STARTING = 2 ,
105105 THREAD_HANDLE_RUNNING = 3 ,
106- THREAD_HANDLE_DONE = 4 ,
106+ THREAD_HANDLE_FAILED = 4 ,
107+ THREAD_HANDLE_DONE = 5 ,
107108} ThreadHandleState ;
108109
109110// A handle to wait for thread completion.
@@ -288,7 +289,8 @@ ThreadHandle_decref(ThreadHandle *self)
288289 // 1. This is the destructor; nothing else holds a reference.
289290 // 2. The refcount going to zero is a "synchronizes-with" event; all
290291 // changes from other threads are visible.
291- if (self -> state == THREAD_HANDLE_RUNNING && !detach_thread (self )) {
292+ if ((self -> state == THREAD_HANDLE_RUNNING || self -> state == THREAD_HANDLE_FAILED )
293+ && !detach_thread (self )) {
292294 self -> state = THREAD_HANDLE_DONE ;
293295 }
294296
@@ -396,8 +398,8 @@ thread_run(void *boot_raw)
396398 PyErr_FormatUnraisable (
397399 "Exception ignored in thread started by %R" , boot -> func );
398400 }
399- // TODO: should we use a new state for failed bootsrap Thread
400- set_thread_handle_state ( handle , THREAD_HANDLE_DONE );
401+ set_thread_handle_state ( handle , THREAD_HANDLE_FAILED );
402+ // Notify that the bootstraped is done, in case the Python call didn't manage too (e.g. Memory error)
401403 _PyEvent_Notify (& handle -> thread_is_bootstraped );
402404 }
403405 else {
@@ -509,7 +511,10 @@ static int
509511join_thread (void * arg )
510512{
511513 ThreadHandle * handle = (ThreadHandle * )arg ;
512- assert (get_thread_handle_state (handle ) >= THREAD_HANDLE_RUNNING );
514+ assert (
515+ get_thread_handle_state (handle ) == THREAD_HANDLE_RUNNING ||
516+ get_thread_handle_state (handle ) == THREAD_HANDLE_FAILED
517+ );
513518 PyThread_handle_t os_handle ;
514519 if (ThreadHandle_get_os_handle (handle , & os_handle )) {
515520 int err = 0 ;
@@ -629,7 +634,7 @@ ThreadHandle_set_done(ThreadHandle *self)
629634}
630635
631636static void
632- ThreadHandle_set_bootstrap_done (ThreadHandle * self )
637+ ThreadHandle_set_bootstraped (ThreadHandle * self )
633638{
634639 _PyEvent_Notify (& self -> thread_is_bootstraped );
635640}
@@ -721,11 +726,10 @@ PyThreadHandleObject_join(PyObject *op, PyObject *args)
721726}
722727
723728static PyObject *
724- PyThreadHandleObject_is_running (PyObject * op , PyObject * Py_UNUSED (dummy ))
729+ PyThreadHandleObject_is_bootstraped (PyObject * op , PyObject * Py_UNUSED (dummy ))
725730{
726731 PyThreadHandleObject * self = PyThreadHandleObject_CAST (op );
727- ThreadHandleState state = get_thread_handle_state (self -> handle );
728- if (state == THREAD_HANDLE_RUNNING ) {
732+ if (_PyEvent_IsSet (& self -> handle -> thread_is_bootstraped )) {
729733 Py_RETURN_TRUE ;
730734 }
731735 else {
@@ -734,21 +738,33 @@ PyThreadHandleObject_is_running(PyObject *op, PyObject *Py_UNUSED(dummy))
734738}
735739
736740static PyObject *
737- PyThreadHandleObject_wait_bootstrap_done (PyObject * op , PyObject * Py_UNUSED (dummy ))
741+ PyThreadHandleObject_wait_bootstraped (PyObject * op , PyObject * Py_UNUSED (dummy ))
738742{
739743 PyThreadHandleObject * self = PyThreadHandleObject_CAST (op );
740744 PyEvent_Wait (& self -> handle -> thread_is_bootstraped );
741745 Py_RETURN_NONE ;
742746}
743747
744748static PyObject *
745- PyThreadHandleObject_set_bootstrap_done (PyObject * op , PyObject * Py_UNUSED (dummy ))
749+ PyThreadHandleObject_set_bootstraped (PyObject * op , PyObject * Py_UNUSED (dummy ))
746750{
747751 PyThreadHandleObject * self = PyThreadHandleObject_CAST (op );
748- ThreadHandle_set_bootstrap_done (self -> handle );
752+ ThreadHandle_set_bootstraped (self -> handle );
749753 Py_RETURN_NONE ;
750754}
751755
756+ static PyObject *
757+ PyThreadHandleObject_is_failed (PyObject * op , PyObject * Py_UNUSED (dummy ))
758+ {
759+ PyThreadHandleObject * self = PyThreadHandleObject_CAST (op );
760+ if (get_thread_handle_state (self -> handle ) == THREAD_HANDLE_FAILED ) {
761+ Py_RETURN_TRUE ;
762+ }
763+ else {
764+ Py_RETURN_FALSE ;
765+ }
766+ }
767+
752768static PyObject *
753769PyThreadHandleObject_is_done (PyObject * op , PyObject * Py_UNUSED (dummy ))
754770{
@@ -782,9 +798,10 @@ static PyGetSetDef ThreadHandle_getsetlist[] = {
782798static PyMethodDef ThreadHandle_methods [] = {
783799 {"join" , PyThreadHandleObject_join , METH_VARARGS , NULL },
784800 {"_set_done" , PyThreadHandleObject_set_done , METH_NOARGS , NULL },
785- {"wait_bootstrap_done" , PyThreadHandleObject_wait_bootstrap_done , METH_NOARGS , NULL },
786- {"set_bootstrap_done" , PyThreadHandleObject_set_bootstrap_done , METH_NOARGS , NULL },
787- {"is_running" , PyThreadHandleObject_is_running , METH_NOARGS , NULL },
801+ {"wait_bootstraped" , PyThreadHandleObject_wait_bootstraped , METH_NOARGS , NULL },
802+ {"set_bootstraped" , PyThreadHandleObject_set_bootstraped , METH_NOARGS , NULL },
803+ {"is_bootstraped" , PyThreadHandleObject_is_bootstraped , METH_NOARGS , NULL },
804+ {"is_failed" , PyThreadHandleObject_is_failed , METH_NOARGS , NULL },
788805 {"is_done" , PyThreadHandleObject_is_done , METH_NOARGS , NULL },
789806 {0 , 0 }
790807};
@@ -2511,6 +2528,7 @@ thread__make_thread_handle(PyObject *module, PyObject *identobj)
25112528 hobj -> handle -> ident = ident ;
25122529 hobj -> handle -> state = THREAD_HANDLE_RUNNING ;
25132530 PyMutex_Unlock (& hobj -> handle -> mutex );
2531+ _PyEvent_Notify (& hobj -> handle -> thread_is_bootstraped );
25142532 return (PyObject * ) hobj ;
25152533}
25162534
0 commit comments