Blame src/regression/pthread_cond-smasher.c

Szabolcs Nagy 195a19
// by Jens Gustedt from http://www.openwall.com/lists/musl/2014/08/11/1
Szabolcs Nagy 195a19
// c11 threads test was removed and t_error messages were added
Szabolcs Nagy 195a19
// the test deadlocks with a broken cond var implementation so
Szabolcs Nagy 195a19
// cond_waits were changed to cond_timedwaits with short timeout
Szabolcs Nagy 195a19
#include <stdio.h>
Szabolcs Nagy 195a19
#include <string.h>
Szabolcs Nagy 195a19
#include <time.h>
Szabolcs Nagy 195a19
#include <stdlib.h>
Szabolcs Nagy 195a19
#include <errno.h>
Szabolcs Nagy 195a19
#include "test.h"
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
# include <pthread.h>
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
# define VERSION "POSIX threads"
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
typedef pthread_mutex_t mutex;
Szabolcs Nagy 195a19
typedef pthread_cond_t condition;
Szabolcs Nagy 195a19
typedef pthread_t thread;
Szabolcs Nagy 195a19
typedef void* thread_ret;
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
# define mutex_init(M) pthread_mutex_init((M), 0)
Szabolcs Nagy 195a19
# define mutex_destroy pthread_mutex_destroy
Szabolcs Nagy 195a19
# define mutex_lock pthread_mutex_lock
Szabolcs Nagy 195a19
# define mutex_unlock pthread_mutex_unlock
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
# define condition_init(C) pthread_cond_init((C), 0)
Szabolcs Nagy 195a19
# define condition_destroy pthread_cond_destroy
Szabolcs Nagy 195a19
# define condition_wait pthread_cond_wait
Szabolcs Nagy 195a19
# define condition_timedwait pthread_cond_timedwait
Szabolcs Nagy 195a19
# define condition_signal pthread_cond_signal
Szabolcs Nagy 195a19
# define condition_broadcast pthread_cond_broadcast
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
# define thread_create(ID, START, ARG) pthread_create(ID, 0, START, ARG)
Szabolcs Nagy 195a19
# define thread_join pthread_join
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
# define gettime(TS) clock_gettime(CLOCK_REALTIME, (TS))
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
# define errorstring strerror
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
#ifdef __GLIBC__
Szabolcs Nagy 195a19
# define LIBRARY "glibc"
Szabolcs Nagy 195a19
#else
Szabolcs Nagy 195a19
# define LIBRARY "unidentified"
Szabolcs Nagy 195a19
#endif
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
#define trace2(L, ...) fprintf(stderr, __FILE__ ":" #L ": " __VA_ARGS__)
Szabolcs Nagy 195a19
#define trace1(L, ...) trace2(L, __VA_ARGS__)
Szabolcs Nagy 195a19
#ifdef DEBUG
Szabolcs Nagy 195a19
# define trace(...) trace1(__LINE__, __VA_ARGS__)
Szabolcs Nagy 195a19
#else
Szabolcs Nagy 195a19
# define trace(...) do { if (0) trace1(__LINE__, __VA_ARGS__); } while (0)
Szabolcs Nagy 195a19
#endif
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
//#define tell(...) trace1(__LINE__, __VA_ARGS__)
Szabolcs Nagy 195a19
#define tell(...) trace(__VA_ARGS__)
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
enum {
Szabolcs Nagy 195a19
  phases = 10,
Szabolcs Nagy 195a19
  threads = 10,
Szabolcs Nagy 195a19
};
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
static thread id[threads];
Szabolcs Nagy 195a19
static unsigned args[threads];
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
static mutex mut[phases];
Szabolcs Nagy 195a19
static unsigned inside[phases];
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
static condition cond_client;
Szabolcs Nagy 195a19
static condition cond_main;
Szabolcs Nagy 195a19
static unsigned volatile phase;
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
static void settimeout(struct timespec *ts)
Szabolcs Nagy 195a19
{
Szabolcs Nagy 195a19
  if (clock_gettime(CLOCK_REALTIME, ts))
Szabolcs Nagy ac9368
    t_error("clock_gettime failed: %s\n", strerror(errno));
Szabolcs Nagy 195a19
  ts->tv_nsec += 500*1000*1000;
Szabolcs Nagy 195a19
}
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
static thread_ret client(void *arg) {
Szabolcs Nagy 195a19
  struct timespec ts;
Szabolcs Nagy 195a19
  unsigned * number = arg;
Szabolcs Nagy 195a19
  for (unsigned i = 0; i < phases; ++i) {
Szabolcs Nagy 195a19
    trace("thread %u in phase %u\n", *number, i);
Szabolcs Nagy 195a19
    mutex_lock(&mut[i]);
Szabolcs Nagy 195a19
    ++inside[i];
Szabolcs Nagy 195a19
    if (inside[i] == threads) {
Szabolcs Nagy 195a19
      trace("thread %u is last, signalling main\n", *number);
Szabolcs Nagy 195a19
      int ret = condition_signal(&cond_main);
Szabolcs Nagy 195a19
      trace("thread %u is last, signalling main, %s\n", *number, errorstring(ret));
Szabolcs Nagy 195a19
      if (ret)
Szabolcs Nagy 195a19
        t_error("thread %u is last in phase %u, signalling main failed: %s\n", *number, i, errorstring(ret));
Szabolcs Nagy 195a19
    }
Szabolcs Nagy 195a19
    while (i == phase) {
Szabolcs Nagy 195a19
      tell("thread %u in phase %u (%u), waiting\n", *number, i, phase);
Szabolcs Nagy 195a19
      settimeout(&ts);
Szabolcs Nagy 195a19
      int ret = condition_timedwait(&cond_client, &mut[i], &ts);
Szabolcs Nagy 195a19
      trace("thread %u in phase %u (%u), finished, %s\n", *number, i, phase, errorstring(ret));
Szabolcs Nagy 195a19
      if (ret) {
Szabolcs Nagy 195a19
        t_error("thread %u in phase %u (%u) finished waiting: %s\n", *number, i, phase, errorstring(ret));
Szabolcs Nagy 195a19
        exit(t_status);
Szabolcs Nagy 195a19
      }
Szabolcs Nagy 195a19
    }
Szabolcs Nagy 195a19
    int ret = mutex_unlock(&mut[i]);
Szabolcs Nagy 195a19
    trace("thread %u in phase %u (%u), has unlocked mutex: %s\n", *number, i, phase, errorstring(ret));
Szabolcs Nagy 195a19
    if (ret)
Szabolcs Nagy 195a19
      t_error("thread %u in phase %u (%u), failed to unlock: %s\n", *number, i, phase, errorstring(ret));
Szabolcs Nagy 195a19
  }
Szabolcs Nagy 195a19
  return 0;
Szabolcs Nagy 195a19
}
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
int main(void) {
Szabolcs Nagy 195a19
  struct timespec ts;
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
  tell("start up of main, using %s, library %s\n", VERSION, LIBRARY);
Szabolcs Nagy 195a19
  condition_init(&cond_client);
Szabolcs Nagy 195a19
  condition_init(&cond_main);
Szabolcs Nagy 195a19
  for (unsigned i = 0; i < phases; ++i) {
Szabolcs Nagy 195a19
    mutex_init(&mut[i]);
Szabolcs Nagy 195a19
  }
Szabolcs Nagy 195a19
  mutex_lock(&mut[0]);
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
  for (unsigned i = 0; i < threads; ++i) {
Szabolcs Nagy 195a19
    args[i] = i;
Szabolcs Nagy 195a19
    thread_create(&id[i], client, &args[i]);
Szabolcs Nagy 195a19
  }
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
  while (phase < phases) {
Szabolcs Nagy 195a19
    while (inside[phase] < threads) {
Szabolcs Nagy 195a19
      trace("main seeing %u threads in phase %u, waiting\n", inside[phase], phase);
Szabolcs Nagy 195a19
      settimeout(&ts);
Szabolcs Nagy 195a19
      int ret = condition_timedwait(&cond_main, &mut[phase], &ts);
Szabolcs Nagy 195a19
      tell("main seeing %u threads in phase %u, %s\n", inside[phase], phase, errorstring(ret));
Szabolcs Nagy 195a19
      if (ret) {
Szabolcs Nagy 195a19
        t_error("main thread in phase %u (%u threads inside), finished waiting: %s\n", phase, inside[phase], errorstring(ret));
Szabolcs Nagy 195a19
        return t_status;
Szabolcs Nagy 195a19
      }
Szabolcs Nagy 195a19
    }
Szabolcs Nagy 195a19
    /* now we know that everybody is waiting inside, lock the next
Szabolcs Nagy 195a19
       mutex, if any, such that nobody can enter the next phase
Szabolcs Nagy 195a19
       without our permission. */
Szabolcs Nagy 195a19
    if (phase < phases-1)
Szabolcs Nagy 195a19
      mutex_lock(&mut[phase+1]);
Szabolcs Nagy 195a19
    /* Now signal all clients, update the phase count and release the
Szabolcs Nagy 195a19
       mutex they are waiting for. */
Szabolcs Nagy 195a19
    int ret = condition_broadcast(&cond_client);
Szabolcs Nagy 195a19
    trace("main has broadcast to %u: %s\n", phase, errorstring(ret));
Szabolcs Nagy 195a19
    if (ret)
Szabolcs Nagy 195a19
      t_error("main broadcast in phase %u failed: %s\n", phase, errorstring(ret));
Szabolcs Nagy 195a19
    ++phase;
Szabolcs Nagy 195a19
    ret = mutex_unlock(&mut[phase-1]);
Szabolcs Nagy 195a19
    trace("main has unlocked mutex %u: %s\n", phase-1, errorstring(ret));
Szabolcs Nagy 195a19
    if (ret)
Szabolcs Nagy 195a19
      t_error("main failed to unlock mutex %u: %s\n", phase-1, errorstring(ret));
Szabolcs Nagy 195a19
  }
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
  trace("main finished loop\n");
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
  for (unsigned i = 0; i < threads; ++i) {
Szabolcs Nagy 195a19
    trace("main joining thread %u\n", i);
Szabolcs Nagy 195a19
    int ret = thread_join(id[i], &(thread_ret){0});
Szabolcs Nagy 195a19
    trace("main joining thread %u: %s\n", i, errorstring(ret));
Szabolcs Nagy 195a19
    if (ret)
Szabolcs Nagy 195a19
      t_error("main failed join thread %u: %s\n", i, errorstring(ret));
Szabolcs Nagy 195a19
  }
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
  /* C functions to destroy the control structures don't return error
Szabolcs Nagy 195a19
     information, so we can't check for errors, here. */
Szabolcs Nagy 195a19
  for (unsigned i = 0; i < phases; ++i) {
Szabolcs Nagy 195a19
    mutex_destroy(&mut[i]);
Szabolcs Nagy 195a19
  }
Szabolcs Nagy 195a19
  condition_destroy(&cond_main);
Szabolcs Nagy 195a19
  condition_destroy(&cond_client);
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
  tell("shut down of main, using %s, library %s\n", VERSION, LIBRARY);
Szabolcs Nagy 195a19
Szabolcs Nagy 195a19
  return t_status;
Szabolcs Nagy 195a19
}