首页 > 代码库 > 用户态线程库——C语言实现

用户态线程库——C语言实现

轮子年年有人造,我们也来凑热闹,参考协程实现,大概有以下几种方法: 1)利用setjmp,longjmp 2)利用ucontext接口函数 3)汇编

(线程无非就是多了个抢占功能,由定时器触发,而非自愿让出运行权限)

因为我写的时候还没看到其他帖子,如果看到了,铁定会用最直观的ucontext接口写的(注意,在macOSX中已经标注为废除,头文件得换做sys/ucontext.h),结果就是我用了汇编来写,但是尽量不用汇编来写整个switch_to调度函数(这样有个明显的坏处,那就是用gas/nasm的标准汇编格式写的函数在macOSX下不能编译通过,这个与系统自带的编译工具有关),而用经量少的内嵌汇编来写。switch_to函数参考的是minix操作系统中任务切换函数实现的,用软件时钟器每隔1s发信号以激发switch_to函数切换任务。下面直接贴代码了,对外提供了类似pthread的接口(只有两个,分别是threadCreate和threadJoin)。现在的代码还非常的buggy,只能安全地支持在线程函数里头纯计算,其他的行为非常可能引发bus error和segmentation fault。(要更加严谨地研究用户态线程库,请去看gnu pth的实现代码)

技术分享
  1 #pragma once
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <unistd.h>
  5 #include <string.h>
  6 #include <signal.h>
  7 #include <assert.h>
  8 #include <time.h>
  9 
 10 #define JMP(r)    asm volatile  11                 (   "pushl %3\n\t"  12                     "popfd\n\t"  13                     "movl %2, %%ebp\n\t"  14                     "movl %0, %%esp\n\t"  15                     "jmp *%1\n\t"  16                     :  17                     : "m"(r._esp),"m"(r._eip),"m"(r._ebp),"m"(r._eflags)  18                     :  19                 )
 20 
 21 #define SAVE()                  asm volatile  22                             (   "movl %%eax, %0\n\t"  23                                 "movl %%ecx, %1\n\t"  24                                 "movl %%edx, %2\n\t"  25                                 "movl %%ebx, %3\n\t"  26                                    "movl %%esp, %4\n\t"  27                                 "movl %%ebp, %5\n\t"  28                                 "movl %%esi, %6\n\t"  29                                 "movl %%edi, %7\n\t"  30                                 "pushfd\n\t"  31                                 "movl (%%esp), %%eax\n\t"  32                                 "movl %%eax, %8\n\t"  33                                 "popfd\n\t"  34                                 : "=m"(_eax),"=m"(_ecx),"=m"(_edx),"=m"(_ebx)  35                                 ,"=m"(_esp),"=m"(_ebp)  36                                 , "=m"(_esi),"=m"(_edi),"=m"(_eflags)  37                                 :  38                                 : "%eax"  39                             )
 40 
 41 #define RESTORE(r)          asm volatile  42                             (   "movl %0, %%eax\n\t"  43                                 "movl %1, %%ecx\n\t"  44                                 "movl %1, %%edx\n\t"  45                                 "movl %3, %%ebx\n\t"  46                                 "movl %4, %%esi\n\t"  47                                 "movl %5, %%edi\n\t"  48                                 :  49                                 :"m"(r._eax),"m"(r._ecx),"m"(r._edx),"m"(r._ebx)  50                                 , "m"(r._esi),"m"(r._edi)  51                             )
 52 
 53 typedef void Func(int);
 54 
 55 /* __timer struct is the real Timer struct we use
 56  * id is unique to each timer
 57  * intersec is the inteval seconds to each signal forwarding the this Timer
 58  * sigactor is the handler for this Timer
 59  * next is a internal member used for linked list
 60  */
 61 struct __timer
 62 {
 63     void *next;
 64     unsigned int sec;
 65     unsigned int intersec;
 66     int id;
 67     Func *sigactor;
 68 };
 69 
 70 /* struct alarm is ugly for the compatibility with early struct.
 71  * I should have used unnamed member instead of __inner.
 72  */
 73 typedef struct alarm *Timer;
 74 struct alarm
 75 {
 76     union{
 77         struct
 78         {
 79             Timer next;
 80             unsigned int sec;
 81         };
 82         struct __timer __inner;
 83     }; 
 84 };
 85 
 86 typedef struct list *Header;
 87 
 88 struct list
 89 {
 90     Timer head;
 91 };
 92 
 93 typedef struct __thread_table_regs Regs;
 94 struct __thread_table_regs
 95 {
 96     int _edi;
 97     int _esi;
 98     int _ebp;
 99     int _esp;
100     int _ebx;
101     int _edx;
102     int _ecx;
103     int _eax;
104     int _eip;
105     int _eflags;
106 };
107 
108 typedef struct __ez_thread Thread_t;
109 struct __ez_thread
110 {
111     Regs regs;
112     int tid;
113     sigset_t sigmask;
114     unsigned int priority;
115     int tick;
116     int state;
117     int errno;
118     unsigned int stacktop;
119     unsigned int stacksize;
120     void *stack;
121     void *retval;
122     volatile int __reenter;
123 };
124 
125 typedef struct __pnode pNode;
126 struct __pnode
127 {
128     pNode *next;
129     pNode *prev;
130     Thread_t *data;
131 };
132 
133 typedef struct __loopcursor Cursor;
134 struct __loopcursor
135 {
136     int total;
137     pNode *current;
138 };
139 typedef struct __stack *Stack_t;
140 struct __stack
141 {
142     int __pad[4096];
143 };
144 
145 void switch_to(int);
146 
147 extern Header hdr_ptr;
148 extern Cursor live;
149 extern Cursor dead;
150 extern Thread_t pmain;
thread.h
技术分享
  1 /* MIT License
  2 
  3 Copyright (c) 2017 Yuandong-Chen
  4 
  5 Permission is hereby granted, free of charge, to any person obtaining a copy
  6 of this software and associated documentation files (the "Software"), to deal
  7 in the Software without restriction, including without limitation the rights
  8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9 copies of the Software, and to permit persons to whom the Software is
 10 furnished to do so, subject to the following conditions:
 11 
 12 The above copyright notice and this permission notice shall be included in all
 13 copies or substantial portions of the Software.
 14 
 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 21 SOFTWARE. */
 22 
 23 #include "thread.h"
 24 /************************* Alarm facility *************************/
 25 
 26 struct list linkedlist;
 27 Header hdr_ptr = &linkedlist;
 28 
 29 
 30 Timer mallocTimer(int id, Func *actor,unsigned int sec, unsigned int interval)
 31 {
 32     Timer ret = (Timer)malloc(sizeof(struct alarm));
 33     assert(ret);
 34     ret->__inner.id = id;
 35     ret->__inner.sigactor = actor;
 36     ret->__inner.intersec = interval;
 37     ret->sec = sec;
 38     return ret;
 39 }
 40 
 41 /* find Timer in linked list which id is id.
 42  * return: return NULL if not found, -1 if it‘s header link, 
 43  * otherwise prev which is the previous Timer member to this Timer
 44  */
 45 
 46 Timer findTimerPrev(Header h, int id)
 47 {
 48     assert(h);
 49     if(h->head == NULL)
 50         return NULL;
 51 
 52     Timer t = h->head;
 53     Timer prev = NULL;
 54 
 55     while(t)
 56     {
 57         if(t->__inner.id == id){
 58             if(prev == NULL)
 59                 return (Timer)-1;
 60             else
 61                 return prev;
 62         }
 63         prev = t;
 64         t = t->next;
 65     }
 66 
 67     return NULL;
 68 }
 69 
 70 /* delete Timer in linked list.
 71  * return: nothing, we ensure this t is deleted in the linked list.
 72  */
 73 
 74 void delTimer(Header h, Timer t)
 75 {
 76     assert(h);
 77     assert(t);
 78     Timer prevtodel = findTimerPrev(h, t->__inner.id);
 79     unsigned int base = 0;
 80 
 81     if(prevtodel)
 82     {
 83         if(prevtodel == (Timer)-1){
 84 
 85             unsigned int res = (h->head)->sec;
 86             if(res != 0)
 87             {
 88                 base = res;
 89             }
 90             else
 91             {
 92                 kill(getpid(),SIGALRM);
 93                 return;
 94             }
 95             h->head = (h->head)->next;
 96             Timer tmp = (h->head);
 97 
 98             while(tmp){
 99                 tmp->sec += base;
100                 tmp = tmp->next;
101             }
102             return;
103         }
104         else
105         {
106             
107             base = (prevtodel->next)->sec;
108             prevtodel->next = (prevtodel->next)->next;
109             Timer tmp = (prevtodel->next);
110             
111             while(tmp){
112                 tmp->sec += base;
113                 tmp = tmp->next;
114             }
115             return;
116         }
117     }
118 
119     return;
120 }
121 
122 /* append Timer in appropriate place in linked list.
123  * the appropriate place means all timers in linked list are arranged 
124  * according their next alarm seconds.
125  * The algorithm we use here is that the real left alarm seconds for this Timer 
126  * is the sum of all the sec member in Timer in linked list prev to this Timer
127  * plus its sec member. For example, we add 3 Timers to the linked list,
128  * whose sec are 4, 3, 2 respectively. Then the linked list looks like:
129  * 2 (real sec = 2) --> 1 (real sec = 2+1 = 3) --> 1 (real sec = 2+1+1 = 4)
130  * The advantage is obviously, we dont need to remember how many seconds passed.
131  * We always fetch the header to respond the alarm signal and set next alarm sec 
132  * as the next timer in the linked list. (The real situation is a little bit more 
133  * complex, for example if upcoming timers‘ sec equals 0, we need to call their
134  * handler right away all together in a certain sequence. If its intersec is not 
135  * zero, we need to append it to the linked list again as quick as possible)
136  * note: delTimer also address this problem. If we delete any Timer, we need to 
137  * recalculate the secs after this timer in the linked list.(simply to add sec to 
138  * the next timer and delete this timer node)
139  * return: only 0 if success, otherwise the hole process failed.
140  */
141 
142 int appendTimer(Header h, Timer t)
143 {
144     assert(h);
145     assert(t);
146     delTimer(h, t);
147 
148     if(h->head == NULL)
149     {
150         h->head = t;
151         return 0;
152     }
153 
154     Timer tmp = h->head;
155     Timer prev = NULL;
156     unsigned int prevbase = 0;
157     unsigned int base = 0;
158 
159     while(tmp)
160     {
161         prevbase = base;
162         base += tmp->sec;
163         if(t->sec < base){
164             break;
165         }
166         else{
167             prev = tmp;
168             tmp = tmp->next;
169         }
170             
171     }
172 
173     if(prev == NULL)
174     {
175         (h->head)->sec -= t->sec;
176         t->next = h->head;
177         h->head = t;
178         return 0;
179     }
180 
181     if(tmp == NULL)
182         t->sec -=base;
183     else
184         t->sec -=prevbase;
185 
186     prev->next = t;
187     t->next = tmp;
188     if(tmp)
189         tmp->sec -= t->sec;
190 
191     return 0;
192 }
193 
194 /* pop header timer in linked list.
195  * return: its hander
196  */
197 
198 Func* popTimer(Header h)
199 {
200     assert(h);
201     if(h->head == NULL)
202         return (Func *)-1;
203     Func *ret = (h->head)->__inner.sigactor;
204     Timer todel = h->head;
205     h->head = (h->head)->next;
206     // if its intersec greater than 0, we append it right away to the linked list
207     if(todel->__inner.intersec > 0)
208     {
209         todel->sec = todel->__inner.intersec;
210         appendTimer(h, todel);
211     }
212     return ret;
213 }
214 
215 void printList(Header h)
216 {
217     assert(h);
218     if(h->head == NULL)
219         return;
220 
221     Timer tmp = h->head;
222 
223     while(tmp)
224     {
225         printf("timer[%d] = %u saved %u\n", tmp->__inner.id, tmp->sec, tmp->__inner.intersec);
226         tmp = tmp->next;
227     }
228 }
229 
230 /* it‘s the real signal handler responding to every SIGALRM.
231  */
232 void sig_alarm_internal(int signo)
233 { 
234     void funcWrapper(int signo, Func *func);
235 
236     if(hdr_ptr->head == NULL)
237         return;
238 
239     Func *recv;
240     if((recv = popTimer(hdr_ptr)) == (Func *)-1){
241         funcWrapper(SIGALRM, recv);
242     }  
243     else
244     {
245         // signal ourself if next timer‘s sec = 0
246         if(hdr_ptr->head){
247             ((hdr_ptr->head)->sec > 0?alarm((hdr_ptr->head)->sec):kill(getpid(), SIGALRM));
248         }
249         funcWrapper(SIGALRM, recv);
250     }
251 }
252 
253 /* Alarm function simulates native alarm function.
254  * what if SIGALRM arrives when process is running in Alarm?
255  * we just block the signal since there is no slow function in Alarm,
256  * sig_alarm_internal will for sure address the signal very soon.
257  */
258 
259 unsigned int Alarm(Header h, Timer mtimer)
260 {
261     sigset_t mask;
262     sigset_t old;
263     sigemptyset(&mask);
264     sigaddset(&mask, SIGALRM);
265     sigprocmask(SIG_BLOCK, &mask, &old);
266     
267     unsigned int res = 0;
268     Timer t;
269 
270     if((t = findTimerPrev(h, mtimer->__inner.id)) == NULL)
271         goto LL;
272 
273     t = h->head;
274     while(t)
275     {
276         res += t->sec; // it‘s not precise, we should use alarm(0) for the first sec.
277                        // However, its simple enough to implement. 
278         if(t->__inner.id == mtimer->__inner.id)
279             break;
280 
281         t = t->next;
282     }
283 LL:
284     if(mtimer->sec == 0)
285     {
286         delTimer(h, mtimer);
287         sigprocmask(SIG_SETMASK, &old, NULL);
288         return res;
289     }
290      
291     appendTimer(h, mtimer);
292     if(mtimer->__inner.id == (h->head)->__inner.id)
293         ((h->head)->sec > 0?alarm((h->head)->sec):kill(getpid(), SIGALRM));
294     sigprocmask(SIG_SETMASK, &old, NULL);
295     return res;
296 }
297 
298 void initTimer()
299 {
300     struct sigaction act;
301     act.sa_handler = sig_alarm_internal;
302     act.sa_flags = SA_RESTART|SA_NODEFER;
303     sigemptyset(&act.sa_mask);
304     sigaction(SIGALRM, &act, NULL);
305 }
306 
307 void funcWrapper(int signo, Func *func)
308 {
309     sigset_t mask;
310     sigset_t old;
311     sigemptyset(&mask);
312     sigaddset(&mask, SIGALRM);
313     sigprocmask(SIG_UNBLOCK, &mask, &old);
314     func(signo);
315     sigprocmask(SIG_SETMASK, &old, NULL);
316 }
317 
318 /************************* Thread facility *************************/
319 
320 
321 Cursor live;
322 Cursor dead;
323 Thread_t pmain;
324 
325 void initCursor(Cursor *cur)
326 {
327     cur->total = 0;
328     cur->current = NULL;
329 }
330 
331 Thread_t *findThread(Cursor *cur, int tid)
332 {
333     sigset_t mask,old;
334     sigemptyset(&mask);
335     sigaddset(&mask, SIGALRM);
336     sigprocmask(SIG_BLOCK, &mask, &old);
337     int counter = cur->total;
338     if(counter == 0){
339         sigprocmask(SIG_SETMASK, &old, NULL);
340         return NULL;
341     }
342         
343 
344     int i;
345     pNode *tmp = cur->current;
346     for (int i = 0; i < counter; ++i)
347     {
348         if((tmp->data)->tid == tid){
349             sigprocmask(SIG_SETMASK, &old, NULL);
350             return tmp->data;
351         }
352         tmp = tmp->next;
353     }
354     sigprocmask(SIG_SETMASK, &old, NULL);
355     return NULL;
356 }
357 
358 int appendThread(Cursor *cur, Thread_t *pth)
359 {
360     sigset_t mask,old;
361     sigemptyset(&mask);
362     sigaddset(&mask, SIGALRM);
363     sigprocmask(SIG_BLOCK, &mask, &old);
364     if(cur->total == 0)
365     {
366         //note this never freed for simple implementation
367         cur->current = (pNode *)malloc(sizeof(pNode));
368         assert(cur->current);
369         (cur->current)->data =http://www.mamicode.com/ pth;
370         (cur->current)->prev = cur->current;
371         (cur->current)->next = cur->current;
372         cur->total++;
373         sigprocmask(SIG_SETMASK, &old, NULL);
374         return 0;
375     }
376     else
377     {
378         #define MAXTHREADS 5
379         if(cur->total > MAXTHREADS)
380         {
381             assert((cur->total == MAXTHREADS));
382             sigprocmask(SIG_SETMASK, &old, NULL);
383             return -1;
384         }
385         //freed at threadJoin for simple implementation
386         pNode *tmp = malloc(sizeof(pNode));
387         assert(tmp);
388         tmp->data =http://www.mamicode.com/ pth;
389         tmp->prev = cur->current;
390         tmp->next = (cur->current)->next;
391         ((cur->current)->next)->prev = tmp;
392         (cur->current)->next = tmp;
393         cur->total++;
394         sigprocmask(SIG_SETMASK, &old, NULL);
395         return 0;
396     }
397 }
398 
399 pNode *deleteThread(Cursor *cur, int tid)
400 {
401     sigset_t mask,old;
402     sigemptyset(&mask);
403     sigaddset(&mask, SIGALRM);
404     sigprocmask(SIG_BLOCK, &mask, &old);
405 
406     int counter = cur->total;
407     int i;
408     pNode *tmp = cur->current;
409     for (int i = 0; i < counter; ++i)
410     {
411         if((tmp->data)->tid == tid){
412             (tmp->prev)->next = tmp->next;
413             (tmp->next)->prev = tmp->prev;
414             if(tmp == cur->current)
415             {
416                 cur->current = cur->current->next;
417             }  
418             //free(tmp);
419             cur->total--;
420             assert(cur->total);
421             sigprocmask(SIG_SETMASK, &old, NULL);
422             return tmp;
423         }
424         tmp = tmp->next;
425     }
426     sigprocmask(SIG_SETMASK, &old, NULL);
427     return NULL;
428 }
429 
430 void printThread(Thread_t *pth)
431 {
432     printf("pth tid: %d\n", pth->tid);
433     printf("pth stack top: %x\n", pth->stacktop);
434     printf("pth stack size: %u\n", pth->stacksize);
435     printf("pth state: %d\n", pth->state);
436     printf("pth errno: %d\n", pth->errno);
437     printf("pth retval: %p\n", pth->retval);
438     printf("pth sigmask: %u\n", pth->sigmask);
439     printf("pth priority: %d\n", pth->priority);
440     printf("pth tick: %d\n", pth->tick);
441     printf("EFLAGS: %x\t", pth->regs._eflags);
442     printf("EIP: %x\t", pth->regs._eip);
443     printf("EAX: %x\t", pth->regs._eax);
444     printf("ECX: %x\n", pth->regs._ecx);
445     printf("EDX: %x\t", pth->regs._edx);
446     printf("EBX: %x\t", pth->regs._ebx);
447     printf("ESP: %x\t", pth->regs._esp);
448     printf("EBP: %x\n", pth->regs._ebp);
449     printf("ESI: %x\t", pth->regs._esi);
450     printf("EDI: %x\n", pth->regs._edi);
451 
452 }
453 
454 void printLoop(Cursor *cur)
455 {
456     int count = 0;
457     pNode *tmp = cur->current;
458     assert(tmp);
459     do{
460         printThread(tmp->data);
461         tmp = tmp->next;
462         count ++; 
463     }while(tmp != cur->current);
464     printf("real total: %d\n", count);
465     printf("total record:%d\n", cur->total);
466     assert(count == cur->total);
467 }
468 
469 int fetchTID()
470 {
471     static int tid;
472     return ++tid;
473 }
474 
475 void real_entry(Thread_t *pth, void *(*start_rtn)(void *), void* args)
476 {
477     //printf("in real entry: %p\n", start_rtn);
478     
479     pth->retval = (*start_rtn)(args);
480     //deleteThread(&live, pth->tid);
481     /* some clean job here */
482     //free(pth->stack);
483     //pth->stack = NULL;
484     //pth->stacktop = 0;
485     //pth->stacksize = 0;
486     #define DETACHED 1
487     deleteThread(&live, pth->tid);
488     appendThread(&dead, pth);
489 
490     if(pth->state == DETACHED)
491         threadJoin(pth, NULL);
492 
493     switch_to(-1);
494 }
495 
496 int threadCreat(Thread_t **pth, void *(*start_rtn)(void *), void *arg)
497 {
498     sigset_t mask,old;
499     sigemptyset(&mask);
500     sigaddset(&mask, SIGALRM);
501     sigprocmask(SIG_BLOCK, &mask, &old);
502     //freed at threadJoin for simple implementation
503     *pth = malloc(sizeof(Thread_t));
504     #define PTHREAD_STACK_MIN 4096
505     //freed at threadJoin for simple implementation
506     (*pth)->stack = malloc(PTHREAD_STACK_MIN);
507     assert((*pth)->stack);
508     (*pth)->stacktop = (((int)(*pth)->stack + PTHREAD_STACK_MIN)&(0xfffff000));
509     (*pth)->stacksize = PTHREAD_STACK_MIN - (((int)(*pth)->stack + PTHREAD_STACK_MIN) - (*pth)->stacktop);
510     (*pth)->state = 0; // 0 JOINABLE 1 DETACHED
511     (*pth)->priority = 1; //one seconds
512     (*pth)->tick = (*pth)->priority;
513     (*pth)->tid = fetchTID();
514     sigprocmask(0,NULL,&((*pth)->sigmask));
515     /* set params */
516     void *dest = (*pth)->stacktop - 12;
517     memcpy(dest, pth, 4);
518     dest += 4;
519     memcpy(dest, &start_rtn, 4);
520     dest += 4;
521     memcpy(dest, &arg, 4);
522     (*pth)->regs._eip = &real_entry;
523     (*pth)->regs._esp = (*pth)->stacktop - 16;
524     (*pth)->regs._edi = 0;
525     (*pth)->regs._esi = 0;
526     (*pth)->regs._ebp = 0;
527     (*pth)->regs._eax = 0;
528     (*pth)->regs._ebx = 0;
529     (*pth)->regs._ecx = 0;
530     (*pth)->regs._edx = 0;
531     (*pth)->regs._eflags = 0;
532     appendThread(&live, (*pth));
533     sigprocmask(SIG_SETMASK, &old, NULL);
534     return 0;
535 }
536 
537 int threadJoin(Thread_t *pth, void **rval_ptr)
538 {
539 
540     sigset_t mask,old;
541     sigemptyset(&mask);
542     sigaddset(&mask, SIGALRM);
543     sigprocmask(SIG_BLOCK, &mask, &old);
544     Thread_t *find1, *find2;
545     find1 = findThread(&live, pth->tid);
546     find2 = findThread(&dead, pth->tid);
547     
548 
549     if((find1 == NULL)&&(find2 == NULL)){
550         sigprocmask(SIG_SETMASK, &old, NULL);
551         return -1;
552     }
553 
554     if(find2){
555         if(rval_ptr != NULL)
556             *rval_ptr = find2->retval;
557 
558         sigprocmask(SIG_SETMASK, &old, NULL);
559         return 0;
560     }
561     sigprocmask(SIG_SETMASK, &old, NULL);
562     while(1)
563     {
564         if((find2 = findThread(&dead, pth->tid))!= NULL){
565             if(rval_ptr!= NULL)
566                 *rval_ptr = find2->retval;
567 
568             pNode *tmp = deleteThread(&dead, pth->tid);
569             free(tmp);
570             free((Stack_t)find2->stack);
571             free(find2);
572             return 0;
573         }
574     }
575     return -1;
576 }
577 
578 void init()
579 {
580     initTimer();
581     initCursor(&live);
582     initCursor(&dead);
583     appendThread(&live, &pmain);
584     Alarm(hdr_ptr,mallocTimer(1, switch_to, 1, 1));
585 }
586 
587 void switch_to(int signo)
588 {
589     sigset_t mask,old;
590     sigemptyset(&mask);
591     sigaddset(&mask, SIGALRM);
592     sigprocmask(SIG_BLOCK, &mask, &old);
593     Regs regs;
594     //printf("");
595     if(signo == -1)
596     {
597         regs = live.current->data->regs;
598         sigprocmask(SIG_SETMASK, &old, NULL);
599         JMP(regs);
600         assert(0);
601     }
602     
603     int _edi;
604     int _esi;
605     int _ebp;
606     int _esp;
607     int _ebx;
608     int _edx;
609     int _ecx;
610     int _eax;
611     int _eip = &&_REENTERPOINT;
612     int _eflags;
613     live.current->data->__reenter = 0; 
614     /* save current context */
615     SAVE();
616 
617     /* save context in current thread */
618     live.current->data->regs._eflags = _eflags;
619     live.current->data->regs._eip = _eip;
620     live.current->data->regs._eax = _eax;
621     live.current->data->regs._ecx = _ecx;
622     live.current->data->regs._edx = _edx;
623     live.current->data->regs._ebx = _ebx;
624     live.current->data->regs._esp = _esp;
625     live.current->data->regs._ebp = _ebp;
626     live.current->data->regs._esi = _esi;
627     live.current->data->regs._edi = _edi;
628 
629     if(!live.current->data->__reenter)
630     {
631         goto _END;
632     }
633 
634 _REENTERPOINT:
635     regs = live.current->data->regs;
636 
637     if(live.current->data->__reenter){
638         live.current->data->__reenter = 0;
639         sigprocmask(SIG_SETMASK, &old, NULL);
640         return;
641     } 
642 
643 _END:
644     live.current->data->__reenter = 1;
645     regs = live.current->next->data->regs;
646     live.current = live.current->next;
647     sigprocmask(SIG_SETMASK, &old, NULL);
648     JMP(regs);
649     assert(0);
650 }
651 
652 /************************* Test *************************/
653 /**
654  * Note: The implementation is really bugy, right now only support compute in thread.
655  * Even standard I/O in the thread will cause I/O bus error or segmentation error because
656  * all pthread-reentrant function is not guaranteed in our thread model.
657  * (pthread_mutex_t cannot block thread in our model cause we modify eip directly)
658  */
659 void *sum1tod(void *d)
660 {
661     int i, k, j=0;
662 
663     for (i = 0; i <= (int)d; ++i)
664     {
665             /* code */
666             j+=i;      
667     }
668     return ((void *)j);
669 }
670 
671 int main(int argc, char const *argv[])
672 {
673     int res = 0;
674     int i;
675     init();
676     Thread_t *tid1, *tid2;
677     int *res1, *res2;
678     threadCreat(&tid1, sum1tod, 100);
679     threadCreat(&tid2, sum1tod, 100);
680     for (i = 0; i <= 100; ++i){
681         res+=i;
682     }
683 
684     threadJoin(tid1, &res1);
685     threadJoin(tid2, &res2);
686     printf("parallel compute: %d = 5050 * 3\n", (int)res1+(int)res2+(int)res);
687     return 0;
688 }
thread.c

 

用户态线程库——C语言实现