//: 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 # 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) { run(new routine(r)); } :(code) void run(routine* rr) { Routines.push_back(rr); 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(9990, "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 } } 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; const call_stack& calls = Current_routine->calls; for (call_stack::const_iterator p = calls.begin(); p != calls.end(); ++p) { if (p != calls.begin()) result << '/'; result << get(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(); Current_routine = NULL; //: special case for the very first routine :(replace{} "void run_main(int argc, char* argv[])") void run_main(int argc, char* argv[]) { recipe_ordinal r = get(Recipe_ordinal, "main"); assert(r); routine* main_routine = new routine(r); // pass in commandline args as ingredients to main // todo: test this Current_routine = main_routine; for (long long int i = 1; i < argc; ++i) { vector arg; arg.push_back(new_mu_string(argv[i])); current_call().ingredient_atoms.push_back(arg); } run(main_routine); } //:: 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") put(Recipe_ordinal, "start-running", START_RUNNING); :(before "End Primitive Recipe Checks") case START_RUNNING: { if (inst.ingredients.empty()) { raise_error << maybe(get(Recipe, r).name) << "'start-running' requires at least one ingredient: the recipe to start running\n" << end(); break; } if (!is_mu_recipe(inst.ingredients.at(0))) { raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'start-running' should be a recipe, but got " << debug_string(inst.ingredients.at(0)) << '\n' << end(); break; } break; } :(before "End Primitive Recipe Implementations") case START_RUNNING: { routine* new_routine = new routine(ingredients.at(0).at(0)); new_routine->parent_index = Current_routine_index; // populate ingredients for (long long int i = 1; i < SIZE(current_instruction().ingredients); ++i) { new_routine->calls.front().ingredient_atoms.push_back(ingredients.at(i)); reagent ingredient = current_instruction().ingredients.at(i); canonize_type(ingredient); new_routine->calls.front().ingredients.push_back(ingredient); } Routines.push_back(new_routine); products.resize(1); products.at(0).push_back(new_routine->id); break; } :(scenario scheduler_runs_single_routine) % Scheduling_interval = 1; recipe f1 [ 1:number <- copy 0 2:number <- copy 0 ] +schedule: f1 +run: 1:number <- copy 0 +schedule: f1 +run: 2:number <- copy 0 :(scenario scheduler_interleaves_routines) % Scheduling_interval = 1; recipe f1 [ start-running f2 1:number <- copy 0 2:number <- copy 0 ] recipe f2 [ 3:number <- copy 0 4:number <- copy 0 ] +schedule: f1 +run: start-running f2 +schedule: f2 +run: 3:number <- copy 0 +schedule: f1 +run: 1:number <- copy 0 +schedule: f2 +run: 4:number <- copy 0 +schedule: f1 +run: 2:number <- copy 0 :(scenario start_running_takes_ingredients) recipe f1 [ start-running f2, 3 # wait for f2 to run { jump-unless 1:number, -1 } ] recipe f2 [ 1:number <- next-ingredient 2:number <- add 1:number, 1 ] +mem: storing 4 in location 2 :(scenario start_running_returns_routine_id) recipe f1 [ 1:number <- start-running f2 ] recipe f2 [ 12:number <- copy 44 ] +mem: storing 2 in location 1 //: this scenario will require some careful setup in escaped C++ //: (straining our tangle capabilities to near-breaking point) :(scenario scheduler_skips_completed_routines) % recipe_ordinal f1 = load("recipe f1 [\n1:number <- copy 0\n]\n").front(); % recipe_ordinal f2 = load("recipe f2 [\n2:number <- copy 0\n]\n").front(); % Routines.push_back(new routine(f1)); // f1 meant to run % Routines.push_back(new routine(f2)); % Routines.back()->state = COMPLETED; // f2 not meant to run # must have at least one routine without escaping recipe f3 [ 3:number <- copy 0 ] # by interleaving '+' lines with '-' lines, we allow f1 and f3 to run in any order +schedule: f1 +mem: storing 0 in location 1 -schedule: f2 -mem: storing 0 in location 2 +schedule: f3 +mem: storing 0 in location 3 :(scenario scheduler_starts_at_middle_of
.TH DWM 1 dwm-VERSION
.SH NAME
dwm \- dynamic window manager
.SH SYNOPSIS
.B dwm
.RB [ \-v ]
.SH DESCRIPTION
.B dwm
is a dynamic window manager for X11. It manages windows in tiling and floating
modes. Either mode can be applied dynamically, optimizing the environment for
the application in use and the task performed.
.P
In tiling mode windows are managed in a master and stacking column. The master
column contains the window which currently needs most attention, whereas the
stacking column contains all other windows. In floating mode windows can be
resized and moved freely. Dialog windows are always managed floating,
regardless of the mode selected.
.P
Windows are grouped by tags. Each window can be tagged with one or multiple
tags. Selecting a certain tag for viewing will display all windows with that
tag.
.P
.B dwm
has a small status bar which displays the text read from standard
input, if written. Besides that, it displays all available tags, and the title
of the focused window. It draws a 1-pixel border around windows to
indicate the focus state. Unfocused windows contain a small bar in front of
them displaying their tags and title.
.SH OPTIONS
.TP
.B \-v
prints version information to standard output, then exits.
.SH USAGE
.SS Status bar
.TP
.B Standard input
is read and displayed in the status text area.
.TP
.B Button[1,2]
click on a tag label focuses that
.B tag.
.TP
.B Button3
click on a tag label toggles that
.B tag.
.SS Keyboard commands
.TP
.B Mod1-Return
Zoom current
.B window
to the 
.B master
column.
.TP
.B Mod1-j
Focus next
.B window.
.TP
.