mirror of https://github.com/lukechilds/node.git
Browse Source
Fixes: https://github.com/nodejs/node/issues/4002 Fixes: https://github.com/nodejs/node/issues/5384 Fixes: https://github.com/nodejs/node/issues/6563 Refs: https://github.com/nodejs/node/issues/2680#issuecomment-213521708 PR-URL: https://github.com/nodejs/node/pull/6796 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Johan Bergström <bugs@bergstroem.nu> Reviewed-By: Myles Borins <myles.borins@gmail.com>v6.x
committed by
Evan Lucas
55 changed files with 962 additions and 550 deletions
@ -0,0 +1,64 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2016, Kari Tristan Helgason <kthelgason@gmail.com> |
||||
|
|
||||
|
Permission to use, copy, modify, and/or distribute this software for any |
||||
|
purpose with or without fee is hereby granted, provided that the above |
||||
|
copyright notice and this permission notice appear in all copies. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef _UV_PTHREAD_BARRIER_ |
||||
|
#define _UV_PTHREAD_BARRIER_ |
||||
|
#include <errno.h> |
||||
|
#include <pthread.h> |
||||
|
#include <semaphore.h> /* sem_t */ |
||||
|
|
||||
|
#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 |
||||
|
|
||||
|
/*
|
||||
|
* To maintain ABI compatibility with |
||||
|
* libuv v1.x struct is padded according |
||||
|
* to target platform |
||||
|
*/ |
||||
|
#if defined(__ANDROID__) |
||||
|
# define UV_BARRIER_STRUCT_PADDING \ |
||||
|
sizeof(pthread_mutex_t) + \ |
||||
|
sizeof(pthread_cond_t) + \ |
||||
|
sizeof(unsigned int) - \ |
||||
|
sizeof(void *) |
||||
|
#elif defined(__APPLE__) |
||||
|
# define UV_BARRIER_STRUCT_PADDING \ |
||||
|
sizeof(pthread_mutex_t) + \ |
||||
|
2 * sizeof(sem_t) + \ |
||||
|
2 * sizeof(unsigned int) - \ |
||||
|
sizeof(void *) |
||||
|
#endif |
||||
|
|
||||
|
typedef struct { |
||||
|
pthread_mutex_t mutex; |
||||
|
pthread_cond_t cond; |
||||
|
unsigned threshold; |
||||
|
unsigned in; |
||||
|
unsigned out; |
||||
|
} _uv_barrier; |
||||
|
|
||||
|
typedef struct { |
||||
|
_uv_barrier* b; |
||||
|
char _pad[UV_BARRIER_STRUCT_PADDING]; |
||||
|
} pthread_barrier_t; |
||||
|
|
||||
|
int pthread_barrier_init(pthread_barrier_t* barrier, |
||||
|
const void* barrier_attr, |
||||
|
unsigned count); |
||||
|
|
||||
|
int pthread_barrier_wait(pthread_barrier_t* barrier); |
||||
|
int pthread_barrier_destroy(pthread_barrier_t *barrier); |
||||
|
|
||||
|
#endif /* _UV_PTHREAD_BARRIER_ */ |
@ -0,0 +1,120 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2016, Kari Tristan Helgason <kthelgason@gmail.com> |
||||
|
|
||||
|
Permission to use, copy, modify, and/or distribute this software for any |
||||
|
purpose with or without fee is hereby granted, provided that the above |
||||
|
copyright notice and this permission notice appear in all copies. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
|
*/ |
||||
|
#include "uv-common.h" |
||||
|
#include "pthread-barrier.h" |
||||
|
|
||||
|
#include <stdlib.h> |
||||
|
#include <assert.h> |
||||
|
|
||||
|
/* TODO: support barrier_attr */ |
||||
|
int pthread_barrier_init(pthread_barrier_t* barrier, |
||||
|
const void* barrier_attr, |
||||
|
unsigned count) { |
||||
|
int rc; |
||||
|
_uv_barrier* b; |
||||
|
|
||||
|
if (barrier == NULL || count == 0) |
||||
|
return EINVAL; |
||||
|
|
||||
|
if (barrier_attr != NULL) |
||||
|
return ENOTSUP; |
||||
|
|
||||
|
b = uv__malloc(sizeof(*b)); |
||||
|
if (b == NULL) |
||||
|
return ENOMEM; |
||||
|
|
||||
|
b->in = 0; |
||||
|
b->out = 0; |
||||
|
b->threshold = count; |
||||
|
|
||||
|
if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0) |
||||
|
goto error2; |
||||
|
if ((rc = pthread_cond_init(&b->cond, NULL)) != 0) |
||||
|
goto error; |
||||
|
|
||||
|
barrier->b = b; |
||||
|
return 0; |
||||
|
|
||||
|
error: |
||||
|
pthread_mutex_destroy(&b->mutex); |
||||
|
error2: |
||||
|
uv__free(b); |
||||
|
return rc; |
||||
|
} |
||||
|
|
||||
|
int pthread_barrier_wait(pthread_barrier_t* barrier) { |
||||
|
int rc; |
||||
|
_uv_barrier* b; |
||||
|
|
||||
|
if (barrier == NULL || barrier->b == NULL) |
||||
|
return EINVAL; |
||||
|
|
||||
|
b = barrier->b; |
||||
|
/* Lock the mutex*/ |
||||
|
if ((rc = pthread_mutex_lock(&b->mutex)) != 0) |
||||
|
return rc; |
||||
|
|
||||
|
/* Increment the count. If this is the first thread to reach the threshold,
|
||||
|
wake up waiters, unlock the mutex, then return |
||||
|
PTHREAD_BARRIER_SERIAL_THREAD. */ |
||||
|
if (++b->in == b->threshold) { |
||||
|
b->in = 0; |
||||
|
b->out = b->threshold - 1; |
||||
|
assert(pthread_cond_signal(&b->cond) == 0); |
||||
|
|
||||
|
pthread_mutex_unlock(&b->mutex); |
||||
|
return PTHREAD_BARRIER_SERIAL_THREAD; |
||||
|
} |
||||
|
/* Otherwise, wait for other threads until in is set to 0,
|
||||
|
then return 0 to indicate this is not the first thread. */ |
||||
|
do { |
||||
|
if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0) |
||||
|
break; |
||||
|
} while (b->in != 0); |
||||
|
|
||||
|
/* mark thread exit */ |
||||
|
b->out--; |
||||
|
pthread_cond_signal(&b->cond); |
||||
|
pthread_mutex_unlock(&b->mutex); |
||||
|
return rc; |
||||
|
} |
||||
|
|
||||
|
int pthread_barrier_destroy(pthread_barrier_t* barrier) { |
||||
|
int rc; |
||||
|
_uv_barrier* b; |
||||
|
|
||||
|
if (barrier == NULL || barrier->b == NULL) |
||||
|
return EINVAL; |
||||
|
|
||||
|
b = barrier->b; |
||||
|
|
||||
|
if ((rc = pthread_mutex_lock(&b->mutex)) != 0) |
||||
|
return rc; |
||||
|
|
||||
|
if (b->in > 0 || b->out > 0) |
||||
|
rc = EBUSY; |
||||
|
|
||||
|
pthread_mutex_unlock(&b->mutex); |
||||
|
|
||||
|
if (rc) |
||||
|
return rc; |
||||
|
|
||||
|
pthread_cond_destroy(&b->cond); |
||||
|
pthread_mutex_destroy(&b->mutex); |
||||
|
uv__free(barrier->b); |
||||
|
barrier->b = NULL; |
||||
|
return 0; |
||||
|
} |
Loading…
Reference in new issue