轮子年年有人造,我们也来凑热闹,参考协程实现,大概有以下几种方法: 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