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 #ifdef NUTDEBUG
00221 #include <sys/osdebug.h>
00222 #endif
00223
00224 #ifdef NUTTRACER
00225 #include <sys/tracer.h>
00226 #endif
00227
00232
00233 #if defined(NUT_CRITICAL_NESTING) && !defined(NUT_CRITICAL_NESTING_STACK)
00234 unsigned int critical_nesting_level;
00235 #endif
00236
00237 #ifdef __NUT_EMULATION__
00238
00239 extern void NutUnixThreadYieldHook(void);
00240 #endif
00241
00248 NUTTHREADINFO * runningThread;
00249
00256 NUTTHREADINFO * killedThread;
00257
00266 NUTTHREADINFO * nutThreadList;
00267
00275 NUTTHREADINFO * runQueue;
00276
00277
00278
00289 void NutThreadAddPriQueue(NUTTHREADINFO * td, NUTTHREADINFO * volatile *tqpp)
00290 {
00291 NUTTHREADINFO *tqp;
00292
00293 NUTASSERT(td != NULL);
00294
00295 td->td_queue = (HANDLE) tqpp;
00296 td->td_qpec = 0;
00297
00298
00299
00300
00301
00302
00303 NutEnterCritical();
00304 tqp = *tqpp;
00305
00306 if (tqp == SIGNALED) {
00307 tqp = 0;
00308 td->td_qpec++;
00309 } else if (tqp) {
00310 NutExitCritical();
00311
00312
00313 while (tqp && tqp->td_priority <= td->td_priority) {
00314 tqpp = &tqp->td_qnxt;
00315 tqp = tqp->td_qnxt;
00316 }
00317
00318 NutEnterCritical();
00319 }
00320
00321 td->td_qnxt = tqp;
00322
00323 *tqpp = td;
00324 if (td->td_qnxt && td->td_qnxt->td_qpec) {
00325 td->td_qpec += td->td_qnxt->td_qpec;
00326 td->td_qnxt->td_qpec = 0;
00327 }
00328 NutExitCritical();
00329 }
00330
00341 void NutThreadRemoveQueue(NUTTHREADINFO * td, NUTTHREADINFO * volatile *tqpp)
00342 {
00343 NUTTHREADINFO *tqp;
00344
00345 NutEnterCritical();
00346 tqp = *tqpp;
00347 NutExitCritical();
00348
00349 if (tqp != SIGNALED) {
00350 while (tqp) {
00351 if (tqp == td) {
00352 NutEnterCritical();
00353 *tqpp = td->td_qnxt;
00354 if (td->td_qpec) {
00355 if (td->td_qnxt) {
00356 td->td_qnxt->td_qpec = td->td_qpec;
00357 }
00358 td->td_qpec = 0;
00359 }
00360 NutExitCritical();
00361
00362 td->td_qnxt = 0;
00363 td->td_queue = 0;
00364 break;
00365 }
00366 tqpp = &tqp->td_qnxt;
00367 tqp = tqp->td_qnxt;
00368 }
00369 }
00370 }
00371
00382 void NutThreadResume(void)
00383 {
00384 NUTTHREADINFO *td;
00385 NUTTHREADINFO **qhp;
00386 NUTTHREADINFO *tqp;
00387 unsigned int cnt;
00388
00389
00390
00391
00392 td = nutThreadList;
00393 while (td) {
00394 NutEnterCritical();
00395 cnt = td->td_qpec;
00396 NutExitCritical();
00397 if (cnt) {
00398
00399
00400 qhp = (NUTTHREADINFO **)(td->td_queue);
00401 NutEnterCritical();
00402 td->td_qpec--;
00403 tqp = *qhp;
00404 NutExitCritical();
00405 if (tqp != SIGNALED) {
00406 NutEventPostAsync((HANDLE *)qhp);
00407 }
00408 }
00409 td = td->td_next;
00410 }
00411
00412
00413
00414
00415
00416 NutTimerProcessElapsed();
00417
00418
00419 if (runningThread != runQueue) {
00420 #ifdef NUTTRACER
00421 TRACE_ADD_ITEM(TRACE_TAG_THREAD_YIELD,(int)runningThread);
00422 #endif
00423
00424 if (runningThread->td_state == TDS_RUNNING) {
00425 runningThread->td_state = TDS_READY;
00426 }
00427 NutEnterCritical();
00428 NutThreadSwitch();
00429 NutExitCritical();
00430 }
00431 }
00432
00450 void NutThreadWake(HANDLE timer, HANDLE th)
00451 {
00452 NUTASSERT(th != NULL);
00453
00454
00455 ((NUTTHREADINFO *) th)->td_timer = 0;
00456 ((NUTTHREADINFO *) th)->td_state = TDS_READY;
00457 NutThreadAddPriQueue(th, (NUTTHREADINFO **) & runQueue);
00458 }
00459
00468 void NutThreadYield(void)
00469 {
00470
00471 #ifdef __NUT_EMULATION__
00472 NutEnterCritical();
00473 NutUnixThreadYieldHook();
00474 NutExitCritical();
00475 #endif
00476
00477
00478
00479
00480
00481
00482 if (runningThread->td_qnxt) {
00483 NutThreadRemoveQueue(runningThread, (NUTTHREADINFO **) & runQueue);
00484 NutThreadAddPriQueue(runningThread, (NUTTHREADINFO **) & runQueue);
00485 }
00486
00487
00488 NutThreadResume();
00489 }
00490
00518 uint8_t NutThreadSetPriority(uint8_t level)
00519 {
00520 uint8_t last = runningThread->td_priority;
00521
00522
00523
00524
00525
00526
00527 NutThreadRemoveQueue(runningThread, &runQueue);
00528 runningThread->td_priority = level;
00529 if (level < 255) {
00530 NutThreadAddPriQueue(runningThread, (NUTTHREADINFO **) & runQueue);
00531 } else {
00532 NutThreadKill();
00533 }
00534
00535
00536
00537
00538
00539 if (runningThread == runQueue) {
00540 runningThread->td_state = TDS_RUNNING;
00541 } else {
00542 runningThread->td_state = TDS_READY;
00543 #ifdef NUTTRACER
00544 TRACE_ADD_ITEM(TRACE_TAG_THREAD_SETPRIO,(int)runningThread);
00545 #endif
00546
00547 NutEnterCritical();
00548 NutThreadSwitch();
00549 NutExitCritical();
00550 }
00551
00552 return last;
00553 }
00554
00565 void NutThreadExit(void)
00566 {
00567 NutThreadSetPriority(255);
00568 }
00569
00579 void NutThreadDestroy(void)
00580 {
00581 if (killedThread) {
00582 NutStackFree(killedThread->td_memory);
00583 killedThread = 0;
00584 }
00585 }
00586
00594 void NutThreadKill(void)
00595 {
00596
00597 NUTTHREADINFO *pCur = nutThreadList;
00598 NUTTHREADINFO **pp = (NUTTHREADINFO **) & nutThreadList;
00599
00600
00601 NutThreadDestroy();
00602
00603
00604 while (pCur) {
00605 if (pCur == runningThread) {
00606 *pp = pCur->td_next;
00607 break;
00608 }
00609
00610 pp = (NUTTHREADINFO **) & pCur->td_next;
00611 pCur = pCur->td_next;
00612 }
00613
00614
00615 killedThread = runningThread;
00616 }
00617
00627 HANDLE GetThreadByName(char * name)
00628 {
00629 NUTTHREADINFO *tdp;
00630
00631 if (name) {
00632 for (tdp = nutThreadList; tdp; tdp = tdp->td_next) {
00633 if (strcmp(tdp->td_name, name) == 0)
00634 return tdp;
00635 }
00636 } else {
00637 return runningThread;
00638 }
00639 return NULL;
00640 }
00641
00642 #if defined(NUTDEBUG_CHECK_STACKMIN) || defined(NUTDEBUG_CHECK_STACK)
00643
00644 static size_t StackAvail(NUTTHREADINFO *td)
00645 {
00646 uint32_t *sp = (uint32_t *)td->td_memory;
00647
00648 while(*sp++ == DEADBEEF);
00649
00650 return (size_t)((uintptr_t)sp - (uintptr_t)td->td_memory);
00651 }
00652
00674 size_t NutThreadStackAvailable(char *name)
00675 {
00676 NUTTHREADINFO *tdp = (NUTTHREADINFO *)GetThreadByName(name);
00677
00678 return tdp ? StackAvail(tdp) : 0;
00679 }
00680
00692 NUTTHREADINFO *NutThreadStackCheck(size_t minsiz)
00693 {
00694 NUTTHREADINFO *tdp;
00695
00696 for (tdp = nutThreadList; tdp; tdp = tdp->td_next) {
00697 if (StackAvail(tdp) < minsiz) {
00698 break;
00699 }
00700 }
00701 return tdp;
00702 }
00703 #endif
00704