Hi Ludovic, > Let me rephrase it: what can happen is that, during the tick, another > thread could actually take M, increase `M->level' and mark itself as the > owner. After the tick, our primary thread takes `M->lock' back, > thinking it now owns M, and goes to sleep; but M is actually already > taken by that other thread, so our primary thread never wakes up. (Not > sure this description is any clearer...)
Almost, but not quite. Let me try again: Thread A wants to lock fat_mutex M. It seizes the administrative lock M->lock and examines the state of M. M is held by thread B, so thread A prepares to put itself onto the blocking queue for M by calling `SCM_TICK'. In order to call `SCM_TICK', thread A must temporarily release M->lock. When it does this, thread B, the owner of M, seizes M->lock and releases M, which involves waking up the next waiting thread on the blocking queue for M -- but thread A hasn't finished doing the tick and so isn't on the blocking queue. Thread B releases M->lock and goes about its business. Thread A finishes the tick and seizes M->lock again and adds itself to the blocking queue for M without re-examining M's state. The only way thread A can ever wake up after this is if another thread locks and releases M. > I guess it can be applied to 1.8 as well? I would say so, yes. I'll make a patch against it if you tell me how to do that with git. :) > Another question: why is there this mixture of `scm_i_pthread' and > `scm_i_scm_pthread' calls? The scm_i_pthread_* functions are actually preprocessor #defines that map directly onto pthreads API functions. The scm_i_scm_pthread_* functions are wrappers around pthreads functions that could block -- the wrappers leave Guile mode before calling into pthreads. pthread_mutex_lock can block, so from Guile mode (e.g., from fat_mutex_lock), it needs to be called via scm_i_scm_pthread_mutex_lock; but pthread_mutex_unlock can't block, so it can be called directly via scm_i_pthread_mutex_unlock. Is that what you were asking? Regards, Julian