Mailing-List: contact cygwin-help AT sourceware DOT cygnus DOT com; run by ezmlm List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT sources DOT redhat DOT com Delivered-To: mailing list cygwin AT sources DOT redhat DOT com Message-ID: <008b01c0c13d$313003d0$0200a8c0@lifelesswks> From: "Robert Collins" To: =?iso-8859-1?Q?Ren=E9_M=F8ller_Fonseca?= Cc: References: <3AD1A64D DOT 7DC36DF0 AT mip DOT sdu DOT dk> <012a01c0c0f1$baf65110$0200a8c0 AT lifelesswks> <3AD1D41D DOT 2FC62EF1 AT mip DOT sdu DOT dk> Subject: Re: contribution soapbox(was Re: G++ guru's please comment - Re: FW: pthread_create problem in Cygwin 1.1.8-2]) Date: Tue, 10 Apr 2001 07:36:51 +1000 MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 8bit X-Priority: 3 X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook Express 5.50.4133.2400 X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4133.2400 X-OriginalArrivalTime: 09 Apr 2001 21:30:20.0329 (UTC) FILETIME=[4735F190:01C0C13C] ----- Original Message ----- From: "René Møller Fonseca" To: "Robert Collins" Cc: Sent: Tuesday, April 10, 2001 1:24 AM Subject: Re: contribution soapbox(was Re: G++ guru's please comment - Re: FW: pthread_create problem in Cygwin 1.1.8-2]) > Hi Robert, > > The tricky part is to make pthread_once MT-safe without doing a busy > wait. I just had this pointed out by another reader as well. Win32 does provide the tools to do this. I'm about to code it up and I'll drop the revised version to the list.. > > Your code is not MT-safe; more than one thread can enter init_routine. > > I'm not familiar with the requirements of pthread_once but I'm expecting > the following to be true: > > 1. Only one thread may enter init_routine (otherwise the "once" suffix > doesn't make any sense). Yes. > 2. if init_routine is currently being run by some thread then all other > threads must block until the function has completed. No. This could deadlock an application. Also pthread_once is cancellable if init_routine is cancelable, which means that we cannot suspend the other threads. Most of the pthreads functions are designed around the early low level unix scheduling environment, thus they are often easily implemented 1-1 with Win32 calls. The hard ones are ones that specify a particular scheduling algorithm. Rob > > > Here is my implementation of pthread_once using busy waiting. If > init_routine takes a long time then busy waiting becomes very bad :-( Thanks for helping. > > >>>> > typedef struct {unsigned int state; unsigned int lock;} pthread_once_t; > > #define PTHREAD_ONCE_INIT {0, 0} Unfortunately this is wrong. PTHREAD_ONCE_INIT has to take no parameters. pthread_once_t is opaque to the user so pthread_once_init can be anything we want. > > inline unsigned int pthread_once_try_lock(pthread_once_t* once_control) > { > register unsigned int previous; > asm volatile ("xchgl %0, %1" : "=&r" (previous), "=m" > (once_control->lock) : "0" (1)); > return !previous; > } Win32 has Interlocked* functions that expand to pretty much what you've got there. > > int __pthread_once(pthread_once_t* once_control, void (*init_routine) > (void)) { > if (!once_control->state) { // should init_routine possible be called > by this thread > while (!pthread_once_try_lock(once_control)); // wait for exclusive > lock > // only one thread can be here at any time > if (!once_control->state) { // should this thread run init_routine > init_routine(); > once_control->state = 1; // make sure init_routine is not called > again > } > once_control->lock = 0; // release lock > } > return 0; > } > <<<< > > Warning: I have not checked and optimized it thoroughly. > > P.S. I have put the code in the attachment! > > René > Here's my V2. (PTHREAD_ONCE_INIT is defined as 0x0001) int __pthread_once (pthread_once_t * once_control, void (*init_routine) (void)) { if (InterlockedDecrement(once_control)!=0) { InterlockIncrement(once_control); return 0; } init_routine(); /* cancel test will go here when canceability states are implemneted */ /* if (init_routine was canceled) InterlockIncrement(once_control); */ return 0; } As you can see, there's no busy wait. Given that reads are atomic, an alternative implementation could check a flag, and then wait for a mutex or condition variable, but there's no need for a mutex here. Rob -- Want to unsubscribe from this list? Check out: http://cygwin.com/ml/#unsubscribe-simple