0

I am using ucontext along with pthread. The below program works OK on Linux, but has failed assertion on Mac.

The problem seems that thread local variables are not correctly accessed after resuming the context from another thread.

The program creates two threads, A and B. A sets the context ready before B could resume the context, for it's synced properly.

It's very appreciated if someone could shed some light on this behavior on mac.

ENV:

clang version 3.7.0  (http://llvm.org/git/llvm.git 8d70064a4ac2ae09b8003173e751cfad9dc15400)
Target: x86_64-apple-darwin13.4.0
Thread model: posix

Program:

#define _XOPEN_SOURCE 800
#include <ucontext.h>
#include <signal.h>

#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <assert.h>

static int flag = 0;

void swap(ucontext_t *old, ucontext_t *new)
{
    int ret = swapcontext(old, new);
    assert(ret == 0);
}

#define SSIZE MINSIGSTKSZ

static char stack[SSIZE];
static ucontext_t a_ctx[2];
static ucontext_t b_ctx[2];

volatile static __thread int bug = 0;

static void func(int b) { }

static void f1 (void)
{
    assert(bug == 0);
    func(bug);
    swap(&a_ctx[1], &a_ctx[0]);
    assert(bug == 1);
}

void *thread_a(void *arg)
{
    printf("A is %lu\n", pthread_self());

    bug = 0;

    ucontext_t ctx = a_ctx[1];

    getcontext(&ctx);
    ctx.uc_stack.ss_sp = stack;
    ctx.uc_stack.ss_size = sizeof stack;
    makecontext(&ctx, f1, 0);

    swap(&a_ctx[0], &ctx);
    __atomic_store_n(&flag, 1, __ATOMIC_RELAXED);
    sleep(1);

    return NULL;
}

void *thread_b(void *arg)
{
    printf("B is %lu\n", pthread_self());

    bug = 1;
    while(__atomic_load_n(&flag, __ATOMIC_RELAXED) == 0) ;
    swap(&b_ctx[0], &a_ctx[1]);

    return NULL;
}

int main(int argc, char **argv)
{
    pthread_t a, b;
    pthread_create(&b, NULL, &thread_b, NULL);
    pthread_create(&a, NULL, &thread_a, NULL);
    pthread_exit(NULL);
}
Albert Netymk
  • 1,102
  • 8
  • 24
  • 1
    Why do you try to use context swtching together with PThreads? – alk Apr 03 '15 at 13:40
  • 1
    From `man swapcontext`: "*SUSv2, POSIX.1-2001. POSIX.1-2008 removes the specifications of makecontext() and swapcontext(), citing portability issues, and recommending that applications be rewritten to use POSIX threads instead.*" – alk Apr 03 '15 at 13:41
  • @alk `ucontext` is used for cooperative scheduling, while `pthread` is for preemptive. Yes, `ucontext` is deprecated, but the different behaviors on linux and mac still feel weird. Maybe I am missing sth. – Albert Netymk Apr 03 '15 at 15:56
  • there seems to be some problems with the code. For instance. threads are properly exited by calling 'thread_exit(value)' not by 'return NULL' and the main() function should be calling thread_join() twice, never calling 'thread_exit()' and then finally exiting with 'return 0' – user3629249 Apr 03 '15 at 16:15
  • since ucontext is depreciated (no longer supported and soon to disappear completely) and the manual says it has portability problems, why are you writing new code using it and then complaining that the resulting code is not portable? – user3629249 Apr 03 '15 at 16:22
  • @user3629249 The manual of `pthread_exit` says `return` is the same to calling `pthread_exit` for non-main thread. Calling `pthread_exit` in main means `pthread_join` and `return 0`. See [SO](http://stackoverflow.com/questions/4298986/is-there-something-to-replace-the-ucontext-h-functions) for why I still use them. – Albert Netymk Apr 03 '15 at 19:23

0 Answers0