//: Run a second routine concurrently using 'start-running', without any //: guarantees on how the operations in each are interleaved with each other. :(scenario scheduler) recipe f1 [ start-running f2:recipe # wait for f2 to run { jump-unless 1:number, -1 } ] recipe f2 [ 1:number <- copy 1 ] +schedule: f1 +schedule: f2 //: first, add a deadline to run(routine) //: these changes are ugly and brittle; just close your nose and get through the next few lines :(replace "void run_current_routine()") void run_current_routine(long long int time_slice) :(replace "while (!Current_routine->completed())" following "void run_current_routine(long long int time_slice)") long long int ninstrs = 0; while (Current_routine->state == RUNNING && ninstrs < time_slice) :(after "Running One Instruction") ninstrs++; //: now the rest of the scheduler is clean :(before "struct routine") enum routine_state { RUNNING, COMPLETED, // End routine States }; :(before "End routine Fields") enum routine_state state; :(before "End routine Constructor") state = RUNNING; :(before "End Globals") vector Routines; long long int Current_routine_index = 0; long long int Scheduling_interval = 500; :(before "End Setup") Scheduling_interval = 500; Routines.clear(); :(replace{} "void run(recipe_ordinal r)") void run(recipe_ordinal r) { Routines.push_back(new routine(r)); Current_routine_index = 0, Current_routine = Routines.at(0); while (!all_routines_done()) { skip_to_next_routine(); assert(Current_routine); assert(Current_routine->state == RUNNING); trace("schedule") << current_routine_label() << end(); run_current_routine(Scheduling_interval); // Scheduler State Transitions if (Current_routine->completed()) Current_routine->state = COMPLETED; // End Scheduler State Transitions // Scheduler Cleanup // End Scheduler Cleanup } } :(code) bool all_routines_done() { for (long long int i = 0; i < SIZE(Routines); ++i) { if (Routines.at(i)->state == RUNNING) { return false; } } return true; } // skip Current_routine_index past non-RUNNING routines void skip_to_next_routine() { assert(!Routines.empty()); assert(Current_routine_index < SIZE(Routines)); for (long long int i = (Current_routine_index+1)%SIZE(Routines); i != Current_routine_index; i = (i+1)%SIZE(Routines)) { if (Routines.at(i)->state == RUNNING) { Current_routine_index = i; Current_routine = Routines.at(i); return; } } } string current_routine_label() { ostringstream result; call_stack calls = Current_routine->calls; for (call_stack::iterator p = calls.begin(); p != calls.end(); ++p) { if (p != calls.begin()) result << '/'; result << Recipe[p->running_recipe].name; } return result.str(); } :(before "End Teardown") for (long long int i = 0; i < SIZE(Routines); ++i) delete Routines.at(i); Routines.clear(); //:: To schedule new routines to run, call 'start-running'. //: 'start-running' will return a unique id for the routine that was created. //: routine id is a number, but don't do any arithmetic on it :(before "End routine Fields") long long int id; :(before "End Globals") long long int Next_routine_id = 1; :(before "End Setup") Next_routine_id = 1; :(before "End routine Constructor") id = Next_routine_id; Next_routine_id++; //: routines save the routine that spawned them :(before "End routine Fields") // todo: really should be routine_id, but that's less efficient. long long int parent_index; // only < 0 if there's no parent_index :(before "End routine Constructor") parent_index = -1; :(before "End Primitive Recipe Declarations") START_RUNNING, :(before "End Primitive Recipe Numbers") Recipe_ordinal["start-running"] = START_RUNNING; :(before
# dwm version
VERSION = 2.0

# Customize below to fit your system

# paths
PREFIX = /usr/local
MANPREFIX = ${PREFIX}/share/man

X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib

# includes and libs
INCS = -I. -I/usr/include -I${X11INC}
LIBS = -L/usr/lib -lc -L${X11LIB} -lX11

# flags
CFLAGS = -Os ${INCS} -DVERSION=\"${VERSION}\"
LDFLAGS = ${LIBS}
#CFLAGS = -g -Wall -O2 ${INCS} -DVERSION=\"${VERSION}\"
#LDFLAGS = -g ${LIBS}

# compiler and linker
CC = cc
LD = ${CC}
utine->id << end(); Current_routine->state = DISCONTINUED; Current_routine->limit = 0; } else { Current_routine->limit -= Scheduling_interval; } } :(before "End routine Fields") long long int limit; :(before "End routine Constructor") limit = -1; /* no limit */ :(before "End Primitive Recipe Declarations") LIMIT_TIME, :(before "End Primitive Recipe Numbers") Recipe_ordinal["limit-time"] = LIMIT_TIME; :(before "End Primitive Recipe Implementations") case LIMIT_TIME: { if (SIZE(ingredients) != 2) { raise << current_recipe_name() << ": 'limit-time' requires exactly two ingredient, but got " << current_instruction().to_string() << '\n' << end(); break; } if (!scalar(ingredients.at(0))) { raise << current_recipe_name() << ": first ingredient of 'limit-time' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } if (!scalar(ingredients.at(1))) { raise << current_recipe_name() << ": second ingredient of 'limit-time' should be a number (of instructions to run for), but got " << current_instruction().ingredients.at(1).original_string << '\n' << end(); break; } long long int id = ingredients.at(0).at(0); for (long long int i = 0; i < SIZE(Routines); ++i) { if (Routines.at(i)->id == id) { Routines.at(i)->limit = ingredients.at(1).at(0); break; } } break; }