Skip to content

Instantly share code, notes, and snippets.

@wilx
Last active February 1, 2016 01:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wilx/bb77de5d3f554afedd79 to your computer and use it in GitHub Desktop.
Save wilx/bb77de5d3f554afedd79 to your computer and use it in GitHub Desktop.
possible reimplementation of pthread_barrier* API for Cygwin
#include <pthread.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#define faux_LIKELY(X) __builtin_expect (!!(X), 1)
#define faux_UNLIKELY(X) __builtin_expect (!!(X), 0)
struct faux_pthread_barrierattr_t_struct
{
unsigned magic;
int shared;
};
typedef struct faux_pthread_barrierattr_t_struct faux_pthread_barrierattr_t;
#define faux_PTHREAD_BARRIERATTR_MAGIC \
((0xBAu << 24) \
| (((unsigned)(unsigned char)'R') << 16) \
| (((unsigned)(unsigned char)'R') << 8) \
| 0x1Au)
#define faux_PTHREAD_PROCESS_SHARED (1)
#define faux_PTHREAD_PROCESS_PRIVATE (0)
int
faux_pthread_barrierattr_init (faux_pthread_barrierattr_t * battr)
{
if (faux_UNLIKELY(battr == NULL))
return EINVAL;
battr->shared = faux_PTHREAD_PROCESS_PRIVATE;
battr->magic = faux_PTHREAD_BARRIERATTR_MAGIC;
return 0;
}
int
faux_pthread_barrierattr_setpshared (faux_pthread_barrierattr_t * battr, int shared)
{
if (faux_UNLIKELY(battr == NULL
|| battr->magic != faux_PTHREAD_BARRIERATTR_MAGIC))
return EINVAL;
if (faux_UNLIKELY(shared != faux_PTHREAD_PROCESS_SHARED
&& shared != faux_PTHREAD_PROCESS_PRIVATE))
return EINVAL;
battr->shared = shared;
return 0;
}
int
faux_pthread_barrierattr_getpshared (const faux_pthread_barrierattr_t * restrict battr,
int * restrict shared)
{
if (faux_UNLIKELY(battr == NULL
|| battr->magic != faux_PTHREAD_BARRIERATTR_MAGIC
|| shared == NULL))
return EINVAL;
*shared = battr->shared;
return 0;
}
int
faux_pthread_barrierattr_destroy (faux_pthread_barrierattr_t * battr)
{
if (faux_UNLIKELY(battr == NULL
|| battr->magic != faux_PTHREAD_BARRIERATTR_MAGIC))
return EINVAL;
battr->magic = 0;
return 0;
}
#define faux_PTHREAD_BARRIER_MAGIC \
((0xBAu << 24) \
| (((unsigned)(unsigned char)'R') << 16) \
| (((unsigned)(unsigned char)'R') << 8) \
| 0x1Eu)
struct faux_pthread_barrier_t_struct
{
unsigned magic;
pthread_mutex_t mtx; /* Mutex protecting everything below. */
pthread_cond_t cond; /* Conditional variable to wait on. */
unsigned cnt; /* Barrier count. Threads to wait for. */
uint64_t cyc; /* Cycle count. */
unsigned wt; /* Already waiting threads count. */
};
typedef struct faux_pthread_barrier_t_struct faux_pthread_barrier_t;
#define faux_PTHREAD_BARRIER_SERIAL_THREAD (-1)
int
faux_pthread_barrier_init (faux_pthread_barrier_t * bar,
const faux_pthread_barrierattr_t * attr,
unsigned count)
{
(void)attr;
pthread_mutex_t * mutex = NULL;
if (faux_UNLIKELY(bar == NULL
|| (attr != NULL
&& (attr->magic != faux_PTHREAD_BARRIERATTR_MAGIC
|| attr->shared == faux_PTHREAD_PROCESS_SHARED))
|| count == 0))
return EINVAL;
int retval = pthread_mutex_init (&bar->mtx, NULL);
if (faux_UNLIKELY(retval != 0))
return retval;
retval = pthread_cond_init (&bar->cond, NULL);
if (faux_UNLIKELY(retval != 0))
{
(void)pthread_mutex_destroy (mutex);
return retval;
}
bar->cnt = count;
bar->cyc = 0;
bar->wt = 0;
bar->magic = faux_PTHREAD_BARRIER_MAGIC;
return 0;
}
int
faux_pthread_barrier_destroy (faux_pthread_barrier_t * bar)
{
if (faux_UNLIKELY(bar == NULL
|| bar->magic != faux_PTHREAD_BARRIER_MAGIC))
return EINVAL;
if (faux_UNLIKELY(bar->wt != 0))
return EBUSY;
int retval = pthread_cond_destroy (&bar->cond);
if (faux_UNLIKELY(retval != 0))
return retval;
retval = pthread_mutex_destroy (&bar->mtx);
if (faux_UNLIKELY(retval != 0))
return retval;
bar->cnt = 0;
bar->cyc = 0;
bar->wt = 0;
bar->magic = 0;
return 0;
}
int
faux_pthread_barrier_wait (faux_pthread_barrier_t * bar)
{
if (faux_UNLIKELY(bar == NULL
|| bar->magic != faux_PTHREAD_BARRIER_MAGIC))
return EINVAL;
int retval = pthread_mutex_lock (&bar->mtx);
if (faux_UNLIKELY(retval != 0))
return retval;
if (faux_UNLIKELY(bar->wt >= bar->cnt))
abort ();
if (faux_UNLIKELY(++bar->wt == bar->cnt))
{
++bar->cyc;
/* This is the last thread to reach the barrier. Signal the waiting
threads to wake up and continue. */
retval = pthread_cond_broadcast (&bar->cond);
if (faux_UNLIKELY(retval != 0))
goto cond_error;
bar->wt = 0;
retval = pthread_mutex_unlock (&bar->mtx);
if (faux_UNLIKELY(retval != 0))
abort ();
return faux_PTHREAD_BARRIER_SERIAL_THREAD;
}
else
{
uint64_t cycle = bar->cyc;
do
{
retval = pthread_cond_wait (&bar->cond, &bar->mtx);
if (faux_UNLIKELY(retval != 0))
goto cond_error;
}
while (faux_UNLIKELY(cycle == bar->cyc));
retval = pthread_mutex_unlock (&bar->mtx);
if (faux_UNLIKELY(retval != 0))
abort ();
return 0;
}
cond_error:
{
--bar->wt;
int ret = pthread_mutex_unlock (&bar->mtx);
if (faux_UNLIKELY(ret != 0))
abort ();
return retval;
}
}
faux_pthread_barrier_t barrier;
#define ROUNDS 5
void *
thread_routine (void * arg)
{
int myid = (ptrdiff_t)arg;
for (int round = 0; round != ROUNDS; ++round)
{
printf ("Thread %d reporting for duty. Going to wait on barrier. Round %d.\n",
myid, round);
int retval = faux_pthread_barrier_wait (&barrier);
if (retval == faux_PTHREAD_BARRIER_SERIAL_THREAD)
printf ("I, number %d, was the last thread to make it to the barrier. Round %d.\n",
myid, round);
else if (retval != 0)
printf ("I, number %d, got error %d on barrier. Round %d.\n",
myid, retval, round);
else
printf ("I, number %d, got released by the barrier. Round %d.\n",
myid, round);
}
return NULL;
}
#define COUNT 5
pthread_t threads[COUNT];
int
main ()
{
faux_pthread_barrierattr_t battr;
int retval = faux_pthread_barrierattr_init (&battr);
if (retval != 0)
{
printf ("Failed to initialize barrier attribute: %d", retval);
return retval;
}
retval = faux_pthread_barrierattr_setpshared (&battr, faux_PTHREAD_PROCESS_SHARED);
if (retval != 0)
{
printf ("Failed to set faux_PTHREAD_PROCESS_SHARED on barrier attribute: %d\n",
retval);
return retval;
}
retval = faux_pthread_barrierattr_setpshared (&battr, faux_PTHREAD_PROCESS_PRIVATE);
if (retval != 0)
{
printf ("Failed to set faux_PTHREAD_PROCESS_PRIVATE on barrier attribute: %d\n",
retval);
return retval;
}
retval = faux_pthread_barrier_init (&barrier, &battr, COUNT);
if (retval != 0)
{
printf ("Failed to init barrier: %d\n", retval);
return retval;
}
retval = faux_pthread_barrierattr_destroy (&battr);
if (retval != 0)
{
printf ("Failed to destroy barrier attribute: %d\n", retval);
return retval;
}
for (int i = 0; i != COUNT; ++i)
{
retval = pthread_create(&threads[i], NULL, thread_routine,
(void*)(ptrdiff_t)i);
if (retval != 0)
{
printf ("Failed to create thread %d, error %d.\n", i, retval);
return retval;
}
}
for (int i = 0; i != COUNT; ++i)
{
retval = pthread_join (threads[i], NULL);
if (retval != 0)
{
printf ("Failed to join thread %d, error %d.\n", i, retval);
return retval;
}
}
retval = faux_pthread_barrier_destroy (&barrier);
if (retval != 0)
{
printf ("Failed to destroy barrier: %d\n", retval);
return retval;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment