Mail Archives: cygwin/2001/04/09/13:09:38
--------------BB7DACD615389B0C8EB49F59
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: 8bit
Hi Robert,
The tricky part is to make pthread_once MT-safe without doing a busy
wait.
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).
2. if init_routine is currently being run by some thread then all other
threads must block until the function has completed.
Here is my implementation of pthread_once using busy waiting. If
init_routine takes a long time then busy waiting becomes very bad :-(
>>>>
typedef struct {unsigned int state; unsigned int lock;} pthread_once_t;
#define PTHREAD_ONCE_INIT {0, 0}
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;
}
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é
Robert Collins wrote:
>
> Rene, this isn't pointed at you! I just reread my reply and I realised
> I'd missed an IMO important point.
>
> ----- Original Message -----
> From: "René Mřller Fonseca" <fonseca AT mip DOT sdu DOT dk>
>
> > Please correct me if I'm wrong.
> >
> > The problem, as I understand it, is that gcc is not built with thread
> > support which is required for exception handling to work in a
> > multithreaded environment. Unfortunately the thread support has not
> been
> > ported to the win32 api. I suspect functionality like "pthread_once"
> to
> > be required (tricky to implement).
>
> Guys, Girls, secret service agents,
>
> Contributing to cygwin is not hard. In fact it's dead easy. The biggest
> obstacle is perception. All you need are basic C++ (even straight C will
> do if you're a hacker or just willing to try new things) skills, and a
> small target.
>
> (Non-coders, you are hereby off the coding hook, and onto the why don't
> you contribute your knowledge in the form of feedback on documentation -
> something every open source project can use more of).
>
> I strongly suspect that most of you coders out there are guilty of the
> thought "Gee it would be nice if cygwin had feature foo, but I [wouldn't
> know where to start to fix it|I don't have the time to contribute] so
> I'll just spend hours now working around the lack of foo".
>
> I am guilty of that thought. Then one day I got tired of the the fact
> that I couldn't built squid with thread support, so I ported the thread
> code to win32 threads. During that port I realised just how thin a layer
> cygwin is over win32 - it's hardly there at all. So I threw out the
> win32 threads code, and fixed up what was missing in Cygwin. That core
> fixup took me about twice as long as porting the original code, but I
> can reuse the fixedup cygwin code to port other applications with
> greater ease.
>
> The follow-up to that spurt of coding was that I got tired of the
> lamentations about threads and cygwin and started fixing the entire
> thread support... In fact I've now been labelled the pthreads
> maintainer, which as far as I can tell means that you lot are now
> *allowed* to complain about pthreads!
>
> I want to ask you all to do something for cygwin (and I have no right to
> ask this, but I'm going to anyway): The next time you work around a bug
> in cygwin when porting an application, put aside 2 hours (thats all
> you'll need for most things). Download the cygwin source via CVS. (The
> documentation is accurate). Build it. Add your feature, or a tweak to an
> existing feature, or even just the outline code to return ENOSYS - no
> supported for the relevant function call. Send that in with a Changelog.
> You've now become a contributor, and saved yourself sending in a patch
> to the application developers for cygwin compatability, all by changing
> cygwin. And in future, chances are someone else will add to what you've
> done, and finish off your partial code, or tweak it even more.
>
> Rob.
>
> P.S. To support my claim about perception being the issue, here is the
> code for the diffucult function pthread_once.
>
> int
> __pthread_once (pthread_once_t * once_control, void (*init_routine)
> (void))
> {
> if (*once_control!=PTHREAD_ONCE_INIT)
> init_routine();
> *once_control=!PTHREAD_ONCE_INIT;
> return 0;
> }
>
> And most of the cygwin internal functions are not much longer.
>
> --
> Want to unsubscribe from this list?
> Check out: http://cygwin.com/ml/#unsubscribe-simple
--------------BB7DACD615389B0C8EB49F59
Content-Type: text/plain; charset=us-ascii;
name="main.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="main.c"
#include <stdio.h>
typedef struct {unsigned int state; unsigned int lock;} pthread_once_t;
#define PTHREAD_ONCE_INIT {0, 0}
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;
}
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
printf("D: state=%d lock=%d\n", once_control->state, once_control->lock);
init_routine();
once_control->state = 1; // make sure init_routine is not called again
}
once_control->lock = 0; // release lock
}
return 0;
}
void myfunction() {
printf("I'm only executed once\n");
}
int main() {
pthread_once_t once= PTHREAD_ONCE_INIT;
printf("A: state=%d lock=%d\n", once.state, once.lock);
__pthread_once(&once, &myfunction);
printf("B: state=%d lock=%d\n", once.state, once.lock);
__pthread_once(&once, &myfunction);
printf("C: state=%d lock=%d\n", once.state, once.lock);
return 0;
}
--------------BB7DACD615389B0C8EB49F59
Content-Type: text/plain; charset=us-ascii
--
Want to unsubscribe from this list?
Check out: http://cygwin.com/ml/#unsubscribe-simple
--------------BB7DACD615389B0C8EB49F59--
- Raw text -