]> Zhao Yanbai Git Server - minix.git/commitdiff
ddekit:use ucontext to switch threads
authorKees Jongenburger <kees.jongenburger@gmail.com>
Mon, 24 Mar 2014 15:55:57 +0000 (16:55 +0100)
committerLionel Sambuc <lionel@minix3.org>
Mon, 28 Jul 2014 15:05:22 +0000 (17:05 +0200)
Use getcontext/makecontext and setcontext to create/modify and
switch thread when using ddekit.

Change-Id: I485ad61cb2eb5b8e7b486775f282ff6501912dfd

lib/libddekit/src/thread.c
lib/libddekit/src/thread.h

index c8b2ba141701fd93b630e057374d722fbddb3acd..2aa800e0ac975de8c76d7a048610fcd7e9a30bcb 100644 (file)
@@ -5,11 +5,14 @@
 #include <ddekit/panic.h>
 #include <ddekit/timer.h>
 
+
 #ifdef DDEBUG_LEVEL_THREAD
 #undef DDEBUG
 #define DDEBUG DDEBUG_LEVEL_THREAD
 #endif
 
+//#define DDEBUG DDEBUG_VERBOSE
+
 #include "debug.h"
 #include "util.h"
 #include "thread.h"
@@ -80,7 +83,7 @@ ddekit_thread_create(void (*fun)(void *), void *arg, const char *name)
 {
        ddekit_thread_t *th  =  
          (ddekit_thread_t *) ddekit_simple_malloc(sizeof(ddekit_thread_t));
-
+       memset(th,0,sizeof(ddekit_thread_t));
        strncpy(th->name, name, DDEKIT_THREAD_NAMELEN); 
        th->name[DDEKIT_THREAD_NAMELEN-1] = 0;
        
@@ -94,32 +97,14 @@ ddekit_thread_create(void (*fun)(void *), void *arg, const char *name)
        th->next = NULL;
        th->sleep_sem = ddekit_sem_init(0);
 
-       
-       /* setup stack */
-
-       void **ptr = (void **)(th->stack + DDEKIT_THREAD_STACKSIZE);
-       *(--ptr) = th;
-       --ptr;
-       --ptr;
-
-       /* TAKEN FROM P_THREAD (written by david?)*/
-#ifdef __ACK__
-    th->jb[0].__pc = _ddekit_thread_start;
-    th->jb[0].__sp = ptr;
-#else /* !__ACK__ */
-#include <sys/jmp_buf.h>
-#if defined(JB_PC) && defined(JB_SP)
-    /* um, yikes. */
-
-    *((void (**)(void))(&((char *)th->jb)[JB_PC])) =
-           (void *)_ddekit_thread_start;
-
-    *((void **)(&((char *)th->jb)[JB_SP])) = ptr;
-#else
-#error "Unsupported Minix architecture"
-#endif
-#endif /* !__ACK__ */
-
+       /* Setup thread context */
+       th->ctx.uc_flags |= _UC_IGNSIGM | _UC_IGNFPU;
+       if (getcontext(&th->ctx) != 0) {
+               panic("ddekit thread create thread getcontext error");
+       }
+       th->ctx.uc_stack.ss_sp = th->stack;/* makecontext will determine sp */
+       th->ctx.uc_stack.ss_size = DDEKIT_THREAD_STACKSIZE;
+       makecontext(&th->ctx,_ddekit_thread_start,1 /* argc */,th /* pass thread as argument */);
        DDEBUG_MSG_VERBOSE("created thread %s, stack at: %p\n", name,
            th->stack + DDEKIT_THREAD_STACKSIZE);
        _ddekit_thread_enqueue(th);
@@ -159,7 +144,7 @@ ddekit_thread_t *ddekit_thread_myself(void)
 ddekit_thread_t *ddekit_thread_setup_myself(const char *name) {
        ddekit_thread_t *th  =  
          (ddekit_thread_t *) ddekit_simple_malloc(sizeof(ddekit_thread_t));
-
+       memset(th,0,sizeof(ddekit_thread_t));
        strncpy(th->name, name, DDEKIT_THREAD_NAMELEN); 
        th->name[DDEKIT_THREAD_NAMELEN-1] = 0;
        th->stack = NULL;
@@ -341,14 +326,30 @@ void _ddekit_thread_schedule()
 
        /* get our tcb */
        ddekit_thread_t * th = current;
+       volatile int is_callback;
 
 #if DDEBUG >= 4
        _ddekit_print_backtrace(th);
 #endif
-
+       /* getcontext saves the current context in ctx. When setcontext is called
+        * with that ctx it will return execution at getcontext here. To
+        * discriminate between the initial call to getcontext that simply returns
+        * and the situation where getcontext returns because of a setcontext call
+        * we use the is_callback variable.
+        *
+        * When the program flow passes via the assignment bellow it will enter
+        * the scheduling loop and set is_callback to 1. When the function returns
+        * because of a setcontext call the program skip the scheduling and return
+        * from this method to continue normal execution.
+        */
+       is_callback =0;
        /* save our context */
-       if (_setjmp(th->jb) == 0) {
-       
+       th->ctx.uc_flags |= _UC_IGNSIGM | _UC_IGNFPU;
+       if (getcontext(&th->ctx) != 0){
+               panic("ddekit thread schedule getcontext error");
+       }
+       if (is_callback == 0) {
+               is_callback = 1;
                int i;
 
                /* find a runnable thread */
@@ -365,7 +366,7 @@ void _ddekit_thread_schedule()
                }
 
                if (current == NULL) {
-                       ddekit_panic("No runable threads?!");
+                       ddekit_panic("No runnable threads?!");
                }
                
                DDEBUG_MSG_VERBOSE("switching to id: %d name %s, prio: %d",
@@ -373,8 +374,14 @@ void _ddekit_thread_schedule()
 #if DDEBUG >= 4
        _ddekit_print_backtrace(current);
 #endif
-               _longjmp(current->jb, 1);
+               //th->ctx.uc_flags |= _UC_IGNSIGM | _UC_IGNFPU;
+               if (setcontext(&current->ctx) == -1){
+                       panic("ddekit threading setcontext error");
+               }
+               panic("unreachable code");
        }
+       DDEBUG_MSG_VERBOSE("continuing thread execution  id: %d name %s, prio: %d",
+                       current->id, current->name, current->prio);
 
 }
 
@@ -410,7 +417,7 @@ void _ddekit_thread_enqueue(ddekit_thread_t *th)
 void _ddekit_thread_set_myprio(int prio)
 {
        DDEBUG_MSG_VERBOSE("changing thread prio, id: %d name %s, old prio: %d, "
-               "new prio: %d", current->id, current->name, current->prio);
+               "new prio: %d", current->id, current->name, current->prio, prio);
 
        current->prio = prio;
        ddekit_thread_schedule();
@@ -466,22 +473,12 @@ void _ddekit_thread_wakeup_sleeping()
  ****************************************************************************/
 void _ddekit_print_backtrace(ddekit_thread_t *th)
 {
+#if defined(__i386)
        unsigned long bp, pc, hbp;                              
 
        ddekit_printf("%s: ", th->name);
 
-#ifdef __ACK__
-       bp =th->jb[0].__bp;
-#else /* !__ACK__ */
-#include <sys/jmp_buf.h>
-#if defined(JB_BP)
-       /* um, yikes. */
-       bp = (unsigned long) *((void **)(&((char *)th->jb)[JB_BP]));
-#else
-#error "Unsupported Minix architecture"
-#endif
-#endif /* !__ACK__ */
-
+       bp =    th->ctx.uc_mcontext.__gregs[_REG_EBP];
        while (bp) {                                                    
                pc  = ((unsigned long *)bp)[1];                         
                hbp = ((unsigned long *)bp)[0];
@@ -494,6 +491,8 @@ void _ddekit_print_backtrace(ddekit_thread_t *th)
                        break;                                  
                }                                               
                bp= hbp;                                        
-       }                                                       
+       }
+
        ddekit_printf("\n");
+#endif
 }
index 322fa6223d0d3107ec5b1e43875aa144f18c9304..d79751c4b2a1d1d6db3d61c3b09bba0bad9c1a9e 100644 (file)
@@ -2,7 +2,7 @@
 #define DDEKIT_SRC_THREAD_H 1
 #include <ddekit/thread.h> 
 #include <ddekit/semaphore.h> 
-#include <setjmp.h>
+#include <ucontext.h>
 
 #define DDEKIT_THREAD_NAMELEN 32
 #define DDEKIT_THREAD_PRIOS 3
@@ -26,7 +26,7 @@ struct ddekit_thread {
        void *data;
        unsigned sleep_until;
        char name[DDEKIT_THREAD_NAMELEN];
-       jmp_buf jb;
+       ucontext_t ctx;
        ddekit_sem_t *sleep_sem;
        struct ddekit_thread * next;
 };