
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 I believe there is a mistake in the 'details/lwm_gcc.hpp' and 'details/lwm_linux.hpp' (and possibly the other lightweight_mutex implementation as well -- I haven't looked at them). In both of these files we have a counter (m_.a_) that is initialized to 1. The lock routine is implemented as follows: while( !__exchange_and_add(&m_.a_, -1) ){ __atomic_add(&m_.a_, 1); sched_yield(); } The unlock as: __atomic_add(&m_.a_, 1); This works if there are only two contenders for the lock. It can fail if there are three or more: 1- Thread one takes the lock, putting the counter at 0. 2- Thread two does the __exchange_and_add, fails the test, and then its time time slice expires before the __atomic_add, leaving the counter at -1. 3- Thread three also takes the lock (because !-1 is false). A simple solution is to initialize the counter to zero and replace the above lock by: while( __exchange_and_add(&m_.a_, 1) ){ __atomic_add(&m_.a_, -1); sched_yield(); } and the unlock by: __atomic_add(&m_.a_, -1); This would result in: 1- Thread one takes the lock, putting the counter at 1. 2- Thread two does the __exchange_and_add, fails the test, and then its time slice expires before it can do the __atomic_add, leaving the counter at 2. 3- Thread cannot take the the lock (because 2 is true). - -T - -- Tyson Whitehead (-twhitehe@uwo.ca -- WSC-) Computer Engineer Dept. of Applied Mathematics, Graduate Student- Applied Mathematics University of Western Ontario, GnuPG Key ID# 0x8A2AB5D8 London, Ontario, Canada -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.4 (GNU/Linux) iD8DBQFA5dgwRXbLmIoqtdgRAmbyAJ0aZFZvxn5MXeXyNqSAI63o9EqddQCfTK9p wFAoBbQueoo9hLNhXJtit44= =SPra -----END PGP SIGNATURE-----

Tyson Whitehead wrote:
I believe there is a mistake in the 'details/lwm_gcc.hpp' and 'details/lwm_linux.hpp' (and possibly the other lightweight_mutex implementation as well -- I haven't looked at them).
I am not sure what the status of these are. Are other components supposed to be using these? In addition to what you mentioned, they're broken in other ways:
In both of these files we have a counter (m_.a_) that is initialized to 1. The lock routine is implemented as follows:
while( !__exchange_and_add(&m_.a_, -1) ){ __atomic_add(&m_.a_, 1); sched_yield();
If a low priority thread is preempted by a high priority thread immediately before __atomic_add, and the high priority thread is attempting to grab the spinlock, deadlock is acheived, despite the sched_yield(). I think that spinlocks should not be used in a way other than as an optimization for the non-contended case in an algorithm with fallback to a real synchronization primative. I think it is a bug to do otherwise on most non-realtime systems. Aaron W. LaFramboise
participants (3)
-
Aaron W. LaFramboise
-
Peter Dimov
-
Tyson Whitehead