From: gkochanski AT attmail DOT com Date: 27 Sep 92 23:52:06 GMT To: djgpp AT sun DOT soe DOT clarkson DOT edu Message-Version: 2 >To: internet!sun.soe.clarkson.edu!djgpp Original-Date: Sun Sep 27 23:52:06 GMT 1992 Original-From: attmail!gkochanski (Greg Kochanski ) Mts-Message-Id: Ua-Content-Id: Email-Version: 2 Subject: Task Package Fixes Ua-Message-Id: Original-To: attmail!internet!sun.soe.clarkson.edu!djgpp Despite significant efforts, I was not able to get the contributed task library (.../contrib/tasks) to do anything but wedge itself, even on its own test program. To console myself, I upgraded the supplied (and functional) task package in .../samples/grtask to allow the creation of semaphores and mailboxes (not included here). I also added a few comments to make it a bit more intelligible, and reduced the time to task switch (by eliminating a setjmp/longjmp pair in case the task doesn't need to change when Yield() is called. I also added the possibility of a single high-priority task that gets called once between every two other tasks. Also, I added the capability of killing a task from another, and caused all descendants of a task to die when the parent dies. This makes it a *lot* easier to clean things up when a program is finished. There were also a few other minor cleanups, such as changing the default stacksize from 1024 (very small) to 9999 bytes. ##################task.h differences #################### *** /djgpp2/samples/grtask/task.h Wed Mar 20 16:56:38 1991 --- task.h Thu Sep 10 17:23:48 1992 *************** *** 6,9 typedef int (TaskProc)(int, void*); class Task { public: --- 6,10 ----- typedef int (TaskProc)(int, void*); + class Task { public: *************** *** 31,35 public: ! Task(TaskProc proc=0, int val=0, void* ptr=0, int stacksize=1024); // use default proc in main() to setup initial task ~Task(); --- 32,41 ----- public: ! Task(TaskProc proc=0, int val=0, void* ptr=0, int stacksize=9999, ! int priviliged=0); ! // use default proc in main() to setup initial task ! /* Val and ptr are passed into TaskProc when it begins */ ! /* to execute. If proviliged is nonzero, the task will */ ! /* be executed once for every call to Yield(). */ ~Task(); *************** *** 38,41 friend int Wait(Task* child=0); friend void Return(int rv=0); friend void Yield(); }; --- 44,48 ----- friend int Wait(Task* child=0); friend void Return(int rv=0); + /* All child tasks are killed when a task returns. */ friend void Yield(); friend void Block(Task **my_task_ptr); *************** *** 39,42 friend void Return(int rv=0); friend void Yield(); }; --- 46,59 ----- /* All child tasks are killed when a task returns. */ friend void Yield(); + friend void Block(Task **my_task_ptr); + /* This task won't execute until unblock() is called. */ + /* My_task_ptr points to a place to put an identifier for */ + /* this task; you'll need it to unblock. Usually used as */ + /* Task *p; Block(&p); ....... Unblock(p); */ + /* Execution doesn't make it out of Block() until Unblock() */ + /* is called (from another task). */ + friend void Unblock(Task *blocked_task); + friend void Kill(Task *victim_task, int rv=0); + /* Equivalent to having the victim task call Return(rv) */ }; *************** *** 40,45 friend void Yield(); }; - - extern Task *thisTask; #endif --- 57,60 ----- /* Equivalent to having the victim task call Return(rv) */ }; #endif ##################task.cc differences #################### *** /djgpp2/samples/grtask/task.cc Wed Mar 20 16:56:38 1991 --- task.cc Fri Sep 11 19:07:26 1992 *************** *** 3,6 #include #include "Task.h" --- 3,10 ----- #include + typedef int BOOL; + #define FALSE 0 + #define TRUE 1 + #include "Task.h" *************** *** 7,12 #define dprintf if(0)printf ! Task *thisTask=0; ! static Task *task_list=0; --- 11,16 ----- #define dprintf if(0)printf ! static Task *thisTask=0; ! static Task *priviligedTask=0; static Task *task_list=0; *************** *** 24,28 case Task::Dead: rs="Dead"; break; } ! dprintf(" 0x%08x p=0x%08x s=%s\n", t, t->parent, rs); } } --- 28,33 ----- case Task::Dead: rs="Dead"; break; } ! dprintf(" 0x%08x p=0x%08x s=%s%c\n", t, t->parent, rs, ! t==thisTask?'*':' '); } } *************** *** 36,40 } ! Task::Task(TaskProc proc, int val, void* ptr, int stacksize) { prev = 0; --- 41,45 ----- } ! Task::Task(TaskProc proc, int val, void* ptr, int stacksize, int priviliged) { prev = 0; *************** *** 47,52 memset(state, 0, sizeof(state)); stack = 0; ! if (proc) ! { stack_len = stacksize; stack = new unsigned[stacksize]; --- 52,56 ----- memset(state, 0, sizeof(state)); stack = 0; ! if (proc) { stack_len = stacksize; stack = new unsigned[stacksize]; *************** *** 57,61 state->esp = (unsigned)(stack+stacksize-3); state->eip = (unsigned long) proc; ! } if (thisTask == 0) thisTask = this; --- 61,65 ----- state->esp = (unsigned)(stack+stacksize-3); state->eip = (unsigned long) proc; ! } if (thisTask == 0) thisTask = this; *************** *** 60,63 if (thisTask == 0) thisTask = this; dprintf("Task::Task -> 0x%x\n", this); } --- 64,69 ----- if (thisTask == 0) thisTask = this; + if(priviliged) + priviligedTask = this; dprintf("Task::Task -> 0x%x\n", this); } *************** *** 94,99 else dprintf("Task::Wait\n"); ! while (waiting) ! { waiting = 0; if (child) --- 100,104 ----- else dprintf("Task::Wait\n"); ! while (waiting) { waiting = 0; if(child && child->run_state==Task::Dead) { *************** *** 97,104 { waiting = 0; ! if (child) ! { ! if (child->run_state == Task::Dead) ! { rv = child->ret_val; delete child; --- 102,106 ----- while (waiting) { waiting = 0; ! if(child && child->run_state==Task::Dead) { rv = child->ret_val; delete child; *************** *** 104,109 delete child; return rv; ! } ! } Task *t, *tn; --- 106,110 ----- delete child; return rv; ! } Task *t, *tn; *************** *** 108,113 Task *t, *tn; ! for (t=task_list; t; t=tn) ! { tn = t->next; if (t->parent == thisTask) --- 109,113 ----- Task *t, *tn; ! for (t=task_list; t; t=tn) { tn = t->next; if (t->parent == thisTask) { *************** *** 111,118 { tn = t->next; ! if (t->parent == thisTask) ! { ! if (t->run_state == Task::Dead) ! { dprintf("Dead child 0x%x\n", t); delete t; --- 111,116 ----- for (t=task_list; t; t=tn) { tn = t->next; ! if (t->parent == thisTask) { ! if (t->run_state == Task::Dead) { dprintf("Dead child 0x%x\n", t); delete t; *************** *** 117,123 dprintf("Dead child 0x%x\n", t); delete t; ! } ! else ! { dprintf("Running child 0x%x\n", t); waiting = 1; --- 115,120 ----- dprintf("Dead child 0x%x\n", t); delete t; ! } ! else { dprintf("Running child 0x%x\n", t); waiting = 1; *************** *** 125,130 } } ! if (waiting) ! { dprintf("parent waiting...\n"); thisTask->run_state = Task::Waiting; --- 122,126 ----- } } ! if (waiting) { dprintf("parent waiting...\n"); thisTask->run_state = Task::Waiting; *************** *** 132,135 } } } --- 128,132 ----- } } + return 0; } *************** *** 134,138 } ! void Return(int rv) { dprintf("Task::Return(%d) <- 0x%x\n", rv, thisTask); --- 131,135 ----- } ! void Yield() { dprintf("Task::Yield 0x%x -> ", thisTask); *************** *** 136,145 void Return(int rv) { ! dprintf("Task::Return(%d) <- 0x%x\n", rv, thisTask); ! thisTask->ret_val = rv; ! thisTask->run_state = Task::Dead; ! if (thisTask->parent) ! thisTask->parent->run_state = Task::Running; ! Yield(); } --- 133,163 ----- void Yield() { ! dprintf("Task::Yield 0x%x -> ", thisTask); ! if(priviligedTask && thisTask!=priviligedTask && ! priviligedTask->run_state==Task::Running) { ! if (setjmp(thisTask->state)) ! return; ! thisTask = priviligedTask; ! dprintf("0x%x P(0x%x)\n", thisTask, thisTask->state->eip); ! longjmp(thisTask->state, 1); ! } ! ! Task *p = thisTask; ! do { ! p = (p->next ? p->next : task_list); ! } while(p!=thisTask && p->run_state!=Task::Running); ! ! if(p->run_state != Task::Running) { ! fprintf(stderr, "Wedged.\n"); ! TaskList(); ! abort(); ! } ! else if(p != thisTask) { ! if (setjmp(thisTask->state)) ! return; ! thisTask = p; ! dprintf("0x%x (0x%x)\n", thisTask, thisTask->state->eip); ! longjmp(thisTask->state, 1); ! } } *************** *** 144,148 } ! void Yield() { dprintf("Task::Yield 0x%x -> ", thisTask); --- 162,166 ----- } ! void Unblock(Task *blocked_task) { if(blocked_task->run_state == Task::Blocked) *************** *** 146,163 void Yield() { ! dprintf("Task::Yield 0x%x -> ", thisTask); ! fflush(stdout); ! if (setjmp(thisTask->state)) ! return; ! while (1) ! { ! if (thisTask->next) ! thisTask = thisTask->next; ! else ! thisTask = task_list; ! if (thisTask->run_state == Task::Running) ! break; ! } ! dprintf("0x%x (0x%x)\n", thisTask, thisTask->state->eip); ! longjmp(thisTask->state,1); } --- 164,210 ----- void Unblock(Task *blocked_task) { ! if(blocked_task->run_state == Task::Blocked) ! blocked_task->run_state = Task::Running; ! } ! ! void Block(Task **p) ! { ! thisTask->run_state = Task::Blocked; ! *p = thisTask; ! Yield(); ! } ! ! void Kill(Task *victim, int rv) ! { ! Task *t; ! BOOL found = FALSE; ! ! dprintf("Task::Kill(%d) <- 0x%x\n", rv, victim); ! for (t=task_list; t; t=t->next) ! if(t == victim) { ! found = TRUE; ! if(victim->run_state != Task::Dead) { ! victim->ret_val = rv; ! victim->run_state = Task::Dead; ! if (victim->parent) ! victim->parent->run_state = Task::Running; ! } ! } ! ! if(!found) { ! fprintf(stderr, "Task::Kill - victim not found.\n"); ! abort(); ! } ! ! for (t=task_list; t; t=t->next) /* Kill all children of a victim. */ ! if(t->parent == victim) ! Kill(t, rv); ! ! if(victim == thisTask) ! Yield(); ! } ! ! void Return(int rv) ! { ! Kill(thisTask, rv); } --Greg Kochanski attmail!gkochanski