[gnutls-devel] [TLS] multiple clients in one process
Patrick Pelletier
code at funwithsoftware.org
Sun Dec 1 20:04:59 CET 2013
On 11/30/13, 1:00 AM, Nikos Mavrogiannopoulos wrote:
> On Fri, 2013-11-29 at 18:00 -0600, Nico Williams wrote:
>> See http://stackoverflow.com/questions/3555859/is-it-possible-to-do-static-initialization-of-mutexes-in-windows
> That looks interesting thanks.
My preferred way of handling this on Windows is similar, but uses a
CRITICAL_SECTION instead of a mutex, because CRITICAL_SECTIONs are
handled in userspace if possible, much like pthread mutexes are on Linux.
--Patrick
-------------- next part --------------
/**
* Return *loc after executing a memory barrier.
*/
#define ob_atomic_pointer_ref(loc) (MemoryBarrier(), *(loc))
/**
* Set *loc to \a shall_be, and then execute a memory barrier.
*/
#define ob_atomic_pointer_set(loc, shall_be) \
do \
{ *(loc) = (shall_be); \
MemoryBarrier (); \
} while (0)
/**
* If *loc equals \a was, then set *loc to \a shall_be and return
* true. Otherwise, leave *loc unchanged and return false.
*/
#define ob_atomic_pointer_compare_and_swap(loc, was, shall_be) \
ob_private_atomic_pointer_compare_and_swap ((void**) (loc), (was), (shall_be))
static inline bool
ob_private_atomic_pointer_compare_and_swap (void **loc, void *was, void *shall_be)
{ return (was == InterlockedCompareExchangePointer (loc, shall_be, was));
}
/**
* Windows critical sections seem to have a problem; you have
* to initialize them with InitializeCriticalSection() before
* you can use them. If you want to protect a global object, and
* are worried about the "initialization order fiasco":
* http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12
* then there's no good time to initialize it.
*
* This function solves that problem by using atomic ops to make
* sure the critical section gets initialized before the first
* time it is used. (Unfortunately, DeleteCriticalSection will
* never be called, but I think that's okay for objects of global
* scope, because the OS should reclaim the resources on program
* termination.)
*
* To use it, have a global/static variable of type "void *"
* that represents your critical section. (Which will start out
* as NULL.) Then call ob_fetch_critical() with the address of
* your void * variable whenever you want to use the critical
* section. You'll get back a pointer to the critical section,
* which will be allocated and initialized if necessary.
*/
CRITICAL_SECTION *ob_fetch_critical (void **vpp)
{ void *vp = ob_atomic_pointer_ref (vpp);
if (!vp)
{ CRITICAL_SECTION *cs = (CRITICAL_SECTION *)
calloc (1, sizeof (CRITICAL_SECTION));
if (!cs || !InitializeCriticalSectionAndSpinCount (cs, 4000))
{ free (cs);
return NULL;
}
if (ob_atomic_pointer_compare_and_swap (vpp, NULL, cs))
vp = cs; // we won
else
{ // somebody else beat us to it, so deallocate our critical
// section, because it didn't "win"
DeleteCriticalSection (cs);
free (cs);
vp = ob_atomic_pointer_ref (vpp); // get the guy who did win
}
}
return (CRITICAL_SECTION *) vp;
}
More information about the Gnutls-devel
mailing list