Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 
00048 
00207 #include <cfg/os.h>
00208 #include <cfg/memory.h>
00209 
00210 #include <string.h>
00211 
00212 #include <sys/types.h>
00213 #include <sys/heap.h>
00214 #include <sys/atom.h>
00215 #include <sys/timer.h>
00216 #include <sys/event.h>
00217 #include <sys/thread.h>
00218 #include <sys/nutdebug.h>
00219 
00220 #include <sys/osdebug.h>
00221 
00222 #ifdef NUTTRACER
00223 #include <sys/tracer.h>
00224 #endif
00225 
00230 
00231 #if defined(NUT_CRITICAL_NESTING) && !defined(NUT_CRITICAL_NESTING_STACK)
00232 unsigned int critical_nesting_level;
00233 #endif
00234 
00235 #ifdef __NUT_EMULATION__
00236 
00237 extern void NutUnixThreadYieldHook(void);  
00238 #endif
00239 
00246 NUTTHREADINFO * runningThread;
00247 
00254 NUTTHREADINFO * killedThread;
00255 
00264 NUTTHREADINFO * nutThreadList;
00265 
00273 NUTTHREADINFO * runQueue;
00274 
00275 
00276 
00287 void NutThreadAddPriQueue(NUTTHREADINFO * td, NUTTHREADINFO * volatile *tqpp)
00288 {
00289     NUTTHREADINFO *tqp;
00290 
00291     NUTASSERT(td != NULL);
00292 
00293     td->td_queue = (HANDLE) tqpp;
00294     td->td_qpec = 0;                    
00295 
00296     
00297 
00298 
00299 
00300 
00301     NutEnterCritical();
00302     tqp = *tqpp;
00303 
00304     if (tqp == SIGNALED) {
00305         tqp = 0;
00306         td->td_qpec++;                  
00307     } else if (tqp) {
00308         NutExitCritical();              
00309                                                 
00310 
00311         while (tqp && tqp->td_priority <= td->td_priority) {
00312             tqpp = &tqp->td_qnxt;
00313             tqp = tqp->td_qnxt;
00314         }
00315 
00316         NutEnterCritical();             
00317     }
00318 
00319     td->td_qnxt = tqp;
00320 
00321     *tqpp = td;
00322     if (td->td_qnxt && td->td_qnxt->td_qpec) {
00323         td->td_qpec += td->td_qnxt->td_qpec; 
00324         td->td_qnxt->td_qpec = 0;
00325     }
00326     NutExitCritical();
00327 }
00328 
00339 void NutThreadRemoveQueue(NUTTHREADINFO * td, NUTTHREADINFO * volatile *tqpp)
00340 {
00341     NUTTHREADINFO *tqp;
00342 
00343     NutEnterCritical();
00344     tqp = *tqpp;
00345     NutExitCritical();
00346 
00347     if (tqp != SIGNALED) {
00348         while (tqp) {
00349             if (tqp == td) {
00350                 NutEnterCritical();
00351                 *tqpp = td->td_qnxt;
00352                 if (td->td_qpec) {
00353                     if (td->td_qnxt) {
00354                         td->td_qnxt->td_qpec = td->td_qpec;
00355                     }
00356                     td->td_qpec = 0;
00357                 }
00358                 NutExitCritical();
00359 
00360                 td->td_qnxt = 0;
00361                 td->td_queue = 0;
00362                 break;
00363             }
00364             tqpp = &tqp->td_qnxt;
00365             tqp = tqp->td_qnxt;
00366         }
00367     }
00368 }
00369 
00380 void NutThreadResume(void)
00381 {
00382     NUTTHREADINFO *td;
00383     NUTTHREADINFO **qhp;
00384     NUTTHREADINFO *tqp;
00385     unsigned int cnt;
00386 
00387     
00388 
00389 
00390     td = nutThreadList;
00391     while (td) {
00392         NutEnterCritical();
00393         cnt = td->td_qpec;
00394         NutExitCritical();
00395         if (cnt) {
00396             
00397 
00398             qhp = (NUTTHREADINFO **)(td->td_queue);
00399             NutEnterCritical();
00400             td->td_qpec--;
00401             tqp = *qhp;
00402             NutExitCritical();
00403             if (tqp != SIGNALED) {
00404                 NutEventPostAsync((HANDLE *)qhp);
00405             }
00406         }
00407         td = td->td_next;
00408     }
00409 
00410     
00411 
00412 
00413 
00414     NutTimerProcessElapsed();
00415 
00416     
00417     if (runningThread != runQueue) {
00418 #ifdef NUTTRACER
00419         TRACE_ADD_ITEM(TRACE_TAG_THREAD_YIELD,(int)runningThread);
00420 #endif
00421 
00422         if (runningThread->td_state == TDS_RUNNING) {
00423             runningThread->td_state = TDS_READY;
00424         }
00425         NutEnterCritical();
00426         NutThreadSwitch();
00427         NutExitCritical();
00428     }
00429 }
00430 
00448 void NutThreadWake(HANDLE timer, HANDLE th)
00449 {
00450     NUTASSERT(th != NULL);
00451 
00452     
00453     ((NUTTHREADINFO *) th)->td_timer = 0;
00454     ((NUTTHREADINFO *) th)->td_state = TDS_READY;
00455     NutThreadAddPriQueue(th, (NUTTHREADINFO **) & runQueue);
00456 }
00457 
00466 void NutThreadYield(void)
00467 {
00468 
00469 #ifdef __NUT_EMULATION__
00470     NutEnterCritical();
00471     NutUnixThreadYieldHook();
00472     NutExitCritical();
00473 #endif
00474 
00475     
00476 
00477 
00478 
00479 
00480     if (runningThread->td_qnxt) {
00481         NutThreadRemoveQueue(runningThread, (NUTTHREADINFO **) & runQueue);
00482         NutThreadAddPriQueue(runningThread, (NUTTHREADINFO **) & runQueue);
00483     }
00484 
00485     
00486     NutThreadResume();
00487 }
00488 
00516 uint8_t NutThreadSetPriority(uint8_t level)
00517 {
00518     uint8_t last = runningThread->td_priority;
00519 
00520     
00521 
00522 
00523 
00524 
00525     NutThreadRemoveQueue(runningThread, &runQueue);
00526     runningThread->td_priority = level;
00527     if (level < 255) {
00528         NutThreadAddPriQueue(runningThread, (NUTTHREADINFO **) & runQueue);
00529     } else {
00530         NutThreadKill();
00531     }
00532 
00533     
00534 
00535 
00536 
00537     if (runningThread == runQueue) {
00538         runningThread->td_state = TDS_RUNNING;
00539     } else {
00540         runningThread->td_state = TDS_READY;
00541 #ifdef NUTTRACER
00542         TRACE_ADD_ITEM(TRACE_TAG_THREAD_SETPRIO,(int)runningThread);
00543 #endif
00544 
00545         NutEnterCritical();
00546         NutThreadSwitch();
00547         NutExitCritical();
00548     }
00549 
00550     return last;
00551 }
00552 
00563 void NutThreadExit(void)
00564 {
00565     NutThreadSetPriority(255);
00566 }
00567 
00577 void NutThreadDestroy(void)
00578 {
00579     if (killedThread) {
00580         NutStackFree(killedThread->td_memory);
00581         killedThread = 0;
00582     }
00583 }
00584 
00592 void NutThreadKill(void)
00593 {
00594 
00595     NUTTHREADINFO *pCur = nutThreadList;
00596     NUTTHREADINFO **pp = (NUTTHREADINFO **) & nutThreadList;
00597 
00598     
00599     NutThreadDestroy();
00600 
00601     
00602     while (pCur) {
00603         if (pCur == runningThread) {
00604             *pp = pCur->td_next;
00605             break;
00606         }
00607 
00608         pp = (NUTTHREADINFO **) & pCur->td_next;
00609         pCur = pCur->td_next;
00610     }
00611 
00612     
00613     killedThread = runningThread;
00614 }
00615 
00625 HANDLE GetThreadByName(char * name)
00626 {
00627     NUTTHREADINFO *tdp;
00628 
00629     if (name) {
00630         for (tdp = nutThreadList; tdp; tdp = tdp->td_next) {
00631             if (strcmp(tdp->td_name, name) == 0)
00632                 return tdp;
00633         }
00634     } else {
00635         return runningThread;
00636     }
00637     return NULL;
00638 }
00639 
00640 #if defined(NUTDEBUG_CHECK_STACKMIN) || defined(NUTDEBUG_CHECK_STACK)
00641 
00642 static size_t StackAvail(NUTTHREADINFO *td)
00643 {
00644     uint32_t *sp = (uint32_t *)td->td_memory;
00645 
00646     while(*sp++ == DEADBEEF);
00647 
00648     return (size_t)((uintptr_t)sp - (uintptr_t)td->td_memory);
00649 }
00650 
00672 size_t NutThreadStackAvailable(char *name)
00673 {
00674     NUTTHREADINFO *tdp = (NUTTHREADINFO *)GetThreadByName(name);
00675 
00676     return tdp ? StackAvail(tdp) : 0;
00677 }
00678 
00690 NUTTHREADINFO *NutThreadStackCheck(size_t minsiz)
00691 {
00692     NUTTHREADINFO *tdp;
00693 
00694     for (tdp = nutThreadList; tdp; tdp = tdp->td_next) {
00695         if (StackAvail(tdp) < minsiz) {
00696             break;
00697         }
00698     }
00699     return tdp;
00700 }
00701 #endif
00702