2011/4/23 Eric Blake <eblake@xxxxxxxxxx>: > mingw lacks the counterpart to PTHREAD_MUTEX_INITIALIZER, so the > best we can do is portably expose once-only runtime initialization. > > * src/util/threads.h (virOnceControlPtr): New opaque type. > (virOnceFunc): New callback type. > (virOnce): New prototype. > * src/util/threads-pthread.h (virOnceControl): Declare. > (VIR_ONCE_CONTROL_INITIALIZER): Define. > * src/util/threads-win32.h (virOnceControl) > (VIR_ONCE_CONTROL_INITIALIZER): Likewise. > * src/util/threads-pthread.c (virOnce): Implement in pthreads. > * src/util/threads-win32.c (virOnce): Implement in WIN32. > * src/libvirt_private.syms: Export it. > --- > > v2: change WIN32 implementation to use lower-level primitives available > to mingw and older windows, rather than higher level but newer INIT_ONCE. > > Meanwhile, I noticed that gnulib has an LGPLv2+ 'lock' module that > provides a lot of multi-threading primitives for both pthreads, pth, > and mingw; maybe we should think about rewriting threads.c in terms > of gnulib and only have one implementation, rather than maintaining > pthread and mingw in parallel? > +int virOnce(virOnceControlPtr once, virOnceFunc func) > +{ > + Â Âif (!once->complete) { > + Â Â Â Âif (InterlockedIncrement(&once->init) == 1) { > + Â Â Â Â Â Â/* We're the first thread. */ > + Â Â Â Â Â Âfunc(); > + Â Â Â Â Â Âonce->complete = 1; > + Â Â Â Â} else { > + Â Â Â Â Â Â/* We're a later thread. ÂDecrement the init counter back > + Â Â Â Â Â Â * to avoid overflow, then yield until the first thread > + Â Â Â Â Â Â * marks that the function is complete. ÂIt is rare that > + Â Â Â Â Â Â * multiple threads will be waiting here, and since each > + Â Â Â Â Â Â * thread is yielding except the first, we should get out > + Â Â Â Â Â Â * soon enough. Â*/ > + Â Â Â Â Â ÂInterlockedDecrement(&once->init); > + Â Â Â Â Â Âwhile (!once->complete) > + Â Â Â Â Â Â Â ÂSleep(0); > + Â Â Â Â} > + Â Â} > + Â Âreturn 0; > +} Compared to the gnulib lock module version, this one is less complex and I don't get why gnulib uses 3 states for the init and complete variables and an additional lock object. The only reason could be to minimize the time busy waiting in the while loop. > + > +struct virOnceControl { > + Â Âlong init; /* 0 at startup, > 0 if init has started */ > + Â Âvolatile long complete; /* 0 until first thread completes callback */ > +}; MSDN docs about InterlockedIncrement suggest that init should be volatile too. ACK, with init marked volatile. Matthias -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list