Skip to content

Instantly share code, notes, and snippets.

@DaoWen
Last active March 29, 2017 06:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DaoWen/c2bb8c1b7ae75791255a46e2a0682d94 to your computer and use it in GitHub Desktop.
Save DaoWen/c2bb8c1b7ae75791255a46e2a0682d94 to your computer and use it in GitHub Desktop.
consistently segfaults in pthread_create on os x but not on linux
#include <assert.h>
#include <pthread.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#define N 10
#define RCHECK(expr) \
do { \
int _rcheck_expr_return_value = expr; \
if (_rcheck_expr_return_value != 0) { \
fprintf(stderr, "FAILED CALL: " #expr "\n"); \
abort(); \
} \
} while (0);
typedef struct wait_state_st {
volatile intptr_t val;
pthread_t other;
pthread_mutex_t lock;
pthread_cond_t cond;
struct wait_state_st *next;
} wait_state;
pthread_mutex_t wait_list_lock = PTHREAD_MUTEX_INITIALIZER;
wait_state *wait_list_head = NULL;
volatile int active = 0;
static inline void push_thread(wait_state *ws) {
RCHECK(pthread_mutex_lock(&wait_list_lock));
ws->next = wait_list_head;
wait_list_head = ws;
RCHECK(pthread_mutex_unlock(&wait_list_lock));
}
static inline wait_state *pop_thread(void) {
wait_state *ws = NULL;
while (true) {
RCHECK(pthread_mutex_lock(&wait_list_lock));
if (wait_list_head) {
ws = wait_list_head;
wait_list_head = ws->next;
}
RCHECK(pthread_mutex_unlock(&wait_list_lock));
if (ws) return ws;
usleep(1000);
}
assert(!"UNREACHABLE");
}
intptr_t thread_suspend(int count) {
intptr_t sum = 0;
// WAIT TO BE WOKEN UP "count" TIMES
for (int i = 0; i < count; i++) {
wait_state ws;
ws.val = -1;
ws.other = pthread_self();
RCHECK(pthread_mutex_init(&ws.lock, NULL));
RCHECK(pthread_cond_init(&ws.cond, NULL));
RCHECK(pthread_mutex_lock(&ws.lock));
push_thread(&ws);
while (ws.val < 0) {
RCHECK(pthread_cond_wait(&ws.cond, &ws.lock));
}
assert(ws.other != pthread_self());
pthread_join(ws.other, NULL);
sum += ws.val;
RCHECK(pthread_mutex_unlock(&ws.lock));
}
return sum;
}
void thread_signal(intptr_t x) {
// wake up the suspended thread
__sync_fetch_and_add(&active, -1);
wait_state *ws = pop_thread();
RCHECK(pthread_mutex_lock(&ws->lock));
ws->val = x;
ws->other = pthread_self();
RCHECK(pthread_cond_signal(&ws->cond));
RCHECK(pthread_mutex_unlock(&ws->lock));
}
void *fib(void *arg) {
intptr_t n = (intptr_t)arg;
if (n > 1) {
pthread_t t1, t2;
__sync_fetch_and_add(&active, 2);
RCHECK(pthread_create(&t1, NULL, fib, (void *)(n - 1)));
RCHECK(pthread_create(&t2, NULL, fib, (void *)(n - 2)));
intptr_t sum = thread_suspend(2);
thread_signal(sum);
}
else {
thread_signal(n);
}
return NULL;
}
intptr_t pure_fib(intptr_t n) {
if (n < 2) return n;
return pure_fib(n-1) + pure_fib(n-2);
}
int main(int argc, char *argv[]) {
printf("EXPECTED = %" PRIdPTR "\n", pure_fib(N));
assert("START" && wait_list_head == NULL);
active = 1;
pthread_t t;
RCHECK(pthread_create(&t, NULL, fib, (void *)N));
while (active > 0) { usleep(100000); }
intptr_t sum = thread_suspend(1);
printf("SUM = %" PRIdPTR "\n", sum);
printf("DONE %p\n", wait_list_head);
assert("END" && wait_list_head == NULL);
return 0;
}
@sitsofe
Copy link

sitsofe commented Mar 29, 2017

I wonder if the problem described in http://stackoverflow.com/a/36774524 is being triggered here...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment