Search code examples
clinuxmultithreadingcloneportaudio

Linux Clone "kills" main thread


I'm trying to implement threads in C on Linux (with clone(), obviously) but I'm having a weird problem.

First, here are my mutex functions :

void mutex_lock(int* lock) {
  while (!__sync_bool_compare_and_swap(lock, 0, 1)) {
    syscall(SYS_futex, lock, FUTEX_WAIT_PRIVATE, 1, NULL, NULL, 0);
  }
}

void mutex_unlock(int* lock) {
  if (__sync_bool_compare_and_swap(lock, 1, 0)) {
    syscall(SYS_futex, lock, FUTEX_WAKE_PRIVATE, 0, NULL, NULL, 0);
  }
}

And my Thread struct

typedef int (*ThreadCallback)(void*);

typedef struct Thread {

  void* alloc;

  char lockSpace[sizeof(int) * 2]; /* Used to align lock pointer properly */
  int* lock;
  int started;
  int tid;

  void* stack;
  size_t stackSize;

  ThreadCallback fn;
  void* args;

}* Thread;

In my code, I allocate and initialize a Thread struct I will use later

void* start = memAllocThread(sizeof(void*) + sizeof(struct Thread) + TH_STACK_SIZE);
if (start == NULL) {
  return TH_MEM;
}

struct Thread* th = start + TH_STACK_SIZE + sizeof(void*);
th->alloc = start;

size_t lockSpacePtr = (size_t)(th->lockSpace);
lockSpacePtr += 4 - ((lockSpacePtr % 4) % 4); /* To align ptr on? at? 4 bytes */

th->lock = (int*)lockSpacePtr;
*th->lock = 0;
th->started = 0;

th->stack = start + TH_STACK_SIZE;
th->stackSize = TH_STACK_SIZE;

th->fn = fn;
th->args = args;

Where "TH_STACK_SIZE", "fn" and "args" are "0x7fff" "ThreadCallback" and "void*" respectively

Now I have my Thread struct initialized, I initialize PortAudio and the default stream with one input channel and zero output channels. Then I start my thread

THResult thStart(struct Thread* th) {

  int tid;

  mutex_lock(th->lock);

  if (th->started) {
    mutex_unlock(th->lock);
    return TH_RUNNING;
  }

  tid = clone(_thFunction, th->stack, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_IO | CLONE_SIGHAND | CLONE_THREAD, th);

  if (tid < 0) {
    mutex_unlock(th->lock);
    return TH_CLONE_ERRNO;
  }

  th->started = 1;
  th->tid = tid;

  mutex_unlock(th->lock);
  return TH_OK;
}

"int _thFunction(void*)" is currently empty (when filled, it should start th->fn, but there's no problem here)

And now, after a call to Pa_StartStream(), I can write anything I want, it's not executed (and by the way, printf goes wild if I spread some in the code).

  • I tried to track down segment violations
  • I removed Pa_StartStream : It worked but printf was still too wild
  • I removed my thread's start and everything was fine

Any idea ?

EDIT 1 :

  • When the created thread ends, program ends
  • gdb says nothing about that, I tried breakdowns to analyze the stack but nothing wrong with it

Solution

  • I probably figured out why it doesn't work.

    I read about how errno is thread-safe and I think it's because pthreads create thread-local variables (used by the (g)libc) my implementation doesn't.