Tue Sep 11 18:15:00 2001 Robert Collins <rbtcollins@hotmail.com>
* 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.
This commit is contained in:
parent
c4b7e16dd9
commit
f9229ef74b
@ -1,3 +1,26 @@
|
|||||||
|
Tue Sep 11 18:15:00 2001 Robert Collins <rbtcollins@hotmail.com>
|
||||||
|
|
||||||
|
* 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 <cgf@cygnus.com>
|
Sun Sep 9 22:11:27 2001 Christopher Faylor <cgf@cygnus.com>
|
||||||
|
|
||||||
* dtable.cc (dtable::fixup_after_fork): Use SetStdHandle appropriately
|
* dtable.cc (dtable::fixup_after_fork): Use SetStdHandle appropriately
|
||||||
|
@ -70,7 +70,7 @@ int cygwin_finished_initializing;
|
|||||||
unsigned NO_COPY int signal_shift_subtract = 1;
|
unsigned NO_COPY int signal_shift_subtract = 1;
|
||||||
|
|
||||||
ResourceLocks _reslock NO_COPY;
|
ResourceLocks _reslock NO_COPY;
|
||||||
MTinterface _mtinterf NO_COPY;
|
MTinterface _mtinterf;
|
||||||
|
|
||||||
bool NO_COPY _cygwin_testing;
|
bool NO_COPY _cygwin_testing;
|
||||||
|
|
||||||
|
@ -309,6 +309,8 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls)
|
|||||||
if ((*t)->clear_on_fork ())
|
if ((*t)->clear_on_fork ())
|
||||||
(*t)->set ();
|
(*t)->set ();
|
||||||
|
|
||||||
|
user_data->threadinterface->fixup_after_fork ();
|
||||||
|
|
||||||
/* Initialize signal/process handling */
|
/* Initialize signal/process handling */
|
||||||
sigproc_init ();
|
sigproc_init ();
|
||||||
__pthread_atforkchild ();
|
__pthread_atforkchild ();
|
||||||
|
@ -302,6 +302,10 @@ MTinterface::Init (int forked)
|
|||||||
if (forked)
|
if (forked)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
mutexs = NULL;
|
||||||
|
conds = NULL;
|
||||||
|
semaphores = NULL;
|
||||||
|
|
||||||
/*possible the atfork lists should be inited here as well */
|
/*possible the atfork lists should be inited here as well */
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -313,6 +317,33 @@ MTinterface::Init (int forked)
|
|||||||
#endif
|
#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),
|
pthread::pthread ():verifyable_object (PTHREAD_MAGIC), win32_obj_id (0),
|
||||||
cancelstate (0), canceltype (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)
|
if (!this->win32_obj_id)
|
||||||
magic = 0;
|
magic = 0;
|
||||||
|
/* threadsafe addition is easy */
|
||||||
|
next = (pthread_cond *)InterlockedExchangePointer (&MT_INTERFACE->conds, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_cond::~pthread_cond ()
|
pthread_cond::~pthread_cond ()
|
||||||
@ -409,6 +442,17 @@ pthread_cond::~pthread_cond ()
|
|||||||
if (win32_obj_id)
|
if (win32_obj_id)
|
||||||
CloseHandle (win32_obj_id);
|
CloseHandle (win32_obj_id);
|
||||||
pthread_mutex_destroy (&cond_access);
|
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
|
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)
|
pthread_key::pthread_key (void (*destructor) (void *)):verifyable_object (PTHREAD_KEY_MAGIC)
|
||||||
{
|
{
|
||||||
dwTlsIndex = TlsAlloc ();
|
dwTlsIndex = TlsAlloc ();
|
||||||
@ -536,6 +595,13 @@ pthread_key::get ()
|
|||||||
*Isn't duplicated, it's reopened.
|
*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)
|
pthread_mutex::pthread_mutex (pthread_mutexattr *attr):verifyable_object (PTHREAD_MUTEX_MAGIC)
|
||||||
{
|
{
|
||||||
/*attr checked in the C call */
|
/*attr checked in the C call */
|
||||||
@ -552,6 +618,8 @@ pthread_mutex::pthread_mutex (pthread_mutexattr *attr):verifyable_object (PTHREA
|
|||||||
magic = 0;
|
magic = 0;
|
||||||
condwaits = 0;
|
condwaits = 0;
|
||||||
pshared = PTHREAD_PROCESS_PRIVATE;
|
pshared = PTHREAD_PROCESS_PRIVATE;
|
||||||
|
/* threadsafe addition is easy */
|
||||||
|
next = (pthread_mutex *)InterlockedExchangePointer (&MT_INTERFACE->mutexs, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex::~pthread_mutex ()
|
pthread_mutex::~pthread_mutex ()
|
||||||
@ -559,6 +627,17 @@ pthread_mutex::~pthread_mutex ()
|
|||||||
if (win32_obj_id)
|
if (win32_obj_id)
|
||||||
CloseHandle (win32_obj_id);
|
CloseHandle (win32_obj_id);
|
||||||
win32_obj_id = NULL;
|
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
|
int
|
||||||
@ -579,6 +658,21 @@ pthread_mutex::UnLock ()
|
|||||||
return ReleaseMutex (win32_obj_id);
|
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),
|
pthread_mutexattr::pthread_mutexattr ():verifyable_object (PTHREAD_MUTEXATTR_MAGIC),
|
||||||
pshared (PTHREAD_PROCESS_PRIVATE), mutextype (PTHREAD_MUTEX_DEFAULT)
|
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)
|
if (!this->win32_obj_id)
|
||||||
magic = 0;
|
magic = 0;
|
||||||
this->shared = pshared;
|
this->shared = pshared;
|
||||||
|
currentvalue = value;
|
||||||
|
/* threadsafe addition is easy */
|
||||||
|
next = (semaphore *)InterlockedExchangePointer (&MT_INTERFACE->semaphores, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
semaphore::~semaphore ()
|
semaphore::~semaphore ()
|
||||||
{
|
{
|
||||||
if (win32_obj_id)
|
if (win32_obj_id)
|
||||||
CloseHandle (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
|
void
|
||||||
semaphore::Post ()
|
semaphore::Post ()
|
||||||
{
|
{
|
||||||
long pc;
|
/* we can't use the currentvalue, because the wait functions don't let us access it */
|
||||||
ReleaseSemaphore (win32_obj_id, 1, &pc);
|
ReleaseSemaphore (win32_obj_id, 1, NULL);
|
||||||
|
currentvalue++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -618,14 +727,27 @@ semaphore::TryWait ()
|
|||||||
*/
|
*/
|
||||||
if (WaitForSingleObject (win32_obj_id, 0) == WAIT_TIMEOUT)
|
if (WaitForSingleObject (win32_obj_id, 0) == WAIT_TIMEOUT)
|
||||||
return EAGAIN;
|
return EAGAIN;
|
||||||
else
|
currentvalue--;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
semaphore::Wait ()
|
semaphore::Wait ()
|
||||||
{
|
{
|
||||||
WaitForSingleObject (win32_obj_id, INFINITE);
|
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):
|
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.
|
/*Register a set of functions to run before and after fork.
|
||||||
*prepare calls are called in LI-FC order.
|
*prepare calls are called in LI-FC order.
|
||||||
*parent and child calls are called in FI-FC order.
|
*parent and child calls are called in FI-FC order.
|
||||||
|
@ -270,10 +270,12 @@ public:
|
|||||||
HANDLE win32_obj_id;
|
HANDLE win32_obj_id;
|
||||||
LONG condwaits;
|
LONG condwaits;
|
||||||
int pshared;
|
int pshared;
|
||||||
|
class pthread_mutex * next;
|
||||||
|
|
||||||
int Lock ();
|
int Lock ();
|
||||||
int TryLock ();
|
int TryLock ();
|
||||||
int UnLock ();
|
int UnLock ();
|
||||||
|
void fixup_after_fork ();
|
||||||
|
|
||||||
pthread_mutex (unsigned short);
|
pthread_mutex (unsigned short);
|
||||||
pthread_mutex (pthread_mutexattr *);
|
pthread_mutex (pthread_mutexattr *);
|
||||||
@ -299,9 +301,11 @@ public:
|
|||||||
/* to allow atomic behaviour for cond_broadcast */
|
/* to allow atomic behaviour for cond_broadcast */
|
||||||
pthread_mutex_t cond_access;
|
pthread_mutex_t cond_access;
|
||||||
HANDLE win32_obj_id;
|
HANDLE win32_obj_id;
|
||||||
|
class pthread_cond * next;
|
||||||
int TimedWait (DWORD dwMilliseconds);
|
int TimedWait (DWORD dwMilliseconds);
|
||||||
void BroadCast ();
|
void BroadCast ();
|
||||||
void Signal ();
|
void Signal ();
|
||||||
|
void fixup_after_fork ();
|
||||||
|
|
||||||
pthread_cond (pthread_condattr *);
|
pthread_cond (pthread_condattr *);
|
||||||
~pthread_cond ();
|
~pthread_cond ();
|
||||||
@ -319,10 +323,13 @@ class semaphore:public verifyable_object
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HANDLE win32_obj_id;
|
HANDLE win32_obj_id;
|
||||||
|
class semaphore * next;
|
||||||
int shared;
|
int shared;
|
||||||
|
long currentvalue;
|
||||||
void Wait ();
|
void Wait ();
|
||||||
void Post ();
|
void Post ();
|
||||||
int TryWait ();
|
int TryWait ();
|
||||||
|
void fixup_after_fork ();
|
||||||
|
|
||||||
semaphore (int, unsigned int);
|
semaphore (int, unsigned int);
|
||||||
~semaphore ();
|
~semaphore ();
|
||||||
@ -358,8 +365,11 @@ public:
|
|||||||
|
|
||||||
// list of mutex's. USE THREADSAFE INSERTS AND DELETES.
|
// list of mutex's. USE THREADSAFE INSERTS AND DELETES.
|
||||||
class pthread_mutex * mutexs;
|
class pthread_mutex * mutexs;
|
||||||
|
class pthread_cond * conds;
|
||||||
|
class semaphore * semaphores;
|
||||||
|
|
||||||
void Init (int);
|
void Init (int);
|
||||||
|
void fixup_after_fork (void);
|
||||||
|
|
||||||
MTinterface ():reent_index (0), indexallocated (0), threadcount (1)
|
MTinterface ():reent_index (0), indexallocated (0), threadcount (1)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user