Project Home
Project Home
Documents
Documents
Wiki
Wiki
Discussion Forums
Discussions
Project Information
Project Info
Forum Topic - Commit #209305 to libc: (8 Items)
   
Commit #209305 to libc  
I was just reviewing commit log for libc for fun and noticed the following thing.

-----------------------------------------
-			_Mtxinit(&str->_Flock);
-
+			_Mtxinit(&_Mtx);
+			str->_Flock = _Mtx;
-----------------------------------------
The comment says:
PR:63915
CI:cburgess
CI:dbailey
CI:bstecher
CI:acripps

For statically allocated streams (stdio, stderr, stdout etc), multiple
threads are  trying to call fprintf at the same time, and one thread is
attempting to initialise the stream mutex (in InitLocks, there is a
potential window for a race condition, where a second thread may
perform the test for the existence of
the lock, and go on to use it before the first thread has
initialised the mutex completely. This could leave the mutex in an
inconsitent state and even locked
by an owner well after the thread has completed the fprintf operation.

This solution is to ensure that the the stream lock is assigned to the
stream only after initialisation of the mutex has completed.


So my question is: for multiprocessor system where writes can be re-ordered, is not initialization of mutex into a local
 varaible and its assignment to a shared variable potentially as dangerous as initialization in place? What if writes 
will be reordered and for some other thread value in shared varaible still appears before mutex is completely 
initialized? Should not memory barrier be used here to separate these two operations?
Re: Commit #209305 to libc  
There's been a lot of discussion of this general issue as part of PR#
65776 (although I don't recall if anyone brought up re-ordering).

http://community.qnx.com/sf/discussion/do/listPosts/projects.core_os/discussion.osrev.topc6394

My opinion is that _Mtxinit() should include a barrier if any is
required.

On Thu, 2009-03-05 at 15:39 -0500, Oleh Derevenko wrote:
> I was just reviewing commit log for libc for fun and noticed the following thing.
> 
> -----------------------------------------
> -			_Mtxinit(&str->_Flock);
> -
> +			_Mtxinit(&_Mtx);
> +			str->_Flock = _Mtx;
> -----------------------------------------
> The comment says:
> PR:63915
> CI:cburgess
> CI:dbailey
> CI:bstecher
> CI:acripps
> 
> For statically allocated streams (stdio, stderr, stdout etc), multiple
> threads are  trying to call fprintf at the same time, and one thread is
> attempting to initialise the stream mutex (in InitLocks, there is a
> potential window for a race condition, where a second thread may
> perform the test for the existence of
> the lock, and go on to use it before the first thread has
> initialised the mutex completely. This could leave the mutex in an
> inconsitent state and even locked
> by an owner well after the thread has completed the fprintf operation.
> 
> This solution is to ensure that the the stream lock is assigned to the
> stream only after initialisation of the mutex has completed.
> 
> 
> So my question is: for multiprocessor system where writes can be re-ordered, is not initialization of mutex into a 
local varaible and its assignment to a shared variable potentially as dangerous as initialization in place? What if 
writes will be reordered and for some other thread value in shared varaible still appears before mutex is completely 
initialized? Should not memory barrier be used here to separate these two operations?
> 
> 
> _______________________________________________
> OSTech
> http://community.qnx.com/sf/go/post23707
> 
Re: Commit #209305 to libc  
Well, it may include, but just as well it may not. It's not evident from function name and from abstract programming 
logic you can't assume anything about implementation of function that is not even a part of current program unit.
Re: Commit #209305 to libc  
Actually I was suggesting that it should be made so if that isn't
currently the case.  It is good software engineering practice to
encapsulate correctness guarantees.

On Thu, 2009-03-05 at 17:37 -0500, Oleh Derevenko wrote:
> Well, it may include, but just as well it may not. It's not evident from function name and from abstract programming 
logic you can't assume anything about implementation of function that is not even a part of current program unit.
> 
> _______________________________________________
> OSTech
> http://community.qnx.com/sf/go/post23727
> 
Re: Commit #209305 to libc  
No, it doesn't need a barrier instruction. The mutex isn't in the _Mtx
variable, it's in the memory pointed to by the variable. 

On Thu, Mar 05, 2009 at 03:39:38PM -0500, Oleh Derevenko wrote:
> I was just reviewing commit log for libc for fun and noticed the following thing.
> 
> -----------------------------------------
> -			_Mtxinit(&str->_Flock);
> -
> +			_Mtxinit(&_Mtx);
> +			str->_Flock = _Mtx;
> -----------------------------------------
> The comment says:
> PR:63915
> CI:cburgess
> CI:dbailey
> CI:bstecher
> CI:acripps
> 
> For statically allocated streams (stdio, stderr, stdout etc), multiple
> threads are  trying to call fprintf at the same time, and one thread is
> attempting to initialise the stream mutex (in InitLocks, there is a
> potential window for a race condition, where a second thread may
> perform the test for the existence of
> the lock, and go on to use it before the first thread has
> initialised the mutex completely. This could leave the mutex in an
> inconsitent state and even locked
> by an owner well after the thread has completed the fprintf operation.
> 
> This solution is to ensure that the the stream lock is assigned to the
> stream only after initialisation of the mutex has completed.
> 
> 
> So my question is: for multiprocessor system where writes can be re-ordered, is not initialization of mutex into a 
local varaible and its assignment to a shared variable potentially as dangerous as initialization in place? What if 
writes will be reordered and for some other thread value in shared varaible still appears before mutex is completely 
initialized? Should not memory barrier be used here to separate these two operations?
> 
> 
> _______________________________________________
> OSTech
> http://community.qnx.com/sf/go/post23707
> 

-- 
Brian Stecher (bstecher@qnx.com)        QNX Software Systems
phone: +1 (613) 591-0931 (voice)        175 Terence Matthews Cr.
       +1 (613) 591-3579 (fax)          Kanata, Ontario, Canada K2M 1W8
Re: Commit #209305 to libc  
> No, it doesn't need a barrier instruction. The mutex isn't in the _Mtx
> variable, it's in the memory pointed to by the variable. 
> 
Right, but you need to make sure, the memory of mutex is written before the memory of pointer. How can you be sure 
without a barrier?
Re: Commit #209305 to libc  
On Fri, Mar 06, 2009 at 11:07:47AM -0500, Oleh Derevenko wrote:
> > No, it doesn't need a barrier instruction. The mutex isn't in the _Mtx
> > variable, it's in the memory pointed to by the variable. 
> > 
> Right, but you need to make sure, the memory of mutex is written before the memory of pointer. How can you be sure 
without a barrier?

Because we go into the kernel to initialize the mutex and kernel calls
all have (implicit) memory barriers before they come back to user code.

-- 
Brian Stecher (bstecher@qnx.com)        QNX Software Systems
phone: +1 (613) 591-0931 (voice)        175 Terence Matthews Cr.
       +1 (613) 591-3579 (fax)          Kanata, Ontario, Canada K2M 1W8
Re: Commit #209305 to libc  
> Because we go into the kernel to initialize the mutex and kernel calls
> all have (implicit) memory barriers before they come back to user code.

Well, that is a solid argument. :-) I just wanted to make sure you do not initialize mutex in user mode with something 
like PTHRED_MUTEX_INITIALIZER.