用户态线程库——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 = 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 = 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

时间: 2024-11-06 09:59:47

用户态线程库——C语言实现的相关文章

线程的实现方式之内核支持线程和用户级线程

线程是OS进行独立调试.执行的基本单位,进程是系统进行资源分配的基本单位,一个进程可以包含若干个线程.无论是系统进程还是用户进程,进程的创建.撤消.以及要求系统设备完成的IO操作,都是利用系统调用而进入内核,再由内核中相应处理程序予以完成.进程的切换同样是在内核的支持下实现的.即不论什么样的进程,它们都是在OS内核的支持下运行的,是与内核紧密相关的. 1. 线程的分类 线程根据其实现方式不同又可分为内核支持线程KST(Kernel Supported Threads).用户级线程ULT(User

4-15 OS(线程,用户态,内核态,页) 数据库(原子性,日志) JAVA(I/O)

在internet services课上老师说到Capriccio 是用户模式下的thread library,OS课里第2个project也是实现一个用户模式下的线程库.之前用过POSIX库,我知道这是在内核模式里的线程库,那就表示由内核来创建.调度线程吧.但内核就像一个黑盒,一直不明白它做了什么,怎么做到的.Modern Operating System有章讲user space和kernel space控制线程. 在user space:所有线程的管理都在用户区,内核不知道多线程的存在.在

Linux用户态程序计时方式详解

前言 良好的计时器可帮助程序开发人员确定程序的性能瓶颈,或对不同算法进行性能比较.但要精确测量程序的运行时间并不容易,因为进程切换.中断.共享的多用户.网络流量.高速缓存访问及转移预测等因素都会对程序计时产生影响. 本文将不考虑这些影响因素(相关资料可参考<深入理解计算机系统>一书),而仅仅关注Linux系统中用户态程序执行时间的计算方式.除本文所述计时方式外,还可借助外部工具统计耗时,如<Linux调试分析诊断利器——strace>一文中介绍的strace. 本文示例代码的运行环

Linux用户态程序计时方式详解[转]

转自: http://www.cnblogs.com/clover-toeic/p/3845210.html 前言 良好的计时器可帮助程序开发人员确定程序的性能瓶颈,或对不同算法进行性能比较.但要精确测量程序的运行时间并不容易,因为进程切换.中断.共享的多用户.网络流量.高速缓存访问及转移预测等因素都会对程序计时产生影响. 本文将不考虑这些影响因素(相关资料可参考<深入理解计算机系统>一书),而仅仅关注Linux系统中用户态程序执行时间的计算方式.除本文所述计时方式外,还可借助外部工具统计耗时

操作系统: 用户级线程和内核级线程

1 .内核级线程:切换由内核控制,当线程进行切换的时候,由用户态转化为内核态.切换完毕要从内核态返回用户态:可以很好的利用smp,即利用多核cpu.windows线程就是这样的. 2. 用户级线程内核的切换由用户态程序自己控制内核切换,不需要内核干涉,少了进出内核态的消耗,但不能很好的利用多核Cpu,目前Linux pthread大体是这么做的. 线程的实现可以分为两类:用户级线程(User-Level Thread)和内核线线程(Kernel-Level Thread),后者又称为内核支持的线

用户级线程和内核级线程的区别

转载于http://col1.blog.163.com/blog/static/1909775192012719114033352/ 1 .内核级线程:切换由内核控制,当线程进行切换的时候,由用户态转化为内核态.切换完毕要从内核态返回用户态:可以很好的利用smp,即利用多核cpu.windows线程就是这样的. 2. 用户级线程内核的切换由用户态程序自己控制内核切换,不需要内核干涉,少了进出内核态的消耗,但不能很好的利用多核Cpu,目前Linux pthread大体是这么做的. 线程的实现可以分

线程的3种实现方式--内核级线程, 用户级线程和混合型线程

之前降解过内核线程.轻量级进程.用户线程三种线程概念解惑(线程≠轻量级进程), 但是一直对其中提到的线程的实现模型比较迷惑, 这次就花了点时间怎么学习了一下子 1 线程的3种实现方式 在传统的操作系统中,拥有资源和独立调度的基本单位都是进程.在引入线程的操作系统中,线程是独立调度的基本单位,进程是资源拥有的基本单位.在同一进程中,线程的切换不会引起进程切换.在不同进程中进行线程切换,如从一个进程内的线程切换到另一个进程中的线程时,会引起进程切换 根据操作系统内核是否对线程可感知,可以把线程分为内

操作系统--用户级线程和内核级线程

在多线程操作系统中,各个系统的实现方式并不相同.在有的系统中实现了用户级线程,有的系统中实现了内核级线程 1.内核级线程: (1)线程的创建.撤销和切换等,都需要内核直接实现,即内核了解每一个作为可调度实体的线程. (2)这些线程可以在全系统内进行资源的竞争. (3)内核空间内为每一个内核支持线程设置了一个线程控制块(TCB),内核根据该控制块,感知线程的存在,并进行控制. 在一定程度上类似于进程,只是创建.调度的开销要比进程小.有的统计是1:10 2.用户级线程: (1)用户级线程仅存在于用户

内核态与用户态【转载】

原文:http://blog.csdn.net/skywalkzf/article/details/5185442 内核态与用户态是操作系统的两种运行级别,intel cpu提供Ring0-Ring3三种级别的运行模式.Ring0级别最高,Ring3最低.其中特权级0(Ring0)是留给操作系统代码,设备驱动程序代码使用的,它们工作于系统核心态:而特权极3(Ring3)则给普通的用户程序使用,它们工作在用户态.运行于处理器核心态的代码不受任何的限制,可以自由地访问任何有效地址,进行直接端口访问.