00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <setjmp.h>
00012 #include <unistd.h>
00013 #include <string.h>
00014 #include <assert.h>
00015 #include <stdlib.h>
00016 #include <limits.h>
00017 #include <stdarg.h>
00018 #include <stdio.h>
00019 #include <stdarg.h>
00020 #include <time.h>
00021
00022 #include "trt.h"
00023
00024 #define FIFO_READY_LIST 1
00025
00026
00027
00028 #ifndef MIN
00029 #define MIN(a, b) ((a) < (b) ? (a) : (b))
00030 #endif
00031
00032 #ifndef MAX
00033 #define MAX(a, b) ((a) > (b) ? (a) : (b))
00034 #endif
00035
00036 #define TRUE 1
00037 #define FALSE 0
00038
00041
00042
00043
00044 extern processor_t trt_processor_table[TRT_MAX_NUM_PROCESSORS_PER_TILE];
00045
00046
00047
00048
00049 extern thread_table_t trt_thread_table;
00050
00051
00052
00053
00054 extern int trt_num_processors;
00055
00056
00057
00058
00059 extern int trt_tile_idx;
00060
00061
00062
00063
00064 extern unsigned int trt_next_thread_ID;
00065
00066
00067
00068
00069 extern int trt_serial_lock;
00070
00071
00072
00073
00074 processor_t *current_processor;
00075
00076 #define current_thread (get_current_processor()->running_thread)
00077
00078 enum purpose
00079 {
00080 GENERAL, INPUT, OUTPUT, INPUT_OUTPUT, COPROC_CNTL, MAX_PURPOSE
00081 };
00082
00083
00084
00085
00086 static void debug_handler(int key);
00087
00090
00091
00092
00093 #define append(list, member, ien) \
00094 { \
00095 thread_t *__m = (member); \
00096 \
00097 ien = acquire_lock(list ## _lock, TRUE); \
00098 \
00099 __m->next = NULL; \
00100 \
00101 if(list ## _head == NULL) \
00102 list ## _head = __m; \
00103 else \
00104 list ## _tail->next = __m; \
00105 \
00106 list ## _tail = __m; \
00107 }
00108
00109
00110
00111
00112 #define prepend(list, member, ien) \
00113 { \
00114 thread_t *__m = (member); \
00115 \
00116 ien = acquire_lock(list ## _lock, TRUE); \
00117 \
00118 __m->next = list ## _head; \
00119 \
00120 if(__m->next == NULL) \
00121 list ## _tail = __m; \
00122 \
00123 list ## _head = __m; \
00124 }
00125
00126
00127
00128
00129 #define unlink(list, member, prev_member) \
00130 { \
00131 if((prev_member)) \
00132 (prev_member)->next = (member)->next; \
00133 else \
00134 list ## _head = (member)->next; \
00135 \
00136 if((member)->next == NULL) \
00137 list ## _tail = (prev_member); \
00138 }
00139
00140
00141
00142
00143 #define unlink_head(list, head) \
00144 { \
00145 list ## _head = (head)->next; \
00146 }
00147
00148
00149
00150
00151 #define unlink_tail(list) \
00152 { \
00153 thread_t *t; \
00154 \
00155 if(list ## _head->next != NULL) \
00156 { \
00157 for(t = list ## _head; t->next->next; t = t->next) \
00158 ; \
00159 \
00160 t->next = NULL; \
00161 list ## _tail = t; \
00162 } \
00163 else \
00164 list ## _head = NULL; \
00165 }
00166
00167 #define top_of_scheduler_stack() \
00168 ( \
00169 &get_current_processor()->scheduler_stack[TRT_SCHEDULER_STACK_SIZE - 1]\
00170 )
00171
00172 #define switch_to_scheduler_stack(fun, arg) \
00173 ( \
00174 fun(arg) \
00175 )
00176
00179 int __bit_bucket;
00180
00183
00184
00185
00186 static inline int add_to_ready_list(thread_t *thread, int keep_lock, int back)
00187 {
00188 processor_t *p = thread->processor;
00189 int ien;
00190
00191 if(back)
00192 append(p->ready_list, thread, ien)
00193 else
00194 prepend(p->ready_list, thread, ien)
00195
00196 if(!keep_lock)
00197 release_lock(p->ready_list_lock, ien);
00198
00199
00200
00201 return ien;
00202 }
00203
00204
00205
00206
00207 static void scale_spin_counts()
00208 {
00209 processor_t *p;
00210 processor_t *p2 = get_current_processor();
00211 int i;
00212
00213 for(i = 0; i < trt_num_processors; i++)
00214 {
00215 p = &trt_processor_table[i];
00216
00217 if(p->domain != p2->domain)
00218 continue;
00219
00220 atomic_srl(trt_processor_table[i].idle_spin_count, 1);
00221 }
00222 }
00223
00224
00225
00226
00227 int trt_is_idle()
00228 {
00229 processor_t *p;
00230 int i;
00231
00232 for(i = 0; i < trt_num_processors; i++)
00233 {
00234 p = &trt_processor_table[i];
00235
00236 if(p->purpose != GENERAL)
00237 continue;
00238
00239 if(p->running_thread != NULL ||
00240 p->schedule_me != NULL ||
00241 p->ready_list_head != NULL)
00242 return FALSE;
00243 }
00244
00245 return TRUE;
00246 }
00247
00248
00249
00250
00251 static thread_t *steal_thread()
00252 {
00253 thread_t *t;
00254 processor_t *victim = NULL, *p;
00255 int i, j, ien;
00256 domain_t *domain;
00257
00258 domain = get_current_processor()->domain;
00259 i = get_current_processor()->index;
00260
00261 for(j = 1; j < trt_num_processors; j++)
00262 {
00263 if(++i == trt_num_processors)
00264 i = 0;
00265
00266 p = &trt_processor_table[i];
00267
00268 if(p->domain != domain)
00269 continue;
00270
00271 if(p->running_thread == NULL)
00272 break;
00273
00274 if(p->ready_list_head == NULL)
00275 continue;
00276
00277 if(!victim || victim->idle_spin_count > p->idle_spin_count)
00278 victim = p;
00279 }
00280
00281 if(victim == NULL)
00282 return NULL;
00283
00284
00285
00286 ien = acquire_lock(victim->ready_list_lock, TRUE);
00287
00288 #if FIFO_READY_LIST
00289 if(t = victim->ready_list_head)
00290 unlink_head(victim->ready_list, t);
00291 #else
00292 if(victim->ready_list_head)
00293 {
00294 t = victim->ready_list_tail;
00295
00296 unlink_tail(victim->ready_list)
00297 }
00298 else
00299 t = NULL;
00300 #endif
00301
00302 release_lock(victim->ready_list_lock, ien);
00303
00304 if(t != NULL)
00305 {
00306 t->processor = get_current_processor();
00307
00308 if(atomic_sll(victim->idle_spin_count, 1) > 2500)
00309 scale_spin_counts();
00310 }
00311
00312 return t;
00313 }
00314
00315
00316
00317
00318 static thread_t *select_thread()
00319 {
00320 processor_t *p = get_current_processor();
00321 thread_t *t;
00322 int ien;
00323
00324
00325
00326
00327 if(t = p->schedule_me)
00328 {
00329 release_lock_no_ien(p->schedule_me);
00330
00331 goto exit;
00332 }
00333
00334
00335
00336
00337 ien = acquire_lock(p->ready_list_lock, TRUE);
00338
00339
00340 while((t = force_load(p->ready_list_head)) == NULL)
00341 {
00342
00343
00344 release_lock(p->ready_list_lock, ien);
00345
00346
00347 while(!force_load(p->ready_list_head))
00348 {
00349 if(t = p->schedule_me)
00350 {
00351 release_lock_no_ien(p->schedule_me);
00352
00353 goto exit;
00354 }
00355
00356 if(t = steal_thread())
00357 {
00358 #if TRT_STATISTICS
00359 p->domain->num_thread_migrates++;
00360 #endif
00361 goto exit;
00362 }
00363
00364
00365
00366 atomic_addi(p->idle_spin_count,1);
00367
00368 if(p->idle_spin_count > 5000)
00369 {
00370 scale_spin_counts();
00371
00372 if(p->idle_handler && trt_is_idle())
00373 p->idle_handler();
00374 }
00375 }
00376
00377
00378
00379 acquire_lock(p->ready_list_lock, TRUE);
00380 }
00381
00382
00383 unlink_head(p->ready_list, t);
00384
00385 release_lock(p->ready_list_lock, ien);
00386
00387 exit: return t;
00388 }
00389
00392 #if defined(__hpux__) || defined(__sun__)
00393 #define SAVE_CONTEXT(context) _setjmp(context)
00394 #define RESTORE_CONTEXT(context) _longjmp(context, TRUE)
00395 #else
00396 #define SAVE_CONTEXT(context) setjmp(context)
00397 #define RESTORE_CONTEXT(context) longjmp(context, TRUE)
00398 #endif
00399
00400 #if defined(__linux__) && defined(__i386__)
00401
00402 #define SET_SP(context, sp) ((context)->__jmpbuf[4] = (int) (sp))
00403 #define GET_SP(context) ((context)->__jmpbuf[4])
00404 #define ISA TRT_ISA_I386
00405
00406 #elif defined(__CYGWIN__) && defined(__i386__)
00407
00408 #define SET_SP(context, sp) ((context)[7] = (int) (sp))
00409 #define GET_SP(context) ((context)[7])
00410 #define ISA TRT_ISA_I386
00411
00412 #elif defined(__sgi__) && defined(__mips__)
00413
00414 #define SET_SP(context, sp) ((context)[JB_SP] = (int) (sp))
00415 #define GET_SP(context) ((context)[JB_SP])
00416 #define ISA TRT_ISA_MIPS
00417
00418 #elif defined(__sun__) && defined(__sparc__)
00419
00420 #define SET_SP(context, sp) ((context)[1] = (int) (sp))
00421 #define GET_SP(context) ((context)[1])
00422 #define ISA TRT_ISA_SPARC
00423
00424 #elif defined(__hpux__) && defined(__hppa__)
00425
00426 #define SET_SP(context, sp) (((int *) (context))[1] = (int) (sp))
00427 #define GET_SP(context) (((int *) (context))[1])
00428 #define ISA TRT_ISA_HPPA
00429
00430 #else
00431 #error Sorry, your architecture is not supported
00432 #endif
00433
00434
00435
00436
00437
00438 static void schedule_next_thread(void (*block_handler)())
00439 {
00440 #if TRT_STATISTICS
00441 get_current_processor()->domain->num_context_switches++;
00442 #endif
00443
00444 block_handler();
00445
00446 current_thread = NULL;
00447 current_thread = select_thread();
00448
00449 RESTORE_CONTEXT(current_thread->context.context);
00450 }
00451
00452
00453
00454
00455 static void context_switch(int *unlock_me, int ien, void (*block_handler)())
00456 {
00457 if(!SAVE_CONTEXT(current_thread->context.context))
00458 {
00459 if(unlock_me != NULL)
00460 release_lock(*unlock_me, ien);
00461
00462 switch_to_scheduler_stack(schedule_next_thread, block_handler);
00463 }
00464 }
00465
00466 static void empty_handler()
00467 {
00468 }
00469
00470 static int addr2isa(void *addr)
00471 {
00472 return ISA;
00473 }
00474
00475 static void thread_table_add(thread_t *thread)
00476 {
00477 int ien;
00478
00479 ien = acquire_lock(trt_thread_table.lock, TRUE);
00480
00481 thread->next_table = NULL;
00482 thread->prev_table = trt_thread_table.tail;
00483
00484 if(trt_thread_table.head == NULL)
00485 trt_thread_table.head = thread;
00486 else
00487 trt_thread_table.tail->next_table = thread;
00488
00489 trt_thread_table.tail = thread;
00490
00491 release_lock(trt_thread_table.lock, ien);
00492 }
00493
00494 static void thread_table_remove(thread_t *thread)
00495 {
00496 int ien;
00497
00498 ien = acquire_lock(trt_thread_table.lock, TRUE);
00499
00500 if(thread->prev_table == NULL)
00501 trt_thread_table.head = thread->next_table;
00502 else
00503 thread->prev_table->next_table = thread->next_table;
00504
00505 if(thread->next_table == NULL)
00506 trt_thread_table.tail = thread->prev_table;
00507 else
00508 thread->next_table->prev_table = thread->prev_table;
00509
00510 release_lock(trt_thread_table.lock, ien);
00511 }
00512
00513 static void call_start_function()
00514 {
00515 int arg, res, (*fun)(int);
00516
00517 arg = current_thread->start_arg;
00518 fun = current_thread->start_fun;
00519
00520 res = fun(arg);
00521
00522 thr_exit(res);
00523 }
00524
00525 static void set_sp(thread_t *thread, void *sp)
00526 {
00527 SET_SP(thread->context.context, sp);
00528 }
00529
00530 static char *isa_name(int isa)
00531 {
00532 if(isa == TRT_ISA_MIPS) return "MIPS";
00533 if(isa == TRT_ISA_I386) return "i386";
00534 if(isa == TRT_ISA_SPARC) return "Sparc";
00535 if(isa == TRT_ISA_HPPA) return "HPPA";
00536
00537 return "???";
00538 }
00539
00540 static processor_t *find_processor(int isa)
00541 {
00542 processor_t *p;
00543 int i;
00544
00545 if(isa == ISA)
00546 return get_current_processor();
00547
00548 for(i = 0; i < trt_num_processors; i++)
00549 {
00550 p = &trt_processor_table[i];
00551
00552 if(p->domain->isa == isa && p->purpose == GENERAL)
00553 return p;
00554 }
00555
00556 trt_panic_s("failed to find processor", isa_name(isa));
00557
00558 return NULL;
00559 }
00560
00561 void thr_create(thread_t *new_thread, int (*fun)(int), int arg)
00562 {
00563 int isa = addr2isa(fun);
00564
00565 if(trt_num_processors == 0)
00566 trt_init(NULL, NULL);
00567
00568 memset(new_thread, 0, sizeof(thread_t));
00569 new_thread->start_fun = fun;
00570 new_thread->start_arg = arg;
00571 new_thread->name = "noname";
00572 new_thread->processor = find_processor(isa);
00573 new_thread->id = atomic_add(trt_next_thread_ID, 1);
00574
00575 thr_onblock(new_thread, NULL);
00576
00577 thr_set_cache_ddr_domain(new_thread, 0, 0);
00578
00579 sem_init(&new_thread->exit, 0, "exit");
00580
00581 thread_table_add(new_thread);
00582
00583 if(SAVE_CONTEXT(new_thread->context.context))
00584 call_start_function();
00585 }
00586
00587 thread_t *thr_lookup(int id)
00588 {
00589 thread_t *t;
00590
00591 int ien;
00592
00593 ien = acquire_lock(trt_thread_table.lock, TRUE);
00594
00595 for(t = trt_thread_table.head; t && t->id != id; t = t->next_table)
00596 ;
00597
00598 release_lock(trt_thread_table.lock, ien);
00599
00600 return t;
00601 }
00602
00603 typedef struct call_isa_s
00604 {
00605 context_t context;
00606 int (*fun)(int, int, int, int);
00607 int arg[4];
00608 int result;
00609 void (*block_handler)();
00610 processor_t *processor;
00611 } call_isa_t;
00612
00613 static void call_function()
00614 {
00615 call_isa_t *call_isa = (call_isa_t *) current_thread->exit_status;
00616
00617 current_thread->block_handler = empty_handler;
00618
00619 call_isa->result = call_isa->fun(call_isa->arg[0], call_isa->arg[1],
00620 call_isa->arg[2], call_isa->arg[3]);
00621
00622 current_thread->block_handler = call_isa->block_handler;
00623 current_thread->processor = call_isa->processor;
00624 current_thread->context = call_isa->context;
00625
00626 add_to_ready_list(current_thread, FALSE, FIFO_READY_LIST);
00627
00628 switch_to_scheduler_stack(schedule_next_thread, empty_handler);
00629 }
00630
00631 int thr_isa(thread_t *thread)
00632 {
00633 return ISA;
00634 }
00635
00636 char *thr_isa_name(thread_t *thread)
00637 {
00638 return isa_name(thr_isa(thread));
00639 }
00640
00641 void thr_stack_size(thread_t *thread, int stack_size)
00642 {
00643 int *stack_bot, *stack_top;
00644
00645 if(stack_size == 0)
00646 stack_size = trt_config_stack_size;
00647
00648 if(thread->stack)
00649 trt_free(thread->stack);
00650
00651 thread->stack = trt_malloc(stack_size);
00652 stack_bot = thread->stack + 32;
00653 stack_top = thread->stack + (stack_size / sizeof(int)) - 32;
00654
00655 assert(((long) stack_top & 3) == 0);
00656 assert(((long) stack_bot & 3) == 0);
00657
00658 #if defined(__hppa__)
00659 thread->stack_init_sp = stack_bot;
00660 thread->stack_magic = stack_top;
00661 #else
00662 thread->stack_init_sp = stack_top;
00663 thread->stack_magic = stack_bot;
00664 #endif
00665
00666 thread->stack_magic[0] = TRT_STACK_OVERFLOW_MAGIC;
00667 thread->atexit.free_stack = TRUE;
00668
00669 set_sp(thread, thread->stack_init_sp);
00670 }
00671
00672 void thr_stack_addr(thread_t *thread, void *addr)
00673 {
00674 static int stack_overflow_magic = TRT_STACK_OVERFLOW_MAGIC;
00675
00676 thread->stack_init_sp = addr;
00677 thread->stack_magic = &stack_overflow_magic;
00678
00679 set_sp(thread, thread->stack_init_sp);
00680 }
00681
00682 static void thr_exit_cont()
00683 {
00684 thread_t *curr = current_thread;
00685 int free_desc = curr->atexit.free_desc;
00686 int free_stack = curr->atexit.free_stack;
00687
00688 static void *free_me = NULL;
00689
00690 if(free_me != NULL)
00691 trt_free(free_me);
00692
00693 free_me = curr->stack;
00694
00695 sem_Vn(&curr->exit, 999999);
00696
00697 if(free_desc)
00698 trt_free(curr);
00699
00700 current_thread = NULL;
00701
00702 schedule_next_thread(empty_handler);
00703 }
00704
00705 void thr_exit(int exit_status)
00706 {
00707 atexit_t *atexit = ¤t_thread->atexit;
00708 int i;
00709
00710 current_thread->exit_status = exit_status;
00711
00712 current_thread->block_handler();
00713
00714 for(i = atexit->count - 1; i >= 0; i--)
00715 atexit->fun[i](atexit->arg[i]);
00716
00717 if(current_thread->stack_magic[0] != TRT_STACK_OVERFLOW_MAGIC)
00718 trt_panic_s("Stack overflow", current_thread->name);
00719
00720 thread_table_remove(current_thread);
00721
00722 switch_to_scheduler_stack(thr_exit_cont, empty_handler);
00723 }
00724
00725 void thr_destroy(thread_t *thread)
00726 {
00727 int free_desc = thread->atexit.free_desc;
00728 int free_stack = thread->atexit.free_stack;
00729
00730 if(thread->stack == NULL)
00731 return;
00732
00733 thread_table_remove(thread);
00734
00735 if(free_stack)
00736 trt_free(thread->stack);
00737
00738 thread->stack = NULL;
00739
00740 sem_Vn(&thread->exit, 999999);
00741
00742 if(free_desc)
00743 trt_free(thread);
00744 }
00745
00746 void thr_atexit(thread_t *thread, void (*fun)(int), int arg)
00747 {
00748 int i = thread->atexit.count++;
00749
00750 assert(i < sizeof(thread->atexit.arg) / sizeof(int));
00751
00752 thread->atexit.fun[i] = fun;
00753 thread->atexit.arg[i] = arg;
00754 }
00755
00756 void thr_atexit_pop(thread_t *thread, int execute)
00757 {
00758 int i = --thread->atexit.count;
00759
00760 if(execute)
00761 thread->atexit.fun[i](thread->atexit.arg[i]);
00762 }
00763
00764 void thr_onblock(thread_t *thread, void (*fun)(void))
00765 {
00766 if(fun == NULL)
00767 {
00768 int isa = thread->processor->domain->isa;
00769
00770 fun = (void (*)()) sym_query(isa, "$empty_handler", TRUE);
00771 }
00772
00773 thread->block_handler = fun;
00774 }
00775
00776 void trt_onidle(void (*handler)(void))
00777 {
00778 processor_t *p;
00779 int i;
00780
00781 for(i = 0; i < trt_num_processors; i++)
00782 {
00783 p = &trt_processor_table[i];
00784
00785 if(p->domain->isa == ISA)
00786 p->idle_handler = handler;
00787 }
00788 }
00789
00790 void thr_start(thread_t *thread)
00791 {
00792 if(thread->stack == NULL)
00793 thr_stack_size(thread, trt_config_stack_size);
00794
00795 add_to_ready_list(thread, FALSE, FIFO_READY_LIST);
00796 }
00797
00798 static int search_ready_list(processor_t *processor, thread_t *thread)
00799 {
00800 thread_t *t, *t_prev = NULL;
00801 int ien;
00802
00803 ien = acquire_lock(processor->ready_list_lock, TRUE);
00804
00805 for(t = processor->ready_list_head; t; t_prev = t, t = t->next)
00806 {
00807 if(t == thread)
00808 break;
00809 }
00810
00811 if(t != NULL)
00812 {
00813 unlink(processor->ready_list, t, t_prev);
00814 }
00815
00816 release_lock(processor->ready_list_lock, ien);
00817
00818 return t != NULL;
00819 }
00820
00821 static int search_blocked_list(semaphore_t *semaphore, thread_t *thread)
00822 {
00823 thread_t *t = NULL, *t_prev = NULL;
00824 int ien;
00825
00826 if(atomic_addi(semaphore->count, 1) < 0)
00827 {
00828 ien = acquire_lock(semaphore->blocked_lock, TRUE);
00829
00830 for(t = semaphore->blocked_head; t; t_prev = t, t = t->next)
00831 {
00832 if(t == thread)
00833 break;
00834 }
00835
00836 if(t != NULL)
00837 unlink(semaphore->blocked, t, t_prev);
00838
00839 release_lock(semaphore->blocked_lock, ien);
00840 }
00841
00842 if(t == NULL)
00843 atomic_subi(semaphore->count, 1);
00844
00845 return t != NULL;
00846 }
00847
00848 void thr_suspend(thread_t *thread)
00849 {
00850 processor_t *processor;
00851 semaphore_t *semaphore, suspend_point_sem;
00852
00853 if(thread == current_thread || thread == NULL)
00854 context_switch(NULL, 0, current_thread->block_handler);
00855 else if(thread->suspension_mode == SUSPEND_DISABLE)
00856 {
00857 sem_init(&suspend_point_sem, 0, "suspend");
00858
00859 thread->suspend_point_sem = &suspend_point_sem;
00860
00861 sem_P(&suspend_point_sem);
00862
00863 thread->suspend_point_sem = NULL;
00864 }
00865 else
00866 {
00867 while(TRUE)
00868 {
00869 if(semaphore = thread->blocked_on)
00870 {
00871 if(search_blocked_list(semaphore, thread))
00872 {
00873 thread->blocked_on = semaphore;
00874 return;
00875 }
00876 }
00877
00878 if(processor = thread->processor)
00879 {
00880 if(search_ready_list(processor, thread))
00881 {
00882 thread->blocked_on = NULL;
00883 return;
00884 }
00885 }
00886
00887 thr_switch();
00888 }
00889 }
00890 }
00891
00892 void thr_resume(thread_t *thread)
00893 {
00894 semaphore_t *semaphore = thread->blocked_on;
00895 int ien;
00896
00897 if(semaphore != NULL && atomic_subi(semaphore->count, 1) <= 0)
00898 {
00899 append(semaphore->blocked, thread, ien);
00900
00901 release_lock(semaphore->blocked_lock, ien);
00902 }
00903 else
00904 {
00905 thread->blocked_on = NULL;
00906
00907 add_to_ready_list(thread, FALSE, FIFO_READY_LIST);
00908 }
00909 }
00910
00911 int thr_suspend_mode(thread_t *thread, int suspension_mode)
00912 {
00913 int old_suspension_mode = thread->suspension_mode;
00914
00915 thread->suspension_mode = suspension_mode;
00916
00917 return old_suspension_mode;
00918 }
00919
00920 void thr_suspend_me()
00921 {
00922 sem_V(current_thread->suspend_point_sem);
00923
00924 context_switch(NULL, 0, current_thread->block_handler);
00925 }
00926
00927 void thr_restart(thread_t *thread, int (*fun)(int), int arg)
00928 {
00929 thread->blocked_on = NULL;
00930
00931 if(fun != NULL)
00932 {
00933 thread->start_fun = fun;
00934 thread->start_arg = arg;
00935 }
00936
00937 if(!SAVE_CONTEXT(thread->context.context))
00938 {
00939 set_sp(thread, thread->stack_init_sp);
00940
00941 add_to_ready_list(thread, FALSE, FIFO_READY_LIST);
00942 }
00943 else
00944 call_start_function();
00945 }
00946
00947 void thr_stop(thread_t *thread, int status)
00948 {
00949 if(thread->stack != NULL)
00950 thr_restart(thread, (int (*)(int)) thr_exit, status);
00951 }
00952
00953 void thr_switch()
00954 {
00955 int *lock = ¤t_thread->processor->ready_list_lock;
00956 int ien;
00957
00958 ien = add_to_ready_list(current_thread, TRUE, TRUE);
00959
00960 context_switch(lock, ien, empty_handler);
00961 }
00962
00963 void thr_join(thread_t *thread, int *exit_status)
00964 {
00965 sem_P(&thread->exit);
00966
00967 if(exit_status)
00968 *exit_status = thread->exit_status;
00969 }
00970
00971 void thr_set_name(thread_t *thread, char *name)
00972 {
00973 thread->name = name;
00974 }
00975
00976 void trt_init_scheduling_domain(domain_t *domain, int isa)
00977 {
00978 domain->isa = isa;
00979 domain->num_context_switches = 0;
00980 domain->num_thread_migrates = 0;
00981 }
00982
00983 void trt_set_scheduling_domain(int processor_index, domain_t *domain)
00984 {
00985 domain_t *domain_old = trt_processor_table[processor_index].domain;
00986
00987 assert(domain_old->isa == domain->isa);
00988
00989 trt_processor_table[processor_index].domain = domain;
00990 }
00991
00992 domain_t *trt_scheduling_domain(int processor_index)
00993 {
00994 return trt_processor_table[processor_index].domain;
00995 }
00996
00997 void thr_migrate_domain(thread_t *thread, domain_t *domain)
00998 {
00999 int i;
01000
01001 assert(thread->processor->domain->isa == domain->isa);
01002
01003 for(i = 0; i < trt_num_processors; i++)
01004 {
01005 if(trt_processor_table[i].domain == domain)
01006 {
01007 #if TRT_STATISTICS
01008 trt_processor_table[i].domain->num_thread_migrates++;
01009 #endif
01010
01011 thread->processor = &trt_processor_table[i];
01012
01013 if(thread == current_thread)
01014 thr_switch();
01015
01016 return;
01017 }
01018 }
01019 }
01020
01023 #if 0
01024
01025 #define ROUTE_HEADER(src, dst, dir0, dist0, dir1, dist1) \
01026 ((dst) | ((src) << 8) | ((dist1) << 16) | ((dir1) << 21) | \
01027 ((dist0) << 22) | ((dir0) << 27) | (5 << 28))
01028 #endif
01029
01030 static volatile int num_tile_rows = 0;
01031 static volatile int num_tile_cols = 0;
01032 static volatile int num_tile_rows_cols_valid = FALSE;
01033
01034 int trt_num_tiles()
01035 {
01036 return num_tile_rows * num_tile_cols;
01037 }
01038
01041 #define K(n) ((n) >> 10)
01042 #define M(n) ((n) >> 20)
01043
01044 void trt_init(int *stack_bot, int *stack_top)
01045 {
01046 static domain_t domain = {ISA, 0, 0};
01047 static int stack_overflow_magic = TRT_STACK_OVERFLOW_MAGIC;
01048 static thread_t main_thread;
01049 processor_t *processor;
01050 int processor_index;
01051
01052 processor_index = atomic_addi(trt_num_processors, 1);
01053 processor = &trt_processor_table[processor_index];
01054
01055 assert(processor_index < TRT_MAX_NUM_PROCESSORS_PER_TILE);
01056
01057 set_current_processor(processor);
01058
01059 processor->index = processor_index;
01060 processor->purpose = GENERAL;
01061 processor->domain = &domain;
01062
01063 current_thread = &processor->crt0_thread;
01064 current_thread->processor = processor;
01065 current_thread->name = "root";
01066 current_thread->stack = NULL;
01067 current_thread->block_handler = empty_handler;
01068 current_thread->id = atomic_add(trt_next_thread_ID, 1);
01069
01070 thr_set_cache_ddr_domain(current_thread, 0, 0);
01071
01072 if(stack_top != NULL)
01073 {
01074 current_thread->stack_magic = stack_bot + 1;
01075 current_thread->stack_magic[0] = TRT_STACK_OVERFLOW_MAGIC;
01076 }
01077 else
01078 current_thread->stack_magic = &stack_overflow_magic;
01079
01080 thread_table_add(current_thread);
01081
01082
01083
01084 sym_register("$call_start_function", call_start_function);
01085 sym_register("$call_function", call_function);
01086 sym_register("$empty_handler", empty_handler);
01087
01088 num_tile_rows = MAX(1, num_tile_rows);
01089 num_tile_cols = MAX(1, num_tile_cols);
01090 }
01091
01092 void trt_finalize(int status)
01093 {
01094 }
01095
01098 void sem_init(semaphore_t *semaphore, int init, char *name)
01099 {
01100 semaphore->count = init;
01101 semaphore->blocked_head = NULL;
01102 semaphore->blocked_tail = NULL;
01103 semaphore->blocked_lock = FALSE;
01104 semaphore->name = name;
01105 }
01106
01107 void sem_block_me(semaphore_t *semaphore)
01108 {
01109 thread_t *curr = current_thread;
01110 int ien;
01111
01112 append(semaphore->blocked, curr, ien);
01113
01114 curr->blocked_on = semaphore;
01115
01116 context_switch(&semaphore->blocked_lock, ien, curr->block_handler);
01117 }
01118
01119 void sem_unblock_someone(semaphore_t *semaphore)
01120 {
01121 thread_t *thread;
01122 int ien;
01123
01124 retry: ien = acquire_lock(semaphore->blocked_lock, TRUE);
01125
01126 thread = (thread_t *) semaphore->blocked_head;
01127
01128 if(thread == NULL)
01129 {
01130 release_lock(semaphore->blocked_lock, ien);
01131
01132 while(!force_load(semaphore->blocked_head))
01133 ;
01134
01135 goto retry;
01136 }
01137
01138 semaphore->blocked_head = thread->next;
01139
01140 release_lock(semaphore->blocked_lock, ien);
01141
01142 thread->blocked_on = NULL;
01143
01144 add_to_ready_list(thread, FALSE, FIFO_READY_LIST);
01145 }
01146
01147 #define atomic_sub_special(var, val, dec_leq0, dec, old_val) \
01148 { \
01149 int new_val; \
01150 \
01151 (old_val) = (var); \
01152 (dec) = ((old_val) <= 0) ? (dec_leq0) : MIN((old_val), (val)); \
01153 new_val = (old_val) - (dec); \
01154 (var) = new_val; \
01155 }
01156
01157 int sem_Pn(semaphore_t *semaphore, int n)
01158 {
01159 thread_t *curr = current_thread;
01160 int dec, old_count, dummy, ien;
01161
01162 atomic_sub_special(semaphore->count, n, 1, dec, old_count);
01163
01164 if(old_count <= 0)
01165 {
01166 append(semaphore->blocked, curr, ien);
01167
01168 curr->blocked_on = semaphore;
01169
01170 context_switch(&semaphore->blocked_lock, ien,
01171 curr->block_handler);
01172
01173 atomic_sub_special(semaphore->count, n - 1, 0, dec, dummy);
01174
01175 return 1 + dec;
01176 }
01177 else
01178 return dec;
01179 }
01180
01181 void sem_Vn(semaphore_t *semaphore, int n)
01182 {
01183 int old_count, ien;
01184 thread_t *thread;
01185
01186 old_count = atomic_add(semaphore->count, n);
01187
01188 if(old_count < 0)
01189 {
01190 n = MIN(n, -old_count);
01191
01192 ien = acquire_lock(semaphore->blocked_lock, TRUE);
01193
01194 while(n-- > 0)
01195 {
01196 retry: thread = (thread_t *) semaphore->blocked_head;
01197
01198 if(thread == NULL)
01199 {
01200 release_lock(semaphore->blocked_lock, ien);
01201
01202 while(!force_load(semaphore->blocked_head))
01203 ;
01204
01205 acquire_lock(semaphore->blocked_lock, TRUE);
01206
01207 goto retry;
01208 }
01209
01210 semaphore->blocked_head = thread->next;
01211
01212 thread->blocked_on = NULL;
01213
01214 add_to_ready_list(thread, FALSE, FIFO_READY_LIST);
01215 }
01216
01217 release_lock(semaphore->blocked_lock, ien);
01218 }
01219 }
01220
01221 void thr_set_cache_ddr_domain(thread_t *thread, int cache_domain,
01222 int ddr_domain)
01223 {
01224 thread->task_id = (thread->id & 0xffff) |
01225 ((cache_domain & 0x1f) << 16) |
01226 ((ddr_domain & 0x1f) << 21);
01227 }
01228
01231 static void dump_processor_info(char *dummy)
01232 {
01233 processor_t *p;
01234 thread_t *t;
01235 int i;
01236
01237 serial_out("%18s ", "RUNNING");
01238 serial_out("%8s ", "WHERE");
01239 serial_out("%8s ", "ISA");
01240 serial_out("READY LIST\n");
01241
01242 for(i = 0; i < trt_num_processors; i++)
01243 {
01244 p = &trt_processor_table[i];
01245
01246 serial_out("%18s ", p->running_thread ? p->running_thread->name
01247 : "-");
01248 serial_out("%8s ", isa_name(p->domain->isa));
01249
01250 for(t = p->ready_list_head; t != NULL; t = t->next)
01251 serial_out("%s ", t->name);
01252
01253 if(p->schedule_me)
01254 serial_out("%s ", p->schedule_me->name);
01255
01256 serial_out("\n");
01257 }
01258 }
01259
01260 static void dump_thread_info(char *dummy)
01261 {
01262 thread_t *t;
01263
01264 for(t = trt_thread_table.head; t; t = t->next_table)
01265 thr_dump_info(t, t == trt_thread_table.head);
01266 }
01267
01268 static void dump_registry_info_R(char *dummy)
01269 {
01270 sym_dump(TRUE);
01271 }
01272
01273 static void dump_registry_info_r(char *dummy)
01274 {
01275 sym_dump(FALSE);
01276 }
01277
01278 void thr_dump_info(thread_t *thread, int header)
01279 {
01280 if(header)
01281 serial_out(" P BLOCKED ISA NAME\n");
01282
01283 serial_out("%d ", thread->processor->index);
01284
01285 if(thread->stack_magic == NULL)
01286 serial_out(" EMBRYO ");
01287 else if(thread->exit.count > 0)
01288 serial_out(" ZOMBIE ");
01289 else if(!thread->blocked_on)
01290 serial_out(" ");
01291 else
01292 serial_out("%8s ", thread->blocked_on->name);
01293
01294 serial_out("%8s %s\n", thr_isa_name(thread), thread->name);
01295 }
01296
01297 static struct dbg_handler_s
01298 {
01299 char *name;
01300 char *help;
01301 void (*handler)(char *);
01302 } dbg_handler[32];
01303
01304 void trt_debug_handler(char *name, void (*handler)(char *), char *help)
01305 {
01306 int i;
01307
01308 for(i = 0; i < 32; i++)
01309 {
01310 struct dbg_handler_s *p = &dbg_handler[i];
01311
01312 if(!p->name || !p->handler || !strcmp(p->name, name))
01313 {
01314 p->name = name;
01315 p->help = help;
01316 p->handler = handler;
01317
01318 return;
01319 }
01320 }
01321
01322 trt_panic_s("trt_debug_handler: can not register", name);
01323 }
01324
01327 static void panic()
01328 {
01329 char *thread_name;
01330
01331 thread_name = current_thread && current_thread->name
01332 ? current_thread->name
01333 : "???";
01334
01335 serial_out("\tthread = %s\n", thread_name);
01336 serial_out("\tcpu = %d (%s)\n", trt_processor_index(),
01337 isa_name(ISA));
01338
01339 _exit(1);
01340 }
01341
01342 void trt_panic(char *error_message)
01343 {
01344 serial_out("PANIC: %s\n", error_message);
01345
01346 panic();
01347 }
01348
01349 void trt_panic_d(char *error_message, int argument)
01350 {
01351 serial_out("PANIC: %s: %d\n", error_message, argument);
01352
01353 panic();
01354 }
01355
01356 void trt_panic_s(char *error_message, char *argument)
01357 {
01358 serial_out("PANIC: %s: %s\n", error_message, argument);
01359
01360 panic();
01361 }
01362
01365 void *trt_malloc(unsigned int size)
01366 {
01367 char *p = malloc(size);
01368
01369 if(p == NULL)
01370 trt_panic("Out of memory");
01371
01372 return p;
01373 }
01374
01375 void trt_free(void *p)
01376 {
01377 free(p);
01378 }
01379
01382 extern volatile sym_table_t trt_sym_table;
01383
01384 static int sym_hash(int isa, char *name)
01385 {
01386 int s = isa, i;
01387
01388 for(i = 0; name[i]; i++)
01389 s ^= name[i] << (i & 7);
01390
01391 return s;
01392 }
01393
01394 void sym_register(char *name, void *addr)
01395 {
01396 sym_t *new;
01397 int hash, index, ien;
01398
01399 assert(addr != NULL);
01400
01401 if(sym_query(ISA, name, FALSE))
01402 return;
01403
01404 new = trt_malloc(sizeof(sym_t));
01405 hash = sym_hash(ISA, name);
01406 index = (unsigned) hash % 19u;
01407
01408 ien = acquire_lock(trt_sym_table.lock, TRUE);
01409
01410 new->isa = ISA;
01411 new->hash = hash;
01412 new->name = name;
01413 new->addr = addr;
01414 new->next = trt_sym_table.list[index];
01415 trt_sym_table.list[index] = new;
01416
01417 release_lock(trt_sym_table.lock, ien);
01418 }
01419
01420 void *sym_query(int isa, char *name, int wait)
01421 {
01422 int hash, index, count = 0;
01423 sym_t *p;
01424
01425 isa = ISA;
01426
01427 hash = sym_hash(isa, name);
01428 index = (unsigned) hash % 19u;
01429
01430 while(TRUE)
01431 {
01432 for(p = trt_sym_table.list[index]; p; p = p->next)
01433 {
01434 if(p->hash == hash &&
01435 p->isa == isa && !strcmp(p->name, name))
01436 return p->addr;
01437 }
01438
01439 if(!wait)
01440 return NULL;
01441
01442 if(++count % 5000 == 0)
01443 serial_out("sym_query: waiting for %s/%s\n",
01444 name, isa_name(isa));
01445
01446 thr_switch();
01447 }
01448 }
01449
01450 void sym_dump(int system)
01451 {
01452 sym_t *p;
01453 int i;
01454
01455 for(i = 0; i < 19; i++)
01456 {
01457 for(p = trt_sym_table.list[i]; p; p = p->next)
01458 {
01459 if(system ^ (p->name[0] == '$'))
01460 continue;
01461
01462 serial_out("%x %8s %s\n", p->addr, isa_name(p->isa),
01463 p->name);
01464 }
01465 }
01466 }
01467
01470 int trt_load()
01471 {
01472 thread_t *t;
01473 processor_t *p;
01474 int count = 0, ien, i;
01475
01476 for(i = 0; i < trt_num_processors; i++)
01477 {
01478 p = &trt_processor_table[i];
01479
01480 if(p->purpose != GENERAL)
01481 continue;
01482
01483 ien = acquire_lock(p->ready_list_lock, TRUE);
01484
01485 if(p->running_thread)
01486 count++;
01487
01488 if(p->schedule_me)
01489 count++;
01490
01491 for(t = (thread_t *) p->ready_list_head; t; t = t->next)
01492 count++;
01493
01494 release_lock(p->ready_list_lock, ien);
01495 }
01496
01497 return count;
01498 }
01499
01500 int trt_num_procs(int isa)
01501 {
01502 int i, count = 0;
01503 processor_t *p;
01504
01505 for(i = 0; i < trt_num_processors; i++)
01506 {
01507 p = &trt_processor_table[i];
01508
01509 if(p->purpose == GENERAL && (isa < 0 || p->domain->isa == isa))
01510 count++;
01511 }
01512
01513 return count;
01514 }
01515
01516 static void schedule_me(processor_t *processor)
01517 {
01518 if(processor == get_current_processor())
01519 return;
01520
01521 if(SAVE_CONTEXT(current_thread->context.context))
01522 return;
01523
01524 acquire_lock_no_ien(processor->schedule_me, current_thread);
01525
01526
01527
01528 switch_to_scheduler_stack(schedule_next_thread, empty_handler);
01529 }
01530
01533 void trt_putc(int port, char c)
01534 {
01535 putchar(c);
01536 }
01537
01538 static void trt_putcn(int n, char c)
01539 {
01540 while(n-- > 0)
01541 trt_putc(0, c);
01542 }
01543
01544 static void serial_out_hex(unsigned int n)
01545 {
01546 int i, d;
01547
01548 for(i = 28; i >= 0; i -= 4)
01549 {
01550 d = (n >> i) & 15;
01551
01552 if(d < 10)
01553 trt_putc(0, d + '0');
01554 else
01555 trt_putc(0, d + 'a' - 10);
01556 }
01557 }
01558
01559 static void serial_out_str(char *s, int left, int field)
01560 {
01561 int len;
01562
01563 if(s == NULL)
01564 s = "<NULL>";
01565
01566 if(field)
01567 {
01568 len = strlen(s);
01569
01570 if(!left)
01571 trt_putcn(field - len, ' ');
01572
01573 while(*s)
01574 trt_putc(0, *s++);
01575
01576 if(left)
01577 trt_putcn(field - len, ' ');
01578 }
01579 else
01580 {
01581 while(*s)
01582 trt_putc(0, *s++);
01583 }
01584 }
01585
01586 static void serial_out_dec(int n, int is_signed, int left, int field)
01587 {
01588 char buff[40], *s = &buff[39];
01589 unsigned int un, negative;
01590
01591 if(is_signed && n < 0)
01592 {
01593 negative = 1;
01594 un = (unsigned int) -n;
01595 }
01596 else
01597 {
01598 negative = 0;
01599 un = (unsigned int) n;
01600 }
01601
01602 *s = '\0';
01603
01604 do
01605 {
01606 *(--s) = '0' + un % 10;
01607 un /= 10;
01608 } while(un > 0);
01609
01610 if(negative)
01611 *(--s) = '-';
01612
01613 serial_out_str(s, left, field);
01614 }
01615
01616 static void formated_out(char *format, va_list arg_list)
01617 {
01618 int field, left;
01619
01620 if(format == NULL)
01621 format = "<NULL>";
01622
01623 while(*format)
01624 {
01625 if(*format != '%')
01626 {
01627 trt_putc(0, *format++);
01628 continue;
01629 }
01630
01631 format++;
01632
01633 if(*format == '-')
01634 {
01635 format++;
01636 left = 1;
01637 }
01638 else
01639 left = 0;
01640
01641 field = 0;
01642 while(isdigit(*format))
01643 field = 10 * field + *format++ - '0';
01644
01645 switch(*format)
01646 {
01647 case 's': serial_out_str(va_arg(arg_list, char *),
01648 left, field);
01649 break;
01650 case 'u': serial_out_dec(va_arg(arg_list, int), 0,
01651 left, field);
01652 break;
01653 case 'd': serial_out_dec(va_arg(arg_list, int), 1,
01654 left, field);
01655 break;
01656 case 'x':
01657 case 'p': serial_out_hex(va_arg(arg_list, int));
01658 break;
01659 case 'c': trt_putc(0, va_arg(arg_list, int));
01660 break;
01661 case '%': trt_putc(0, *format);
01662 break;
01663 default: trt_putc(0, '%');
01664 trt_putc(0, *format);
01665 break;
01666 }
01667
01668 format++;
01669 }
01670 }
01671
01672 void serial_out(char *format, ...)
01673 {
01674 va_list arg_list;
01675 int ien;
01676
01677 ien = acquire_lock(trt_serial_lock, TRUE);
01678
01679 va_start(arg_list, format);
01680
01681 formated_out(format, arg_list);
01682
01683 va_end(arg_list);
01684
01685 release_lock(trt_serial_lock, ien);
01686 }
01687