[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