Asynchronous Transfer of Control in the Timesys Reference Implementation
Asynchronous Transfer of Control Event Recognizer (OS or Scheduler) Running Thread Signal Handler Signal Handling Routine ATC is handled with signals in the reference implementation
Sync_md.c Most details of signal handling are in this file. Functions: linuxsyncinit initializes signal handler, masks linuxSyncInterruptWait emulates waiting on a semaphore linuxSyncSuspend suspends the thread linuxSyncResume resumes the thread sigfunc0 signal handler for mutex, suspend crash sends SIGSTOP in case of crash
void linuxSyncSuspend(CVMThreadID *t) { if (POSIX_COOKIE(t) == thr_self()) { t->suspended = 1; pthread_kill(POSIX_COOKIE(t), SIGUSR1); } else { mutex_lock(&t->lock); if (!t->suspended) { t->suspended = 1; /* * If the thread is performing a wait, we do special handling, * to avoid the use of signals. */ if (t->in_wait) { t->suspended_in_wait = 1; } else { pthread_kill(POSIX_COOKIE(t), SIGUSR1); } mutex_unlock(&t->lock); }
SyncResume void linuxSyncResume(CVMThreadID *t) { pthread_mutex_lock(&t->lock); if (t->suspended) { t->suspended = 0; if (t->suspended_in_wait) { t->suspended_in_wait = 0; pthread_cond_signal(&t->suspend_cv); } else { pthread_kill(POSIX_COOKIE(t), SIGUSR1); } pthread_mutex_unlock(&t->lock); }
Dispatcher Loop while(1) { /* suspend Dispatcher thread (us) until signal reception */ sigwait(&signal_set, &signum); (*env)->CallStaticVoidMethod(env,AsyncEvent,eventHappened,sig num); if((*env)->ExceptionCheck(env)){ return; }
Scheduling Scheduling in the RI is handled through signals and timers. Most of the scheduling is handled on the Java side. Some low level functions are in: RMScheduler.java / RMScheduler.c dispatcher.java / dispatcher.c
Semantics of ATC ATC semantics are based on two ideas: The RealtimeThread.interrupt() method. How instances of AIE are propogated.
realtimeThread.interrupt() When t.interrupt is called on RealtimeThread t, A 'generic' AIE becomes pending on t. Then there are two possibilities: if t is in ATC-deferred code, it continues execution until it enters an AI section. By returning to an AI method. By calling an AI method. if t is in AI code, the AIE is thrown immediately. Control is transferred to the first enclosing catch clause. The AIE stays pending.
Import javax.realtime.*; class TimeoutExample extends RealtimeThread{ RealtimeThread target; static class AtcTrigger extends AsyncEventHandler{ AtcTrigger(RealtimeThread target, runnable logic){ // target is the thread to be interrupted // logic.run is the handler AsynchEventHandler(logic); this.target=target; } void interruptableCode() throws AIE { //interruptable code chunk int i = 0; while (true) { i = i + 1; System.out.println(i + "\n"); }
public void run(){ OneShotTimer ost = new OneShotTimer( new RelativeTime( 1000, 0 ), //1 second new AtcTrigger( // async event handler this, // target to be interrupted new Runnable(){ public void run(){ this.target.interrupt(); } ) ); try{ interruptableCode(); } catch (AIE aie) { System.out.println("\n AIE Caught\n\n\n"); aie.happened(false); }
AsyncEventHandler() public AsyncEventHandler( args... ) {... HandlerThread = new RealtimeThread(scheduling, release, memory, area, group, this); } The RealtimeThread creates a new thread to run 'this' which is the run method from the previous slide.
OneShotTimer Class milli, nano are the time until the timer expires. if(isEnabled){ try{ waitLock.wait(milli,nano); if(rescheduled){ rescheduled = false; continue; } catch(Exception e){ e.printStackTrace(); } fire(); //AsyncEvent's method return; }
HandleAsyncEvent() When handleAsyncEvent() is called, the run method of the handler is started. public void handleAsyncEvent(){ if(logic != null){ logic.run(); } In this example, the run method calls "this.target.interrupt" which calls RealtimeThread.interrupt on the InturruptableCode method.
RealtimeThread.interrupt() public synchronized void interrupt() { AsynchronouslyInterruptedException genericAIE = AsynchronouslyInterruptedException.getGeneric(); if(!genericAIE.isDoInterruptibleInProcess()){ postAIE(genericAIE); /* ROBBINS SEZ: * we additionally interrupt with the original interrupt to wake * threads from sleep, wait */ super.interrupt(); return; }
PostAIE() JNIEXPORT void JNICALL Java_javax_realtime_RealtimeThread_postAIE (JNIEnv * env, jobject target, jobject genericAIE) { CVMExecEnv* ee = CVMjniEnv2ExecEnv(env); CVMExecEnv* tee = ThreadObj2ExecEnv(env,target); if(tee==NULL) return; CVMD_gcUnsafeExec(ee,{ CVMgcUnsafeSetPendingAIException(ee,tee, CVMID_icellDirect(ee,genericAIE)); }); if(tee->isIOBlocked==CVM_TRUE){ CVMthreadIOInterrupt(&tee->threadInfo); }
interpreter.h /* This is how AI exceptions actually get posted this macro */ /* unconditionally sets targets exc env pending object to obj */ #define CVMgcUnsafeSetPendingAIException(ee, targetEE, obj) { \ CVMsetPendingAIExceptionObj(ee, targetEE, obj); \ CVMsetPendingAIExceptionFlag(targetEE); \ } #define CVMsetPendingAIExceptionFlag(ee) ((ee)- >pendingAIExceptionFlag = CVM_TRUE) #define CVMsetPendingAIExceptionObj(ee, targetEE, obj_){ \ CVMID_icellSetDirect(ee, CVMpendingAIExceptionICell(targetEE), obj_); \ }
Last Step Finally, in the file interpreter.c, we see that in the interpreter loop, if an exception is pending, and if it's an AIE, then this function is called: CVMsetCurrentExceptionObj(ee,CVMgetPendingAIExceptionObj(ee) ); This is the call which actually runs the handler method.