* thread.cc: Add a temporary workaround to help Cygwin along while
newlib doesn't install cleanup handlers. Explain the problem. (class __cygwin_lock_handler): New class. (__cygwin_lock_cleanup): New function. (__cygwin_lock_lock): Push __cygwin_lock_cleanup thread cleanup handler. (__cygwin_lock_trylock): Ditto. (__cygwin_lock_unlock): Pop thread cleanup handler. (pthread::pop_cleanup_handler): Temporarily allow cleanup function to destroy cleanup handler so we can pop in another function than we pushed in.
This commit is contained in:
parent
86b35406f2
commit
bff08077a6
|
@ -1,3 +1,17 @@
|
||||||
|
2012-05-23 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
|
* thread.cc: Add a temporary workaround to help Cygwin along while
|
||||||
|
newlib doesn't install cleanup handlers. Explain the problem.
|
||||||
|
(class __cygwin_lock_handler): New class.
|
||||||
|
(__cygwin_lock_cleanup): New function.
|
||||||
|
(__cygwin_lock_lock): Push __cygwin_lock_cleanup thread cleanup
|
||||||
|
handler.
|
||||||
|
(__cygwin_lock_trylock): Ditto.
|
||||||
|
(__cygwin_lock_unlock): Pop thread cleanup handler.
|
||||||
|
(pthread::pop_cleanup_handler): Temporarily allow cleanup function to
|
||||||
|
destroy cleanup handler so we can pop in another function than we
|
||||||
|
pushed in.
|
||||||
|
|
||||||
2012-05-23 Corinna Vinschen <corinna@vinschen.de>
|
2012-05-23 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
* thread.cc (pthread::cancel): Only allow asynchronous cancellation
|
* thread.cc (pthread::cancel): Only allow asynchronous cancellation
|
||||||
|
|
|
@ -95,24 +95,86 @@ __cygwin_lock_fini (_LOCK_T *lock)
|
||||||
pthread_mutex_destroy ((pthread_mutex_t*) lock);
|
pthread_mutex_destroy ((pthread_mutex_t*) lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define WORKAROUND_NEWLIB
|
||||||
|
|
||||||
|
#ifdef WORKAROUND_NEWLIB
|
||||||
|
/* FIXME:
|
||||||
|
|
||||||
|
This cleanup stuff is necessary to harden Cygwin against thread
|
||||||
|
cancellation. In theory, installing a cleanup handler is the task of
|
||||||
|
the calling function.
|
||||||
|
|
||||||
|
The problem here is that a lot of calling functions are in newlib's
|
||||||
|
stdio implementation. So, the right thing to do would be to change
|
||||||
|
newlib's stdio functions to install the required pthread cleanup
|
||||||
|
handlers.
|
||||||
|
|
||||||
|
This is a bigger task than it sounds, so, as a temporary workaround,
|
||||||
|
what we do here is to install a cleanup handler in the lock function
|
||||||
|
itself and to cleanup in the unlock function. This works around the
|
||||||
|
problem for the time being. */
|
||||||
|
class __cygwin_lock_handler : public __pthread_cleanup_handler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
pthread_mutex_t *lock;
|
||||||
|
|
||||||
|
__cygwin_lock_handler (__cleanup_routine_type _fn, _LOCK_T *_lock)
|
||||||
|
{
|
||||||
|
function = _fn;
|
||||||
|
arg = this;
|
||||||
|
next = NULL;
|
||||||
|
lock = (pthread_mutex_t *) _lock;
|
||||||
|
}
|
||||||
|
void *operator new (size_t) __attribute__ ((nothrow))
|
||||||
|
{return cmalloc (HEAP_BUF, sizeof (__cygwin_lock_handler));}
|
||||||
|
void operator delete (void *p) { cfree (p); }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
__cygwin_lock_cleanup (void *hdl)
|
||||||
|
{
|
||||||
|
__cygwin_lock_handler *cleanup = (__cygwin_lock_handler *) hdl;
|
||||||
|
pthread_mutex_unlock (cleanup->lock);
|
||||||
|
delete cleanup;
|
||||||
|
}
|
||||||
|
#endif /* WORKAROUND_NEWLIB */
|
||||||
|
|
||||||
extern "C" void
|
extern "C" void
|
||||||
__cygwin_lock_lock (_LOCK_T *lock)
|
__cygwin_lock_lock (_LOCK_T *lock)
|
||||||
{
|
{
|
||||||
paranoid_printf ("threadcount %d. locking", MT_INTERFACE->threadcount);
|
paranoid_printf ("threadcount %d. locking", MT_INTERFACE->threadcount);
|
||||||
|
#ifdef WORKAROUND_NEWLIB
|
||||||
|
__cygwin_lock_handler *cleanup
|
||||||
|
= new __cygwin_lock_handler (__cygwin_lock_cleanup, lock);
|
||||||
|
pthread::self ()->push_cleanup_handler (cleanup);
|
||||||
|
#endif /* WORKAROUND_NEWLIB */
|
||||||
pthread_mutex_lock ((pthread_mutex_t*) lock);
|
pthread_mutex_lock ((pthread_mutex_t*) lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" int
|
extern "C" int
|
||||||
__cygwin_lock_trylock (_LOCK_T *lock)
|
__cygwin_lock_trylock (_LOCK_T *lock)
|
||||||
{
|
{
|
||||||
|
#ifdef WORKAROUND_NEWLIB
|
||||||
|
__cygwin_lock_handler *cleanup
|
||||||
|
= new __cygwin_lock_handler (__cygwin_lock_cleanup, lock);
|
||||||
|
pthread::self ()->push_cleanup_handler (cleanup);
|
||||||
|
int ret = pthread_mutex_trylock ((pthread_mutex_t*) lock);
|
||||||
|
if (ret)
|
||||||
|
pthread::self ()->pop_cleanup_handler (0);
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
return pthread_mutex_trylock ((pthread_mutex_t*) lock);
|
return pthread_mutex_trylock ((pthread_mutex_t*) lock);
|
||||||
|
#endif /* WORKAROUND_NEWLIB */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" void
|
extern "C" void
|
||||||
__cygwin_lock_unlock (_LOCK_T *lock)
|
__cygwin_lock_unlock (_LOCK_T *lock)
|
||||||
{
|
{
|
||||||
|
#ifdef WORKAROUND_NEWLIB
|
||||||
|
pthread::self ()->pop_cleanup_handler (1);
|
||||||
|
#else
|
||||||
pthread_mutex_unlock ((pthread_mutex_t*) lock);
|
pthread_mutex_unlock ((pthread_mutex_t*) lock);
|
||||||
|
#endif /* WORKAROUND_NEWLIB */
|
||||||
paranoid_printf ("threadcount %d. unlocked", MT_INTERFACE->threadcount);
|
paranoid_printf ("threadcount %d. unlocked", MT_INTERFACE->threadcount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1101,10 +1163,22 @@ pthread::pop_cleanup_handler (int const execute)
|
||||||
if (cleanup_stack != NULL)
|
if (cleanup_stack != NULL)
|
||||||
{
|
{
|
||||||
__pthread_cleanup_handler *handler = cleanup_stack;
|
__pthread_cleanup_handler *handler = cleanup_stack;
|
||||||
|
#ifdef WORKAROUND_NEWLIB
|
||||||
|
/* We split out handler->next so we can set cleanup_stack to handler->next
|
||||||
|
without relying on handler still existing. This allows to delete the
|
||||||
|
handler in the handler function. For a description why we need that,
|
||||||
|
at least temporarly, see the comment preceeding the definition of
|
||||||
|
__cygwin_lock_handler earlier in this file. */
|
||||||
|
__pthread_cleanup_handler *next = handler->next;
|
||||||
|
|
||||||
|
if (execute)
|
||||||
|
(*handler->function) (handler->arg);
|
||||||
|
cleanup_stack = next;
|
||||||
|
#else
|
||||||
if (execute)
|
if (execute)
|
||||||
(*handler->function) (handler->arg);
|
(*handler->function) (handler->arg);
|
||||||
cleanup_stack = handler->next;
|
cleanup_stack = handler->next;
|
||||||
|
#endif /* WORKAROUND_NEWLIB */
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex.unlock ();
|
mutex.unlock ();
|
||||||
|
|
Loading…
Reference in New Issue