c - Segmentation fault after swapcontext in alarm handler -
basically trying simulate multithreading on single thread context switching. set alarm every 10 microseconds, , switch context 1 thread. problem 1 in 5 runs ends seg fault right after alarm finishes swapcontext, @ least traced gdb.
here source files main.c
#include "umt.h" void f() { int x = 10; printf("starting thread\n"); while(x) { printf("thread %d\n", x); sleep(1); x--; } } int main() { int x = 0, y, z; umt_init(); y = umt_thread_create(f); printf("starting main\n"); if(y == 0) { printf("problems creating thread\n"); return; } x = 10; z = 1; while(x) { printf("main\n"); x--; } umt_thread_join(y); printf("done waiting\n"); return 0; }
umt.h
#include <sys/time.h> #include <stdio.h> #include <signal.h> #include <ucontext.h> #include <stdlib.h> #define true 1 #define false 0 typedef struct _umt_thread { int thread_id; ucontext_t context; void (*handler)(void); int hasfinished; }umt_thread, *pumt_thread; void umt_init(); int umt_thread_create(void (*handler)(void)); void umt_thread_join(int thr);
and umt.c
#include "umt.h" #define main_context 0 #define stack_size 1638400 int currentthread; char threadpool[15]; pumt_thread threads; void signal_thread_finish(); void thread_handler() { threads[currentthread].handler(); signal_thread_finish(); } void thread_scheduler(); void signal_thread_finish() { threads[currentthread].hasfinished = true; threadpool[currentthread] = 0; thread_scheduler(); } void thread_scheduler() { int nextthread = 0, curthread = 0; int x = 0; ucontext_t *con1, *con2; nextthread = currentthread + 1; while(1) { if(nextthread == 15) nextthread = 0; if(nextthread == currentthread) break; if(threadpool[nextthread] == 1) break; nextthread++; } if(nextthread == currentthread) return; curthread = currentthread; currentthread = nextthread; con1 = &(threads[curthread].context); con2 = &(threads[nextthread].context); x = swapcontext(con1, con2); } void umt_init() { ucontext_t context; struct itimerval mytimer; int i; stack_t new_stack; getcontext(&context); threads = (pumt_thread)malloc(sizeof(umt_thread) * 15); threads[main_context].thread_id = main_context; threads[main_context].context = context; threadpool[main_context] = 1; for(i = 1;i<15;i++) { threadpool[i] = 0; } currentthread = 0; new_stack.ss_sp = (char*)malloc(stack_size); new_stack.ss_size = stack_size; new_stack.ss_flags = 0; = sigaltstack(&new_stack, null); if(i != 0) { printf("problems assigning new stack signaling\n"); } signal(sigalrm, thread_scheduler); mytimer.it_interval.tv_sec = 0; mytimer.it_interval.tv_usec = 10; mytimer.it_value.tv_sec = 0; mytimer.it_value.tv_usec = 5; setitimer(itimer_real, &mytimer, 0); } int umt_thread_create(void (*handler)(void)) { ucontext_t context; int i, pos; for(i = 1;i<15;i++) { if(threadpool[i] == 0) { pos = i; break; } } if(i == 15) { printf("no empty space in threadpool\n"); return -1; } if(getcontext(&context) == -1) { printf("problems getting context\n"); return 0; } context.uc_link = 0;//&(threads[main_context].context); context.uc_stack.ss_sp = (char*)malloc(stack_size); if(context.uc_stack.ss_sp == null) { printf("problems allocating stack\n"); } context.uc_stack.ss_size = stack_size; context.uc_stack.ss_flags = 0; makecontext(&context, thread_handler, 0); threads[pos].thread_id = pos; threads[pos].context = context; threads[pos].handler = handler; threads[pos].hasfinished = false; threadpool[pos] = 1; printf("created thread on pos %d\n", pos); return pos; } void umt_thread_join(int tid) { while(!threads[tid].hasfinished) { } }
i tried lot of combinations , tried tracing instruction not arrive conclusion or idea might cause seg fault. thanks
few issues see (some related segfault + other comments)
you scheduler (thread_scheduler) should in critical section, e.g. should block alarm signals (or ignore them) handing of threadpool done in way doesn't corrupt it. can either use sigprocmask or volatile boolean variable silence alarm (note not same user threads mutex, internal synchronization scheduling logic)
your clock ticks way fast imho, in micro seconds, not milliseconds, 1000 microseconds tv_usec might make more sense testing purposes.
small stack sizes might cause seg fault seems stack big enough.
p.s. there better way handle join, waste lot's of cpu cycles on it, why not avoid switching thread called join, untill thread it's waiting has terminated?
Comments
Post a Comment