From 63ba77a406d44298c891da2174fe4d773945168f Mon Sep 17 00:00:00 2001 From: Martin Stjernholm <mast@lysator.liu.se> Date: Tue, 12 Oct 2010 00:46:24 +0200 Subject: [PATCH] Drastically improved chances of actually switching threads when yielding. This solution still has two weaknesses though: A presumably mostly theoretical one is that it might keep alternating between two threads while starving a third. The other more pertinent one is that it still doesn't handle threads waiting on condvars. Adaption of patch suggested by Artur Skawina. Thanks. --- src/threads.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/threads.c b/src/threads.c index ee584c6e9a..66a9948c19 100644 --- a/src/threads.c +++ b/src/threads.c @@ -365,6 +365,7 @@ PMOD_EXPORT unsigned long thread_yields = 0; #endif static int th_running = 0; static MUTEX_T interpreter_lock; +static MUTEX_T interpreter_lock_wanted; MUTEX_T thread_table_lock; static MUTEX_T interleave_lock; static struct program *mutex_key = 0; @@ -411,7 +412,14 @@ static INLINE void check_interpreter_lock (DLOC_DECL) {} PMOD_EXPORT INLINE void pike_low_lock_interpreter (DLOC_DECL) { + /* The double locking here is to ensure that when a thread releases + * the interpreter lock, a different thread gets it first. Thereby + * we ensure a thread switch in check_threads, if there are other + * threads waiting. */ + mt_lock (&interpreter_lock_wanted); mt_lock (&interpreter_lock); + mt_unlock (&interpreter_lock_wanted); + SET_LOCKING_THREAD; THREADS_FPRINTF (1, (stderr, "Got iplock" DLOC_PF(" @ ",) "\n" COMMA_DLOC_ARGS_OPT)); @@ -422,7 +430,12 @@ PMOD_EXPORT INLINE void pike_low_wait_interpreter (COND_T *cond COMMA_DLOC_DECL) THREADS_FPRINTF (1, (stderr, "Waiting on cond %p without iplock" DLOC_PF(" @ ",) "\n", cond COMMA_DLOC_ARGS_OPT)); + + /* FIXME: Should use interpreter_lock_wanted here as well. The + * problem is that few (if any) thread libs lets us atomically + * unlock a mutex and wait, and then lock a different mutex. */ co_wait (cond, &interpreter_lock); + SET_LOCKING_THREAD; THREADS_FPRINTF (1, (stderr, "Got signal on cond %p with iplock" DLOC_PF(" @ ",) "\n", @@ -437,7 +450,12 @@ PMOD_EXPORT INLINE int pike_low_timedwait_interpreter (COND_T *cond, THREADS_FPRINTF (1, (stderr, "Waiting on cond %p without iplock" DLOC_PF(" @ ",) "\n", cond COMMA_DLOC_ARGS_OPT)); + + /* FIXME: Should use interpreter_lock_wanted here as well. The + * problem is that few (if any) thread libs lets us atomically + * unlock a mutex and wait, and then lock a different mutex. */ res = co_wait_timeout (cond, &interpreter_lock, sec, nsec); + SET_LOCKING_THREAD; THREADS_FPRINTF (1, (stderr, "Got signal on cond %p with iplock" DLOC_PF(" @ ",) "\n", @@ -2866,6 +2884,7 @@ void low_th_init(void) really_low_th_init(); mt_init( & interpreter_lock); + mt_init( & interpreter_lock_wanted); low_mt_lock_interpreter(); mt_init( & thread_table_lock); mt_init( & interleave_lock); -- GitLab