home *** CD-ROM | disk | FTP | other *** search
- /*----------------------------------------------------------------------
- *
- * kbbgtask.c
- *
- * copyright (c) 1987,88,89,90 J. Alan Eldridge
- *
- * background tasking keyboard handler for Curses
- *
- * NOTES:
- *
- * look, folks, all this does is fake multitasking while
- * the user is sitting thinking about what to type
- *
- * there are a maximum of MAX tasks in the queue, and each
- * task must be a function that takes no args and whose
- * return value can be ignored
- *
- * lastly, and most importantly, this thing relies on two basic
- * concepts:
- *
- * 1. a user sits there without typing anyting, just
- * thinking, quite a bit of the time, so DOS sits there are
- * repeatedly polls the keyboard (twiddling its thumbs)
- *
- * 2. if i poll the keyboard myself, i can use some time to
- * do some TRIVIAL (meaning FAST!!) tasks while said user
- * is ruminating on what key to press next, thereby making
- * more effective use of available CPU cycles
- *
- * example use of all this:
- *
- * int show_time_in_corner();
- *
- * addbgtask(show_time_in_corner,5); -- add a real time clock, priority 5
- * so that whenever you're waiting, the time is updated onscreen
- *
- * now, whenever Curses reads a character, it will go through this
- * routine kbgetc() and automagically run things for you! anytime
- * you call getch() or wgetch() etc. you'll come here
- *
- * BUGS/WARNINGS:
- *
- * 1. a task (obviously!) can't do keyboard input (FIXED 1/90)
- *
- * 2. a task shouldn't mess with other tasks
- *
- * 3. task ids are assigned in numerical order, and are not reused,
- * so you can't add more than 32k tasks in a single program run
- * without risking weirdness (this limit really shouldn't be of
- * any consequence, since if you add and kill that many tasks you
- * probably are doing something else wrong that is worse, anyway)
- *
- * 4. a task should be a short, fast routine or else keyboard
- * response will be degraded unacceptably
- *
- *----------------------------------------------------------------------
- */
-
- #include "curses.h"
-
- #define TASK_MAX 32
- typedef void (*PFV)();
-
- /*----------------------------------------------------------------------
- *
- * the task handler's private storage
- *
- * how many tasks, who is up next, and pointers
- *
- *----------------------------------------------------------------------
- */
-
- struct tcb {
- int id,pri,cnt;
- PFV func;
- };
-
- static int taskcnt = 0, currtask = 0, nextid = 0;
- static struct tcb tasktabl[TASK_MAX];
-
- /*----------------------------------------------------------------------
- *
- * static findtask -- look up a task id in the table
- *
- *----------------------------------------------------------------------
- */
-
- static int
- findtask(id)
- int id;
- {
- int i;
-
- for (i = 0; i < taskcnt; i++)
- if (tasktabl[i].id == id)
- return i;
- return -1;
- }
-
- /*----------------------------------------------------------------------
- *
- * getbgpri -- returns the priority of the task specified
- *
- * BUGS:
- *
- * since it returns -1 on error, there is no way to know if a
- * task is invalid or just not running
- *
- *----------------------------------------------------------------------
- */
-
- int
- getbgpri(id)
- int id;
- {
- int n = findtask(id);
-
- return (n >= 0) ? tasktabl[n].pri : -1;
- }
-
- /*----------------------------------------------------------------------
- *
- * setbgpri -- given a task id, sets the priority
- *
- * a priority < 0 disables the task from running
- *
- *----------------------------------------------------------------------
- */
-
- int
- setbgpri(id, pri)
- int id, pri;
- {
- int n = findtask(id);
-
- if (n >= 0) {
- tasktabl[n].pri = pri;
- return 0;
- }
-
- return -1;
- }
-
- /*----------------------------------------------------------------------
- *
- * addbgtask -- queues up a task in the scheduler & executes it once
- *
- * returns the task id or -1 if error
- *
- *----------------------------------------------------------------------
- */
-
- int
- addbgtask(func, pri)
- void (*func)();
- int pri;
- {
- if (taskcnt < TASK_MAX) {
- (*func)();
- tasktabl[taskcnt].func = func;
- tasktabl[taskcnt].pri = pri;
- tasktabl[taskcnt].cnt = 0;
- return tasktabl[taskcnt++].id = nextid++;
- }
-
- return -1;
- }
-
- /*----------------------------------------------------------------------
- *
- * rmvbgtask -- removes a task (unqueues it)
- *
- * returns the number of tasks remaining
- *
- *----------------------------------------------------------------------
- */
-
- int
- rmvbgtask(id)
- int id;
- {
- int n = findtask(id);
-
- if (n >= 0 && n < taskcnt) {
- int i;
-
- for (i = n; i < taskcnt - 1; i++)
- tasktabl[i] = tasktabl[i+1];
- if (currtask == n) {
- if (currtask == taskcnt - 1)
- currtask = 0;
- } else if (currtask > n)
- currtask--;
- return --taskcnt;
- }
-
- return -1;
- }
-
- /*----------------------------------------------------------------------
- *
- * kbgetc -- poll the keyboard and multitask while waiting
- * then return a character
- *
- * the static recursion flag lets a task do keyboard input
- *
- * this should really be reserved for things like error conditions
- * because it is just not a clean way to do things in general
- *
- * if the key is ctl-backslash, clean up and exit (panic)
- *
- *----------------------------------------------------------------------
- */
-
- static int recurse = 0;
-
- int
- kbgetc()
- {
-
- int c;
-
- if (!recurse) {
- recurse++;
- while (!_kb_look()) {
- if (taskcnt < 1)
- continue;
- if (tasktabl[currtask].cnt++ >= tasktabl[currtask].pri) {
- if (tasktabl[currtask].pri >= 0)
- (*(tasktabl[currtask].func))();
- tasktabl[currtask].cnt = 0;
- }
- if (++currtask >= taskcnt)
- currtask = 0;
- }
- recurse--;
- }
-
- c = _kb_getc();
-
- if (c == K_CTL_BKSLASH) {
- endwin();
- exit(1);
- }
-
- return c;
- }
-