static void* wait_for_wakeup(Parrot_Interp interpreter, void *next) { QUEUE_ENTRY *entry; parrot_event* event; QUEUE * tq = interpreter->task_queue; interpreter->sleeping = 1; /* * event handler likes callbacks or timers are run as normal code * so inside such an even handler function another event might get * handled, which is good (higher priority events can interrupt * other event handler) OTOH we must ensure that all state changes * are done in do_event and we should probably suspend nested * event handlers sometimes * * FIXME: the same is true for the *next param: * get rid of that, instead mangle the resume flags * and offset to stop the runloop * */ while (interpreter->sleeping) { entry = wait_for_entry(tq); event = (parrot_event* )entry->data; mem_sys_free(entry); edebug((stderr, "got ev %s head : %p\n", et(event), tq->head)); next = do_event(interpreter, event, next); } edebug((stderr, "woke up\n")); return next; }
static void* do_event(Parrot_Interp interpreter, parrot_event* event, void *next) { edebug((stderr, "do_event %s\n", et(event))); switch (event->type) { case EVENT_TYPE_TERMINATE: next = NULL; /* this will terminate the run loop */ break; case EVENT_TYPE_SIGNAL: interpreter->sleeping = 0; /* generate exception */ event_to_exception(interpreter, event); /* not reached - will longjmp */ break; case EVENT_TYPE_TIMER: /* run ops, save registers */ Parrot_runops_fromc_save(interpreter, event->u.timer_event.sub); break; case EVENT_TYPE_CALL_BACK: edebug((stderr, "starting user cb\n")); Parrot_run_callback(interpreter, event->u.call_back.cbi, event->u.call_back.external_data); break; case EVENT_TYPE_SLEEP: interpreter->sleeping = 0; break; default: fprintf(stderr, "Unhandled event type %d\n", event->type); break; } mem_sys_free(event); return next; }
void Parrot_schedule_broadcast_qentry(QUEUE_ENTRY* entry) { Parrot_Interp interp; parrot_event* event; size_t i; event = entry->data; switch (event->type) { case EVENT_TYPE_SIGNAL: edebug((stderr, "broadcast signal\n")); /* * we don't have special signal handlers in usercode yet * e.g.: * install handler like exception handler *and* * set a interpreter flag, that a handler exists * we then could examine that flag (after LOCKing it) * and dispatch the exception to all interpreters that * handle it * Finally, we send the first (main) interpreter that signal * * For now just send to all. * */ switch(event->u.signal) { case SIGINT: if (n_interpreters) { LOCK(interpreter_array_mutex); for (i = 1; i < n_interpreters; ++i) { edebug((stderr, "deliver SIGINT to %d\n", i)); interp = interpreter_array[i]; if (interp) Parrot_schedule_interp_qentry(interp, dup_entry(entry)); } UNLOCK(interpreter_array_mutex); } interp = interpreter_array[0]; Parrot_schedule_interp_qentry(interp, entry); edebug((stderr, "deliver SIGINT to 0\n")); break; default: mem_sys_free(entry); mem_sys_free(event); } break; default: mem_sys_free(entry); mem_sys_free(event); internal_exception(1, "Unknown event to broadcast"); break; } }
void Parrot_schedule_interp_qentry(Parrot_Interp interpreter, QUEUE_ENTRY* entry) { parrot_event* event; event = entry->data; /* * sleep checks events when it awakes */ edebug((stderr, "got entry - schedule_inter_qentry %s\n", et(event))); if (event->type != EVENT_TYPE_SLEEP) enable_event_checking(interpreter); /* * do push_entry last - this signales the queue condition so the * interpreter might starting process that event immediately * * we should better use a priority for placing the event * in front or at the end of the queue */ switch (event->type) { case EVENT_TYPE_CALL_BACK: case EVENT_TYPE_SIGNAL: unshift_entry(interpreter->task_queue, entry); break; default: push_entry(interpreter->task_queue, entry); break; } }
void TH__setup_threads(const TH_thread_funptr *thfptrs){ debug((uint16_t) thfptrs[0].fptr); int16_t i, n; debug(F("Tset:")); assert(thfptrs); TH__thread_funptrs = (TH_thread_funptr *)thfptrs; i = get_len_fptrs(); sdebug(F("len:")); edebug(i); assert(i <= MAX_THREADS); TH__threads = (pthread *)malloc(sizeof(pthread) * i); debug((uint16_t) TH__threads); memcheck(TH__threads); for(n = 0; n < i; n++){ //PT_INIT(&TH__threads[n]); //set_thread_innactive(&TH__threads[n]); TH__threads[n].lc = PT_INNACTIVE; TH__threads[n].data = NULL; } TH__threads_len = i; debug(F("TsetD")); return; error: memclr(TH__threads); return; }
static void* event_thread(void *data) { QUEUE* event_q = (QUEUE*) data; parrot_event* event; QUEUE_ENTRY *entry; int running = 1; LOCK(event_q->queue_mutex); /* * we might already have an event in the queue */ if (peek_entry(event_q)) running = process_events(event_q); while (running) { entry = peek_entry(event_q); if (!entry) { /* wait infinite until entry arrives */ queue_wait(event_q); } else if (entry->type == QUEUE_ENTRY_TYPE_TIMED_EVENT) { /* do a_timedwait for entry */ struct timespec abs_time; FLOATVAL when; event = (parrot_event* )entry->data; when = event->u.timer_event.abs_time; abs_time.tv_sec = (time_t) when; abs_time.tv_nsec = (when - abs_time.tv_sec) * (1000L*1000L*1000L); queue_timedwait(event_q, &abs_time); } else { /* we shouldn't get here probably */ internal_exception(1, "Spurious event"); } /* * one or more entries arrived - we hold the mutex again * so we have to use the nonsync_pop_entry to pop off event entries */ running = process_events(event_q); } /* event loop */ /* * the main interpreter is dying * TODO empty the queue */ UNLOCK(event_q->queue_mutex); queue_destroy(event_q); stop_io_thread(); edebug((stderr, "event thread stopped\n")); return NULL; }
uint8_t schedule_thread(pthread *th){ uint8_t out = false; TH_funptr tfun; sdebug(F("schT:")); edebug(get_index(th)); assert(thread_exists(th)); assert_raise(not is_active(th), ERR_VALUE, th->lc); debug("Init"); PT_INIT(th); tfun = get_thread_function(get_index(th)); assert(tfun); out = tfun(th); if(out >= PT_EXITED){ set_thread_innactive(th); out = true; sdebug("Ts:"); edebug(get_index(th)); } else{ sdebug("Ts:"); edebug(get_index(th)); out = true; } error: return out; }
static void* io_thread(void *data) { QUEUE* event_q = (QUEUE*) data; fd_set rfds, wfds; int n_highest; int running = 1; FD_ZERO(&rfds); FD_ZERO(&wfds); UNUSED(event_q); /* * Watch the reader end of the pipe for messages */ FD_SET(PIPE_READ_FD, &rfds); n_highest = PIPE_READ_FD + 1; /* * all signals that we shall handle here have to be unblocked * in this and only in this thread */ Parrot_unblock_signal(SIGINT); while (running) { int retval = select(n_highest, &rfds, &wfds, NULL, NULL); switch (retval) { case -1: if (errno == EINTR) { edebug((stderr, "select EINTR\n")); if (sig_int) { edebug((stderr, "int arrived\n")); sig_int = 0; /* * signal the event thread */ schedule_signal_event(SIGINT); } } break; default: if (retval > 0) { edebug((stderr, "IO ready\n")); if (FD_ISSET(PIPE_READ_FD, &rfds)) { int buf[3]; /* * a command arrived */ edebug((stderr, "msg arrived\n")); if (read(PIPE_READ_FD, buf, MSG_SIZE) != MSG_SIZE) internal_exception(1, "read error from msg pipe"); switch (buf[0]) { case 'e': running = 0; break; /* TODO */ case 'r': /* insert fd in buf[1] into rfds */ case 'w': /* insert fd in buf[1] into wfds */ case 'R': /* delete fd in buf[1] from rfds */ case 'W': /* delete fd in buf[1] from wfds */ break; default: internal_exception(1, "unhandled msg in pipe"); break; } } /* TODO check fds */ break; } } } edebug((stderr, "IO thread terminated\n")); close(PIPE_READ_FD); close(PIPE_WRITE_FD); return NULL; }