delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2001/04/10/14:47:39

Mailing-List: contact cygwin-help AT sourceware DOT cygnus DOT com; run by ezmlm
List-Subscribe: <mailto:cygwin-subscribe AT sources DOT redhat DOT com>
List-Archive: <http://sources.redhat.com/ml/cygwin/>
List-Post: <mailto:cygwin AT sources DOT redhat DOT com>
List-Help: <mailto:cygwin-help AT sources DOT redhat DOT com>, <http://sources.redhat.com/ml/#faqs>
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" <robert DOT collins AT itdomain DOT com DOT au>
To: =?iso-8859-1?Q?Ren=E9_M=F8ller_Fonseca?= <fonseca AT mip DOT sdu DOT dk>
Cc: <cygwin AT cygwin DOT com>
References: <EA18B9FA0FE4194AA2B4CDB91F73C0EF79B9 AT itdomain002 DOT itdomain DOT net DOT au> <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
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" <fonseca AT mip DOT sdu DOT dk>
To: "Robert Collins" <robert DOT collins AT itdomain DOT com DOT au>
Cc: <cygwin AT cygwin DOT com>
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

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019