Note that there are some explanatory texts on larger screens.

plurals
  1. POc context switching segfault
    primarykey
    data
    text
    <p>I'm required to simulate threads using context switching and interrupts. I am occasionally (1/25 runs) getting a segfault in my program. I am not really sure what the cause of it is. I suspect it has to do with the manner in which I do the context switching. I've tried determining the reason for the segfault with gdb and valgrind with no success. </p> <p>GDB results:</p> <pre><code>0x0000007b in ?? () (gdb) bt #0 0x0000007b in ?? () (gdb) </code></pre> <p>Valgrind results (not complete):</p> <pre><code> ==6343== Conditional jump or move depends on uninitialised value(s) 8 ==6343== at 0x808F8CA: __linkin_atfork (in my-test) 9 ==6343== by 0x809046B: _dl_non_dynamic_init (in my-test) 10 ==6343== by 0x8090C31: __libc_init_first (in my-test) 11 ==6343== by 0x805EEB0: (below main) (in my-test) 12 ==6343== Uninitialised value was created 13 ==6343== at 0x80900E2: _dl_sysinfo_int80 (in my-test) 14 ==6343== by 0x80C056F: brk (in my-test) 15 ==6343== by 0x808D6C9: sbrk (in my-test) 16 ==6343== by 0x805F1CB: __libc_setup_tls (in my-test) 17 ==6343== by 0x805F3C6: __pthread_initialize_minimal (in my-test) 18 ==6343== by 0x805EE5C: (below main) (in my-test) 19 ==6343== 20 ==6343== Conditional jump or move depends on uninitialised value(s) 21 ==6343== at 0x806C015: malloc (in my-test) 22 ==6343== by 0x809046B: _dl_non_dynamic_init (in my-test) 23 ==6343== by 0x8090C31: __libc_init_first (in my-test) 24 ==6343== by 0x805EEB0: (below main) (in my-test) 25 ==6343== Uninitialised value was created 26 ==6343== at 0x80900E2: _dl_sysinfo_int80 (in my-test) 27 ==6343== by 0x80C056F: brk (in my-test) 28 ==6343== by 0x808D6C9: sbrk (in my-test) 29 ==6343== by 0x805F1CB: __libc_setup_tls (in my-test) 30 ==6343== by 0x805F3C6: __pthread_initialize_minimal (in my-test) 31 ==6343== by 0x805EE5C: (below main) (in my-test) ... ==6343== Warning: client switching stacks? SP change: 0xbee18ea0 --&gt; 0x8135e08 281 ==6343== to suppress, use: --max-stackframe=1228001128 or greater 282 ==6343== Conditional jump or move depends on uninitialised value(s) 283 ==6343== at 0x806C015: malloc (in my-test) 284 ==6343== by 0x804E5D4: mem_resize_fn (in my-test) 285 ==6343== by 0x804A5D1: expand (iin my-test) 286 ==6343== by 0x804B0C4: list_insert (in my-test) 287 ==6343== by 0x804BE7E: list_append_int (in my-test) 288 ==6343== by 0x8049B4D: handler (in my-test) 289 ==6343== by 0x8060B42: makecontext (in my-test) 290 ==6343== by 0x8049AB0: main (in my-test) 291 ==6343== Uninitialised value was created 292 ==6343== at 0x80900E2: _dl_sysinfo_int80 (in my-test) 293 ==6343== by 0x80C056F: brk (in my-test) 294 ==6343== by 0x808D6C9: sbrk (in my-test) 295 ==6343== by 0x805F1CB: __libc_setup_tls (in my-test) 296 ==6343== by 0x805F3C6: __pthread_initialize_minimal (in my-test) 297 ==6343== by 0x805EE5C: (below main) (in my-test) ... ==6343== Warning: client switching stacks? SP change: 0x813da60 --&gt; 0xbee18ea0 385 ==6343== to suppress, use: --max-stackframe=1228032960 or greater 386 ==6343== Use of uninitialised value of size 4 387 ==6343== at 0x804A1E9: scheduler (in my-test) 388 ==6343== by 0x809F617: ??? (in my-test) 389 ==6343== by 0x809F617: ??? (in my-test) 390 ==6343== Uninitialised value was created by a stack allocation 391 ==6343== at 0x8060BD8: swapcontext (in my-test) ... ==6343== Use of uninitialised value of size 4 434 ==6343== at 0x805F644: sigprocmask (in my-test) 435 ==6343== by 0x1FFF: ??? 436 ==6343== by 0x8049B4D: handler (in my-test) 437 ==6343== by 0x8060B42: makecontext (in my-test) 438 ==6343== by 0x8049AB0: main (in my-test) 439 ==6343== Uninitialised value was created by a stack allocation 440 ==6343== at 0x8060BD8: swapcontext (in my-test) 441 ==6343== 442 ==6343== Jump to the invalid address stated on the next line 443 ==6343== at 0x2000: ??? 444 ==6343== by 0x8049B4D: handler (in my-test) 445 ==6343== by 0x8060B42: makecontext (in my-test) 446 ==6343== by 0x8049AB0: main (in my-test) 447 ==6343== Address 0x2000 is not stack'd, malloc'd or (recently) free'd 448 ==6343== 449 ==6343== 450 ==6343== Process terminating with default action of signal 11 (SIGSEGV) 451 ==6343== Bad permissions for mapped region at address 0x2000 452 ==6343== at 0x2000: ??? 453 ==6343== by 0x8049B4D: handler (in my-test) 454 ==6343== by 0x8060B42: makecontext (in my-test) 455 ==6343== by 0x8049AB0: main (in my-test) 456 ==6343== 457 ==6343== HEAP SUMMARY: 458 ==6343== in use at exit: 0 bytes in 0 blocks 459 ==6343== total heap usage: 0 allocs, 0 frees, 0 bytes allocated 460 ==6343== 461 ==6343== All heap blocks were freed -- no leaks are possible 462 ==6343== 463 ==6343== For counts of detected and suppressed errors, rerun with: -v 464 ==6343== ERROR SUMMARY: 114 errors from 38 contexts (suppressed: 0 from 0) </code></pre> <p>my-test.c:</p> <pre><code>/* Includes */ #include &lt;stdio.h&gt; /* Input/Output */ #include &lt;stdlib.h&gt; /* General Utilities */ #include &lt;math.h&gt; #include "mythreads.h" /* prototype for thread routine */ void handler ( ); /* global vars */ /* semaphores are declared global so they can be accessed in main() and in thread routine, here, the semaphore is used as a mutex */ int counter_mutex; /* shared variables */ int counter; double result = 0.0; int main() { int thread_num = 10; int j; char* thread_names[] = { "thread 0", "thread 1", "thread 2", "thread 3", "thread 4", "thread 5", "thread 6", "thread 7", "thread 8", "thread 9" }; /* Initialize MyThreads library. */ mythread_init(); /* 250 ms */ set_quantum_size(500); counter_mutex = create_semaphore(1); for(j=0; j&lt;thread_num; j++) { mythread_create(thread_names[j], (void *) &amp;handler, 6004); } /* Print threads informations before run */ //mythread_state(); /* When this function returns, all threads should have exited. */ runthreads(); destroy_semaphore(counter_mutex); // /* Print threads informations after run */ mythread_state(); printf("The counter is %d\n", counter); printf("The result is %f\n", result); if (counter == 50 &amp;&amp; (result - 151402.656521) &lt; 0.000001) printf("&gt;&gt;&gt; Thread library PASSED the Test 1\n"); exit(0); } void handler () { int i; for(i=0; i &lt; 5; i++) { /* If you remove this protection, you should be able to see different * out of every time you run this program. With this protection, you * should always be able to see result to be 151402.656521 */ semaphore_wait(counter_mutex); /* down semaphore */ /* START CRITICAL REGION */ int j; for (j = 0; j &lt; 1000; j++) { result = result + sin(counter) * tan(counter); } counter++; /* END CRITICAL REGION */ semaphore_signal(counter_mutex); /* up semaphore */ } mythread_exit(); /* exit thread */ } </code></pre> <p>mythreads.h</p> <pre><code>#ifndef __MY_THREADS_H__ #define __MY_THREADS_H__ #include &lt;signal.h&gt; #include &lt;string.h&gt; #include &lt;time.h&gt; #include &lt;sys/time.h&gt; #include &lt;sys/timeb.h&gt; #include &lt;ucontext.h&gt; #include &lt;slack/std.h&gt; #include &lt;slack/list.h&gt; #define THREAD_NAME_LEN 32 #define THREAD_MAX 128 #define SEMAPHORE_MAX 128 #define THREAD_STACK_SIZE 4096 #define QUANTUM_N_SIZE 60000 enum ThreadState { NOTCREATED, RUNNING, RUNNABLE, BLOCKED, EXIT }; typedef struct ControlBlock_t { ucontext_t context; char thread_name[THREAD_NAME_LEN]; int thread_id; enum ThreadState state; struct timespec start; struct timespec end; double run_time; void *stack; } ControlBlock; typedef struct Semaphore_t { List * thread_queue; int value; int initial; int active; } Semaphore; int mythreads_init(); int mythread_create(char *threadname, void (*threadfunc)(), int stacksize); void mythread_exit(); int mythread_id(); void runthreads(); void set_quantum_size(int quantum); int create_semaphore(int value); void semaphore_wait(int semaphore); void semaphore_signal(int semaphore); void destroy_semaphore(int semaphore); void mythread_state(); void evict_thread(); void scheduler(); #endif /* __MY_THREADS_H__ */ </code></pre> <p>mythreads.c</p> <pre><code>#include &lt;stdio.h&gt; #include &lt;signal.h&gt; #include &lt;unistd.h&gt; #include &lt;slack/std.h&gt; #include &lt;slack/list.h&gt; #include "mythreads.h" static ControlBlock tcbTable[THREAD_MAX]; static Semaphore semTable[SEMAPHORE_MAX]; static List * runqueue; static ControlBlock * current_thread; static int threadId = 0; static int runningThreadId = 0; static ucontext_t uctx_main; static int quantum_size; struct itimerval timer; static int current_threads; static int my_threads_init; static int current_semaphores; static int done = 0; static int totalThreadsCreated = 0; static int totalThreadsExited = 0; long long int switch_ctr; int i=0; /* This function initializes all the globa data structures for the thread system */ int mythread_init(){ int i=0; //Initialize the run queue. runqueue = list_create(NULL); //Initialize the thread control table. for(i = 0;i &lt; THREAD_MAX;i++){ tcbTable[i].state = NOTCREATED; } //Initialize the semaphore table. for(i = 0;i &lt; SEMAPHORE_MAX;i++){ semTable[i].active = 0; } } int mythread_create(char *threadName, void(*threadfunc)(), int stacksize){ //Set basic information about the thread. strcpy(tcbTable[threadId].thread_name, threadName); tcbTable[threadId].thread_id = threadId; tcbTable[threadId].state = RUNNABLE; //Set the context information about the thread. getcontext(&amp;tcbTable[threadId].context); //Save the current context. tcbTable[threadId].context.uc_link = &amp;uctx_main; //The context that will be resumed when the current context exits. tcbTable[threadId].stack = malloc(stacksize); tcbTable[threadId].context.uc_stack.ss_sp = tcbTable[threadId].stack; //Allocate the stack and make it point to the beginning of the stack. tcbTable[threadId].context.uc_stack.ss_size = stacksize; //Set the signal stack size. makecontext(&amp;tcbTable[threadId].context,threadfunc,0); //Creates the context with the information set above. //Add thread to the runqueue. runqueue = list_append_int(runqueue,threadId); totalThreadsCreated++; //If an error occured, return -1. Otherwise, return the thread id. if(!tcbTable[threadId].context.uc_stack.ss_sp){ //We failed to allocate memory for the stack printf("Failed to allocate memory for the stack\n"); fflush(stdout); return -1; }else{ int tmp = threadId; threadId++; return tmp; } } /* This function is called at the end of the function that was invoked by the thread. */ void mythread_exit(){ sigset_t x; sigemptyset(&amp;x); sigaddset(&amp;x, SIGALRM); sigprocmask(SIG_BLOCK, &amp;x, NULL); printf("Setting state of thread %d to EXIT.\n",runningThreadId); fflush(stdout); tcbTable[runningThreadId].state = EXIT; //Set the state of the thread to EXIT. totalThreadsExited++; if(totalThreadsCreated == totalThreadsExited){ done = 1; } sigprocmask(SIG_UNBLOCK, &amp;x, NULL); } /* Starts running one of the threads in the runqueue. */ void runthreads(){ /* Block Signals */ sigset_t x; sigemptyset(&amp;x); sigaddset(&amp;x, SIGALRM); sigprocmask(SIG_BLOCK, &amp;x, NULL); struct itimerval timer; timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = quantum_size; timer.it_value.tv_sec = 0; timer.it_value.tv_usec = quantum_size; setitimer(ITIMER_REAL, &amp;timer, 0); sigset(SIGALRM, &amp;scheduler); runningThreadId = list_shift_int(runqueue); tcbTable[runningThreadId].state = RUNNING; //begin_time(running_thread); /* Unblock signal */ sigprocmask(SIG_UNBLOCK, &amp;x, NULL); if(swapcontext(&amp;uctx_main, &amp;tcbTable[runningThreadId].context) == -1) { perror("swapcontext error"); exit(1); } while(!list_empty(semTable[0].thread_queue) || (totalThreadsExited&lt;totalThreadsCreated)); sigprocmask(SIG_BLOCK, &amp;x, NULL); for(i = 0; i &lt; 10 ; i++) { tcbTable[i].state = EXIT; } printf("Back in main\n"); fflush(stdout); } void set_quantum_size(int size){ quantum_size = size; } /* Called when the ALRM signal fires */ void scheduler(){ switch_ctr++; if (list_empty(runqueue) &amp;&amp; tcbTable[runningThreadId].state == EXIT) { printf("returning to main"); fflush(stdout); setcontext(&amp;uctx_main); } if (!list_empty(runqueue) ) { sigset_t x; sigemptyset(&amp;x); sigaddset(&amp;x, SIGALRM); sigprocmask(SIG_BLOCK, &amp;x, NULL); int old_running_thread = runningThreadId; runningThreadId = list_shift_int(runqueue); if (tcbTable[old_running_thread].state == RUNNABLE || tcbTable[old_running_thread].state == RUNNING) { runqueue = list_append_int(runqueue, old_running_thread); } sigprocmask(SIG_UNBLOCK, &amp;x, NULL); if (swapcontext(&amp;tcbTable[old_running_thread].context, &amp;tcbTable[runningThreadId].context) == -1) { printf("swapcontext error"); fflush(stdout); } } } int create_semaphore(int val){ if (current_semaphores == SEMAPHORE_MAX){ //We already have the maximum number of semphores allowed //so we cannot create new ones. return -1; }else{ semTable[current_semaphores].initial = val; semTable[current_semaphores].value = val; semTable[current_semaphores].thread_queue = list_create(NULL); int tmp = current_semaphores; current_semaphores++; return tmp; } } /* Called by the handler() funcion in my-test.c */ void semaphore_wait(int semaphore){ sigset_t x; sigemptyset(&amp;x); sigaddset(&amp;x, SIGALRM); sigprocmask(SIG_BLOCK, &amp;x, NULL); long long int old_switch_ctr = switch_ctr; (semTable[semaphore]).value--; if((semTable[semaphore]).value&lt;0) { (tcbTable[runningThreadId]).state = BLOCKED; (semTable[semaphore]).thread_queue = list_append_int((semTable[semaphore]).thread_queue,runningThreadId); } sigprocmask(SIG_UNBLOCK,&amp;x,NULL); while(old_switch_ctr==switch_ctr); } /* Called by the handler() funcion in my-test.c */ void semaphore_signal(int semaphore){ // Block Signals sigset_t x; sigemptyset (&amp;x); sigaddset(&amp;x, SIGALRM); sigprocmask(SIG_BLOCK, &amp;x, NULL); /* Increase Semaphore value */ semTable[semaphore].value = semTable[semaphore].value + 1; if (semTable[semaphore].value &lt; 1) { int should_run; should_run = list_shift_int(semTable[semaphore].thread_queue); tcbTable[should_run].state = RUNNABLE; runqueue = list_append_int(runqueue, should_run); } // Unblock Signals sigprocmask(SIG_UNBLOCK, &amp;x, NULL); scheduler(); } void destroy_semaphore(int semaphore){ if(!list_empty(semTable[semaphore].thread_queue)){ fprintf(stderr, "There are threads waiting on this semaphore. Thus, it cannot be destroyed\n"); return; } } void mythread_state() { printf("\nTHREADNAME\tTHREAD\tTHREAD STATE\tCPU TIME(ns)\n"); fflush(stdout); int i; for(i = 0; (tcbTable[i].state != NOTCREATED) &amp;&amp; (i &lt; THREAD_MAX); ++i) { char * state_i; switch(tcbTable[i].state) { case 0: state_i = "NOTCREATED"; break; case 1: state_i = "RUNNING"; break; case 2: state_i = "RUNNABLE"; break; case 3: state_i = "RUNNABLE"; break; case 4: state_i = "EXIT"; break; default: state_i = "UNDEFINED"; break; } printf("\n%s\t%d\t%s\t\t%la\n", tcbTable[i].thread_name, i, state_i, tcbTable[i].run_time); } } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload