static void WrapperLoop(workerctx_t *wp) { lpel_task_t *t = NULL; workermsg_t msg; do { t = wp->current_task; if (t != NULL) { /* execute task */ mctx_switch(&wp->mctx, &t->mctx); } else { /* no ready tasks */ LpelMailboxRecv(wp->mailbox, &msg); switch(msg.type) { case WORKER_MSG_ASSIGN: t = msg.body.task; WORKER_DBG("wrapper: get task %d\n", t->uid); assert(t->state == TASK_CREATED); t->state = TASK_READY; wp->current_task = t; #ifdef USE_LOGGING if (t->mon) { if (MON_CB(worker_create_wrapper)) { wp->mon = MON_CB(worker_create_wrapper)(t->mon); } else { wp->mon = NULL; } } if (t->mon && MON_CB(task_assign)) { MON_CB(task_assign)(t->mon, wp->mon); } #endif break; case WORKER_MSG_WAKEUP: t = msg.body.task; WORKER_DBG("wrapper: unblock task %d\n", t->uid); assert (t->state == TASK_BLOCKED); t->state = TASK_READY; wp->current_task = t; #ifdef USE_LOGGING if (t->mon && MON_CB(task_assign)) { MON_CB(task_assign)(t->mon, wp->mon); } #endif break; default: assert(0); break; } } } while (!wp->terminate); LpelTaskDestroy(wp->current_task); /* cleanup task context marked for deletion */ }
/** * Deferred deletion of a task */ static void CleanupTaskContext(workerctx_t *wc, lpel_task_t *t) { /* delete task marked before */ if (wc->marked_del != NULL) { //LpelMonDebug( wc->mon, "Destroy task %d\n", wc->marked_del->uid); LpelTaskDestroy( wc->marked_del); wc->marked_del = NULL; } /* place a new task (if any) */ if (t != NULL) { wc->marked_del = t; } }
/* * clean up master's mailbox before terminating master * last messages including: task request from worker, and return zombie task */ static void cleanupMasterMb() { workermsg_t msg; lpel_task_t *t; while (LpelMailboxHasIncoming(master->mailbox)) { LpelMailboxRecv(master->mailbox, &msg); switch(msg.type) { case WORKER_MSG_REQUEST: break; case WORKER_MSG_RETURN: t = msg.body.task; WORKER_DBG("master: get returned task %d\n", t->uid); assert(t->state == TASK_ZOMBIE); LpelTaskDestroy(t); break; default: assert(0); break; } } }
/** * Thread function for workers (and wrappers) */ static void *WorkerThread( void *arg) { workerctx_t *wc = (workerctx_t *)arg; lpel_task_t *t; #ifdef HAVE___THREAD workerctx_cur = wc; #else /* HAVE___THREAD */ /* set pointer to worker context as TSD */ pthread_setspecific(workerctx_key, wc); #endif /* HAVE___THREAD */ #ifdef USE_MCTX_PCL int res = co_thread_init(); assert( 0 == res); wc->mctx = co_current(); #endif wc->current_task = NULL; /* no task marked for deletion */ wc->marked_del = NULL; /* assign to cores */ LpelThreadAssign( wc->wid); /*******************************************************/ if ( wc->wid >= 0) { WorkerLoop( wc); } else { WrapperLoop( wc); } /*******************************************************/ #ifdef USE_LOGGING /* cleanup monitoring */ if (wc->mon && MON_CB(worker_destroy)) { MON_CB(worker_destroy)(wc->mon); } #endif /* destroy all the free tasks */ while ((t = LpelPopTask(free, &wc->free_tasks))) { LpelTaskDestroy(t); } /* on a wrapper, we also can cleanup more*/ if (wc->wid < 0) { /* clean up the mailbox for the worker */ LpelMailboxDestroy(wc->mailbox); /* free the worker context */ free( wc); } #ifdef USE_MCTX_PCL co_thread_cleanup(); #endif return NULL; }
static void MasterLoop(masterctx_t *master) { WORKER_DBG("start master\n"); do { workermsg_t msg; LpelMailboxRecv(mastermb, &msg); lpel_task_t *t; int wid; switch(msg.type) { case WORKER_MSG_ASSIGN: /* master receive a new task */ t = msg.body.task; assert (t->state == TASK_CREATED); t->state = TASK_READY; WORKER_DBG("master: get task %d\n", t->uid); if (servePendingReq(master, t) < 0) { // no pending request t->sched_info.prior = DBL_MAX; //created task does not set up input/output stream yet, set as highest priority t->state = TASK_INQUEUE; LpelTaskqueuePush(master->ready_tasks, t); } break; case WORKER_MSG_RETURN: t = msg.body.task; WORKER_DBG("master: get returned task %d\n", t->uid); switch(t->state) { case TASK_BLOCKED: if (t->wakenup == 1) { /* task has been waked up */ t->wakenup = 0; t->state = TASK_READY; // no break, task will be treated as if it is returned as ready } else { t->state = TASK_RETURNED; updatePriorityNeigh(master->ready_tasks, t); break; } case TASK_READY: // task yields #ifdef _USE_NEG_DEMAND_LIMIT_ t->sched_info.prior = LpelTaskCalPriority(t); if (t->sched_info.prior == LPEL_DBL_MIN) { // if not schedule task if it has too low priority t->state = TASK_INQUEUE; LpelTaskqueuePush(master->ready_tasks, t); break; } #endif if (servePendingReq(master, t) < 0) { // no pending request updatePriorityNeigh(master->ready_tasks, t); t->sched_info.prior = LpelTaskCalPriority(t); //update new prior before add to the queue t->state = TASK_INQUEUE; LpelTaskqueuePush(master->ready_tasks, t); } break; case TASK_ZOMBIE: updatePriorityNeigh(master->ready_tasks, t); LpelTaskDestroy(t); break; default: assert(0); break; } break; case WORKER_MSG_WAKEUP: t = msg.body.task; if (t->state != TASK_RETURNED) { // task has not been returned yet t->wakenup = 1; // set task as wakenup so that when returned it will be treated as ready break; } WORKER_DBG("master: unblock task %d\n", t->uid); t->state = TASK_READY; #ifdef _USE_NEG_DEMAND_LIMIT_ t->sched_info.prior = LpelTaskCalPriority(t); if (t->sched_info.prior == LPEL_DBL_MIN) { // if not schedule task if it has too low priority t->state = TASK_INQUEUE; LpelTaskqueuePush(master->ready_tasks, t); break; } #endif if (servePendingReq(master, t) < 0) { // no pending request #ifndef _USE_NEG_DEMAND_LIMIT_ t->sched_info.prior = LpelTaskCalPriority(t); //update new prior before add to the queue #endif t->state = TASK_INQUEUE; LpelTaskqueuePush(master->ready_tasks, t); } break; case WORKER_MSG_REQUEST: wid = msg.body.from_worker; WORKER_DBG("master: request task from worker %d\n", wid); t = LpelTaskqueuePeek(master->ready_tasks); if (t == NULL) { master->waitworkers[wid] = 1; } else { #ifdef _USE_NEG_DEMAND_LIMIT_ if (t->sched_info.prior == LPEL_DBL_MIN) { // if not schedule task if it has too low priority master->waitworkers[wid] = 1; break; } #endif t->state = TASK_READY; sendTask(wid, t); t = LpelTaskqueuePop(master->ready_tasks); } break; case WORKER_MSG_TERMINATE: master->terminate = 1; break; default: assert(0); } } while (!(master->terminate && LpelTaskqueueSize(master->ready_tasks) == 0)); }