home *** CD-ROM | disk | FTP | other *** search
/ Frostbyte's 1980s DOS Shareware Collection / floppyshareware.zip / floppyshareware / DOOG / CTASK.ZIP / CTASK.DOC < prev    next >
Text File  |  1990-01-02  |  215KB  |  5,312 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.                                       CTask
  17.  
  18.                            A Multitasking Kernel for C
  19.  
  20.  
  21.  
  22.                           Version 2.0  Released 89-12-24
  23.  
  24.  
  25.  
  26.  
  27.                         Public Domain Software written by
  28.  
  29.                                   Thomas Wagner
  30.  
  31.                              Ferrari electronic GmbH
  32.  
  33.  
  34.  
  35.                                      Contents
  36.  
  37.  
  38.         About this Manual                                               1
  39.  
  40.         Introduction                                                    1
  41.           An Example                                                    1
  42.             Switching the Context                                       2
  43.             You have Mail                                               2
  44.             Reentrancy and Resources                                    3
  45.             DOS Access                                                  3
  46.             Handling the Keyboard                                       4
  47.             Serial I/O and Timeouts                                     4
  48.             Priorities                                                  5
  49.           Change to your liking                                         5
  50.  
  51.         General Notes                                                   6
  52.           What can CTask NOT be used for?                               6
  53.           What is required to use CTask?                                6
  54.           Do I have to pay for using CTask?                             7
  55.           What support can I expect?                                    8
  56.           About this Release                                            9
  57.  
  58.         Multitasking Basics                                            10
  59.           Tasks                                                        10
  60.           Events                                                       10
  61.           Reentrancy                                                   11
  62.           Deadlocks                                                    12
  63.  
  64.         Using CTask                                                    14
  65.           Configuration Options                                        14
  66.           Memory Allocation                                            16
  67.           Snapshot                                                     17
  68.           Task Stacks                                                  17
  69.           Drivers                                                      18
  70.           Things to remember                                           18
  71.           Priority Handling                                            19
  72.  
  73.         Multitasking and DOS                                           20
  74.           Spawning and CTask TSR's                                     21
  75.           Task Groups                                                  22
  76.  
  77.         How does CTask work                                            24
  78.           Queues                                                       24
  79.           The Scheduler                                                25
  80.           Events                                                       25
  81.             Resources                                                  25
  82.             Flags                                                      26
  83.             Counters                                                   26
  84.             Mailboxes and Pipes                                        26
  85.           Serial and Printer Drivers                                   27
  86.  
  87.  
  88.         
  89.         
  90.         Ctask Manual       - Version 2.0 - 89-12-21 -          Contents 1
  91.  
  92.  
  93.         CTask Data Types                                               29
  94.           Typedefs used for simplified type specifications             30
  95.           Error return values for event wait functions                 30
  96.           Queues                                                       31
  97.           The timer/watch control block                                32
  98.           The name link structure                                      36
  99.           The task control block structure                             36
  100.           Task states                                                  38
  101.           Task flags                                                   39
  102.           The Group Control Block                                      40
  103.           The event control blocks                                     40
  104.             The Ticker structure                                       41
  105.             The flag event structure                                   41
  106.             The counter event structure                                42
  107.             The resource event structure                               42
  108.             The mailbox event structure                                43
  109.             The pipe and word pipe event structure                     43
  110.             The buffer event structure                                 44
  111.  
  112.         CTask Routines                                                 45
  113.           Installation and Removal                                     45
  114.           Searching for names                                          47
  115.           Miscellaneous                                                48
  116.           Task Operations                                              50
  117.           Timer Operations                                             52
  118.           Event wait Timeouts                                          53
  119.           "Tickers"                                                    53
  120.           Delays                                                       54
  121.           Timed Events and Watch Events                                54
  122.           Event Operations                                             59
  123.             Resources                                                  59
  124.             Flags                                                      61
  125.             Counters                                                   62
  126.             Mailboxes                                                  64
  127.             Pipes                                                      65
  128.             Buffers                                                    67
  129.           The Keyboard Handler                                         69
  130.           The Serial I/O handler                                       69
  131.           The Printer Output Driver                                    75
  132.  
  133.         Some notes on potential trouble spots                          77
  134.           Turbo C console output                                       77
  135.           The timer tick EOI                                           77
  136.           Debugging                                                    77
  137.  
  138.         Changes from Previous Versions                                 79
  139.           Changes for CTask 1.2 to 2.0                                 79
  140.             Interface Changes                                          79
  141.           Changes for CTask 1.1b to 1.2                                81
  142.           Changes for CTask 1.1 to 1.1b                                83
  143.           Changes for CTask 0.1 to 1.1                                 83
  144.  
  145.  
  146.         
  147.         
  148.         Ctask Manual       - Version 2.0 - 89-12-21 -          Contents 2
  149.  
  150.  
  151.                                 About this Manual
  152.  
  153.         If you are new to CTask, I would suggest reading all chapters
  154.         before attempting to build your first application. One chapter
  155.         you can skip is the CTask Data Types section, since you are not
  156.         required to know about the innards of CTask's structures. You can
  157.         also ignore the List of Changes.
  158.  
  159.         If you are updating from an older release, the List of Changes
  160.         at the end is for you. You can safely skip the Introduction, and
  161.         the section on Multitasking Basics. In the General Notes, you
  162.         should read the section on support and the info about this
  163.         release. In the Using CTask section, check the new configuration
  164.         options, and the chapter on Memory Allocation. Check the Routine
  165.         descriptions, and, if you are using internal data structures
  166.         directly, the Data Type descriptions, for changes.
  167.  
  168.  
  169.         Finally, a note to German speaking readers:
  170.  
  171.         Dieses Handbuch, wie auch die Kommentare im Quellcode, ist in
  172.         Englisch abgefaßt, da dies die universelle Sprache für Computer-
  173.         benutzer weltweit ist. Es gibt keine deutsche Version, und es
  174.         wird auch keine geben (sofern nicht jemand bereit ist einen
  175.         angemessenen Betrag für eine Übersetzung auf den Tisch des Hauses
  176.         zu legen). Selbstverständlich bleibt es Ihnen unbenommen, das
  177.         Handbuch selbst zu übersetzen und diese Version auch zu
  178.         vertreiben, oder mir zum Vertrieb anzubieten. Wie die Software
  179.         ist auch dieses Handbuch Public Domain.
  180.  
  181.  
  182.  
  183.                                    Introduction
  184.  
  185.         CTask is a set of routines that allow your C program to execute
  186.         functions in parallel, without you having to build in sophisti-
  187.         cated polling and switching schemes. CTask handles the switching
  188.         of processor time with a priority based, preemptive scheduler,
  189.         and provides a fairly complete set of routines for inter-task
  190.         communication, event signalling, and task interlocking. CTask
  191.         also includes a number of drivers for MS-DOS that build on the
  192.         basic functions to allow you to include serial I/O, printer
  193.         buffering, and concurrent access to DOS functions into your
  194.         programs with little programming effort.
  195.  
  196.  
  197.                                     An Example
  198.  
  199.         To illustrate one possible use of CTask, let me elaborate on the
  200.         following example. Say you just finished your nifty telecommuni-
  201.         cations program, complete with download protocols, scripts, and
  202.         everything.  But wouldn't it be nice to be able to print the file
  203.         you just downloaded while receiving the next, and edit a comment
  204.         
  205.         
  206.         Ctask Manual       - Version 2.0 - 89-12-21 -              Page 1
  207.  
  208.  
  209.         to some previous message without interrupting the transmission?
  210.         So you take those editor routines from a previous project, plug
  211.         them in, and - oops, how do you switch back and forth between
  212.         editing, communication and printing? The answer to this is CTask.
  213.         CTask allows your C program to do many different things at the
  214.         same time by switching the processor between the tasks you de-
  215.         fine. And since most of the time your program is waiting for some
  216.         slow device (like the human hand) to provide feedback, this
  217.         switching is completely transparent, and will not noticeably slow
  218.         your program down.
  219.  
  220.  
  221.                               Switching the Context
  222.  
  223.         So what is needed to allow the user to edit a file while at the
  224.         same time downloading another and printing a third? First, you
  225.         have to have some form of "context switching". This means that
  226.         you have to be able to interrupt the processing of the download
  227.         when the user presses a key, process the key, and return to the
  228.         download "task" at the exact same point it was interrupted. One
  229.         solution to this would be to include a poll for the keyboard at
  230.         several points in the download routine, and call the editor task
  231.         when a key is available.  But apart from cluttering your code
  232.         with lots of unrelated calls, there is another problem. What if
  233.         the operation the user requested is more involved than just
  234.         putting the character on the screen, like writing the file to
  235.         disk? This might take so long that your download times out. There
  236.         must be a way to pass control back and forth between the two
  237.         tasks, such that no task is delayed for an extended period of
  238.         time, and also to activate the print spooler task at some defined
  239.         interval to output the data to the printer. This context
  240.         switching is called "scheduling" in CTask. The "scheduler" is
  241.         invoked on every system timer tick, and will save the context of
  242.         the current task. The scheduler then takes the first element from
  243.         the queue of tasks that are eligible to be run, and restores the
  244.         context of this task, returning to the point where the task was
  245.         interrupted. This switching is completely automatic, and requires
  246.         no special programming in the tasks itself. All you have to do is
  247.         to tell CTask that there are three tasks, the download task, the
  248.         spooler task, and the editor task.
  249.  
  250.  
  251.                                   You have Mail
  252.  
  253.         All you have to do for context switching, that is. There's a bit
  254.         more to multitasking than meets the eye. How do you tell the
  255.         spooler task what files to spool, and the download task what
  256.         files to download? You can't call a task like an ordinary func-
  257.         tion, so what you need for this is "inter-task communication".
  258.         There must be a way to pass a message containing the filename to
  259.         be printed to the spooler task, and there are several in CTask,
  260.         one of them the "mailbox". The spooler can use a CTask call,
  261.         wait_mail, to wait for a message to arrive at its mailbox. As
  262.         
  263.         
  264.         Ctask Manual       - Version 2.0 - 89-12-21 -              Page 2
  265.  
  266.  
  267.         long as nothing arrives, the spooler task will no longer be
  268.         scheduled, so if there is nothing to print, it will not use any
  269.         processor time. When you send a message with send_mail to the
  270.         mailbox, the spooler will wake up, and process the file. You can
  271.         also send more file name messages to the spooler while it still
  272.         prints a file, leaving the messages in the mailbox until the
  273.         spooler is ready to process the next file.
  274.  
  275.  
  276.                              Reentrancy and Resources
  277.  
  278.         This last example seems innocent enough, but there's a big stumb-
  279.         ling block hidden in it. You allocate the file name messages in
  280.         the controlling task with malloc, and you free them in the
  281.         spooler with free, no problem, right? Wrong, there is a big
  282.         problem, "reentrancy". Reentrancy means that you can re-enter a
  283.         routine while another task is already using it, and that this
  284.         will not disturb the operation of the interrupted task. But
  285.         malloc and free share and modify global data, the chain of free
  286.         memory blocks. Imagine the following: You just called malloc from
  287.         the controlling task. Malloc has loaded the address of a free
  288.         element into a local variable, and is about to write back the
  289.         pointer to the next free element into the last. At exactly this
  290.         moment, the timer ticks, and the spooler is activated. It has
  291.         just finished printing, so it calls free. Free steps through the
  292.         chain of free blocks to find the right place to insert the block.
  293.         According to Murphy's law, it will find just the place where
  294.         malloc is about to write back the pointer. Free coerces the
  295.         elements, points the next pointer to the element malloc just
  296.         wants to take off the chain, and returns. Malloc writes its next
  297.         pointer into the middle of the newly coerced block, and now re-
  298.         turns an element which is still in the free list. Compared to the
  299.         job of finding this kind of bug, stepping in for Tantalus may
  300.         feel like a vacation. This kind of problem code is called a
  301.         "critical region". There must be a way to make sure that no two
  302.         tasks simultaneously enter such a region, and, you guessed it,
  303.         CTask provides one, the "resource". When you request a resource
  304.         in one task, all other tasks trying to request the same resource
  305.         after that are put to sleep until you call release_resource. Only
  306.         then will the highest priority task that waits for the resource
  307.         wake up, and get access to the protected region. So you would
  308.         have to substitute malloc and free calls in your routines with
  309.         calls to functions that first request a resource, execute the
  310.         function, and then release the resource.
  311.  
  312.  
  313.                                     DOS Access
  314.  
  315.         But, you might ask, isn't there another reentrancy problem in
  316.         this example, since both the spooler and the download task might
  317.         simultaneously call DOS to do their file-I/O, and DOS is not
  318.         reentrant? Do I have to substitute all my calls to fread and
  319.         fwrite, too? The answer to this, luckily, is no. CTask traps all
  320.         
  321.         
  322.         Ctask Manual       - Version 2.0 - 89-12-21 -              Page 3
  323.  
  324.  
  325.         your DOS calls, and automatically encloses them in the necessary
  326.         resource request and release calls, so you don't have to worry
  327.         about trashing your disk by simultaneous DOS requests. The
  328.         limited multitasking capabilities of DOS are exploited to allow
  329.         some parallel processing in DOS, and CTask will also detect and
  330.         handle DOS calls by resident background programs like the DOS
  331.         PRINT utility.
  332.  
  333.  
  334.                               Handling the Keyboard
  335.  
  336.         CTask also allows you to circumvent DOS for keyboard input, so
  337.         that waiting for the keyboard will not block other tasks from
  338.         access to DOS functions. Previous versions of CTask used a "pipe"
  339.         to store all keyboard input. Starting with version 1.2, CTask
  340.         uses a "flag" to signal that keyboard input might be available. A
  341.         "flag" is another form of inter-task communication that just sig-
  342.         nals that some event occurred, without passing any specific data.
  343.         The reason for using flags in the keyboard handler is compati-
  344.         bility to TSR's. If a keyboard interrupt occurs, the interrupt
  345.         handler just sets a flag, and passes on the interrupt. The key-
  346.         board routines wait for this flag to be set, and then check the
  347.         keyboard buffer if a character has arrived. If the keyboard buf-
  348.         fer is empty, the flag is again cleared, and the keyboard rou-
  349.         tines put the waiting task to sleep again, so the processor is
  350.         free to do more interesting things than to loop waiting for the
  351.         user to press a key.
  352.  
  353.                              Serial I/O and Timeouts
  354.  
  355.         The "pipe" is similar to the mailbox in that you can wait for
  356.         items to be sent to a pipe. But unlike mailboxes, pipes use their
  357.         own buffer to store the items (which are limited to bytes and
  358.         words), so you don't have to allocate mail blocks for each item.
  359.         When waiting on the pipe, your task is put to sleep, freeing the
  360.         processor. Pipes are used for the serial I/O handler included
  361.         with CTask that makes some of the work you've put into your
  362.         communications package obsolete. When outputting data to the
  363.         serial port via the CTask routines, the data is buffered in a
  364.         pipe, and incoming data is also placed in a pipe. All interrupt
  365.         handling, and the processing of modem status and XON/XOFF proto-
  366.         cols, is done by CTask, so you can concentrate on implementing
  367.         the higher level protocols. Since CTask allows all calls that
  368.         wait for pipes, mail, and other events, to specify a timeout that
  369.         is based on the system tick, you do not have to resort to timed
  370.         waiting loops to detect communication line faults. You simply
  371.         give a time limit on the wait call, and if that limit expires,
  372.         the wait routine will return with an error indication.
  373.  
  374.  
  375.  
  376.  
  377.  
  378.         
  379.         
  380.         Ctask Manual       - Version 2.0 - 89-12-21 -              Page 4
  381.  
  382.  
  383.                                     Priorities
  384.  
  385.         If the protocol you implement requires fast responses to incoming
  386.         blocks, you can influence the response of CTask to your comm
  387.         task's needs by giving this task a higher priority. CTask allows
  388.         65535 different priority levels, and tasks having higher priority
  389.         are scheduled before tasks with lower priority. Also, high prio-
  390.         rity tasks will get access to mail, pipes, and resources, before
  391.         other tasks. It might even be sensible to split the comm task
  392.         into two separate tasks, one of high priority that assembles the
  393.         incoming bytes into blocks and handles the protocol, and a lower
  394.         priority task that reads the received blocks from a mailbox and
  395.         stores them on the disk. In extremely time critical applications,
  396.         you can even turn off task preemption, so the timer tick will no
  397.         longer cause a task switch.
  398.  
  399.  
  400.                               Change to your liking
  401.  
  402.         CTask provides all basic building blocks for implementing
  403.         concurrent programs in an easy and comprehensible way. Since
  404.         CTask is mainly implemented in C, it may not be the fastest
  405.         possible system, but due to the straightforward design which uses
  406.         few shortcuts, modifying the sources to suit your needs and taste
  407.         can be done without weeks of studying assembler code that
  408.         squeezes every microsecond from the processor. CTask is public
  409.         domain code, and there are no restrictions on its use. It is
  410.         distributed in source form, so you are free to change all aspects
  411.         of the package. Multitasking programs, especially in embedded
  412.         applications, tend to be very diverse in their needs for specific
  413.         constructs. So although CTask is ready to run under DOS, and is
  414.         easily adaptable for embedded applications, you should see CTask
  415.         more as a starting point for your own thoughts, and as a toolbox
  416.         from which you can pick the instruments you need, than as a
  417.         finished and fixed block of code you simply plug into your
  418.         application.
  419.  
  420.  
  421.  
  422.  
  423.  
  424.  
  425.  
  426.  
  427.  
  428.  
  429.  
  430.  
  431.  
  432.  
  433.  
  434.  
  435.  
  436.         
  437.         
  438.         Ctask Manual       - Version 2.0 - 89-12-21 -              Page 5
  439.  
  440.  
  441.                                   General Notes
  442.  
  443.  
  444.                          What can CTask NOT be used for?
  445.  
  446.         CTask is not intended to provide for multitasking on the command
  447.         level of MS-DOS. Although version 1.2 of CTask added the ability
  448.         to TSR and spawn other programs, and to communicate between
  449.         multiple copies of CTask, a full DOS-process management (which
  450.         would have to include keeping track of memory allocation and DOS
  451.         process control blocks) is not included. Adding this functio-
  452.         nality would not be trivial (although certainly worthwhile).
  453.  
  454.         CTask also is not a true "Real-Time" multitasking system. Due to
  455.         the completely dynamic structure of tasks and events, and the
  456.         minimal restrictions on what interrupt handlers may do, it is
  457.         nearly impossible to calculate a maximum interrupt or task switch
  458.         latency. If you have critical timing requirements, you should
  459.         consider getting a professional package like AMX. CTask has been
  460.         used successfully in embedded control applications, and if your
  461.         timing requirements are not that critical, or you're ready to
  462.         take up the task of measuring and calculating latencies with your
  463.         specific task setup, CTask may be useful even for Real-Time
  464.         applications. However, you're more or less on your own in this
  465.         field.
  466.  
  467.         And, there is no warranty that CTask does perform without errors,
  468.         or does exactly what you or I intended. So CTask should not be
  469.         used in applications in which malfunction of routines of this
  470.         package would result in damage to property or health of any
  471.         person without *very* extensive testing under all kinds of loads.
  472.         In using CTask, you do so at your own risk. I have tested CTask
  473.         extensively, but with a complex system like CTask, where timing
  474.         might make a big difference, you can't be completely sure that
  475.         all will work as intended.
  476.  
  477.  
  478.                           What is required to use CTask?
  479.  
  480.         To compile CTask, Microsoft C 5.1 or later, or Turbo C 2.0 or
  481.         later are required. Microsoft MASM 5.1 or later, or TASM 1.0 or
  482.         later is required for the assembler parts. Conversion to other
  483.         compilers is possible if they conform to the new ANSI (draft)
  484.         standard. Conversion of the assembler parts to other Assembler
  485.         versions requires substitution of the simplified model directives
  486.         by explicit segment definitions, and adding the DGROUP to offsets
  487.         referencing data.
  488.  
  489.         CTask will add 14k-25k of code to your program, depending on
  490.         options and installed drivers. The minimum static data used by
  491.         CTask is approximately 4k. Non-DOS versions use less memory.
  492.  
  493.  
  494.         
  495.         
  496.         Ctask Manual       - Version 2.0 - 89-12-21 -              Page 6
  497.  
  498.  
  499.         Converting CTask for stand-alone operation requires few changes.
  500.         Mainly, the timer interrupt handler (in "tsktim.asm") has to be
  501.         rewritten, and the initialization code (in "tskmain.c") may have
  502.         to be changed. Changes to other modules (naturally except the
  503.         optional hardware drivers) should not be necessary. The "DOS"
  504.         configuration flag in tskconf.h can be disabled to eliminate most
  505.         system-dependent features of CTask.
  506.  
  507.         Another requirement is a good debugger. If you never before wrote
  508.         multitasking applications, you're in for some surprises. The
  509.         normal debugging tools (Symdeb, Codeview) are of only limited
  510.         use, since they use DOS calls for their I/O, and thus may
  511.         conflict with your background tasks. One safety measure is to
  512.         first thoroughly test your program with preemption disabled,
  513.         possibly inserting some schedule() calls, and only allow task
  514.         preemption if you found most major bugs. I personally recommend
  515.         Periscope for debugging, since it can be made resident and so is
  516.         always available, and because it does not use DOS. Periscope IV
  517.         is the most expensive solution, and the best tool you can
  518.         imagine, but the less costly versions will also help a lot.
  519.  
  520.  
  521.                         Do I have to pay for using CTask?
  522.  
  523.         No. One reason for writing CTask was to provide a free, no
  524.         strings attached, utility, instead of the usual "for personal use
  525.         only" restriction. Writing a multitasking application for
  526.         personal use only doesn't seem too interesting to me. CTask is
  527.         completely free, and there is no restriction on its use. You may
  528.         incorporate all or parts of CTask in your programs, and redistri-
  529.         bute it in source or binary form by any means. I also do not
  530.         restrict the use of CTask in commercial applications. Since
  531.         trying to distribute the unmodified CTask for money will only
  532.         give you a bad name, you may even do that if you find someone
  533.         dumb enough to buy it. Naturally, if you make a bundle from it,
  534.         or simply like CTask, I would not reject a donation. However,
  535.         this is not required, and it will not give you any special
  536.         support.
  537.  
  538.  
  539.  
  540.  
  541.  
  542.  
  543.  
  544.  
  545.  
  546.  
  547.  
  548.  
  549.  
  550.  
  551.  
  552.         
  553.         
  554.         Ctask Manual       - Version 2.0 - 89-12-21 -              Page 7
  555.  
  556.  
  557.                            What support can I expect?
  558.  
  559.         I will try my best to eliminate any bugs reported to me, and to
  560.         incorporate suggested enhancements and changes. However, my spare
  561.         time is limited, so I can not guarantee continued or individual
  562.         support. (But since I'm one of the owners of a consulting firm,
  563.         you can always hire me to do it...). Please address all reports
  564.         or questions to my business address:
  565.  
  566.                 Ferrari electronic GmbH
  567.                 attn: Thomas Wagner
  568.                 Beusselstrasse 27
  569.                 D-1000 Berlin 21, West Germany
  570.  
  571.                 Phone: (49-30) 396 50 21
  572.                 Fax:   (49-30) 396 80 20
  573.  
  574.                 BIX:   twagner
  575.                 UUCP:  oeschi@netmbx.UUCP (attn: Thomas Wagner)
  576.  
  577.         But, please, if at all possible, do it in writing. Please do not
  578.         phone unless it is absolutely vital (or you have a business
  579.         proposal). I like to hear about any applications for CTask, and
  580.         if you are visiting Berlin, I also invite you to drop by for a
  581.         talk. But I am usually not that happy when I am interrupted in my
  582.         paid work by a phone call requesting support for a free product.
  583.  
  584.         I will try to answer all letters and Faxes I receive. However, I
  585.         am usually not the fastest in this respect, so please be patient.
  586.         The preferred, and the fastest, method to reach me is through
  587.         BIX.
  588.  
  589.         BIX (tm) is the BYTE Information Exchange, an electronic confe-
  590.         rencing system created by McGraw-Hill, the publishers of the well
  591.         renowned BYTE magazine. BIX can be (and is) accessed from all
  592.         parts of the world. Although accessing BIX from outside the US
  593.         isn't exactly cheap (don't ask me what I have to pay each month),
  594.         the wealth of information available there, and the fast and
  595.         extensive help the other members can give you on all kinds of
  596.         hard- and software problems, makes it worth every Mark, Peseta,
  597.         Franc, or Ruble you have to spend. New versions and updates of
  598.         CTask will first appear on BIX.
  599.  
  600.         At the time of this writing, I am one of the moderators of the
  601.         IBM exchange on BIX, moderating the "ibm.other" conference. I
  602.         have created a support topic for CTask, where all suggested
  603.         enhancements and changes, plus bug reports, can be posted. Just
  604.         join "ibm.other", topic "ctask". You can also report problems of
  605.         limited general interest via BIXmail to "twagner". Unless I am
  606.         not able to reach the keyboard for some reason, I log on at least
  607.         once per day, so you can expect relatively fast responses to your
  608.         queries.
  609.  
  610.         
  611.         
  612.         Ctask Manual       - Version 2.0 - 89-12-21 -              Page 8
  613.  
  614.  
  615.         To get more info on joining BIX, call the BIX Customer Service at
  616.         800-227-2983 (U.S. and Canada), or 603-924-7681 (New Hampshire
  617.         and outside the U.S.) from 8:30 to 23:00 Eastern Time (-5 GMT).
  618.         BIX access currently is $39 for three months (flat fee, no extra
  619.         charges for connect time), plus the applicable telecomm charges
  620.         (Tymnet in the U.S. and Canada, your local PTT's Packet Net
  621.         charges from outside the U.S.). If you're calling from the US,
  622.         you can subscribe by dialling BIX direct at 617-861-9767. Hit the
  623.         return key, and enter "bix" at the 'login (enter "bix")' prompt.
  624.         At the 'Name?' prompt, enter "bix.flatfee". International users
  625.         need an account (NUI) with their local packet net. Please enquire
  626.         at your post/telecomm office for details. If you already own a
  627.         NUI, enter the BIX international network address (NUA),
  628.         "310690157800", and enter "bix.flatfee" at the 'Name?' prompt.
  629.  
  630.  
  631.                                 About this Release
  632.  
  633.         Since the Beta release of CTask in March 1988, CTask has found
  634.         widespread distribution through several channels. I have heard
  635.         from some users, and their suggestions have been implemented in
  636.         this version as far as possible. Special thanks go to Kent J.
  637.         Quirk, Peter Heinrich, Stephen Worthington, Burt Bicksler, Tron
  638.         Hvaring, Joe Urso, and Dave Goodwin, for their bug reports,
  639.         suggestions, and enhancements. Bug reports also came in from
  640.         others, thanks to all who wrote or called. The serial code in
  641.         TSKSIO.C was enhanced by S. Worthington.
  642.  
  643.         This release is the long awaited successor to version 1.1.
  644.         Although I did announce a "version 1.2", and some users even
  645.         received beta copies of it, 1.2 was never officially released.
  646.         This release is called 2.0 because of the major changes to the
  647.         main CTask data structures, which significantly impact the kernel
  648.         routines. Version 1.2 added most of the new features, so you will
  649.         see references to 1.2 throughout the manual. If you've been using
  650.         (and modifying) 1.1 or a 1.2 pre-release, and the changes to the
  651.         queue structure cause trouble for your application, the final
  652.         version of 1.2 is available on special request.
  653.  
  654.         Again, please notify me of your CTask application, report bugs,
  655.         or suggest changes and enhancements. If I know you're using
  656.         CTask, I can notify you of possible new releases (although none
  657.         is currently planned), and of possible severe bugs.
  658.  
  659.  
  660.  
  661.  
  662.  
  663.  
  664.  
  665.  
  666.  
  667.  
  668.         
  669.         
  670.         Ctask Manual       - Version 2.0 - 89-12-21 -              Page 9
  671.  
  672.  
  673.                                Multitasking Basics
  674.  
  675.                                       Tasks
  676.  
  677.         In CTask, a "task" is defined as a (far) C function. The number
  678.         of tasks is not limited, and one function may be used for several
  679.         tasks. There is little difference between a task function and a
  680.         normal function. The usual form of a task function is
  681.  
  682.              void far my_task (farptr arg)
  683.              {
  684.                   one-time initialization code
  685.                   while (TRUE)
  686.                     {
  687.                     processing code
  688.                     }
  689.              }
  690.  
  691.         A task function is (usually) never called directly. Rather, it is
  692.         specified in the call to the create_task routine, and started by
  693.         start_task. It will then continue to run, sharing the processor
  694.         time with all other tasks, until it is "killed" by kill_task.
  695.         Returning from the routine will have the same effect as a kill.
  696.         The sharing of processor time is accomplished by "preempting" the
  697.         tasks. Preemption means that the task is interrupted in the
  698.         middle of some statement by a hardware interrupt (usually the
  699.         timer), and is *not* immediately restarted when the interrupt
  700.         handler returns. Instead, the next task that is able to run is
  701.         activated by the "scheduler", with the interrupted task
  702.         continuing its duty at some (normally unpredictable) later time.
  703.         You can also have multi-tasking without preemption, and CTask
  704.         supports this, too, but this requires full cooperation of all
  705.         tasks in the system, such that no task continues to run for an
  706.         extended period of time without passing control to other tasks by
  707.         an explicit scheduling request, or by waiting for an event.
  708.  
  709.         The optional argument to the task function may be used if one
  710.         function is to be used for more than one task, for example to
  711.         pass a pointer to a static data area for use by this specific
  712.         instance of the function.
  713.  
  714.  
  715.                                       Events
  716.  
  717.         Tasks alone would be of limited use. If you have several routines
  718.         which just do number crunching or sorting or such, making them
  719.         into parallel tasks would be sensible only on a multiprocessor
  720.         system. Normally, at least some of your tasks will wait for some
  721.         outside "event" to happen, be it the user pressing a key, or a
  722.         character arriving from the modem. Then there may be tasks which
  723.         have to wait until another task finishes processing on some piece
  724.         of data before they can continue. For this synchronization, there
  725.         are a number of constructs in CTask, which I summarize under the
  726.         
  727.         
  728.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 10
  729.  
  730.  
  731.         name "event". Common to all events are the operations of waiting
  732.         for an event to happen, and signalling that the event has
  733.         happened. Using a CTask event is much more efficient than looping
  734.         while waiting on some shared data location to change state, and
  735.         also eliminates concurrency problems inherent in such a simple
  736.         approach. Tasks waiting for an event are taken off the scheduler
  737.         queue, so they no longer use processor time.
  738.  
  739.  
  740.                                     Reentrancy
  741.  
  742.         One of the biggest problem with multitasking in general, and C on
  743.         the PC in particular, is reentrancy. Reentrancy means that you
  744.         can use a routine, be it you own, or one of the C run-time
  745.         library, from different tasks at the same time. When writing your
  746.         own code, you can easily avoid problems, but when using the run-
  747.         time library routines, you often can only guess if the routines
  748.         are reentrant or not.
  749.  
  750.         A routine is NOT reentrant if it modifies static data. This can
  751.         be illustrated by the following nonsense example:
  752.  
  753.              int non_reentrant (int val)
  754.              {    static int temp;
  755.                   temp = val;
  756.                   return temp * 2;
  757.              }
  758.  
  759.         Now take two tasks, which call this routine. Task1 calls it with
  760.         val=3, Task2 with val=7. What will be the return value for both
  761.         tasks? You never know. There are three possible outcomes:
  762.  
  763.           1) The tasks execute sequentially. Task1 will get 6, and Task2
  764.              14 as a result. This is what one normally expects.
  765.  
  766.           2) Task1 runs up to "temp = val", then is interrupted by the
  767.              timer. Task2 executes, and gets 14 as result. Then Task1
  768.              continues. Return for Task1 is 14.
  769.  
  770.           3) Task2 runs up to "temp = val", then is interrupted by the
  771.              timer. Task1 executes, and gets 6 as result. Then Task2
  772.              continues. Return for Task2 is 6.
  773.  
  774.         add to this the effects of optimization, and a loop, and the
  775.         outcome is completely random.
  776.  
  777.         Most routines in the C library will not explicitly do something
  778.         like this, but all functions that
  779.  
  780.              - do file I/O (read, write, printf, scanf, etc.) or
  781.              - change memory allocation (malloc, free, etc.)
  782.  
  783.  
  784.         
  785.         
  786.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 11
  787.  
  788.  
  789.         have to use some static data to do buffering, or to store the
  790.         chain of memory blocks in. Interrupting such an operation may
  791.         have disastrous effects. The most devilish aspect of non-
  792.         reentrancy is that the effects are unpredictable. Your program
  793.         may run 1000 times without any error, and then on the 1001th time
  794.         crash the system so completely that only the big red switch will
  795.         help.
  796.  
  797.         So what can you do about it? A lot. There are several ways to
  798.         protect "critical regions" from being entered in parallel. The
  799.         most simple method is to disable interrupts. This, however,
  800.         should be used only for *very* short periods of time, and not for
  801.         rou-tines that might themselves re-enable them (like file-I/O). A
  802.         better method is to temporarily disable task preemption. The
  803.         routines tsk_dis_preempt and tsk_ena_preempt allow this form of
  804.         short-term task switch disable. Interrupts may still be
  805.         processed, but tasks will not be preempted. The best way is to
  806.         use a "resource". A resource is a special kind of event, which
  807.         only one task can possess at a time. Requesting the resource
  808.         before entering the routine, and releasing it afterwards, will
  809.         protect you from any other task simultaneously entering the
  810.         critical region (assuming that this task also requests the
  811.         resource).
  812.  
  813.         It is also reasonably safe to use file-I/O without protection if
  814.         it goes to different files. The C file control blocks for
  815.         different files are distinct, so there will be no conflict
  816.         between tasks. Since DOS access is automatically protected by
  817.         CTask, concurrent file I/O is possible.
  818.  
  819.         What you may NEVER do is to use a non-reentrant routine that is
  820.         not protected by an interrupt disable from an interrupt handler.
  821.         An interrupt handler is not a task, and so can not safely request
  822.         a resource or disable task preemption. This is the reason why the
  823.         CTask routines generally disable interrupts before manipulating
  824.         the internal queues rather than only disabling task preemption.
  825.  
  826.  
  827.                                     Deadlocks
  828.  
  829.         One thing to watch out for when using resources or similar event
  830.         mechanisms is not to get into a situation where Task 1 waits for
  831.         a resource that Task 2 has requested, while at the same time Task
  832.         2 waits for a resource that Task 1 already has. This situation is
  833.         called a deadlock (or, more picturesque, deadly embrace), and it
  834.         can only be resolved with outside help (e.g. waking up one of the
  835.         tasks forcibly). To illustrate, consider the following example:
  836.  
  837.  
  838.  
  839.  
  840.  
  841.  
  842.         
  843.         
  844.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 12
  845.  
  846.  
  847.              void far task_1 ()
  848.              {
  849.                ...
  850.                request_resource (&rsc1, 0L);
  851.                request_resource (&rsc2, 0L);
  852.                ...
  853.              }
  854.  
  855.              void far task_2 ()
  856.              {
  857.                ...
  858.                request_resource (&rsc2, 0L);
  859.                request_resource (&rsc1, 0L);
  860.                ...
  861.              }
  862.  
  863.         Since interrupts are always enabled on return from a task switch,
  864.         even if the statements are enclosed in a critical region, there
  865.         is no guarantee that the request_resource calls will be executed
  866.         without interruption. In this example, the problem is obvious,
  867.         but in a more complex application, where resource requests or
  868.         other waits might be buried in some nested routine, you should
  869.         watch out for similar situations. One way to avoid problems would
  870.         be in this example to change task_2 to
  871.  
  872.              void far task_2 ()
  873.              {
  874.                   int again;
  875.                   ...
  876.                   do {
  877.                        request_resource (&rsc2, 0L);
  878.                        if (again = c_request_resource (&rsc1))
  879.                           {
  880.                           release_resource (&rsc2);
  881.                           delay (2L);
  882.                           }
  883.                      } while (again);
  884.                   ...
  885.              }
  886.  
  887.         Note that this is only one of many possible approaches, and that
  888.         this approach favors task_1 over task_2.
  889.  
  890.         You should also take care not to kill tasks that currently own a
  891.         resource. CTask will not detect this, and the resource will never
  892.         be freed.
  893.  
  894.  
  895.  
  896.  
  897.  
  898.  
  899.  
  900.         
  901.         
  902.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 13
  903.  
  904.  
  905.                                    Using CTask
  906.  
  907.         CTask comes archived with both source and binaries. The binary
  908.         version is compiled in the large model, but since the precompiled
  909.         kernel routines don't use any functions from the C library, you
  910.         can use all functions in small or other model programs (except
  911.         Turbo C's Tiny and Huge models). The include files provided
  912.         specify all model dependencies, so you don't have to use the
  913.         large model for your application, but always remember to include
  914.         "tsk.h" for the type definitions and function prototypes.
  915.  
  916.         The C source files will work without changes for both Microsoft
  917.         and Turbo C. The library files are not compatible, so use
  918.         "ctaskms.lib" for Microsoft, and "ctasktc.lib" for Turbo C.
  919.  
  920.         In the distributed configuration (i.e. dynamic allocation of
  921.         control blocks enabled), the file TSKALLOC.C must be added to the
  922.         library or separately linked after compiling it *in the same
  923.         model as the main program*. This file uses C-library routines,
  924.         and thus must match the main program's memory model. The same
  925.         goes for TSKSNAP.C, an optional snapshot-dump utility, and
  926.         CONOUT.C, the sample console output handler. The provided
  927.         "ctsupms.lib" and "ctsuptc.lib" files have been compiled in the
  928.         large model, and may only be used with large model programs.
  929.  
  930.         Turbo C's huge model uses a different segment setup for data
  931.         segments. This requires using a special data segment for all
  932.         CTask data, and compilation of the CTask kernel in huge model.
  933.         For the assembler files, the symbol TC_HUGE must be defined
  934.         during assembly, the C files must be compiled with the Data-
  935.         Segment and BSS-Segment naming options. Make-files for Turbo C
  936.         Huge model are included.
  937.  
  938.  
  939.                               Configuration Options
  940.  
  941.         The file TSKCONF.H contains a number of #define's that allow you
  942.         to configure some CTask features. In general, you should
  943.         recompile all of CTask when changing one of the flags. You must
  944.         also take care to modify the corresponding equate in the
  945.         assembler-include TSK.MAC.
  946.  
  947.         The entries are
  948.  
  949.         TSK_DYNAMIC
  950.              If 1, you can let CTask dynamically create task and event
  951.              control blocks, task stacks, and pipe buffers, by passing
  952.              NULL as the block address. Since this requires the C runtime
  953.              allocation calls, it is not suitable for non-DOS
  954.              applications (except if you provide your own memory
  955.              allocation routines).
  956.  
  957.  
  958.         
  959.         
  960.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 14
  961.  
  962.  
  963.              This option is normally enabled (1).
  964.  
  965.         TSK_NAMEPAR
  966.              If 1, all create_xxx calls accept an additional parameter,
  967.              the name of the created control block. This name should con-
  968.              tain only printeable characters, and should not be longer
  969.              than 8 characters plus the zero terminator. This option is
  970.              used together with TSK_NAMED (see below).
  971.  
  972.              This option is normally enabled (1).
  973.              It must be enabled for DOS.
  974.  
  975.         TSK_NAMED
  976.              If 1, all control blocks (except timer control blocks) are
  977.              named and linked on creation. This allows the snapshot dump
  978.              routine to display the system state. TSK_NAMEPAR must be
  979.              defined for this option to work. Since it may be desirable
  980.              to switch off the handling of the names after the debugging
  981.              phase, without having to change all create_xxx calls to omit
  982.              the name parameter, the name parameter is ignored if
  983.              TSK_NAMED is undefined, but TSK_NAMEPAR is defined.
  984.  
  985.              This option is normally enabled (1). It must be enabled for
  986.              DOS.
  987.  
  988.         CLOCK_MSEC
  989.              If 1, all timeouts are specified in milliseconds instead of
  990.              timer ticks. This allows programming of delays and timeouts
  991.              independent of the speedup-parameter or the system tick
  992.              rate. Since timeout calculations use floating point
  993.              operations if this option is enabled, a floating point
  994.              library is needed. This precludes model independence of the
  995.              CTask kernel.
  996.  
  997.              This option is normally disabled (0).
  998.  
  999.         PRI_TIMER
  1000.              Specifies the priority of the timer task. Normally the timer
  1001.              task should have a higher priority than any other task in
  1002.              the system.
  1003.  
  1004.              The value is normally 0xf000.
  1005.  
  1006.         PRI_STD
  1007.              This value may be used in your programs as the standard
  1008.              priority of user tasks. Its value is arbitrary. It is not
  1009.              used in the kernel except for the definition of PRI_INT9
  1010.              (see below).
  1011.  
  1012.              The value is normally 100 (decimal).
  1013.  
  1014.         PRI_INT8
  1015.              Determines the priority of the "int8"-task. This task chains
  1016.         
  1017.         
  1018.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 15
  1019.  
  1020.  
  1021.              to the previous interrupt vector for the sytem timer tick,
  1022.              and thus may activate resident TSR's. Since TSR's normally
  1023.              use polling when accessing the keyboard and other devices,
  1024.              the priority of the int8-task should be equal to or lower
  1025.              than normal user-defined tasks to allow your program to con-
  1026.              tinue to run while the TSR is active. You can tune this
  1027.              value so that some tasks are blocked by the TSR to avoid
  1028.              trashing the screen.
  1029.  
  1030.              The value is normally  PRI_STD.
  1031.  
  1032.         IBM
  1033.         DOS
  1034.              Both IBM and DOS are more or less of informative value only,
  1035.              to point out those areas in the kernel that need attention
  1036.              when converting to non-IBM or non-DOS environments.
  1037.              Disabling one or both of this options requires the
  1038.              substitution of your own routines for installation, timer,
  1039.              and keyboard handling.
  1040.  
  1041.              Both options must normally be enabled (1).
  1042.  
  1043.         GROUPS
  1044.              If enabled, task groups, i.e. multiple invocations of CTask,
  1045.              are supported.
  1046.  
  1047.              This option is normally enabled (1).
  1048.              It should be enabled for DOS.
  1049.  
  1050.         SINGLE_DATA
  1051.              If enabled, only a single global data block is used. This
  1052.              speeds up processing, but prohibits linkage of multiple
  1053.              groups. Useful for dedicated systems, and also if your
  1054.              program is known to never interact with another copy of
  1055.              CTask. Should be left 0 if you're not so sure, must be 0 if
  1056.              GROUPS is enabled.
  1057.  
  1058.         AT_BIOS
  1059.              If enabled, the AT BIOS wait/post handler is installed. May
  1060.              be disabled when compatibility problems arise.
  1061.  
  1062.              This option is normally enabled (1).
  1063.              You can also disable installation of this handler with an
  1064.              install flag in the install_tasker call.
  1065.  
  1066.  
  1067.  
  1068.                                 Memory Allocation
  1069.  
  1070.         TSKALLOC.C is needed if TSK_DYNAMIC is enabled in tskconf.h to
  1071.         handle the allocation and free calls. If you want to use dynamic
  1072.         allocation in your own tasks, you should also use the functions
  1073.         tsk_alloc and tsk_free to avoid the reentrancy problems mentioned
  1074.         
  1075.         
  1076.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 16
  1077.  
  1078.  
  1079.         in the introduction. If you should need other forms of alloc
  1080.         (like calloc) the recommended way is to add those functions to
  1081.         TSKALLOC.C, requesting the resource alloc_resource before calling
  1082.         the C memory-allocation function.
  1083.  
  1084.         Joe Urso provided the following tip on how to force all memory
  1085.         allocation to pass through the resource handling functions:
  1086.  
  1087.         "I have found that some MS Library functions call the allocate
  1088.         and free library functions, namely the first call to fread(),
  1089.         fopen(), and fclose().
  1090.  
  1091.         To fix this situation I have
  1092.  
  1093.            - extracted FMALLOC from the llibce library,
  1094.  
  1095.            - renamed the functions within that object (via the Norton
  1096.              Utilities) to the upper case spelling of the functions
  1097.              (FREE, MALLOC, _FFREE and _FMALLOC) and replaced the file in
  1098.              the lib. I also did the same for object EXPAND because of
  1099.              the function REALLOC.
  1100.  
  1101.            - then modified TSKALLOC.C to contain the lower case spelling
  1102.              of malloc, free, and expand. These functions aquire the
  1103.              alloc resource, then call the upper case spelling of the
  1104.              name.
  1105.  
  1106.         At link time I now link with /NOIGNORECASE and /NODEFAULTLIB."
  1107.  
  1108.  
  1109.                                      Snapshot
  1110.  
  1111.         TSKSNAP.C is only needed if you want to include the snapshot dump
  1112.         into your program. Note that you can *not* use snapshot if you
  1113.         disable TSK_NAMED in tskconf.h.
  1114.  
  1115.  
  1116.                                    Task Stacks
  1117.  
  1118.         When compiling your application, turn stack checking off. The
  1119.         standard stack check is of little use with task stacks, and may
  1120.         interfere with CTask's operation. The stack area for tasks should
  1121.         be allocated on the main program's stack, not in the static or
  1122.         heap data space. The reason for this is that some of the C
  1123.         library routines check for stack overflow regardless of your
  1124.         compile-time switches, and will crash your application if you use
  1125.         stacks outside the normal stack. The stack allocation parameter
  1126.         with LINK (MS-C), or the _stacksize variable (Turbo C) have to be
  1127.         increased to reflect the additional stack space. When calculating
  1128.         task stack sizes, keep in mind that library routines (esp.
  1129.         printf) allocate a lot of space on the stack for temporary
  1130.         variables. A minimum of 1k for tasks using library routines is
  1131.         recommended, 2k puts you on the safe side. Tasks not using C
  1132.         
  1133.         
  1134.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 17
  1135.  
  1136.  
  1137.         library routines may use a smaller stack, about 256 bytes at a
  1138.         minimum, plus space for any local variables and nested routines.
  1139.         Then add up all task stacks, and add space for the main task (the
  1140.         function calling install_tasker), with this size also dependent
  1141.         on what you will do in the main task while CTask is active.
  1142.         Stacks for tasks that do not use C library routines may be
  1143.         allocated anywhere.
  1144.  
  1145.  
  1146.                                      Drivers
  1147.  
  1148.         The keyboard and DOS handlers are always installed with CTask.
  1149.         Using the serial I/O and printer drivers is optional, so you have
  1150.         to install them separately, but only *after* installing CTask.
  1151.         When using the serial driver, include "sio.h" in your modules,
  1152.         when using the printer driver, include "prt.h".
  1153.  
  1154.         Another driver that is automatically installed is the BIOS
  1155.         wait/post handler for the IBM AT. The AT BIOS contains some
  1156.         multitasking hooks to avoid busy waiting in the BIOS. If you
  1157.         experience problems with disk accesses or printer output through
  1158.         BIOS (not through the CTask printer driver), you should disable
  1159.         installation of this driver by setting AT_BIOS to zero in
  1160.         tskconf.h, or not specifying the IFL_INT15 flag in
  1161.         install_tasker. Normally, no problems should arise with this
  1162.         driver even in XT type machines.
  1163.  
  1164.  
  1165.                                 Things to remember
  1166.  
  1167.         Remember that tasks are not automatically started after creation.
  1168.         Use start_task to allow a created task to run.
  1169.  
  1170.         Always use create_xxx on resources, pipes, etc. Using the event
  1171.         routines without doing so will have unpredictable results.
  1172.  
  1173.         Before exiting the program, all installed drivers and CTask
  1174.         should be explicitly removed. Although the DOS handler traps the
  1175.         terminate call and automatically calls remove_tasker, you should
  1176.         make sure that all tasks are completed properly, and call
  1177.         remove_tasker yourself.
  1178.  
  1179.         Deleting events before exiting the program is not mandatory, but
  1180.         recommended to kill all tasks waiting for the event. You should
  1181.         be careful not to kill tasks while they are active in DOS. The
  1182.         kill_task routine should be reserved for fatal error handling.
  1183.         The best way is to let the tasks kill themselves depending on
  1184.         some global variable or event. If a task is killed while waiting
  1185.         for input in DOS, DOS operation may be severely impaired. If you
  1186.         use the C console input routines, make sure that the task returns
  1187.         from DOS before it is killed, if necessary by requesting the user
  1188.         to press a key.
  1189.  
  1190.         
  1191.         
  1192.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 18
  1193.  
  1194.  
  1195.                                 Priority Handling
  1196.  
  1197.         CTask provides for prioritized task execution and event
  1198.         processing. This means that a task that has a higher priority
  1199.         will be run before any other tasks having lower priority. Also, a
  1200.         higher priority task will gain access to resources, counters,
  1201.         pipes, and mail, before lower priority tasks. With fixed
  1202.         priorities, this means that a high priority task can monopolize
  1203.         CPU time, even if it calls schedule() explicitly. Variable
  1204.         priority increases each eligible task's priority by one on each
  1205.         scheduler call, so that lower priority tasks will slowly rise to
  1206.         the head of the queue until they get executed. The priority will
  1207.         be reset to the initial priority when a task is run.
  1208.  
  1209.         Since variable priority increases processing time in the critical
  1210.         region of the scheduler, it is not recommended for systems in
  1211.         which a larger number of tasks is expected to be eligible
  1212.         simultaneously.
  1213.  
  1214.         Usually, all tasks in a system should have the same priority,
  1215.         with only very few exceptions for non-critical background
  1216.         processing (low priority) or very time-critical tasks (high
  1217.         priority). High priority tasks should be written in such a way
  1218.         that they either reduce their priority when processing is
  1219.         completed, or that they wait for an event. Busy waiting in a high
  1220.         priority task will severely impair system operation with variable
  1221.         priority enabled, and will stop the system until the task is
  1222.         placed in a waiting state with fixed priority.
  1223.  
  1224.         The (automatically created) main task is started with the highest
  1225.         possible priority below the timer task, so that it can process
  1226.         all initialisations before other tasks start running. To allow
  1227.         the system to operate, the priority of the main task must be
  1228.         reduced, or the main task must wait for an event or a timeout.
  1229.  
  1230.  
  1231.  
  1232.  
  1233.  
  1234.  
  1235.  
  1236.  
  1237.  
  1238.  
  1239.  
  1240.  
  1241.  
  1242.  
  1243.  
  1244.  
  1245.  
  1246.  
  1247.  
  1248.         
  1249.         
  1250.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 19
  1251.  
  1252.  
  1253.                                Multitasking and DOS
  1254.  
  1255.  
  1256.         CTask includes (and automatically installs) a routine which traps
  1257.         all DOS calls, and makes sure that no two tasks simultaneously
  1258.         enter DOS. This is accomplished using the resource mechanism,
  1259.         with special provisions for the limited multitasking capabilities
  1260.         provided by DOS. There are a few calls, namely those with
  1261.         function codes <= 0x0c, which allow functions with codes > 0x0c
  1262.         to be executed while DOS is waiting for an external device
  1263.         (generally the keyboard) to get ready.
  1264.  
  1265.         This, however, limits the use of some C library functions, namely
  1266.         scanf and fread, for console input. Both these functions use
  1267.         handle input, and thus can not be interrupted. When writing
  1268.         routines for handling user input, keyboard read functions should
  1269.         either use the low-level calls getch and gets, or, better yet,
  1270.         the direct entries into the keyboard handler, t_read_key and
  1271.         t_keyhit, and then process the string with sscanf if desired.
  1272.  
  1273.         The keyboard handler (contained in tskkbd.asm) traps all keyboard
  1274.         interrupts, setting a flag when a key is hit. If a task reads
  1275.         from the keyboard, it is automatically made waiting if there is
  1276.         no key to read. Using getch and gets is less desirable since they
  1277.         use polling instead of event waiting, and thus degrade system
  1278.         performance. Also, the t_read_key and t_keyhit functions do not
  1279.         use DOS, so DOS functions <= 0C can be executed concurrently.
  1280.  
  1281.         The BIOS interrupts 10 (Video), 13 (Disk), and 16 (Keyboard) are
  1282.         protected by CTask. Using other BIOS interrupts directly should
  1283.         generally be avoided, unless you are absolutely sure they will
  1284.         not be used by other routines via DOS, or you provide your own
  1285.         critical region handling. Protection of INT 10 is optional, and
  1286.         should only be used if you expect to use BIOS level video output
  1287.         in parallel to other tasks. Since INT 10 calls occur extremely
  1288.         frequent in most programs, the overhead for reserving and
  1289.         releasing the resource can slow down the system noticeably.
  1290.  
  1291.         Starting with version 1.2, the DOS handling has been extended to
  1292.         automatically save and restore the DOS variable context on a task
  1293.         switch. This is done by directly saving the critical variables of
  1294.         the DOS data area in the task control block. An undocumented DOS
  1295.         call is used to determine location and length of this area. NOTE
  1296.         that this call is not available in DOS versions prior to 3.1, and
  1297.         may not be available in MS-DOS clones or emulators. This context
  1298.         save allows multiple DOS applications to run concurrently.
  1299.  
  1300.         The DOS access module has been tested to work with PC-DOS and MS-
  1301.         DOS versions 3.20, 3.30, 4.00, and 4.01. There were also no
  1302.         problems with the DOS PRINT program running in the background.
  1303.         Special provisions are built into the DOS module to detect
  1304.         background DOS calls. Using Sidekick also hasn't lead to any
  1305.         problems, although you may trash Sidekick's screen display by
  1306.         
  1307.         
  1308.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 20
  1309.  
  1310.  
  1311.         writing to the screen while Sidekick is active (note that your
  1312.         application *continues* to run while Sidekick or other pop-ups
  1313.         are active). I can not guarantee complete compatibility with all
  1314.         background and pop-up programs under all versions of DOS.
  1315.         Specifically, DOS versions prior to 3.1 have significant problems
  1316.         with multitasking, and do not support the variable save call
  1317.         necessary for full DOS multitasking. Upgrading to a newer DOS
  1318.         version is recommended if you are still using DOS < 3.2 (DOS 3.1
  1319.         has some bugs in other areas).
  1320.  
  1321.         Also starting with version 1.2, CTask is now compatible with MS-
  1322.         Windows. It has been tested to work with Windows 286 1.2 and 2.1,
  1323.         but the mechanism used should work with other non-preemptive
  1324.         versions, too.  CTask can be installed as a background TSR before
  1325.         starting Windows, or you may spawn Windows from CTask.
  1326.         Windows/386 is a special virtual-mode operating system and can
  1327.         generally not be combined with other multitaskers.
  1328.  
  1329.         Preemptive multitaskers like DesqView will most likely not
  1330.         coexist peacefully with CTask.
  1331.  
  1332.         Critical errors and Control C occurring while concurrent DOS
  1333.         access takes place may be fatal. Using the ctrlbrk() and
  1334.         harderr() functions of Turbo C, or their equivalents in MS C, to
  1335.         trap critical errors and Control C is highly recommended. Error
  1336.         handlers should be installed before CTask is installed.
  1337.  
  1338.  
  1339.                              Spawning and CTask TSR's
  1340.  
  1341.         Starting with Version 1.2, CTask programs can now spawn other
  1342.         programs, and Terminate and Stay Resident (TSR). The DOS context
  1343.         switch, plus the saving and restoring of interrupts 21-24, on
  1344.         every task switch, makes it possible to have multiple, nearly
  1345.         completely independent, programs running under DOS. But please
  1346.         note that CTask is not intended as a replacement for true DOS-
  1347.         multitaskers like DesqView. Implementation of such a system would
  1348.         surely be possible, using CTask as a base, but would require
  1349.         keeping track of all DOS control blocks. This is left as an
  1350.         exercise to the reader. The new features are intended to allow
  1351.         you to easily write background data aquisition or communication
  1352.         modules that run in parallel to other DOS applications.
  1353.  
  1354.         Since the spawned program might itself be a CTask program,
  1355.         Version 1.2 automatically checks for the presence of a background
  1356.         copy of CTask. If one is found, the secondary invocation will
  1357.         link to the global data of the first CTask copy, making it
  1358.         possible to easily communicate between independent instances of
  1359.         CTask programs. The naming mechanism has been slightly changed to
  1360.         make it easier to find a task or data structure by name.
  1361.  
  1362.         For example, you could write a communications program in two
  1363.         separate parts. One part, the resident part, contains interrupt
  1364.         
  1365.         
  1366.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 21
  1367.  
  1368.  
  1369.         handlers and the protocol routines. The other part, the transient
  1370.         portion, contains the driving program, with editor, menus, script
  1371.         language and so on.  If the resident part is started, it first
  1372.         spawns the transient part, which handles setup, and starts
  1373.         communications. Both parts can communicate using all CTask
  1374.         mechanisms, i.e. pipes, buffers, mailboxes etc., with the
  1375.         transient part obtaining the pointers to the CTask structures
  1376.         defined in the resident part via the structure name. Now if an
  1377.         up- or download is started, the transient part can exit to DOS,
  1378.         and the resident part can spawn a copy of command.com. Voila -
  1379.         background up/download with minimum hassle.
  1380.  
  1381.  
  1382.                                    Task Groups
  1383.  
  1384.         Each invocation of the CTask kernel (i.e. each call of the
  1385.         install_tasker routine) creates a new "Task Group". This group
  1386.         chains all tasks and other control structures created by this
  1387.         program together, so they can be killed if the group terminates
  1388.         (through a DOS call or the remove_tasker routine). Although it is
  1389.         recommended to kill all structures before terminating, there are
  1390.         a number of situations where this is hard to control under DOS.
  1391.         So CTask tries to take a few safety measures to make sure the
  1392.         system does not crash due to pointers chaining into nowhere.
  1393.  
  1394.         But please note that care should be taken not to "pull the rug
  1395.         under a group's feet". CTask will attempt to clean up memory when
  1396.         a group terminates. However, if that group has spawned another
  1397.         non-CTask program, CTask doesn't know about it, so an orphan will
  1398.         be left in memory, and you might even manage to get the system
  1399.         into an unstable state.
  1400.  
  1401.         And, there are a few restrictions. Although it is possible to
  1402.         create multiple groups running, and terminating, independently in
  1403.         parallel, those groups must be created by separate tasks from one
  1404.         "home group". If one task creates a group, and the same task, or
  1405.         another task from this group, creates a second, then it is not
  1406.         possible to terminate the first group without also killing the
  1407.         second. You can view this like a tree, where you can cut off
  1408.         branches, but all sub-branches of that branch will come down with
  1409.         it.  The root of that tree, the primary invocation of CTask, can
  1410.         not be killed without killing the whole tree.
  1411.  
  1412.         Also, it is mandatory that you at least try to call remove_tasker
  1413.         on termination. CTask can trap a program's termination, but this
  1414.         happens at a time when all the program's memory has already been
  1415.         released by DOS. This can lead to extremely dangerous situations
  1416.         if other tasks, or TSR's, allocate and modify this memory before
  1417.         CTask finishes it's cleanup. CTask will stop preemption while it
  1418.         is removing the group, but it still is definitely not recommended
  1419.         to rely on this mechanism.
  1420.  
  1421.  
  1422.         
  1423.         
  1424.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 22
  1425.  
  1426.  
  1427.         A sample for a task group structure follows:
  1428.  
  1429.                                -Root-
  1430.                                 home
  1431.                                 level
  1432.                                 branch -----+
  1433.                                  ^ ^        |
  1434.                                  | |        |
  1435.                                  | |        v
  1436.                    -Group1-      | |     -Group2-
  1437.                     home   ------+ +----- home
  1438.                     level  <------------- level
  1439.                     branch -----+         branch
  1440.                      ^ ^        |
  1441.                      | |        |
  1442.                      | |        v
  1443.         -GroupA-     | |     -GroupB-
  1444.          home   -----+ +----- home
  1445.          level  <------------ level
  1446.          branch               branch
  1447.  
  1448.  
  1449.         In this sample, Groups 1 and 2 were created by different tasks in
  1450.         the Root group, Groups A and B by different tasks in Group 1.
  1451.  
  1452.         Three pointers are used in chaining groups. The 'branch' points
  1453.         to the first element in an unordered list of task groups on the
  1454.         same "branch level" one level "up" the tree. Those groups are
  1455.         chained by the 'level' pointer. To allow finding the home group
  1456.         when going "down" the tree (towards the root), all groups on the
  1457.         same level point there through the 'home' pointer. In this
  1458.         sample, you could kill Group2 without affecting Group1 or it's
  1459.         subgroups. Killing Group1 will terminate GroupA and GroupB.
  1460.  
  1461.  
  1462.  
  1463.  
  1464.  
  1465.  
  1466.  
  1467.  
  1468.  
  1469.  
  1470.  
  1471.  
  1472.  
  1473.  
  1474.  
  1475.  
  1476.  
  1477.  
  1478.  
  1479.  
  1480.         
  1481.         
  1482.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 23
  1483.  
  1484.  
  1485.                                How does CTask work
  1486.  
  1487.                                       Queues
  1488.  
  1489.         CTask uses priority queues for most of its functions. A priority
  1490.         queue differs from the usual FIFO (first in, first out) queues in
  1491.         the insertion of elements into the queue. Rather than just
  1492.         placing new elements after the last queue member, the priority of
  1493.         the task determines its place in the queue. A task is enqueued
  1494.         after all queue members with higher or equal priority, but before
  1495.         any member with lower priority. Removal from the queue takes
  1496.         place at the first element. These queues are used with all
  1497.         operations in which a task is made waiting, be it waiting to get
  1498.         run, or waiting for an event. The advantage of this is the
  1499.         simplicity of implementing priorities. Other schemes might rely
  1500.         on arrays of queues, or searching through lists, to determine the
  1501.         highest priority waiting task. With priority queues, the most
  1502.         time critical function, scheduling, is very fast, since it can
  1503.         simply take the first task from the queue of eligible functions.
  1504.         The disadvantage is the time required to step through all greater
  1505.         or equal priority members of a queue to find the right place to
  1506.         insert the task. But since the number of tasks simultaneously
  1507.         enqueued in the same queue is normally relatively small with most
  1508.         multitasking systems, this disadvantage is more than offset by
  1509.         the simple, and thus easy to implement efficiently, scheme.
  1510.  
  1511.         Version 2.0 generalizes the queueing scheme, and uses doubly
  1512.         linked lists for all internal chains (except the ticker chain).
  1513.         The introduction of the "yield" function, which inserts a task at
  1514.         the end of the eligible queue, but resets the priority, mandated
  1515.         searching through the queue from the back end. The previous
  1516.         scheme, which walked the queue from the front end, could lead to
  1517.         task starvation in a system with polling tasks when yielding.
  1518.         Also, the timer algorithm was changed such that the timer task
  1519.         didn't have to step through all timeout elements, but rather to
  1520.         only decrement the first queue element ticker. This is
  1521.         implemented by storing the timeout as a tick difference to the
  1522.         next queue element rather than as an absolute value. Doubly
  1523.         linked lists make insertion and removal of elements at arbitrary
  1524.         points very simple, and eliminate the time needed to find an
  1525.         element in a queue.
  1526.  
  1527.         To alleviate the additional overhead associated with managing
  1528.         dual pointers, the main queueing routines were coded in
  1529.         assembler. Especially when operating with multiple far pointers,
  1530.         the code generated by the C compilers even with maximum
  1531.         optimization is not that impressive. The corresponding C code is
  1532.         included as a reference, and to aid porting.
  1533.  
  1534.  
  1535.  
  1536.  
  1537.  
  1538.         
  1539.         
  1540.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 24
  1541.  
  1542.  
  1543.                                   The Scheduler
  1544.  
  1545.         In a CTask system, there is at least one essential queue: the
  1546.         eligible queue, which contains all tasks waiting to run. Each
  1547.         time the scheduler is invoked, it will first save all processor
  1548.         registers in the current task control block, and then enqueue the
  1549.         current task into the appropriate queue.  Normally, this will be
  1550.         the eligible queue. Then the first element in the eligible queue
  1551.         is removed from the queue, the stack is switched to the stack of
  1552.         this task, and processor registers are restored from the new TCB,
  1553.         returning to the point where the new task was interrupted. If the
  1554.         eligible queue is empty the scheduler will loop with interrupts
  1555.         enabled. The queue head pointer of the task control block of the
  1556.         current running task determines what will happen to the task when
  1557.         the scheduler is invoked. If it points to an event control block,
  1558.         the task will be enqueued as waiting for this event. If it is
  1559.         NULL, the task will not be enqueued in any queue, effectively
  1560.         stopping it. If it points to the eligible queue, the task will be
  1561.         enqueued there. In any case, the scheduler does not care what
  1562.         queue the task is to be enqueued in, since all queues use the
  1563.         same priority based ordering. If a task is no longer in the
  1564.         eligible queue, it can only be returned to this queue by an
  1565.         external event.
  1566.  
  1567.  
  1568.                                      Events
  1569.  
  1570.         External events can take several forms, which are relatively
  1571.         similar on the inside. All CTask events use a control block, with
  1572.         at least one queue for tasks waiting for the event. Although it
  1573.         would have been possible to summarize all events under a global
  1574.         structure, this approach was not used in CTask, the main reasons
  1575.         being execution speed and ease of use. So if you scan through the
  1576.         source files for CTask events, you will see many very similar
  1577.         routines, which only differ in the types of data and the names of
  1578.         queues they process. In a class based language like C++, one
  1579.         would certainly define all events as instances or derivations of
  1580.         one class. In plain C, the necessary type casting, and the
  1581.         different handling of certain cases, would clobber the code to
  1582.         the point of illegibility.
  1583.  
  1584.  
  1585.                                     Resources
  1586.  
  1587.         The event types "resource", "flag", and "counter" differ only in
  1588.         the kind of wait operations and the handling of the state
  1589.         variable. The resource is mainly for use in interlocking critical
  1590.         regions of code, to protect access to non-reentrant resources.
  1591.         Only one task can "own" a resource, all other tasks requesting
  1592.         the resource are delayed until the owning task releases it. For
  1593.         added protection, CTask stores the task control block address of
  1594.         the current owner of the resource in the resource control block,
  1595.         so no other task can erroneously release it.
  1596.         
  1597.         
  1598.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 25
  1599.  
  1600.  
  1601.                                       Flags
  1602.  
  1603.         Flags, on the other hand, can be set and cleared by any task, and
  1604.         also by interrupt handlers. Tasks can wait on either state of the
  1605.         flag, and all tasks waiting for a state are simultaneously
  1606.         activated when the flag is changed to this state. This makes
  1607.         flags suitable for use as a global signalling mechanism.
  1608.  
  1609.  
  1610.                                      Counters
  1611.  
  1612.         Counters are a variation on the flag concept. A counter can be
  1613.         incremented and cleared by any task, and by interrupt handlers.
  1614.         Tasks can wait for a counter to be zero or nonzero. Like flags,
  1615.         all tasks waiting for the zero state are activated
  1616.         simultaneously. But unlike flags, only the first task waiting for
  1617.         the nonzero state of a counter will be activated on incrementing
  1618.         the counter, and the counter will be automatically decremented by
  1619.         one. The counter is used inside CTask to handle timer interrupts.
  1620.         The timer counter will be incremented on each timer tick,
  1621.         activating the timer task. If for any reason the timer task is
  1622.         unable to complete its run until the next tick, this tick will
  1623.         not be lost, since the counter is incremented, and the timer task
  1624.         will continue to run the next time it calls the counter wait
  1625.         request.
  1626.  
  1627.  
  1628.                                Mailboxes and Pipes
  1629.  
  1630.         The "mailbox" and "pipe" events can be used for inter-task
  1631.         communication, and for the communication between interrupt
  1632.         handlers and tasks.
  1633.  
  1634.         Mailboxes can hold an unlimited number of mail blocks. Mail
  1635.         blocks have no fixed structure, but the first doubleword in each
  1636.         block passed to a mailbox routine is used as a chain pointer.
  1637.         Mail blocks are chained into a mailbox in FIFO order. Tasks can
  1638.         wait for mail to arrive, or can conditionally read mail if a
  1639.         block is available. Tasks and interrupt handlers can write blocks
  1640.         to a mailbox. Since mailboxes don't need any copying of data,
  1641.         they are suited for high speed exchange of larger amounts of data
  1642.         between tasks. The disadvantage of sending mail this way is that
  1643.         you have to make sure that a mail block is not re-used before it
  1644.         has been read out of the box and processed by the receiving task.
  1645.         When exchanging fixed length messages, you can build a free mail
  1646.         block chain by using a mailbox to hold the available blocks.
  1647.  
  1648.         Buffered message exchange is possible using pipes. When creating
  1649.         a pipe, you specify a buffer area and its length, and the pipe
  1650.         routines will buffer all data written to the pipe in this area.
  1651.         This implies that writing to a pipe may cause a task to be
  1652.         delayed until there is space available in the pipe. To allow
  1653.         interrupt handlers to write to pipes, there is a conditional
  1654.         
  1655.         
  1656.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 26
  1657.  
  1658.  
  1659.         write request, which will simply return if the pipe is full.
  1660.         Tasks can wait for data to arrive in a pipe, and for the pipe to
  1661.         be emptied. A conditional read request is also provided. The
  1662.         disadvantage of pipes is that they are slightly slower than
  1663.         mailboxes due to the necessary copying, and that you can only
  1664.         place word or byte sized items in a pipe. When there is more than
  1665.         one reader or writer task, you can not rely on the bytes in a
  1666.         pipe being in any specific order. A "buffer" construct is
  1667.         provided in CTask that expands pipes to allow arbitrary length
  1668.         messages to be written and read. This is implemented using a
  1669.         resource for reading and writing to the pipe associated with the
  1670.         buffer, so the message is always guaranteed to be written and
  1671.         read in one piece. But since resources can not be used in
  1672.         interrupt handlers, using such buffers is not allowed from
  1673.         interrupts.
  1674.  
  1675.  
  1676.                             Serial and Printer Drivers
  1677.  
  1678.         There are a number of routines included in the CTask package for
  1679.         PC-specific tasks. Although they will be of limited use for
  1680.         embed-ded applications, studying the serial I/O and printer
  1681.         interface routines will give you some hints on how to use the
  1682.         CTask kernel for implementing your own device drivers. For PC
  1683.         based appli-cations, the routines should be usable with no or
  1684.         little changes for implementing complete communications packages.
  1685.  
  1686.         The serial I/O handler uses interrupts for both input and output
  1687.         of data, and supports both XON/XOFF and RTS/CTS handshake
  1688.         methods. The modem inputs can selectively be enabled to control
  1689.         data transmission. Pipes are used for transmit and receive data,
  1690.         with the buffer and its size specified on initialization. Both
  1691.         COM1 and COM2 can be active simultaneously, and other ports can
  1692.         be supported by editing a table in the source code or defining
  1693.         ports on-line. Since CTask allows the access to all events in
  1694.         interrupt handlers, writing interrupt based I/O drivers is
  1695.         relatively simple.  On receiving a character, the character and
  1696.         any associated errors are placed in the receive pipe, and the
  1697.         transmit pipe is read on transmit ready interrupt. Note that
  1698.         conditional reads and writes have to be used in the interrupt
  1699.         handler, since you can't safely delay an interrupt handler.
  1700.  
  1701.         The printer output driver supports both polling and interrupt
  1702.         output. Again, a pipe is used for the output characters.
  1703.         However, since polling is supported, and because of the somewhat
  1704.         unreliable interrupt structure of the printer ports, a driver
  1705.         task is required. This task is automatically created on
  1706.         installing the driver. The task first waits on the pipe for a
  1707.         character to be written to the printer.  When polling is enabled,
  1708.         it tries to output the character directly, using a short busy-
  1709.         waiting loop. So as not to load the system too heavily by the
  1710.         polling, the task will yield if it can't output the character
  1711.         after a small number of loops. When interrupts are enabled, the
  1712.         
  1713.         
  1714.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 27
  1715.  
  1716.  
  1717.         process is essentially the same at the start, but after the
  1718.         character is written to the port, the task will wait on a flag to
  1719.         be set. The interrupt handler will set the flag on interrupt,
  1720.         enabling the task to get the next character from the pipe. Since
  1721.         interrupts are unreliable with most printers due to the usually
  1722.         very short pulses on the acknowledge line, the task uses a
  1723.         timeout on the flag wait, so it does not hang if an interrupt is
  1724.         missed. Studying the printer driver will also give you an idea
  1725.         what the optional parameter on task creation can be used for. In
  1726.         the printer driver, this parameter is used to pass the address of
  1727.         the printer control block, which contains the pipe, the flag, and
  1728.         the hardware info, to the task. This allows the printer driver to
  1729.         be simultaneously installed for any number of printers without
  1730.         having to write separate printer tasks.
  1731.  
  1732.  
  1733.  
  1734.  
  1735.  
  1736.  
  1737.  
  1738.  
  1739.  
  1740.  
  1741.  
  1742.  
  1743.  
  1744.  
  1745.  
  1746.  
  1747.  
  1748.  
  1749.  
  1750.  
  1751.  
  1752.  
  1753.  
  1754.  
  1755.  
  1756.  
  1757.  
  1758.  
  1759.  
  1760.  
  1761.  
  1762.  
  1763.  
  1764.  
  1765.  
  1766.  
  1767.  
  1768.  
  1769.  
  1770.         
  1771.         
  1772.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 28
  1773.  
  1774.  
  1775.                                  CTask Data Types
  1776.  
  1777.  
  1778.         Note that you do not have to know the innards of the structures.
  1779.         All structure fields are filled by the "create_xxx" routines and
  1780.         modified by the CTask functions. You should NEVER modify a field
  1781.         in one of the structures directly. The structures are explained
  1782.         here shortly only for those wanting to modify the routines.
  1783.  
  1784.         NOTE: When modifying CTask structures, take care to modify the
  1785.         equivalent definitions in the assembler include file "tsk.mac".
  1786.         Some of the assembler routines have to use field offsets into
  1787.         pointers, so having different offsets in C and assembler will
  1788.         crash the system.
  1789.  
  1790.  
  1791.         If you only want to use the routines, you should simply include
  1792.         the file "tsk.h" in your source, and define variables of the
  1793.         types
  1794.  
  1795.              tcb         - for task control blocks
  1796.              tcbptr      - for far pointers to tcbs
  1797.  
  1798.              flag        - for flag events
  1799.              flagptr     - for far pointers to flags
  1800.  
  1801.              resource    - for resource events
  1802.              resourceptr - for far pointers to resources
  1803.  
  1804.              counter     - for counter events
  1805.              counterptr  - for far pointers to counters
  1806.  
  1807.              mailbox     - for mailbox events
  1808.              mailboxptr  - for far pointers to mailboxes
  1809.  
  1810.              pipe        - for pipe events
  1811.              pipeptr     - for far pointers to pipes
  1812.  
  1813.              wpipe       - for word pipe events
  1814.              wpipeptr    - for far pointers to word pipes
  1815.  
  1816.              buffer      - for buffer events
  1817.              bufferptr   - for far pointers to buffers
  1818.  
  1819.              tlink       - for timeout and watch control blocks
  1820.              tlinkptr    - for far pointers to timeout control blocks
  1821.  
  1822.              namerec     - for control block names
  1823.              nameptr     - for name pointers
  1824.  
  1825.         without caring what's behind them.
  1826.  
  1827.  
  1828.         
  1829.         
  1830.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 29
  1831.  
  1832.  
  1833.         Additionally, you may use the types
  1834.  
  1835.              byte        - for unsigned characters
  1836.              word        - for unsigned short integers
  1837.              dword       - for unsigned long integers
  1838.  
  1839.              funcptr     - for pointers to task functions
  1840.              farptr      - for far pointers to anything
  1841.              byteptr     - for far pointers to byte arrays
  1842.              wordptr     - for far pointers to word arrays
  1843.  
  1844.         in defining or typecasting items to be passed as parameters to
  1845.         CTask functions.
  1846.  
  1847.  
  1848.                  Typedefs used for simplified type specifications
  1849.  
  1850.              typedef unsigned char byte;
  1851.              typedef unsigned short word;
  1852.              typedef unsigned long dword;
  1853.              typedef void (cdecl far *funcptr)();
  1854.              typedef void far *farptr;
  1855.              typedef byte far *byteptr;
  1856.              typedef word far *wordptr;
  1857.  
  1858.  
  1859.  
  1860.                    Error return values for event wait functions
  1861.  
  1862.  
  1863.              #define TTIMEOUT ((farptr) -1L)
  1864.              #define TIMEOUT  (-1)
  1865.  
  1866.                   -1 is returned if a timeout occurred while waiting for
  1867.                   an event.
  1868.  
  1869.              #define TWAKE    ((farptr) -2L)
  1870.              #define WAKE     (-2)
  1871.  
  1872.                   -2 is returned if the task was waked up while waiting
  1873.                   for an event.
  1874.  
  1875.              #define TWATCH    ((farptr) -3L)
  1876.              #define WATCH     (-3)
  1877.  
  1878.                   -3 is returned if the task was waked up during a wait
  1879.                   by a watchpoint action.
  1880.  
  1881.  
  1882.  
  1883.  
  1884.  
  1885.  
  1886.         
  1887.         
  1888.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 30
  1889.  
  1890.  
  1891.                                       Queues
  1892.  
  1893.         The 'queue' structure is a dual link for linking task control
  1894.         blocks and timer blocks. The first three fields are used both for
  1895.         the queue head, and for elements to be inserted in a queue.
  1896.  
  1897.         CAUTION: Do not change the order of the first three fields in
  1898.         either queue or queue_head! Those two structures are used
  1899.         interchangeably in various places in the CTask kernel. Changing
  1900.         one of them would have catastrophic results.
  1901.  
  1902.         The queue element ("queue") contains the forward and backward
  1903.         pointer, a structure kind field, plus the priority (when used in
  1904.         a TCB) or the timeout value (when used in a tlink structure). The
  1905.         kind field is used to identify the type of structure the queue
  1906.         element is a part of, and also to identify the "end" of the
  1907.         queue. To simplify insertion and removal, all queues are circular
  1908.         in nature, i.e. there is no NULL-pointer at the head or tail. The
  1909.         queue head, and thus the end of a queue, is identified by a zero
  1910.         kind field.
  1911.  
  1912.              typedef struct {
  1913.                              word     prior;
  1914.                              word     ini_prior;
  1915.                             } qelem_pri;
  1916.  
  1917.              typedef struct queue_rec far *queptr;
  1918.  
  1919.              typedef struct queue_rec {
  1920.                                        queptr   volatile next;
  1921.                                        queptr   volatile prev;
  1922.                                        byte     kind;
  1923.                                        union  {
  1924.                                               qelem_pri   pri;
  1925.                                               dword       ticks;
  1926.                                               } el;
  1927.                                        } queue;
  1928.  
  1929.         The queue head ("queue_head") also contains the forward and
  1930.         backward pointer, and the structure kind field. The kind field is
  1931.         0 in true queue heads. The same structure is also used to chain
  1932.         name blocks, since those do not need the priority/tick field
  1933.         present in normal queue elements.
  1934.  
  1935.              typedef struct {
  1936.                              queptr   volatile first;
  1937.                              queptr   volatile last;
  1938.                              byte     kind;
  1939.                             } queue_head;
  1940.  
  1941.              typedef queue_head far *queheadptr;
  1942.  
  1943.  
  1944.         
  1945.         
  1946.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 31
  1947.  
  1948.  
  1949.                           The timer/watch control block
  1950.  
  1951.         The timer control block is included in every task control block.
  1952.         It may also be created as a separate entity to specify special
  1953.         actions to be executed after or every n timer ticks. It may also
  1954.         be used to specify memory or port locations to be watched for a
  1955.         change or a certain value on every timer tick.
  1956.  
  1957.         The "link" field links the active structures into the timer
  1958.         queue.
  1959.  
  1960.         "strucp" points to the structure to be acted upon, "kind"
  1961.         specifies the kind of structure:
  1962.  
  1963.              #define  TKIND_TASK        1
  1964.  
  1965.                   Strucp points to the task control block of which the
  1966.                   element is a member. The task will be awakened when the
  1967.                   timeout expires.
  1968.  
  1969.              #define  TKIND_WAKE        2
  1970.  
  1971.                   Strucp points to a task control block. Otherwise same
  1972.                   as TKIND_TASK.
  1973.  
  1974.              #define  TKIND_PROC        3
  1975.  
  1976.                   Strucp contains the address of a function to be called
  1977.                   on timeout.
  1978.  
  1979.              #define  TKIND_FLAG        4
  1980.  
  1981.                   Strucp points to a flag that should be set on timeout.
  1982.  
  1983.              #define  TKIND_COUNTER     5
  1984.  
  1985.                   Strucp points to a counter that should be increased on
  1986.                   timeout.
  1987.  
  1988.         The timeout structure is used for both timeouts and memory/port
  1989.         watchpoints. The union "elem" contains either the tick reload value,
  1990.         or the specs for the memory or port location to watch. "elkind"
  1991.         specifies the kind of structure used in the upper nibble:
  1992.  
  1993.              #define  TELEM_TIMER       0x10
  1994.  
  1995.                   This is a timeout element.
  1996.  
  1997.              #define  TELEM_MEM         0x20
  1998.  
  1999.                   This is a memory watch element.
  2000.  
  2001.  
  2002.         
  2003.         
  2004.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 32
  2005.  
  2006.  
  2007.              #define  TELEM_PORT        0x30
  2008.  
  2009.                   This is a port watch element.
  2010.  
  2011.         The lower nibble of "elkind" is used for watchpoints, it
  2012.         specifies the comparison operation:
  2013.  
  2014.              #define  TCMP_EQ           1
  2015.  
  2016.                   Activate watch if value read is equal to "compare".
  2017.  
  2018.              #define  TCMP_NE           2
  2019.  
  2020.                   Activate watch if value read is not equal to "compare".
  2021.  
  2022.              #define  TCMP_GE           3
  2023.  
  2024.                   Activate watch if value read is >= "compare"
  2025.                   (unsigned).
  2026.  
  2027.              #define  TCMP_LE           4
  2028.  
  2029.                   Activate watch if value read is <= "compare"
  2030.                   (unsigned).
  2031.  
  2032.              #define  TCMP_GES          5
  2033.  
  2034.                   Activate watch if value read is >= "compare" (signed).
  2035.  
  2036.              #define  TCMP_LES          6
  2037.  
  2038.                   Activate watch if value read is <= "compare" (signed).
  2039.  
  2040.              #define  TCMP_CHG          7
  2041.  
  2042.                   Activate watch if value read is not equal to "compare".
  2043.                   Additionally, store the value read into the "compare"
  2044.                   field. Only useful for continuous watchpoints.
  2045.  
  2046.  
  2047.         For timeouts, "elem.time" contains the "reload" value used for
  2048.         repetitive timeout actions to reload the original timeout value.
  2049.         The actual timeout value is part of the link structure.
  2050.  
  2051.         For port watches, "elem.port" contains the values "port", "mask",
  2052.         "compare" and "in_word". "port" holds the port number to read
  2053.         from.  The value read is masked with "mask", and compared with
  2054.         "compare". A word access is used if "in_word" is nonzero.
  2055.  
  2056.         Memory watches are similar to port watches, with "elem.mem"
  2057.         containing "address", the memory address to watch, and "mask" and
  2058.         "compare" as above.
  2059.  
  2060.         
  2061.         
  2062.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 33
  2063.  
  2064.  
  2065.         "tstate" contains the state of the element:
  2066.  
  2067.              #define  TSTAT_REMOVE      0xff
  2068.  
  2069.                   The element should be deleted.
  2070.  
  2071.              #define  TSTAT_IDLE        0
  2072.  
  2073.                   The element is not enqueued.
  2074.  
  2075.              #define  TSTAT_WATCH       1
  2076.  
  2077.                   The element is a watchpoint (port or memory).
  2078.                   It will be removed when the watch is activated.
  2079.  
  2080.              #define  TSTAT_CONTWATCH   2
  2081.  
  2082.                   The element is a watchpoint (port or memory).
  2083.                   It will not be removed on activation.
  2084.  
  2085.              #define  TSTAT_COUNTDOWN   3
  2086.  
  2087.                   The timeout counter is counted down. If the timeout is
  2088.                   reached, the element is removed from the queue.
  2089.  
  2090.              #define  TSTAT_REPEAT      4
  2091.  
  2092.                   The timeout counter is counted down. If the timeout is
  2093.                   reached, the timeout count is reloaded.
  2094.  
  2095.         The "flags" field holds two bits:
  2096.  
  2097.              #define  TFLAG_BUSY        0x01
  2098.  
  2099.                   If this bit is set, the timer task is busy processing
  2100.                   this element. It may not be deleted or enqueued.
  2101.  
  2102.              #define  TFLAG_TEMP        0x80
  2103.  
  2104.                   If this bit is set, this is a temporary element, which
  2105.                   will be deleted if the timeout is reached, or the watch
  2106.                   condition is met.
  2107.  
  2108.         The "user_parm" field may be used to pass pointers or other
  2109.         values to timeout functions. It is not modified by the CTask
  2110.         kernel routines.
  2111.  
  2112.  
  2113.  
  2114.  
  2115.  
  2116.  
  2117.  
  2118.         
  2119.         
  2120.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 34
  2121.  
  2122.  
  2123.              typedef struct tlink_rec far *tlinkptr;
  2124.  
  2125.              struct telem_memwatch {
  2126.                                    wordptr address;
  2127.                                    word    mask;
  2128.                                    word    compare;
  2129.                                    };
  2130.  
  2131.              struct telem_portwatch {
  2132.                                      word  port;
  2133.                                      word  mask;
  2134.                                      word  compare;
  2135.                                      byte  in_word;
  2136.                                     };
  2137.  
  2138.              struct telem_timeout {
  2139.                                    dword    reload;
  2140.                                   };
  2141.  
  2142.              struct tlink_rec {
  2143.                                queue    link;
  2144.                                farptr   strucp;
  2145.                                dword    user_parm;
  2146.                                union {
  2147.                                      struct telem_memwatch   mem;
  2148.                                      struct telem_portwatch  port;
  2149.                                      struct telem_timeout    time;
  2150.                                      }  elem;
  2151.                                byte     elkind;
  2152.                                byte     tstate;
  2153.                                byte     flags;
  2154.                               };
  2155.  
  2156.              typedef struct tlink_rec tlink;
  2157.  
  2158.  
  2159.  
  2160.  
  2161.  
  2162.  
  2163.  
  2164.  
  2165.  
  2166.  
  2167.  
  2168.  
  2169.  
  2170.  
  2171.  
  2172.  
  2173.  
  2174.  
  2175.  
  2176.         
  2177.         
  2178.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 35
  2179.  
  2180.  
  2181.                              The name link structure
  2182.  
  2183.         If TSK_NAMED is enabled, all structures except the timer control
  2184.         block contain a name link. All control blocks are linked and
  2185.         named via this element.
  2186.  
  2187.         "strucp" points to the head of the structure the name link is an
  2188.         element of, with "kind" in the list field specifying the type of
  2189.         structure:
  2190.  
  2191.              #define  TYP_TCB        1     task control block
  2192.              #define  TYP_FLAG       2     flag event
  2193.              #define  TYP_RESOURCE   3     resource event
  2194.              #define  TYP_COUNTER    4     counter event
  2195.              #define  TYP_MAILBOX    5     mailbox event
  2196.              #define  TYP_PIPE       6     byte pipe
  2197.              #define  TYP_WPIPE      7     word pipe
  2198.              #define  TYP_BUFFER     8     buffer
  2199.  
  2200.         The head element of the name list (normally the group control
  2201.         block) has its kind field set to zero.
  2202.  
  2203.         The "name" field contains an up to 8-character name plus a zero
  2204.         terminator.
  2205.  
  2206.              #define  NAMELENGTH     9
  2207.  
  2208.              typedef struct name_rec far *nameptr;
  2209.  
  2210.              struct name_rec {
  2211.                              queue_head list;
  2212.                              farptr     strucp;
  2213.                              char       name [NAMELENGTH];
  2214.                              };
  2215.  
  2216.              typedef struct name_rec namerec;
  2217.  
  2218.  
  2219.                          The task control block structure
  2220.  
  2221.  
  2222.         The "cqueue" field links the TCB into one of the queues. The
  2223.         "qhead" pointer points to the head of the queue the task is
  2224.         enqueued in, or will be enqueued in on the next schedule request
  2225.         in the case of the current running task.
  2226.  
  2227.         The "prior" field in the cqueue structure contains the tasks
  2228.         current priority, with 0xffff the highest possible priority, and
  2229.         0 the lowest. The "ini_prior" field initially contains the same
  2230.         value. If variable priority is enabled, "prior" is incremented on
  2231.         each scheduler call, and reset to "ini_prior" when the task is
  2232.         activated.
  2233.  
  2234.         
  2235.         
  2236.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 36
  2237.  
  2238.  
  2239.         "stack" contains the saved task stack pointer (offset and
  2240.         segment) if the task is not running. The field "stkbot" contains
  2241.         the bottom address of the task stack. It is set by create_task,
  2242.         but is currently not used anywhere else. Stack checking routines
  2243.         might use this value to test for stack overflow and/or stack
  2244.         usage. The "t_ax", "t_cx", ..., "t_ds" fields hold the register
  2245.         contents while a task is inactive.
  2246.  
  2247.         "state" and "flags" contain the tasks state and flags.
  2248.  
  2249.         "timerq" is a tlink structure used to chain the tcb into the
  2250.         timer queue if the task is waiting for a timeout, or into the
  2251.         watch queue if the task is waiting for a watch event. See above
  2252.         for a description of the tlink structure.
  2253.  
  2254.         The fields "retptr" and "retsize" are used in event handling.
  2255.         They are used when a task is waiting for an event by the task
  2256.         activating the event, and also by timeout and wake to indicate
  2257.         error returns. The use of these pointers eliminates the need to
  2258.         loop for an event, which requires slightly more code in the event
  2259.         handling routines, but reduces the need for task switching.
  2260.  
  2261.         The "save_func" and "rest_func" pointers can optionally point to
  2262.         task-switch save and restore functions. In special applications,
  2263.         it may be necessary to save and restore global variables or other
  2264.         items when a task is deactivated. The save function is called
  2265.         when a task is deactivated, the restore function when a task is
  2266.         activated. Both functions should be defined as
  2267.  
  2268.            void far funcname (tcbptr tcb);
  2269.  
  2270.         The functions are called with a pointer to the current TCB, DS
  2271.         and ES are set up to point to the task's current data segment.
  2272.         Please note that the data segment may be different from the
  2273.         default data segment if the task switch occurred while the task
  2274.         executed a DOS or BIOS function. Interrupts are disabled, and
  2275.         should not be re-enabled. The stack is the scheduler's local
  2276.         stack. Calling CTask-routines that might cause the scheduler to
  2277.         be activated should be avoided.
  2278.  
  2279.         The "user_ptr" field can hold any pointer or other value to be
  2280.         used by the save/restore functions or to point to task-related
  2281.         items. This field is not modified by the CTask routines.
  2282.  
  2283.         The "group" and "homegroup" pointers link a task with it's
  2284.         current task group, and with the base group that created the task
  2285.         if the task spawned a secondary invocation of CTask.
  2286.  
  2287.         The DOS-related fields "indos", "new", "base_psp", "psp_sssp",
  2288.         and "swap_area" are used to save critical information on the
  2289.         state of DOS. They should never be tampered with.
  2290.  
  2291.  
  2292.         
  2293.         
  2294.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 37
  2295.  
  2296.  
  2297.         The "name" namerec structure is present only if TSK_NAMED is
  2298.         enabled. It may be used in debugging (see tsksnap.c for an
  2299.         example), and in applications where the address of the structure
  2300.         can not be passed directly.
  2301.  
  2302.  
  2303.              typedef struct tcb_rec far *tcbptr;
  2304.  
  2305.            struct tcb_rec {
  2306.                            tcbptr   next;
  2307.                            tqueptr  queue;
  2308.                            byteptr  stack;
  2309.                            byteptr  stkbot;
  2310.                            word     prior;
  2311.                            word     initprior;
  2312.                            byte     state;
  2313.                            byte     flags;
  2314.                            dlink    timerq;
  2315.                            farptr   retptr;
  2316.                            int      retsize;
  2317.                           };
  2318.  
  2319.            typedef struct tcb_rec tcb;
  2320.  
  2321.  
  2322.  
  2323.                                    Task states
  2324.  
  2325.  
  2326.              #define  ST_KILLED   0
  2327.  
  2328.                   The task has been killed. Restarting the task is not
  2329.                   possible. Queue pointers are invalid.
  2330.  
  2331.              #define  ST_STOPPED  1
  2332.  
  2333.                   The task is not enqueued in any queue. To be in-cluded
  2334.                   in scheduling, it has to be explicitly started. The
  2335.                   queue head pointer is NULL.
  2336.  
  2337.              #define  ST_DELAYED  2
  2338.  
  2339.                   The task is enqueued in the timer queue only. When the
  2340.                   timer expires, it is placed in the eligible queue.  The
  2341.                   queue head pointer is NULL.
  2342.  
  2343.              #define  ST_WAITING  3
  2344.  
  2345.                   The task is waiting for an event to happen.  It can
  2346.                   also be chained into the timer queue if a timeout was
  2347.                   specified in the call.  The queue head pointer points
  2348.                   to the queue head in the event control block for the
  2349.                   event the process is waiting on.
  2350.         
  2351.         
  2352.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 38
  2353.  
  2354.  
  2355.              #define  ST_ELIGIBLE 4
  2356.  
  2357.                   The task is enqueued in the queue of processes eligible
  2358.                   for running. It can not be chained in the timer queue.
  2359.                   The queue head pointer points to the eligible queue.
  2360.  
  2361.              #define  ST_RUNNING  5
  2362.  
  2363.                   The task is the current running process. Although it is
  2364.                   not enqueued in any queue, the queue head pointer in
  2365.                   its control block is valid and points to the queue the
  2366.                   process will be enqueued in on the next schedule
  2367.                   request.
  2368.  
  2369.  
  2370.         Possible state transitions and their reasons:
  2371.  
  2372.            stopped  -> eligible    by start_task ()
  2373.  
  2374.            delayed  -> killed      by kill_task ()
  2375.                     -> eligible    by timer task, or wake_task ()
  2376.  
  2377.            eligible -> killed      by kill_task ()
  2378.                     -> running     by scheduler
  2379.  
  2380.            running  -> killed      by kill_task ()
  2381.                     -> stopped     by delay (0)
  2382.                     -> delayed     by delay (n != 0)
  2383.                     -> eligible    by scheduler
  2384.                     -> waiting     by wait_xxx ()
  2385.  
  2386.            waiting  -> killed      by kill_task ()
  2387.                     -> eligible    by event happening, timeout,
  2388.                                    or wake_task()
  2389.  
  2390.  
  2391.  
  2392.                                     Task flags
  2393.  
  2394.         System flags:
  2395.  
  2396.              #define  F_TEMP   0x80
  2397.  
  2398.                   This tcb was allocated automatically, and must be
  2399.                   free'd on task kill.
  2400.  
  2401.              #define  F_STTEMP 0x40
  2402.  
  2403.                   The tasks stack was allocated automatically, and must
  2404.                   be free'd on task kill.
  2405.  
  2406.  
  2407.  
  2408.         
  2409.         
  2410.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 39
  2411.  
  2412.  
  2413.         User changeable flags:
  2414.  
  2415.              #define  F_CRIT   0x01
  2416.  
  2417.                   This task may not be preempted. It will run until it
  2418.                   clears this flag, delays itself, calls the scheduler
  2419.                   explicitly, or waits for an event.
  2420.  
  2421.  
  2422.  
  2423.                              The Group Control Block
  2424.  
  2425.         Each invocation of CTask owns a group control block, gcb. This
  2426.         structure holds all information relevant to this invocation only,
  2427.         and chains all data structures created in this group.
  2428.  
  2429.         The "home", "level", and "branch" fields interconnect the groups
  2430.         (see the chapter on groups for more information).
  2431.  
  2432.         The "creator" field identifies the creating task.
  2433.  
  2434.         The "exit_addr", "create_psp", "save_psp", and "save_sssp" fields
  2435.         hold the information necessary to allow spawning CTask
  2436.         applications.
  2437.  
  2438.         The "namelist" field contains the name of the group itself, and
  2439.         links all structures created within this group.
  2440.  
  2441.  
  2442.              struct group_rec {
  2443.                                gcbptr    home;
  2444.                                gcbptr    level;
  2445.                                gcbptr    branch;
  2446.                                tcbptr    creator;
  2447.                                dword     exit_addr;
  2448.                                word      create_psp;
  2449.                                word      save_psp;
  2450.                                dword     save_sssp;
  2451.                                namerec   namelist;
  2452.                               };
  2453.  
  2454.  
  2455.  
  2456.                              The event control blocks
  2457.  
  2458.         All event control blocks have two optional fields:
  2459.  
  2460.         "name" is only present if TSK_NAMED is enabled. It is a namerec
  2461.         structure as explained above.
  2462.  
  2463.  
  2464.  
  2465.  
  2466.         
  2467.         
  2468.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 40
  2469.  
  2470.  
  2471.         "flags" is only present if TSK_DYNAMIC is enabled. It contains
  2472.  
  2473.              F_TEMP     If this control block was allocated
  2474.                         automatically, and must be free'd on delete.
  2475.  
  2476.              F_STTEMP   If the buffer for this event was allocated auto-
  2477.                         matically, and must be free'd on delete (pipes
  2478.                         and buffers only).
  2479.  
  2480.  
  2481.  
  2482.                                The Ticker structure
  2483.  
  2484.         The ticker is not an event structure in the true sense, since
  2485.         there are no operations that wait on a ticker. It is the only
  2486.         control structure linked by a single forward pointer. It contains
  2487.         this "next" pointer, a doubleword "ticks" count that is counted
  2488.         down towards zero on every hardware clock tick, and the optional
  2489.         "flags" field. It is permissible to access and modify the "ticks"
  2490.         field directly.
  2491.  
  2492.              typedef struct ticker_rec far *tick_ptr;
  2493.  
  2494.              typedef struct ticker_rec {
  2495.                                         tick_ptr next;
  2496.                                         dword    ticks;
  2497.                                         byte     flags; (if TSK_DYNAMIC)
  2498.                                         } ticker;
  2499.  
  2500.  
  2501.  
  2502.                              The Flag event structure
  2503.  
  2504.         Contains two queues for processes waiting on a flag state (clear
  2505.         or set), plus the flag state (0 = clear, 1 = set).
  2506.  
  2507.              typedef struct {
  2508.                              queue_head  wait_set;
  2509.                              queue_head  wait_clear;
  2510.                              int         state;
  2511.                              byte        flags;   (if TSK_DYNAMIC)
  2512.                              namerec     name;    (if TSK_NAMED)
  2513.                              } flag;
  2514.  
  2515.              typedef flag far *flagptr;
  2516.  
  2517.  
  2518.  
  2519.  
  2520.  
  2521.  
  2522.  
  2523.  
  2524.         
  2525.         
  2526.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 41
  2527.  
  2528.  
  2529.                            The counter event structure
  2530.  
  2531.         Similar to a flag, but contains a doubleword state counter.
  2532.  
  2533.              typedef struct {
  2534.                              queue_head  wait_set;
  2535.                              queue_head  wait_clear;
  2536.                              dword       state;
  2537.                              byte        flags;   (if TSK_DYNAMIC)
  2538.                              namerec     name;    (if TSK_NAMED)
  2539.                             } counter;
  2540.  
  2541.              typedef counter far *counterptr;
  2542.  
  2543.  
  2544.                            The resource event structure
  2545.  
  2546.         Contains a queue for the tasks waiting for access to the
  2547.         resource, a pointer to the current owner of the resource (to
  2548.         check for illegal "release_resource" and nested request calls),
  2549.         and the resource request counter (0 = free, <> 0 = in use).
  2550.  
  2551.              typedef struct {
  2552.                              queue_head   waiting;
  2553.                              queue_head   owner;
  2554.                              word         count;
  2555.                              byte         flags;   (if TSK_DYNAMIC)
  2556.                              namerec      name;    (if TSK_NAMED)
  2557.                             } resource;
  2558.  
  2559.              typedef resource far *resourceptr;
  2560.  
  2561.  
  2562.  
  2563.  
  2564.  
  2565.  
  2566.  
  2567.  
  2568.  
  2569.  
  2570.  
  2571.  
  2572.  
  2573.  
  2574.  
  2575.  
  2576.  
  2577.  
  2578.  
  2579.  
  2580.  
  2581.  
  2582.         
  2583.         
  2584.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 42
  2585.  
  2586.  
  2587.                            The mailbox event structure
  2588.  
  2589.         The msgptr type is only used internally to chain mail blocks into
  2590.         the mailbox. The mailbox type contains a queue of the tasks
  2591.         waiting for mail, and a first and last pointer for the chain of
  2592.         mail blocks.
  2593.  
  2594.              struct msg_header {
  2595.                                 struct msg_header far *next;
  2596.                                };
  2597.  
  2598.              typedef struct msg_header far *msgptr;
  2599.              typedef mailbox far *mailboxptr;
  2600.  
  2601.              typedef struct {
  2602.                              queue_head  waiting;
  2603.                              msgptr      mail_first;
  2604.                              msgptr      mail_last;
  2605.                              byte        flags;   (if TSK_DYNAMIC)
  2606.                              namerec     name;    (if TSK_NAMED)
  2607.                             } mailbox;
  2608.  
  2609.  
  2610.  
  2611.                       The pipe and word pipe event structure
  2612.  
  2613.         Contains queues of the tasks waiting to read or write to the
  2614.         pipe, indices for reading (outptr) and writing (inptr) into the
  2615.         buffer, the buffer size, the number of bytes or words currently
  2616.         in the pipe ("filled"), and the pointer to the buffer. A word
  2617.         pipe is handled exactly the same as a byte pipe, the only
  2618.         difference being the element size placed in the buffer. With
  2619.         normal pipes, characters are buffered, with word pipes, words.
  2620.  
  2621.              typedef struct {
  2622.                              queue_head  wait_read;
  2623.                              queue_head  wait_write;
  2624.                              queue_head  wait_clear;
  2625.                              word        bufsize;
  2626.                              word        filled;
  2627.                              word        inptr;
  2628.                              word        outptr;
  2629.                              byteptr     contents;
  2630.                              byte        flags;   (if TSK_DYNAMIC)
  2631.                              namerec     name;    (if TSK_NAMED)
  2632.                             } pipe;
  2633.  
  2634.              typedef pipe far *pipeptr;
  2635.  
  2636.  
  2637.  
  2638.  
  2639.  
  2640.         
  2641.         
  2642.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 43
  2643.  
  2644.  
  2645.              typedef struct {
  2646.                              queue_head  wait_read;
  2647.                              queue_head  wait_write;
  2648.                              queue_head  wait_clear;
  2649.                              word        bufsize;
  2650.                              word        filled;
  2651.                              word        inptr;
  2652.                              word        outptr;
  2653.                              wordptr     wcontents;
  2654.                              byte        flags;   (if TSK_DYNAMIC)
  2655.                              namerec     name;    (if TSK_NAMED)
  2656.                             } wpipe;
  2657.  
  2658.              typedef wpipe far *wpipeptr;
  2659.  
  2660.  
  2661.                             The buffer event structure
  2662.  
  2663.         Contains resources for read and write access, the word pipe used
  2664.         for buffering, and a message counter.
  2665.  
  2666.              typedef struct {
  2667.                               resource   buf_write;
  2668.                               resource   buf_read;
  2669.                               wpipe      pip;
  2670.                               word       msgcnt;
  2671.                               byte       flags;   (if TSK_DYNAMIC)
  2672.                               namerec    name;    (if TSK_NAMED)
  2673.                              } buffer;
  2674.  
  2675.              typedef buffer far *bufferptr;
  2676.  
  2677.  
  2678.  
  2679.  
  2680.  
  2681.  
  2682.  
  2683.  
  2684.  
  2685.  
  2686.  
  2687.  
  2688.  
  2689.  
  2690.  
  2691.  
  2692.  
  2693.  
  2694.  
  2695.  
  2696.  
  2697.  
  2698.         
  2699.         
  2700.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 44
  2701.  
  2702.  
  2703.                                   CTask Routines
  2704.  
  2705.  
  2706.                              Installation and Removal
  2707.  
  2708.         int install_tasker (int varpri, int speedup,
  2709.                             word flags, byteptr name);
  2710.  
  2711.  
  2712.              Installs the multitasker. Must be called prior to any other
  2713.              routine. The calling routine is defined as the main task,
  2714.              and assigned the highest priority.  To allow other tasks to
  2715.              execute, the main task must have its priority reduced, be
  2716.              delayed, or wait on an event.
  2717.  
  2718.              Returns 1 if CTask was already present in the system, i.e.
  2719.              this is a secondary invocation. Returns 0 if this is the
  2720.              first installation of CTask.
  2721.  
  2722.              "varpri"  Enables variable priority if nonzero.
  2723.  
  2724.              "speedup" is defined for the IBM PC/XT/AT as the clock tick
  2725.                        speedup factor. The timer tick frequency will be
  2726.                        set to 
  2727.  
  2728.                        speedup  ticks/sec   msecs/tick
  2729.                           0        18.2        54.9   (normal clock)
  2730.                           1        36.4        27.5
  2731.                           2        72.8        13.7
  2732.                           3       145.6         6.9
  2733.                           4       291.3         3.4
  2734.  
  2735.                        Note that all timeouts are specified in tick
  2736.                        units, so changing the speedup parameter will
  2737.                        influence timeouts and delays. You can enable
  2738.                        CLOCK_MSEC in tskconf.h to allow timeouts to be
  2739.                        specified in milliseconds. The system clock will
  2740.                        not be disturbed by changing the speed. Using
  2741.                        values above 2 can lead to interrupt overruns on
  2742.                        slower machines and is not recommended.
  2743.  
  2744.              "flags"   controls various installation flags through the
  2745.                        bitwise OR of the following flags defined in
  2746.                        TSK.H:
  2747.  
  2748.                IFL_VIDEO      Install INT 10 access resource if set. No
  2749.                            protection of Video interrupt if clear.
  2750.                            Installation of the Video resource is safer,
  2751.                            but may slow down the system noticeably. It is
  2752.                            not necessary if you don't do screen-I/O
  2753.                            through the BIOS from your CTask program.
  2754.  
  2755.  
  2756.         
  2757.         
  2758.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 45
  2759.  
  2760.  
  2761.                IFL_DISK        Install INT 13 access resource if set. No
  2762.                            protection of Disk interrupt if clear.
  2763.                            Installation of INT 13 is recommended for
  2764.                            better system safety. The resource will allow
  2765.                            parallel access to floppy and harddisk, but
  2766.                            might be incompatible with some special
  2767.                            programs (though none have yet been reported).
  2768.  
  2769.                IFL_INT8_DIR Call original INT 8 directly if set.
  2770.                            This changes the timing for the timer inter-
  2771.                            rupt. If this flag is clear, the original
  2772.                            timer interrupt is chained to through a task,
  2773.                            so it can be preempted. If it is set, the
  2774.                            original interrupt is chained to directly, at
  2775.                            the start of timer interrupt processing. This
  2776.                            avoids compatibility problems with certain
  2777.                            TSR's and Networks, but may impair CTask
  2778.                            operations while those TSR's are active.
  2779.  
  2780.                IFL_PRINTER  Install INT 17 handler if set.
  2781.                            Installation of the printer interrupt handler
  2782.                            avoids lengthy busy waiting on printer output,
  2783.                            but might be incompatible with certain printer
  2784.                            redirectors.
  2785.  
  2786.                IFL_INT15      Install IBM-AT INT 15 handler if set.
  2787.                            The IBM INT 15 handler allows avoiding some
  2788.                            busy waiting loops. It may, however, be
  2789.                            incompatible with some non-100% clones, and
  2790.                            with debuggers like Periscope IV. If you're
  2791.                            not sure, don't set this flag.
  2792.  
  2793.                IFL_NODOSVARS
  2794.                            Do not copy the internal DOS variable area if
  2795.                            set. This flag may be used for incompatible
  2796.                            versions of DOS or it's clones, but background
  2797.                            DOS access will not work if this flag is set.
  2798.                            Use only for known incompatible versions, and
  2799.                            only if you do not intend to TSR or Spawn.
  2800.  
  2801.              "name"     is the name of the created task group.
  2802.  
  2803.  
  2804.         void  remove_tasker (void);
  2805.  
  2806.              Uninstalls the multitasker. Must only be called from the
  2807.              main task, and should be called before exiting the program.
  2808.  
  2809.  
  2810.  
  2811.  
  2812.  
  2813.  
  2814.         
  2815.         
  2816.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 46
  2817.  
  2818.  
  2819.         int ctask_resident (void);
  2820.  
  2821.              This routine allows checking if another copy of CTask is
  2822.              already resident. It should be called before install_tasker
  2823.              is invoked.
  2824.  
  2825.              Returns 1 if CTask is resident, 0 otherwise. It always
  2826.              returns 1 after install_tasker has been called.
  2827.  
  2828.  
  2829.  
  2830.                                Searching for names
  2831.  
  2832.  
  2833.         farptr find_name (byteptr name, int kind);
  2834.  
  2835.              This routine searches for a task, group, or event structure
  2836.              from the current task's group downward to the base group.
  2837.  
  2838.              Returns a pointer to the structure, or a pointer to the name
  2839.              record within the structure (depending on kind) if the name
  2840.              was found, NULL otherwise.
  2841.  
  2842.              This routine may be called before "install_tasker" has been
  2843.              invoked to search names in resident copies.
  2844.  
  2845.              "name"     pointer to a zero-terminated, up to eight
  2846.                         character, name. Case is significant in names.
  2847.  
  2848.              "kind"     is the kind of structure to search for:
  2849.  
  2850.                         If -1, all structures are searched, and the first
  2851.                         structure with the given name is returned. In
  2852.                         this case, the returned pointer points to the
  2853.                         name record within the structure, to allow
  2854.                         identification of the structure. The "strucp"
  2855.                         pointer within that record points to the start of
  2856.                         the structure, the "kind" field in the link
  2857.                         structure identifies the type of the structure.
  2858.  
  2859.                         If kind is >= 0, the returned pointer is a
  2860.                         pointer to the start of the structure:
  2861.  
  2862.                           TYP_GROUP      - Search for Groups only
  2863.                           TYP_FLAG       - Search for Flags only
  2864.                           TYP_RESOURCE   - Search for Resources only
  2865.                           TYP_COUNTER    - Search for Counters only
  2866.                           TYP_MAILBOX    - Search for Mailboxes only
  2867.                           TYP_PIPE       - Search for Pipes only
  2868.                           TYP_WPIPE      - Search for Word Pipes only
  2869.                           TYP_BUFFER     - Search for Buffers only
  2870.  
  2871.  
  2872.         
  2873.         
  2874.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 47
  2875.  
  2876.  
  2877.         farptr find_group_name (gcbptr group, byteptr name, int kind);
  2878.  
  2879.              Looks for a name in the specified group only.
  2880.  
  2881.              Return value and parameters match those of find_group_name,
  2882.              except
  2883.  
  2884.              "group"    pointer to a group control block.
  2885.  
  2886.  
  2887.  
  2888.                                   Miscellaneous
  2889.  
  2890.  
  2891.         void  preempt_off (void);
  2892.  
  2893.              Disables task preemption. This is the default after instal-
  2894.              lation. With preemption turned off, only delays, event
  2895.              waits, and explicit scheduler calls will cause a task
  2896.              switch.
  2897.  
  2898.  
  2899.         void  preempt_on (void);
  2900.  
  2901.              Enables task preemption. Task switches will occur on timer
  2902.              ticks.
  2903.  
  2904.  
  2905.         void  schedule (void);
  2906.  
  2907.              Explicit scheduling request. The highest priority eligible
  2908.              task will be made running.
  2909.  
  2910.  
  2911.         void  c_schedule (void);
  2912.  
  2913.              Conditional scheduling request. Scheduling will take place
  2914.              only if preemption is allowed.
  2915.  
  2916.  
  2917.         void  yield (void);
  2918.  
  2919.              Explicit scheduling request, with task priority temporarily
  2920.              set to zero. If a task has to wait for some external event
  2921.              in a polling loop, this call may be used to allow tasks of
  2922.              lower priority to execute.
  2923.  
  2924.  
  2925.         void  tsk_dis_preempt (void)
  2926.  
  2927.              Temporarily disable task preemption. Preemption will be re-
  2928.              enabled by tsk_ena_preempt or an unconditional scheduler
  2929.              call.
  2930.         
  2931.         
  2932.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 48
  2933.  
  2934.  
  2935.         void  tsk_ena_preempt (void)
  2936.  
  2937.              Re-enable task preemption. Note that tsk_dis_preempt and
  2938.              tsk_ena_preempt do not change the global preemption state
  2939.              set by preempt_off and preempt_on.
  2940.  
  2941.  
  2942.         int tsk_dis_int (void)
  2943.  
  2944.              Disable interrupts. Returns the state of the interrupt flag
  2945.              prior to this call (1 if interrupts were enabled).
  2946.  
  2947.  
  2948.         void  tsk_ena_int (int state)
  2949.  
  2950.              Enables interrupts if "state" is nonzero. Normally used in
  2951.              conjunction with tsk_dis_int.
  2952.  
  2953.  
  2954.         The routines tsk_dis_int and tsk_ena_int may be used in a simpli-
  2955.         fied  scheme with the defines
  2956.  
  2957.              CRITICAL;      Declares "int crit_intsav;".
  2958.              C_ENTER;       Expands to "crit_intsav = tsk_dis_int ();"
  2959.              C_LEAVE;       Expands to "tsk_ena_int (crit_intsav);".
  2960.  
  2961.  
  2962.         void  tsk_cli (void)
  2963.  
  2964.              Disables interrupts (intrinsic function).
  2965.  
  2966.  
  2967.         void  tsk_sti (void)
  2968.  
  2969.              Unconditionally enables interrupts (intrinsic function).
  2970.  
  2971.  
  2972.         void  tsk_outp (int port, byte b)
  2973.  
  2974.              Outputs the value "b" to hardware-port "port" (intrinsic
  2975.              function).
  2976.  
  2977.         byte  tsk_inp (int port)
  2978.  
  2979.              Returns the value read from port "port" (intrinsic
  2980.              function).
  2981.  
  2982.  
  2983.  
  2984.  
  2985.  
  2986.  
  2987.  
  2988.         
  2989.         
  2990.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 49
  2991.  
  2992.  
  2993.         The following entry points may be used from assembler routines:
  2994.  
  2995.         extrn _tsk_scheduler: far
  2996.  
  2997.              Direct entry into the scheduler. The stack must be set up as
  2998.              for an interrupt handler, e.g.
  2999.  
  3000.                   pushf
  3001.                   cli
  3002.                   call  _tsk_scheduler
  3003.  
  3004.  
  3005.         extrn _sched_int: far
  3006.  
  3007.              Conditional scheduling call. The stack must be set up as for
  3008.              an interrupt handler.
  3009.  
  3010.  
  3011.  
  3012.                                  Task Operations
  3013.  
  3014.  
  3015.         tcbptr create_task (tcbptr task, funcptr func, byteptr stack,
  3016.                             word stksz, word prior, farptr arg
  3017.                             [, byteptr name]);
  3018.  
  3019.              Initialises a task. Must be called prior to any other opera-
  3020.              tions on this task. The task is in the stopped state after
  3021.              creation. It must be started to be able to run.
  3022.  
  3023.              Returns a pointer to the created tcb, or NULL on error.
  3024.  
  3025.              "task"     is a pointer to a tcb (NULL for automatic allo-
  3026.                         cation).
  3027.  
  3028.              "func"     is a pointer to a void far function, with a
  3029.                         single dword sized parameter.
  3030.  
  3031.              "stack"    is a pointer to a stack area for the task (NULL
  3032.                         for automatic allocation).
  3033.  
  3034.              "stksz"    is the size of the stack area in bytes.
  3035.  
  3036.              "prior"    is the tasks priority (0 lowest, 0xffff highest).
  3037.  
  3038.              "arg"      is an argument to the created task. It may be
  3039.                         used to differentiate between tasks when using
  3040.                         the same function in different tasks.
  3041.  
  3042.              "name"     is the name of the task, up to eight characters,
  3043.                         plus zero-terminator. This parameter is defined
  3044.                         only if TSK_NAMEPAR is enabled in tskconf.h.
  3045.  
  3046.         
  3047.         
  3048.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 50
  3049.  
  3050.  
  3051.         void  kill_task (tcbptr task);
  3052.  
  3053.              Kills a task. The task can no longer be used.
  3054.  
  3055.  
  3056.         int start_task (tcbptr task);
  3057.  
  3058.              Starts a task, i.e. makes it eligible for running.
  3059.  
  3060.              Returns 0 if task was started, -1 if the task was not
  3061.              stopped. A value of NULL for "task" will start the "main
  3062.              task".
  3063.  
  3064.  
  3065.         int stop_task (tcbptr task);
  3066.  
  3067.              Stops a task, i.e. removes it from all queues. A value of
  3068.              NULL for "task" will stop the "main task".
  3069.  
  3070.              Returns 0 on success.
  3071.  
  3072.  
  3073.         int wake_task (tcbptr task);
  3074.  
  3075.              Prematurely wakes a delayed or waiting task. If the task was
  3076.              waiting for an event, it will be removed from the waiting
  3077.              queue, with the operation terminating with an error return
  3078.              value.
  3079.  
  3080.              Returns 0 if task was waked, -1 if the task was not delayed
  3081.              or waiting. A value of NULL for "task" will wake the "main
  3082.              task".
  3083.  
  3084.  
  3085.         void  set_priority (tcbptr task, word prior)
  3086.  
  3087.              Sets the priority of the specified task to "prior". Note
  3088.              that you should NOT modify the priority field in the tcb
  3089.              structure directly. A value of NULL for "task" will set the
  3090.              priority of the "main task".
  3091.  
  3092.  
  3093.         word  get_priority (tcbptr task)
  3094.  
  3095.              Returns the current priority of the specified task. A value
  3096.              of NULL for "task" will get the priority of the "main task".
  3097.  
  3098.  
  3099.  
  3100.  
  3101.  
  3102.  
  3103.  
  3104.         
  3105.         
  3106.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 51
  3107.  
  3108.  
  3109.         void  set_task_flags (tcbptr task, byte flags)
  3110.  
  3111.              Sets the flags of the task to "flags". Currently, the only
  3112.              flag that can be changed is
  3113.  
  3114.                        F_CRIT   the task can not be preempted if set.
  3115.  
  3116.              Note that you may NOT modify the flag field in the tcb
  3117.              structure directly. A value of NULL for "task" will set the
  3118.              flags of the "main task".
  3119.  
  3120.  
  3121.         void  set_funcs (tcbptr task, funcptr save, funcptr rest);
  3122.  
  3123.              Sets the save and restore functions for the specified task.
  3124.              The save function is called whenever the task is deacti-
  3125.              vated, the restore function is called whenever the task is
  3126.              scheduled. This allows saving of critical system states upon
  3127.              a task switch. Both functions are called with a far call,
  3128.              the pointer to the task control block is passed as
  3129.              parameter. A value of NULL for "task" will set the functions
  3130.              of the "main task". To deactivate one or both functions,
  3131.              pass NULL as function parameter.
  3132.  
  3133.  
  3134.         farptr set_user_ptr (tcbptr task, farptr uptr);
  3135.  
  3136.              Sets the user pointer in the specified TCB, and returns it's
  3137.              previous value. The user pointer may be used to point to
  3138.              memory blocks local to a task, or to hold other task-
  3139.              specific values. It is never accessed or modified by the
  3140.              CTask kernel. A value of NULL for "task" will set the user
  3141.              pointer of the "main task".
  3142.  
  3143.  
  3144.         farptr get_user_ptr (tcbptr task);
  3145.  
  3146.              Returns the user pointer of the specified TCB. A value of
  3147.              NULL for "task" will get the user pointer of the "main
  3148.              task".
  3149.  
  3150.  
  3151.  
  3152.                                  Timer Operations
  3153.  
  3154.  
  3155.         Timeouts are normally specified in timer ticks. If CLOCK_MSEC is
  3156.         enabled, timeouts will be converted to the nearest number of
  3157.         timer ticks automatically. The global word variable
  3158.         "ticks_per_sec" contains a rough estimate of the number of ticks
  3159.         per second even if CLOCK_MSEC is not enabled.
  3160.  
  3161.  
  3162.         
  3163.         
  3164.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 52
  3165.  
  3166.  
  3167.                                Event wait Timeouts
  3168.  
  3169.         When  waiting for an event, a timeout may be specified.  The
  3170.         operation will terminate with an error return value if the
  3171.         timeout is reached before the event occurs. NOTE that the timeout
  3172.         parameter is not optional. To specify no timeout, use the value 0.
  3173.  
  3174.  
  3175.                                     "Tickers"
  3176.  
  3177.         It sometimes is desirable to measure timing intervals or global
  3178.         timeouts without creating special tasks, or while waiting for
  3179.         external events in polling loops. A low overhead way of doing
  3180.         this  is the "ticker" structure. When this structure is linked
  3181.         into  the ticker chain, the doubleword "ticks" field is decre-
  3182.         mented on every timer tick (in the timer interrupt itself), until
  3183.         it reaches zero.
  3184.  
  3185.  
  3186.         tick_ptr create_ticker (tick_ptr elem, dword val);
  3187.  
  3188.              Links a ticker element into the ticker chain. The ticks
  3189.              field is initialized to "val", and will be decremented to
  3190.              zero. If the elem pointer is NULL, a new ticker element will
  3191.              be created.
  3192.  
  3193.              Returns the ticker element pointer, NULL on error.
  3194.  
  3195.  
  3196.         void  delete_ticker (tick_ptr elem);
  3197.  
  3198.              Unlinks a ticker element from the ticker chain. Countdown
  3199.              will stop. If the element was allocated dynamically, it will
  3200.              be deleted.
  3201.  
  3202.  
  3203.         void  set_ticker (tick_ptr elem, dword val);
  3204.  
  3205.              Sets the ticks field to the given value. If the ticks field
  3206.              is modified directly instead of through this routine,
  3207.              interrupts should be disabled when writing a doubleword
  3208.              value.
  3209.  
  3210.  
  3211.         dword get_ticker (tick_ptr elem)
  3212.  
  3213.              Returns the current ticker value. If the ticks field is read
  3214.              directly instead of through this routine, interrupts should
  3215.              be disabled when reading the doubleword value.
  3216.  
  3217.  
  3218.  
  3219.  
  3220.         
  3221.         
  3222.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 53
  3223.  
  3224.  
  3225.                                       Delays
  3226.  
  3227.  
  3228.         int t_delay (dword ticks);
  3229.  
  3230.              Delay the current task for "ticks" clock ticks/milliseconds.
  3231.              If ticks is 0, the task is stopped.
  3232.  
  3233.              Returns TIMEOUT if the delay expired, WAKE if the task was
  3234.              activated by wake_task.
  3235.  
  3236.  
  3237.  
  3238.                           Timed Events and Watch Events
  3239.  
  3240.         You can create timer control blocks and memory/port watch blocks
  3241.         to
  3242.              - set a flag
  3243.              - increment a counter
  3244.              - wake up a task
  3245.              - call a function
  3246.  
  3247.         after a specified timeout interval, or when a certain condition
  3248.         is met. The operation may optionally be repeated.
  3249.  
  3250.         Watch control blocks are checked on every timer tick. They allow
  3251.         memory locations and I/O ports to be checked for a certain value,
  3252.         or for a change in value. When the specified condition is met,
  3253.         the given action is executed.
  3254.  
  3255.         For calling functions on a timeout or watch, the following must
  3256.         be noted:
  3257.  
  3258.            -  Timeout/watch functions should be as short as possible,
  3259.              since they run at the highest priority.
  3260.            -  The stack and data area is the area of the timer task. Be
  3261.              careful when referencing variables.
  3262.            -  Timeout/watch functions may not use any functions that could
  3263.              cause the timer task to be made waiting.
  3264.  
  3265.         Since version 2.0, timeout/watch functions are called with
  3266.         interrupts enabled. The definition of the timeout function is
  3267.  
  3268.              void far funcname (dword user_parm);
  3269.  
  3270.         The function is called with the "userpar" parameter specified
  3271.         with  the create_timer, create_memory_watch, and create_port_watch
  3272.         calls.
  3273.  
  3274.  
  3275.  
  3276.  
  3277.  
  3278.         
  3279.         
  3280.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 54
  3281.  
  3282.  
  3283.         tlinkptr create_timer (tlinkptr elem, dword tout, farptr strucp,
  3284.                                byte kind, byte rept [,dword userpar]);
  3285.  
  3286.              Create a timer control block.
  3287.  
  3288.              Returns the address of the control block, NULL on error.
  3289.  
  3290.              "elem"     is the control block to initialise (NULL for
  3291.                         auto-matic allocation).
  3292.  
  3293.              "tout"     specifies the timeout interval.
  3294.  
  3295.              "strucp"   points to the structure to be used. This is a
  3296.                         flagptr for setting a flag, a counterptr for
  3297.                         increasing counters, a tcbptr for waking a task,
  3298.                         or a funcptr for calling a function.
  3299.  
  3300.              "kind"     gives the kind of structure "strucp" points to.
  3301.                         It must be one of
  3302.  
  3303.                            TKIND_WAKE     for task-wakeup
  3304.                            TKIND_PROC     for function call
  3305.                            TKIND_FLAG     for flag set
  3306.                            TKIND_COUNTER  for counter increment.
  3307.  
  3308.              "rept"     if nonzero, the action will be repeated on every
  3309.                         "tout" timeout interval.
  3310.  
  3311.              "userpar"  is a doubleword value that is passed to the
  3312.                         timeout function if kind is TKIND_PROC. This
  3313.                         parameter is optional.
  3314.  
  3315.              NOTE: Timer control blocks can not be named.
  3316.  
  3317.  
  3318.         void  change_timer (tlinkptr elem, dword tout, byte rept);
  3319.  
  3320.              Changes the timeout value and/or the repeat flag for an
  3321.              existing timer control block. If "tout" is zero, the call
  3322.              has the same effect as delete_timer.
  3323.  
  3324.  
  3325.         void  delete_timer (tlinkptr elem);
  3326.  
  3327.              Deletes a timer control block, and removes it from the
  3328.              timeout queue.
  3329.  
  3330.  
  3331.  
  3332.  
  3333.  
  3334.  
  3335.  
  3336.         
  3337.         
  3338.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 55
  3339.  
  3340.  
  3341.         tlinkptr create_memory_watch (tlinkptr elem, farptr address,
  3342.                                       word mask, word compare,
  3343.                                       byte cmpkind, farptr strucp,
  3344.                                       byte kind, byte rept
  3345.                                       [, dword userpar]);
  3346.  
  3347.              Creates a memory watch control block. Memory watches compare
  3348.              a byte or word value at the specified address against a
  3349.              comparison value. The value loaded is always a word, the
  3350.              "mask" parameter may be used to restrict comparison to a
  3351.              byte.
  3352.  
  3353.              Returns the watch control block pointer, or NULL on error.
  3354.  
  3355.              "elem"     is the control block to initialise (NULL for
  3356.                         automatic allocation).
  3357.  
  3358.              "address"  is a pointer to the memory location to watch.
  3359.  
  3360.              "mask"     is a bitmask to mask out irrelevant bits before
  3361.                         comparison.
  3362.  
  3363.              "compare"  is the value the memory contents are to be
  3364.                         compared with.
  3365.  
  3366.              "cmpkind"  is the kind of comparison to be used:
  3367.  
  3368.                         TCMP_EQ   (*address & mask) == compare
  3369.                         TCMP_NE   (*address & mask) != compare
  3370.                         TCMP_GE   (*address & mask) >= compare (unsigned)
  3371.                         TCMP_LE   (*address & mask) <= compare (unsigned)
  3372.                         TCMP_GES  (*address & mask) >= compare (signed)
  3373.                         TCMP_LES  (*address & mask) <= compare (signed)
  3374.  
  3375.                         TCMP_CHG  Change in value:
  3376.                                   (*address & mask) != compare
  3377.                                   compare = *address & mask
  3378.  
  3379.              "strucp"   points to the structure to be used. This is a
  3380.                         flagptr for setting a flag, a counterptr for
  3381.                         increasing counters, a tcbptr for waking a task,
  3382.                         or a funcptr for calling a function.
  3383.  
  3384.              "kind"     gives the kind of structure "strucp" points to.
  3385.                         It must be one of
  3386.  
  3387.                             TKIND_WAKE     for task-wakeup
  3388.                             TKIND_PROC     for function call
  3389.                             TKIND_FLAG     for flag set
  3390.                             TKIND_COUNTER  for counter increment.
  3391.  
  3392.              "rept"     if nonzero, the action will be repeated whenever
  3393.                         the condition is met.
  3394.         
  3395.         
  3396.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 56
  3397.  
  3398.  
  3399.              "userpar"  is a doubleword value that is passed to the watch
  3400.                         function if kind is TKIND_PROC. This parameter is
  3401.                         optional.
  3402.  
  3403.              NOTE: Watch control blocks can not be named.
  3404.  
  3405.  
  3406.         int wait_memory (farptr address,
  3407.                          word mask, word compare, byte cmpkind)
  3408.  
  3409.              Delays the current task until the specified condition is
  3410.              met. Parameters are the same as in create_memory_watch. No
  3411.              timeout can be specified.
  3412.  
  3413.              Returns WATCH if the watch condition was met, WAKE if the
  3414.              task was activated by wake_task.
  3415.  
  3416.  
  3417.         tlinkptr create_port_watch (tlinkptr elem,
  3418.                                     word port, byte in_word,
  3419.                                     word mask, word compare,
  3420.                                     byte cmpkind, farptr strucp,
  3421.                                     byte kind, byte rept
  3422.                                     [, dword userpar]);
  3423.  
  3424.              Creates a port watch control block. Port watches compare a
  3425.              byte or word value read from the specified port address
  3426.              against a comarison value. The value read is either a word
  3427.              or a byte, depending on the "in_word" parameter.
  3428.  
  3429.              Returns the watch control block pointer, or NULL on error.
  3430.  
  3431.              "elem"     is the control block to initialise (NULL for
  3432.                         automatic allocation).
  3433.  
  3434.              "port"     is the port address to read.
  3435.  
  3436.              "in_word"  Specifies whether a word or byte input
  3437.                         instruction is to be used. If zero, a byte is
  3438.                         input, if nonzero, a word is read from the port.
  3439.  
  3440.              "mask"     is a bitmask to mask out irrelevant bits before
  3441.                         comparison.
  3442.  
  3443.              "compare"  is the value the port contents are to be compared
  3444.                         with.
  3445.  
  3446.  
  3447.  
  3448.  
  3449.  
  3450.  
  3451.  
  3452.         
  3453.         
  3454.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 57
  3455.  
  3456.  
  3457.              "cmpkind"  is the kind of comparison to be used:
  3458.  
  3459.                         TCMP_EQ   (in(port) & mask) == compare
  3460.                         TCMP_NE   (in(port) & mask) != compare
  3461.                         TCMP_GE   (in(port) & mask) >= compare (unsigned)
  3462.                         TCMP_LE   (in(port) & mask) <= compare (unsigned)
  3463.                         TCMP_GES  (in(port) & mask) >= compare (signed)
  3464.                         TCMP_LES  (in(port) & mask) <= compare (signed)
  3465.  
  3466.                         TCMP_CHG  Change in value:
  3467.                                   (in(port) & mask) != compare
  3468.                                   compare = in(port) & mask
  3469.                                   (NOTE: The port is read only once.)
  3470.  
  3471.              "strucp"   points to the structure to be used. This is a
  3472.                         flagptr for setting a flag, a counterptr for
  3473.                         increasing counters, a tcbptr for waking a task,
  3474.                         or a funcptr for calling a function.
  3475.  
  3476.              "kind"     gives the kind of structure "strucp" points to.
  3477.                         It must be one of
  3478.  
  3479.                             TKIND_WAKE     for task-wakeup
  3480.                             TKIND_PROC     for function call
  3481.                             TKIND_FLAG     for flag set
  3482.                             TKIND_COUNTER  for counter increment.
  3483.  
  3484.              "rept"     if nonzero, the action will be repeated whenever
  3485.                         the condition is met.
  3486.  
  3487.              "userpar"  is a doubleword value that is passed to the watch
  3488.                         function if kind is TKIND_PROC. This parameter is
  3489.                         optional.
  3490.  
  3491.              NOTE: Watch control blocks can not be named.
  3492.  
  3493.  
  3494.  
  3495.         int wait_port (word port, byte in_word,
  3496.                        word mask, word compare, byte cmpkind)
  3497.  
  3498.              Delays the current task until the specified condition is
  3499.              met. Parameters are the same as in create_port_watch. No
  3500.              timeout can be specified.
  3501.  
  3502.              Returns WATCH if the watch condition was met, WAKE if the
  3503.              task was activated by wake_task.
  3504.  
  3505.  
  3506.         void  delete_watch (tlinkptr elem);
  3507.  
  3508.  
  3509.  
  3510.         
  3511.         
  3512.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 58
  3513.  
  3514.  
  3515.              The specified watch element is removed from the watch queue.
  3516.  
  3517.  
  3518.         NOTE: delete_timer, delete_watch, and change_timer should not be
  3519.         used  on automatically allocated timer/watch control blocks. Since
  3520.         such  blocks are deallocated once the timeout expires or the
  3521.         condition is met (except for repeat operations), the validity of
  3522.         the pointer is not guaranteed.
  3523.  
  3524.  
  3525.  
  3526.                                  Event Operations
  3527.  
  3528.                                     Resources
  3529.  
  3530.         A Resource is either in use or free, the default state is free.
  3531.         If a  task has requested a resource, its state is in use, and the
  3532.         requesting task is said to "own" the resource.  Tasks requesting
  3533.         a resource while it is in use will be made waiting. If the
  3534.         resource is released, the highest priority waiting task is made
  3535.         eligible, and is assigned the resource. Interrupt handlers may
  3536.         not use resource functions other than "check_resource".
  3537.  
  3538.         To facilitate use of resources in nested routines, CTask allows a
  3539.         resource to be requested by a Task already owning it. Different
  3540.         calls may be used to request resources, depending on how such
  3541.         nested calls should be handled. The standard request_resource and
  3542.         c_request_resource calls just mark the resource as in use by
  3543.         setting the owner count to 1, and the first nested routine that
  3544.         releases the resource will cause the resource to be freed. The
  3545.         request_cresource and c_request_cresource calls increment the
  3546.         owner count, so the resource will only be freed upon a matching
  3547.         count of requests and releases.
  3548.  
  3549.  
  3550.         resourceptr create_resource (resourceptr rsc [, byteptr name]);
  3551.  
  3552.              This initialises a resource. Must be used prior to any other
  3553.              operations on a resource.
  3554.  
  3555.              Returns the address of the control block, NULL on error.
  3556.  
  3557.              "rsc"      is the resource control block (NULL for automatic
  3558.                         allocation).
  3559.  
  3560.              "name"     is the name of the resource, up to eight
  3561.                         characters, plus zero-terminator. This parameter
  3562.                         is defined only if TSK_NAMEPAR is enabled in
  3563.                         tskconf.h.
  3564.  
  3565.  
  3566.  
  3567.  
  3568.         
  3569.         
  3570.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 59
  3571.  
  3572.  
  3573.         void  delete_resource (resourceptr rsc);
  3574.  
  3575.              Calling this routine is optional. It will kill all tasks
  3576.              waiting for the resource.
  3577.  
  3578.  
  3579.         void  release_resource (resourceptr rsc);
  3580.  
  3581.              Decrement the owner count, and release the resource if it is
  3582.              zero. If the task does not own the resource, the call is
  3583.              ignored. If the resource is released, and tasks are waiting
  3584.              for access, the highest priority task will gain access to
  3585.              the resource.
  3586.  
  3587.  
  3588.         int request_resource (resourceptr rsc, dword timeout);
  3589.  
  3590.              Requests the resource. If it is not available, the task is
  3591.              suspended. A timeout may be specified.
  3592.  
  3593.              Returns 0 if resource was allocated, TIMEOUT if a timeout
  3594.              occurred, WAKE on wake.
  3595.  
  3596.              This call is ignored (returns a 0) if the calling task
  3597.              already owns the resource.
  3598.  
  3599.  
  3600.         int request_cresource (resourceptr rsc, dword timeout);
  3601.  
  3602.              Requests the resource. If it is not available, the task is
  3603.              suspended. A timeout may be specified.
  3604.  
  3605.              Returns 0 if resource was allocated, TIMEOUT if a timeout
  3606.              occurred, WAKE on wake.
  3607.  
  3608.              This call increments the owner count, and returns 0, if the
  3609.              calling task already owns the resource.
  3610.  
  3611.  
  3612.         int c_request_resource (resourceptr rsc);
  3613.  
  3614.              Requests the resource only if it is available.
  3615.  
  3616.              Returns 0 if resource was allocated, -1 if unavailable.
  3617.  
  3618.  
  3619.         int check_resource (resourceptr rsc);
  3620.  
  3621.              Returns 0 if resource is allocated, 1 if free.
  3622.  
  3623.  
  3624.  
  3625.  
  3626.         
  3627.         
  3628.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 60
  3629.  
  3630.  
  3631.                                       Flags
  3632.  
  3633.         A Flag can be either on or off, the default state is off (0).
  3634.         Tasks can wait on either state of the flag. If the state is
  3635.         changed, all tasks waiting for the state are made eligible.
  3636.         Interrupt handlers may use the "set_flag", "clear_flag", and
  3637.         "check_flag" functions.
  3638.  
  3639.  
  3640.         flagptr create_flag (flagptr flg [, byteptr name]);
  3641.  
  3642.              This initialises a flag. Must be used prior to any other
  3643.              operations on a flag. The state is set to 0.
  3644.  
  3645.              Returns the address of the control block, NULL on error.
  3646.  
  3647.              "flg"      is the flag control block (NULL for automatic
  3648.                         allocation).
  3649.  
  3650.              "name"     is the name of the flag, up to eight characters,
  3651.                         plus zero-terminator. This parameter is defined
  3652.                         only if TSK_NAMEPAR is enabled in tskconf.h.
  3653.  
  3654.  
  3655.         void  delete_flag (flagptr flg);
  3656.  
  3657.              Calling this routine is optional. It will kill all tasks
  3658.              waiting for the flag.
  3659.  
  3660.  
  3661.         void  set_flag (flagptr flg);
  3662.  
  3663.              This sets the flag. All tasks waiting for the set state will
  3664.              be made eligible for running.
  3665.  
  3666.  
  3667.         void  clear_flag (flagptr flg);
  3668.  
  3669.              This clears the flag. All tasks waiting for the clear state
  3670.              will be made eligible for running.
  3671.  
  3672.  
  3673.         int wait_flag_set (flagptr flg, dword timeout);
  3674.  
  3675.              Waits for the set state of the flag. If the flag is not set,
  3676.              the task is suspended. A timeout may be specified.
  3677.  
  3678.              Returns 0 if the flag was set, TIMEOUT on timeout, WAKE on
  3679.              wake.
  3680.  
  3681.  
  3682.  
  3683.  
  3684.         
  3685.         
  3686.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 61
  3687.  
  3688.  
  3689.         int wait_flag_clear (flagptr flg, dword timeout);
  3690.  
  3691.              Waits for the clear state of the flag. If the flag is not
  3692.              clear, the task is suspended. A timeout may be specified.
  3693.  
  3694.              Returns 0 if the flag was cleared, TIMEOUT on timeout, WAKE
  3695.              on wake.
  3696.  
  3697.  
  3698.         int clear_flag_wait_set (flagptr flg, dword timeout)
  3699.  
  3700.              Combines the operations clear_flag and wait_flag_set.
  3701.  
  3702.              Returns 0 if the flag was set, TIMEOUT on timeout, WAKE on
  3703.              wake.
  3704.  
  3705.  
  3706.         int check_flag (flagptr flg);
  3707.  
  3708.              Returns 0 if flag clear, 1 if set.
  3709.  
  3710.  
  3711.  
  3712.                                      Counters
  3713.  
  3714.         A Counter can have any value from 0L to 0xffffffffL, the default
  3715.         value is 0. Tasks can wait for a counter being zero or non-zero.
  3716.         If the counter is cleared or decremented to zero, all tasks wai-
  3717.         ting  for the zero condition are made eligible. If the counter is
  3718.         incremented, the highest priority task waiting for non-zero is
  3719.         made  eligible, and the counter is decremented by one. Interrupt
  3720.         handlers may use the "clear_counter", "inc_counter",
  3721.         "set_counter", and "check_counter" functions.
  3722.  
  3723.  
  3724.         counterptr create_counter (counterptr cnt [, byteptr name]);
  3725.  
  3726.              This initialises a counter. Must be used prior to any other
  3727.              operations on a flag. The value is set to 0.
  3728.  
  3729.              Returns the address of the control block, NULL on error.
  3730.  
  3731.              "cnt"      is the counter control block (NULL for automatic
  3732.                         allocation).
  3733.  
  3734.              "name"     is the name of the counter, up to eight
  3735.                         characters, plus zero-terminator. This parameter
  3736.                         is defined only if TSK_NAMEPAR is enabled in
  3737.                         tskconf.h.
  3738.  
  3739.  
  3740.  
  3741.  
  3742.         
  3743.         
  3744.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 62
  3745.  
  3746.  
  3747.         void  delete_counter (counterptr cnt);
  3748.  
  3749.              Calling this routine is optional. It will kill all tasks
  3750.              waiting for the counter.
  3751.  
  3752.  
  3753.         void  clear_counter (counterptr cnt);
  3754.  
  3755.              Clears the counter to zero. All tasks waiting for the zero
  3756.              state will be made eligible for running.
  3757.  
  3758.  
  3759.         int wait_counter_set (counterptr cnt, dword timeout);
  3760.  
  3761.              Waits for the counter having a nonzero value. If the value
  3762.              is zero, the task is suspended. The value is decremented
  3763.              when the task gets access to the counter.  A timeout may be
  3764.              specified.
  3765.  
  3766.              Returns 0 if the counter was nonzero, TIMEOUT on timeout,
  3767.              WAKE on wake.
  3768.  
  3769.  
  3770.         int wait_counter_clear (counterptr cnt, dword timeout);
  3771.  
  3772.              Waits for the counter having a zero value. If the value is
  3773.              nonzero, the task is suspended. A timeout may be specified.
  3774.  
  3775.              Returns 0 if the counter was zero, TIMEOUT on timeout, WAKE
  3776.              on wake.
  3777.  
  3778.  
  3779.         void  inc_counter (counterptr cnt);
  3780.  
  3781.              Increments the counter. If tasks are waiting for the nonzero
  3782.              state, the highest priority task is given access to the
  3783.              counter.
  3784.  
  3785.  
  3786.         void  set_counter (counterptr cnt, dword val);
  3787.  
  3788.              Sets the counter to the given value. If "val" is nonzero,
  3789.              and tasks are waiting for the set state, the highest
  3790.              priority tasks are made eligible, and "val" is decremented,
  3791.              until either "val" reaches zero, or there are no more tasks
  3792.              waiting. If val is, or is counted down to, zero, all tasks
  3793.              waiting for the zero state are made eligible.
  3794.  
  3795.  
  3796.         dword check_counter (counterptr cnt);
  3797.  
  3798.              Returns the current value of the counter.
  3799.  
  3800.         
  3801.         
  3802.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 63
  3803.  
  3804.  
  3805.                                     Mailboxes
  3806.  
  3807.         A Mailbox can hold any number of mail blocks. Tasks can send mail
  3808.         to a  mailbox and wait for mail to arrive. A mail block is
  3809.         assigned to the highest priority waiting task. Care must be
  3810.         exercised not to re-use a mail block until it has been processed
  3811.         by the receiving task. The mail block format is user defineable,
  3812.         with  the first doubleword in a block reserved for the tasking
  3813.         system. Interrupt handlers may use the "send_mail",
  3814.         "c_wait_mail", and "check_mailbox" functions.
  3815.  
  3816.         Note  that mailboxes are well suited to provide the mechanism for
  3817.         managing a chain of (equally sized) free mail blocks. On
  3818.         initialization, all free blocks would be "sent" to the manager
  3819.         box.  Requesting a free block would use "wait_mail", and freeing a
  3820.         used  block would again "send" it to the manager mailbox.
  3821.  
  3822.  
  3823.         mailboxptr create_mailbox (mailboxptr box [, byteptr name]);
  3824.  
  3825.              This initialises a mailbox. Must be used prior to any other
  3826.              operations on a mailbox.
  3827.  
  3828.              Returns the address of the control block, NULL on error.
  3829.  
  3830.              "box"      is the mailbox control block (NULL for automatic
  3831.                         allocation).
  3832.  
  3833.              "name"     is the name of the mailbox, up to eight
  3834.                         characters, plus zero-terminator. This parameter
  3835.                         is defined only if TSK_NAMEPAR is enabled in
  3836.                         tskconf.h.
  3837.  
  3838.  
  3839.         void  delete_mailbox (mailboxptr box);
  3840.  
  3841.              Calling this routine is optional. It will kill all tasks
  3842.              waiting for mail.
  3843.  
  3844.  
  3845.         void  send_mail (mailboxptr box, farptr msg);
  3846.  
  3847.              Sends a message to the specified mailbox. If tasks are
  3848.              waiting for mail, the highest priority task will get it.
  3849.  
  3850.  
  3851.         farptr wait_mail (mailboxptr box, dword timeout);
  3852.  
  3853.              Waits for mail. If no mail is available, the task is
  3854.              suspended. A timeout may be specified.
  3855.  
  3856.              Returns the pointer to the received mail block, TTIMEOUT on
  3857.              timeout, TWAKE on wake.
  3858.         
  3859.         
  3860.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 64
  3861.  
  3862.  
  3863.         farptr c_wait_mail (mailboxptr box);
  3864.  
  3865.              Reads mail only if mail is available.
  3866.  
  3867.              Returns NULL if there is no mail, else a pointer to the
  3868.              received message.
  3869.  
  3870.  
  3871.         int check_mailbox (mailboxptr box);
  3872.  
  3873.              Returns 0 if mailbox is empty, 1 otherwise.
  3874.  
  3875.  
  3876.  
  3877.                                       Pipes
  3878.  
  3879.         A Pipe has a buffer to hold character or word sized items. An
  3880.         item  may be written to a pipe if there is space in the buffer.
  3881.         Otherwise, the writing task will be made waiting. A reading task
  3882.         will  be made waiting if the buffer is empty. If an item has been
  3883.         read, the highest priority task waiting to write to the pipe will
  3884.         be allowed to write. Interrupt handlers may only use pipe
  3885.         functions "check_pipe", "c_write_pipe", and "c_read_pipe".
  3886.  
  3887.         Note  that the values -1 and -2 (0xffff and 0xfffe) should be
  3888.         avoided when writing to word pipes. These values are used to mark
  3889.         timeout and wake when reading, or pipe empty when checking a word
  3890.         pipe, and thus may lead to erroneous operation of your routines.
  3891.  
  3892.  
  3893.         pipeptr create_pipe (pipeptr pip, farptr buf, word bufsize
  3894.                              [, byteptr name]);
  3895.         wpipeptr create_wpipe (wpipeptr pip, farptr buf, word bufsize
  3896.                                [, byteptr name]);
  3897.  
  3898.              This initialises a pipe. Must be used prior to any other
  3899.              operations on a pipe. "bufsize" specifies the buffer size in
  3900.              bytes. With word pipes, the buffer size should be divisible
  3901.              by two.
  3902.  
  3903.              Returns the address of the control block, NULL on error.
  3904.  
  3905.              "pip"      is the pipe/wpipe control block (NULL for
  3906.                         automatic allocation).
  3907.  
  3908.              "name"     is the name of the pipe, up to eight characters,
  3909.                         plus zero-terminator. This parameter is defined
  3910.                         only if TSK_NAMEPAR is enabled in tskconf.h.
  3911.  
  3912.  
  3913.  
  3914.  
  3915.  
  3916.         
  3917.         
  3918.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 65
  3919.  
  3920.  
  3921.         void  delete_pipe (pipeptr pip);
  3922.         void  delete_wpipe (wpipeptr pip);
  3923.  
  3924.              Calling this routine is optional. It will kill all tasks
  3925.              waiting to read or write messages.
  3926.  
  3927.  
  3928.         int read_pipe (pipeptr pip, dword timeout);
  3929.         word  read_wpipe (wpipeptr pip, dword timeout);
  3930.  
  3931.              Read an item from a pipe. If no item is available, the task
  3932.              is suspended. A timeout may be specified.
  3933.  
  3934.              Returns the item, or TIMEOUT on timeout, WAKE on wake.
  3935.  
  3936.  
  3937.         int c_read_pipe (pipeptr pip);
  3938.         word  c_read_wpipe (wpipeptr pip);
  3939.  
  3940.              Reads an item from a pipe only if one is available.
  3941.  
  3942.              Returns the received item, or -1 if none is available.
  3943.  
  3944.  
  3945.         int write_pipe (pipeptr pip, byte ch, dword timeout);
  3946.         int write_wpipe (wpipeptr pip, word ch, dword timeout);
  3947.  
  3948.              Writes an item to a pipe. If the buffer is full, the task is
  3949.              suspended. A timeout may be specified. If tasks are waiting
  3950.              to read, the item will be assigned to the highest priority
  3951.              waiting task.
  3952.  
  3953.              Returns 0 on success, or TIMEOUT on timeout, WAKE on wake.
  3954.  
  3955.  
  3956.         int c_write_pipe (pipeptr pip, byte ch);
  3957.         int c_write_wpipe (wpipeptr pip, word ch);
  3958.  
  3959.              Writes an item to a pipe only if enough space is available.
  3960.  
  3961.              Returns 0 on success, or -1 if no space available.
  3962.  
  3963.  
  3964.         int wait_pipe_empty (pipeptr pip, dword timeout);
  3965.         int wait_wpipe_empty (wpipeptr pip, dword timeout);
  3966.  
  3967.              Waits for the pipe to be emptied. If the pipe is already
  3968.              empty on entry, the task continues to run.
  3969.  
  3970.              Returns 0 on empty, TIMEOUT on timeout, WAKE on wake.
  3971.  
  3972.  
  3973.  
  3974.         
  3975.         
  3976.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 66
  3977.  
  3978.  
  3979.         int check_pipe (pipeptr pip);
  3980.         word  check_wpipe (pipeptr pip);
  3981.  
  3982.              Returns -1 if the pipe is empty, else the first item in the
  3983.              pipe. The item is not removed from the pipe.
  3984.  
  3985.  
  3986.         word  pipe_free (pipeptr pip);
  3987.         word  wpipe_free (wpipeptr pip);
  3988.  
  3989.              Returns the number of free items available in the pipe.
  3990.  
  3991.  
  3992.         void  flush_pipe (pipeptr pip)
  3993.         void  flush_wpipe (wpipeptr pip)
  3994.  
  3995.              Clears the pipe. Tasks waiting for the empty state are made
  3996.              eligible.
  3997.  
  3998.  
  3999.                                      Buffers
  4000.  
  4001.         A Buffer has a buffer to hold message strings. A message may be
  4002.         written to a buffer if it fits into the buffer. Otherwise, the
  4003.         writing task will be made waiting. A reading task will be made
  4004.         waiting if the buffer is empty. If a message has been read, the
  4005.         highest priority task waiting to write to the buffer will be
  4006.         allowed to write if its message fits into the available space.
  4007.         Interrupt handlers may not use buffer functions other than
  4008.         "check_buffer".
  4009.  
  4010.         The buffer routines are implemented using resources and pipes,
  4011.         and thus are not part of the true "kernel" routines.
  4012.  
  4013.  
  4014.         bufferptr create_buffer (bufferptr buf, farptr pbuf, word bufsize
  4015.                                  [, byteptr name]);
  4016.  
  4017.              This initialises a buffer. Must be used prior to any other
  4018.              operations on a buffer.
  4019.  
  4020.              The minimum buffer size is the length of the longest
  4021.              expected message plus two.
  4022.  
  4023.              Returns the address of the control block, NULL on error.
  4024.  
  4025.              "buf"      is the buffer control block (NULL for automatic
  4026.                         allocation).
  4027.  
  4028.              "name"     is the name of the buffer, up to eight
  4029.                         characters, plus zero-terminator. This parameter
  4030.                         is defined only if TSK_NAMEPAR is enabled in
  4031.                         tskconf.h.
  4032.         
  4033.         
  4034.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 67
  4035.  
  4036.  
  4037.         void  delete_buffer (bufferptr buf);
  4038.  
  4039.              Calling this routine is optional. It will kill all tasks
  4040.              waiting to read or write messages.
  4041.  
  4042.  
  4043.         int read_buffer (bufferptr buf, farptr msg, int size,
  4044.                          dword timeout);
  4045.  
  4046.              Read a message from a buffer. If no message is available,
  4047.              the task is suspended. A timeout may be specified.
  4048.  
  4049.              The message will be copied to the buffer "buf", with a
  4050.              maximum length of "size" bytes.
  4051.  
  4052.              Returns the length of the received message, TIMEOUT on
  4053.              timeout, WAKE on wake.
  4054.  
  4055.  
  4056.         int c_read_buffer (bufferptr buf, farptr msg, int size);
  4057.  
  4058.              Reads a message from a buffer only if one is available.
  4059.  
  4060.              Returns the length of the received message, or -1 if none is
  4061.              available.
  4062.  
  4063.  
  4064.         int write_buffer (bufferptr buf, farptr msg, int size,
  4065.                           dword timeout);
  4066.  
  4067.              Writes a message from "msg" with length "size" to a buffer.
  4068.              If not enough space for the message is available, the task
  4069.              is suspended. A timeout may be specified. If tasks are
  4070.              waiting for messages, the highest priority task will get it.
  4071.  
  4072.              Returns the length of the message, TIMEOUT on timeout, WAKE
  4073.              on wake, -3 on error (length < 0 or length > buffer size).
  4074.  
  4075.  
  4076.         int c_write_buffer (bufferptr buf, farptr msg, int size);
  4077.  
  4078.              Writes a message to a buffer only if enough space is
  4079.              available.
  4080.  
  4081.              Returns the length of the message, -1 if no space available,
  4082.              or -3 on error (length < 0 or length > buffer size).
  4083.  
  4084.  
  4085.         word  check_buffer (bufferptr buf);
  4086.  
  4087.              Returns the current number of bytes (not messages) in the
  4088.              buffer, including the length words.
  4089.  
  4090.         
  4091.         
  4092.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 68
  4093.  
  4094.  
  4095.                                The Keyboard Handler
  4096.  
  4097.  
  4098.         word  t_read_key (void)
  4099.  
  4100.              Waits for a key to be entered. Returns the ASCII-code in the
  4101.              lower byte, and the scan-code in the upper byte, or WAKE
  4102.              (0xfffe) on wake.
  4103.  
  4104.  
  4105.         word  t_wait_key (dword timeout)
  4106.  
  4107.              Waits for a key to be entered. Returns the ASCII-code in the
  4108.              lower byte, and the scan-code in the upper byte, or TIMEOUT
  4109.              (0xffff) on timeout, WAKE (0xfffe) on wake.
  4110.  
  4111.  
  4112.         word  t_keyhit (void)
  4113.  
  4114.              Returns -1 (0xffff) if no key was entered, else the value of
  4115.              the key. The key is not removed.
  4116.  
  4117.  
  4118.  
  4119.                               The Serial I/O handler
  4120.  
  4121.         The serial I/O handler provides full duplex interrupt driven I/O
  4122.         on the serial ports. Support for COM1 and COM2 is included,
  4123.         adding other ports is possible by changing the source and/or
  4124.         defining ports on-line.
  4125.  
  4126.  
  4127.         int v24_define_port (int base, byte irq, byte vector)
  4128.  
  4129.              Defines a new COM-port. This routine can only be used if
  4130.              TSK_DYNAMIC is enabled.
  4131.  
  4132.              "base"     is the port base I/O address.
  4133.  
  4134.              "irq"      is the IRQ-line number (0-7 for XT, 0-15 for AT)
  4135.                         the port uses for interrupts.
  4136.  
  4137.              "vector"   is the interrupt vector number (0-0xff).
  4138.  
  4139.              The return value is the internal port number for use with
  4140.              v24_install. -1 is returned on error (memory full).
  4141.  
  4142.  
  4143.  
  4144.  
  4145.  
  4146.  
  4147.  
  4148.         
  4149.         
  4150.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 69
  4151.  
  4152.  
  4153.         sioptr v24_install (int port, int init,
  4154.                             farptr rcvbuf, word rcvsize,
  4155.                             farptr xmitbuf, word xmitsize);
  4156.  
  4157.              Installs the handler for the specified port. Currently,
  4158.              ports 0 (COM1) and 1 (COM2) are supported by default. Both
  4159.              ports may be used simultaneously, the buffer areas for the
  4160.              ports must not be shared.
  4161.  
  4162.              "rcvbuf"   is a word pipe buffer area for received
  4163.                         characters. May be NULL for automatic allocation.
  4164.  
  4165.              "rcvsize"  specifies the receive buffer size in bytes. Note
  4166.                         that the buffer will hold rcvsize / 2 received
  4167.                         characters.
  4168.  
  4169.              "xmitbuf"  is a byte pipe buffer for characters waiting for
  4170.                         transmission. May be NULL for automatic
  4171.                         allocation.
  4172.  
  4173.              "xmitsize" gives the transmit buffer size in bytes.
  4174.  
  4175.              "port"     Port number to install (0: COM1, 1: COM2).
  4176.  
  4177.                         If the port number is ORed with 0x80, the port is
  4178.                         *relative*. This means that the entry in the BIOS
  4179.                         table for COM-Ports is used to search the tables
  4180.                         internal to the driver for the port information,
  4181.                         instead of using the table entry directly. If the
  4182.                         port address cannot be found, the driver returns
  4183.                         with an error code. Note that ports are numbered
  4184.                         from 0, so to specify relative COM1, pass 0x80 as
  4185.                         parameter.
  4186.  
  4187.              "init"     if non-zero, the port is initialised with the
  4188.                         default values specified in the source. If the
  4189.                         parameter is zero, the control registers and baud
  4190.                         rates on entry are not modified.
  4191.  
  4192.              The return value is a pointer to the sio control block for
  4193.              use with the other driver routines. NULL is returned on
  4194.              error (invalid port number, bad buffer sizes, nonexistent
  4195.              hardware, out of memory).
  4196.  
  4197.  
  4198.  
  4199.  
  4200.  
  4201.  
  4202.  
  4203.  
  4204.  
  4205.  
  4206.         
  4207.         
  4208.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 70
  4209.  
  4210.  
  4211.         void  v24_remove (sioptr sio, int restore);
  4212.  
  4213.              Removes the driver for the specified control block. Should
  4214.              be called for all ports installed before exiting the
  4215.              program.
  4216.  
  4217.              If the "restore" parameter is nonzero, the control registers
  4218.              and the baud rate that were set before installation of the
  4219.              driver are restored. If the parameter is zero, the values
  4220.              are not changed.
  4221.  
  4222.  
  4223.         void  v24_remove_all (void)
  4224.  
  4225.              Removes all installed serial i/o drivers. This routine is
  4226.              automatically called on remove_tasker if drivers were
  4227.              installed. Note that you can not specify a restore
  4228.              parameter, the default restore parameter is used (constant
  4229.              in tsksio.c).
  4230.  
  4231.  
  4232.         void  v24_change_rts (sioptr sio, int on);
  4233.  
  4234.              Changes the state of the RTS output line. A nonzero value
  4235.              for "on" will turn the output on.
  4236.  
  4237.  
  4238.         void  v24_change_dtr (sioptr sio, int on);
  4239.  
  4240.              Changes the state of the DTR output line. A nonzero value
  4241.              for "on" will turn the output on.
  4242.  
  4243.  
  4244.         void  v24_change_baud (sioptr sio, long rate);
  4245.  
  4246.              Changes the baud rate. The following baud rates are suppor-
  4247.              ted:
  4248.  
  4249.                 50,    75,   110,   134,   150,   300,   600,
  4250.               1200,  1800,  2000,  2400,  3600,  4800,  7200,  9600,
  4251.              19200, 38400.
  4252.  
  4253.              Note that baud rates above 9600 may cause problems on slow
  4254.              machines.
  4255.  
  4256.  
  4257.  
  4258.  
  4259.  
  4260.  
  4261.  
  4262.  
  4263.  
  4264.         
  4265.         
  4266.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 71
  4267.  
  4268.  
  4269.         void  v24_change_parity (sioptr sio, int par);
  4270.  
  4271.              Changes parity. The parameter must be one of the following
  4272.              values defined in "sio.h":
  4273.  
  4274.                   PAR_NONE  no parity checks
  4275.                   PAR_EVEN  even parity
  4276.                   PAR_ODD   odd parity
  4277.                   PAR_MARK  mark parity
  4278.                   PAR_SPACE space parity
  4279.  
  4280.  
  4281.         void  v24_change_wordlength (sioptr sio, int len);
  4282.  
  4283.              Changes word length. Values 5, 6, 7, 8 may be given.
  4284.  
  4285.  
  4286.         void  v24_change_stopbits (sioptr sio, int n);
  4287.  
  4288.              Changes Stopbits. Values 1 and 2 are allowed.
  4289.  
  4290.  
  4291.         void  v24_watch_modem (sioptr sio, byte flags);
  4292.  
  4293.              Watches the modem status lines to control transmission.
  4294.  
  4295.              "flags"    Specifies the input lines that must be active to
  4296.                         allow transmission. Transmission will stop if one
  4297.                         of the lines goes inactive. The parameter may be
  4298.                         combined from the following values defined in
  4299.                         "sio.h":
  4300.  
  4301.                         CTS  to watch clear to send
  4302.                         DSR  to watch data set ready
  4303.                         RI   to watch ring indicator
  4304.                         CD   to watch carrier detect
  4305.  
  4306.              A value of zero (the default) will allow transmission
  4307.              regardless of modem status.
  4308.  
  4309.  
  4310.  
  4311.  
  4312.  
  4313.  
  4314.  
  4315.  
  4316.  
  4317.  
  4318.  
  4319.  
  4320.  
  4321.  
  4322.         
  4323.         
  4324.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 72
  4325.  
  4326.  
  4327.         void  v24_protocol (sioptr sio, int prot,
  4328.                            word offthresh, word onthresh);
  4329.  
  4330.              Sets the handshake protocol to use.
  4331.  
  4332.              "prot"     specifies the protocol. This parameter may be
  4333.                         combined from the following values:
  4334.  
  4335.                         XONXOFF   to enable XON/XOFF (DC1/DC3) handshake
  4336.                         RTSCTS    to enable RTS/CTS handshake
  4337.  
  4338.              "offthresh" specifies the minimum number of free items in
  4339.                         the receive buffer. If this threshold is reached,
  4340.                         an XOFF is transmitted and/or the RTS line is
  4341.                         inactivated.
  4342.  
  4343.              "onthresh" specifies the minimum number of items that must
  4344.                         be free before XON is transmitted and/or the RTS
  4345.                         line is re-activated.
  4346.  
  4347.              Enabling XONXOFF will remove all XON and XOFF characters
  4348.              from the input stream. Transmission will be disabled when
  4349.              XOFF is received, and re-enabled when XON is received.
  4350.  
  4351.              Enabling RTSCTS will stop transmission when the CTS modem
  4352.              input line is inactive.
  4353.  
  4354.  
  4355.         int v24_send (sioptr sio, byte ch, dword timeout);
  4356.  
  4357.              Transmits the character "ch". A timeout may be specified.
  4358.  
  4359.              Returns TIMEOUT on timeout, WAKE on wake, else 0.
  4360.  
  4361.  
  4362.         int v24_receive (sioptr sio, dword timeout);
  4363.  
  4364.              Waits for a received character. A timeout may be specified.
  4365.  
  4366.              Returns TIMEOUT on timeout, WAKE on wake, else the character
  4367.              in the lower byte, plus an error code in the upper byte. The
  4368.              error code is the combination of
  4369.  
  4370.                   0x02      overrun error
  4371.                   0x04      parity error
  4372.                   0x08      framing error
  4373.                   0x10      break interrupt.
  4374.  
  4375.  
  4376.         int v24_check (sioptr sio);
  4377.  
  4378.              Returns -1 if no receive character is available, else the
  4379.              next character from the pipe. The character is not removed.
  4380.         
  4381.         
  4382.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 73
  4383.  
  4384.  
  4385.         int v24_overrun (sioptr sio);
  4386.  
  4387.              Checks for receive pipe overrun. Returns 1 if an overrun
  4388.              occurred, 0 otherwise. Clears the overrun flag.
  4389.  
  4390.  
  4391.         int v24_modem_status (sioptr sio);
  4392.  
  4393.              Returns the current modem status word. The CTS, DSR, RI, and
  4394.              CD defines may be used to extract the modem input line
  4395.              status.
  4396.  
  4397.  
  4398.         int v24_complete (sioptr sio);
  4399.  
  4400.              Returns 1 if all characters in the transmit pipe have been
  4401.              sent, else 0.
  4402.  
  4403.  
  4404.         int v24_wait_complete (sioptr sio, dword timeout);
  4405.  
  4406.              Waits for the transmit pipe to be empty. Returns TIMEOUT on
  4407.              timeout, WAKE on wake, else 0.
  4408.  
  4409.  
  4410.         void  v24_flush_receive (sioptr sio);
  4411.  
  4412.              Flushes the receive pipe.
  4413.  
  4414.  
  4415.         void  v24_flush_transmit (sioptr sio)
  4416.  
  4417.              Flushes the transmit pipe. Tasks waiting for transmit
  4418.              completion are made eligible.
  4419.  
  4420.  
  4421.  
  4422.  
  4423.  
  4424.  
  4425.  
  4426.  
  4427.  
  4428.  
  4429.  
  4430.  
  4431.  
  4432.  
  4433.  
  4434.  
  4435.  
  4436.  
  4437.  
  4438.         
  4439.         
  4440.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 74
  4441.  
  4442.  
  4443.                             The Printer Output Driver
  4444.  
  4445.  
  4446.         The printer output driver provides for buffered output to up to
  4447.         three printer ports (more can be added by editing the source).
  4448.         Interrupt or polling may be selected. Due to the usual hardware
  4449.         implementation of printers and the printer interface, using
  4450.         polling is recommended. When using interrupts, you should not
  4451.         simultaneously install both port 0 and port 1 with interrupt
  4452.         enabled, since both ports share the same interrupt line.
  4453.  
  4454.  
  4455.         int prt_install (int port, byte polling, word prior,
  4456.                          farptr xmitbuf, word xmitsize);
  4457.  
  4458.              Installs the printer driver for the specified port. Ports 0
  4459.              (LPT1), 1 (LPT2), and 2 (LPT3) are supported.
  4460.  
  4461.              "port"     The output port to use.
  4462.  
  4463.                         If the port number is ORed with 0x80, the port is
  4464.                         relative. This means that the entry in the BIOS
  4465.                         table for LPT-Ports is used to search the tables
  4466.                         internal to the driver for the port information,
  4467.                         instead of using the table entry directly. If the
  4468.                         port address cannot be found, the driver returns
  4469.                         with an error code. Note that ports are numbered
  4470.                         from 0, so to specify LPT1, pass 0x80 as
  4471.                         parameter.
  4472.  
  4473.              "polling"  specifies polling output when nonzero, interrupt
  4474.                         output when zero.
  4475.  
  4476.              "prior"    sets the priority of the printer output task.
  4477.  
  4478.              "xmitbuf"  is a buffer area for the printer output buffer.
  4479.                         May be NULL for automatic allocation.
  4480.  
  4481.              "xmitsize" specifies the output buffer size in bytes.
  4482.  
  4483.              The return value is the internal port number for use with
  4484.              the other driver routines. -1 is returned on error (invalid
  4485.              port number, bad buffer sizes, nonexistent hardware).
  4486.  
  4487.  
  4488.         void  prt_remove (int port);
  4489.  
  4490.              Removes the printer driver for the specified port.
  4491.  
  4492.  
  4493.  
  4494.  
  4495.  
  4496.         
  4497.         
  4498.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 75
  4499.  
  4500.  
  4501.         void  prt_remove_all (void)
  4502.  
  4503.              Removes all installed printer ports. This routine is
  4504.              automatically called on remove_tasker if ports were
  4505.              installed.
  4506.  
  4507.  
  4508.         void  prt_change_control (int port, byte control);
  4509.  
  4510.              Changes the printer control output lines of the port. The
  4511.              value for "control" may be combined from the following
  4512.              values defined in "prt.h":
  4513.  
  4514.                   AUTOFEED  will enable printer auto feed if set
  4515.                   INIT      will initialise (prime) the printer if clear
  4516.                   SELECT    will select the printer if set
  4517.  
  4518.  
  4519.         int prt_write (int port, byte ch, dword timeout);
  4520.  
  4521.              Write a byte to the printer. A timeout may be given.
  4522.  
  4523.              Returns 0 on success, TIMEOUT on timeout, WAKE on wake.
  4524.  
  4525.  
  4526.         int prt_status (int port);
  4527.  
  4528.              Returns the current printer status lines, combined from the
  4529.              values
  4530.  
  4531.                   BUSY      Printer is busy when 0
  4532.                   ACK       Acknowledge (pulsed 0)
  4533.                   PEND      Paper End detected when 0
  4534.                   SELIN     Printer is selected (on line) when 1
  4535.                   ERROR     Printer error when 0
  4536.  
  4537.  
  4538.         int prt_complete (int port);
  4539.  
  4540.              Returns 1 if the printer buffer has been completely
  4541.              transmitted, 0 otherwise.
  4542.  
  4543.  
  4544.         int prt_wait_complete (int port, dword timeout);
  4545.  
  4546.              Waits for printer output to complete.
  4547.  
  4548.              Returns 0 on success, else TIMEOUT on timeout, WAKE on wake.
  4549.  
  4550.         void  prt_flush (int port)
  4551.  
  4552.              Flushes the output pipe of the printer. Tasks waiting for
  4553.              print completion are made eligible.
  4554.         
  4555.         
  4556.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 76
  4557.  
  4558.  
  4559.                       Some notes on potential trouble spots
  4560.  
  4561.                               Turbo C console output
  4562.  
  4563.         As mentioned in the manual, console output should generally be
  4564.         done  only from one task, or be protected with resources. This is
  4565.         especially true for Turbo C (Version 1.5 and later), because the
  4566.         putch function is NOT REENTRANT. Since other console output also
  4567.         uses  putch in the end, you have to be extremely careful not to
  4568.         crash your system by entering the putch routine concurrently. You
  4569.         should use the "conout" module provided with CTask to channel
  4570.         console output through a buffer. If you own the Turbo C library
  4571.         source code, you could replace the "_VideoInt" routine in file
  4572.         "crtinit.cas" with an (inline) assembler equivalent that pushes
  4573.         BP on the stack instead of storing it into a static variable.
  4574.  
  4575.  
  4576.                                 The timer tick EOI
  4577.  
  4578.         To allow CTask to run concurrently with other background programs
  4579.         that  might steal the timer tick interrupt, and to enable high
  4580.         priority tasks to override timer ticks, the tick interrupt
  4581.         handler issues an EOI before calling the scheduler. Later, the
  4582.         tick  task will (possibly indirectly) call the original BIOS tick
  4583.         handler, which again issues an EOI for an interrupt that is no
  4584.         longer pending. Although this should practically not pose any
  4585.         problems, since no other interrupts could normally be pending at
  4586.         this  time, and the EOI is not stored, it is theoretically
  4587.         possible for interrupts to be falsely acknowledged (at least
  4588.         that's what the books say).
  4589.  
  4590.         If you experience problems in special applications (especially if
  4591.         interrupt priorities have been reprogrammed), you may use the
  4592.         IFL_INT8_DIR installation flag. This flag changes the logic in
  4593.         the timer interrupt handler such that the original interrupt is
  4594.         called first, and no additional EOI is issued. You could also
  4595.         replace the timer-chaining logic with a routine that substitutes
  4596.         the BIOS timekeeping (use the BIOS listing as a reference). This,
  4597.         however, would preclude chaining to TSR's that have hooked the
  4598.         timer tick.
  4599.  
  4600.  
  4601.                                     Debugging
  4602.  
  4603.         Debugging CTask programs can be surprising. The debugger can't
  4604.         know  about the task structure of your program, and you can easily
  4605.         sit and wonder for hours why the debugger is behaving so
  4606.         strangely until it finally sinks down: the debugger itself can be
  4607.         preempted.
  4608.  
  4609.         The keyboard and timer interrupts are the main culprits. Both can
  4610.         hit during execution of debugger routines, so that data may be
  4611.         different from what you expect it to be. For example, if you are
  4612.         
  4613.         
  4614.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 77
  4615.  
  4616.  
  4617.         tracing through code that reads or writes a global variable that
  4618.         is also modified by another task, you may find that this variable
  4619.         has a completely different value when you dump it from the value
  4620.         that  was just loaded into a register on the last instruction
  4621.         trace. If you are using Periscope, be sure to let Periscope
  4622.         restore the INT 8 and INT 9 entries. This is not exactly pleasant
  4623.         when  you're using a foreign keyboard, but it can avoid a lot of
  4624.         trouble. If you're debugging at the application level, those
  4625.         precautions may not be necessary, but if you want to trace into
  4626.         the kernel routines, you must be extremely careful not to trash
  4627.         the debugger.
  4628.  
  4629.  
  4630.  
  4631.  
  4632.  
  4633.  
  4634.  
  4635.  
  4636.  
  4637.  
  4638.  
  4639.  
  4640.  
  4641.  
  4642.  
  4643.  
  4644.  
  4645.  
  4646.  
  4647.  
  4648.  
  4649.  
  4650.  
  4651.  
  4652.  
  4653.  
  4654.  
  4655.  
  4656.  
  4657.  
  4658.  
  4659.  
  4660.  
  4661.  
  4662.  
  4663.  
  4664.  
  4665.  
  4666.  
  4667.  
  4668.  
  4669.  
  4670.         
  4671.         
  4672.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 78
  4673.  
  4674.  
  4675.                           Changes from Previous Versions
  4676.  
  4677.  
  4678.         When  upgrading from previous versions, you have to recompile all
  4679.         modules that use any CTask functions or data structures. Due to
  4680.         the major changes in the control blocks, just re-linking is not
  4681.         sufficient.
  4682.  
  4683.  
  4684.                            Changes for CTask 1.2 to 2.0
  4685.  
  4686.         CTask 2.0 unifies the queue concept, and uses doubly-linked lists
  4687.         for all queues, including the task and timer queues. Although the
  4688.         overhead is slightly higher when inserting elements, the overall
  4689.         logic is greatly simplified, and removing elements from arbitrary
  4690.         points in a queue is a snap. To avoid a timing penalty for the
  4691.         new functionality, all low-level queue handling code was
  4692.         implemented in assembler.
  4693.  
  4694.         The new concept allows better support for the yield() operation,
  4695.         and it also allows an improved handling of timeout elements. With
  4696.         the 1.1/1.2 algorithm, it was not completely safe to process the
  4697.         timeout queue with interrupts enabled, and changes to the queue
  4698.         required great care. The new handling of the timeout queue, which
  4699.         is now sorted, and stores the tick difference to the previous
  4700.         element instead of an absolute count, decreases the amount of
  4701.         time  spent in the timeout loop. Watch elements, which still
  4702.         require stepping through all queue elements, have been separated
  4703.         from  timeouts. While the processing of the queue still has to be
  4704.         done  with interrupts disabled, the timeout/watch action now is
  4705.         completely uncritical.
  4706.  
  4707.         The changes to the queue structures required changes in nearly
  4708.         all modules. The main changes were in the tsksub, tsktimer, and
  4709.         tskasm modules, the tskque module was added.
  4710.  
  4711.  
  4712.                                 Interface Changes
  4713.  
  4714.         Version 2.0 introduces some changes in the interface. Since the
  4715.         changes only affect installation and previously unavailable
  4716.         functions, the impact on your programs should be minimal. If
  4717.         you're using a 1.2 pre-release, watch out for the changes in the
  4718.         name  search and ticker functions. The affected routines are
  4719.  
  4720.                 install_tasker
  4721.                         Two new parameters added. Late 1.2 pre-releases
  4722.                         implemented but ignored the "flags" parameter,
  4723.                         and recommended setting it to zero. This is no
  4724.                         longer true.
  4725.  
  4726.  
  4727.  
  4728.         
  4729.         
  4730.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 79
  4731.  
  4732.  
  4733.                 ctask_resident
  4734.                         New routine to check if CTask is already
  4735.                         resident.
  4736.  
  4737.                 find_name
  4738.                         Name changed from tsk_find_name, values for
  4739.                         "kind" parameter changed.
  4740.  
  4741.                 find_group_name
  4742.                         New routine for 1.1, in 1.2 this was called
  4743.                         tsk_find_group_name. Searches names within a
  4744.                         group. The "kind" parameter values changed.
  4745.  
  4746.                 yield
  4747.                         New routine, schedules with minimal priority.
  4748.                         Version 1.2 also had this, but using it could
  4749.                         lead to task starvation under certain conditions.
  4750.  
  4751.                 get_priority
  4752.                 set_funcs
  4753.                 set_user_ptr
  4754.                 get_user_ptr
  4755.                         New routines to access fields in the TCB.
  4756.  
  4757.                 create_ticker
  4758.                 delete_ticker
  4759.                 set_ticker
  4760.                 get_ticker
  4761.                         New routines for a simplistic time counter. Late
  4762.                         versions of 1.2 had similar functions with
  4763.                         different names, and different parameters.
  4764.  
  4765.                 create_timer
  4766.                         New optional parameter.
  4767.  
  4768.                 create_memory_watch
  4769.                 create_port_watch
  4770.                         New routines to create memory/port watch entries.
  4771.                         Some pre-release versions of 1.2 don't support
  4772.                         the last, optional, user pointer parameter.
  4773.  
  4774.                 wait_memory
  4775.                 wait_port
  4776.                         New routines to wait for memory/port changes.
  4777.  
  4778.                 delete_watch
  4779.                         New routine to delete watch element. Pre-release
  4780.                         versions of 1.2 equated this to delete_timer,
  4781.                         version 2.0 requires delete_watch to be
  4782.                         different.
  4783.  
  4784.                 set_counter
  4785.                         New routine to set counter to given value.
  4786.         
  4787.         
  4788.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 80
  4789.  
  4790.  
  4791.                 v24_flush_transmit
  4792.                         New routine in serial handler to flush transmit
  4793.                         pipe.
  4794.  
  4795.                 prt_flush
  4796.                         New routine in printer handler to flush output
  4797.                         pipe.
  4798.  
  4799.  
  4800.                 timout functions
  4801.                         The timeout function now is passed a parameter,
  4802.                         and is called with interrupts enabled.
  4803.  
  4804.                 assembler interface
  4805.                         All entry points now start with the usual
  4806.                         underline, since the extended language-specific
  4807.                         procedure definitions are used. The "scheduler"
  4808.                         entry was renamed to _tsk_scheduler to avoid
  4809.                         catastrophic results of typos.
  4810.  
  4811.                 internal functions
  4812.                         Previous versions defined most internal CTask
  4813.                         functions as far. This allowed calling them from
  4814.                         outside the CTask kernel (although that was never
  4815.                         recommended). The new version no longer allows
  4816.                         this, since internal functions are near relative
  4817.                         to the common CTask code segment.
  4818.  
  4819.  
  4820.                           Changes for CTask 1.1b to 1.2
  4821.  
  4822.         The never released version 1.2 added the concept of task groups,
  4823.         and the save/restore of internal DOS variables, to support
  4824.         spawning and TSR'ing CTask programs. The TSKDOS module went
  4825.         through several changes in the pre-release copies.
  4826.  
  4827.         All relevant global variables of CTask were grouped into a single
  4828.         structure, and are indirectly accessed through a pointer. This
  4829.         allows linkage between multiple copies of CTask, with automatic
  4830.         detection of other copies.
  4831.  
  4832.         This  change required adding new structures, and changing the task
  4833.         control block to accommodate the new group linkage and the space
  4834.         for the DOS variable swap.
  4835.  
  4836.         Also  new in 1.2 was the addition of a stack switch on entry to
  4837.         all interrupt handlers. This change was required to eliminate
  4838.         problems with TSR's, especially networks, and to support spawned
  4839.         programs that supply only a minimal amount of stack. CTask now
  4840.         allocates local stacks from a stack pool to hardware and software
  4841.         interrupt handlers. On entry to the scheduler, the task registers
  4842.         are no longer pushed on the stack, but instead are stored in the
  4843.         task  control block. This again mandated a change to the TCB.
  4844.         
  4845.         
  4846.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 81
  4847.  
  4848.  
  4849.         Support for memory and port watches that check the state of a
  4850.         memory location or an I/O port on every tick was added.
  4851.  
  4852.         A "ticker" structure that allows simple timeouts in polling tasks
  4853.         was introduced.
  4854.  
  4855.         Task  switch save/restore functions were added.
  4856.  
  4857.         The printer output driver was reworked, an an INT 17 interface
  4858.         driver has been added. The INT 15 printer output support was
  4859.         dropped.
  4860.  
  4861.         Resources to protect concurrent access to INT 10 and INT 13 were
  4862.         added in the TSKDOS module.
  4863.  
  4864.         The timer tick interrupt now supports both early and late INT 8
  4865.         chaining (and the INT9 stuff has finally been renamed to INT8).
  4866.         This  change was required to support network software that would
  4867.         time  out without really having waited long enough if the INT 8
  4868.         task  was postponed, and ticked a number of ticks at once. It can
  4869.         also  avoid incompatibilities with other software that does
  4870.         strange things in the timer interrupt. Installation of the new
  4871.         INT 8 handling is optional.
  4872.  
  4873.         Installation flags now allow on-line customization of some
  4874.         functions, especially the installation of some of the BIOS
  4875.         interrupts, and the INT 8 algorithm.
  4876.  
  4877.         The name-searching functions were augmented to better support
  4878.         searching local to groups, and searching groups.
  4879.  
  4880.         The make-files were cleaned up, and the Turbo C make-files
  4881.         changed to work with Borland's make.
  4882.  
  4883.         Support for the Turbo C Huge model was added, assembler files now
  4884.         load  the DS register when necessary.
  4885.  
  4886.         The placement of external definitions in the assembler files was
  4887.         changed to avoid the fixup errors that appeared when assembling
  4888.         with  TASM instead of MASM (thanks for H.J. Haug for pointing this
  4889.         out).
  4890.  
  4891.         All CTask routines are now allocated in a common code segment.
  4892.         This  allows calling local functions with a near call.
  4893.  
  4894.         All files were polished a bit, with a version number and change
  4895.         date  at the top. Comments have again been added. No warnings
  4896.         remain for Turbo and Microsoft with all warnings enabled.
  4897.  
  4898.         All files were affected, and some new files were added.
  4899.  
  4900.  
  4901.  
  4902.         
  4903.         
  4904.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 82
  4905.  
  4906.  
  4907.                           Changes for CTask 1.1 to 1.1b
  4908.  
  4909.         Release 1.1b fixed a minor bug in tskmain.c which prevented the
  4910.         main  task from being delayed.
  4911.  
  4912.         Thanks to Kent J. Quirk for reporting the bug.
  4913.  
  4914.         Release 1.1a was necessary to fix three severe and some minor
  4915.         bugs  in release 1.1. The bugs corrected in 1.1a were
  4916.  
  4917.            -  tskasm.asm:  Interrupts enabled too early in the scheduler
  4918.                           (severe)
  4919.            -  tskdos.asm:  Registers swapped in DOS version test (severe)
  4920.            -  tsksio.c:    Incorrect loop variable in v24_sio_initialise
  4921.                           (severe)
  4922.  
  4923.            -  tskmain.c:   Function tsk_dis_preempt missing
  4924.            -  tsksnap.c:   Incorrect format specification for continuation
  4925.                           line
  4926.            -  tskasm.asm:  Task state incorrect for eligible tasks
  4927.  
  4928.         Also  some minor changes to eliminate warnings, and changes to the
  4929.         test  files so they no longer use concurrent console output.
  4930.  
  4931.         A console output task was added ("conout.c" and "conout.h") as a
  4932.         sample for channeling console output through a single task.
  4933.  
  4934.         Some  changes suggested by Stephen Worthington were incorporated
  4935.         (pipe flush functions, better SIO transmit interrupt handling).
  4936.  
  4937.         Thanks to Peter Heinrich, Stephen Worthington, and Burt Bicksler
  4938.         for reporting the bugs.
  4939.  
  4940.  
  4941.                            Changes for CTask 0.1 to 1.1
  4942.  
  4943.         Thanks to Peter Heinrich, Tron Hvaring, and Dave Goodwin for
  4944.         their suggestions and the bug reports.
  4945.  
  4946.         The main changes were
  4947.  
  4948.            -  Support for named control blocks
  4949.            -  Support for dynamic allocation of control blocks and
  4950.              buffers
  4951.            -  Task state display support (snapshot dump)
  4952.            -  More flexible timer handling, interrupt disable times
  4953.              reduced
  4954.            -  SIO support extended for shared IRQ's and on-line
  4955.              definition of ports; save and restore of control
  4956.              registers
  4957.            -  Bug fixes for known bugs
  4958.  
  4959.  
  4960.         
  4961.         
  4962.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 83
  4963.  
  4964.  
  4965.         Affected files:
  4966.  
  4967.         TSKCONF.H   - new file, contains configuration options.
  4968.  
  4969.         TSK.H       - additional optional fields in most control
  4970.                       structures
  4971.                     - timer queue structure changed completely
  4972.                     - additional #defines and types for name and timer
  4973.                       control blocks
  4974.                     - tsk_inp, tsk_outp, tsk_dis_int, and tsk_ena_int
  4975.                       functions defined as intrinsics.
  4976.  
  4977.         TSKMAIN.C   - timeout queue handling, and support for timeout
  4978.                       blocks
  4979.                     - system tick interrupt chaining separated from
  4980.                       timeout
  4981.                     - minor changes to accommodate named and dynamic
  4982.                       structures.
  4983.  
  4984.         TSKSUB.C    - changes to the timeout-functions
  4985.                     - new routines for managing named structures.
  4986.  
  4987.         TSKSIO.C    - support for shared IRQ lines an dynamic definition
  4988.                       of ports was added
  4989.                     - complete status of the port is saved before
  4990.                       initialising, and optionally restored on removal of
  4991.                       the driver
  4992.                     - relative port number support added.
  4993.  
  4994.         TSKPRT.C    - relative port number support added.
  4995.  
  4996.         TSKBUF.C    - bug corrections.
  4997.  
  4998.         TSKALLOC.C  - new file, interface to memory allocation functions.
  4999.  
  5000.         TSKSNAP.C   - new file, provides snapshot dump of CTask state.
  5001.  
  5002.         TSKASM.ASM  - Partly runs with interrupts enabled, idle task
  5003.                       removed.
  5004.  
  5005.         TSKTIM.ASM  - cleanup, and changes to accommodate changes in
  5006.                       timeout logic.
  5007.  
  5008.         TSKBIOS.ASM - new file, handles the AT BIOS INT 15 wait/post
  5009.                       calls.
  5010.  
  5011.         Minor changes in other files to accommodate named and dynamic
  5012.         control blocks.
  5013.  
  5014.  
  5015.  
  5016.  
  5017.  
  5018.         
  5019.         
  5020.         Ctask Manual       - Version 2.0 - 89-12-21 -             Page 84
  5021.  
  5022.  
  5023.                                       Index
  5024.  
  5025.  
  5026.            AT_BIOS                            16
  5027.            BIOS                               20
  5028.            buffer                             44
  5029.            bufferptr                          44
  5030.            byte                               30
  5031.            byteptr                            30
  5032.            change_timer                       55
  5033.            check_buffer                       68
  5034.            check_counter                      63
  5035.            check_flag                         62
  5036.            check_mailbox                      65
  5037.            check_pipe                         67
  5038.            check_resource                     60
  5039.            check_wpipe                        67
  5040.            clear_counter                      63
  5041.            clear_flag                         61
  5042.            clear_flag_wait_set                62
  5043.            CLOCK_MSEC                         15
  5044.            CLOCK_MSEC                         52
  5045.            console                            20
  5046.            counter                            42
  5047.            counterptr                         42
  5048.            create_buffer                      67
  5049.            create_counter                     62
  5050.            create_flag                        61
  5051.            create_mailbox                     64
  5052.            create_memory_watch                56
  5053.            create_pipe                        65
  5054.            create_port_watch                  57
  5055.            create_resource                    59
  5056.            create_task                        50
  5057.            create_ticker                      53
  5058.            create_timer                       55
  5059.            create_wpipe                       65
  5060.            CRITICAL                           49
  5061.            ctask_resident                     47
  5062.            C_ENTER                            49
  5063.            C_LEAVE                            49
  5064.            c_read_buffer                      68
  5065.            c_read_pipe                        66
  5066.            c_read_wpipe                       66
  5067.            c_request_resource                 60
  5068.            c_schedule                         48
  5069.            c_wait_mail                        65
  5070.            c_write_buffer                     68
  5071.            c_write_pipe                       66
  5072.            c_write_wpipe                      66
  5073.            delete_buffer                      68
  5074.            delete_counter                     63
  5075.            delete_flag                        61
  5076.              
  5077.              
  5078.              Ctask Manual     - Version 2.0 - 89-12-21 -          Index 1
  5079.  
  5080.  
  5081.            delete_mailbox                     64
  5082.            delete_pipe                        66
  5083.            delete_resource                    60
  5084.            delete_ticker                      53
  5085.            delete_timer                       55
  5086.            delete_watch                       58
  5087.            delete_wpipe                       66
  5088.            DOS                                16
  5089.            DOS                                20
  5090.            dword                              30
  5091.            farptr                             30
  5092.            find_group_name                    48
  5093.            find_name                          47
  5094.            flag                               41
  5095.            flagptr                            41
  5096.            flush_pipe                         67
  5097.            flush_wpipe                        67
  5098.            funcptr                            30
  5099.            F_CRIT                             40
  5100.            F_STTEMP                           39
  5101.            F_TEMP                             39
  5102.            get_priority                       51
  5103.            get_ticker                         53
  5104.            get_user_ptr                       52
  5105.            GROUPS                             16
  5106.            group_rec                          40
  5107.            IBM                                16
  5108.            IFL_DISK                           46
  5109.            IFL_INT15                          46
  5110.            IFL_INT8_DIR                       46
  5111.            IFL_NODOSVARS                      46
  5112.            IFL_PRINTER                        46
  5113.            IFL_VIDEO                          45
  5114.            inc_counter                        63
  5115.            installation flags                 45
  5116.            install_tasker                     45
  5117.            keyboard                           20
  5118.            kill_task                          51
  5119.            mailbox                            43
  5120.            mailboxptr                         43
  5121.            msgptr                             43
  5122.            msg_header                         43
  5123.            NAMELENGTH                         36
  5124.            nameptr                            36
  5125.            namerec                            36
  5126.            pipe                               43
  5127.            pipeptr                            43
  5128.            pipe_free                          67
  5129.            preempt_off                        48
  5130.            preempt_on                         48
  5131.            PRI_INT8                           15
  5132.            PRI_STD                            15
  5133.            PRI_TIMER                          15
  5134.              
  5135.              
  5136.              Ctask Manual     - Version 2.0 - 89-12-21 -          Index 2
  5137.  
  5138.  
  5139.            prt_change_control                 76
  5140.            prt_complete                       76
  5141.            prt_flush                          76
  5142.            prt_install                        75
  5143.            prt_remove                         75
  5144.            prt_remove_all                     76
  5145.            prt_status                         76
  5146.            prt_wait_complete                  76
  5147.            prt_write                          76
  5148.            qelem_pri                          31
  5149.            queheadptr                         31
  5150.            queptr                             31
  5151.            queue                              31
  5152.            queue_head                         31
  5153.            read_buffer                        68
  5154.            read_pipe                          66
  5155.            read_wpipe                         66
  5156.            release_resource                   60
  5157.            remove_tasker                      46
  5158.            request_cresource                  60
  5159.            request_resource                   60
  5160.            resource                           42
  5161.            resourceptr                        42
  5162.            restore function                   37
  5163.            save function                      37
  5164.            schedule                           48
  5165.            sched_int                          50
  5166.            send_mail                          64
  5167.            set_counter                        63
  5168.            set_flag                           61
  5169.            set_funcs                          52
  5170.            set_priority                       51
  5171.            set_task_flags                     52
  5172.            set_ticker                         53
  5173.            set_user_ptr                       52
  5174.            SINGLE_DATA                        16
  5175.            spawn                              21
  5176.            start_task                         51
  5177.            stop_task                          51
  5178.            ST_DELAYED                         38
  5179.            ST_ELIGIBLE                        39
  5180.            ST_KILLED                          38
  5181.            ST_RUNNING                         39
  5182.            ST_STOPPED                         38
  5183.            ST_WAITING                         38
  5184.            tcb                                38
  5185.            tcbptr                             38
  5186.            TCMP_CHG                           33
  5187.            TCMP_EQ                            33
  5188.            TCMP_GE                            33
  5189.            TCMP_GES                           33
  5190.            TCMP_LE                            33
  5191.            TCMP_LES                           33
  5192.              
  5193.              
  5194.              Ctask Manual     - Version 2.0 - 89-12-21 -          Index 3
  5195.  
  5196.  
  5197.            TCMP_NE                            33
  5198.            TELEM_MEM                          32
  5199.            telem_memwatch                     35
  5200.            TELEM_PORT                         33
  5201.            telem_portwatch                    35
  5202.            telem_timeout                      35
  5203.            TELEM_TIMER                        32
  5204.            TFLAG_BUSY                         34
  5205.            TFLAG_TEMP                         34
  5206.            ticker                             41
  5207.            ticker                             53
  5208.            tick_ptr                           41
  5209.            TIMEOUT                            30
  5210.            Timeout/watch functions            54
  5211.            Timeouts                           52
  5212.            TKIND_COUNTER                      32
  5213.            TKIND_FLAG                         32
  5214.            TKIND_PROC                         32
  5215.            TKIND_TASK                         32
  5216.            TKIND_WAKE                         32
  5217.            tlink                              35
  5218.            tlinkptr                           35
  5219.            tsk_cli                            49
  5220.            tsk_dis_int                        49
  5221.            tsk_dis_preempt                    48
  5222.            TSK_DYNAMIC                        14
  5223.            tsk_ena_int                        49
  5224.            tsk_ena_preempt                    49
  5225.            tsk_inp                            49
  5226.            TSK_NAMED                          15
  5227.            TSK_NAMEPAR                        15
  5228.            tsk_outp                           49
  5229.            tsk_scheduler                      50
  5230.            tsk_sti                            49
  5231.            TSR                                21
  5232.            TSTAT_CONTWATCH                    34
  5233.            TSTAT_COUNTDOWN                    34
  5234.            TSTAT_IDLE                         34
  5235.            TSTAT_REMOVE                       34
  5236.            TSTAT_REPEAT                       34
  5237.            TSTAT_WATCH                        34
  5238.            TTIMEOUT                           30
  5239.            TWAKE                              30
  5240.            TWATCH                             30
  5241.            TYP_BUFFER                         36
  5242.            TYP_COUNTER                        36
  5243.            TYP_FLAG                           36
  5244.            TYP_MAILBOX                        36
  5245.            TYP_PIPE                           36
  5246.            TYP_RESOURCE                       36
  5247.            TYP_TCB                            36
  5248.            TYP_WPIPE                          36
  5249.            t_delay                            54
  5250.              
  5251.              
  5252.              Ctask Manual     - Version 2.0 - 89-12-21 -          Index 4
  5253.  
  5254.  
  5255.            t_keyhit                           69
  5256.            t_read_key                         69
  5257.            t_wait_key                         69
  5258.            user pointer                       37
  5259.            v24_change_baud                    71
  5260.            v24_change_dtr                     71
  5261.            v24_change_parity                  72
  5262.            v24_change_rts                     71
  5263.            v24_change_stopbits                72
  5264.            v24_change_wordlength              72
  5265.            v24_check                          73
  5266.            v24_complete                       74
  5267.            v24_define_port                    69
  5268.            v24_flush_receive                  74
  5269.            v24_flush_transmit                 74
  5270.            v24_install                        70
  5271.            v24_modem_status                   74
  5272.            v24_overrun                        74
  5273.            v24_protocol                       73
  5274.            v24_receive                        73
  5275.            v24_remove                         71
  5276.            v24_remove_all                     71
  5277.            v24_send                           73
  5278.            v24_wait_complete                  74
  5279.            v24_watch_modem                    72
  5280.            wait_counter_clear                 63
  5281.            wait_counter_set                   63
  5282.            wait_flag_clear                    62
  5283.            wait_flag_set                      61
  5284.            wait_mail                          64
  5285.            wait_memory                        57
  5286.            wait_pipe_empty                    66
  5287.            wait_port                          58
  5288.            wait_wpipe_empty                   66
  5289.            WAKE                               30
  5290.            wake_task                          51
  5291.            WATCH                              30
  5292.            word                               30
  5293.            wordptr                            30
  5294.            wpipe                              44
  5295.            wpipeptr                           44
  5296.            wpipe_free                         67
  5297.            write_buffer                       68
  5298.            write_pipe                         66
  5299.            write_wpipe                        66
  5300.            yield                              48
  5301.  
  5302.  
  5303.  
  5304.  
  5305.  
  5306.  
  5307.  
  5308.              
  5309.              
  5310.              Ctask Manual     - Version 2.0 - 89-12-21 -          Index 5
  5311.  
  5312.