Main Page | Class Hierarchy | Compound List | File List | Compound Members | File Members

trt.c

Go to the documentation of this file.
00001 /*--------------------------------------------------------------------
00002  *
00003  * (C) Copyright Koninklijke Philips Electronics NV 2006. 
00004  * All rights reserved. This software is licensed under the terms of
00005  * version 2.1 of the GNU Lesser General Public License as published 
00006  * by the Free Software Foundation. For licensing and warranty
00007  * information, see the file COPYING in the main directory.
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  * processor table. one entry for each processor.
00043  */
00044 extern processor_t trt_processor_table[TRT_MAX_NUM_PROCESSORS_PER_TILE];
00045 
00046 /*
00047  * thread table. all threads in the system are in this table.
00048  */
00049 extern thread_table_t trt_thread_table;
00050 
00051 /*
00052  * number of processors in tile. incl. communication processors.
00053  */
00054 extern int trt_num_processors;
00055 
00056 /*
00057  * index of the tile we are running on.
00058  */
00059 extern int trt_tile_idx;
00060 
00061 /*
00062  * next ID to be assigned to thread.
00063  */
00064 extern unsigned int trt_next_thread_ID;
00065 
00066 /*
00067  * lock to do serial output
00068  */
00069 extern int trt_serial_lock;
00070 
00071 /*
00072  * pointer to the processor table entry for `this' processor.
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  * some forward decls
00085  */
00086 static void debug_handler(int key);
00087 
00090 /*
00091  * append member to list. lock but don't unlock!!
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  * prepend member to list. lock but don't unlock!!
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  * unlink member from a (locked) list.
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  * unlink head from a (locked) list.
00142  */
00143 #define unlink_head(list, head)                                   \
00144 {                                                                       \
00145   list ## _head = (head)->next;         \
00146 }
00147 
00148 /*
00149  * unlink tail from a (locked) list.
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  * add thread to ready list
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   /* p->domain->sleep_variable = 1; */
00200 
00201   return ien;
00202 }
00203 
00204 /*
00205  * divide idle_spin_count of all processors by 2.
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  * are all general purpose CPUs idle?
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  * steal thread from another processor.
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)       /* end of table? */
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)   /* stop if p is also stealing */
00272       break;
00273 
00274     if(p->ready_list_head == NULL)  /* skip if p has nothing */
00275       continue;
00276 
00277     if(!victim || victim->idle_spin_count > p->idle_spin_count)
00278       victim = p;             /* select lowest spin count */
00279   }
00280 
00281   if(victim == NULL)                      /* nothing found? */
00282     return NULL;
00283 
00284   /* now try to get a thread from victim */
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  * select a ready thread.
00317  */
00318 static thread_t *select_thread()
00319 {
00320   processor_t *p = get_current_processor();
00321   thread_t *t;
00322   int ien;
00323 
00324   /* before checking our ready list we check the schedule_me pointer
00325    * to see whether there is a thread that is forced to be scheduled
00326    * on this processor. */
00327   if(t = p->schedule_me)
00328   {
00329     release_lock_no_ien(p->schedule_me);
00330 
00331     goto exit;
00332   }
00333 
00334   /* (void) p->domain->sleep_variable; */
00335 
00336   /* lock our ready list */
00337   ien = acquire_lock(p->ready_list_lock, TRUE);
00338 
00339   /* let's see whether there is something in it */
00340   while((t = force_load(p->ready_list_head)) == NULL)
00341   {
00342     /* if not then release lock so that another processor can put
00343      * something in our ready list */
00344     release_lock(p->ready_list_lock, ien);
00345 
00346     /* wait for it */
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       /* sws(p->domain->sleep_variable); */
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     /* there is something in our ready list. before we try
00378      * to grab it we first have to lock the list again. */
00379     acquire_lock(p->ready_list_lock, TRUE);
00380   }
00381 
00382   /* unlink first thread of our ready list. */
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  * select a ready thread and switch to it. don't save context of 
00436  * current thread. run block_handler prior to selection of a new thread.
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  * do a context switch. run block handler between the old and new thread.
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;              /* context to return to */
00606   int (*fun)(int, int, int, int); /* function to be called */
00607   int arg[4];                     /* arguments for it */
00608   int result;                     /* its result */
00609   void (*block_handler)();        /* saved block_handler */
00610   processor_t *processor;         /* processor that did thr_call_isa */
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 = &current_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) /* already exited? */
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 = &current_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 /* header for old router */
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   /* at this point only one processor per isa will come by */
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)   /* were there any threads blocked? */
01189   {
01190     n = MIN(n, -old_count); /* determine how many to unblock */
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   /* processor->domain->sleep_variable = 1; */
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 

Generated on Wed Feb 15 14:52:39 2006 for yapi by doxygen 1.3.2