home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / progm / ctask.zip / CTASK.DOC next >
Text File  |  1988-03-01  |  74KB  |  2,014 lines

  1.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 1
  2.  
  3.  
  4.  
  5.  
  6.                                     CTask
  7.                          A Multitasking Kernel for C
  8.  
  9.                      Version 0.1 (Beta-Release) 88-03-01
  10.  
  11.                       Public Domain Software written by
  12.  
  13.                                 Thomas Wagner
  14.                               Patschkauer Weg 31
  15.                                D-1000 Berlin 33
  16.                                  West Germany
  17.  
  18.                                BIXmail: twagner
  19.  
  20.  
  21.                                 General Notes
  22.                                 =============
  23.  
  24.                                 What is CTask?
  25.  
  26.       CTask is a set of routines that allow functions in a C program  to 
  27.       run  concurrently.  This  is accomplished by giving  each  defined 
  28.       task-function  a slice of the processor time,  switching tasks  on 
  29.       each system timer tick,  or if the task is waiting for an external 
  30.       event to occur,  or is synchronizing with another task. This gives 
  31.       the  illusion of simultaneous execution of the tasks if  switching 
  32.       is fast enough, and no task excessively blocks system resources.
  33.  
  34.       CTask  includes  the  basic kernel,  which provides  the  building 
  35.       blocks  for implementing more complex multitasking  systems,  plus 
  36.       additional drivers for DOS access, keyboard and printer buffering, 
  37.       and  serial  asynchronous I/O,  which allow  writing  multitasking 
  38.       applications under DOS with little effort.
  39.  
  40.  
  41.                          What can CTask be used for?
  42.  
  43.       CTask can be used for utilities requiring background processing of 
  44.       serial communication,  printer spooling,  disk updates,  etc., and 
  45.       also  for  multitasking software in stand-alone (i.e.  not  MS-DOS 
  46.       based)  applications.  Very few functions of the CTask kernel  are 
  47.       system  specific,  so  adaptation for other systems is  relatively 
  48.       painless.
  49.  
  50.  
  51.                        What can CTask NOT be used for?
  52.  
  53.       CTask  is not intended to provide for multitasking on the  command 
  54.       level of MS-DOS.  Although CTask includes a module for  channeling 
  55.       simultaneous  DOS requests inside a program,  the strategy used in 
  56.       this module is not sufficient for the functionality required  when 
  57.       switching between programs. Adding this functionality would not be 
  58.       trivial (although certainly worthwile).
  59.  
  60.  
  61.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 2
  62.  
  63.  
  64.  
  65.       Also, there is no warranty that CTask does perform without errors, 
  66.       or  does exactly what you or I intended.  So CTask should  not  be 
  67.       used  in  applications  in which malfunction of routines  of  this 
  68.       package would result in damage to property or health of any person 
  69.       without  *very*  extensive testing under all kinds  of  loads.  In 
  70.       using CTask, you do so at your own risk.
  71.  
  72.  
  73.                         What is required to use CTask?
  74.  
  75.       To  compile  CTask,  Microsoft C 5.0 or later,  or Turbo C 1.0  or 
  76.       later  are required.  Microsoft MASM 5.0 or later is required  for 
  77.       the assembler parts.  Conversion to other compilers is possible if 
  78.       they conform to the new ANSI standard. Conversion of the assembler 
  79.       parts  to  other Assembler versions requires substitution  of  the 
  80.       simplified  model directives by explicit segment definitions,  and 
  81.       adding the DGROUP to offsets referencing data.
  82.  
  83.       Converting  CTask for stand-alone operation requires few  changes. 
  84.       Mainly,  the  timer interrupt handler (in "tsktim.asm") has to  be 
  85.       rewritten,  and the initialisation code (in "tskmain.c") may  have 
  86.       to  be  changed.  Changes to other modules (naturally  except  the 
  87.       optional hardware drivers) should not be necessary.
  88.  
  89.       Another requirement is a good debugger.  If you never before wrote 
  90.       multitasking  applications,  you're  in for  some  surprises.  The 
  91.       normal debugging tools (Symdeb, Codeview) are of only limited use, 
  92.       since they use DOS calls for their I/O, and thus may conflict with 
  93.       your background tasks.  One safety measure is to first  thoroughly 
  94.       test  your  program with preemption disabled,  possibly  inserting 
  95.       some schedule() calls, and only allow task preemption if you found 
  96.       most major bugs.  I personally recommend Periscope for  debugging, 
  97.       since  it  can be made resident and so is  always  available,  and 
  98.       because it does not use DOS.  Periscope III is the most  expensive 
  99.       solution,  and the best tool you can imagine (except for Periscope 
  100.       IV,  announced for April),  but the less costly versions will also 
  101.       help a lot.
  102.  
  103.  
  104.                       Do I have to pay for using CTask?
  105.  
  106.       No. One reason for writing CTask was to provide a free, no strings 
  107.       attached,  utility,  instead ot the usual "for personal use  only" 
  108.       restriction.  Writing  a multitasking application for personal use 
  109.       only dosen't seem too interesting to me. CTask is completely free, 
  110.       and there is no restriction on its use. You may incorporate all or 
  111.       parts of CTask in your programs,  and redistribute it in source or 
  112.       binary form by any means.  I also do not restrict the use of CTask 
  113.       in  commercial  applications.   Since  trying  to  distribute  the 
  114.       unmodified CTask for money will only give you a bad name,  you may 
  115.       even do that if you find someone dumb enough to buy it. Naturally, 
  116.       if you make a bundle from it,  or simply like CTask,  I would  not 
  117.       reject a donation.  However, this is not required, and it will not 
  118.       give you any additional support.
  119.  
  120.  
  121.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 3
  122.  
  123.  
  124.  
  125.  
  126.  
  127.                           What support can I expect?
  128.  
  129.       None. Naturally, I will try my best to eliminate any bugs reported 
  130.       to me, and to incorporate suggested enhancements and changes. If I 
  131.       fail to do so, however, you're out of luck. Sound familiar?
  132.  
  133.       At the time of this writing,  I'm connecting to BIX almost  daily. 
  134.       Problems  of limited general interest can be reported via BIXmail, 
  135.       suggested enhancements and changes,  plus bug reports,  should  be 
  136.       posted  in the c.language/tools conference on BIX (until responses 
  137.       warrant a new conference,  or I can't afford BIX any  longer),  so 
  138.       they can be discussed among all interested (I hope there will be a 
  139.       few).  Normal  mail  can  be used,  too,  but  don't  expect  fast 
  140.       responses.
  141.  
  142.                          Why is this a Beta Release?
  143.  
  144.       Because I expect input from you. The kernel alone may be nice, but 
  145.       I can imagine several changes to make it more suitable for  every-
  146.       day use. 
  147.  
  148.       For  one,  the algorithms used are relatively simple and straight-
  149.       forward.  Singly linked lists are used for chaining tasks  (except 
  150.       for  the  timer  queue),  and all list processing (except  in  the 
  151.       scheduler)  is done in C.  The main reason for this is  that  this 
  152.       allows the routines to be (in my opinion) very easy to comprehend, 
  153.       and changes can easily be incorporated.
  154.  
  155.       Also,  interrupts are disabled most of the time during event  pro-
  156.       cessing and queue rearrangement to allow interrupt handlers to use 
  157.       most of the intertask communication functions. 
  158.  
  159.       All  this may be completely acceptable,  given the quality of  the 
  160.       code  both MS C and Turbo C produce,  and the  usually  relatively 
  161.       small  number of tasks simultaneously enqueued in the same  queue,  
  162.       but  there  may be applications for which the current approach  is 
  163.       insufficient.
  164.  
  165.       So  feel  free  to voice your  complaints,  suggest  enhancements, 
  166.       supply  your own code for inclusion in the package (note that  any 
  167.       code  submitted  for inclusion must not be  copyrighted  or  usage 
  168.       restricted,  but I'll naturally respect copyrights in code submit-
  169.       ted for demo purposes), or suggest additions to this manual.
  170.  
  171.  
  172.  
  173.  
  174.  
  175.  
  176.  
  177.  
  178.  
  179.  
  180.  
  181.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 4
  182.  
  183.  
  184.  
  185.                              Multitasking Basics
  186.                              ===================
  187.  
  188.                                     Tasks
  189.  
  190.       In CTask, a "task" is defined as a (far) C function. The number of 
  191.       tasks  is  not limited,  and one function may be used for  several 
  192.       tasks.  There  is little difference between a task function and  a 
  193.       normal function. The usual form of a task function is
  194.  
  195.            void far my_task (farptr arg)
  196.            {
  197.                 one-time initialisation code
  198.                 while (TRUE)
  199.                   {
  200.                   processing code
  201.                   }
  202.            }
  203.  
  204.       A task function is (usually) never called directly.  Rather, it is 
  205.       specified  in the call to the create_task routine,  and started by 
  206.       start_task.  It will then continue to run,  sharing the  processor 
  207.       time  with  all other tasks,  until it is "killed"  by  kill_task. 
  208.       Returning  from  the routine will have the same effect as a  kill. 
  209.       The sharing of processor time is accomplished by "preempting"  the 
  210.       tasks. Preemption means that the task is interrupted in the middle 
  211.       of some statement by a hardware interrupt (usually the timer), and 
  212.       is *not* immediately restarted when the interrupt handler returns. 
  213.       Instead,  the  next  task that is able to run is activated by  the 
  214.       "scheduler", with the interrupted task continuing its duty at some 
  215.       (normally  unpredictable)  later time.  You can also  have  multi-
  216.       tasking without preemption, and CTask supports this, too, but this 
  217.       requires full cooperation of all tasks in the system, such that no 
  218.       task  continues  to  run for an extended period  of  time  without 
  219.       passing control to other tasks by an explicit scheduling  request, 
  220.       or by waiting for an event.
  221.  
  222.       The  optional  argument  to the task function may be used  if  one 
  223.       function is to be used for more than one task, for example to pass 
  224.       a  pointer to a static data area for use by this specific instance 
  225.       of the function.
  226.  
  227.  
  228.  
  229.  
  230.  
  231.  
  232.  
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 5
  242.  
  243.  
  244.  
  245.                                     Events
  246.  
  247.       Tasks alone would be of limited use.  If you have several routines 
  248.       which  just do number crunching or sorting or  such,  making  them 
  249.       into  parallel  tasks would be sensible only on  a  multiprocessor 
  250.       system.  Normally,  at least some of your tasks will wait for some 
  251.       outside  "event" to happen,  be it the user pressing a key,  or  a 
  252.       character  arriving from the modem.  Then there may be tasks which 
  253.       have to wait until another task finishes processing on some  piece 
  254.       of data before they can continue.  For this synchronization, there 
  255.       are  a number of constructs in CTask,  which I summarize under the 
  256.       name "event".  Common to all events are the operations of  waiting 
  257.       for  an  event  to  happen,  and signalling  that  the  event  has 
  258.       happened.  Using a CTask event is much more efficient than looping 
  259.       while  waiting on some shared data location to change  state,  and 
  260.       also  eliminates  concurrency problems inherent in such  a  simple 
  261.       approach.  Tasks  waiting for an event are taken off the scheduler 
  262.       queue, so they no longer use processor time.
  263.  
  264.                                   Reentrancy
  265.  
  266.       One of the biggest problem with multitasking in general,  and C on 
  267.       the PC in particular, is reentrancy. Reentrancy means that you can 
  268.       use  a routine,  be it you own,  or one of the C run-time library, 
  269.       from different tasks at the same time. When writing your own code, 
  270.       you can easily avoid problems, but when using the run-time library 
  271.       routines,  you often can only guess if the routines are  reentrant 
  272.       or not. 
  273.  
  274.       A routine is NOT reentrant if it modifies static data. This can be 
  275.       illustrated by the following nonsense example:
  276.  
  277.            int non_reentrant (int val)
  278.            {    static int temp;
  279.                 temp = val;
  280.                 return temp * 2;
  281.            }
  282.  
  283.       Now take two tasks,  which call this routine.  Task1 calls it with 
  284.       val=3,  Task2  with val=7.  What will be the return value for both 
  285.       tasks? You never know. There are three possible outcomes:
  286.  
  287.         1) The tasks execute sequentially.  Task1 will get 6,  and Task2 
  288.            14 as a result. This is what one normally expects.
  289.  
  290.         2) Task1  runs  up to "temp = val",  then is interrupted by  the 
  291.            timer.  Task2  executes,  and gets 14 as result.  Then  Task1 
  292.            continues. Return for Task1 is 14.
  293.  
  294.         3) Task2  runs up to "temp = val",  then is interrupted  by  the 
  295.            timer.  Task1  executes,  and  gets 6 as result.  Then  Task2 
  296.            continues. Return for Task2 is 6.
  297.  
  298.  
  299.  
  300.  
  301.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 6
  302.  
  303.  
  304.  
  305.       add  to  this the effects of optimization,  and a  loop,  and  the 
  306.       outcome is completly random. 
  307.  
  308.       Most  routines in the C library will not explicitly  do  something 
  309.       like this, but all functions that 
  310.  
  311.            - do file I/O (read, write, printf, scanf, etc.) or
  312.            - change memory allocation (malloc, free, etc.)
  313.  
  314.       have  to  use some static data to do buffering,  or to  store  the 
  315.       chain of memory blocks in. Interrupting such an operation may have 
  316.       disastrous effects.  The most devilish aspect of non-reentrancy is 
  317.       that  the  effects are unpredictable.  Your program may  run  1000 
  318.       times  without  any error,  and then on the 1001th time crash  the 
  319.       system so completely that only the big red switch will help.
  320.  
  321.       So  what can you do about it?  A lot.  There are several  ways  to 
  322.       protect  "critical  regions" from being entered in  parallel.  The 
  323.       most simple method is to disable interrupts. This, however, should 
  324.       be  used only for *very* short periods of time,  and not for  rou-
  325.       tines  that  might themselves re-enable them  (like  file-I/O).  A 
  326.       better  method  is to temporarily  disable  task  preemption.  The 
  327.       routines  tsk_dis_preempt  and tsk_ena_preempt allow this form  of 
  328.       short-term task switch disable. Interrupts may still be processed, 
  329.       but  tasks  will  not  be preempted.  The best way  is  to  use  a 
  330.       "resource".  A resource is a special kind of event, which only one 
  331.       task  can  possess  at  a time.  Requesting  the  resource  before 
  332.       entering the routine,  and releasing it afterwards,  will  protect 
  333.       you  from  any  other task simultaneously  entering  the  critical 
  334.       region (assuming that this task also requests the resource).
  335.  
  336.       It  is also reasonably safe to use file-I/O without protection  if 
  337.       it  goes  to  different  files.  The C  file  control  blocks  for 
  338.       different files are distinct, so there will be no conflict between 
  339.       tasks.  Since  DOS  access is automatically  protected  by  CTask, 
  340.       concurrent file I/O is possible.
  341.  
  342.       What  you  may NEVER do is to use a non-reentrant routine that  is 
  343.       not  protected by an interrupt disable from an interrupt  handler. 
  344.       An interrupt handler is not a task,  and so can not safely request 
  345.       a resource or disable task preemption.  This is the reason why the 
  346.       CTask  routines  generally disable interrupts before  manipulating 
  347.       the internal queues rather than only disabling task preemption.
  348.  
  349.  
  350.                                   Deadlocks
  351.  
  352.       One  thing to watch out for when using resources or similar  event 
  353.       mechanisms is not to get into a situation where Task 1 waits for a 
  354.       resource that Task 2 has requested,  while at the same time Task 2 
  355.       waits  for a resource that Task 1 already has.  This situation  is 
  356.       called a deadlock (or,  more picturesque,  deadly embrace), and it 
  357.       can only be resolved with outside help (e.g.  waking up one of the 
  358.       tasks forcibly). To illustrate, consider the following example:
  359.  
  360.  
  361.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 7
  362.  
  363.  
  364.  
  365.  
  366.            void far task_1 ()
  367.            {
  368.              ...
  369.              request_resource (&rsc1, 0L);
  370.              request_resource (&rsc2, 0L);
  371.              ...
  372.            }
  373.  
  374.            void far task_2 ()
  375.            {
  376.              ...
  377.              request_resource (&rsc2, 0L);
  378.              request_resource (&rsc1, 0L);
  379.              ...
  380.            }
  381.  
  382.       Since interrupts are always enabled on return from a task  switch, 
  383.       even if the statements are enclosed in a critical region, there is 
  384.       no  guarantee  that  the request_resource calls will  be  executed 
  385.       without interruption. In this example, the problem is obvious, but 
  386.       in  a more complex application,  where resource requests or  other 
  387.       waits might be buried in some nested routine, you should watch out 
  388.       for similar situations. One way to avoid problems would be in this 
  389.       example to change task_2 to
  390.  
  391.            void far task_2 ()
  392.            {
  393.                 int again;
  394.                 ...
  395.                 do {
  396.                      request_resource (&rsc2, 0L);
  397.                      if (again = c_request_resource (&rsc1))
  398.                         {
  399.                         release_resource (&rsc2);
  400.                         delay (2L);
  401.                         }
  402.                    } while (again);
  403.                 ...
  404.            } 
  405.                    
  406.       Note that this is only one of many possible approaches,  and  that 
  407.       this approach favours task_1 over task_2.
  408.  
  409.  
  410.  
  411.  
  412.  
  413.  
  414.  
  415.  
  416.  
  417.  
  418.  
  419.  
  420.  
  421.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 8
  422.  
  423.  
  424.  
  425.                              Multitasking and DOS
  426.  
  427.       CTask includes (and automatically installs) a routine which  traps 
  428.       all  DOS  calls,  and makes sure that no two tasks  simultaneously 
  429.       enter DOS. This is accomplished using the resource mechanism, with 
  430.       special  provisions  for  the  limited  multitasking  capabilities 
  431.       provided by DOS. There are a few calls, namely those with function 
  432.       codes  <=  0x0c,  which allow functions with codes >  0x0c  to  be 
  433.       executed  while  DOS is waiting for an external device  (generally 
  434.       the keyboard) to get ready.  This, however, limits the use of some 
  435.       C library functions,  namely scanf and fread,  for console  input. 
  436.       Both  these  functions  use  handle input,  and thus  can  not  be 
  437.       interrupted.  When  writing  routines  for  handling  user  input, 
  438.       keyboard  read  functions should either use  the  low-level  calls 
  439.       getch  and  gets,  or,  better yet,  the direct entries  into  the 
  440.       keyboard  handler,  t_read_key and t_keyhit,  and then process the 
  441.       string with sscanf if desired.  The keyboard handler (contained in 
  442.       tskkbd.asm) traps all keyboard interrupts, storing entered keys in 
  443.       a  pipe.  If a task reads from the keyboard,  it is  automatically 
  444.       waiting  for  this pipe.  Using getch and gets is  less  desirable 
  445.       since they use polling instead of waiting, and thus degrade system 
  446.       performance.  Also,  the t_read_key and t_keyhit functions do  not 
  447.       use DOS, so DOS functions <= 0C can be executed concurrently.
  448.  
  449.       You  should  NEVER  circumvent DOS by  calling  the  BIOS-disk-I/O 
  450.       function (INT 13) directly.  This entry is not protected by CTask, 
  451.       and  using it in parallel to DOS file-I/O may send your  hard-disk 
  452.       FAT and directory into never-never land. If you really should need 
  453.       this  interrupt,  you should consider adding support for it in the 
  454.       DOS-handler module "tskdos.asm".  Using the direct sector read and 
  455.       write interrupts 25 and 26 is supported, however. Using other BIOS 
  456.       interrupts  directly  should  also  be  avoided,  unless  you  are 
  457.       absolutely  sure they will not be used by other routines via  DOS, 
  458.       or you provide your own critical region handling.  Using interrupt 
  459.       16, the keyboard interrupt, is safe, since it is redirected to the 
  460.       keyboard handler pipe.
  461.  
  462.       The DOS access module has been tested to work with DOS  3.30,  and 
  463.       with the DOS 3.30 PRINT routine running in the background. Special 
  464.       provisions  are built into the DOS module to detect background DOS 
  465.       calls.  Using Sidekick also hasn't lead to any problems,  although 
  466.       you  may trash Sidekick's screen display by writing to the  screen 
  467.       while  Sidekick is active (note that your application  *continues* 
  468.       to  run  while Sidekick or other pop-ups are active).  I  can  not 
  469.       guarantee  complete compatibility with all background  and  pop-up 
  470.       programs  under all versions of DOS.  Specifically,  DOS  versions 
  471.       prior   to  3.1  have  significant  problems  with   multitasking. 
  472.       Upgrading  to a newer DOS version is recommended if you are  still 
  473.       using DOS < 3.2 (DOS 3.1 has some bugs in other areas).
  474.  
  475.       Critical  errors  and  Control C occurring  while  concurrent  DOS 
  476.       access  takes  place may also be fatal.  Using the  ctrlbrk()  and 
  477.       dosexterr() functions of Turbo C, or their equivalents in MS C, to 
  478.       trap critical errors and Control C is highly recommended.
  479.  
  480.  
  481.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 9
  482.  
  483.  
  484.  
  485.  
  486.                                  Using CTask
  487.                                  ===========
  488.  
  489.       CTask  comes  archived with both source  and  binary.  The  binary 
  490.       version  is  compiled  in the large model,  but since  the  kernel 
  491.       routines don't use any functions from the C library,  you can  use 
  492.       all functions in small or other model programs (except Tiny).  The 
  493.       include  files  provided specify all model  dependencies,  so  you 
  494.       don't have to use the large model for your application, but always 
  495.       remember  to include "tsk.h" for the type and routine  prototypes. 
  496.       The  C  source files will work without changes for both  Microsoft 
  497.       and  Turbo  C.  The  library files  are  not  compatible,  so  use 
  498.       "ctaskms.lib" for Microsoft, and "ctasktc.lib" for Turbo C.
  499.  
  500.       When  compiling your application,  turn stack  checking  off.  The 
  501.       standard  stack check is of little use with task stacks,  and  may 
  502.       interfere with CTask's operation.  The stack area for tasks should 
  503.       be  allocated  on the main program's stack,  not in the static  or 
  504.       heap data space. The reason for this is that some of the C library 
  505.       routines check for stack overflow regardless of your  compile-time 
  506.       switches,  and  will  crash  your application if  you  use  stacks 
  507.       outside the normal stack. The stack allocation parameter with LINK 
  508.       (MS-C),  or the _stacksize variable (Turbo C) have to be increased 
  509.       to reflect the additional stack space. When calculating task stack 
  510.       sizes, keep in mind that library routines (esp. printf) allocate a 
  511.       lot of space on the stack for temporary variables. A minimum of 1k 
  512.       for  tasks using library routines is recommended,  2k puts you  on 
  513.       the  safe  side.  Tasks  not using C library routines  may  use  a 
  514.       smaller  stack,  about 256 bytes at a minimum,  plus space for any 
  515.       local varibles and nested routines.  Then add up all task  stacks, 
  516.       and   add   space  for  the  main  task  (the   function   calling 
  517.       install_tasker), with this size also dependent on what you will do 
  518.       in  the main task while CTask is active.  Stacks for tasks that do 
  519.       not use C library routines may be allocated anywhere.
  520.  
  521.       The  keyboard  and DOS handlers are always installed  with  CTask. 
  522.       Using the serial I/O and printer drivers is optional,  so you have 
  523.       to  install them separately,  but only *after*  installing  CTask. 
  524.       When  using  the serial driver,  include "sio.h" in your  modules, 
  525.       when using the printer driver, include "prt.h".
  526.  
  527.       Remember that tasks are not automatically started after  creation. 
  528.       Use start_task to allow a created task to run.
  529.  
  530.       Always use create_xxx on resources,  pipes,  etc.  Using the event 
  531.       routines without doing so will have unpredictable results.
  532.  
  533.       Before  exiting the program,  all installed drivers and CTask must 
  534.       be uninstalled, or you'll crash the system.
  535.  
  536.       Deleting events before exiting the program is not  mandatory,  but 
  537.       recommended to kill all tasks waiting for the event. You should be 
  538.       careful  not  to  kill tasks while they are  active  in  DOS.  The 
  539.  
  540.  
  541.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 10
  542.  
  543.  
  544.  
  545.       kill_task routine should be reserved for fatal error handling. The 
  546.       best  way  is to let the tasks kill themselves depending  on  some 
  547.       global  variable or event.  If a task is killed while waiting  for 
  548.       input  in DOS,  DOS operation may be severly impaired.  If you use 
  549.       the C console input routines, make sure that the task returns from 
  550.       DOS  before it is killed,  if necessary by requesting the user  to 
  551.       press a key.
  552.  
  553.  
  554.                               Priority Handling
  555.                               =================
  556.  
  557.       CTask   provides   for  prioritized  task  execution   and   event 
  558.       processing. This means that a task that has a higher priority will 
  559.       be  run  before any other tasks having  lower  priority.  Also,  a 
  560.       higher  priority  task will gain access  to  resources,  counters, 
  561.       pipes,   and  mail,   before  lower  priority  tasks.  With  fixed 
  562.       priorities,  this  means that a high priority task can  monopolize 
  563.       CPU  time,  even  if  it  calls  schedule()  explicitly.  Variable 
  564.       priority  increases each eligible task's priority by one  on  each 
  565.       scheduler  call,  so that lower priority tasks will slowly rise to 
  566.       the head of the queue until they get executed.  The priority  will 
  567.       be reset to the initial priority when a task is run.
  568.  
  569.       Since  variable priority increases processing time in the critical 
  570.       region  of  the scheduler,  it is not recommended for  systems  in 
  571.       which  a  larger  number  of tasks  is  expected  to  be  eligible 
  572.       simultaneously.
  573.  
  574.       Usually,  all  tasks  in a system should have the  same  priority, 
  575.       with   only  very  few  exceptions  for  non-critical   background 
  576.       processing  (low  priority)  or  very  time-critical  tasks  (high 
  577.       priority).  High  priority  tasks should be written in such a  way 
  578.       that  they  either  reduce  their  priority  when  processing   is 
  579.       completed,  or that they wait for an event. Busy waiting in a high 
  580.       priority  task will severely impair system operation with variable 
  581.       priority  enabled,  and  will stop the system until  the  task  is 
  582.       placed in a waiting state with fixed priority.
  583.  
  584.       The  (automatically created) main task is started with the highest 
  585.       possible priority below the timer task, so that it can process all 
  586.       initialisations  before other tasks start running.  To  allow  the 
  587.       system to operate,  the priority of the main task must be reduced, 
  588.       or the main task must wait for an event or a timeout.
  589.  
  590.  
  591.  
  592.  
  593.  
  594.  
  595.  
  596.  
  597.  
  598.  
  599.  
  600.  
  601.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 11
  602.  
  603.  
  604.  
  605.                                CTask Data Types
  606.                                ================
  607.  
  608.       Note  that you do not have to know the innards of the  structures. 
  609.       All  structure fields are filled by the "create_xxx" routines  and 
  610.       modified  by the CTask functions.  You should NEVER modify a field 
  611.       in  one of the structures directly.  The structures are  explained 
  612.       here shortly only for those wanting to modify the routines. 
  613.  
  614.       If  you only want to use the routines,  you should simply  include 
  615.       the file "tsk.h" in your source, and define variables of the types
  616.  
  617.             tcb         - for task control blocks
  618.             tcbptr      - for far pointers to tcbs
  619.  
  620.             flag        - for flag events
  621.             flagptr     - for far pointers to flags
  622.  
  623.             resource    - for resource events
  624.             resourceptr - for far pointers to resources
  625.  
  626.             counter     - for counter events
  627.             counterptr  - for far pointers to counters
  628.  
  629.             mailbox     - for mailbox events
  630.             mailboxptr  - for far pointers to mailboxes
  631.  
  632.             pipe        - for pipe events
  633.             pipeptr     - for far pointers to pipes
  634.  
  635.             wpipe       - for word pipe events
  636.             wpipeptr    - for far pointers to word pipes
  637.  
  638.       without caring what's behind them.
  639.  
  640.       Additionally, you may use the types
  641.  
  642.             byte        - for unsigned characters
  643.             word        - for unsigned short integers
  644.             dword       - for unsigned long integers
  645.  
  646.             funcptr     - for pointers to task functions
  647.             farptr      - for far pointers to anything
  648.             byteptr     - for far pointers to byte arrays
  649.             wordptr     - for far pointers to word arrays
  650.  
  651.       in  defining  or typecasting items to be passed as  parameters  to 
  652.       CTask functions.
  653.  
  654.  
  655.  
  656.  
  657.  
  658.  
  659.  
  660.  
  661.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 12
  662.  
  663.  
  664.  
  665.               Typedefs used for simplified type specifications
  666.  
  667.          typedef unsigned char byte;
  668.          typedef unsigned short word;
  669.          typedef unsigned long dword;
  670.          typedef void (cdecl far *funcptr)();
  671.          typedef void far *farptr;
  672.          typedef byte far *byteptr;
  673.          typedef word far *wordptr;
  674.  
  675.                   Error return values for mailbox functions
  676.  
  677.          #define TTIMEOUT ((farptr) -1L)
  678.          #define TWAKE    ((farptr) -2L)
  679.  
  680.                       The task control block structure
  681.  
  682.       The  "next" field points to the next tcb in a queue.  The  "queue" 
  683.       pointer  points to the head of the queue the task is enqueued  in, 
  684.       or will be enqueued in on the next schedule request in the case of 
  685.       the current running task. 
  686.  
  687.       "stack" contains the saved task stack pointer (offset and segment) 
  688.       if the task is not running. The field "stkbot" contains the bottom 
  689.       address  of  the task stack.  It is set  by  create_task,  but  is 
  690.       currently  not used anywhere else.  Stack checking routines  might 
  691.       use this value to test for stack overflow and/or stack usage.
  692.  
  693.       "prior"  contains  the tasks current  priority,  with  0xffff  the 
  694.       highest possible priority, and 0 the lowest. "initprior" initially 
  695.       contains the same value.  If variable priority is enabled, "prior" 
  696.       is  incremented on each scheduler call,  and reset to  "initprior" 
  697.       when the task is activated.
  698.  
  699.       "state" and "flags" contain the tasks state and flags.
  700.  
  701.       "timerq" is a dlink structure used to chain the tcb into the timer 
  702.       queue,  if the task is waiting for a timeout.  In this  case,  the 
  703.       F_TIMER  flag  is set.   "timeout" in the timerq structure  counts 
  704.       down the ticks when waiting for a timeout.  "follow" and "prev" in 
  705.       the  dlink point to the next and previous dlinks in the  tcb's  in 
  706.       the timer queue. Since dlinks point to dlinks, the field "tcbp" in 
  707.       a  dlink  points  to the beginning of the tcb to which  the  dlink 
  708.       belongs to allow access to the tcb when steping through the  timer 
  709.       queue.
  710.  
  711.       The fields "retptr" and "retsize" are used in event handling. They 
  712.       are  used  when a task is waiting for an event by the  task  acti-
  713.       vating the event,  and also by timeout and wake to indicate  error 
  714.       returns.   The  use of these pointers eliminates the need to  loop 
  715.       for  an  event,  which  requires slightly more code in  the  event 
  716.       handling routines, but reduces the need for task switching.
  717.  
  718.  
  719.  
  720.  
  721.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 13
  722.  
  723.  
  724.  
  725.          typedef struct dlink_rec far *dlinkptr;
  726.  
  727.          struct dlink_rec {
  728.                           dlinkptr follow;
  729.                           dlinkptr prev;
  730.                           dword    timeout;
  731.                           tcbptr   tcbp;
  732.                           };
  733.  
  734.          typedef struct dlink_rec dlink;
  735.          typedef struct tcb_rec far *tcbptr;
  736.          typedef tcbptr far *tqueptr;
  737.  
  738.          struct tcb_rec {
  739.                          tcbptr   next;
  740.                          tqueptr  queue;
  741.                          byteptr  stack;
  742.                          byteptr  stkbot;
  743.                          word     prior;
  744.                          word     initprior;
  745.                          byte     state;
  746.                          byte     flags;
  747.                          dlink    timerq;
  748.                          farptr   retptr;
  749.                          int      retsize;
  750.                         };
  751.  
  752.          typedef struct tcb_rec tcb;
  753.  
  754.  
  755.                                  Task states
  756.  
  757.          #define  ST_KILLED  -1
  758.          #define  ST_STOPPED  0
  759.          #define  ST_DELAYED  1
  760.          #define  ST_WAITING  2
  761.          #define  ST_ELIGIBLE 3
  762.          #define  ST_RUNNING  4
  763.  
  764.  
  765.  
  766.  
  767.  
  768.  
  769.  
  770.  
  771.  
  772.  
  773.  
  774.  
  775.  
  776.  
  777.  
  778.  
  779.  
  780.  
  781.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 14
  782.  
  783.  
  784.  
  785.                  Possible task states and queue association
  786.  
  787.       ST_KILLED      The  task has been killed.  Restarting the task  is 
  788.                      not possible. Queue pointers are invalid.
  789.  
  790.       ST_STOPPED     The  task is not enqueued in any queue.  To be  in-
  791.                      cluded  in  scheduling,  it  has to  be  explicitly 
  792.                      started. The queue head pointer is NULL.
  793.  
  794.       ST_DELAYED     The task is enqueued in the timer queue only.  When 
  795.                      the  timer expires,  it is placed in  the  eligible 
  796.                      queue.  The queue head pointer is NULL.
  797.  
  798.       ST_ELIGIBLE    The  task  is  enqueued in the queue  of  processes 
  799.                      eligible for running.  It can not be chained in the 
  800.                      timer queue.  The queue head pointer points to  the 
  801.                      eligible queue.
  802.  
  803.       ST_RUNNING     The task is the current running process.   Although 
  804.                      it  is  not enqueued in any queue,  the queue  head 
  805.                      pointer in its control block is valid and points to 
  806.                      the  queue the process will be enqueued in  on  the 
  807.                      next schedule request.
  808.  
  809.       ST_WAITING     The task is waiting for an event to happen.  It can 
  810.                      also  be chained into the timer queue if a  timeout 
  811.                      was specified in the call.   The queue head pointer 
  812.                      points to the queue head in the event control block 
  813.                      for the event the process is waiting on.
  814.  
  815.  
  816.                 Possible state transitions and their reasons
  817.  
  818.          stopped  -> eligible    by start_task ()
  819.  
  820.          delayed  -> killed      by kill_task ()
  821.                   -> eligible    by timer task, or wake_task ()
  822.          
  823.          eligible -> killed      by kill_task ()
  824.                   -> running     by scheduler
  825.  
  826.          running  -> killed      by kill_task ()
  827.                   -> stopped     by delay (0)
  828.                   -> delayed     by delay (n != 0)
  829.                   -> eligible    by scheduler
  830.                   -> waiting     by wait_xxx ()
  831.  
  832.          waiting  -> killed      by kill_task ()
  833.                   -> eligible    by event happening, timeout,
  834.                                  or wake_task()
  835.  
  836.  
  837.  
  838.  
  839.  
  840.  
  841.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 15
  842.  
  843.  
  844.  
  845.                                  Task flags
  846.  
  847.          #define  F_TIMER  0x80     Task is enqueued in timer queue
  848.          #define  F_CRIT   0x01     Task may not be preempted
  849.  
  850.  
  851.                           The flag event structure
  852.  
  853.       Contains  two queues for processes waiting on a flag state  (clear 
  854.       or set), plus the flag state (0 = clear, 1 = set).
  855.  
  856.          typedef struct {
  857.                         tcbptr  wait_set;
  858.                         tcbptr  wait_clear;
  859.                         int     state;
  860.                         } flag;
  861.  
  862.          typedef flag far *flagptr;
  863.  
  864.  
  865.                          The counter event structure
  866.  
  867.       Similar to a flag, but contains a doubleword state counter.
  868.  
  869.          typedef struct {
  870.                         tcbptr  wait_set;
  871.                         tcbptr  wait_clear;
  872.                         dword   state;
  873.                         } counter;
  874.  
  875.          typedef counter far *counterptr;
  876.  
  877.  
  878.                         The resource event structure
  879.  
  880.       Contains a queue for the tasks waiting for access to the resource, 
  881.       a  pointer  to  the current owner of the resource  (to  check  for 
  882.       illegal "release_resource" calls),  and the resource state (0 = in 
  883.       use, 1 = free).
  884.  
  885.          typedef struct {
  886.                         tcbptr   waiting;
  887.                         tcbptr   owner;
  888.                         int      state;
  889.                         } resource;
  890.  
  891.          typedef resource far *resourceptr;
  892.  
  893.  
  894.  
  895.  
  896.  
  897.  
  898.  
  899.  
  900.  
  901.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 16
  902.  
  903.  
  904.  
  905.                          The mailbox event structure
  906.  
  907.       The msgptr type is only used internally to chain mail blocks  into 
  908.       the  mailbox.  The  mailbox  type contains a queue  of  the  tasks 
  909.       waiting  for mail,  and a first and last pointer for the chain  of 
  910.       mail blocks.  
  911.  
  912.          struct msg_header {
  913.                            struct msg_header far *next;
  914.                            };
  915.  
  916.          typedef struct msg_header far *msgptr;
  917.  
  918.          typedef struct {
  919.                         tcbptr  waiting;
  920.                         msgptr  mail_first;
  921.                         msgptr  mail_last;
  922.                         } mailbox;
  923.  
  924.          typedef mailbox far *mailboxptr;
  925.  
  926.  
  927.                     The pipe and word pipe event structure
  928.  
  929.       Contains queues of the tasks waiting to read or write to the pipe, 
  930.       indices  for reading (outptr) and writing (inptr) into the buffer, 
  931.       the  buffer size,  the number of bytes or words currently  in  the 
  932.       pipe  ("filled"),  and the pointer to the buffer.  A word pipe  is 
  933.       handled exactly the same as a byte pipe, the only difference being 
  934.       the element size placed in the buffer.  With normal pipes, charac-
  935.       ters are buffered, with word pipes, words.
  936.  
  937.          typedef struct {
  938.                         tcbptr   wait_read;
  939.                         tcbptr   wait_write;
  940.                         tcbptr   wait_clear;
  941.                         word     bufsize;
  942.                         word     filled;
  943.                         word     inptr;
  944.                         word     outptr;
  945.                         byteptr  contents;
  946.                         } pipe;
  947.  
  948.          typedef pipe far *pipeptr;
  949.  
  950.  
  951.  
  952.  
  953.  
  954.  
  955.  
  956.  
  957.  
  958.  
  959.  
  960.  
  961.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 17
  962.  
  963.  
  964.  
  965.          typedef struct {
  966.                         tcbptr   wait_read;
  967.                         tcbptr   wait_write;
  968.                         tcbptr   wait_clear;
  969.                         word     bufsize;
  970.                         word     filled;
  971.                         word     inptr;
  972.                         word     outptr;
  973.                         wordptr  wcontents;
  974.                         } wpipe;
  975.  
  976.          typedef wpipe far *wpipeptr;
  977.  
  978.  
  979.  
  980.  
  981.       NOTE:  When  modifying CTask structures,  take care to modify  the 
  982.       equivalent  definitions  in the assembler include file  "tsk.mac". 
  983.       Some  of  the assembler routines have to use  field  offsets  into 
  984.       pointers,  so  having  different offsets in C and  assembler  will 
  985.       crash the system.
  986.  
  987.  
  988.  
  989.  
  990.  
  991.  
  992.  
  993.  
  994.  
  995.  
  996.  
  997.  
  998.  
  999.  
  1000.  
  1001.  
  1002.  
  1003.  
  1004.  
  1005.  
  1006.  
  1007.  
  1008.  
  1009.  
  1010.  
  1011.  
  1012.  
  1013.  
  1014.  
  1015.  
  1016.  
  1017.  
  1018.  
  1019.  
  1020.  
  1021.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 18
  1022.  
  1023.  
  1024.  
  1025.                                CTask Routines
  1026.                                ==============
  1027.  
  1028.                           Installation and Removal
  1029.  
  1030.       void install_tasker (int varpri, int speedup);
  1031.  
  1032.            Installs  the multitasker.  Must be called prior to any other 
  1033.            routine. The calling routine is defined as the main task, and 
  1034.            assigned  the  highest priority.   To allow  other  tasks  to 
  1035.            execute,  the  main task must have its priority  reduced,  be 
  1036.            delayed,  or  wait  on an event.   
  1037.  
  1038.            The "varpri" parameter enables variable priority if nonzero.
  1039.  
  1040.            The "speed" parameter is defined for the IBM PC/XT/AT as  the 
  1041.            clock  tick speedup factor.  The timer tick frequency will be 
  1042.            set to
  1043.  
  1044.                 speed    ticks/sec   msecs/tick
  1045.                   0        18.2        54.9     (normal clock)
  1046.                   1        36.4        27.5
  1047.                   2        72.8        13.7
  1048.                   3       145.6         6.9
  1049.                   4       291.3         3.4
  1050.  
  1051.            Note  that  all  timeouts are specified  in  tick  units,  so 
  1052.            changing  the  speed  parameter will influence  timeouts  and 
  1053.            delays.  The  system clock will not be disturbed by  changing 
  1054.            the  speed.  Using  values  above 2  can  lead  to  interrupt 
  1055.            overruns on slower machines and is not recommended.
  1056.  
  1057.  
  1058.       void remove_tasker (void);
  1059.  
  1060.            Uninstalls the multitasker. Must only be called from the main 
  1061.            task,  and MUST be called before exiting the program,  or the 
  1062.            system will crash.
  1063.  
  1064.  
  1065.                                 Miscellaneous
  1066.  
  1067.  
  1068.       void preempt_off (void);
  1069.  
  1070.            Disables task preemption. This is the default after installa-
  1071.            tion.  With preemption turned off,  only delays, event waits, 
  1072.            and explicit scheduler calls will cause a task switch.
  1073.  
  1074.  
  1075.       void preempt_on (void);
  1076.  
  1077.            Enables  task preemption.  Task switches will occur on  timer 
  1078.            ticks.
  1079.  
  1080.  
  1081.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 19
  1082.  
  1083.  
  1084.  
  1085.  
  1086.  
  1087.       void far schedule (void);
  1088.  
  1089.            Explicit  scheduling request.  The highest priority  eligible 
  1090.            task will be made running.
  1091.  
  1092.  
  1093.       void far c_schedule (void);
  1094.  
  1095.            Conditional  scheduling request.  Scheduling will take  place 
  1096.            only if preemption is allowed.
  1097.  
  1098.  
  1099.       void tsk_dis_preempt (void)
  1100.  
  1101.            Temporarily  disable task preemption.  Preemption will be re-
  1102.            enabled  by  tsk_ena_preempt or  an  unconditional  scheduler 
  1103.            call.
  1104.  
  1105.  
  1106.       void tsk_ena_preempt (void)
  1107.  
  1108.            Re-enable  task  preemption.  Note that  tsk_dis_preempt  and 
  1109.            tsk_ena_preempt do not change the global preemption state set 
  1110.            by preempt_off and preempt_on.
  1111.  
  1112.  
  1113.       int tsk_dis_int (void)
  1114.  
  1115.            Disable  interrupts.  Returns the state of the interrupt flag 
  1116.            prior to this call (1 if interrupts were enabled).
  1117.  
  1118.  
  1119.       void tsk_ena_int (int state)
  1120.  
  1121.            Enables  interrupts if "state" is nonzero.  Normally used  in 
  1122.            conjunction with tsk_dis_int.
  1123.  
  1124.       The routines tsk_dis_int and tsk_ena_int may be used in a  simpli-
  1125.       fied scheme with the defines
  1126.  
  1127.            CRITICAL;      Declares "int intsav;".
  1128.            C_ENTER;       Expands to "intsav = tsk_dis_int ();"
  1129.            C_LEAVE;       Expands to "tsk_ena_int (intsav);".
  1130.  
  1131.  
  1132.       void tsk_cli (void)
  1133.  
  1134.            Disables interrupts. 
  1135.  
  1136.  
  1137.  
  1138.  
  1139.  
  1140.  
  1141.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 20
  1142.  
  1143.  
  1144.  
  1145.       void tsk_sti (void)
  1146.  
  1147.            Unconditionally enables interrupts.
  1148.  
  1149.  
  1150.       void tsk_outp (int port, byte b)
  1151.  
  1152.            Outputs the value "b" to hardware-port "port".
  1153.  
  1154.  
  1155.       byte tsk_inp (int port)
  1156.  
  1157.            Returns the value read from port "port".
  1158.  
  1159.  
  1160.       The following entry points may be used from assembler routines:
  1161.  
  1162.       extrn scheduler: far
  1163.  
  1164.            Direct entry into the scheduler.  The stack must be set up as 
  1165.            for an interrupt handler, e.g.
  1166.                 pushf
  1167.                 cli
  1168.                 call  scheduler
  1169.  
  1170.  
  1171.       extrn _sched_int: far
  1172.  
  1173.            Conditional scheduling call.  The stack must be set up as for 
  1174.            an interrupt handler.
  1175.  
  1176.  
  1177.  
  1178.                                Task Operations
  1179.  
  1180.       void create_task (tcbptr task, funcptr func, byteptr stack,
  1181.                         word stksz, word prior, farptr arg);
  1182.  
  1183.            Initialises a task.  Must be called prior to any other opera-
  1184.            tions  on this task.  The task is in the stopped state  after 
  1185.            creation. It must be started to be able to run.
  1186.  
  1187.            "task"    is a pointer to a tcb.
  1188.            "func"    is a pointer to a void far function, with a single 
  1189.                      dword sized parameter.
  1190.            "stack"   is a pointer to a stack area for the task. 
  1191.            "stksz"   is the size of the stack area in bytes.
  1192.            "prior"   is the tasks priority (0 lowest, 0xffff highest).
  1193.            "arg"     is an argument to the created task. It may be used 
  1194.                      to differentiate between tasks when using the same 
  1195.                      function in different tasks.
  1196.  
  1197.  
  1198.  
  1199.  
  1200.  
  1201.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 21
  1202.  
  1203.  
  1204.  
  1205.       void kill_task (tcbptr task);
  1206.  
  1207.            Kills a task. The task can no longer be used.
  1208.  
  1209.  
  1210.       int start_task (tcbptr task);
  1211.  
  1212.            Starts a task, i.e. makes it eligible for running.
  1213.            Returns  0  if  task  was started,  -1 if the  task  was  not 
  1214.            stopped.
  1215.            A value of NULL for "task" will start the "main task".
  1216.  
  1217.  
  1218.       int wake_task (tcbptr task);
  1219.  
  1220.            Prematurely wakes a delayed or waiting task.
  1221.            If the task was waiting for an event, it will be removed from 
  1222.            the  waiting queue,  with the operation terminating  with  an 
  1223.            error return value.
  1224.            Returns  0 if task was waked,  -1 if the task was not delayed 
  1225.            or waiting.
  1226.            A value of NULL for "task" will wake the "main task".
  1227.  
  1228.  
  1229.       void set_priority (tcbptr task, word prior)
  1230.  
  1231.            Sets the priority of the specified task to "prior".
  1232.            Note that you should NOT modify the priority field in the tcb 
  1233.            structure directly.
  1234.            A value of NULL for "task" will set the priority of the "main 
  1235.            task".
  1236.  
  1237.  
  1238.       void set_task_flags (tcbptr task, byte flags)
  1239.  
  1240.            Sets the flags of the task to "flags".  Currently,  the  only 
  1241.            flag that can be changed is
  1242.  
  1243.                      F_CRIT   the task can not be preempted if set.
  1244.  
  1245.            Note  that  you  may  NOT modify the flag field  in  the  tcb 
  1246.            structure directly.
  1247.            A  value of NULL for "task" will set the flags of  the  "main 
  1248.            task".
  1249.  
  1250.  
  1251.                               Timer Operations
  1252.  
  1253.       Timeouts:
  1254.            When waiting for an event,  a timeout may be specified.   The 
  1255.            operation  will  terminate with an error return value if  the 
  1256.            timeout is reached before the event occurs.
  1257.            NOTE that the timeout parameter is not optional.  To  specify 
  1258.            no timeout, use the value 0.
  1259.  
  1260.  
  1261.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 22
  1262.  
  1263.  
  1264.  
  1265.  
  1266.       Delays:
  1267.  
  1268.       int delay (dword ticks);
  1269.  
  1270.            Delay the current task for "ticks" clock ticks. 
  1271.            If ticks is 0, the task is stopped.
  1272.  
  1273.  
  1274.                               Event Operations
  1275.  
  1276.                                   Resources
  1277.  
  1278.       A Resource is either in use or free, the default state is free.
  1279.       If a task has requested a resource, its state is in use.
  1280.       Tasks  requesting  a  resource  while it is in use  will  be  made 
  1281.       waiting. If the resource is released, the highest priority waiting 
  1282.       task is made eligible,  and is assigned the  resource.   Interrupt 
  1283.       handlers    may   not   use   resource   functions   other    than 
  1284.       "check_resource".
  1285.  
  1286.  
  1287.       void create_resource (resourceptr rsc);
  1288.  
  1289.            This initialises a resource.  Must be used prior to any other 
  1290.            operations on a resource.
  1291.  
  1292.  
  1293.       void delete_resource (resourceptr rsc);
  1294.  
  1295.            Calling  this  routine is optional.  It will kill  all  tasks 
  1296.            waiting for the resource.
  1297.  
  1298.  
  1299.       void release_resource (resourceptr rsc);
  1300.  
  1301.            Release the resource.  If the task does not own the resource, 
  1302.            the call is ignored.
  1303.            If  tasks  are waiting,  the highest priority task will  gain 
  1304.            access to the resource.
  1305.  
  1306.  
  1307.       int request_resource (resourceptr rsc, dword timeout);
  1308.  
  1309.            Requests the resource.  If it is not available,  the task  is 
  1310.            suspended. A timeout may be specified.
  1311.            Returns  0  if  resource  was  allocated,  -1  if  a  timeout 
  1312.            occurred, -2 on wake.
  1313.            This  call  is  ignored (returns a 0)  if  the  calling  task 
  1314.            already owns the resource.
  1315.  
  1316.  
  1317.  
  1318.  
  1319.  
  1320.  
  1321.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 23
  1322.  
  1323.  
  1324.  
  1325.       int c_request_resource (resourceptr rsc);
  1326.  
  1327.            Requests the resource only if it is available.
  1328.            Returns 0 if resource was allocated, -1 if unavailable.
  1329.  
  1330.  
  1331.       int check_resource (resourceptr rsc);
  1332.             
  1333.            Returns 0 if resource is allocated, 1 if free.
  1334.  
  1335.  
  1336.                                     Flags
  1337.  
  1338.       A Flag can be either on or off, the default state is off (0).
  1339.       Tasks  can  wait  on either state of the flag.  If  the  state  is 
  1340.       changed,  all  tasks  waiting  for the state  are  made  eligible.  
  1341.       Interrupt  handlers  may use  the  "set_flag",  "clear_flag",  and 
  1342.       "check_flag" functions.
  1343.  
  1344.  
  1345.       void create_flag (flagptr flg);
  1346.  
  1347.            This  initialises  a flag.  Must be used prior to  any  other 
  1348.            operations on a flag. The state is set to 0.
  1349.  
  1350.  
  1351.       void delete_flag (flagptr flg);
  1352.  
  1353.            Calling  this  routine is optional.  It will kill  all  tasks 
  1354.            waiting for the flag.
  1355.  
  1356.  
  1357.       void set_flag (flagptr flg);
  1358.  
  1359.            This sets the flag.  All tasks waiting for the set state will 
  1360.            be made eligible for running.
  1361.  
  1362.  
  1363.       void clear_flag (flagptr flg);
  1364.  
  1365.            This  clears the flag.  All tasks waiting for the clear state 
  1366.            will be made eligible for running.
  1367.  
  1368.                   
  1369.       int wait_flag_set (flagptr flg, dword timeout);
  1370.  
  1371.            Waits for the set state of the flag.  If the flag is not set, 
  1372.            the task is suspended. A timeout may be specified.
  1373.            Returns 0 if the flag was set, -1 on timeout, -2 on wake.
  1374.  
  1375.  
  1376.  
  1377.  
  1378.  
  1379.  
  1380.  
  1381.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 24
  1382.  
  1383.  
  1384.  
  1385.       int wait_flag_clear (flagptr flg, dword timeout);
  1386.  
  1387.            Waits  for the clear state of the flag.  If the flag  is  not 
  1388.            clear, the task is suspended. A timeout may be specified.  
  1389.  
  1390.            Returns 0 if the flag was cleared, -1 on timeout, -2 on wake.
  1391.  
  1392.  
  1393.       int check_flag (flagptr flg);
  1394.  
  1395.            Returns 0 if flag clear, 1 if set.
  1396.  
  1397.  
  1398.  
  1399.                                   Counters
  1400.  
  1401.       A  Counter can have any value from 0L to 0xffffffffL,  the default 
  1402.       value is 0. Tasks can wait for a counter being zero or non-zero.
  1403.       If the counter is cleared or decremented to zero,  all tasks  wai-
  1404.       ting for the zero condition are made eligible.
  1405.       If  the counter is incremented,  the highest priority task waiting 
  1406.       for non-zero is made eligible,  and the counter is decremented  by 
  1407.       one.
  1408.       Interrupt handlers may use the "clear_counter", "inc_counter", and 
  1409.       "check_counter" functions.
  1410.  
  1411.  
  1412.       void create_counter (counterptr cnt);
  1413.  
  1414.            This  initialises a counter.  Must be used prior to any other 
  1415.            operations on a flag. The value is set to 0.
  1416.  
  1417.  
  1418.       void delete_counter (counterptr cnt);
  1419.  
  1420.            Calling  this  routine is optional.  It will kill  all  tasks 
  1421.            waiting for the counter.
  1422.  
  1423.  
  1424.       void clear_counter (counterptr cnt);
  1425.  
  1426.            Clears  the counter to zero.  All tasks waiting for the  zero 
  1427.            state will be made eligible for running.
  1428.  
  1429.  
  1430.       int wait_counter_set (counterptr cnt, dword timeout);
  1431.  
  1432.            Waits for the counter having a nonzero value. If the value is 
  1433.            zero,  the task is suspended.  The value is decremented  when 
  1434.            the task gets access to the counter.  A timeout may be speci-
  1435.            fied.
  1436.            Returns  0 if the counter was nonzero,  -1 on timeout,  -2 on 
  1437.            wake.  
  1438.  
  1439.  
  1440.  
  1441.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 25
  1442.  
  1443.  
  1444.  
  1445.  
  1446.       int wait_counter_clear (counterptr cnt, dword timeout);
  1447.  
  1448.            Waits  for the counter having a zero value.  If the value  is 
  1449.            nonzero, the task is suspended. A timeout may be specified.
  1450.            Returns 0 if the counter was zero, -1 on timeout, -2 on wake.
  1451.  
  1452.  
  1453.       void inc_counter (counterptr cnt);
  1454.  
  1455.            Increments the counter.  If tasks are waiting for the nonzero 
  1456.            state,  the  highest  priority task is given  access  to  the 
  1457.            counter.
  1458.  
  1459.  
  1460.       dword check_counter (counterptr cnt);
  1461.  
  1462.            Returns the current value of the counter.
  1463.  
  1464.  
  1465.  
  1466.                                   Mailboxes
  1467.  
  1468.       A Mailbox can hold any number of mail blocks.
  1469.       Tasks  can send mail to a mailbox and wait for mail to  arrive.  A 
  1470.       mail block is assigned to the highest priority waiting task.  Care 
  1471.       must  be  exercised not to re-use a mail block until it  has  been 
  1472.       processed  by the receiving task.   The mail block format is  user 
  1473.       defineable,  with the first doubleword in a block reserved for the 
  1474.       tasking  system.   Interrupt  handlers  may use  the  "send_mail", 
  1475.       "c_wait_mail", and "check_mailbox" functions.
  1476.  
  1477.       Note  that mailboxes are well suited to provide the mechanism  for 
  1478.       managing a chain of (equally sized) free mail blocks. On initiali-
  1479.       sation,  all  free  blocks  would be "sent" to  the  manager  box. 
  1480.       Requesting a free block would use "wait_mail",  and freeing a used 
  1481.       block would again "send" it to the manager mailbox.
  1482.  
  1483.  
  1484.       void create_mailbox (mailboxptr box);
  1485.  
  1486.            This initialises a mailbox.  Must be used prior to any  other 
  1487.            operations on a mailbox.
  1488.  
  1489.  
  1490.       void delete_mailbox (mailboxptr box);
  1491.  
  1492.            Calling  this  routine is optional.  It will kill  all  tasks 
  1493.            waiting for mail.
  1494.  
  1495.  
  1496.  
  1497.  
  1498.  
  1499.  
  1500.  
  1501.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 26
  1502.  
  1503.  
  1504.  
  1505.       void send_mail (mailboxptr box, farptr msg);
  1506.  
  1507.            Sends  a message to the specified mailbox.  If tasks are wai-
  1508.            ting for mail, the highest priority task will get it.  
  1509.  
  1510.  
  1511.       farptr wait_mail (mailboxptr box, dword timeout);
  1512.  
  1513.            Waits for mail.  If no mail is available, the task is suspen-
  1514.            ded. A timeout may be specified.
  1515.            Returns the pointer to the received mail block, TTIMEOUT 
  1516.            (-1) on timeout, TWAKE (-2) on wake.
  1517.  
  1518.  
  1519.       farptr c_wait_mail (mailboxptr box);
  1520.  
  1521.            Reads mail only if mail is available.
  1522.            Returns  NULL  if there is no mail,  else a  pointer  to  the 
  1523.            received message.
  1524.  
  1525.  
  1526.       int check_mailbox (mailboxptr box);
  1527.  
  1528.            Returns 0 if mailbox is empty, 1 otherwise.
  1529.  
  1530.  
  1531.  
  1532.                                     Pipes
  1533.  
  1534.       A Pipe has a buffer to hold character or word sized items.
  1535.       An  item may be written to a pipe if there is space in the buffer. 
  1536.       Otherwise,  the writing task will be made waiting.  A reading task 
  1537.       will be made waiting if the buffer is empty.   If an item has been 
  1538.       read,  the highest priority task waiting to write to the pipe will 
  1539.       be allowed to write.
  1540.       Interrupt  handlers  may  only use  pipe  functions  "check_pipe", 
  1541.       "c_write_pipe", and "c_read_pipe".
  1542.  
  1543.       Note  that  the  values -1 and -2 (0xffff and  0xfffe)  should  be 
  1544.       avoided when writing to word pipes.  These values are used to mark 
  1545.       timeout and wake when reading,  or pipe empty when checking a word 
  1546.       pipe, and thus may lead to erroneous operation of your routines.
  1547.  
  1548.  
  1549.       void create_pipe (pipeptr pip, farptr buf, word bufsize);
  1550.       void create_wpipe (wpipeptr pip, farptr buf, word bufsize);
  1551.  
  1552.            This  initialises  a pipe.  Must be used prior to  any  other 
  1553.            operations on a pipe.  "bufsize" specifies the buffer size in 
  1554.            bytes.  With word pipes,  the buffer size should be divisible 
  1555.            by two.
  1556.  
  1557.  
  1558.  
  1559.  
  1560.  
  1561.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 27
  1562.  
  1563.  
  1564.  
  1565.       void delete_pipe (pipeptr pip);
  1566.       void delete_wpipe (wpipeptr pip);
  1567.  
  1568.            Calling  this  routine is optional.  It will kill  all  tasks 
  1569.            waiting to read or write messages.
  1570.  
  1571.  
  1572.       int read_pipe (pipeptr pip, dword timeout);
  1573.       word read_wpipe (wpipeptr pip, dword timeout);
  1574.  
  1575.            Read an item from a pipe.  If no item is available,  the task 
  1576.            is suspended. A timeout may be specified.
  1577.            Returns the item, or -1 on timeout, -2 on wake.
  1578.  
  1579.  
  1580.       int c_read_pipe (pipeptr pip);
  1581.       word c_read_wpipe (wpipeptr pip);
  1582.  
  1583.            Reads an item from a pipe only if one is available.
  1584.            Returns the received item, or -1 if none is available.
  1585.  
  1586.  
  1587.       int write_pipe (pipeptr pip, byte ch, dword timeout);
  1588.       int write_wpipe (wpipeptr pip, word ch, dword timeout);
  1589.  
  1590.            Writes an item to a pipe.  If the buffer is full, the task is 
  1591.            suspended. A timeout may be specified.
  1592.            If  tasks are waiting to read,  the item will be assigned  to 
  1593.            the highest priority waiting task.
  1594.            Returns 0 on success, or -1 on timeout, -2 on wake.
  1595.                   
  1596.  
  1597.       int c_write_pipe (pipeptr pip, byte ch);
  1598.       int c_write_wpipe (wpipeptr pip, word ch);
  1599.  
  1600.            Writes an item to a pipe only if enough space is available.
  1601.            Returns 0 on success, or -1 if no space available.
  1602.                   
  1603.  
  1604.       int wait_pipe_empty (pipeptr pip, dword timeout);
  1605.       int wait_wpipe_empty (wpipeptr pip, dword timeout);
  1606.  
  1607.            Waits  for  the pipe to be emptied.  If the pipe  is  already 
  1608.            empty  on  entry,  the task continues to run.  Returns  0  on 
  1609.            empty, -1 on timeout, -2 on wake.
  1610.  
  1611.  
  1612.       int check_pipe (pipeptr pip);
  1613.       word check_wpipe (pipeptr pip);
  1614.  
  1615.            Returns  -1 if the pipe is empty,  else the first item in the 
  1616.            pipe. The item is not removed from the pipe.
  1617.  
  1618.  
  1619.  
  1620.  
  1621.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 28
  1622.  
  1623.  
  1624.  
  1625.       word pipe_free (pipeptr pip);
  1626.       word wpipe_free (wpipeptr pip);
  1627.  
  1628.                 Returns the number of free items available in the pipe.
  1629.  
  1630.  
  1631.  
  1632.                                     Buffers
  1633.  
  1634.       A Buffer has a buffer to hold message strings.
  1635.       A  message may be written to a buffer if it fits into the  buffer. 
  1636.       Otherwise,  the writing task will be made waiting.  A reading task 
  1637.       will  be made waiting if the buffer is empty.   If a  message  has 
  1638.       been  read,  the  highest  priority task waiting to write  to  the 
  1639.       buffer  will  be  allowed to write if its message  fits  into  the 
  1640.       available space.
  1641.       Interrupt  handlers  may  not  use  buffer  functions  other  than 
  1642.       "check_buffer".
  1643.       The buffer routines are implemented using resources and pipes, and 
  1644.       thus are not part of the true "kernel" routines.
  1645.  
  1646.  
  1647.       void create_buffer (bufferptr buf, farptr pbuf, word bufsize);
  1648.  
  1649.            This  initialises a buffer.  Must be used prior to any  other 
  1650.            operations on a buffer.
  1651.            The minimum buffer size is the length of the longest expected 
  1652.            message plus two.
  1653.  
  1654.  
  1655.       void delete_buffer (bufferptr buf);
  1656.  
  1657.            Calling  this  routine is optional.  It will kill  all  tasks 
  1658.            waiting to read or write messages.
  1659.  
  1660.  
  1661.       int read_buffer (bufferptr buf, farptr msg, int size, 
  1662.                        dword timeout);
  1663.  
  1664.            Read a message from a buffer. If no message is available, the 
  1665.            task is suspended. A timeout may be specified.
  1666.            The  message  will  be copied to the  buffer  "buf",  with  a 
  1667.            maximum length of "size" bytes.
  1668.            Returns the length of the received message, -1 on timeout, -2 
  1669.            on wake.
  1670.  
  1671.  
  1672.       int c_read_buffer (bufferptr buf, farptr msg, int size);
  1673.  
  1674.            Reads  a  message  from a buffer only if  one  is  available.  
  1675.            Returns the length of the received message,  or -1 if none is 
  1676.            available.
  1677.  
  1678.  
  1679.  
  1680.  
  1681.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 29
  1682.  
  1683.  
  1684.  
  1685.       int write_buffer (bufferptr buf, farptr msg, int size, 
  1686.                         dword timeout);
  1687.  
  1688.            Writes  a message from "msg" with length "size" to a  buffer. 
  1689.            If not enough space for the message is available, the task is 
  1690.            suspended. A timeout may be specified.
  1691.            If tasks are waiting for messages,  the highest priority task 
  1692.            will get it.
  1693.            Returns the length of the message, -1 on timeout, -2 on wake, 
  1694.            -3 on error (length < 0 or length > buffer buffer size).
  1695.  
  1696.                   
  1697.       int c_write_buffer (bufferptr buf, farptr msg, int size);
  1698.  
  1699.            Writes  a  message  to  a buffer  only  if  enough  space  is 
  1700.            available.
  1701.            Returns the length of the message,  -1 if no space available, 
  1702.            or -3 on error (length < 0 or length > buffer buffer size).
  1703.  
  1704.  
  1705.       word check_buffer (bufferptr buf);
  1706.  
  1707.            Returns  the  current number of bytes (not messages)  in  the 
  1708.            buffer, including the length words.
  1709.  
  1710.  
  1711.  
  1712.  
  1713.                              The Keyboard Handler
  1714.                              ====================
  1715.  
  1716.       word t_read_key (void)
  1717.  
  1718.            Waits for a key to be entered.  Returns the ASCII-code in the 
  1719.            lower  byte,  and  the  scan-code in the upper  byte,  or  -2 
  1720.            (0xfffe) on wake.
  1721.  
  1722.  
  1723.       word t_wait_key (dword timeout)
  1724.  
  1725.            Waits for a key to be entered.  Returns the ASCII-code in the 
  1726.            lower  byte,  and  the scan-code in the  upper  byte,  or  -1 
  1727.            (0xffff) on timeout, -2 (0xfffe) on wake.
  1728.  
  1729.  
  1730.       word t_keyhit (void)
  1731.  
  1732.            Returns -1 (0xffff) if no key was entered,  else the value of 
  1733.            the key. The key is not removed.
  1734.  
  1735.  
  1736.  
  1737.  
  1738.  
  1739.  
  1740.  
  1741.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 30
  1742.  
  1743.  
  1744.  
  1745.                             The Serial I/O handler
  1746.                             ======================
  1747.  
  1748.       The  serial I/O handler provides full duplex interrupt driven  I/O 
  1749.       on the serial ports. Support for COM1 and COM2 is included, adding 
  1750.       other ports is possible by changing the source.
  1751.  
  1752.  
  1753.       int v24_install (int port, farptr rcvbuf, word rcvsize, 
  1754.                        farptr xmitbuf, word xmitsize);
  1755.  
  1756.            Installs the handler for the specified port. Currently, ports 
  1757.            0 (COM1) and 1 (COM2) are supported. Returns -1 if an invalid 
  1758.            port is specified, else 0. Both ports may be used simultaneo-
  1759.            usly, the buffer areas for the ports must not be shared.
  1760.            "rcvbuf" is a word pipe buffer area for received  characters, 
  1761.            with "rcvsize" specifying the buffer size in bytes. Note that 
  1762.            the buffer will hold rcvsize / 2 received characters.
  1763.            "xmitbuf"  is  a byte pipe buffer for characters  waiting  for 
  1764.            transmissions, "xmitsize" gives its size in bytes.
  1765.  
  1766.  
  1767.       void v24_remove (int port);
  1768.  
  1769.            Must  be  called for all ports installed before  exiting  the 
  1770.            program.
  1771.  
  1772.  
  1773.       void v24_change_rts (int port, int on);
  1774.  
  1775.            Changes the state of the RTS output line. A nonzero value for 
  1776.            "on" will turn the output on.
  1777.  
  1778.  
  1779.       void v24_change_dtr (int port, int on);
  1780.  
  1781.            Changes the state of the DTR output line. A nonzero value for 
  1782.            "on" will turn the output on.
  1783.  
  1784.  
  1785.       extern void far v24_change_baud (int port, long rate);
  1786.  
  1787.            Changes  the baud rate.  The following baud rates are suppor-
  1788.            ted:
  1789.  
  1790.            50,  75, 110, 134, 150, 300, 600, 1200, 1800, 2000, 
  1791.            2400, 3600, 4800, 7200, 9600, 19200L, 38400L.
  1792.  
  1793.            Note  that baud rates above 9600 may cause problems  on  slow 
  1794.            machines.
  1795.  
  1796.  
  1797.  
  1798.  
  1799.  
  1800.  
  1801.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 31
  1802.  
  1803.  
  1804.  
  1805.       extern void far v24_change_parity (int port, int par);
  1806.  
  1807.            Changes  parity.  The parameter must be one of the  following 
  1808.            values defined in "sio.h":
  1809.  
  1810.                 PAR_NONE  no parity checks
  1811.                 PAR_EVEN  even parity
  1812.                 PAR_ODD   odd parity
  1813.                 PAR_MARK  mark parity
  1814.                 PAR_SPACE space parity
  1815.  
  1816.  
  1817.       extern void far v24_change_wordlength (int port, int len);
  1818.  
  1819.            Changes word length. Values 5, 6, 7, 8 may be given.
  1820.  
  1821.  
  1822.       extern void far v24_change_stopbits (int port, int n);
  1823.  
  1824.            Changes Stopbits. Values 1 and 2 are allowed.
  1825.  
  1826.  
  1827.       extern void far v24_watch_modem (int port, byte flags);
  1828.  
  1829.            The  modem  status  input  lines  specified  in  the  "flags" 
  1830.            parameter must be active to allow transmission.  Transmission 
  1831.            will  stop if one of the lines goes inactive.  The  parameter 
  1832.            may be combined from the following values defined in "sio.h":
  1833.  
  1834.                 CTS  to watch clear to send
  1835.                 DSR  to watch data set ready
  1836.                 RI   to watch ring indicator
  1837.                 CD   to watch carrier detect
  1838.  
  1839.            A  value  of  zero  (the  default)  will  allow  transmission 
  1840.            regardless of modem status.
  1841.  
  1842.  
  1843.       extern void far v24_protocol (int port, int prot, 
  1844.                                     word offthresh, word onthresh);
  1845.  
  1846.            Sets the handshake protocol to use.  The "prot" parameter may 
  1847.            be combined from the following values:
  1848.  
  1849.                 XONXOFF   to enable XON/XOFF (DC1/DC3) handshake
  1850.                 RTSCTS    to enable RTS/CTS handshake
  1851.  
  1852.            The  "offthresh"  value specifies the minimum number of  free 
  1853.            items in the receive buffer. If this threshold is reached, an 
  1854.            XOFF is transmitted and/or the RTS line is inactivated.
  1855.            The  "onthresh"  value specifies the minimum number of  items 
  1856.            that  must be free before XON is transmitted and/or  the  RTS 
  1857.            line is re-activated.
  1858.  
  1859.  
  1860.  
  1861.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 32
  1862.  
  1863.  
  1864.  
  1865.            Enabling XONXOFF will remove all XON and XOFF characters from 
  1866.            the input stream.  Transmission will be disabled when XOFF is 
  1867.            received, and re-enabled when XON is received.
  1868.  
  1869.            Enabling RTSCTS will stop transmission when the CTS modem 
  1870.            input line is inactive.
  1871.  
  1872.  
  1873.       int v24_send (int port, byte ch, dword timeout);
  1874.  
  1875.            Transmits the character "ch". A timeout may be specified. 
  1876.            Returns -1 on timeout, -2 on wake, else 0.
  1877.  
  1878.  
  1879.       int v24_receive (int port, dword timeout);
  1880.  
  1881.            Waits  for  a  received  character.   A  timeout  may  be 
  1882.            specified.  Returns -1 on timeout,  -2 on wake,  else the 
  1883.            character  in the lower byte,  plus an error code in  the 
  1884.            upper byte. The error code is the combination of
  1885.  
  1886.                 0x02      overrun error
  1887.                 0x04      parity error
  1888.                 0x08      framing error
  1889.                 0x10      break interrupt.
  1890.  
  1891.  
  1892.       int v24_check (int port);
  1893.  
  1894.            Returns -1 if no receive character is available, else the 
  1895.            next  character  from  the pipe.  The  character  is  not 
  1896.            removed.
  1897.  
  1898.  
  1899.       int v24_overrun (int port);
  1900.  
  1901.            Checks for receive pipe overrun.  Returns 1 if an overrun 
  1902.            occurred, 0 otherwise. Clears the overrun flag.
  1903.  
  1904.  
  1905.       int v24_modem_status (int port);
  1906.  
  1907.            Returns the current modem status word.  The CTS, DSR, RI, 
  1908.            and  CD  defines may be used to extract the  modem  input 
  1909.            line status.
  1910.  
  1911.  
  1912.       int v24_complete (int port);
  1913.  
  1914.            Returns  1 if all characters in the transmit pipe  have  been 
  1915.            sent, else 0.
  1916.  
  1917.  
  1918.  
  1919.  
  1920.  
  1921.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 33
  1922.  
  1923.  
  1924.  
  1925.       int v24_wait_complete (int port, dword timeout);
  1926.  
  1927.            Waits  for  the  transmit pipe to be  empty.  Returns  -1  on 
  1928.            timeout, -2 on wake, else 0.
  1929.  
  1930.  
  1931.  
  1932.  
  1933.                           The Printer Output Driver
  1934.                           =========================
  1935.  
  1936.       The  printer output driver provides for buffered output to  up  to 
  1937.       three  printer  ports (more can be added by editing  the  source). 
  1938.       Interrupt  or polling may be selected.  Due to the usual  hardware 
  1939.       implementation  of  printers  and print  buffers,  and  the  level 
  1940.       triggered  interrupt structure of the IBM XT/AT,  using polling is 
  1941.       recommended.  When using interrupts, you should not simultaneously 
  1942.       install both port 0 and port 1 with interrupt enabled,  since both 
  1943.       ports share the same interrupt line.
  1944.  
  1945.  
  1946.       int prt_install (int port, byte polling, word prior, 
  1947.                        farptr xmitbuf, word xmitsize);
  1948.  
  1949.            Installs the printer driver for the specified port.  Ports  0 
  1950.            (LPT1), 1 (LPT2), and 2 (LPT3) are supported.
  1951.            The   "polling"  parameter  specifies  polling  output   when 
  1952.            nonzero, interrupt output when zero.
  1953.            The "prior" parameter sets the priority of the printer output 
  1954.            task.
  1955.            "xmitbuf"  is  a buffer area for the printer  output  buffer, 
  1956.            "xmitsize" specifies its size in bytes.
  1957.  
  1958.  
  1959.       void prt_remove (int port);
  1960.  
  1961.            Removes  the  printer  driver for  the  specified  port.  All 
  1962.            installed  ports  must  be  removed  before  terminating  the 
  1963.            program,  or  the system may crash when interrupt  processing 
  1964.            was selected.
  1965.  
  1966.  
  1967.       void prt_change_control (int port, byte control);
  1968.  
  1969.            Changes  the  printer control output lines of the  port.  The 
  1970.            value for "control" may be combined from the following values 
  1971.            defined in "prt.h":
  1972.  
  1973.                 AUTOFEED  will enable printer auto feed if set
  1974.                 INIT      will initialise (prime) the printer if clear
  1975.                 SELECT    will select the printer if set
  1976.  
  1977.  
  1978.  
  1979.  
  1980.  
  1981.       CTask Manual        Version 0.1 (Beta) 88-03-01            Page 34
  1982.  
  1983.  
  1984.  
  1985.       int prt_write (int port, byte ch, dword timeout);
  1986.  
  1987.            Write a byte to the printer.  A timeout may be given. Returns 
  1988.            0 on success, -1 on timeout, -2 on wake.
  1989.  
  1990.  
  1991.       int prt_status (int port);
  1992.  
  1993.            Returns the current printer status lines,  combined from  the 
  1994.            values
  1995.  
  1996.                 BUSY      Printer is busy when 0
  1997.                 ACK       Acknowledge (pulsed 0)
  1998.                 PEND      Paper End detected when 0
  1999.                 SELIN     Printer is selected (on line) when 1
  2000.                 ERROR     Printer error when 0
  2001.  
  2002.  
  2003.       int prt_complete (int port);
  2004.  
  2005.            Returns 1 if the printer buffer has been completely transmit-
  2006.            ted, 0 otherwise.
  2007.  
  2008.  
  2009.       int prt_wait_complete (int port, dword timeout);
  2010.  
  2011.            Waits for printer output to complete.  Returns 0 on  success, 
  2012.            else -1 on timeout, -2 on wake.
  2013.  
  2014.