ADMITTING THE NEXT JOB OF A TASK

BACKGROUND:

Upon reaching the a task's deadline, the SRMS scheduler records the results of the job, cleans up the job if it remained unfinished, and then tries to admit the next job for the ensuing period. All three chores are the performed when the SRMS scheduler calls the record_job_results() function. After all the record keeping and cleaning is finished, admit_next_job() is used to get the task's job requirements for the next period.

GETTING A JOB'S EXECUTION TIME:

The most critical function of admit_next_job() is to communicate with the task so that SRMS scheduler can receive its job's estimated execution requirements. Communication consists of the scheduler giving the task its remaining time budget and the task replying with its expected execution requirement. The function get_next_exec() performs the actual communication between the scheduler and task. Remember, however, that at this point in the scheduling process, all tasks are suspended in waiting states. In order to perform communication, the SRMS scheduler needs to move the task to a ready state. Therefore, the first thing that record_job_results() does even before record keeping or cleaning up the last job is it calls Win32's ResumeThread()on the task that it needs to wake up. [Note that the call to ResumeThread() is made at the beginning of record_job_results(), but communication actually occurs at the end of the function when admit_next_job() is called. Logically, ResumeThread() should be called just before communication should occur, but it was found in practice that calling ResumeThread() in admit_next_job() just prior to communication caused unpredictable delays. Therefore, the call is made earlier to give the NT kernel sufficient time to transfer the task thread to a ready state.]

Communication begins in get_next_exec() with the scheduler copying the task's remaining budget to a shared memory buffer and then signaling the task's hJobReleasedEvent handle. Following this, the scheduler immediately waits for the task to reply by signaling the its hExecCalcEvent handle. Note that the scheduler limits its wait time to SRMS_COMMUNICATION_WAIT which by default is set to 10 milliseconds in srms.h. This limitation acts as a failsafe in case the task thread does not respond immediately. If the timeout period elapses, the time spent gets subtracted from the task's budget and the process repeats itself one more time. If the timeout period elapses again, then a job failed signal is sent to the task and the scheduler moves on. Otherwise, the task processed the budget value and replaced it with its next job's execution requirement. The scheduler reads the value from the shared memory buffer and assigns that value to the task's task_struct exec and exec_left entries. [On a side note, it also records the amount of time that is wasted during communication with the task in the task's execution history array entry.]

ACCEPTING OR REJECTING THE JOB:

Upon returning from get_next_exec(), admit_next_job() recomputes the job's ready time and deadline. Next, the function checks to see if the task has reached its super-deadline and replenishes its budget if so. If not, then the job may overlap the super-deadline which means that its ready time comes before its super-deadline and its deadline comes after it. In that case, the scheduler renews the budget and accepts or rejects the job based on if the job of the next lower-priority task has completed or not. Also, two heuristics adapted from Atlas' SRMS Simulator are used to improve the overall system performance. The first heuristic checks if the task has enough allowance and time to run on this super-period's allowance and if so, accepts the job. Another performance heuristic checks if the job will be able to complete after the next task's job is finished and if so accepts the job at a lower priority so that it will complete after the next task's job completes.

In the event that the last task did not overlap a super-deadline, then the task can use leftover time, assuming that the user has permitted time inheritance (the boolean variable do_inherit in rt.c is set to true if permitted). Otherwise, the time needs to be passed on. Finally, the job is accepted so long as its execution requirement is less than or equal to its remaining budget.  By accepting the job, SRMS guarantees its completion before its deadline and therefore sets the job's guaranteed flag to true and assigns it a "high" priority.  Otherwise, a rejected job is not guaranteed to finish, and it is set to run at a lower priority so that it does not use up any processor resources guaranteed to other tasks.  In a dual priority system, lower priority jobs will execute only if there are no other higher priority tasks with work to finish.  It also records the admit/reject status of the job in its execution history array entry and then sends it an accept/reject message via the send_job_accept_message() or send_job_reject_message() functions.

JOBS UNABLE TO CALCULATE THEIR EXECUTION TIME:

On a side note, admit_next_job() is also prepared to accept or reject jobs from tasks that do not know their execution requirement for the next job.  Tasks in this situation respond to the SRMS scheduler with an SRMS_EXEC_UNSURE value instead of an estimated execution time. The scheduler will always reject any job that is unsure of its execution requirement, and that job will be run at a lower priority than all other accepted real-time jobs.

< Back to the SRMS Service Home Page >