diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 6bdc2fac2..8474745b2 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,26 @@ +Tue Sep 11 18:15:00 2001 Robert Collins + + * dcrt0.cc (cygwin_finished_initializing): Copy _mtinterf on fork; + * fork.cc (fork_child): fixup thread-related structures after fork; + * thread.cc (MTinterface::Init): Initialise the new mutex, condition and semaphore lists. + (MTinterface::fixup_after_fork): Iterate through each list and fixup the objects. + (pthread_cond::pthread_cond): Add this to the condition list. + (pthread_cond::~pthread_cond): Remove this from the condition list. + (pthread_cond::fixup_after_fork): Recreate as best we can the pre-fork state. + (pthread_mutex::pthread_mutex): Add this to the mutex list. + (pthread_mutex::~pthread_mutex): Remove this from the mutex list. + (pthread_mutex::fixup_after_fork): Recreate as best we can the pre-fork state. + (semaphore::semaphore): Store the initial value, and add this to the semaphore list. + (semaphore::~semaphore): Remove this from the semaphore list. + (semaphore::Post): Increment the current semaphore value. + (semaphore::TryWait): Decrement the current semaphore value. + (semaphore::Wait): Ditto. + (semaphote::fixup_after_fork): Recreate the pre-fork state as best we can. + * thread.h (pthread_mutex): New members to allow fixup_after_fork. + (pthread_cond): Ditto. + (semaphore): Ditto. + (MTinterface): New list heads for tracking conds and semaphores. + Sun Sep 9 22:11:27 2001 Christopher Faylor * dtable.cc (dtable::fixup_after_fork): Use SetStdHandle appropriately diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 4f278cee1..ef0338651 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -70,7 +70,7 @@ int cygwin_finished_initializing; unsigned NO_COPY int signal_shift_subtract = 1; ResourceLocks _reslock NO_COPY; -MTinterface _mtinterf NO_COPY; +MTinterface _mtinterf; bool NO_COPY _cygwin_testing; diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index 3a63e3901..ccfc2aa26 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -309,6 +309,8 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls) if ((*t)->clear_on_fork ()) (*t)->set (); + user_data->threadinterface->fixup_after_fork (); + /* Initialize signal/process handling */ sigproc_init (); __pthread_atforkchild (); diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index f05d441f4..c4d6c05e8 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -302,6 +302,10 @@ MTinterface::Init (int forked) if (forked) return; + mutexs = NULL; + conds = NULL; + semaphores = NULL; + /*possible the atfork lists should be inited here as well */ #if 0 @@ -313,6 +317,33 @@ MTinterface::Init (int forked) #endif } +/* This function is called from a single threaded process */ +void +MTinterface::fixup_after_fork (void) +{ + pthread_mutex *mutex = mutexs; + debug_printf("mutexs is %x\n",mutexs); + while (mutex) + { + mutex->fixup_after_fork (); + mutex = mutex->next; + } + pthread_cond *cond = conds; + debug_printf("conds is %x\n",conds); + while (cond) + { + cond->fixup_after_fork (); + cond = cond->next; + } + semaphore *sem = semaphores; + debug_printf("semaphores is %x\n",semaphores); + while (sem) + { + sem->fixup_after_fork (); + sem = sem->next; + } +} + pthread::pthread ():verifyable_object (PTHREAD_MAGIC), win32_obj_id (0), cancelstate (0), canceltype (0) { @@ -402,6 +433,8 @@ pthread_cond::pthread_cond (pthread_condattr *attr):verifyable_object (PTHREAD_C if (!this->win32_obj_id) magic = 0; + /* threadsafe addition is easy */ + next = (pthread_cond *)InterlockedExchangePointer (&MT_INTERFACE->conds, this); } pthread_cond::~pthread_cond () @@ -409,6 +442,17 @@ pthread_cond::~pthread_cond () if (win32_obj_id) CloseHandle (win32_obj_id); pthread_mutex_destroy (&cond_access); + /* I'm not 100% sure the next bit is threadsafe. I think it is... */ + if (MT_INTERFACE->conds == this) + MT_INTERFACE->conds = (pthread_cond *)InterlockedExchangePointer (&MT_INTERFACE->conds, this->next); + else + { + pthread_cond *tempcond = MT_INTERFACE->conds; + while (tempcond->next && tempcond->next != this) + tempcond = tempcond->next; + /* but there may be a race between the loop above and this statement */ + tempcond->next = (pthread_cond *)InterlockedExchangePointer (&tempcond->next, this->next); + } } void @@ -478,6 +522,21 @@ pthread_cond::TimedWait (DWORD dwMilliseconds) } } +void +pthread_cond::fixup_after_fork () +{ + debug_printf("cond %x in fixup_after_fork\n", this); + if (shared != PTHREAD_PROCESS_PRIVATE) + api_fatal("doesn't understand PROCESS_SHARED condition variables\n"); + /* FIXME: duplicate code here and in the constructor. */ + this->win32_obj_id =::CreateEvent (&sec_none_nih, false, false, NULL); + if (!win32_obj_id) + api_fatal("failed to create new win32 mutex\n"); + if (waiting) + api_fatal("Forked() while a condition variable has waiting threads.\nReport to cygwin@cygwin.com\n"); +} + + pthread_key::pthread_key (void (*destructor) (void *)):verifyable_object (PTHREAD_KEY_MAGIC) { dwTlsIndex = TlsAlloc (); @@ -536,6 +595,13 @@ pthread_key::get () *Isn't duplicated, it's reopened. */ +/*FIXME: implement InterlockExchangePointer and get rid of the silly typecasts in pthread_atfork + */ +#ifndef InterlockedExchangePointer +#define InterlockedExchangePointer InterlockedExchange +#endif + + pthread_mutex::pthread_mutex (pthread_mutexattr *attr):verifyable_object (PTHREAD_MUTEX_MAGIC) { /*attr checked in the C call */ @@ -552,6 +618,8 @@ pthread_mutex::pthread_mutex (pthread_mutexattr *attr):verifyable_object (PTHREA magic = 0; condwaits = 0; pshared = PTHREAD_PROCESS_PRIVATE; + /* threadsafe addition is easy */ + next = (pthread_mutex *)InterlockedExchangePointer (&MT_INTERFACE->mutexs, this); } pthread_mutex::~pthread_mutex () @@ -559,6 +627,17 @@ pthread_mutex::~pthread_mutex () if (win32_obj_id) CloseHandle (win32_obj_id); win32_obj_id = NULL; + /* I'm not 100% sure the next bit is threadsafe. I think it is... */ + if (MT_INTERFACE->mutexs == this) + MT_INTERFACE->mutexs = (pthread_mutex *)InterlockedExchangePointer (&MT_INTERFACE->mutexs, this->next); + else + { + pthread_mutex *tempmutex = MT_INTERFACE->mutexs; + while (tempmutex->next && tempmutex->next != this) + tempmutex = tempmutex->next; + /* but there may be a race between the loop above and this statement */ + tempmutex->next = (pthread_mutex *)InterlockedExchangePointer (&tempmutex->next, this->next); + } } int @@ -579,6 +658,21 @@ pthread_mutex::UnLock () return ReleaseMutex (win32_obj_id); } +void +pthread_mutex::fixup_after_fork () +{ + debug_printf("mutex %x in fixup_after_fork\n", this); + if (pshared != PTHREAD_PROCESS_PRIVATE) + api_fatal("pthread_mutex::fixup_after_fork () doesn'tunderstand PROCESS_SHARED mutex's\n"); + /* FIXME: duplicate code here and in the constructor. */ + this->win32_obj_id =::CreateMutex (&sec_none_nih, false, NULL); + + if (!win32_obj_id) + api_fatal("pthread_mutex::fixup_after_fork() failed to create new win32 mutex\n"); + if (condwaits) + api_fatal("Forked() while a mutex has condition variables waiting on it.\nReport to cygwin@cygwin.com\n"); +} + pthread_mutexattr::pthread_mutexattr ():verifyable_object (PTHREAD_MUTEXATTR_MAGIC), pshared (PTHREAD_PROCESS_PRIVATE), mutextype (PTHREAD_MUTEX_DEFAULT) { @@ -595,19 +689,34 @@ semaphore::semaphore (int pshared, unsigned int value):verifyable_object (SEM_MA if (!this->win32_obj_id) magic = 0; this->shared = pshared; + currentvalue = value; + /* threadsafe addition is easy */ + next = (semaphore *)InterlockedExchangePointer (&MT_INTERFACE->semaphores, this); } semaphore::~semaphore () { if (win32_obj_id) CloseHandle (win32_obj_id); + /* I'm not 100% sure the next bit is threadsafe. I think it is... */ + if (MT_INTERFACE->semaphores == this) + MT_INTERFACE->semaphores = (semaphore *)InterlockedExchangePointer (&MT_INTERFACE->semaphores, this->next); + else + { + semaphore *tempsem = MT_INTERFACE->semaphores; + while (tempsem->next && tempsem->next != this) + tempsem = tempsem->next; + /* but there may be a race between the loop above and this statement */ + tempsem->next = (semaphore *)InterlockedExchangePointer (&tempsem->next, this->next); + } } void semaphore::Post () { - long pc; - ReleaseSemaphore (win32_obj_id, 1, &pc); + /* we can't use the currentvalue, because the wait functions don't let us access it */ + ReleaseSemaphore (win32_obj_id, 1, NULL); + currentvalue++; } int @@ -618,14 +727,27 @@ semaphore::TryWait () */ if (WaitForSingleObject (win32_obj_id, 0) == WAIT_TIMEOUT) return EAGAIN; - else - return 0; + currentvalue--; + return 0; } void semaphore::Wait () { WaitForSingleObject (win32_obj_id, INFINITE); + currentvalue--; +} + +void +semaphore::fixup_after_fork () +{ + debug_printf("sem %x in fixup_after_fork\n", this); + if (shared != PTHREAD_PROCESS_PRIVATE) + api_fatal("doesn't understand PROCESS_SHARED semaphores variables\n"); + /* FIXME: duplicate code here and in the constructor. */ + this->win32_obj_id =::CreateSemaphore (&sec_none_nih, currentvalue, LONG_MAX, NULL); + if (!win32_obj_id) + api_fatal("failed to create new win32 semaphore\n"); } verifyable_object::verifyable_object (long verifyer): @@ -1052,12 +1174,6 @@ __pthread_atforkchild (void) } } -/*FIXME: implement InterlockExchangePointer and get rid of the silly typecasts below - */ -#ifndef InterlockedExchangePointer -#define InterlockedExchangePointer InterlockedExchange -#endif - /*Register a set of functions to run before and after fork. *prepare calls are called in LI-FC order. *parent and child calls are called in FI-FC order. diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h index d027830d4..e810530e0 100644 --- a/winsup/cygwin/thread.h +++ b/winsup/cygwin/thread.h @@ -270,10 +270,12 @@ public: HANDLE win32_obj_id; LONG condwaits; int pshared; + class pthread_mutex * next; int Lock (); int TryLock (); int UnLock (); + void fixup_after_fork (); pthread_mutex (unsigned short); pthread_mutex (pthread_mutexattr *); @@ -299,9 +301,11 @@ public: /* to allow atomic behaviour for cond_broadcast */ pthread_mutex_t cond_access; HANDLE win32_obj_id; + class pthread_cond * next; int TimedWait (DWORD dwMilliseconds); void BroadCast (); void Signal (); + void fixup_after_fork (); pthread_cond (pthread_condattr *); ~pthread_cond (); @@ -319,10 +323,13 @@ class semaphore:public verifyable_object { public: HANDLE win32_obj_id; + class semaphore * next; int shared; + long currentvalue; void Wait (); void Post (); int TryWait (); + void fixup_after_fork (); semaphore (int, unsigned int); ~semaphore (); @@ -358,8 +365,11 @@ public: // list of mutex's. USE THREADSAFE INSERTS AND DELETES. class pthread_mutex * mutexs; + class pthread_cond * conds; + class semaphore * semaphores; void Init (int); + void fixup_after_fork (void); MTinterface ():reent_index (0), indexallocated (0), threadcount (1) {