home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / CPROG / CTASK22.ZIP / CTASK.DOC < prev    next >
Text File  |  1990-10-12  |  306KB  |  7,631 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.2  Released 90-10-12
  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                                                    2
  41.           An Example                                                    2
  42.             Switching the Context                                       2
  43.             You have Mail                                               3
  44.             Reentrancy and Resources                                    3
  45.             DOS Access                                                  4
  46.             Handling the Keyboard                                       4
  47.             Serial I/O and Timeouts                                     5
  48.             Priorities                                                  5
  49.           Change to your liking                                         5
  50.  
  51.         General Notes                                                   7
  52.           What can CTask NOT be used for?                               7
  53.           What is required to use CTask?                                7
  54.           Do I have to pay for using CTask?                             8
  55.           What support can I expect?                                    9
  56.           About this Release                                           10
  57.  
  58.         Multitasking Basics                                            11
  59.           Tasks                                                        11
  60.           Events                                                       11
  61.           Reentrancy                                                   12
  62.           Deadlocks                                                    13
  63.  
  64.         Using CTask                                                    15
  65.           Configuration Options                                        15
  66.           Memory Allocation                                            21
  67.           Snapshot                                                     21
  68.           Task Stacks                                                  22
  69.           Drivers                                                      22
  70.           Things to remember                                           23
  71.           Priority Handling                                            23
  72.  
  73.         Multitasking and DOS                                           25
  74.           Spawning and CTask TSR's                                     26
  75.           Task Groups                                                  27
  76.  
  77.         How does CTask work                                            29
  78.           Queues                                                       29
  79.           The Scheduler                                                30
  80.           Events                                                       30
  81.             Resources                                                  30
  82.             Flags                                                      31
  83.             Counters                                                   31
  84.             Mailboxes and Pipes                                        31
  85.           Serial and Printer Drivers                                   32
  86.  
  87.  
  88.         
  89.         
  90.         Ctask Manual       - Version 2.2 - 90-10-12 -          Contents 1
  91.  
  92.  
  93.         CTask Data Types                                               34
  94.           Other definitions                                            35
  95.           Typedefs used for simplified type specifications             36
  96.           Error return values for event wait functions                 37
  97.           Queues                                                       37
  98.           The timer/watch/hotkey control block                         38
  99.           The name link structure                                      43
  100.           The task control block structure                             43
  101.           Task states                                                  46
  102.           Task flags                                                   47
  103.           The Group Control Block                                      48
  104.           The event control blocks                                     49
  105.             The Ticker structure                                       49
  106.             The flag event structure                                   50
  107.             The counter event structure                                50
  108.             The resource event structure                               51
  109.             The mailbox event structure                                51
  110.             The pipe and word pipe event structure                     51
  111.             The buffer event structure                                 52
  112.             The call chain structure                                   53
  113.  
  114.         CTask Routines                                                 54
  115.           Global Variables                                             54
  116.           Installation and Removal                                     54
  117.           Searching for names                                          57
  118.           Adding names                                                 58
  119.           Remove Functions                                             58
  120.           Preemption and Scheduling                                    59
  121.           Miscellaneous                                                60
  122.           Task Operations                                              62
  123.           Timer Operations                                             64
  124.           Event wait Timeouts                                          65
  125.           "Tickers"                                                    65
  126.           Delays                                                       66
  127.           Timed Events, Watch Events, and Hotkeys                      66
  128.           Event Operations                                             75
  129.             Resources                                                  75
  130.             Flags                                                      77
  131.             Counters                                                   79
  132.             Mailboxes                                                  81
  133.             Pipes                                                      83
  134.             Buffers                                                    86
  135.           The Keyboard Handler                                         88
  136.           The Serial I/O handler                                       88
  137.           The Printer Output Driver                                    94
  138.           Support Modules                                              96
  139.             Memory Allocation Interface                                96
  140.             Printf replacements                                        97
  141.             Snapshot Dump                                             100
  142.  
  143.  
  144.  
  145.  
  146.         
  147.         
  148.         Ctask Manual       - Version 2.2 - 90-10-12 -          Contents 2
  149.  
  150.  
  151.         Advanced Topics                                               101
  152.           Primary and Secondary Kernels                               101
  153.           TSR, Spawning, and EMS                                      104
  154.           Functions called by Kernel Routines                         105
  155.  
  156.         Some notes on potential trouble spots                         107
  157.           Turbo C console output                                      107
  158.           The timer tick EOI                                          107
  159.           Debugging                                                   108
  160.  
  161.         Changes from Previous Versions                                109
  162.           Changes for CTask 2.1 to 2.2                                109
  163.             Version 2.2 Interface Changes                             111
  164.           Changes for CTask 2.0 to 2.1                                112
  165.             Version 2.1 Interface Changes                             115
  166.           Changes for CTask 1.2 to 2.0                                116
  167.             Version 2.0 Interface Changes                             116
  168.           Changes for CTask 1.1b to 1.2                               118
  169.           Changes for CTask 1.1 to 1.1b                               120
  170.           Changes for CTask 0.1 to 1.1                                120
  171.  
  172.  
  173.  
  174.  
  175.  
  176.  
  177.  
  178.  
  179.  
  180.  
  181.  
  182.  
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190.  
  191.  
  192.  
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.  
  204.         
  205.         
  206.         Ctask Manual       - Version 2.2 - 90-10-12 -          Contents 3
  207.  
  208.  
  209.                                 About this Manual
  210.  
  211.         If you are new to CTask, I would suggest reading all chapters
  212.         before attempting to build your first application. One chapter
  213.         you can skip is the CTask Data Types section, since you are not
  214.         required to know about the innards of CTask's structures. You can
  215.         also ignore the List of Changes.
  216.  
  217.         If you are updating from version 2.0, read the List of Changes,
  218.         and the new Advanced Topics section. The chapters on Data Types
  219.         and Routines, and the Using CTask section, also contain new
  220.         information. All other chapters are basically unchanged.
  221.  
  222.         Version 2.1 users will find little new information here. The
  223.         changes in the data structures, and the new routines, are
  224.         reflected here, but if you're short on paper, it should be
  225.         sufficient to print just the list of changes.
  226.  
  227.         If you are updating from an older release, the List of Changes at
  228.         the end is for you. You can safely skip the Introduction, and the
  229.         section on Multitasking Basics. In the General Notes, you should
  230.         read the section on support and the info about this release. In
  231.         the Using CTask section, check the new configuration options, and
  232.         the chapter on Memory Allocation. Check the Routine descriptions,
  233.         and, if you are using internal data structures directly, the Data
  234.         Type descriptions, for changes. The Advanced Topics section is
  235.         new.
  236.  
  237.  
  238.         Finally, a note to German speaking readers:
  239.  
  240.         Dieses Handbuch, wie auch die Kommentare im Quellcode, ist in
  241.         Englisch abgefaßt, da dies die universelle Sprache für Computer-
  242.         benutzer weltweit ist. Es gibt keine deutsche Version, und es
  243.         wird voraussichtlich auch keine geben (sofern nicht jemand bereit
  244.         ist einen angemessenen Betrag für eine Übersetzung auf den Tisch
  245.         des Hauses zu legen). Selbstverständlich bleibt es Ihnen
  246.         unbenommen, das Handbuch selbst zu übersetzen und diese Version
  247.         auch zu vertreiben, oder mir zum Vertrieb anzubieten. Wie die
  248.         Software ist auch dieses Handbuch Public Domain.
  249.  
  250.  
  251.  
  252.  
  253.  
  254.  
  255.  
  256.  
  257.  
  258.  
  259.  
  260.  
  261.  
  262.         
  263.         
  264.         Ctask Manual       - Version 2.2 - 90-10-12 -              Page 1
  265.  
  266.  
  267.                                    Introduction
  268.  
  269.         CTask is a set of routines that allow your C program to execute
  270.         functions in parallel, without you having to build in sophisti-
  271.         cated polling and switching schemes. CTask handles the switching
  272.         of processor time with a priority based, preemptive scheduler,
  273.         and provides a fairly complete set of routines for inter-task
  274.         communication, event signalling, and task interlocking. CTask
  275.         also includes a number of drivers for MS-DOS that build on the
  276.         basic functions to allow you to include serial I/O, printer
  277.         buffering, and concurrent access to DOS functions into your
  278.         programs with little programming effort.
  279.  
  280.  
  281.                                     An Example
  282.  
  283.         To illustrate one possible use of CTask, let me elaborate on the
  284.         following example. Say you just finished your nifty telecommuni-
  285.         cations program, complete with download protocols, scripts, and
  286.         everything.  But wouldn't it be nice to be able to print the file
  287.         you just downloaded while receiving the next, and edit a comment
  288.         to some previous message without interrupting the transmission?
  289.         So you take those editor routines from a previous project, plug
  290.         them in, and - oops, how do you switch back and forth between
  291.         editing, communication and printing? The answer to this is CTask.
  292.         CTask allows your C program to do many different things at the
  293.         same time by switching the processor between the tasks you de-
  294.         fine. And since most of the time your program is waiting for some
  295.         slow device (like the human hand) to provide feedback, this
  296.         switching is completely transparent, and will not noticeably slow
  297.         your program down.
  298.  
  299.  
  300.                               Switching the Context
  301.  
  302.         So what is needed to allow the user to edit a file while at the
  303.         same time downloading another and printing a third? First, you
  304.         have to have some form of "context switching". This means that
  305.         you have to be able to interrupt the processing of the download
  306.         when the user presses a key, process the key, and return to the
  307.         download "task" at the exact same point it was interrupted. One
  308.         solution to this would be to include a poll for the keyboard at
  309.         several points in the download routine, and call the editor task
  310.         when a key is available.  But apart from cluttering your code
  311.         with lots of unrelated calls, there is another problem. What if
  312.         the operation the user requested is more involved than just
  313.         putting the character on the screen, like writing the file to
  314.         disk? This might take so long that your download times out. There
  315.         must be a way to pass control back and forth between the two
  316.         tasks, such that no task is delayed for an extended period of
  317.         time, and also to activate the print spooler task at some defined
  318.         interval to output the data to the printer. This context
  319.         switching is called "scheduling" in CTask. The "scheduler" is
  320.         
  321.         
  322.         Ctask Manual       - Version 2.2 - 90-10-12 -              Page 2
  323.  
  324.  
  325.         invoked on every system timer tick, and will save the context of
  326.         the current task. The scheduler then takes the first element from
  327.         the queue of tasks that are eligible to be run, and restores the
  328.         context of this task, returning to the point where the task was
  329.         interrupted. This switching is completely automatic, and requires
  330.         no special programming in the tasks itself. All you have to do is
  331.         to tell CTask that there are three tasks, the download task, the
  332.         spooler task, and the editor task.
  333.  
  334.  
  335.                                   You have Mail
  336.  
  337.         All you have to do for context switching, that is. There's a bit
  338.         more to multitasking than meets the eye. How do you tell the
  339.         spooler task what files to spool, and the download task what
  340.         files to download? You can't call a task like an ordinary func-
  341.         tion, so what you need for this is "inter-task communication".
  342.         There must be a way to pass a message containing the filename to
  343.         be printed to the spooler task, and there are several in CTask,
  344.         one of them the "mailbox". The spooler can use a CTask call,
  345.         wait_mail, to wait for a message to arrive at its mailbox. As
  346.         long as nothing arrives, the spooler task will no longer be
  347.         scheduled, so if there is nothing to print, it will not use any
  348.         processor time. When you send a message with send_mail to the
  349.         mailbox, the spooler will wake up, and process the file. You can
  350.         also send more file name messages to the spooler while it still
  351.         prints a file, leaving the messages in the mailbox until the
  352.         spooler is ready to process the next file.
  353.  
  354.  
  355.                              Reentrancy and Resources
  356.  
  357.         This last example seems innocent enough, but there's a big stumb-
  358.         ling block hidden in it. You allocate the file name messages in
  359.         the controlling task with malloc, and you free them in the
  360.         spooler with free, no problem, right? Wrong, there is a big
  361.         problem, "reentrancy". Reentrancy means that you can re-enter a
  362.         routine while another task is already using it, and that this
  363.         will not disturb the operation of the interrupted task. But
  364.         malloc and free share and modify global data, the chain of free
  365.         memory blocks. Imagine the following: You just called malloc from
  366.         the controlling task. Malloc has loaded the address of a free
  367.         element into a local variable, and is about to write back the
  368.         pointer to the next free element into the last. At exactly this
  369.         moment, the timer ticks, and the spooler is activated. It has
  370.         just finished printing, so it calls free. Free steps through the
  371.         chain of free blocks to find the right place to insert the block.
  372.         According to Murphy's law, it will find just the place where
  373.         malloc is about to write back the pointer. Free coerces the
  374.         elements, points the next pointer to the element malloc just
  375.         wants to take off the chain, and returns. Malloc writes its next
  376.         pointer into the middle of the newly coerced block, and now re-
  377.         turns an element which is still in the free list. Compared to the
  378.         
  379.         
  380.         Ctask Manual       - Version 2.2 - 90-10-12 -              Page 3
  381.  
  382.  
  383.         job of finding this kind of bug, stepping in for Tantalus may
  384.         feel like a vacation. This kind of problem code is called a
  385.         "critical region". There must be a way to make sure that no two
  386.         tasks simultaneously enter such a region, and, you guessed it,
  387.         CTask provides one, the "resource". When you request a resource
  388.         in one task, all other tasks trying to request the same resource
  389.         after that are put to sleep until you call release_resource. Only
  390.         then will the highest priority task that waits for the resource
  391.         wake up, and get access to the protected region. So you would
  392.         have to substitute malloc and free calls in your routines with
  393.         calls to functions that first request a resource, execute the
  394.         function, and then release the resource.
  395.  
  396.  
  397.                                     DOS Access
  398.  
  399.         But, you might ask, isn't there another reentrancy problem in
  400.         this example, since both the spooler and the download task might
  401.         simultaneously call DOS to do their file-I/O, and DOS is not
  402.         reentrant? Do I have to substitute all my calls to fread and
  403.         fwrite, too? The answer to this, luckily, is no. CTask traps all
  404.         your DOS calls, and automatically encloses them in the necessary
  405.         resource request and release calls, so you don't have to worry
  406.         about trashing your disk by simultaneous DOS requests. The
  407.         limited multitasking capabilities of DOS are exploited to allow
  408.         some parallel processing in DOS, and CTask will also detect and
  409.         handle DOS calls by resident background programs like the DOS
  410.         PRINT utility.
  411.  
  412.  
  413.                               Handling the Keyboard
  414.  
  415.         CTask also allows you to circumvent DOS for keyboard input, so
  416.         that waiting for the keyboard will not block other tasks from
  417.         access to DOS functions. Previous versions of CTask used a "pipe"
  418.         to store all keyboard input. Starting with version 1.2, CTask
  419.         uses a "flag" to signal that keyboard input might be available. A
  420.         "flag" is another form of inter-task communication that just sig-
  421.         nals that some event occurred, without passing any specific data.
  422.         The reason for using flags in the keyboard handler is compati-
  423.         bility to TSR's. If a keyboard interrupt occurs, the interrupt
  424.         handler just sets a flag, and passes on the interrupt. The key-
  425.         board routines wait for this flag to be set, and then check the
  426.         keyboard buffer if a character has arrived. If the keyboard buf-
  427.         fer is empty, the flag is again cleared, and the keyboard rou-
  428.         tines put the waiting task to sleep again, so the processor is
  429.         free to do more interesting things than to loop waiting for the
  430.         user to press a key.
  431.  
  432.  
  433.  
  434.  
  435.  
  436.         
  437.         
  438.         Ctask Manual       - Version 2.2 - 90-10-12 -              Page 4
  439.  
  440.  
  441.                              Serial I/O and Timeouts
  442.  
  443.         The "pipe" is similar to the mailbox in that you can wait for
  444.         items to be sent to a pipe. But unlike mailboxes, pipes use their
  445.         own buffer to store the items (which are limited to bytes and
  446.         words), so you don't have to allocate mail blocks for each item.
  447.         When waiting on the pipe, your task is put to sleep, freeing the
  448.         processor. Pipes are used for the serial I/O handler included
  449.         with CTask that makes some of the work you've put into your
  450.         communications package obsolete. When outputting data to the
  451.         serial port via the CTask routines, the data is buffered in a
  452.         pipe, and incoming data is also placed in a pipe. All interrupt
  453.         handling, and the processing of modem status and XON/XOFF proto-
  454.         cols, is done by CTask, so you can concentrate on implementing
  455.         the higher level protocols. Since CTask allows all calls that
  456.         wait for pipes, mail, and other events, to specify a timeout that
  457.         is based on the system tick, you do not have to resort to timed
  458.         waiting loops to detect communication line faults. You simply
  459.         give a time limit on the wait call, and if that limit expires,
  460.         the wait routine will return with an error indication.
  461.  
  462.  
  463.                                     Priorities
  464.  
  465.         If the protocol you implement requires fast responses to incoming
  466.         blocks, you can influence the response of CTask to your comm
  467.         task's needs by giving this task a higher priority. CTask allows
  468.         65535 different priority levels, and tasks having higher priority
  469.         are scheduled before tasks with lower priority. Also, high prio-
  470.         rity tasks will get access to mail, pipes, and resources, before
  471.         other tasks. It might even be sensible to split the comm task
  472.         into two separate tasks, one of high priority that assembles the
  473.         incoming bytes into blocks and handles the protocol, and a lower
  474.         priority task that reads the received blocks from a mailbox and
  475.         stores them on the disk. In extremely time critical applications,
  476.         you can even turn off task preemption, so the timer tick will no
  477.         longer cause a task switch.
  478.  
  479.  
  480.                               Change to your liking
  481.  
  482.         CTask provides all basic building blocks for implementing
  483.         concurrent programs in an easy and comprehensible way. Since
  484.         CTask is mainly implemented in C, it may not be the fastest
  485.         possible system, but due to the straightforward design which uses
  486.         few shortcuts, modifying the sources to suit your needs and taste
  487.         can be done without weeks of studying assembler code that
  488.         squeezes every microsecond from the processor. CTask is public
  489.         domain code, and there are no restrictions on its use. It is
  490.         distributed in source form, so you are free to change all aspects
  491.         of the package. Multitasking programs, especially in embedded
  492.         applications, tend to be very diverse in their needs for specific
  493.         constructs. So although CTask is ready to run under DOS, and is
  494.         
  495.         
  496.         Ctask Manual       - Version 2.2 - 90-10-12 -              Page 5
  497.  
  498.  
  499.         easily adaptable for embedded applications, you should see CTask
  500.         more as a starting point for your own thoughts, and as a toolbox
  501.         from which you can pick the instruments you need, than as a
  502.         finished and fixed block of code you simply plug into your
  503.         application.
  504.  
  505.  
  506.  
  507.  
  508.  
  509.  
  510.  
  511.  
  512.  
  513.  
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529.  
  530.  
  531.  
  532.  
  533.  
  534.  
  535.  
  536.  
  537.  
  538.  
  539.  
  540.  
  541.  
  542.  
  543.  
  544.  
  545.  
  546.  
  547.  
  548.  
  549.  
  550.  
  551.  
  552.         
  553.         
  554.         Ctask Manual       - Version 2.2 - 90-10-12 -              Page 6
  555.  
  556.  
  557.                                   General Notes
  558.  
  559.  
  560.                          What can CTask NOT be used for?
  561.  
  562.         CTask is not intended to provide for multitasking on the command
  563.         level of MS-DOS. Although version 1.2 of CTask added the ability
  564.         to TSR and spawn other programs, and to communicate between
  565.         multiple copies of CTask, a full DOS-process management (which
  566.         would have to include keeping track of memory allocation and DOS
  567.         process control blocks) is not included. Adding this functio-
  568.         nality would not be trivial (although certainly worthwhile).
  569.  
  570.         CTask also is not a true "Real-Time" multitasking system. Due to
  571.         the completely dynamic structure of tasks and events, and the
  572.         minimal restrictions on what interrupt handlers may do, it is
  573.         nearly impossible to calculate a maximum interrupt or task switch
  574.         latency. If you have critical timing requirements, you should
  575.         consider getting a professional package like AMX. CTask has been
  576.         used successfully in embedded control applications, and if your
  577.         timing requirements are not that critical, or you're ready to
  578.         take up the task of measuring and calculating latencies with your
  579.         specific task setup, CTask may be useful even for Real-Time
  580.         applications. However, you're more or less on your own in this
  581.         field.
  582.  
  583.         And, there is no warranty that CTask does perform without errors,
  584.         or does exactly what you or I intended. So CTask should not be
  585.         used in applications in which malfunction of routines of this
  586.         package would result in damage to property or health of any
  587.         person without *very* extensive testing under all kinds of loads.
  588.         In using CTask, you do so at your own risk. I have tested CTask
  589.         extensively, but with a complex system like CTask, where timing
  590.         might make a big difference, you can't be completely sure that
  591.         all will work as intended.
  592.  
  593.  
  594.                           What is required to use CTask?
  595.  
  596.         To compile CTask, Microsoft C 5.1 or later, or Turbo C 2.0 or
  597.         later are required. Microsoft MASM 5.1 or later, or TASM 1.01 or
  598.         later is required for the assembler parts. Conversion to other
  599.         compilers is possible if they conform to the new ANSI standard.
  600.         Conversion of the assembler parts to other Assembler versions
  601.         will likely be more complicated, since it requires substitution
  602.         of the simplified model directives by explicit segment
  603.         definitions, and adding the DGROUP to offsets referencing data.
  604.  
  605.         Note that you can not use TASM 1.0 to assemble CTask routines.
  606.         The first version of TASM was not fully compatible with MASM, and
  607.         creates different code in some places, which will lead to fatal
  608.         crashes. TASM version 1.01 does not have this problem, and can
  609.         safely be used.
  610.         
  611.         
  612.         Ctask Manual       - Version 2.2 - 90-10-12 -              Page 7
  613.  
  614.  
  615.         The CTask modules have been compiled and tested with Microsoft C
  616.         6.0 without any apparent problems (Optimization level tested was
  617.         /Ox). Since the stability of the MSC 6.0 code generator is
  618.         doubtful, the distributed library was compiled with MSC 5.1.
  619.  
  620.         CTask will add 14k-25k of code to your program, depending on
  621.         options and installed drivers. The minimum static data used by
  622.         CTask is approximately 4k. Non-DOS versions use less memory.
  623.  
  624.         Converting CTask for stand-alone operation requires few changes.
  625.         Mainly, the timer interrupt handler (in "tsktim.asm") has to be
  626.         rewritten, and the initialization code (in "tskmain.c") may have
  627.         to be changed. Changes to other modules (naturally except the
  628.         optional hardware drivers) should not be necessary. The "DOS" and
  629.         "IBM" configuration flags in tskconf.h can be disabled to elimi-
  630.         nate most system-dependent features of CTask.
  631.  
  632.         Another requirement is a good debugger. If you never before wrote
  633.         multitasking applications, you're in for some surprises. The nor-
  634.         mal debugging tools (Symdeb, Codeview) are of only limited use,
  635.         since they use DOS calls for their I/O, and thus may conflict
  636.         with your background tasks. One safety measure is to first thor-
  637.         oughly test your program with preemption disabled, possibly
  638.         inserting some schedule() calls, and only allow task preemption
  639.         if you found most major bugs. I personally recommend Periscope
  640.         for debugging, since it can be made resident and so is always
  641.         available, and because it does not use DOS. Periscope IV is the
  642.         most expensive solution, and the best tool you can imagine, but
  643.         the less costly versions will also help a lot.
  644.  
  645.  
  646.                         Do I have to pay for using CTask?
  647.  
  648.         No. One reason for writing CTask was to provide a free, no
  649.         strings attached, utility, instead of the usual "for personal use
  650.         only" restriction. Writing a multitasking application for
  651.         personal use only doesn't seem too interesting to me. CTask is
  652.         completely free, and there is no restriction on its use. You may
  653.         incorporate all or parts of CTask in your programs, and redistri-
  654.         bute it in source or binary form by any means. I also do not
  655.         restrict the use of CTask in commercial applications. Since
  656.         trying to distribute the unmodified CTask for money will only
  657.         give you a bad name, you may even do that if you find someone
  658.         dumb enough to buy it. Naturally, if you make a bundle from it,
  659.         or simply like CTask, I would not reject a donation. However,
  660.         this is not required, and it will not give you any special
  661.         support.
  662.  
  663.  
  664.  
  665.  
  666.  
  667.  
  668.         
  669.         
  670.         Ctask Manual       - Version 2.2 - 90-10-12 -              Page 8
  671.  
  672.  
  673.                            What support can I expect?
  674.  
  675.         I will try my best to eliminate any bugs reported to me, and to
  676.         incorporate suggested enhancements and changes. However, my spare
  677.         time is limited, so I can not guarantee continued or individual
  678.         support. (But since I'm one of the owners of a consulting firm,
  679.         you can always hire me to do it...). Please address all reports
  680.         or questions to my business address:
  681.  
  682.                 Ferrari electronic GmbH
  683.                 attn: Thomas Wagner
  684.                 Beusselstrasse 27
  685.                 D-1000 Berlin 21, Germany
  686.  
  687.                 Phone: (+49 30) 396 50 21
  688.                 Fax:   (+49 30) 396 80 20
  689.  
  690.                 BIX:   twagner
  691.                 UUCP:  oeschi@netmbx.UUCP (attn: Thomas Wagner)
  692.  
  693.  
  694.         But, please, if at all possible, do it in writing. Please do not
  695.         phone unless it is absolutely vital (or you have a business
  696.         proposal). I like to hear about any applications for CTask, and
  697.         if you are visiting Berlin, I also invite you to drop by for a
  698.         talk. But I am usually not that happy when I am interrupted in my
  699.         paid work by a phone call requesting support for a free product.
  700.  
  701.         I will try to answer all letters and Faxes I receive. However, I
  702.         am usually not the fastest in this respect, so please be patient.
  703.         If you don't hear for me for a while, send me a short reminder.
  704.         The same goes for UUCP E-mail, since I'm not directly connected.
  705.         The preferred, and the fastest, method to reach me is through
  706.         BIX.
  707.  
  708.         BIX (tm) is the BYTE Information Exchange, an electronic confe-
  709.         rencing system created by McGraw-Hill, the publishers of the well
  710.         renowned BYTE magazine. BIX can be (and is) accessed from all
  711.         parts of the world. Although accessing BIX from outside the US
  712.         isn't exactly cheap (don't ask me what I have to pay each month),
  713.         the wealth of information available there, and the fast and
  714.         extensive help the other members can give you on all kinds of
  715.         hard- and software problems, makes it worth every Mark, Peseta,
  716.         Franc, or Ruble you have to spend. New versions and updates of
  717.         CTask will first appear on BIX.
  718.  
  719.         At the time of this writing, I am one of the moderators of the
  720.         IBM exchange on BIX, moderating the "ibm.other" conference. I
  721.         have created a support topic for CTask, where all suggested
  722.         enhancements and changes, plus bug reports, can be posted. Just
  723.         join "ibm.other", topic "ctask". You can also report problems of
  724.         limited general interest via BIXmail to "twagner". Unless I am
  725.         not able to reach the keyboard for some reason, I log on at least
  726.         
  727.         
  728.         Ctask Manual       - Version 2.2 - 90-10-12 -              Page 9
  729.  
  730.  
  731.         once per day, so you can expect relatively fast responses to your
  732.         queries.
  733.  
  734.         To get more info on joining BIX, call the BIX Customer Service at
  735.         800-227-2983 (U.S. and Canada), or 603-924-7681 (New Hampshire
  736.         and outside the U.S.) from 8:30 to 23:00 Eastern Time (-5 GMT).
  737.         BIX access currently is $39 for three months (flat fee, no extra
  738.         charges for connect time), plus the applicable telecomm charges
  739.         (Tymnet in the U.S. and Canada, your local PTT's Packet Net
  740.         charges from outside the U.S.). If you're calling from the US,
  741.         you can subscribe by dialling BIX direct at 617-861-9767. Hit the
  742.         return key, and enter "bix" at the 'login (enter "bix")' prompt.
  743.         At the 'Name?' prompt, enter "bix.flatfee". International users
  744.         living near a BT Tymnet node can access BIX through international
  745.         Tymnet at special low rates. Call the BIX helpline for Tymnet
  746.         access points and charges. Other international users will need an
  747.         account (NUI) with their local packet net. Please enquire at your
  748.         post/telecomm office for details. If you already own a NUI, enter
  749.         the BIX international network address (NUA), "310690157800", and
  750.         enter "bix.flatfee" at the 'Name?' prompt.
  751.  
  752.  
  753.                                 About this Release
  754.  
  755.         Since the Beta release of CTask in March 1988, CTask has found
  756.         widespread distribution through several channels. I have heard
  757.         from some users, and their suggestions have been implemented in
  758.         this version as far as possible.
  759.  
  760.         Special thanks go to Kent J. Quirk, Peter Heinrich, Stephen
  761.         Worthington, Burt Bicksler, Tron Hvaring, Joe Urso, Dave Goodwin,
  762.         Chris Blum, and Dan Heine, for their bug reports, suggestions,
  763.         and enhancements. Bug reports and suggestions also came in from
  764.         others, thanks to all who wrote or called. The serial code in
  765.         TSKSIO.C was enhanced for version 2.0 by S. Worthington, and his
  766.         ideas on debugging have been incorporated in the version 2.1
  767.         debugging mode. Dan Heine provided valuable info on 80x87 numeric
  768.         coprocessor support. Chris Blum wrote the integer-based
  769.         millisecond to clock-tick conversion routine.
  770.  
  771.         Again, please notify me of your CTask application, report bugs,
  772.         or suggest changes and enhancements. If I know you're using
  773.         CTask, I can notify you of possible new releases and of possible
  774.         severe bugs.
  775.  
  776.  
  777.  
  778.  
  779.  
  780.  
  781.  
  782.  
  783.  
  784.         
  785.         
  786.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 10
  787.  
  788.  
  789.                                Multitasking Basics
  790.  
  791.                                       Tasks
  792.  
  793.         In CTask, a "task" is defined as a (far) C function. The number
  794.         of tasks is not limited, and one function may be used for several
  795.         tasks. There is little difference between a task function and a
  796.         normal function. The usual form of a task function is
  797.  
  798.              void Taskfunc my_task (farptr arg)
  799.              {
  800.                   one-time initialization code
  801.                   while (TRUE)
  802.                     {
  803.                     processing code
  804.                     }
  805.              }
  806.  
  807.         A task function is (usually) never called directly. Rather, it is
  808.         specified in the call to the create_task routine, and started by
  809.         start_task. It will then continue to run, sharing the processor
  810.         time with all other tasks, until it is "killed" by kill_task.
  811.         Returning from the routine will have the same effect as a kill.
  812.         The sharing of processor time is accomplished by "preempting" the
  813.         tasks. Preemption means that the task is interrupted in the
  814.         middle of some statement by a hardware interrupt (usually the
  815.         timer), and is *not* immediately restarted when the interrupt
  816.         handler returns. Instead, the next task that is able to run is
  817.         activated by the "scheduler", with the interrupted task
  818.         continuing its duty at some (normally unpredictable) later time.
  819.         You can also have multi-tasking without preemption, and CTask
  820.         supports this, too, but this requires full cooperation of all
  821.         tasks in the system, such that no task continues to run for an
  822.         extended period of time without passing control to other tasks by
  823.         an explicit scheduling request, or by waiting for an event.
  824.  
  825.         The optional argument to the task function may be used if one
  826.         function is to be used for more than one task, for example to
  827.         pass a pointer to a static data area for use by this specific
  828.         instance of the function.
  829.  
  830.  
  831.                                       Events
  832.  
  833.         Tasks alone would be of limited use. If you have several routines
  834.         which just do number crunching or sorting or such, making them
  835.         into parallel tasks would be sensible only on a multiprocessor
  836.         system. Normally, at least some of your tasks will wait for some
  837.         outside "event" to happen, be it the user pressing a key, or a
  838.         character arriving from the modem. Then there may be tasks which
  839.         have to wait until another task finishes processing on some piece
  840.         of data before they can continue. For this synchronization, there
  841.         are a number of constructs in CTask, which I summarize under the
  842.         
  843.         
  844.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 11
  845.  
  846.  
  847.         name "event". Common to all events are the operations of waiting
  848.         for an event to happen, and signalling that the event has
  849.         happened. Using a CTask event is much more efficient than looping
  850.         while waiting on some shared data location to change state, and
  851.         also eliminates concurrency problems inherent in such a simple
  852.         approach. Tasks waiting for an event are taken off the scheduler
  853.         queue, so they no longer use processor time.
  854.  
  855.  
  856.                                     Reentrancy
  857.  
  858.         One of the biggest problem with multitasking in general, and C on
  859.         the PC in particular, is reentrancy. Reentrancy means that you
  860.         can use a routine, be it you own, or one of the C run-time
  861.         library, from different tasks at the same time. When writing your
  862.         own code, you can easily avoid problems, but when using the run-
  863.         time library routines, you often can only guess if the routines
  864.         are reentrant or not.
  865.  
  866.         A routine is NOT reentrant if it modifies static data. This can
  867.         be illustrated by the following nonsense example:
  868.  
  869.              int non_reentrant (int val)
  870.              {    static int temp;
  871.                   temp = val;
  872.                   return temp * 2;
  873.              }
  874.  
  875.         Now take two tasks, which call this routine. Task1 calls it with
  876.         val=3, Task2 with val=7. What will be the return value for both
  877.         tasks? You never know. There are three possible outcomes:
  878.  
  879.           1) The tasks execute sequentially. Task1 will get 6, and Task2
  880.              14 as a result. This is what one normally expects.
  881.  
  882.           2) Task1 runs up to "temp = val", then is interrupted by the
  883.              timer. Task2 executes, and gets 14 as result. Then Task1
  884.              continues. Return for Task1 is 14.
  885.  
  886.           3) Task2 runs up to "temp = val", then is interrupted by the
  887.              timer. Task1 executes, and gets 6 as result. Then Task2
  888.              continues. Return for Task2 is 6.
  889.  
  890.         add to this the effects of optimization, and a loop, and the
  891.         outcome is completely random.
  892.  
  893.         Most routines in the C library will not explicitly do something
  894.         like this, but all functions that
  895.  
  896.              - do file I/O (read, write, printf, scanf, etc.) or
  897.              - change memory allocation (malloc, free, etc.)
  898.  
  899.  
  900.         
  901.         
  902.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 12
  903.  
  904.  
  905.         have to use some static data to do buffering, or to store the
  906.         chain of memory blocks in. Interrupting such an operation may
  907.         have disastrous effects. The most devilish aspect of non-
  908.         reentrancy is that the effects are unpredictable. Your program
  909.         may run 1000 times without any error, and then on the 1001th time
  910.         crash the system so completely that only the big red switch will
  911.         help.
  912.  
  913.         So what can you do about it? A lot. There are several ways to
  914.         protect "critical regions" from being entered in parallel. The
  915.         most simple method is to disable interrupts. This, however,
  916.         should be used only for *very* short periods of time, and not for
  917.         rou-tines that might themselves re-enable them (like file-I/O). A
  918.         better method is to temporarily disable task preemption. The
  919.         routines tsk_dis_preempt and tsk_ena_preempt allow this form of
  920.         short-term task switch disable. Interrupts may still be
  921.         processed, but tasks will not be preempted. The best way is to
  922.         use a "resource". A resource is a special kind of event, which
  923.         only one task can possess at a time. Requesting the resource
  924.         before entering the routine, and releasing it afterwards, will
  925.         protect you from any other task simultaneously entering the
  926.         critical region (assuming that this task also requests the
  927.         resource).
  928.  
  929.         It is also reasonably safe to use file-I/O without protection if
  930.         it goes to different files. The C file control blocks for
  931.         different files are distinct, so there will be no conflict
  932.         between tasks. Since DOS access is automatically protected by
  933.         CTask, concurrent file I/O is possible.
  934.  
  935.         What you may NEVER do is to use a non-reentrant routine that is
  936.         not protected by an interrupt disable from an interrupt handler.
  937.         An interrupt handler is not a task, and so can not safely request
  938.         a resource or disable task preemption. This is the reason why the
  939.         CTask routines generally disable interrupts before manipulating
  940.         the internal queues rather than only disabling task preemption.
  941.  
  942.  
  943.                                     Deadlocks
  944.  
  945.         One thing to watch out for when using resources or similar event
  946.         mechanisms is not to get into a situation where Task 1 waits for
  947.         a resource that Task 2 has requested, while at the same time Task
  948.         2 waits for a resource that Task 1 already has. This situation is
  949.         called a deadlock (or, more picturesque, deadly embrace), and it
  950.         can only be resolved with outside help (e.g. waking up one of the
  951.         tasks forcibly). To illustrate, consider the following example:
  952.  
  953.  
  954.  
  955.  
  956.  
  957.  
  958.         
  959.         
  960.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 13
  961.  
  962.  
  963.              void far task_1 ()
  964.              {
  965.                ...
  966.                request_resource (&rsc1, 0L);
  967.                request_resource (&rsc2, 0L);
  968.                ...
  969.              }
  970.  
  971.              void far task_2 ()
  972.              {
  973.                ...
  974.                request_resource (&rsc2, 0L);
  975.                request_resource (&rsc1, 0L);
  976.                ...
  977.              }
  978.  
  979.         Since interrupts are always enabled on return from a task switch,
  980.         even if the statements are enclosed in a critical region, there
  981.         is no guarantee that the request_resource calls will be executed
  982.         without interruption. In this example, the problem is obvious,
  983.         but in a more complex application, where resource requests or
  984.         other waits might be buried in some nested routine, you should
  985.         watch out for similar situations. One way to avoid problems would
  986.         be in this example to change task_2 to
  987.  
  988.              void far task_2 ()
  989.              {
  990.                   int again;
  991.                   ...
  992.                   do {
  993.                        request_resource (&rsc2, 0L);
  994.                        if (again = c_request_resource (&rsc1))
  995.                           {
  996.                           release_resource (&rsc2);
  997.                           delay (2L);
  998.                           }
  999.                      } while (again);
  1000.                   ...
  1001.              }
  1002.  
  1003.         Note that this is only one of many possible approaches, and that
  1004.         this approach favors task_1 over task_2.
  1005.  
  1006.         You should also take care not to kill tasks that currently own a
  1007.         resource. CTask will not detect this, and the resource will never
  1008.         be freed.
  1009.  
  1010.  
  1011.  
  1012.  
  1013.  
  1014.  
  1015.  
  1016.         
  1017.         
  1018.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 14
  1019.  
  1020.  
  1021.                                    Using CTask
  1022.  
  1023.         CTask comes archived with both source and binaries. The binary
  1024.         version is compiled in the large model, but since the precompiled
  1025.         kernel routines don't use any functions from the C library, you
  1026.         can use all functions in small or other model programs (except
  1027.         Turbo C's Tiny and Huge models). The include files provided
  1028.         specify all model dependencies, so you don't have to use the
  1029.         large model for your application, but always remember to include
  1030.         "tsk.h" for the type definitions and function prototypes.
  1031.  
  1032.         The C source files will work without changes for both Microsoft
  1033.         and Turbo C. The library files are not compatible, so use
  1034.         "ctaskms.lib" for Microsoft, and "ctasktc.lib" for Turbo C.
  1035.  
  1036.         In the distributed configuration (i.e. dynamic allocation of
  1037.         control blocks enabled), the file TSKALLOC.C must be added to the
  1038.         library or separately linked after compiling it *in the same
  1039.         model as the main program*. This file uses C-library routines,
  1040.         and thus must match the main program's memory model. The same
  1041.         goes for TSKSNAP.C, an optional snapshot-dump utility, and
  1042.         CONOUT.C, the sample console output handler. The provided
  1043.         "ctsupms.lib" and "ctsuptc.lib" files have been compiled in the
  1044.         large model, and may only be used with large model programs.
  1045.  
  1046.         Turbo C's huge model uses a different segment setup for data
  1047.         segments. This requires using a special data segment for all
  1048.         CTask data, and compilation of the CTask kernel in huge model.
  1049.         For the assembler files, the symbol TC_HUGE must be defined
  1050.         during assembly, the C files must be compiled with the Data-
  1051.         Segment and BSS-Segment naming options. Make-files for Turbo C
  1052.         Huge model are included.
  1053.  
  1054.  
  1055.                               Configuration Options
  1056.  
  1057.         The file TSKCONF.H contains a number of #define's that allow you
  1058.         to configure some CTask features. In general, you should
  1059.         recompile all of CTask when changing one of the flags. Version
  1060.         2.1 collects all configuration options for both Assembler and C
  1061.         in this file.
  1062.  
  1063.         The entries are
  1064.  
  1065.         CODE_SHARING
  1066.              If TRUE, the generated kernel supports code sharing. This
  1067.              requires the entry points to load DS on entry, and compi-
  1068.              lation with Large model (MSC) or Huge model (TC).
  1069.  
  1070.              This option is normally disabled (FALSE).
  1071.  
  1072.  
  1073.  
  1074.         
  1075.         
  1076.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 15
  1077.  
  1078.  
  1079.         NEAR_CODE
  1080.              If TRUE, all CTask routines are 'near'. Use only with small
  1081.              or compact model. You will have to change the make-files so
  1082.              the compiler model is no longer Large, and the code segment
  1083.              is not named, when turning on this flag. The default is
  1084.              FALSE. Setting this option TRUE will save code, and make
  1085.              calls faster, but the library will no longer be model
  1086.              independent.
  1087.  
  1088.              This option is normally disabled (FALSE).
  1089.  
  1090.         LOCALS_FAR
  1091.              If TRUE, internal CTask routines ar 'far'. This might be
  1092.              necessary if your compiler/linker does not allow placing all
  1093.              CTask kernel code in a common segment. Do not set this flag
  1094.              if NEAR_CODE is set.
  1095.  
  1096.              This option is normally disabled (FALSE).
  1097.  
  1098.         CALL_PASCAL
  1099.              Use Pascal calling sequence for CTask routines.  This may
  1100.              save some code, but may cause naming conflicts if your
  1101.              compiler limits external Pascal names to 8 characters.
  1102.  
  1103.              This option is normally disabled (FALSE).
  1104.  
  1105.         TC_HUGE
  1106.              (Assembler only) Define TC_HUGE for use with the Turbo C
  1107.              Huge model, and if it is desired to separate CTask's data
  1108.              from the normal data segment. This flag causes the
  1109.              CTASK_DATA segment to be defined, (class is DATA) and DS to
  1110.              be loaded with this segment on function entry. The C
  1111.              functions in the CTask kernel must be compiled to use the
  1112.              same data segment.
  1113.  
  1114.              This option is normally disabled (undefined).
  1115.  
  1116.         LOAD_DS
  1117.              (Assembler only) Define LOAD_DS to reload the data segment
  1118.              on entry to global functions. This flag must be defined for
  1119.              TC_HUGE. It can also be defined if the data segment can not
  1120.              safely be assumed to be loaded in DS on function entry, for
  1121.              example if the code sharing feature of version 2.1 is used.
  1122.              The C routines must be compiled with the necessary compiler
  1123.              switches or the _loadds keyword in this case.
  1124.  
  1125.              This option is normally disabled (undefined).
  1126.  
  1127.  
  1128.  
  1129.  
  1130.  
  1131.  
  1132.         
  1133.         
  1134.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 16
  1135.  
  1136.  
  1137.         ROM_CODE
  1138.              (Assembler only) Define ROM_CODE TRUE for embedded systems
  1139.              using ROM-based code. This option disables storing variables
  1140.              in the code segment in some modules. Note that most DOS-
  1141.              related modules are not ROMable.
  1142.  
  1143.              This option is normally disabled (FALSE).
  1144.  
  1145.         FAR_STACK
  1146.              (Assembler only) Define FAR_STACK TRUE to save some space in
  1147.              the default DGROUP. With this define TRUE, the local stacks
  1148.              for the scheduler, the timer, and the interrupt handlers,
  1149.              are allocated in a separate segment. With Turbo C, you may
  1150.              have to edit the "c0.asm" startup module to accomodate the
  1151.              new segment.
  1152.  
  1153.              This option is normally disabled (FALSE).
  1154.  
  1155.         TSK_DYNAMIC
  1156.              If TRUE, you can let CTask dynamically create task and event
  1157.              control blocks, task stacks, and pipe buffers, by passing
  1158.              NULL as the block address. Since this requires the C runtime
  1159.              allocation calls, it is not suitable for non-DOS appli-
  1160.              cations (except if you provide your own memory allocation
  1161.              routines).
  1162.  
  1163.              This option is normally enabled (TRUE).
  1164.  
  1165.         TSK_DYNLOAD
  1166.              If FALSE, this instance of the kernel does not include
  1167.              dynamic allocation routines. Setting this flag to FALSE when
  1168.              TSK_DYNAMIC is TRUE only makes sense with multiple linked
  1169.              kernels. A resident kernel might not employ dynamic
  1170.              allocation, whereas a secondary kernel needs it. In this
  1171.              situation, TSK_DYNAMIC must be set in the primary so that
  1172.              the task kill code is included and the kernel configurations
  1173.              match, but TSK_DYNLOAD may be false to prevent inclusion of
  1174.              the malloc/free run-time routines. This option has no effect
  1175.              if TSK_DYNAMIC is FALSE. The default is TRUE.
  1176.  
  1177.              This option is normally enabled (TRUE).
  1178.  
  1179.         TSK_NAMEPAR
  1180.              If TRUE, all create_xxx calls accept an additional
  1181.              parameter, the name of the created control block. This name
  1182.              should contain only printeable characters, and should not be
  1183.              longer than 8 characters plus the zero terminator. This
  1184.              option is used together with TSK_NAMED (see below).
  1185.  
  1186.              This option is normally enabled (TRUE).
  1187.              It must be enabled for DOS.
  1188.  
  1189.  
  1190.         
  1191.         
  1192.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 17
  1193.  
  1194.  
  1195.         TSK_NAMED
  1196.              If TRUE, all control blocks (except timer control blocks)
  1197.              are named and linked on creation. This allows the snapshot
  1198.              dump routine to display the system state, and also allows
  1199.              linking to control blocks from secondary kernels.
  1200.              TSK_NAMEPAR must be defined for this option to work. Since
  1201.              it may be desirable to switch off the handling of the names
  1202.              after the debugging phase, without having to change all
  1203.              create_xxx calls to omit the name parameter, the name
  1204.              parameter is ignored if TSK_NAMED is undefined, but
  1205.              TSK_NAMEPAR is defined.
  1206.  
  1207.              This option is normally enabled (TRUE).
  1208.              It must be enabled for DOS.
  1209.  
  1210.         GROUPS
  1211.              If enabled, task groups, i.e. multiple invocations of CTask,
  1212.              are supported.
  1213.  
  1214.              This option is normally enabled (TRUE).
  1215.              It must be enabled for DOS.
  1216.  
  1217.         CLOCK_MSEC
  1218.              If TRUE, all timeouts are specified in milliseconds instead
  1219.              of timer ticks. This allows programming of delays and
  1220.              timeouts independent of the speedup-parameter or the system
  1221.              tick rate.
  1222.  
  1223.              This option is normally disabled (FALSE).
  1224.  
  1225.         PRI_TIMER
  1226.              Specifies the priority of the timer task. Normally the timer
  1227.              task should have a higher priority than any other task in
  1228.              the system.
  1229.  
  1230.              The value is normally 0xf000.
  1231.  
  1232.         PRI_STD
  1233.              This value may be used in your programs as the standard
  1234.              priority of user tasks. Its value is arbitrary. It is not
  1235.              used in the kernel except for the definition of PRI_INT9
  1236.              (see below).
  1237.  
  1238.              The value is normally 100 (decimal).
  1239.  
  1240.  
  1241.  
  1242.  
  1243.  
  1244.  
  1245.  
  1246.  
  1247.  
  1248.         
  1249.         
  1250.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 18
  1251.  
  1252.  
  1253.         PRI_INT8
  1254.              Determines the priority of the "int8"-task. This task chains
  1255.              to the previous interrupt vector for the sytem timer tick,
  1256.              and thus may activate resident TSR's. Since TSR's normally
  1257.              use polling when accessing the keyboard and other devices,
  1258.              the priority of the int8-task should be equal to or lower
  1259.              than normal user-defined tasks to allow your program to con-
  1260.              tinue to run while the TSR is active. You can tune this
  1261.              value so that some tasks are blocked by the TSR to avoid
  1262.              trashing the screen.
  1263.  
  1264.              The value is normally  PRI_STD.
  1265.  
  1266.         AT_BIOS
  1267.              If enabled, the AT BIOS wait/post handler is installed. May
  1268.              be disabled when compatibility problems arise. You can also
  1269.              disable installation of this handler with an install flag in
  1270.              the install_tasker call, but using the configuration flag
  1271.              will save some code. Embedded systems likely will use FALSE.
  1272.  
  1273.              This option is normally enabled (TRUE).
  1274.  
  1275.         INT8_EARLY
  1276.              If TRUE, the timer interrupt always uses early INT8 proces-
  1277.              sing, regardless of the IFL_INT8_EARLY installation flag.
  1278.              Setting this flag saves some code and data, but eliminates
  1279.              some flexibility. Under DOS, timer ticks can be missed under
  1280.              certain circumstances when set, so DOS based configurations
  1281.              always should use FALSE. The installation flag has a
  1282.              slightly different effect, and may be used under DOS with no
  1283.              adverse effects. Embedded systems likely will always use
  1284.              TRUE.
  1285.  
  1286.              This option is normally disabled (FALSE).
  1287.  
  1288.         INT8_LATE
  1289.              If TRUE, the timer interrupt always uses late INT8 proces-
  1290.              sing, regardless of the IFL_INT8_EARLY installation flag.
  1291.              Setting this flag saves some code, but eliminates some
  1292.              flexibility. Embedded systems likely will always use FALSE.
  1293.  
  1294.              This option is normally disabled (FALSE).
  1295.  
  1296.         IBM
  1297.         DOS
  1298.              Both IBM and DOS are more or less of informative value only,
  1299.              to point out those areas in the kernel that need attention
  1300.              when converting to non-IBM or non-DOS environments.
  1301.              Disabling one or both of this options requires the
  1302.              substitution of your own routines for installation, timer,
  1303.              and keyboard handling.
  1304.  
  1305.              Both options must normally be enabled (TRUE).
  1306.         
  1307.         
  1308.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 19
  1309.  
  1310.  
  1311.         SINGLE_DATA
  1312.              If enabled, only a single global data block is used. This
  1313.              speeds up processing, but prohibits linkage of multiple
  1314.              groups. Useful for dedicated systems, and also if your
  1315.              program is known to never interact with another copy of
  1316.              CTask. Should be left FALSE if you're not so sure, must be
  1317.              FALSE if GROUPS is enabled. The current version of the DOS
  1318.              handler requires GROUPS to be used, so it should only be
  1319.              TRUE for embedded systems.
  1320.  
  1321.              This option is normally disabled (FALSE).
  1322.  
  1323.         EMS
  1324.              If TRUE, EMS support is included. For DOS applications using
  1325.              spawn or going TSR, this should always be TRUE, unless it is
  1326.              known that the program will never be executed in an EMS
  1327.              environment. It must also be TRUE for programs using EMS.
  1328.  
  1329.              This option is normally enabled (TRUE).
  1330.  
  1331.         EMS_SAVE_SIZE
  1332.              Size of the EMS page info save area. For LIM 4.0 drivers,
  1333.              only four pages are saved, so 16 bytes should be sufficient.
  1334.              If the partial page map function is not available in the
  1335.              driver, more space may be required for holding the full page
  1336.              map.
  1337.  
  1338.              The value is normally 16.
  1339.  
  1340.         NDP
  1341.              If TRUE, 80x87 support is included. If this option is
  1342.              enabled, and no coprocessor is present, the machine can hang
  1343.              if the BIOS equipment configuration is set incorrectly.
  1344.              NOTE: Coprocessor support is not yet tested. Please report
  1345.              your experiences with this option.
  1346.  
  1347.              This option is normally disabled (FALSE).
  1348.  
  1349.         HOTKEYS
  1350.              If TRUE, keyboard hotkey support is included. Embedded
  1351.              systems likely will not use hotkeys, and may set this to
  1352.              FALSE.
  1353.  
  1354.              This option is normally enabled (TRUE).
  1355.  
  1356.  
  1357.         CHECKING
  1358.              Enables pointer and stack checks when TRUE. Checking
  1359.              pointers and task stacks slows down the system, but it is
  1360.              highly recommended to enable this option during development.
  1361.              Only turn off checking after debugging is complete.
  1362.  
  1363.              This option is normally disabled (FALSE).
  1364.         
  1365.         
  1366.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 20
  1367.  
  1368.  
  1369.                                 Memory Allocation
  1370.  
  1371.         TSKALLOC.C is needed if TSK_DYNAMIC is enabled in tskconf.h to
  1372.         handle the allocation and free calls. If you want to use dynamic
  1373.         allocation in your own tasks, you should also use the functions
  1374.         tsk_alloc and tsk_free to avoid the reentrancy problems mentioned
  1375.         in the introduction. If you should need other forms of alloc
  1376.         (like calloc) the recommended way is to add those functions to
  1377.         TSKALLOC.C, requesting the resource alloc_resource before calling
  1378.         the C memory-allocation function.
  1379.  
  1380.         Joe Urso provided the following tip on how to force all memory
  1381.         allocation to pass through the resource handling functions:
  1382.  
  1383.         "I have found that some MS Library functions call the allocate
  1384.         and free library functions, namely the first call to fread(),
  1385.         fopen(), and fclose().
  1386.  
  1387.         To fix this situation I have
  1388.  
  1389.            - extracted FMALLOC from the llibce library,
  1390.  
  1391.            - renamed the functions within that object (via the Norton
  1392.              Utilities) to the upper case spelling of the functions
  1393.              (FREE, MALLOC, _FFREE and _FMALLOC) and replaced the file in
  1394.              the lib. I also did the same for object EXPAND because of
  1395.              the function REALLOC.
  1396.  
  1397.            - then modified TSKALLOC.C to contain the lower case spelling
  1398.              of malloc, free, and expand. These functions aquire the
  1399.              alloc resource, then call the upper case spelling of the
  1400.              name.
  1401.  
  1402.         At link time I now link with /NOIGNORECASE and /NODEFAULTLIB."
  1403.  
  1404.         An option is provided in tskalloc.c to compile the module with
  1405.         the modifications suggested by Joe Urso.
  1406.  
  1407.  
  1408.                                      Snapshot
  1409.  
  1410.         TSKSNAP.C is only needed if you want to include the snapshot dump
  1411.         into your program. Note that you can *not* use snapshot if you
  1412.         disable TSK_NAMED in tskconf.h.
  1413.  
  1414.  
  1415.  
  1416.  
  1417.  
  1418.  
  1419.  
  1420.  
  1421.  
  1422.         
  1423.         
  1424.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 21
  1425.  
  1426.  
  1427.                                    Task Stacks
  1428.  
  1429.         When compiling your application, turn stack checking off. The
  1430.         standard stack check is of little use with task stacks, and may
  1431.         interfere with CTask's operation. The stack area for tasks should
  1432.         be allocated on the main program's stack, not in the static or
  1433.         heap data space. The reason for this is that some of the C
  1434.         library routines check for stack overflow regardless of your
  1435.         compile-time switches, and will crash your application if you use
  1436.         stacks outside the normal stack. The stack allocation parameter
  1437.         with LINK (MS-C), or the _stacksize variable (Turbo C) have to be
  1438.         increased to reflect the additional stack space. When calculating
  1439.         task stack sizes, keep in mind that library routines (esp.
  1440.         printf) allocate a lot of space on the stack for temporary
  1441.         variables. A minimum of 1k for tasks using library routines is
  1442.         recommended, 2k puts you on the safe side. Tasks not using C
  1443.         library routines may use a smaller stack, about 256 bytes at a
  1444.         minimum, plus space for any local variables and nested routines.
  1445.         Then add up all task stacks, and add space for the main task (the
  1446.         function calling install_tasker), with this size also dependent
  1447.         on what you will do in the main task while CTask is active.
  1448.         Stacks for tasks that do not use C library routines may be
  1449.         allocated anywhere.
  1450.  
  1451.         If you have the CHECKING option enabled, the snapshot dump will
  1452.         output the number of unused bytes of stack for each task. This
  1453.         can help you determine the optimum stack size for your
  1454.         application.
  1455.  
  1456.  
  1457.                                      Drivers
  1458.  
  1459.         The keyboard and DOS handlers are always installed with CTask.
  1460.         Using the serial I/O and printer drivers is optional, so you have
  1461.         to install them separately, but only *after* installing CTask.
  1462.         When using the serial driver, include "sio.h" in your modules,
  1463.         when using the printer driver, include "prt.h".
  1464.  
  1465.         Another driver that is automatically installed is the BIOS
  1466.         wait/post handler for the IBM AT. The AT BIOS contains some
  1467.         multitasking hooks to avoid busy waiting in the BIOS. If you
  1468.         experience problems with disk accesses or printer output through
  1469.         BIOS (not through the CTask printer driver), you should disable
  1470.         installation of this driver by setting AT_BIOS to zero in
  1471.         tskconf.h, or not specifying the IFL_INT15 flag in
  1472.         install_tasker. Normally, no problems should arise with this
  1473.         driver even in XT type machines.
  1474.  
  1475.  
  1476.  
  1477.  
  1478.  
  1479.  
  1480.         
  1481.         
  1482.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 22
  1483.  
  1484.  
  1485.                                 Things to remember
  1486.  
  1487.         Remember that tasks are not automatically started after creation.
  1488.         Use start_task to allow a created task to run.
  1489.  
  1490.         Always use create_xxx on resources, pipes, etc. Using the event
  1491.         routines without doing so will have unpredictable results. This
  1492.         is especially true with the new queue structure introduced in
  1493.         2.0/2.2, where uninitialised control structures will invariably
  1494.         lead to a system crash. Enable the CHECKING option to trap such
  1495.         cases.
  1496.  
  1497.         Before exiting the program, all installed drivers and CTask
  1498.         should be explicitly removed. Although the DOS handler traps the
  1499.         terminate call and automatically calls remove_tasker, you should
  1500.         make sure that all tasks are completed properly, and call
  1501.         remove_tasker yourself.
  1502.  
  1503.         Deleting events before exiting the program is not mandatory, but
  1504.         recommended to kill all tasks waiting for the event. You should
  1505.         be careful not to kill tasks while they are active in DOS. The
  1506.         kill_task routine should be reserved for fatal error handling.
  1507.         The best way is to let the tasks kill themselves depending on
  1508.         some global variable or event. If a task is killed while waiting
  1509.         for input in DOS, DOS operation may be severely impaired. If you
  1510.         use the C console input routines, make sure that the task returns
  1511.         from DOS before it is killed, if necessary by requesting the user
  1512.         to press a key.
  1513.  
  1514.  
  1515.  
  1516.                                 Priority Handling
  1517.  
  1518.         CTask provides for prioritized task execution and event
  1519.         processing. This means that a task that has a higher priority
  1520.         will be run before any other tasks having lower priority. Also, a
  1521.         higher priority task will gain access to resources, counters,
  1522.         pipes, and mail, before lower priority tasks. With fixed
  1523.         priorities, this means that a high priority task can monopolize
  1524.         CPU time, even if it calls schedule() explicitly. Variable
  1525.         priority increases each eligible task's priority by one on each
  1526.         scheduler call, so that lower priority tasks will slowly rise to
  1527.         the head of the queue until they get executed. The priority will
  1528.         be reset to the initial priority when a task is run.
  1529.  
  1530.         Since variable priority increases processing time in the critical
  1531.         region of the scheduler, it is not recommended for systems in
  1532.         which a larger number of tasks is expected to be eligible
  1533.         simultaneously.
  1534.  
  1535.         Usually, all tasks in a system should have the same priority,
  1536.         with only very few exceptions for non-critical background
  1537.         processing (low priority) or very time-critical tasks (high
  1538.         
  1539.         
  1540.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 23
  1541.  
  1542.  
  1543.         priority). High priority tasks should be written in such a way
  1544.         that they either reduce their priority when processing is
  1545.         completed, or that they wait for an event. Busy waiting in a high
  1546.         priority task will severely impair system operation with variable
  1547.         priority enabled, and will stop the system until the task is
  1548.         placed in a waiting state with fixed priority.
  1549.  
  1550.         The (automatically created) main task is started with the highest
  1551.         possible priority below the timer task, so that it can process
  1552.         all initialisations before other tasks start running. To allow
  1553.         the system to operate, the priority of the main task must be
  1554.         reduced, or the main task must wait for an event or a timeout.
  1555.  
  1556.  
  1557.  
  1558.  
  1559.  
  1560.  
  1561.  
  1562.  
  1563.  
  1564.  
  1565.  
  1566.  
  1567.  
  1568.  
  1569.  
  1570.  
  1571.  
  1572.  
  1573.  
  1574.  
  1575.  
  1576.  
  1577.  
  1578.  
  1579.  
  1580.  
  1581.  
  1582.  
  1583.  
  1584.  
  1585.  
  1586.  
  1587.  
  1588.  
  1589.  
  1590.  
  1591.  
  1592.  
  1593.  
  1594.  
  1595.  
  1596.         
  1597.         
  1598.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 24
  1599.  
  1600.  
  1601.                                Multitasking and DOS
  1602.  
  1603.  
  1604.         CTask includes (and automatically installs) a routine which traps
  1605.         all DOS calls, and makes sure that no two tasks simultaneously
  1606.         enter DOS. This is accomplished using the resource mechanism,
  1607.         with special provisions for the limited multitasking capabilities
  1608.         provided by DOS. There are a few calls, namely those with
  1609.         function codes <= 0x0c, which allow functions with codes > 0x0c
  1610.         to be executed while DOS is waiting for an external device
  1611.         (generally the keyboard) to get ready.
  1612.  
  1613.         This, however, limits the use of some C library functions, namely
  1614.         scanf and fread, for console input. Both these functions use
  1615.         handle input, and thus can not be interrupted. When writing
  1616.         routines for handling user input, keyboard read functions should
  1617.         either use the low-level calls getch and gets, or, better yet,
  1618.         the direct entries into the keyboard handler, t_read_key and
  1619.         t_keyhit, and then process the string with sscanf if desired.
  1620.  
  1621.         The keyboard handler (contained in tskkbd.asm) traps all keyboard
  1622.         interrupts, setting a flag when a key is hit. If a task reads
  1623.         from the keyboard, it is automatically made waiting if there is
  1624.         no key to read. Using getch and gets is less desirable since they
  1625.         use polling instead of event waiting, and thus degrade system
  1626.         performance. Also, the t_read_key and t_keyhit functions do not
  1627.         use DOS, so DOS functions <= 0C can be executed concurrently.
  1628.  
  1629.         The BIOS interrupts 10 (Video), 13 (Disk), and 16 (Keyboard) are
  1630.         protected by CTask. Using other BIOS interrupts directly should
  1631.         generally be avoided, unless you are absolutely sure they will
  1632.         not be used by other routines via DOS, or you provide your own
  1633.         critical region handling. Protection of INT 10 is optional, and
  1634.         should only be used if you expect to use BIOS level video output
  1635.         in parallel to other tasks. Since INT 10 calls occur extremely
  1636.         frequent in most programs, the overhead for reserving and
  1637.         releasing the resource can slow down the system noticeably.
  1638.  
  1639.         Starting with version 1.2, the DOS handling has been extended to
  1640.         automatically save and restore the DOS variable context on a task
  1641.         switch. This is done by directly saving the critical variables of
  1642.         the DOS data area in the task control block. An undocumented DOS
  1643.         call is used to determine location and length of this area. NOTE
  1644.         that this call is not available in DOS versions prior to 3.1, and
  1645.         may not be available in MS-DOS clones or emulators. This context
  1646.         save allows multiple DOS applications to run concurrently.
  1647.  
  1648.         The DOS access module has been tested to work with PC-DOS and MS-
  1649.         DOS versions 3.20, 3.30, 4.00, and 4.01. There were also no
  1650.         problems with the DOS PRINT program, and with Network drivers
  1651.         (Invisible Net) running in the background. Special provisions are
  1652.         built into the DOS module to detect background DOS calls. Using
  1653.         Sidekick also hasn't lead to any problems, although you may trash
  1654.         
  1655.         
  1656.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 25
  1657.  
  1658.  
  1659.         Sidekick's screen display by writing to the screen while Sidekick
  1660.         is active (note that your application *continues* to run while
  1661.         Sidekick or other pop-ups are active). I can not guarantee
  1662.         complete compatibility with all background and pop-up programs
  1663.         under all versions of DOS. Specifically, DOS versions prior to
  1664.         3.1 have significant problems with multitasking, and do not
  1665.         support the variable save call necessary for full DOS
  1666.         multitasking. Upgrading to a newer DOS version is recommended if
  1667.         you are still using DOS < 3.2 (DOS 3.1 has some bugs in other
  1668.         areas).
  1669.  
  1670.         Also starting with version 1.2, CTask is now compatible with MS-
  1671.         Windows in non-enhanced mode. It has been tested to work with
  1672.         Windows 286 1.2 and 2.1, and with Windows 3.0 in real mode, but
  1673.         the mechanism used should work with other non-preemptive
  1674.         versions, too.  CTask can be installed as a background TSR before
  1675.         starting Windows, or you may spawn Windows from CTask.
  1676.         Windows/386 is a special virtual-mode operating system and can
  1677.         generally not be combined with other multitaskers.
  1678.  
  1679.         CTask 2.2 will not work with Windows 3.0 in 386 enhanced mode
  1680.         when installed as a TSR before starting Windows. I now know why,
  1681.         but I did not have the time to do anything about it. The next
  1682.         version probably will support full Windows 3.0 compatibility. If
  1683.         you start CTask within Windows, everything will work smoothly,
  1684.         but CTask instances in different DOS-windows will not be able to
  1685.         communicate with each other.
  1686.  
  1687.         Other preemptive multitaskers like DesqView will most likely not
  1688.         coexist peacefully with CTask.
  1689.  
  1690.         Critical errors and Control C occurring while concurrent DOS
  1691.         access takes place may be fatal. Using the ctrlbrk() and
  1692.         harderr() functions of Turbo C, or their equivalents in MS C, to
  1693.         trap critical errors and Control C is highly recommended. Error
  1694.         handlers should be installed before CTask is installed.
  1695.  
  1696.  
  1697.                              Spawning and CTask TSR's
  1698.  
  1699.         Starting with Version 1.2, CTask programs can now spawn other
  1700.         programs, and Terminate and Stay Resident (TSR). The DOS context
  1701.         switch, plus the saving and restoring of interrupts 21-24, on
  1702.         every task switch, makes it possible to have multiple, nearly
  1703.         completely independent, programs running under DOS. But please
  1704.         note that CTask is not intended as a replacement for true DOS-
  1705.         multitaskers like DesqView. Implementation of such a system would
  1706.         surely be possible, using CTask as a base, but would require
  1707.         keeping track of all DOS control blocks. This is left as an
  1708.         exercise to the reader. The new features are intended to allow
  1709.         you to easily write background data aquisition or communication
  1710.         modules that run in parallel to other DOS applications.
  1711.  
  1712.         
  1713.         
  1714.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 26
  1715.  
  1716.  
  1717.         Since the spawned program might itself be a CTask program,
  1718.         Version 1.2 automatically checks for the presence of a background
  1719.         copy of CTask. If one is found, the secondary invocation will
  1720.         link to the global data of the first CTask copy, making it
  1721.         possible to easily communicate between independent instances of
  1722.         CTask programs. The naming mechanism has been slightly changed to
  1723.         make it easier to find a task or data structure by name.
  1724.  
  1725.         For example, you could write a communications program in two
  1726.         separate parts. One part, the resident part, contains interrupt
  1727.         handlers and the protocol routines. The other part, the transient
  1728.         portion, contains the driving program, with editor, menus, script
  1729.         language and so on.  If the resident part is started, it first
  1730.         spawns the transient part, which handles setup, and starts
  1731.         communications. Both parts can communicate using all CTask
  1732.         mechanisms, i.e. pipes, buffers, mailboxes etc., with the
  1733.         transient part obtaining the pointers to the CTask structures
  1734.         defined in the resident part via the structure name. Now if an
  1735.         up- or download is started, the transient part can exit to DOS,
  1736.         and the resident part can spawn a copy of command.com. Voila -
  1737.         background up/download with minimum hassle.
  1738.  
  1739.  
  1740.                                    Task Groups
  1741.  
  1742.         Each invocation of the CTask kernel (i.e. each call of the
  1743.         install_tasker routine) creates a new "Task Group". This group
  1744.         chains all tasks and other control structures created by this
  1745.         program together, so they can be killed if the group terminates
  1746.         (through a DOS call or the remove_tasker routine). Although it is
  1747.         recommended to kill all structures before terminating, there are
  1748.         a number of situations where this is hard to control under DOS.
  1749.         So CTask tries to take a few safety measures to make sure the
  1750.         system does not crash due to pointers chaining into nowhere.
  1751.  
  1752.         But please note that care should be taken not to "pull the rug
  1753.         under a group's feet". CTask will attempt to clean up memory when
  1754.         a group terminates. However, if that group has spawned another
  1755.         non-CTask program, CTask doesn't know about it, so an orphan will
  1756.         be left in memory, and you might even manage to get the system
  1757.         into an unstable state.
  1758.  
  1759.         And, there are a few restrictions. Although it is possible to
  1760.         create multiple groups running, and terminating, independently in
  1761.         parallel, those groups must be created by separate tasks from one
  1762.         "home group". If one task creates a group, and the same task, or
  1763.         another task from this group, creates a second, then it is not
  1764.         possible to terminate the first group without also killing the
  1765.         second. You can view this like a tree, where you can cut off
  1766.         branches, but all sub-branches of that branch will come down with
  1767.         it.  The root of that tree, the primary invocation of CTask, can
  1768.         not be killed without killing the whole tree.
  1769.  
  1770.         
  1771.         
  1772.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 27
  1773.  
  1774.  
  1775.         Also, it is mandatory that you at least try to call remove_tasker
  1776.         on termination. CTask can trap a program's termination, but this
  1777.         happens at a time when all the program's memory has already been
  1778.         released by DOS. This can lead to extremely dangerous situations
  1779.         if other tasks, or TSR's, allocate and modify this memory before
  1780.         CTask finishes it's cleanup. CTask will stop preemption while it
  1781.         is removing the group, but it still is definitely not recommended
  1782.         to rely on this mechanism.
  1783.  
  1784.  
  1785.         A sample for a task group structure follows:
  1786.  
  1787.                                -Root-
  1788.                                 home
  1789.                                 level
  1790.                                 branch -----+
  1791.                                  ^ ^        |
  1792.                                  | |        |
  1793.                                  | |        v
  1794.                    -Group1-      | |     -Group2-
  1795.                     home   ------+ +----- home
  1796.                     level  <------------- level
  1797.                     branch -----+         branch
  1798.                      ^ ^        |
  1799.                      | |        |
  1800.                      | |        v
  1801.         -GroupA-     | |     -GroupB-
  1802.          home   -----+ +----- home
  1803.          level  <------------ level
  1804.          branch               branch
  1805.  
  1806.  
  1807.         In this sample, Groups 1 and 2 were created by different tasks in
  1808.         the Root group, Groups A and B by different tasks in Group 1.
  1809.  
  1810.         Three pointers are used in chaining groups. The 'branch' points
  1811.         to the first element in an unordered list of task groups on the
  1812.         same "branch level" one level "up" the tree. Those groups are
  1813.         chained by the 'level' pointer. To allow finding the home group
  1814.         when going "down" the tree (towards the root), all groups on the
  1815.         same level point there through the 'home' pointer. In this
  1816.         sample, you could kill Group2 without affecting Group1 or it's
  1817.         subgroups. Killing Group1 will terminate GroupA and GroupB.
  1818.  
  1819.  
  1820.  
  1821.  
  1822.  
  1823.  
  1824.  
  1825.  
  1826.  
  1827.  
  1828.         
  1829.         
  1830.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 28
  1831.  
  1832.  
  1833.                                How does CTask work
  1834.  
  1835.                                       Queues
  1836.  
  1837.         CTask uses priority queues for most of its functions. A priority
  1838.         queue differs from the usual FIFO (first in, first out) queues in
  1839.         the insertion of elements into the queue. Rather than just
  1840.         placing new elements after the last queue member, the priority of
  1841.         the task determines its place in the queue. A task is enqueued
  1842.         after all queue members with higher or equal priority, but before
  1843.         any member with lower priority. Removal from the queue takes
  1844.         place at the first element. These queues are used with all
  1845.         operations in which a task is made waiting, be it waiting to get
  1846.         run, or waiting for an event. The advantage of this is the
  1847.         simplicity of implementing priorities. Other schemes might rely
  1848.         on arrays of queues, or searching through lists, to determine the
  1849.         highest priority waiting task. With priority queues, the most
  1850.         time critical function, scheduling, is very fast, since it can
  1851.         simply take the first task from the queue of eligible functions.
  1852.         The disadvantage is the time required to step through all greater
  1853.         or equal priority members of a queue to find the right place to
  1854.         insert the task. But since the number of tasks simultaneously
  1855.         enqueued in the same queue is normally relatively small with most
  1856.         multitasking systems, this disadvantage is more than offset by
  1857.         the simple, and thus easy to implement efficiently, scheme.
  1858.  
  1859.         Version 2.0 generalizes the queueing scheme, and uses doubly
  1860.         linked lists for all internal chains (except the ticker chain).
  1861.         The introduction of the "yield" function, which inserts a task at
  1862.         the end of the eligible queue, but resets the priority, mandated
  1863.         searching through the queue from the back end. The previous
  1864.         scheme, which walked the queue from the front end, could lead to
  1865.         task starvation in a system with polling tasks when yielding.
  1866.         Also, the timer algorithm was changed such that the timer task
  1867.         didn't have to step through all timeout elements, but rather to
  1868.         only decrement the first queue element ticker. This is
  1869.         implemented by storing the timeout as a tick difference to the
  1870.         next queue element rather than as an absolute value. Doubly
  1871.         linked lists make insertion and removal of elements at arbitrary
  1872.         points very simple, and eliminate the time needed to find an
  1873.         element in a queue.
  1874.  
  1875.         To alleviate the additional overhead associated with managing
  1876.         dual pointers, the main queueing routines were coded in
  1877.         assembler. Especially when operating with multiple far pointers,
  1878.         the code generated by the C compilers even with maximum
  1879.         optimization is not that impressive. The corresponding C code is
  1880.         included as a reference, and to aid porting to non-8086
  1881.         environments.
  1882.  
  1883.  
  1884.  
  1885.  
  1886.         
  1887.         
  1888.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 29
  1889.  
  1890.  
  1891.                                   The Scheduler
  1892.  
  1893.         In a CTask system, there is at least one essential queue: the
  1894.         eligible queue, which contains all tasks waiting to run. Each
  1895.         time the scheduler is invoked, it will first save all processor
  1896.         registers in the current task control block, and then enqueue the
  1897.         current task into the appropriate queue.  Normally, this will be
  1898.         the eligible queue. Then the first element in the eligible queue
  1899.         is removed from the queue, the stack is switched to the stack of
  1900.         this task, and processor registers are restored from the new TCB,
  1901.         returning to the point where the new task was interrupted. If the
  1902.         eligible queue is empty the scheduler will loop with interrupts
  1903.         enabled. The queue head pointer of the task control block of the
  1904.         current running task determines what will happen to the task when
  1905.         the scheduler is invoked. If it points to an event control block,
  1906.         the task will be enqueued as waiting for this event. If it is
  1907.         NULL, the task will not be enqueued in any queue, effectively
  1908.         stopping it. If it points to the eligible queue, the task will be
  1909.         enqueued there. In any case, the scheduler does not care what
  1910.         queue the task is to be enqueued in, since all queues use the
  1911.         same priority based ordering. If a task is no longer in the
  1912.         eligible queue, it can only be returned to this queue by an
  1913.         external event.
  1914.  
  1915.  
  1916.                                      Events
  1917.  
  1918.         External events can take several forms, which are relatively
  1919.         similar on the inside. All CTask events use a control block, with
  1920.         at least one queue for tasks waiting for the event. Although it
  1921.         would have been possible to summarize all events under a global
  1922.         structure, this approach was not used in CTask, the main reasons
  1923.         being execution speed and ease of use. So if you scan through the
  1924.         source files for CTask events, you will see many very similar
  1925.         routines, which only differ in the types of data and the names of
  1926.         queues they process. In a class based language like C++, one
  1927.         would certainly define all events as instances or derivations of
  1928.         one class. In plain C, the necessary type casting, and the
  1929.         different handling of certain cases, would clobber the code to
  1930.         the point of illegibility.
  1931.  
  1932.  
  1933.                                     Resources
  1934.  
  1935.         The event types "resource", "flag", and "counter" differ only in
  1936.         the kind of wait operations and the handling of the state
  1937.         variable. The resource is mainly for use in interlocking critical
  1938.         regions of code, to protect access to non-reentrant resources.
  1939.         Only one task can "own" a resource, all other tasks requesting
  1940.         the resource are delayed until the owning task releases it. For
  1941.         added protection, CTask stores the task control block address of
  1942.         the current owner of the resource in the resource control block,
  1943.         so no other task can erroneously release it.
  1944.         
  1945.         
  1946.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 30
  1947.  
  1948.  
  1949.                                       Flags
  1950.  
  1951.         Flags, on the other hand, can be set and cleared by any task, and
  1952.         also by interrupt handlers. Tasks can wait on either state of the
  1953.         flag, and all tasks waiting for a state are simultaneously
  1954.         activated when the flag is changed to this state. This makes
  1955.         flags suitable for use as a global signalling mechanism.
  1956.  
  1957.  
  1958.                                      Counters
  1959.  
  1960.         Counters are a variation on the flag concept. A counter can be
  1961.         incremented and cleared by any task, and by interrupt handlers.
  1962.         Tasks can wait for a counter to be zero or nonzero. Like flags,
  1963.         all tasks waiting for the zero state are activated
  1964.         simultaneously. But unlike flags, only the first task waiting for
  1965.         the nonzero state of a counter will be activated on incrementing
  1966.         the counter, and the counter will be automatically decremented by
  1967.         one. The counter is used inside CTask to handle timer interrupts.
  1968.         The timer counter will be incremented on each timer tick,
  1969.         activating the timer task. If for any reason the timer task is
  1970.         unable to complete its run until the next tick, this tick will
  1971.         not be lost, since the counter is incremented, and the timer task
  1972.         will continue to run the next time it calls the counter wait
  1973.         request.
  1974.  
  1975.  
  1976.                                Mailboxes and Pipes
  1977.  
  1978.         The "mailbox" and "pipe" events can be used for inter-task
  1979.         communication, and for the communication between interrupt
  1980.         handlers and tasks.
  1981.  
  1982.         Mailboxes can hold an unlimited number of mail blocks. Mail
  1983.         blocks have no fixed structure, but the first doubleword in each
  1984.         block passed to a mailbox routine is used as a chain pointer.
  1985.         Mail blocks are chained into a mailbox in FIFO order. Tasks can
  1986.         wait for mail to arrive, or can conditionally read mail if a
  1987.         block is available. Tasks and interrupt handlers can write blocks
  1988.         to a mailbox. Since mailboxes don't need any copying of data,
  1989.         they are suited for high speed exchange of larger amounts of data
  1990.         between tasks. The disadvantage of sending mail this way is that
  1991.         you have to make sure that a mail block is not re-used before it
  1992.         has been read out of the box and processed by the receiving task.
  1993.         When exchanging fixed length messages, you can build a free mail
  1994.         block chain by using a mailbox to hold the available blocks.
  1995.  
  1996.         Buffered message exchange is possible using pipes. When creating
  1997.         a pipe, you specify a buffer area and its length, and the pipe
  1998.         routines will buffer all data written to the pipe in this area.
  1999.         This implies that writing to a pipe may cause a task to be
  2000.         delayed until there is space available in the pipe. To allow
  2001.         interrupt handlers to write to pipes, there is a conditional
  2002.         
  2003.         
  2004.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 31
  2005.  
  2006.  
  2007.         write request, which will simply return if the pipe is full.
  2008.         Tasks can wait for data to arrive in a pipe, and for the pipe to
  2009.         be emptied. A conditional read request is also provided. The
  2010.         disadvantage of pipes is that they are slightly slower than
  2011.         mailboxes due to the necessary copying, and that you can only
  2012.         place word or byte sized items in a pipe. When there is more than
  2013.         one reader or writer task, you can not rely on the bytes in a
  2014.         pipe being in any specific order. A "buffer" construct is
  2015.         provided in CTask that expands pipes to allow arbitrary length
  2016.         messages to be written and read. This is implemented using a
  2017.         resource for reading and writing to the pipe associated with the
  2018.         buffer, so the message is always guaranteed to be written and
  2019.         read in one piece. But since resources can not be used in
  2020.         interrupt handlers, using such buffers is not allowed from
  2021.         interrupts.
  2022.  
  2023.  
  2024.                             Serial and Printer Drivers
  2025.  
  2026.         There are a number of routines included in the CTask package for
  2027.         PC-specific tasks. Although they will be of limited use for
  2028.         embed-ded applications, studying the serial I/O and printer
  2029.         interface routines will give you some hints on how to use the
  2030.         CTask kernel for implementing your own device drivers. For PC
  2031.         based appli-cations, the routines should be usable with no or
  2032.         little changes for implementing complete communications packages.
  2033.  
  2034.         The serial I/O handler uses interrupts for both input and output
  2035.         of data, and supports both XON/XOFF and RTS/CTS handshake
  2036.         methods. The modem inputs can selectively be enabled to control
  2037.         data transmission. Pipes are used for transmit and receive data,
  2038.         with the buffer and its size specified on initialization. Both
  2039.         COM1 and COM2 can be active simultaneously, and other ports can
  2040.         be supported by editing a table in the source code or defining
  2041.         ports on-line. Since CTask allows the access to all events in
  2042.         interrupt handlers, writing interrupt based I/O drivers is
  2043.         relatively simple.  On receiving a character, the character and
  2044.         any associated errors are placed in the receive pipe, and the
  2045.         transmit pipe is read on transmit ready interrupt. Note that
  2046.         conditional reads and writes have to be used in the interrupt
  2047.         handler, since you can't safely delay an interrupt handler.
  2048.  
  2049.         The printer output driver supports both polling and interrupt
  2050.         output. Again, a pipe is used for the output characters.
  2051.         However, since polling is supported, and because of the somewhat
  2052.         unreliable interrupt structure of the printer ports, a driver
  2053.         task is required. This task is automatically created on
  2054.         installing the driver. The task first waits on the pipe for a
  2055.         character to be written to the printer.  When polling is enabled,
  2056.         it tries to output the character directly, using a short busy-
  2057.         waiting loop. So as not to load the system too heavily by the
  2058.         polling, the task will yield if it can't output the character
  2059.         after a small number of loops. When interrupts are enabled, the
  2060.         
  2061.         
  2062.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 32
  2063.  
  2064.  
  2065.         process is essentially the same at the start, but after the
  2066.         character is written to the port, the task will wait on a flag to
  2067.         be set. The interrupt handler will set the flag on interrupt,
  2068.         enabling the task to get the next character from the pipe. Since
  2069.         interrupts are unreliable with most printers due to the usually
  2070.         very short pulses on the acknowledge line, the task uses a
  2071.         timeout on the flag wait, so it does not hang if an interrupt is
  2072.         missed. Studying the printer driver will also give you an idea
  2073.         what the optional parameter on task creation can be used for. In
  2074.         the printer driver, this parameter is used to pass the address of
  2075.         the printer control block, which contains the pipe, the flag, and
  2076.         the hardware info, to the task. This allows the printer driver to
  2077.         be simultaneously installed for any number of printers without
  2078.         having to write separate printer tasks.
  2079.  
  2080.  
  2081.  
  2082.  
  2083.  
  2084.  
  2085.  
  2086.  
  2087.  
  2088.  
  2089.  
  2090.  
  2091.  
  2092.  
  2093.  
  2094.  
  2095.  
  2096.  
  2097.  
  2098.  
  2099.  
  2100.  
  2101.  
  2102.  
  2103.  
  2104.  
  2105.  
  2106.  
  2107.  
  2108.  
  2109.  
  2110.  
  2111.  
  2112.  
  2113.  
  2114.  
  2115.  
  2116.  
  2117.  
  2118.         
  2119.         
  2120.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 33
  2121.  
  2122.  
  2123.                                  CTask Data Types
  2124.  
  2125.  
  2126.         Note that you do not have to know the innards of the structures.
  2127.         All structure fields are filled by the "create_xxx" routines and
  2128.         modified by the CTask functions. You should NEVER modify a field
  2129.         in one of the structures directly. The structures are explained
  2130.         here shortly only for those wanting to modify the routines.
  2131.  
  2132.         NOTE: When modifying CTask structures, take care to modify the
  2133.         equivalent definitions in the assembler include file "tsk.mac".
  2134.         Some of the assembler routines have to use field offsets into
  2135.         pointers, so having different offsets in C and assembler will
  2136.         crash the system.
  2137.  
  2138.  
  2139.         If you only want to use the routines, you should simply include
  2140.         the file "tsk.h" in your source, and define variables of the
  2141.         types
  2142.  
  2143.              tcb         - for task control blocks
  2144.              tcbptr      - for far pointers to tcbs
  2145.  
  2146.              flag        - for flag events
  2147.              flagptr     - for far pointers to flags
  2148.  
  2149.              resource    - for resource events
  2150.              resourceptr - for far pointers to resources
  2151.  
  2152.              counter     - for counter events
  2153.              counterptr  - for far pointers to counters
  2154.  
  2155.              mailbox     - for mailbox events
  2156.              mailboxptr  - for far pointers to mailboxes
  2157.  
  2158.              pipe        - for pipe events
  2159.              pipeptr     - for far pointers to pipes
  2160.  
  2161.              wpipe       - for word pipe events
  2162.              wpipeptr    - for far pointers to word pipes
  2163.  
  2164.              buffer      - for buffer events
  2165.              bufferptr   - for far pointers to buffers
  2166.  
  2167.              tlink       - for timeout and watch control blocks
  2168.              tlinkptr    - for far pointers to timeout control blocks
  2169.  
  2170.              namerec     - for control block names
  2171.              nameptr     - for name pointers
  2172.  
  2173.         without caring what's behind them.
  2174.  
  2175.  
  2176.         
  2177.         
  2178.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 34
  2179.  
  2180.  
  2181.         Additionally, you may use the types
  2182.  
  2183.              byte         - for unsigned characters
  2184.              word         - for unsigned short integers
  2185.              dword        - for unsigned long integers
  2186.  
  2187.              funcptr      - for far pointers to void functions
  2188.              funcptr_void - for far pointers to void functions taking no
  2189.                             parameters
  2190.              funcptr_int  - for far pointers to void functions taking a
  2191.                             single int parameter
  2192.              funcptr_fp   - for far pointers to void functions taking a
  2193.                             single far pointer parameter
  2194.              funcptr_dword - for far pointers to void functions taking a
  2195.                             single doubleword parameter
  2196.  
  2197.              farptr       - for far pointers to anything
  2198.              byteptr      - for far pointers to byte arrays
  2199.              wordptr      - for far pointers to word arrays
  2200.  
  2201.         in defining or typecasting items to be passed as parameters to
  2202.         CTask functions.
  2203.  
  2204.  
  2205.                                 Other definitions
  2206.  
  2207.         The following definitions are used inside CTask to avoid problems
  2208.         with Microsoft C in some memory models. The standard FP_SEG and
  2209.         FP_OFF macros will not work correctly in near data models, and
  2210.         the NULL pointer may not actually be 0 when assigned to a far
  2211.         pointer. The offsetof operator is not defined for MSC 5.1.
  2212.  
  2213.              TFP_SEG(ptr)       Is a macro to isolate the segment part of
  2214.                                 a far pointer.
  2215.  
  2216.              TFP_OFF(ptr)       Is a macro to isolate the offset part of
  2217.                                 a far pointer.
  2218.  
  2219.              TMK_FP(seg,off)    Is a macro to make a far pointer out of a
  2220.                                 segment and an offset.
  2221.  
  2222.              LNULL              Is a far pointer to nothing.
  2223.  
  2224.              TSK_OFFSETOFF(struc,field)
  2225.                                 Is a macro that returns the byte offset
  2226.                                 of "field" within the structure type
  2227.                                 "struc".
  2228.  
  2229.              TSK_STRUCTOP(struc,ptr,field)
  2230.                                 Is a macro that returns a pointer to the
  2231.                                 start of the structure of type "struc",
  2232.                                 given a pointer "ptr" which points to
  2233.                                 "field" within the structure.
  2234.         
  2235.         
  2236.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 35
  2237.  
  2238.  
  2239.         The definition TN is used in CTask starting at version 2.1 to
  2240.         avoid using extensive #if directives for routines accepting name
  2241.         parameters. The previous way of enclosing the parameter in #if /
  2242.         #endif made the sources hard to read. The TN macro will expand to
  2243.         nothing if TSK_NAMEPAR is FALSE, and to a comma followed by the
  2244.         parameter if TSK_NAMEPAR is TRUE.
  2245.  
  2246.              TN(name)           Define name parameter if TSK_NAMEPAR is
  2247.                                 TRUE.
  2248.  
  2249.  
  2250.         In addition, a number of definitions are provided to statically
  2251.         initialise event structures (flags, resources, etc.). Those
  2252.         definitions (DEF_xxx) are listed in the "routines" section under
  2253.         the corresponding create_xxx routine entry. You use them in place
  2254.         of a normal variable definition, i.e. to create an initialised
  2255.         flag, you would write
  2256.  
  2257.              static DEF_FLAG (myflag, "MyFlag");
  2258.              ...
  2259.              add_event_name (&myflag);
  2260.  
  2261.         instead of
  2262.  
  2263.              static flag myflag;
  2264.              ...
  2265.              create_flag (&myflag, "MyFlag");
  2266.  
  2267.  
  2268.                  Typedefs used for simplified type specifications
  2269.  
  2270.              typedef unsigned char byte;
  2271.              typedef unsigned short word;
  2272.              typedef unsigned long dword;
  2273.              typedef void (Taskfunc *funcptr)();
  2274.              typedef void (Taskfunc *funcptr_void)(void);
  2275.              typedef void (Taskfunc *funcptr_int)(int);
  2276.              typedef void (Taskfunc *funcptr_dword)(dword);
  2277.              typedef void (interrupt far *intprocptr)(void);
  2278.              typedef void far *farptr;
  2279.              typedef byte far *byteptr;
  2280.              typedef word far *wordptr;
  2281.  
  2282.  
  2283.  
  2284.  
  2285.  
  2286.  
  2287.  
  2288.  
  2289.  
  2290.  
  2291.  
  2292.         
  2293.         
  2294.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 36
  2295.  
  2296.  
  2297.                    Error return values for event wait functions
  2298.  
  2299.  
  2300.              #define TTIMEOUT ((farptr) -1L)
  2301.              #define TIMEOUT  (-1)
  2302.  
  2303.                   -1 is returned if a timeout occurred while waiting for
  2304.                   an event.
  2305.  
  2306.              #define TWAKE    ((farptr) -2L)
  2307.              #define WAKE     (-2)
  2308.  
  2309.                   -2 is returned if the task was waked up while waiting
  2310.                   for an event.
  2311.  
  2312.              #define TWATCH    ((farptr) -3L)
  2313.              #define WATCH     (-3)
  2314.  
  2315.                   -3 is returned if the task was waked up during a wait
  2316.                   by a watchpoint or hotkey action.
  2317.  
  2318.  
  2319.                                       Queues
  2320.  
  2321.         The 'queue' structure is a dual link for linking task control
  2322.         blocks and timer blocks. The first three fields are used both for
  2323.         the queue head, and for elements to be inserted in a queue.
  2324.  
  2325.         CAUTION: Do not change the order of the first three fields in
  2326.         either queue or queue_head! Those two structures are used
  2327.         interchangeably in various places in the CTask kernel. Changing
  2328.         one of them would have catastrophic results.
  2329.  
  2330.         The queue element ("queue") contains the forward and backward
  2331.         pointer, a structure kind field, plus the priority (when used in
  2332.         a TCB) or the timeout value (when used in a tlink structure). The
  2333.         kind field is used to identify the type of structure the queue
  2334.         element is a part of, and also to identify the "end" of the
  2335.         queue. To simplify insertion and removal, all queues are circular
  2336.         in nature, i.e. there is no NULL-pointer at the head or tail. The
  2337.         queue head, and thus the end of a queue, is identified by a bit 7
  2338.         (Q_HEAD) being set in the kind field.
  2339.  
  2340.         #define Q_HEAD 0x80 /* Queue head flag */
  2341.  
  2342.              typedef struct {
  2343.                              word     prior;
  2344.                              word     ini_prior;
  2345.                             } qelem_pri;
  2346.  
  2347.              typedef struct queue_rec far *queptr;
  2348.  
  2349.  
  2350.         
  2351.         
  2352.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 37
  2353.  
  2354.  
  2355.              typedef struct queue_rec {
  2356.                                        queptr   volatile next;
  2357.                                        queptr   volatile prev;
  2358.                                        byte     kind;
  2359.                                        union  {
  2360.                                               qelem_pri   pri;
  2361.                                               dword       ticks;
  2362.                                               } el;
  2363.                                        } queue;
  2364.  
  2365.         The queue head ("queue_head") also contains the forward and
  2366.         backward pointer, and the structure kind field. The same
  2367.         structure is also used to chain name and timeout/watch/hotkey
  2368.         blocks, since those do not need the priority/tick field present
  2369.         in normal queue elements.
  2370.  
  2371.              typedef struct {
  2372.                              queptr   volatile first;
  2373.                              queptr   volatile last;
  2374.                              byte     kind;
  2375.                             } queue_head;
  2376.  
  2377.              typedef queue_head far *queheadptr;
  2378.  
  2379.  
  2380.  
  2381.                        The timer/watch/hotkey control block
  2382.  
  2383.         The timer control block is included in every task control block.
  2384.         It may also be created as a separate entity to specify special
  2385.         actions to be executed after or every n timer ticks, to specify
  2386.         memory or port locations to be watched for a change or a certain
  2387.         value on every timer tick, or for keyboard hotkeys.
  2388.  
  2389.         The "link" field links the active structures into the timer,
  2390.         watch, or hotkey queue. The kind of the element (which is
  2391.         specified by the "kind" field of "link") determines the
  2392.         appropriate queue.
  2393.  
  2394.         The "chain" field (present only if task groups are enabled) links
  2395.         all timer structures of a group. This allows automatic removal of
  2396.         elements on termination.
  2397.  
  2398.         The "next" field is exclusively used by the timer task to chain
  2399.         elements that have to be activated.
  2400.  
  2401.  
  2402.  
  2403.  
  2404.  
  2405.  
  2406.  
  2407.  
  2408.         
  2409.         
  2410.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 38
  2411.  
  2412.  
  2413.         "strucp" points to the structure to be acted upon, "struckind"
  2414.         specifies the kind of structure:
  2415.  
  2416.              #define  TKIND_TASK        1
  2417.  
  2418.                   Strucp points to the task control block of which the
  2419.                   element is a member. The task will be awakened when the
  2420.                   timeout expires.
  2421.  
  2422.              #define  TKIND_WAKE        2
  2423.  
  2424.                   Strucp points to a task control block. Otherwise same
  2425.                   as TKIND_TASK.
  2426.  
  2427.              #define  TKIND_PROC        3
  2428.  
  2429.                   Strucp contains the address of a function to be called
  2430.                   on timeout.
  2431.  
  2432.              #define  TKIND_FLAG        4
  2433.  
  2434.                   Strucp points to a flag that should be set on timeout.
  2435.  
  2436.              #define  TKIND_COUNTER     5
  2437.  
  2438.                   Strucp points to a counter that should be increased on
  2439.                   timeout.
  2440.  
  2441.              #define  TKIND_COUNTDEC    6
  2442.  
  2443.                   Strucp points to a counter that should be decreased on
  2444.                   timeout.
  2445.  
  2446.         The timeout structure is used for timeouts, memory/port
  2447.         watchpoints, and hotkeys. The union "elem" contains either the
  2448.         tick reload value, the specs for the memory or port location to
  2449.         watch, or the hotkey scancode and flag values. "elkind" specifies
  2450.         the kind of structure used in the upper nibble:
  2451.  
  2452.              #define  TELEM_TIMER       0x10
  2453.  
  2454.                   This is a timeout element.
  2455.  
  2456.              #define  TELEM_MEM         0x20
  2457.  
  2458.                   This is a memory watch element.
  2459.  
  2460.              #define  TELEM_PORT        0x30
  2461.  
  2462.                   This is a port watch element.
  2463.  
  2464.  
  2465.  
  2466.         
  2467.         
  2468.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 39
  2469.  
  2470.  
  2471.              #define  TELEM_HOTKEY      0x40
  2472.  
  2473.                   This is a keyboard hotkey element.
  2474.  
  2475.  
  2476.         The lower nibble of "elkind" is used for watchpoints, it
  2477.         specifies the comparison operation:
  2478.  
  2479.              #define  TCMP_EQ           1
  2480.  
  2481.                   Activate watch if value read is equal to "compare".
  2482.  
  2483.              #define  TCMP_NE           2
  2484.  
  2485.                   Activate watch if value read is not equal to "compare".
  2486.  
  2487.              #define  TCMP_GE           3
  2488.  
  2489.                   Activate watch if value read is >= "compare"
  2490.                   (unsigned).
  2491.  
  2492.              #define  TCMP_LE           4
  2493.  
  2494.                   Activate watch if value read is <= "compare"
  2495.                   (unsigned).
  2496.  
  2497.              #define  TCMP_GES          5
  2498.  
  2499.                   Activate watch if value read is >= "compare" (signed).
  2500.  
  2501.              #define  TCMP_LES          6
  2502.  
  2503.                   Activate watch if value read is <= "compare" (signed).
  2504.  
  2505.              #define  TCMP_CHG          7
  2506.  
  2507.                   Activate watch if value read is not equal to "compare".
  2508.                   Additionally, store the value read into the "compare"
  2509.                   field. Only useful for continuous watchpoints.
  2510.  
  2511.  
  2512.         For timeouts, "elem.time" contains the "reload" value used for
  2513.         repetitive timeout actions to reload the original timeout value.
  2514.         The actual timeout value is part of the link structure.
  2515.  
  2516.         For port watches, "elem.port" contains the values "port", "mask",
  2517.         "compare" and "in_word". "port" holds the port number to read
  2518.         from.  The value read is masked with "mask", and compared with
  2519.         "compare". A word access is used if "in_word" is nonzero.
  2520.  
  2521.         Memory watches are similar to port watches, with "elem.mem"
  2522.         containing "address", the memory address to watch, and "mask" and
  2523.         "compare" as above.
  2524.         
  2525.         
  2526.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 40
  2527.  
  2528.  
  2529.         Keyboard hotkeys hold the three BIOS keyboard flag comparison
  2530.         values, and the keyboard scancode, in "elem.key".
  2531.  
  2532.         The "flags" field holds both permanent and temporary processing
  2533.         flags:
  2534.  
  2535.              #define  TFLAG_BUSY        0x01
  2536.  
  2537.                   If this bit is set, the timer task is busy processing
  2538.                   this element. It may not be deleted or de/enqueued.
  2539.                   Routines processing timer elements must not modify the
  2540.                   control block except the flag field.
  2541.  
  2542.              #define  TFLAG_ENQUEUE     0x02
  2543.  
  2544.                   The element is to be (re-)enqueued in the appropriate
  2545.                   queue after processing. This is a temporary flag, used
  2546.                   only while TFLAG_BUSY is set.
  2547.  
  2548.              #define  TFLAG_UNQUEUE     0x04
  2549.  
  2550.                   The element is to be removed from its queue after
  2551.                   processing. This is a temporary flag, used only while
  2552.                   TFLAG_BUSY is set.
  2553.  
  2554.              #define  TFLAG_REMOVE      0x08
  2555.  
  2556.                   The element is to be deallocated after processing. This
  2557.                   is a temporary flag, used only while TFLAG_BUSY is set,
  2558.                   for elements with TFLAG_TEMP set.
  2559.  
  2560.              #define  TFLAG_REPEAT      0x40
  2561.  
  2562.                   The element is a repeat element. For timeout elements,
  2563.                   the timeout count is reloaded on activation. Other
  2564.                   elements are re-enqueued without change when activated.
  2565.  
  2566.              #define  TFLAG_TEMP        0x80
  2567.  
  2568.                   If this bit is set, this is a temporary element, which
  2569.                   will be deallocated on activation or delete.
  2570.  
  2571.  
  2572.         The "user_parm" field may be used to pass pointers or other
  2573.         values to timeout functions. It is not modified by the CTask
  2574.         kernel routines.
  2575.  
  2576.  
  2577.  
  2578.  
  2579.  
  2580.  
  2581.  
  2582.         
  2583.         
  2584.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 41
  2585.  
  2586.  
  2587.              typedef struct tlink_rec far *tlinkptr;
  2588.  
  2589.              struct telem_memwatch {
  2590.                                    wordptr address;
  2591.                                    word    mask;
  2592.                                    word    compare;
  2593.                                    };
  2594.  
  2595.              struct telem_portwatch {
  2596.                                      word  port;
  2597.                                      word  mask;
  2598.                                      word  compare;
  2599.                                      byte  in_word;
  2600.                                     };
  2601.  
  2602.              struct telem_timeout {
  2603.                                    dword    reload;
  2604.                                   };
  2605.  
  2606.              typedef struct {
  2607.                               byte  mask;
  2608.                               byte  compare;
  2609.                             } kbflag;
  2610.  
  2611.              struct telem_hotkey {
  2612.                                   kbflag   flag1;
  2613.                                   kbflag   flag2;
  2614.                                   kbflag   flag3;
  2615.                                   byte     scancode;
  2616.                                  };
  2617.  
  2618.              struct tlink_rec {
  2619.                                queue    link;
  2620.                                tlinkptr next;
  2621.                                farptr   strucp;
  2622.                                dword    user_parm;
  2623.                                queue_head chain; (if GROUPS)
  2624.                                union {
  2625.                                      struct telem_memwatch   mem;
  2626.                                      struct telem_portwatch  port;
  2627.                                      struct telem_timeout    time;
  2628.                                      struct telem_hotkey     key;
  2629.                                      }  elem;
  2630.                                byte     elkind;
  2631.                                byte     struckind;
  2632.                                byte     flags;
  2633.                               };
  2634.  
  2635.              typedef struct tlink_rec tlink;
  2636.  
  2637.  
  2638.  
  2639.  
  2640.         
  2641.         
  2642.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 42
  2643.  
  2644.  
  2645.                              The name link structure
  2646.  
  2647.         If TSK_NAMED is enabled, all structures except the timer control
  2648.         block contain a name link. All control blocks are linked and
  2649.         named via this element.
  2650.  
  2651.         "strucp" points to the head of the structure the name link is an
  2652.         element of, with "kind" in the list field specifying the type of
  2653.         structure:
  2654.  
  2655.              #define  TYP_GROUP      0     Group control block
  2656.              #define  TYP_TCB        1     task control block
  2657.              #define  TYP_FLAG       2     flag event
  2658.              #define  TYP_RESOURCE   3     resource event
  2659.              #define  TYP_COUNTER    4     counter event
  2660.              #define  TYP_MAILBOX    5     mailbox event
  2661.              #define  TYP_PIPE       6     byte pipe
  2662.              #define  TYP_WPIPE      7     word pipe
  2663.              #define  TYP_BUFFER     8     buffer
  2664.              #define  TYP_TIMER      9     timeout element
  2665.              #define  TYP_WATCH     10     memory/port watch element
  2666.              #define  TYP_HOTKEY    11     hotkey element
  2667.  
  2668.         The head element of the name list (normally the group control
  2669.         block) has the Q_HEAD bit in its kind field set.
  2670.  
  2671.         The "name" field contains an up to 8-character name plus a zero
  2672.         terminator.
  2673.  
  2674.              #define  NAMELENGTH     9
  2675.  
  2676.              typedef struct name_rec far *nameptr;
  2677.  
  2678.              struct name_rec {
  2679.                              queue_head list;
  2680.                              farptr     strucp;
  2681.                              char       name [NAMELENGTH];
  2682.                              };
  2683.  
  2684.              typedef struct name_rec namerec;
  2685.  
  2686.  
  2687.                          The task control block structure
  2688.  
  2689.  
  2690.         The "cqueue" field links the TCB into one of the queues. The
  2691.         "qhead" pointer points to the head of the queue the task is
  2692.         enqueued in, or will be enqueued in on the next schedule request
  2693.         in the case of the current running task.
  2694.  
  2695.         The "prior" field in the cqueue structure contains the tasks
  2696.         current priority, with 0xffff the highest possible priority, and
  2697.         0 the lowest. The "ini_prior" field initially contains the same
  2698.         
  2699.         
  2700.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 43
  2701.  
  2702.  
  2703.         value. If variable priority is enabled, "prior" is incremented on
  2704.         each scheduler call, and reset to "ini_prior" when the task is
  2705.         activated.
  2706.  
  2707.         "stack" contains the saved task stack pointer (offset and
  2708.         segment) if the task is not running. The field "stkbot" contains
  2709.         the bottom address of the task stack. It is set by create_task,
  2710.         and is used by the scheduler and the snapshot dump module if
  2711.         checking is enabled to check for stack overflow and stack usage.
  2712.  
  2713.         The "t_ax", "t_cx", ..., "t_ds" fields hold the register contents
  2714.         while a task is inactive.
  2715.  
  2716.         "state" and "flags" contain the tasks state and flags.
  2717.  
  2718.         "timerq" is a tlink structure used to chain the tcb into the
  2719.         timer queue if the task is waiting for a timeout, into the watch
  2720.         queue if the task is waiting for a watch event, or into one of
  2721.         the hotkey queues if the task is waiting for a hotkey. See above
  2722.         for a description of the tlink structure.
  2723.  
  2724.         The fields "retptr" and "retsize" are used in event handling.
  2725.         They are used when a task is waiting for an event by the task
  2726.         activating the event, and also by timeout and wake to indicate
  2727.         error returns. The use of these pointers eliminates the need to
  2728.         loop for an event, which requires slightly more code in the event
  2729.         handling routines, but reduces the need for task switching.
  2730.  
  2731.         The "save_func" and "rest_func" pointers can optionally point to
  2732.         task-switch save and restore functions. In special applications,
  2733.         it may be necessary to save and restore global variables or other
  2734.         items when a task is deactivated. The save function is called
  2735.         when a task is deactivated, the restore function when a task is
  2736.         activated. Both functions should be defined as
  2737.  
  2738.            void Taskfunc funcname (tcbptr tcb);
  2739.  
  2740.         The functions are called with a pointer to the current TCB, DS is
  2741.         set up to point to the TCB data segment. Interrupts are enabled.
  2742.         The stack is the scheduler's local stack, so the routine must not
  2743.         use excessive local stack space. Calling CTask-routines that
  2744.         might cause the scheduler to be activated must be avoided. See
  2745.         the "Advanced Topics" chapter for more information.
  2746.  
  2747.         The "user_ptr" field can hold any pointer or other value to be
  2748.         used by the save/restore functions or to point to task-related
  2749.         items. This field is not modified by the CTask routines.
  2750.  
  2751.         The "group" and "homegroup" pointers link a task with it's
  2752.         current task group, and with the base group that created the task
  2753.         if the task spawned a secondary invocation of CTask.
  2754.  
  2755.  
  2756.         
  2757.         
  2758.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 44
  2759.  
  2760.  
  2761.         The DOS-related fields "indos", "new", "base_psp", "psp_sssp",
  2762.         and "swap_area" are used to save critical information on the
  2763.         state of DOS. They should never be tampered with. The same goes
  2764.         for "sched_ent_func" which holds a function pointer to an
  2765.         internal function of the DOS module when a task is active in DOS.
  2766.  
  2767.         The "name" namerec structure is present only if TSK_NAMED is
  2768.         enabled. It may be used in debugging (see tsksnap.c for an
  2769.         example), and in applications where the address of the structure
  2770.         can not be passed directly.
  2771.  
  2772.         The "ems_map" and "ndpsave" fields hold the EMS and numeric
  2773.         coprocessor state, and are only present if the respective options
  2774.         are enabled.
  2775.  
  2776.              typedef struct tcb_rec far *tcbptr;
  2777.  
  2778.              struct tcb_rec {
  2779.                          queue          cqueue;
  2780.                          queheadptr     qhead;
  2781.                          byteptr        stkbot;
  2782.                          volatile byte  state;
  2783.                          byte           flags;
  2784.  
  2785.                          byteptr        stack;
  2786.                          word           t_ax;
  2787.                          word           t_cx;
  2788.                          word           t_dx;
  2789.                          word           t_si;
  2790.                          word           t_di;
  2791.                          word           t_bp;
  2792.                          word           t_es;
  2793.                          word           t_ds;
  2794.  
  2795.                          tlink          timerq;
  2796.                          volatile farptr retptr;
  2797.                          volatile int    retsize;
  2798.  
  2799.                          funcptr        save_func;
  2800.                          funcptr        rest_func;
  2801.                          farptr         user_ptr;
  2802.                          gcbptr         group; (if GROUPS)
  2803.                          gcbptr         homegroup; (if GROUPS)
  2804.                          funcptr        sched_ent_func; (if DOS)
  2805.                          volatile byte  indos; (if DOS)
  2806.                          volatile byte  new; (if DOS)
  2807.                          word           base_psp; (if DOS)
  2808.                          dword          psp_sssp; (if DOS)
  2809.                          byte           swap_area [DOSSWAPSIZE]; (if DOS)
  2810.                          namerec        name; (if TSK_NAMED)
  2811.                          byte           ems_map [EMS_SAVE_SIZE]; (if EMS)
  2812.                          ndpsave_t      ndpsave; (if NDP)
  2813.                          };
  2814.         
  2815.         
  2816.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 45
  2817.  
  2818.  
  2819.              typedef struct tcb_rec tcb;
  2820.  
  2821.  
  2822.  
  2823.                                    Task states
  2824.  
  2825.  
  2826.              #define  ST_KILLED   0
  2827.  
  2828.                   The task has been killed. Restarting the task is not
  2829.                   possible. Queue pointers are invalid.
  2830.  
  2831.              #define  ST_STOPPED  1
  2832.  
  2833.                   The task is not enqueued in any queue. To be included
  2834.                   in scheduling, it has to be explicitly started. The
  2835.                   queue head pointer is NULL.
  2836.  
  2837.              #define  ST_DELAYED  2
  2838.  
  2839.                   The task is enqueued in the timer queue only. When the
  2840.                   timer expires, it is placed in the eligible queue.  The
  2841.                   queue head pointer is NULL.
  2842.  
  2843.              #define  ST_WAITING  3
  2844.  
  2845.                   The task is waiting for an event to happen.  It can
  2846.                   also be chained into the timer queue if a timeout was
  2847.                   specified in the call.  The queue head pointer points
  2848.                   to the queue head in the event control block for the
  2849.                   event the process is waiting on.
  2850.  
  2851.              #define  ST_ELIGIBLE 4
  2852.  
  2853.                   The task is enqueued in the queue of processes eligible
  2854.                   for running. It can not be chained in the timer queue.
  2855.                   The queue head pointer points to the eligible queue.
  2856.  
  2857.              #define  ST_RUNNING  5
  2858.  
  2859.                   The task is the current running process. Although it is
  2860.                   not enqueued in any queue, the queue head pointer in
  2861.                   its control block is valid and points to the queue the
  2862.                   process will be enqueued in on the next schedule
  2863.                   request.
  2864.  
  2865.  
  2866.  
  2867.  
  2868.  
  2869.  
  2870.  
  2871.  
  2872.         
  2873.         
  2874.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 46
  2875.  
  2876.  
  2877.         Possible state transitions and their reasons:
  2878.  
  2879.            stopped  -> eligible    by start_task ()
  2880.  
  2881.            delayed  -> killed      by kill_task ()
  2882.                     -> eligible    by timer task, or wake_task ()
  2883.  
  2884.            eligible -> killed      by kill_task ()
  2885.                     -> running     by scheduler
  2886.  
  2887.            running  -> killed      by kill_task (), or return
  2888.                     -> stopped     by delay (0)
  2889.                     -> delayed     by delay (n != 0)
  2890.                     -> eligible    by scheduler
  2891.                     -> waiting     by wait_xxx ()
  2892.  
  2893.            waiting  -> killed      by kill_task (), or event deletion
  2894.                     -> eligible    by event happening, timeout,
  2895.                                    or wake_task()
  2896.  
  2897.  
  2898.  
  2899.                                     Task flags
  2900.  
  2901.         System flags:
  2902.  
  2903.              #define  F_TEMP   0x80
  2904.  
  2905.                   This tcb was allocated automatically, and must be
  2906.                   free'd on task kill.
  2907.  
  2908.              #define  F_STTEMP 0x40
  2909.  
  2910.                   The tasks stack was allocated automatically, and must
  2911.                   be free'd on task kill.
  2912.  
  2913.              #define  F_PERM   0x20
  2914.  
  2915.                   This is a "permanent" system task, it may not be killed.
  2916.  
  2917.  
  2918.  
  2919.  
  2920.  
  2921.  
  2922.  
  2923.  
  2924.  
  2925.  
  2926.  
  2927.  
  2928.  
  2929.  
  2930.         
  2931.         
  2932.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 47
  2933.  
  2934.  
  2935.         User changeable flags:
  2936.  
  2937.              #define  F_CRIT   0x01
  2938.  
  2939.                   This task may not be preempted. It will run until it
  2940.                   clears this flag, delays itself, calls the scheduler
  2941.                   explicitly, or waits for an event.
  2942.  
  2943.              #define  F_USES_NDP  0x02
  2944.  
  2945.                   This task uses the numeric coprocessor. The NDP state
  2946.                   must be saved/restored on a task switch. Do not set
  2947.                   this flag if no coprocessor is installed.
  2948.  
  2949.  
  2950.                              The Group Control Block
  2951.  
  2952.         Each invocation of CTask owns a group control block, gcb. This
  2953.         structure holds all information relevant to this invocation only,
  2954.         and chains all data structures created in this group.
  2955.  
  2956.         The "home", "level", and "branch" fields interconnect the groups
  2957.         (see the chapter on groups for more information).
  2958.  
  2959.         The "creator" field identifies the creating task.
  2960.  
  2961.         The "exit_addr", "create_psp", "save_psp", and "save_sssp" fields
  2962.         hold the information necessary to allow spawning CTask
  2963.         applications.
  2964.  
  2965.         The "namelist" field contains the name of the group itself, and
  2966.         links all structures created within this group.
  2967.  
  2968.         "main_ptr" points to the "main" task of this group, i.e. the task
  2969.         designated by a NULL tcb pointer.
  2970.  
  2971.         "remove" holds the last element in a chain of remove functions.
  2972.         This function is called whenever the group is uninstalled.
  2973.  
  2974.         The "telem_list" and "ticker_list" are the heads for the timer
  2975.         element and ticker lists. Timers and tickers are chained into
  2976.         this list to allow automatic removal on group termination.
  2977.  
  2978.         The "palloc" and "pfree" functions hold pointers to the
  2979.         allocation functions tsk_alloc and tsk_free. The functions are
  2980.         accessed through group-relative pointers to allow code sharing
  2981.         between invocations.
  2982.  
  2983.  
  2984.  
  2985.  
  2986.  
  2987.  
  2988.         
  2989.         
  2990.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 48
  2991.  
  2992.  
  2993.              struct group_rec {
  2994.                             gcbptr         home;
  2995.                             gcbptr         level;
  2996.                             gcbptr         branch;
  2997.                             tcbptr         creator;
  2998.                             dword          exit_addr;
  2999.                             word           create_psp;
  3000.                             word           save_psp;
  3001.                             dword          save_sssp;
  3002.                             namerec        namelist;
  3003.                             tcbptr         main_ptr;
  3004.                             callchainptr   remove;
  3005.                             queue_head     telem_list;
  3006.                             queue_head     ticker_list;
  3007.              #if (TSK_DYNAMIC)
  3008.                             farptr (Globalfunc *palloc)(word);
  3009.                             farptr (Globalfunc *pfree)(farptr);
  3010.              #endif
  3011.                             };
  3012.  
  3013.  
  3014.  
  3015.                              The event control blocks
  3016.  
  3017.         All event control blocks have two optional fields:
  3018.  
  3019.         "name" is only present if TSK_NAMED is enabled. It is a namerec
  3020.         structure as explained above.
  3021.  
  3022.         "flags" is only present if TSK_DYNAMIC is enabled. It contains
  3023.  
  3024.              F_TEMP     If this control block was allocated
  3025.                         automatically, and must be free'd on delete.
  3026.  
  3027.              F_STTEMP   If the buffer for this event was allocated auto-
  3028.                         matically, and must be free'd on delete (pipes
  3029.                         and buffers only).
  3030.  
  3031.  
  3032.  
  3033.                                The Ticker structure
  3034.  
  3035.         The ticker is not an event structure in the true sense, since
  3036.         there are no operations that wait on a ticker. It is the only
  3037.         control structure linked by a single forward pointer. It contains
  3038.         this "next" pointer, a doubleword "ticks" count that is counted
  3039.         down towards zero on every hardware clock tick, and the optional
  3040.         "flags" field. It is permissible to access and modify the "ticks"
  3041.         field directly. If task groups are enabled, an additional "chain"
  3042.         field links all ticker structures of a group to allow automatic
  3043.         removal on group termination.
  3044.  
  3045.  
  3046.         
  3047.         
  3048.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 49
  3049.  
  3050.  
  3051.              typedef struct ticker_rec far *tick_ptr;
  3052.  
  3053.              typedef struct ticker_rec {
  3054.                                         tick_ptr next;
  3055.                                         dword    ticks;
  3056.                                         queue_head chain; (if GROUPS)
  3057.                                         byte     flags; (if TSK_DYNAMIC)
  3058.                                         } ticker;
  3059.  
  3060.  
  3061.  
  3062.                              The Flag event structure
  3063.  
  3064.         Contains two queues for processes waiting on a flag state (clear
  3065.         or set), plus the flag state (0 = clear, 1 = set).
  3066.  
  3067.              typedef struct {
  3068.                              queue_head  wait_set;
  3069.                              queue_head  wait_clear;
  3070.                              int         state;
  3071.                              byte        flags;   (if TSK_DYNAMIC)
  3072.                              namerec     name;    (if TSK_NAMED)
  3073.                              } flag;
  3074.  
  3075.              typedef flag far *flagptr;
  3076.  
  3077.  
  3078.                            The counter event structure
  3079.  
  3080.         Similar to a flag, but contains a doubleword state counter.
  3081.  
  3082.              typedef struct {
  3083.                              queue_head  wait_set;
  3084.                              queue_head  wait_clear;
  3085.                              dword       state;
  3086.                              byte        flags;   (if TSK_DYNAMIC)
  3087.                              namerec     name;    (if TSK_NAMED)
  3088.                             } counter;
  3089.  
  3090.              typedef counter far *counterptr;
  3091.  
  3092.  
  3093.  
  3094.  
  3095.  
  3096.  
  3097.  
  3098.  
  3099.  
  3100.  
  3101.  
  3102.  
  3103.  
  3104.         
  3105.         
  3106.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 50
  3107.  
  3108.  
  3109.                            The resource event structure
  3110.  
  3111.         Contains a queue for the tasks waiting for access to the
  3112.         resource, a pointer to the current owner of the resource (to
  3113.         check for illegal "release_resource" and nested request calls),
  3114.         and the resource request counter (0 = free, <> 0 = in use).
  3115.  
  3116.              typedef struct {
  3117.                              queue_head   waiting;
  3118.                              queue_head   owner;
  3119.                              word         count;
  3120.                              byte         flags;   (if TSK_DYNAMIC)
  3121.                              namerec      name;    (if TSK_NAMED)
  3122.                             } resource;
  3123.  
  3124.              typedef resource far *resourceptr;
  3125.  
  3126.  
  3127.  
  3128.                            The mailbox event structure
  3129.  
  3130.         The msgptr type is only used internally to chain mail blocks into
  3131.         the mailbox. The mailbox type contains a queue of the tasks
  3132.         waiting for mail, and a first and last pointer for the chain of
  3133.         mail blocks.
  3134.  
  3135.              struct msg_header {
  3136.                                 struct msg_header far *next;
  3137.                                };
  3138.  
  3139.              typedef struct msg_header far *msgptr;
  3140.              typedef mailbox far *mailboxptr;
  3141.  
  3142.              typedef struct {
  3143.                              queue_head  waiting;
  3144.                              msgptr      mail_first;
  3145.                              msgptr      mail_last;
  3146.                              byte        flags;   (if TSK_DYNAMIC)
  3147.                              namerec     name;    (if TSK_NAMED)
  3148.                             } mailbox;
  3149.  
  3150.  
  3151.  
  3152.                       The pipe and word pipe event structure
  3153.  
  3154.         Contains queues of the tasks waiting to read or write to the
  3155.         pipe, indices for reading (outptr) and writing (inptr) into the
  3156.         buffer, the buffer size, the number of bytes or words currently
  3157.         in the pipe ("filled"), and the pointer to the buffer. A word
  3158.         pipe is handled exactly the same as a byte pipe, the only
  3159.         difference being the element size placed in the buffer. With
  3160.         normal pipes, characters are buffered, with word pipes, words.
  3161.  
  3162.         
  3163.         
  3164.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 51
  3165.  
  3166.  
  3167.              typedef struct {
  3168.                              queue_head  wait_read;
  3169.                              queue_head  wait_write;
  3170.                              queue_head  wait_clear;
  3171.                              word        bufsize;
  3172.                              word        filled;
  3173.                              word        inptr;
  3174.                              word        outptr;
  3175.                              byteptr     contents;
  3176.                              byte        flags;   (if TSK_DYNAMIC)
  3177.                              namerec     name;    (if TSK_NAMED)
  3178.                             } pipe;
  3179.  
  3180.              typedef pipe far *pipeptr;
  3181.  
  3182.              typedef struct {
  3183.                              queue_head  wait_read;
  3184.                              queue_head  wait_write;
  3185.                              queue_head  wait_clear;
  3186.                              word        bufsize;
  3187.                              word        filled;
  3188.                              word        inptr;
  3189.                              word        outptr;
  3190.                              wordptr     wcontents;
  3191.                              byte        flags;   (if TSK_DYNAMIC)
  3192.                              namerec     name;    (if TSK_NAMED)
  3193.                             } wpipe;
  3194.  
  3195.              typedef wpipe far *wpipeptr;
  3196.  
  3197.  
  3198.                             The buffer event structure
  3199.  
  3200.         Contains resources for read and write access, the word pipe used
  3201.         for buffering, and a message counter.
  3202.  
  3203.              typedef struct {
  3204.                               resource   buf_write;
  3205.                               resource   buf_read;
  3206.                               wpipe      pip;
  3207.                               word       msgcnt;
  3208.                               byte       flags;   (if TSK_DYNAMIC)
  3209.                               namerec    name;    (if TSK_NAMED)
  3210.                              } buffer;
  3211.  
  3212.              typedef buffer far *bufferptr;
  3213.  
  3214.  
  3215.  
  3216.  
  3217.  
  3218.  
  3219.  
  3220.         
  3221.         
  3222.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 52
  3223.  
  3224.  
  3225.                       The call chain structure
  3226.  
  3227.         The call chain structure is used to link "remove" functions into
  3228.         a chain. This chain is processed when a task group, or the CTask
  3229.         kernel, is removed. It contains a single forward link, and a
  3230.         pointer to the remove function. It also contains a user defined
  3231.         value that can be used by the called remove function.
  3232.  
  3233.              typedef struct callchain_rec far *challchainptr;
  3234.  
  3235.              typedef void (Taskfunc *funcptr_ccp)(callchainptr);
  3236.  
  3237.              typedef struct callchain_rec
  3238.                                     {
  3239.                                     callchainptr next;
  3240.                                     funcptr_ccp  func;
  3241.                                     farptr       user_ptr;
  3242.                                     byte         flags; (if TSK_DYNAMIC)
  3243.                                     } callchain;
  3244.  
  3245.  
  3246.  
  3247.  
  3248.  
  3249.  
  3250.  
  3251.  
  3252.  
  3253.  
  3254.  
  3255.  
  3256.  
  3257.  
  3258.  
  3259.  
  3260.  
  3261.  
  3262.  
  3263.  
  3264.  
  3265.  
  3266.  
  3267.  
  3268.  
  3269.  
  3270.  
  3271.  
  3272.  
  3273.  
  3274.  
  3275.  
  3276.  
  3277.  
  3278.         
  3279.         
  3280.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 53
  3281.  
  3282.  
  3283.                                   CTask Routines
  3284.  
  3285.                                  Global Variables
  3286.  
  3287.  
  3288.         int ctask_active
  3289.  
  3290.              Contains 1 if CTask was installed, 0 before the call to
  3291.              install_tasker and after the call to remove_tasker.
  3292.  
  3293.  
  3294.         int tsk_use_ndp
  3295.  
  3296.              Is set to 1 by install_tasker if the NDP configuration
  3297.              option is TRUE and a numeric coprocessor is installed. This
  3298.              variable is used by create_task to determine whether to set
  3299.              the F_USES_NDP task flag. If tsk_use_ndp is nonzero during
  3300.              the call to create_task, the flag is set, causing the NDP
  3301.              state to be saved and restored for this task. You can change
  3302.              this variable to 0 before calling create_task to avoid this.
  3303.              You can also turn on or off the flag individually with
  3304.              tsk_set_flag, but it is usually safer to use the
  3305.              tsk_uses_ndp variable. Setting the F_USES_NDP flag through
  3306.              tsk_set_flag when no coprocessor is present may hang the
  3307.              system.
  3308.  
  3309.  
  3310.                              Installation and Removal
  3311.  
  3312.         int install_tasker (int varpri, int speedup,
  3313.                             word flags, byteptr name);
  3314.  
  3315.  
  3316.              Installs the multitasker. Must be called prior to any other
  3317.              routine except for secondary kernels. The calling routine is
  3318.              defined as the main task, and assigned the highest priority.
  3319.              To allow other tasks to execute, the main task must have its
  3320.              priority reduced, be delayed, or wait on an event.
  3321.  
  3322.              Returns 1 if CTask was already present in the system, i.e.
  3323.              this is a secondary invocation. Returns 0 if this is the
  3324.              first installation of CTask.
  3325.  
  3326.              "varpri"  Enables variable priority if nonzero.
  3327.  
  3328.  
  3329.  
  3330.  
  3331.  
  3332.  
  3333.  
  3334.  
  3335.  
  3336.         
  3337.         
  3338.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 54
  3339.  
  3340.  
  3341.              "speedup" is defined for the IBM PC/XT/AT as the clock tick
  3342.                        speedup factor. The timer tick frequency will be
  3343.                        set to 
  3344.  
  3345.                        speedup  ticks/sec   msecs/tick
  3346.                           0        18.2        54.9   (normal clock)
  3347.                           1        36.4        27.5
  3348.                           2        72.8        13.7
  3349.                           3       145.6         6.9
  3350.                           4       291.3         3.4
  3351.  
  3352.                        Note that all timeouts are specified in tick
  3353.                        units, so changing the speedup parameter will
  3354.                        influence timeouts and delays. You can enable
  3355.                        CLOCK_MSEC in tskconf.h to allow timeouts to be
  3356.                        specified in milliseconds. The system clock will
  3357.                        not be disturbed by changing the speed. Using
  3358.                        values above 2 can lead to interrupt overruns on
  3359.                        slower machines and is not recommended.
  3360.  
  3361.              "flags"   controls various installation flags through the
  3362.                        bitwise OR of the following flags defined in
  3363.                        TSK.H:
  3364.  
  3365.                IFL_VIDEO      Install INT 10 access resource if set. No
  3366.                            protection of Video interrupt if clear.
  3367.                            Installation of the Video resource is safer,
  3368.                            but may slow down the system noticeably. It is
  3369.                            not necessary if you don't do screen-I/O
  3370.                            through the BIOS from your CTask program.
  3371.  
  3372.                IFL_DISK        Install INT 13 access resource if set. No
  3373.                            protection of Disk interrupt if clear.
  3374.                            Installation of INT 13 is recommended for
  3375.                            better system safety. The resource will allow
  3376.                            parallel access to floppy and harddisk, but
  3377.                            might be incompatible with some special
  3378.                            programs (though none have yet been reported).
  3379.  
  3380.                IFL_INT8_DIR Call original INT 8 directly if set.
  3381.                            This changes the timing for the timer inter-
  3382.                            rupt. If this flag is clear, the original
  3383.                            timer interrupt is chained to through a task,
  3384.                            so it can be preempted. If it is set, the
  3385.                            original interrupt is chained to directly, at
  3386.                            the start of timer interrupt processing. This
  3387.                            avoids compatibility problems with certain
  3388.                            TSR's and Networks, but may impair CTask
  3389.                            operations while those TSR's are active.
  3390.  
  3391.  
  3392.  
  3393.  
  3394.         
  3395.         
  3396.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 55
  3397.  
  3398.  
  3399.                IFL_PRINTER  Install INT 17 handler if set.
  3400.                            Installation of the printer interrupt handler
  3401.                            avoids lengthy busy waiting on printer output,
  3402.                            but might be incompatible with certain printer
  3403.                            redirectors.
  3404.  
  3405.                IFL_INT15      Install IBM-AT INT 15 handler if set.
  3406.                            The IBM INT 15 handler allows avoiding some
  3407.                            busy waiting loops. It may, however, be
  3408.                            incompatible with some non-100% clones, and
  3409.                            with debuggers like Periscope IV. If you're
  3410.                            not sure, don't set this flag.
  3411.  
  3412.                IFL_NODOSVARS
  3413.                            Do not copy the internal DOS variable area if
  3414.                            set. This flag may be used for incompatible
  3415.                            versions of DOS or it's clones, but background
  3416.                            DOS access will not work if this flag is set.
  3417.                            Use only for known incompatible versions, and
  3418.                            only if you do not intend to TSR or Spawn.
  3419.  
  3420.                IFL_NOEXITCHECK
  3421.                            Don't check for premature exit if set. This
  3422.                            flag may be set to disable the standard check
  3423.                            for program exit without proper CTask
  3424.                            termination. It may be useful in conjunction
  3425.                            with MS Windows programs using CTask, since
  3426.                            the Windows logic may fool the normal exit
  3427.                            check.
  3428.  
  3429.              "name"     is the name of the created task group.
  3430.  
  3431.  
  3432.         void  remove_tasker (void);
  3433.  
  3434.              Uninstalls the multitasker. Must only be called from the
  3435.              main task, and should be called before exiting the program.
  3436.  
  3437.  
  3438.         int ctask_resident (void);
  3439.  
  3440.              This routine allows checking if another copy of CTask is
  3441.              already resident. It must be called before install_tasker is
  3442.              invoked.
  3443.  
  3444.              Returns 1 if CTask is resident, 0 otherwise. It always
  3445.              returns 1 after install_tasker has been called.
  3446.  
  3447.  
  3448.  
  3449.  
  3450.  
  3451.  
  3452.         
  3453.         
  3454.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 56
  3455.  
  3456.  
  3457.         int link_ctask (void);
  3458.  
  3459.              This routine checks if another copy of CTask is resident,
  3460.              and verifies that the resident copy has a routine stub table
  3461.              to allow code sharing. It must be called before
  3462.              install_tasker is invoked.
  3463.  
  3464.              Returns 1 if a code-sharing copy of CTask is resident, 0
  3465.              otherwise. It always returns 1 after install_tasker has been
  3466.              called.
  3467.  
  3468.  
  3469.                                Searching for names
  3470.  
  3471.  
  3472.         farptr find_name (byteptr name, int kind);
  3473.  
  3474.              This routine searches for a task, group, or event structure
  3475.              from the current task's group downward to the base group.
  3476.  
  3477.              Returns a pointer to the structure, or a pointer to the name
  3478.              record within the structure (depending on kind) if the name
  3479.              was found, LNULL otherwise.
  3480.  
  3481.              This routine may be called before "install_tasker" has been
  3482.              invoked to search names in resident copies.
  3483.  
  3484.              "name"     pointer to a zero-terminated, up to eight
  3485.                         character, name. Case is significant in names.
  3486.  
  3487.              "kind"     is the kind of structure to search for:
  3488.  
  3489.                         If -1, all structures are searched, and the first
  3490.                         structure with the given name is returned. In
  3491.                         this case, the returned pointer points to the
  3492.                         name record within the structure, to allow
  3493.                         identification of the structure. The "strucp"
  3494.                         pointer within that record points to the start of
  3495.                         the structure, the "kind" field in the link
  3496.                         structure identifies the type of the structure.
  3497.  
  3498.                         If kind is >= 0, the returned pointer is a
  3499.                         pointer to the start of the structure:
  3500.  
  3501.                           TYP_GROUP      - Search for Groups only
  3502.                           TYP_FLAG       - Search for Flags only
  3503.                           TYP_RESOURCE   - Search for Resources only
  3504.                           TYP_COUNTER    - Search for Counters only
  3505.                           TYP_MAILBOX    - Search for Mailboxes only
  3506.                           TYP_PIPE       - Search for Pipes only
  3507.                           TYP_WPIPE      - Search for Word Pipes only
  3508.                           TYP_BUFFER     - Search for Buffers only
  3509.  
  3510.         
  3511.         
  3512.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 57
  3513.  
  3514.  
  3515.         farptr find_group_name (gcbptr group, byteptr name, int kind);
  3516.  
  3517.              Looks for a name in the specified group only.
  3518.  
  3519.              Return value and parameters match those of find_group_name,
  3520.              except
  3521.  
  3522.              "group"    pointer to a group control block.
  3523.  
  3524.  
  3525.  
  3526.                                    Adding names
  3527.  
  3528.  
  3529.         void  add_event_name (nameptr elem);
  3530.  
  3531.              Task and event names are normally linked into the name chain
  3532.              automatically on creation. Statically initialised event
  3533.              blocks (events defined with DEF_xxx macros) do not need the
  3534.              create_xxx call, but you have to call add_event_name to link
  3535.              the structure into the name chain.
  3536.  
  3537.              "elem"     is a pointer to the "name" field in the event
  3538.                         control block.
  3539.  
  3540.              Example:
  3541.  
  3542.                   void init_my_flag (void)
  3543.                   {
  3544.                        static DEF_FLAG(my_flag, "MyFlag");
  3545.  
  3546.                        add_event_name (&my_flag.name);
  3547.                   }
  3548.  
  3549.  
  3550.  
  3551.                                   Remove Functions
  3552.  
  3553.  
  3554.         callchainptr chain_removefunc (funcptr_ccp func,
  3555.                                        callchainptr chain,
  3556.                                        farptr user_ptr);
  3557.  
  3558.              Chain a "remove" routine. The remove routine chain is called
  3559.              whenever the group or CTask is removed. It may be used for
  3560.              clean-up work, for example to un-install interrupt handlers.
  3561.              The function enters the routine address passed as parameter
  3562.              into the call chain control block, and chains the block into
  3563.              the remove chain. If dynamic allocation is enabled, the
  3564.              chain pointer may be LNULL.
  3565.  
  3566.              The routine returns the chain pointer, or LNULL if the block
  3567.              could not be allocated.
  3568.         
  3569.         
  3570.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 58
  3571.  
  3572.  
  3573.              Installation example:
  3574.  
  3575.                   callchain remchain;
  3576.  
  3577.                   chain_removefunc (my_remove_func, &remchain, NULL);
  3578.  
  3579.              The remove routine should have the following form:
  3580.  
  3581.                   void Taskfunc my_remove_func (callchainptr chain)
  3582.                   {
  3583.                        ... /* cleanup */
  3584.                   }
  3585.  
  3586.              For more information, refer to the "Advanced Topics" chapter.
  3587.  
  3588.  
  3589.         void  unchain_removefunc (callchainptr chain);
  3590.  
  3591.              Unchain a remove routine from the remove chain.
  3592.  
  3593.  
  3594.  
  3595.                             Preemption and Scheduling
  3596.  
  3597.  
  3598.         void  preempt_off (void);
  3599.  
  3600.              Disables task preemption. This is the default after instal-
  3601.              lation. With preemption turned off, only delays, event
  3602.              waits, and explicit scheduler calls will cause a task
  3603.              switch.
  3604.  
  3605.  
  3606.         void  preempt_on (void);
  3607.  
  3608.              Enables task preemption. Task switches will occur on timer
  3609.              ticks.
  3610.  
  3611.  
  3612.         void  tsk_dis_preempt (void)
  3613.  
  3614.              Temporarily disable task preemption. Preemption will be re-
  3615.              enabled by tsk_ena_preempt or an unconditional scheduler
  3616.              call.
  3617.  
  3618.  
  3619.         void  tsk_ena_preempt (void)
  3620.  
  3621.              Re-enable task preemption. Note that tsk_dis_preempt and
  3622.              tsk_ena_preempt do not change the global preemption state
  3623.              set by preempt_off and preempt_on.
  3624.  
  3625.  
  3626.         
  3627.         
  3628.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 59
  3629.  
  3630.  
  3631.         void  schedule (void);
  3632.  
  3633.              Explicit scheduling request. The highest priority eligible
  3634.              task will be made running.
  3635.  
  3636.  
  3637.         void  c_schedule (void);
  3638.  
  3639.              Conditional scheduling request. Scheduling will take place
  3640.              only if preemption is allowed.
  3641.  
  3642.  
  3643.         void  yield (void);
  3644.  
  3645.              Explicit scheduling request, with task priority temporarily
  3646.              set to zero. If a task has to wait for some external event
  3647.              in a polling loop, this call may be used to allow tasks of
  3648.              lower priority to execute.
  3649.  
  3650.  
  3651.         The following entry points may be used from assembler routines:
  3652.  
  3653.         extrn _tsk_scheduler: far
  3654.  
  3655.              Direct entry into the scheduler. The stack must be set up as
  3656.              for an interrupt handler, e.g.
  3657.  
  3658.                   pushf
  3659.                   cli
  3660.                   call  _tsk_scheduler
  3661.  
  3662.  
  3663.         extrn _sched_int: far
  3664.  
  3665.              Conditional scheduling call. The stack must be set up as for
  3666.              an interrupt handler. This entry should be used by interrupt
  3667.              handlers to cause a reschedule. Interrupt handlers should
  3668.              not use _tsk_schedule.
  3669.  
  3670.  
  3671.  
  3672.                                   Miscellaneous
  3673.  
  3674.  
  3675.         int tsk_dis_int (void)
  3676.  
  3677.              Disable interrupts. Returns the state of the interrupt flag
  3678.              prior to this call (1 if interrupts were enabled).
  3679.  
  3680.  
  3681.  
  3682.  
  3683.  
  3684.         
  3685.         
  3686.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 60
  3687.  
  3688.  
  3689.         void  tsk_ena_int (int state)
  3690.  
  3691.              Enables interrupts if "state" is nonzero. Normally used in
  3692.              conjunction with tsk_dis_int.
  3693.  
  3694.  
  3695.         The routines tsk_dis_int and tsk_ena_int may be used in a simpli-
  3696.         fied  scheme with the defines
  3697.  
  3698.              CRITICAL;      Declares "int crit_intsav;".
  3699.              C_ENTER;       Expands to "crit_intsav = tsk_dis_int ();"
  3700.              C_LEAVE;       Expands to "tsk_ena_int (crit_intsav);".
  3701.  
  3702.  
  3703.         void  tsk_cli (void)
  3704.  
  3705.              Disables interrupts (intrinsic function).
  3706.  
  3707.  
  3708.         void  tsk_sti (void)
  3709.  
  3710.              Unconditionally enables interrupts (intrinsic function).
  3711.  
  3712.  
  3713.         void  tsk_outp (int port, byte b)
  3714.  
  3715.              Outputs the value "b" to hardware-port "port" (intrinsic
  3716.              function).
  3717.  
  3718.  
  3719.         byte  tsk_inp (int port)
  3720.  
  3721.              Returns the value read from port "port" (intrinsic
  3722.              function).
  3723.  
  3724.  
  3725.  
  3726.  
  3727.  
  3728.  
  3729.  
  3730.  
  3731.  
  3732.  
  3733.  
  3734.  
  3735.  
  3736.  
  3737.  
  3738.  
  3739.  
  3740.  
  3741.  
  3742.         
  3743.         
  3744.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 61
  3745.  
  3746.  
  3747.                                  Task Operations
  3748.  
  3749.  
  3750.         tcbptr create_task (tcbptr task, funcptr func, byteptr stack,
  3751.                             word stksz, word prior, farptr arg
  3752.                             [, byteptr name]);
  3753.  
  3754.              Initialises a task. Must be called prior to any other opera-
  3755.              tions on this task. The task is in the stopped state after
  3756.              creation. It must be started to be able to run. If the NDP
  3757.              option is enabled, the F_USES_NDP flag is set in the tcb
  3758.              when the NDP is installed and the global variable
  3759.              tsk_use_ndp is nonzero.
  3760.  
  3761.              Returns a pointer to the created tcb, or LNULL on error.
  3762.  
  3763.              "task"     is a pointer to a tcb (LNULL for automatic allo-
  3764.                         cation).
  3765.  
  3766.              "func"     is a pointer to a void far function, with a
  3767.                         single dword sized parameter.
  3768.  
  3769.              "stack"    is a pointer to a stack area for the task (LNULL
  3770.                         for automatic allocation).
  3771.  
  3772.              "stksz"    is the size of the stack area in bytes.
  3773.  
  3774.              "prior"    is the tasks priority (0 lowest, 0xffff highest).
  3775.  
  3776.              "arg"      is an argument to the created task. It may be
  3777.                         used to differentiate between tasks when using
  3778.                         the same function in different tasks.
  3779.  
  3780.              "name"     is the name of the task, up to eight characters,
  3781.                         plus zero-terminator. This parameter is defined
  3782.                         only if TSK_NAMEPAR is enabled in tskconf.h.
  3783.  
  3784.  
  3785.         void  kill_task (tcbptr task);
  3786.  
  3787.              Kills a task. The task can no longer be used.
  3788.  
  3789.  
  3790.         int start_task (tcbptr task);
  3791.  
  3792.              Starts a task, i.e. makes it eligible for running.
  3793.  
  3794.              Returns 0 if task was started, -1 if the task was not
  3795.              stopped. A value of LNULL for "task" will start the "main
  3796.              task".
  3797.  
  3798.  
  3799.  
  3800.         
  3801.         
  3802.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 62
  3803.  
  3804.  
  3805.         int stop_task (tcbptr task);
  3806.  
  3807.              Stops a task, i.e. removes it from all queues. A value of
  3808.              LNULL for "task" will stop the "main task".
  3809.  
  3810.              Returns 0 on success.
  3811.  
  3812.  
  3813.         int wake_task (tcbptr task);
  3814.  
  3815.              Prematurely wakes a delayed or waiting task. If the task was
  3816.              waiting for an event, it will be removed from the waiting
  3817.              queue, with the operation terminating with an error return
  3818.              value.
  3819.  
  3820.              Returns 0 if task was waked, -1 if the task was not delayed
  3821.              or waiting. A value of LNULL for "task" will wake the "main
  3822.              task".
  3823.  
  3824.  
  3825.         void  set_priority (tcbptr task, word prior)
  3826.  
  3827.              Sets the priority of the specified task to "prior". Note
  3828.              that you should NOT modify the priority field in the tcb
  3829.              structure directly. A value of LNULL for "task" will set the
  3830.              priority of the "main task".
  3831.  
  3832.  
  3833.         word  get_priority (tcbptr task)
  3834.  
  3835.              Returns the initial priority of the specified task. A value
  3836.              of LNULL for "task" will get the priority of the "main
  3837.              task".
  3838.  
  3839.  
  3840.         void  set_task_flags (tcbptr task, byte flags)
  3841.  
  3842.              Sets the flags of the task to "flags". The only flags that
  3843.              can be changed are
  3844.  
  3845.                   F_CRIT         the task can not be preempted if set
  3846.                   F_USES_NDP     the task uses the numeric coprocessor
  3847.  
  3848.              Note that you may NOT modify the flag field in the tcb
  3849.              structure directly. A value of LNULL for "task" will set the
  3850.              flags of the "main task".
  3851.  
  3852.  
  3853.  
  3854.  
  3855.  
  3856.  
  3857.  
  3858.         
  3859.         
  3860.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 63
  3861.  
  3862.  
  3863.         void  set_funcs (tcbptr task, funcptr save, funcptr rest);
  3864.  
  3865.              Sets the save and restore functions for the specified task.
  3866.              The save function is called whenever the task is deacti-
  3867.              vated, the restore function is called whenever the task is
  3868.              scheduled. This allows saving of critical system states upon
  3869.              a task switch. Both functions are called with a far call,
  3870.              the pointer to the task control block is passed as
  3871.              parameter. A value of LNULL for "task" will set the
  3872.              functions of the "main task". To deactivate one or both
  3873.              functions, pass LNULL as function parameter.
  3874.              See the "Advanced Topics" chapter for more information.
  3875.  
  3876.  
  3877.         farptr set_user_ptr (tcbptr task, farptr uptr);
  3878.  
  3879.              Sets the user pointer in the specified TCB, and returns it's
  3880.              previous value. The user pointer may be used to point to
  3881.              memory blocks local to a task, or to hold other task-
  3882.              specific values. It is never accessed or modified by the
  3883.              CTask kernel. A value of LNULL for "task" will set the user
  3884.              pointer of the "main task".
  3885.  
  3886.  
  3887.         farptr get_user_ptr (tcbptr task);
  3888.  
  3889.              Returns the user pointer of the specified TCB. A value of
  3890.              LNULL for "task" will get the user pointer of the "main
  3891.              task".
  3892.  
  3893.  
  3894.         tcbptr curr_task (void);
  3895.  
  3896.              Returns the pointer to the TCB of the currently running
  3897.              task.
  3898.  
  3899.  
  3900.  
  3901.                                  Timer Operations
  3902.  
  3903.  
  3904.         Timeouts are normally specified in timer ticks. If CLOCK_MSEC is
  3905.         enabled, timeouts will be converted to the nearest number of
  3906.         timer ticks automatically.
  3907.  
  3908.  
  3909.         word  ticks_per_sec (void);
  3910.  
  3911.              Returns a rough estimate of the number of ticks per second
  3912.              even if CLOCK_MSEC is not enabled.
  3913.  
  3914.  
  3915.  
  3916.         
  3917.         
  3918.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 64
  3919.  
  3920.  
  3921.                                Event wait Timeouts
  3922.  
  3923.         When  waiting for an event, a timeout may be specified. The ope-
  3924.         ration will terminate with an error return value if the timeout
  3925.         is reached before the event occurs. NOTE that the timeout para-
  3926.         meter is not optional. To specify no timeout, use the value 0L.
  3927.  
  3928.  
  3929.                                     "Tickers"
  3930.  
  3931.         It sometimes is desirable to measure timing intervals or global
  3932.         timeouts without creating special tasks, or while waiting for
  3933.         external events in polling loops. A low overhead way of doing
  3934.         this  is the "ticker" structure. When this structure is linked
  3935.         into  the ticker chain, the doubleword "ticks" field is decre-
  3936.         mented on every timer tick (in the timer interrupt itself), until
  3937.         it reaches zero.
  3938.  
  3939.  
  3940.         tick_ptr create_ticker (tick_ptr elem, dword val);
  3941.  
  3942.              Links a ticker element into the ticker chain. The ticks
  3943.              field is initialized to "val", and will be decremented to
  3944.              zero. If the elem pointer is LNULL, a new ticker element
  3945.              will be created.
  3946.  
  3947.              Returns the ticker element pointer, LNULL on error.
  3948.  
  3949.  
  3950.         void  delete_ticker (tick_ptr elem);
  3951.  
  3952.              Unlinks a ticker element from the ticker chain. Countdown
  3953.              will stop. If the element was allocated dynamically, it will
  3954.              be deleted.
  3955.  
  3956.  
  3957.         void  set_ticker (tick_ptr elem, dword val);
  3958.  
  3959.              Sets the ticks field to the given value. If the ticks field
  3960.              is modified directly instead of through this routine,
  3961.              interrupts should be disabled when writing a doubleword
  3962.              value.
  3963.  
  3964.  
  3965.         dword get_ticker (tick_ptr elem)
  3966.  
  3967.              Returns the current ticker value. If the ticks field is read
  3968.              directly instead of through this routine, interrupts should
  3969.              be disabled when reading the doubleword value.
  3970.  
  3971.  
  3972.  
  3973.  
  3974.         
  3975.         
  3976.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 65
  3977.  
  3978.  
  3979.                                       Delays
  3980.  
  3981.  
  3982.         int t_delay (dword ticks);
  3983.  
  3984.              Delay the current task for "ticks" clock ticks/milliseconds.
  3985.              If ticks is 0, the task is stopped.
  3986.  
  3987.              Returns TIMEOUT if the delay expired, WAKE if the task was
  3988.              activated by wake_task.
  3989.  
  3990.  
  3991.  
  3992.                      Timed Events, Watch Events, and Hotkeys
  3993.  
  3994.         You can create timer control blocks, memory/port watch blocks,
  3995.         and keyboard hotkey blocks, to
  3996.  
  3997.              - set a flag
  3998.              - increment or decrement a counter
  3999.              - wake up a task
  4000.              - call a function
  4001.  
  4002.         after a specified timeout interval, or when a certain condition
  4003.         is met. The operation may optionally be repeated.
  4004.  
  4005.         Watch control blocks are checked on every timer tick. They allow
  4006.         memory locations and I/O ports to be checked for a certain value,
  4007.         or for a change in value. When the specified condition is met,
  4008.         the given action is executed.
  4009.  
  4010.         Keyboard hotkeys are checked in the keyboard hardware interrupt.
  4011.         They  allow checking for key scan codes and/or keyboard state flag
  4012.         combinations.
  4013.  
  4014.         See the "Advanced Topics" chapter on restrictions placed on
  4015.         functions called by timer/watch/hotkey conditions.
  4016.  
  4017.  
  4018.  
  4019.  
  4020.  
  4021.  
  4022.  
  4023.  
  4024.  
  4025.  
  4026.  
  4027.  
  4028.  
  4029.  
  4030.  
  4031.  
  4032.         
  4033.         
  4034.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 66
  4035.  
  4036.  
  4037.         tlinkptr create_timer_elem (tlinkptr elem, dword tout,
  4038.                                     farptr strucp, byte kind,
  4039.                                     byte rept [,dword userpar]);
  4040.  
  4041.              Creates a timer control block, but does not activate it.
  4042.  
  4043.              Returns the address of the control block, LNULL on error.
  4044.  
  4045.              "elem"     is the control block to initialise (LNULL for
  4046.                         automatic allocation).
  4047.  
  4048.              "tout"     specifies the timeout interval.
  4049.  
  4050.              "strucp"   points to the structure to be used. This is a
  4051.                         flagptr for setting a flag, a counterptr for
  4052.                         in/decreasing counters, a tcbptr for waking a
  4053.                         task, or a funcptr for calling a function.
  4054.  
  4055.              "kind"     gives the kind of structure "strucp" points to.
  4056.                         It must be one of
  4057.  
  4058.                            TKIND_WAKE     for task-wakeup
  4059.                            TKIND_PROC     for function call
  4060.                            TKIND_FLAG     for flag set
  4061.                            TKIND_COUNTER  for counter increment.
  4062.                            TKIND_COUNTDEC for counter decrement.
  4063.  
  4064.              "rept"     if nonzero, the action will be repeated on every
  4065.                         "tout" timeout interval.
  4066.  
  4067.              "userpar"  is a doubleword value that can be used by the
  4068.                         timeout function if kind is TKIND_PROC. This
  4069.                         parameter is optional.
  4070.  
  4071.              NOTE: Timer control blocks can not be named.
  4072.  
  4073.  
  4074.         tlinkptr create_timer (tlinkptr elem, dword tout, farptr strucp,
  4075.                                byte kind, byte rept [,dword userpar]);
  4076.  
  4077.              Creates a timer control block and activates it.
  4078.  
  4079.              Returns the address of the control block, LNULL on error.
  4080.  
  4081.              See create_timer_elem above for parameters. If the timeout
  4082.              is zero, the control block is initialized, but is not
  4083.              entered into the timer chain. The timeout must be changed
  4084.              with change_timer for the timer control block to be
  4085.              activated.
  4086.  
  4087.  
  4088.  
  4089.  
  4090.         
  4091.         
  4092.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 67
  4093.  
  4094.  
  4095.         void  enable_timer (tlinkptr elem);
  4096.  
  4097.              Activates a timeout element. This call is ignored if the
  4098.              timeout value in the control block is zero.
  4099.  
  4100.  
  4101.         void  disable_timer (tlinkptr elem);
  4102.  
  4103.              Disables a timeout element. The element is not deleted.
  4104.  
  4105.  
  4106.         void  change_timer (tlinkptr elem, dword tout, byte rept);
  4107.  
  4108.              Changes the timeout value and/or the repeat flag for an
  4109.              existing timer control block. If "tout" is zero, the call
  4110.              has the same effect as disable_timer.
  4111.  
  4112.  
  4113.         void  delete_timer (tlinkptr elem);
  4114.  
  4115.              Deletes a timer control block, and removes it from the
  4116.              timeout queue.
  4117.  
  4118.  
  4119.         tlinkptr create_memory_watch_elem (tlinkptr elem, farptr address,
  4120.                                            word mask, word compare,
  4121.                                            byte cmpkind, farptr strucp,
  4122.                                            byte kind, byte rept
  4123.                                            [, dword userpar]);
  4124.  
  4125.              Creates a memory watch control block. Memory watches compare
  4126.              a byte or word value at the specified address against a
  4127.              comparison value. The value loaded is always a word, the
  4128.              "mask" parameter may be used to restrict comparison to a
  4129.              byte. The watch is not activated.
  4130.  
  4131.              Returns the watch control block pointer, or LNULL on error.
  4132.  
  4133.              "elem"     is the control block to initialise (LNULL for
  4134.                         automatic allocation).
  4135.  
  4136.              "address"  is a pointer to the memory location to watch.
  4137.  
  4138.              "mask"     is a bitmask to mask out irrelevant bits before
  4139.                         comparison.
  4140.  
  4141.              "compare"  is the value the memory contents are to be
  4142.                         compared with.
  4143.  
  4144.  
  4145.  
  4146.  
  4147.  
  4148.         
  4149.         
  4150.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 68
  4151.  
  4152.  
  4153.              "cmpkind"  is the kind of comparison to be used:
  4154.  
  4155.                         TCMP_EQ   (*address & mask) == compare
  4156.                         TCMP_NE   (*address & mask) != compare
  4157.                         TCMP_GE   (*address & mask) >= compare (unsigned)
  4158.                         TCMP_LE   (*address & mask) <= compare (unsigned)
  4159.                         TCMP_GES  (*address & mask) >= compare (signed)
  4160.                         TCMP_LES  (*address & mask) <= compare (signed)
  4161.  
  4162.                         TCMP_CHG  Change in value:
  4163.                                   (*address & mask) != compare
  4164.                                   compare = *address & mask
  4165.  
  4166.              "strucp"   points to the structure to be used. This is a
  4167.                         flagptr for setting a flag, a counterptr for
  4168.                         in/decreasing counters, a tcbptr for waking a
  4169.                         task, or a funcptr for calling a function.
  4170.  
  4171.              "kind"     gives the kind of structure "strucp" points to.
  4172.                         It must be one of
  4173.  
  4174.                             TKIND_WAKE     for task-wakeup
  4175.                             TKIND_PROC     for function call
  4176.                             TKIND_FLAG     for flag set
  4177.                             TKIND_COUNTER  for counter increment.
  4178.                             TKIND_COUNTDEC for counter decrement.
  4179.  
  4180.              "rept"     if nonzero, the action will be repeated whenever
  4181.                         the condition is met.
  4182.  
  4183.              "userpar"  is a doubleword value that is passed to the watch
  4184.                         function if kind is TKIND_PROC. This parameter is
  4185.                         optional.
  4186.  
  4187.              NOTE: Watch control blocks can not be named.
  4188.  
  4189.  
  4190.         tlinkptr create_memory_watch (tlinkptr elem, farptr address,
  4191.                                       word mask, word compare,
  4192.                                       byte cmpkind, farptr strucp,
  4193.                                       byte kind, byte rept
  4194.                                       [, dword userpar]);
  4195.  
  4196.              Creates a memory watch control block and activates it.
  4197.  
  4198.              Returns the watch control block pointer, or LNULL on error.
  4199.  
  4200.              See create_memory_watch_elem for parameters.
  4201.  
  4202.  
  4203.  
  4204.  
  4205.  
  4206.         
  4207.         
  4208.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 69
  4209.  
  4210.  
  4211.         int wait_memory (farptr address,
  4212.                          word mask, word compare, byte cmpkind)
  4213.  
  4214.              Delays the current task until the specified condition is
  4215.              met. Parameters are the same as in create_memory_watch. No
  4216.              timeout can be specified.
  4217.  
  4218.              Returns WATCH if the watch condition was met, WAKE if the
  4219.              task was activated by wake_task.
  4220.  
  4221.  
  4222.         tlinkptr create_port_watch_elem (tlinkptr elem,
  4223.                                          word port, byte in_word,
  4224.                                          word mask, word compare,
  4225.                                          byte cmpkind, farptr strucp,
  4226.                                          byte kind, byte rept
  4227.                                          [, dword userpar]);
  4228.  
  4229.              Creates a port watch control block. Port watches compare a
  4230.              byte or word value read from the specified port address
  4231.              against a comparison value. The value read is either a word
  4232.              or a byte, depending on the "in_word" parameter. The watch
  4233.              is not activated.
  4234.  
  4235.              Returns the watch control block pointer, or LNULL on error.
  4236.  
  4237.              "elem"     is the control block to initialise (LNULL for
  4238.                         automatic allocation).
  4239.  
  4240.              "port"     is the port address to read.
  4241.  
  4242.              "in_word"  Specifies whether a word or byte input
  4243.                         instruction is to be used. If zero, a byte is
  4244.                         input, if nonzero, a word is read from the port.
  4245.  
  4246.              "mask"     is a bitmask to mask out irrelevant bits before
  4247.                         comparison.
  4248.  
  4249.              "compare"  is the value the port contents are to be compared
  4250.                         with.
  4251.  
  4252.  
  4253.  
  4254.  
  4255.  
  4256.  
  4257.  
  4258.  
  4259.  
  4260.  
  4261.  
  4262.  
  4263.  
  4264.         
  4265.         
  4266.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 70
  4267.  
  4268.  
  4269.              "cmpkind"  is the kind of comparison to be used:
  4270.  
  4271.                         TCMP_EQ   (in(port) & mask) == compare
  4272.                         TCMP_NE   (in(port) & mask) != compare
  4273.                         TCMP_GE   (in(port) & mask) >= compare (unsigned)
  4274.                         TCMP_LE   (in(port) & mask) <= compare (unsigned)
  4275.                         TCMP_GES  (in(port) & mask) >= compare (signed)
  4276.                         TCMP_LES  (in(port) & mask) <= compare (signed)
  4277.  
  4278.                         TCMP_CHG  Change in value:
  4279.                                   (in(port) & mask) != compare
  4280.                                   compare = in(port) & mask
  4281.                                   (NOTE: The port is read only once.)
  4282.  
  4283.              "strucp"   points to the structure to be used. This is a
  4284.                         flagptr for setting a flag, a counterptr for
  4285.                         in/decreasing counters, a tcbptr for waking a
  4286.                         task, or a funcptr for calling a function.
  4287.  
  4288.              "kind"     gives the kind of structure "strucp" points to.
  4289.                         It must be one of
  4290.  
  4291.                             TKIND_WAKE     for task-wakeup
  4292.                             TKIND_PROC     for function call
  4293.                             TKIND_FLAG     for flag set
  4294.                             TKIND_COUNTER  for counter increment.
  4295.                             TKIND_COUNTDEC for counter decrement.
  4296.  
  4297.              "rept"     if nonzero, the action will be repeated whenever
  4298.                         the condition is met.
  4299.  
  4300.              "userpar"  is a doubleword value that is passed to the watch
  4301.                         function if kind is TKIND_PROC. This parameter is
  4302.                         optional.
  4303.  
  4304.              NOTE: Watch control blocks can not be named.
  4305.  
  4306.  
  4307.         tlinkptr create_port_watch (tlinkptr elem,
  4308.                                     word port, byte in_word,
  4309.                                     word mask, word compare,
  4310.                                     byte cmpkind, farptr strucp,
  4311.                                     byte kind, byte rept
  4312.                                     [, dword userpar]);
  4313.  
  4314.              Creates a port watch control block and activates it.
  4315.  
  4316.              Returns the watch control block pointer, or LNULL on error.
  4317.  
  4318.              See create_port_watch_elem for parameters.
  4319.  
  4320.  
  4321.  
  4322.         
  4323.         
  4324.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 71
  4325.  
  4326.  
  4327.         int wait_port (word port, byte in_word,
  4328.                        word mask, word compare, byte cmpkind)
  4329.  
  4330.              Delays the current task until the specified condition is
  4331.              met. Parameters are the same as in create_port_watch. No
  4332.              timeout can be specified.
  4333.  
  4334.              Returns WATCH if the watch condition was met, WAKE if the
  4335.              task was activated by wake_task.
  4336.  
  4337.  
  4338.         void  enable_watch (tlinkptr elem);
  4339.  
  4340.              The specified watch element is activated.
  4341.  
  4342.  
  4343.         void  disable_watch (tlinkptr elem);
  4344.  
  4345.              The specified watch element is deactivated. The element is
  4346.              not deleted.
  4347.  
  4348.  
  4349.         void  delete_watch (tlinkptr elem);
  4350.  
  4351.              The specified watch element is removed.
  4352.  
  4353.  
  4354.         NOTE: delete_timer, delete_watch, and change_timer should not be
  4355.         used  on automatically allocated timer/watch control blocks. Since
  4356.         such  blocks are deallocated once the timeout expires or the
  4357.         condition is met (except for repeat operations), the validity of
  4358.         the pointer is not guaranteed.
  4359.  
  4360.  
  4361.         tlinkptr create_hotkey_elem (tlinkptr elem,
  4362.                                      byte scancode,
  4363.                                      byte mask1, byte flag1,
  4364.                                      byte mask2, byte flag2,
  4365.                                      byte mask3, byte flag3,
  4366.                                      farptr strucp, byte kind,
  4367.                                      byte rept
  4368.                                      [, dword userpar]);
  4369.  
  4370.              Creates a keyboard hotkey control block. Keyboard hotkeys
  4371.              compare the scancode and/or the BIOS keyboard flags against
  4372.              the given values. The flag fields are masked before
  4373.              comparing. The hotkey is not activated.
  4374.  
  4375.              The file "kbd.h" contains definitions for scan codes and
  4376.              flag byte values.
  4377.  
  4378.  
  4379.  
  4380.         
  4381.         
  4382.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 72
  4383.  
  4384.  
  4385.              Returns the hotkey control block pointer, or LNULL on error.
  4386.  
  4387.              CAUTION: In contrast to the timer/watch creation functions,
  4388.                       this function does not accept a LNULL parameter for
  4389.                       the element to create. Dynamic allocation can not
  4390.                       be used in an interrupt handler, and a temporary
  4391.                       element would have to be released in the keyboard
  4392.                       interrupt. Therefore, the hotkey control block must
  4393.                       always be static.
  4394.  
  4395.              "elem"     is the control block to initialise. This pointer
  4396.                         must NOT be LNULL.
  4397.  
  4398.              "scancode" is the keyboard scancode to look for. If scancode
  4399.                         is 0, only the flag values are compared.
  4400.  
  4401.              "flag1..3" are the values the BIOS keyboard flags are to be
  4402.                         compared with.
  4403.  
  4404.              "mask1..3" are bitmasks to mask out irrelevant bits before
  4405.                         comparing the flag values. Set both mask and flag
  4406.                         to 0 to disable comparison.
  4407.  
  4408.              "strucp"   points to the structure to be used. This is a
  4409.                         flagptr for setting a flag, a counterptr for
  4410.                         in/decreasing counters, a tcbptr for waking a
  4411.                         task, or a funcptr for calling a function.
  4412.  
  4413.              "kind"     gives the kind of structure "strucp" points to.
  4414.                         It must be one of
  4415.  
  4416.                             TKIND_WAKE     for task-wakeup
  4417.                             TKIND_PROC     for function call
  4418.                             TKIND_FLAG     for flag set
  4419.                             TKIND_COUNTER  for counter increment.
  4420.                             TKIND_COUNTDEC for counter decrement.
  4421.  
  4422.              "rept"     if nonzero, the action will be repeated whenever
  4423.                         the hotkey is activated.
  4424.  
  4425.              "userpar"  is a doubleword value that is passed to the
  4426.                         hotkey function if kind is TKIND_PROC. This
  4427.                         parameter is optional.
  4428.  
  4429.              NOTE: Hotkey control blocks can not be named.
  4430.  
  4431.  
  4432.  
  4433.  
  4434.  
  4435.  
  4436.  
  4437.  
  4438.         
  4439.         
  4440.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 73
  4441.  
  4442.  
  4443.         tlinkptr create_hotkey_entry (tlinkptr elem,
  4444.                                       byte scancode,
  4445.                                       byte mask1, byte flag1,
  4446.                                       byte mask2, byte flag2,
  4447.                                       byte mask3, byte flag3,
  4448.                                       farptr strucp, byte kind,
  4449.                                       byte rept
  4450.                                       [, dword userpar]);
  4451.  
  4452.              Creates a keyboard hotkey control block and enables it.
  4453.  
  4454.              Returns the hotkey control block pointer, or LNULL on error.
  4455.  
  4456.              See create_hotkey_elem for parameters.
  4457.  
  4458.  
  4459.         int wait_hotkey (byte scancode,
  4460.                          byte mask1, byte flag1,
  4461.                          byte mask2, byte flag2,
  4462.                          byte mask3, byte flag3)
  4463.  
  4464.              Delays the current task until the specified hotkey is hit.
  4465.              Parameters are the same as in create_hotkey_entry. No
  4466.              timeout can be specified.
  4467.  
  4468.              Returns WATCH if the hotkey was hit, WAKE if the task was
  4469.              activated by wake_task.
  4470.  
  4471.  
  4472.         void  enable_hotkey (tlinkptr elem);
  4473.  
  4474.              The specified hotkey element is activated.
  4475.  
  4476.  
  4477.         void  disable_hotkey (tlinkptr elem);
  4478.  
  4479.              The specified hotkey element is deactivated. The element is
  4480.              not deleted.
  4481.  
  4482.  
  4483.         void  delete_hotkey (tlinkptr elem);
  4484.  
  4485.              The specified hotkey entry is removed.
  4486.  
  4487.  
  4488.  
  4489.  
  4490.  
  4491.  
  4492.  
  4493.  
  4494.  
  4495.  
  4496.         
  4497.         
  4498.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 74
  4499.  
  4500.  
  4501.                                  Event Operations
  4502.  
  4503.                                     Resources
  4504.  
  4505.         A Resource is either in use or free, the default state is free.
  4506.         If a  task has requested a resource, its state is in use, and the
  4507.         requesting task is said to "own" the resource.  Tasks requesting
  4508.         a resource while it is in use will be made waiting. If the
  4509.         resource is released, the highest priority waiting task is made
  4510.         eligible, and is assigned the resource. Interrupt handlers may
  4511.         not use resource functions other than "check_resource".
  4512.  
  4513.         To facilitate use of resources in nested routines, CTask allows a
  4514.         resource to be requested by a Task already owning it. Different
  4515.         calls may be used to request resources, depending on how such
  4516.         nested calls should be handled. The standard request_resource and
  4517.         c_request_resource calls just mark the resource as in use by
  4518.         setting the owner count to 1, and the first nested routine that
  4519.         releases the resource will cause the resource to be freed. The
  4520.         request_cresource and c_request_cresource calls increment the
  4521.         owner count, so the resource will only be freed upon a matching
  4522.         count of requests and releases.
  4523.  
  4524.  
  4525.         resourceptr create_resource (resourceptr rsc [, byteptr name]);
  4526.  
  4527.              This initialises a resource. Must be used prior to any other
  4528.              operations on a resource.
  4529.  
  4530.              Returns the address of the control block, LNULL on error.
  4531.  
  4532.              "rsc"      is the resource control block (LNULL for
  4533.                         automatic allocation).
  4534.  
  4535.              "name"     is the name of the resource, up to eight
  4536.                         characters, plus zero-terminator. This parameter
  4537.                         is defined only if TSK_NAMEPAR is enabled in
  4538.                         tskconf.h.
  4539.  
  4540.  
  4541.  
  4542.  
  4543.  
  4544.  
  4545.  
  4546.  
  4547.  
  4548.  
  4549.  
  4550.  
  4551.  
  4552.  
  4553.  
  4554.         
  4555.         
  4556.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 75
  4557.  
  4558.  
  4559.         DEF_RESOURCE(var,name)
  4560.  
  4561.              This macro defines and initialises a resource control block
  4562.              at compile time. It can replace the run-time call to
  4563.              create_resource. However, the created block is not linked
  4564.              into the name chain. To make the block visible, you must use
  4565.              add_event_name. Most compilers will not allow aggregate
  4566.              initialisers of automatic variables, so you must use this
  4567.              definition with the static attribute inside routines.
  4568.  
  4569.              "var"      is the variable name to define.
  4570.  
  4571.              "name"     is the name of the resource. It can be a zero
  4572.                         length string, but it must not be LNULL. Since
  4573.                         this is a macro, you must give the parameter even
  4574.                         when TSK_NAMEPAR is disabled.
  4575.  
  4576.  
  4577.         void  delete_resource (resourceptr rsc);
  4578.  
  4579.              Calling this routine is optional. It will kill all tasks
  4580.              waiting for the resource.
  4581.  
  4582.  
  4583.         void  release_resource (resourceptr rsc);
  4584.  
  4585.              Decrement the owner count, and release the resource if it is
  4586.              zero. If the task does not own the resource, the call is
  4587.              ignored. If the resource is released, and tasks are waiting
  4588.              for access, the highest priority task will gain access to
  4589.              the resource.
  4590.  
  4591.  
  4592.         int request_resource (resourceptr rsc, dword timeout);
  4593.  
  4594.              Requests the resource. If it is not available, the task is
  4595.              suspended. A timeout may be specified.
  4596.  
  4597.              Returns 0 if resource was allocated, TIMEOUT if a timeout
  4598.              occurred, WAKE on wake.
  4599.  
  4600.              This call is ignored (returns a 0) if the calling task
  4601.              already owns the resource.
  4602.  
  4603.  
  4604.  
  4605.  
  4606.  
  4607.  
  4608.  
  4609.  
  4610.  
  4611.  
  4612.         
  4613.         
  4614.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 76
  4615.  
  4616.  
  4617.         int request_cresource (resourceptr rsc, dword timeout);
  4618.  
  4619.              Requests the resource. If it is not available, the task is
  4620.              suspended. A timeout may be specified.
  4621.  
  4622.              Returns 0 if resource was allocated, TIMEOUT if a timeout
  4623.              occurred, WAKE on wake.
  4624.  
  4625.              This call increments the owner count, and returns 0, if the
  4626.              calling task already owns the resource.
  4627.  
  4628.  
  4629.         int c_request_resource (resourceptr rsc);
  4630.  
  4631.              Requests the resource only if it is available.
  4632.  
  4633.              Returns 0 if resource was allocated, -1 if unavailable.
  4634.  
  4635.  
  4636.         int check_resource (resourceptr rsc);
  4637.  
  4638.              Returns 0 if resource is allocated, 1 if free.
  4639.  
  4640.  
  4641.  
  4642.                                       Flags
  4643.  
  4644.  
  4645.         A Flag can be either on or off, the default state is off (0).
  4646.         Tasks can wait on either state of the flag. If the state is
  4647.         changed, all tasks waiting for the state are made eligible.
  4648.         Interrupt handlers may use the "set_flag", "clear_flag", and
  4649.         "check_flag" functions.
  4650.  
  4651.  
  4652.         flagptr create_flag (flagptr flg [, byteptr name]);
  4653.  
  4654.              This initialises a flag. Must be used prior to any other
  4655.              operations on a flag. The state is set to 0.
  4656.  
  4657.              Returns the address of the control block, LNULL on error.
  4658.  
  4659.              "flg"      is the flag control block (LNULL for automatic
  4660.                         allocation).
  4661.  
  4662.              "name"     is the name of the flag, up to eight characters,
  4663.                         plus zero-terminator. This parameter is defined
  4664.                         only if TSK_NAMEPAR is enabled in tskconf.h.
  4665.  
  4666.  
  4667.  
  4668.  
  4669.  
  4670.         
  4671.         
  4672.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 77
  4673.  
  4674.  
  4675.         DEF_FLAG(var,name)
  4676.  
  4677.              This macro defines and initialises a flag control block at
  4678.              compile time. It can replace the run-time call to
  4679.              create_flag. However, the created block is not linked into
  4680.              the name chain. To make the block visible, you must use
  4681.              add_event_name. Most compilers will not allow aggregate
  4682.              initialisers of automatic variables, so you must use this
  4683.              definition with the static attribute inside routines.
  4684.  
  4685.              "var"      is the variable name to define.
  4686.  
  4687.              "name"     is the name of the flag. It can be a zero length
  4688.                         string, but it must not be LNULL. Since this is a
  4689.                         macro, you must give the parameter even when
  4690.                         TSK_NAMEPAR is disabled.
  4691.  
  4692.  
  4693.         void  delete_flag (flagptr flg);
  4694.  
  4695.              Calling this routine is optional. It will kill all tasks
  4696.              waiting for the flag.
  4697.  
  4698.  
  4699.         void  set_flag (flagptr flg);
  4700.  
  4701.              This sets the flag. All tasks waiting for the set state will
  4702.              be made eligible for running.
  4703.  
  4704.  
  4705.         void  clear_flag (flagptr flg);
  4706.  
  4707.              This clears the flag. All tasks waiting for the clear state
  4708.              will be made eligible for running.
  4709.  
  4710.  
  4711.         int wait_flag_set (flagptr flg, dword timeout);
  4712.  
  4713.              Waits for the set state of the flag. If the flag is not set,
  4714.              the task is suspended. A timeout may be specified.
  4715.  
  4716.              Returns 0 if the flag was set, TIMEOUT on timeout, WAKE on
  4717.              wake.
  4718.  
  4719.  
  4720.         int wait_flag_clear (flagptr flg, dword timeout);
  4721.  
  4722.              Waits for the clear state of the flag. If the flag is not
  4723.              clear, the task is suspended. A timeout may be specified.
  4724.  
  4725.              Returns 0 if the flag was cleared, TIMEOUT on timeout, WAKE
  4726.              on wake.
  4727.  
  4728.         
  4729.         
  4730.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 78
  4731.  
  4732.  
  4733.         int clear_flag_wait_set (flagptr flg, dword timeout)
  4734.  
  4735.              Combines the operations clear_flag and wait_flag_set.
  4736.  
  4737.              Returns 0 if the flag was set, TIMEOUT on timeout, WAKE on
  4738.              wake.
  4739.  
  4740.  
  4741.         int check_flag (flagptr flg);
  4742.  
  4743.              Returns 0 if flag clear, 1 if set.
  4744.  
  4745.  
  4746.  
  4747.                                      Counters
  4748.  
  4749.         A Counter can have any value from 0L to 0xffffffffL, the default
  4750.         value is 0. Tasks can wait for a counter being zero or non-zero.
  4751.         If the counter is cleared or decremented to zero, all tasks wai-
  4752.         ting  for the zero condition are made eligible. If the counter is
  4753.         incremented, the highest priority task waiting for non-zero is
  4754.         made  eligible, and the counter is decremented by one. Interrupt
  4755.         handlers may use the "clear_counter", "inc_counter",
  4756.         "dec_counter", "set_counter", and "check_counter" functions.
  4757.  
  4758.  
  4759.         counterptr create_counter (counterptr cnt [, byteptr name]);
  4760.  
  4761.              This initialises a counter. Must be used prior to any other
  4762.              operations on a flag. The value is set to 0.
  4763.  
  4764.              Returns the address of the control block, LNULL on error.
  4765.  
  4766.              "cnt"      is the counter control block (LNULL for automatic
  4767.                         allocation).
  4768.  
  4769.              "name"     is the name of the counter, up to eight
  4770.                         characters, plus zero-terminator. This parameter
  4771.                         is defined only if TSK_NAMEPAR is enabled in
  4772.                         tskconf.h.
  4773.  
  4774.  
  4775.  
  4776.  
  4777.  
  4778.  
  4779.  
  4780.  
  4781.  
  4782.  
  4783.  
  4784.  
  4785.  
  4786.         
  4787.         
  4788.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 79
  4789.  
  4790.  
  4791.         DEF_COUNTER(var,name)
  4792.  
  4793.              This macro defines and initialises a counter control block
  4794.              at compile time. It can replace the run-time call to
  4795.              create_counter. However, the created block is not linked
  4796.              into the name chain. To make the block visible, you must use
  4797.              add_event_name. Most compilers will not allow aggregate
  4798.              initialisers of automatic variables, so you must use this
  4799.              definition with the static attribute inside routines.
  4800.  
  4801.              "var"      is the variable name to define.
  4802.  
  4803.              "name"     is the name of the counter. It can be a zero
  4804.                         length string, but it must not be LNULL. Since
  4805.                         this is a macro, you must give the parameter even
  4806.                         when TSK_NAMEPAR is disabled.
  4807.  
  4808.  
  4809.         void  delete_counter (counterptr cnt);
  4810.  
  4811.              Calling this routine is optional. It will kill all tasks
  4812.              waiting for the counter.
  4813.  
  4814.  
  4815.         void  clear_counter (counterptr cnt);
  4816.  
  4817.              Clears the counter to zero. All tasks waiting for the zero
  4818.              state will be made eligible for running.
  4819.  
  4820.  
  4821.         int wait_counter_set (counterptr cnt, dword timeout);
  4822.  
  4823.              Waits for the counter having a nonzero value. If the value
  4824.              is zero, the task is suspended. The value is decremented
  4825.              when the task gets access to the counter.  A timeout may be
  4826.              specified.
  4827.  
  4828.              Returns 0 if the counter was nonzero, TIMEOUT on timeout,
  4829.              WAKE on wake.
  4830.  
  4831.  
  4832.         int wait_counter_clear (counterptr cnt, dword timeout);
  4833.  
  4834.              Waits for the counter having a zero value. If the value is
  4835.              nonzero, the task is suspended. A timeout may be specified.
  4836.  
  4837.              Returns 0 if the counter was zero, TIMEOUT on timeout, WAKE
  4838.              on wake.
  4839.  
  4840.  
  4841.  
  4842.  
  4843.  
  4844.         
  4845.         
  4846.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 80
  4847.  
  4848.  
  4849.         dword inc_counter (counterptr cnt);
  4850.  
  4851.              Increments the counter. If tasks are waiting for the nonzero
  4852.              state, the highest priority task is given access to the
  4853.              counter.
  4854.  
  4855.              Returns the new value of the counter.
  4856.  
  4857.  
  4858.         dword dec_counter (counterptr cnt);
  4859.  
  4860.              Decrements the counter unless it is already zero. If the
  4861.              counter is decremented to zero, all tasks waiting for the
  4862.              zero state are made eligible.
  4863.  
  4864.              Returns the new value of the counter.
  4865.  
  4866.  
  4867.         void  set_counter (counterptr cnt, dword val);
  4868.  
  4869.              Sets the counter to the given value. If "val" is nonzero,
  4870.              and tasks are waiting for the set state, the highest
  4871.              priority tasks are made eligible, and "val" is decremented,
  4872.              until either "val" reaches zero, or there are no more tasks
  4873.              waiting. If val is, or is counted down to, zero, all tasks
  4874.              waiting for the zero state are made eligible.
  4875.  
  4876.  
  4877.         dword check_counter (counterptr cnt);
  4878.  
  4879.              Returns the current value of the counter.
  4880.  
  4881.  
  4882.  
  4883.                                     Mailboxes
  4884.  
  4885.         A Mailbox can hold any number of mail blocks. Tasks can send mail
  4886.         to a  mailbox and wait for mail to arrive. A mail block is
  4887.         assigned to the highest priority waiting task. Care must be
  4888.         exercised not to re-use a mail block until it has been processed
  4889.         by the receiving task. The mail block format is user defineable,
  4890.         with  the first doubleword in a block reserved for the tasking
  4891.         system. Interrupt handlers may use the "send_mail",
  4892.         "c_wait_mail", and "check_mailbox" functions.
  4893.  
  4894.         Note  that mailboxes are well suited to provide the mechanism for
  4895.         managing a chain of (equally sized) free mail blocks. On
  4896.         initialization, all free blocks would be "sent" to the manager
  4897.         box.  Requesting a free block would use "wait_mail", and freeing a
  4898.         used  block would again "send" it to the manager mailbox.
  4899.  
  4900.  
  4901.  
  4902.         
  4903.         
  4904.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 81
  4905.  
  4906.  
  4907.         mailboxptr create_mailbox (mailboxptr box [, byteptr name]);
  4908.  
  4909.              This initialises a mailbox. Must be used prior to any other
  4910.              operations on a mailbox.
  4911.  
  4912.              Returns the address of the control block, LNULL on error.
  4913.  
  4914.              "box"      is the mailbox control block (LNULL for automatic
  4915.                         allocation).
  4916.  
  4917.              "name"     is the name of the mailbox, up to eight
  4918.                         characters, plus zero-terminator. This parameter
  4919.                         is defined only if TSK_NAMEPAR is enabled in
  4920.                         tskconf.h.
  4921.  
  4922.  
  4923.         DEF_MAILBOX(var,name)
  4924.  
  4925.              This macro defines and initialises a mailbox control block
  4926.              at compile time. It can replace the run-time call to
  4927.              create_mailbox. However, the created block is not linked
  4928.              into the name chain. To make the block visible, you must use
  4929.              add_event_name. Most compilers will not allow aggregate
  4930.              initialisers of automatic variables, so you must use this
  4931.              definition with the static attribute inside routines.
  4932.  
  4933.              "var"      is the variable name to define.
  4934.  
  4935.              "name"     is the name of the mailbox. It can be a zero
  4936.                         length string, but it must not be LNULL. Since
  4937.                         this is a macro, you must give the parameter even
  4938.                         when TSK_NAMEPAR is disabled.
  4939.  
  4940.  
  4941.         void  delete_mailbox (mailboxptr box);
  4942.  
  4943.              Calling this routine is optional. It will kill all tasks
  4944.              waiting for mail.
  4945.  
  4946.  
  4947.         void  send_mail (mailboxptr box, farptr msg);
  4948.  
  4949.              Sends a message to the specified mailbox. If tasks are
  4950.              waiting for mail, the highest priority task will get it.
  4951.  
  4952.  
  4953.         farptr wait_mail (mailboxptr box, dword timeout);
  4954.  
  4955.              Waits for mail. If no mail is available, the task is
  4956.              suspended. A timeout may be specified.
  4957.  
  4958.              Returns the pointer to the received mail block, TTIMEOUT on
  4959.              timeout, TWAKE on wake.
  4960.         
  4961.         
  4962.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 82
  4963.  
  4964.  
  4965.         farptr c_wait_mail (mailboxptr box);
  4966.  
  4967.              Reads mail only if mail is available.
  4968.  
  4969.              Returns LNULL if there is no mail, else a pointer to the
  4970.              received message.
  4971.  
  4972.  
  4973.         int check_mailbox (mailboxptr box);
  4974.  
  4975.              Returns 0 if mailbox is empty, 1 otherwise.
  4976.  
  4977.  
  4978.  
  4979.                                       Pipes
  4980.  
  4981.         A Pipe has a buffer to hold character or word sized items. An
  4982.         item  may be written to a pipe if there is space in the buffer.
  4983.         Otherwise, the writing task will be made waiting. A reading task
  4984.         will  be made waiting if the buffer is empty. If an item has been
  4985.         read, the highest priority task waiting to write to the pipe will
  4986.         be allowed to write. Interrupt handlers may only use pipe
  4987.         functions "check_pipe", "c_write_pipe", and "c_read_pipe".
  4988.  
  4989.         Note  that the values -1 and -2 (0xffff and 0xfffe) should be
  4990.         avoided when writing to word pipes. These values are used to mark
  4991.         timeout and wake when reading, or pipe empty when checking a word
  4992.         pipe, and thus may lead to erroneous operation of your routines.
  4993.  
  4994.  
  4995.         pipeptr create_pipe (pipeptr pip, farptr buf, word bufsize
  4996.                              [, byteptr name]);
  4997.         wpipeptr create_wpipe (wpipeptr pip, farptr buf, word bufsize
  4998.                                [, byteptr name]);
  4999.  
  5000.              This initialises a pipe. Must be used prior to any other
  5001.              operations on a pipe. "bufsize" specifies the buffer size in
  5002.              bytes. With word pipes, the buffer size should be divisible
  5003.              by two.
  5004.  
  5005.              Returns the address of the control block, LNULL on error.
  5006.  
  5007.              "pip"      is the pipe/wpipe control block (LNULL for
  5008.                         automatic allocation).
  5009.  
  5010.              "buf"      is a pointer to the pipe buffer.
  5011.  
  5012.              "bufsize"  is the size of the buffer in bytes.
  5013.  
  5014.              "name"     is the name of the pipe, up to eight characters,
  5015.                         plus zero-terminator. This parameter is defined
  5016.                         only if TSK_NAMEPAR is enabled in tskconf.h.
  5017.  
  5018.         
  5019.         
  5020.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 83
  5021.  
  5022.  
  5023.         DEF_PIPE(var,name,buf,bufsize)
  5024.         DEF_WPIPE(var,name,buf,bufsize)
  5025.  
  5026.              This macro defines and initialises a pipe/word pipe control
  5027.              block at compile time. It can replace the run-time call to
  5028.              create_pipe/create_wpipe. However, the created block is not
  5029.              linked into the name chain. To make the block visible, you
  5030.              must use add_event_name. Most compilers will not allow
  5031.              aggregate initialisers of automatic variables, so you must
  5032.              use this definition with the static attribute inside
  5033.              routines.
  5034.  
  5035.              "var"      is the variable name to define.
  5036.  
  5037.              "name"     is the name of the pipe. It can be a zero length
  5038.                         string, but it must not be LNULL. Since this is a
  5039.                         macro, you must give the parameter even when
  5040.                         TSK_NAMEPAR is disabled.
  5041.  
  5042.              "buf"      is a pointer to the pipe buffer.
  5043.  
  5044.              "bufsize"  is the size of the buffer in bytes.
  5045.  
  5046.  
  5047.         void  delete_pipe (pipeptr pip);
  5048.         void  delete_wpipe (wpipeptr pip);
  5049.  
  5050.              Calling this routine is optional. It will kill all tasks
  5051.              waiting to read or write messages.
  5052.  
  5053.  
  5054.         int read_pipe (pipeptr pip, dword timeout);
  5055.         word  read_wpipe (wpipeptr pip, dword timeout);
  5056.  
  5057.              Read an item from a pipe. If no item is available, the task
  5058.              is suspended. A timeout may be specified.
  5059.  
  5060.              Returns the item, or TIMEOUT on timeout, WAKE on wake.
  5061.  
  5062.  
  5063.         int c_read_pipe (pipeptr pip);
  5064.         word  c_read_wpipe (wpipeptr pip);
  5065.  
  5066.              Reads an item from a pipe only if one is available.
  5067.  
  5068.              Returns the received item, or -1 if none is available.
  5069.  
  5070.  
  5071.  
  5072.  
  5073.  
  5074.  
  5075.  
  5076.         
  5077.         
  5078.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 84
  5079.  
  5080.  
  5081.         int write_pipe (pipeptr pip, byte ch, dword timeout);
  5082.         int write_wpipe (wpipeptr pip, word ch, dword timeout);
  5083.  
  5084.              Writes an item to a pipe. If the buffer is full, the task is
  5085.              suspended. A timeout may be specified. If tasks are waiting
  5086.              to read, the item will be assigned to the highest priority
  5087.              waiting task.
  5088.  
  5089.              Returns 0 on success, or TIMEOUT on timeout, WAKE on wake.
  5090.  
  5091.  
  5092.         int c_write_pipe (pipeptr pip, byte ch);
  5093.         int c_write_wpipe (wpipeptr pip, word ch);
  5094.  
  5095.              Writes an item to a pipe only if enough space is available.
  5096.  
  5097.              Returns 0 on success, or -1 if no space available.
  5098.  
  5099.  
  5100.         int wait_pipe_empty (pipeptr pip, dword timeout);
  5101.         int wait_wpipe_empty (wpipeptr pip, dword timeout);
  5102.  
  5103.              Waits for the pipe to be emptied. If the pipe is already
  5104.              empty on entry, the task continues to run.
  5105.  
  5106.              Returns 0 on empty, TIMEOUT on timeout, WAKE on wake.
  5107.  
  5108.  
  5109.         int check_pipe (pipeptr pip);
  5110.         word  check_wpipe (pipeptr pip);
  5111.  
  5112.              Returns -1 if the pipe is empty, else the first item in the
  5113.              pipe. The item is not removed from the pipe.
  5114.  
  5115.  
  5116.         word  pipe_free (pipeptr pip);
  5117.         word  wpipe_free (wpipeptr pip);
  5118.  
  5119.              Returns the number of free items available in the pipe.
  5120.  
  5121.  
  5122.         void  flush_pipe (pipeptr pip)
  5123.         void  flush_wpipe (wpipeptr pip)
  5124.  
  5125.              Clears the pipe. Tasks waiting for the empty state are made
  5126.              eligible.
  5127.  
  5128.  
  5129.  
  5130.  
  5131.  
  5132.  
  5133.  
  5134.         
  5135.         
  5136.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 85
  5137.  
  5138.  
  5139.                                      Buffers
  5140.  
  5141.  
  5142.         A Buffer has a buffer to hold message strings. A message may be
  5143.         written to a buffer if it fits into the buffer. Otherwise, the
  5144.         writing task will be made waiting. A reading task will be made
  5145.         waiting if the buffer is empty. If a message has been read, the
  5146.         highest priority task waiting to write to the buffer will be
  5147.         allowed to write if its message fits into the available space.
  5148.         Interrupt handlers may not use buffer functions other than
  5149.         "check_buffer".
  5150.  
  5151.         The buffer routines are implemented using resources and pipes,
  5152.         and thus are not part of the true "kernel" routines. There is no
  5153.         static creation macro for buffers.
  5154.  
  5155.  
  5156.         bufferptr create_buffer (bufferptr buf, farptr pbuf, word bufsize
  5157.                                  [, byteptr name]);
  5158.  
  5159.              This initialises a buffer. Must be used prior to any other
  5160.              operations on a buffer.
  5161.  
  5162.              The minimum buffer size is the length of the longest
  5163.              expected message plus two.
  5164.  
  5165.              Returns the address of the control block, LNULL on error.
  5166.  
  5167.              "buf"      is the buffer control block (LNULL for automatic
  5168.                         allocation).
  5169.  
  5170.              "pbuf"     is a pointer to the buffer.
  5171.  
  5172.              "bufsize"  is the size of the buffer in bytes.
  5173.  
  5174.              "name"     is the name of the buffer, up to eight
  5175.                         characters, plus zero-terminator. This parameter
  5176.                         is defined only if TSK_NAMEPAR is enabled in
  5177.                         tskconf.h.
  5178.  
  5179.  
  5180.         void  delete_buffer (bufferptr buf);
  5181.  
  5182.              Calling this routine is optional. It will kill all tasks
  5183.              waiting to read or write messages.
  5184.  
  5185.  
  5186.  
  5187.  
  5188.  
  5189.  
  5190.  
  5191.  
  5192.         
  5193.         
  5194.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 86
  5195.  
  5196.  
  5197.         int read_buffer (bufferptr buf, farptr msg, int size,
  5198.                          dword timeout);
  5199.  
  5200.              Read a message from a buffer. If no message is available,
  5201.              the task is suspended. A timeout may be specified.
  5202.  
  5203.              The message will be copied to the buffer "buf", with a
  5204.              maximum length of "size" bytes.
  5205.  
  5206.              Returns the length of the received message, TIMEOUT on
  5207.              timeout, WAKE on wake.
  5208.  
  5209.  
  5210.         int c_read_buffer (bufferptr buf, farptr msg, int size);
  5211.  
  5212.              Reads a message from a buffer only if one is available.
  5213.  
  5214.              Returns the length of the received message, or -1 if none is
  5215.              available.
  5216.  
  5217.  
  5218.         int write_buffer (bufferptr buf, farptr msg, int size,
  5219.                           dword timeout);
  5220.  
  5221.              Writes a message from "msg" with length "size" to a buffer.
  5222.              If not enough space for the message is available, the task
  5223.              is suspended. A timeout may be specified. If tasks are
  5224.              waiting for messages, the highest priority task will get it.
  5225.  
  5226.              Returns the length of the message, TIMEOUT on timeout, WAKE
  5227.              on wake, -3 on error (length < 0 or length > buffer size).
  5228.  
  5229.  
  5230.         int c_write_buffer (bufferptr buf, farptr msg, int size);
  5231.  
  5232.              Writes a message to a buffer only if enough space is
  5233.              available.
  5234.  
  5235.              Returns the length of the message, -1 if no space available,
  5236.              or -3 on error (length < 0 or length > buffer size).
  5237.  
  5238.  
  5239.         word  check_buffer (bufferptr buf);
  5240.  
  5241.              Returns the current number of bytes (not messages) in the
  5242.              buffer, including the length words.
  5243.  
  5244.  
  5245.  
  5246.  
  5247.  
  5248.  
  5249.  
  5250.         
  5251.         
  5252.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 87
  5253.  
  5254.  
  5255.                                The Keyboard Handler
  5256.  
  5257.  
  5258.         word  t_read_key (void)
  5259.  
  5260.              Waits for a key to be entered. Returns the ASCII-code in the
  5261.              lower byte, and the scan-code in the upper byte, or WAKE
  5262.              (0xfffe) on wake.
  5263.  
  5264.  
  5265.         word  t_wait_key (dword timeout)
  5266.  
  5267.              Waits for a key to be entered. Returns the ASCII-code in the
  5268.              lower byte, and the scan-code in the upper byte, or TIMEOUT
  5269.              (0xffff) on timeout, WAKE (0xfffe) on wake.
  5270.  
  5271.  
  5272.         word  t_keyhit (void)
  5273.  
  5274.              Returns -1 (0xffff) if no key was entered, else the value of
  5275.              the key. The key is not removed.
  5276.  
  5277.  
  5278.  
  5279.                               The Serial I/O handler
  5280.  
  5281.         The serial I/O handler provides full duplex interrupt driven I/O
  5282.         on the serial ports. Support for COM1 and COM2 is included,
  5283.         adding other ports is possible by changing the source and/or
  5284.         defining ports on-line.
  5285.  
  5286.  
  5287.         int v24_define_port (int base, byte irq, byte vector)
  5288.  
  5289.              Defines a new COM-port. This routine can only be used if
  5290.              TSK_DYNAMIC is enabled.
  5291.  
  5292.              "base"     is the port base I/O address.
  5293.  
  5294.              "irq"      is the IRQ-line number (0-7 for XT, 0-15 for AT)
  5295.                         the port uses for interrupts.
  5296.  
  5297.              "vector"   is the interrupt vector number (0-0xff).
  5298.  
  5299.              The return value is the internal port number for use with
  5300.              v24_install. -1 is returned on error (memory full).
  5301.  
  5302.  
  5303.  
  5304.  
  5305.  
  5306.  
  5307.  
  5308.         
  5309.         
  5310.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 88
  5311.  
  5312.  
  5313.         sioptr v24_install (int port, int init,
  5314.                             farptr rcvbuf, word rcvsize,
  5315.                             farptr xmitbuf, word xmitsize);
  5316.  
  5317.              Installs the handler for the specified port. Currently,
  5318.              ports 0 (COM1) and 1 (COM2) are supported by default. Both
  5319.              ports may be used simultaneously, the buffer areas for the
  5320.              ports must not be shared.
  5321.  
  5322.              "rcvbuf"   is a word pipe buffer area for received
  5323.                         characters. May be LNULL for automatic allocation.
  5324.  
  5325.              "rcvsize"  specifies the receive buffer size in bytes. Note
  5326.                         that the buffer will hold rcvsize / 2 received
  5327.                         characters.
  5328.  
  5329.              "xmitbuf"  is a byte pipe buffer for characters waiting for
  5330.                         transmission. May be LNULL for automatic
  5331.                         allocation.
  5332.  
  5333.              "xmitsize" gives the transmit buffer size in bytes.
  5334.  
  5335.              "port"     Port number to install (0: COM1, 1: COM2).
  5336.  
  5337.                         If the port number is ORed with 0x80, the port is
  5338.                         *relative*. This means that the entry in the BIOS
  5339.                         table for COM-Ports is used to search the tables
  5340.                         internal to the driver for the port information,
  5341.                         instead of using the table entry directly. If the
  5342.                         port address cannot be found, the driver returns
  5343.                         with an error code. Note that ports are numbered
  5344.                         from 0, so to specify relative COM1, pass 0x80 as
  5345.                         parameter.
  5346.  
  5347.              "init"     if non-zero, the port is initialised with the
  5348.                         default values specified in the source. If the
  5349.                         parameter is zero, the control registers and baud
  5350.                         rates on entry are not modified.
  5351.  
  5352.              The return value is a pointer to the sio control block for
  5353.              use with the other driver routines. LNULL is returned on
  5354.              error (invalid port number, bad buffer sizes, nonexistent
  5355.              hardware, out of memory).
  5356.  
  5357.  
  5358.  
  5359.  
  5360.  
  5361.  
  5362.  
  5363.  
  5364.  
  5365.  
  5366.         
  5367.         
  5368.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 89
  5369.  
  5370.  
  5371.         void  v24_remove (sioptr sio, int restore);
  5372.  
  5373.              Removes the driver for the specified control block. Should
  5374.              be called for all ports installed before exiting the
  5375.              program.
  5376.  
  5377.              If the "restore" parameter is nonzero, the control registers
  5378.              and the baud rate that were set before installation of the
  5379.              driver are restored. If the parameter is zero, the values
  5380.              are not changed.
  5381.  
  5382.  
  5383.         void  v24_remove_all (void)
  5384.  
  5385.              Removes all installed serial i/o drivers. This routine is
  5386.              automatically called on remove_tasker if drivers were
  5387.              installed. Note that you can not specify a restore
  5388.              parameter, the default restore parameter is used (constant
  5389.              in tsksio.c).
  5390.  
  5391.  
  5392.         void  v24_change_rts (sioptr sio, int on);
  5393.  
  5394.              Changes the state of the RTS output line. A nonzero value
  5395.              for "on" will turn the output on.
  5396.  
  5397.  
  5398.         void  v24_change_dtr (sioptr sio, int on);
  5399.  
  5400.              Changes the state of the DTR output line. A nonzero value
  5401.              for "on" will turn the output on.
  5402.  
  5403.  
  5404.         void  v24_change_baud (sioptr sio, long rate);
  5405.  
  5406.              Changes the baud rate. The following baud rates are suppor-
  5407.              ted:
  5408.  
  5409.                 50,    75,   110,   134,   150,   300,   600,
  5410.               1200,  1800,  2000,  2400,  3600,  4800,  7200,  9600,
  5411.              19200, 38400.
  5412.  
  5413.              Note that baud rates above 9600 may cause problems on slow
  5414.              machines.
  5415.  
  5416.  
  5417.  
  5418.  
  5419.  
  5420.  
  5421.  
  5422.  
  5423.  
  5424.         
  5425.         
  5426.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 90
  5427.  
  5428.  
  5429.         void  v24_change_parity (sioptr sio, int par);
  5430.  
  5431.              Changes parity. The parameter must be one of the following
  5432.              values defined in "sio.h":
  5433.  
  5434.                   PAR_NONE  no parity checks
  5435.                   PAR_EVEN  even parity
  5436.                   PAR_ODD   odd parity
  5437.                   PAR_MARK  mark parity
  5438.                   PAR_SPACE space parity
  5439.  
  5440.  
  5441.         void  v24_change_wordlength (sioptr sio, int len);
  5442.  
  5443.              Changes word length. Values 5, 6, 7, 8 may be given.
  5444.  
  5445.  
  5446.         void  v24_change_stopbits (sioptr sio, int n);
  5447.  
  5448.              Changes Stopbits. Values 1 and 2 are allowed.
  5449.  
  5450.  
  5451.         void  v24_watch_modem (sioptr sio, byte flags);
  5452.  
  5453.              Watches the modem status lines to control transmission.
  5454.  
  5455.              "flags"    Specifies the input lines that must be active to
  5456.                         allow transmission. Transmission will stop if one
  5457.                         of the lines goes inactive. The parameter may be
  5458.                         combined from the following values defined in
  5459.                         "sio.h":
  5460.  
  5461.                         CTS  to watch clear to send
  5462.                         DSR  to watch data set ready
  5463.                         RI   to watch ring indicator
  5464.                         CD   to watch carrier detect
  5465.  
  5466.              A value of zero (the default) will allow transmission
  5467.              regardless of modem status.
  5468.  
  5469.  
  5470.  
  5471.  
  5472.  
  5473.  
  5474.  
  5475.  
  5476.  
  5477.  
  5478.  
  5479.  
  5480.  
  5481.  
  5482.         
  5483.         
  5484.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 91
  5485.  
  5486.  
  5487.         void  v24_protocol (sioptr sio, int prot,
  5488.                            word offthresh, word onthresh);
  5489.  
  5490.              Sets the handshake protocol to use.
  5491.  
  5492.              "prot"     specifies the protocol. This parameter may be
  5493.                         combined from the following values:
  5494.  
  5495.                         XONXOFF   to enable XON/XOFF (DC1/DC3) handshake
  5496.                         RTSCTS    to enable RTS/CTS handshake
  5497.  
  5498.              "offthresh" specifies the minimum number of free items in
  5499.                         the receive buffer. If this threshold is reached,
  5500.                         an XOFF is transmitted and/or the RTS line is
  5501.                         inactivated.
  5502.  
  5503.              "onthresh" specifies the minimum number of items that must
  5504.                         be free before XON is transmitted and/or the RTS
  5505.                         line is re-activated.
  5506.  
  5507.              Enabling XONXOFF will remove all XON and XOFF characters
  5508.              from the input stream. Transmission will be disabled when
  5509.              XOFF is received, and re-enabled when XON is received.
  5510.  
  5511.              Enabling RTSCTS will stop transmission when the CTS modem
  5512.              input line is inactive.
  5513.  
  5514.  
  5515.         int v24_send (sioptr sio, byte ch, dword timeout);
  5516.  
  5517.              Transmits the character "ch". A timeout may be specified.
  5518.  
  5519.              Returns TIMEOUT on timeout, WAKE on wake, else 0.
  5520.  
  5521.  
  5522.         int v24_receive (sioptr sio, dword timeout);
  5523.  
  5524.              Waits for a received character. A timeout may be specified.
  5525.  
  5526.              Returns TIMEOUT on timeout, WAKE on wake, else the character
  5527.              in the lower byte, plus an error code in the upper byte. The
  5528.              error code is the combination of
  5529.  
  5530.                   0x02      overrun error
  5531.                   0x04      parity error
  5532.                   0x08      framing error
  5533.                   0x10      break interrupt.
  5534.  
  5535.  
  5536.         int v24_check (sioptr sio);
  5537.  
  5538.              Returns -1 if no receive character is available, else the
  5539.              next character from the pipe. The character is not removed.
  5540.         
  5541.         
  5542.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 92
  5543.  
  5544.  
  5545.         int v24_overrun (sioptr sio);
  5546.  
  5547.              Checks for receive pipe overrun. Returns 1 if an overrun
  5548.              occurred, 0 otherwise. Clears the overrun flag.
  5549.  
  5550.  
  5551.         int v24_modem_status (sioptr sio);
  5552.  
  5553.              Returns the current modem status word. The CTS, DSR, RI, and
  5554.              CD defines may be used to extract the modem input line
  5555.              status.
  5556.  
  5557.  
  5558.         int v24_complete (sioptr sio);
  5559.  
  5560.              Returns 1 if all characters in the transmit pipe have been
  5561.              sent, else 0.
  5562.  
  5563.  
  5564.         int v24_wait_complete (sioptr sio, dword timeout);
  5565.  
  5566.              Waits for the transmit pipe to be empty. Returns TIMEOUT on
  5567.              timeout, WAKE on wake, else 0.
  5568.  
  5569.  
  5570.         void  v24_flush_receive (sioptr sio);
  5571.  
  5572.              Flushes the receive pipe.
  5573.  
  5574.  
  5575.         void  v24_flush_transmit (sioptr sio)
  5576.  
  5577.              Flushes the transmit pipe. Tasks waiting for transmit
  5578.              completion are made eligible.
  5579.  
  5580.  
  5581.  
  5582.  
  5583.  
  5584.  
  5585.  
  5586.  
  5587.  
  5588.  
  5589.  
  5590.  
  5591.  
  5592.  
  5593.  
  5594.  
  5595.  
  5596.  
  5597.  
  5598.         
  5599.         
  5600.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 93
  5601.  
  5602.  
  5603.                             The Printer Output Driver
  5604.  
  5605.  
  5606.         The printer output driver provides for buffered output to up to
  5607.         three printer ports (more can be added by editing the source).
  5608.         Interrupt or polling may be selected. Due to the usual hardware
  5609.         implementation of printers and the printer interface, using
  5610.         polling is recommended. When using interrupts, you should not
  5611.         simultaneously install both port 0 and port 1 with interrupt
  5612.         enabled, since both ports share the same interrupt line.
  5613.  
  5614.  
  5615.         int prt_install (int port, byte polling, word prior,
  5616.                          farptr xmitbuf, word xmitsize);
  5617.  
  5618.              Installs the printer driver for the specified port. Ports 0
  5619.              (LPT1), 1 (LPT2), and 2 (LPT3) are supported.
  5620.  
  5621.              "port"     The output port to use.
  5622.  
  5623.                         If the port number is ORed with 0x80, the port is
  5624.                         relative. This means that the entry in the BIOS
  5625.                         table for LPT-Ports is used to search the tables
  5626.                         internal to the driver for the port information,
  5627.                         instead of using the table entry directly. If the
  5628.                         port address cannot be found, the driver returns
  5629.                         with an error code. Note that ports are numbered
  5630.                         from 0, so to specify LPT1, pass 0x80 as
  5631.                         parameter.
  5632.  
  5633.              "polling"  specifies polling output when nonzero, interrupt
  5634.                         output when zero.
  5635.  
  5636.              "prior"    sets the priority of the printer output task.
  5637.  
  5638.              "xmitbuf"  is a buffer area for the printer output buffer.
  5639.                         May be LNULL for automatic allocation.
  5640.  
  5641.              "xmitsize" specifies the output buffer size in bytes.
  5642.  
  5643.              The return value is the internal port number for use with
  5644.              the other driver routines. -1 is returned on error (invalid
  5645.              port number, bad buffer sizes, nonexistent hardware).
  5646.  
  5647.  
  5648.         void  prt_remove (int port);
  5649.  
  5650.              Removes the printer driver for the specified port.
  5651.  
  5652.  
  5653.  
  5654.  
  5655.  
  5656.         
  5657.         
  5658.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 94
  5659.  
  5660.  
  5661.         void  prt_remove_all (void)
  5662.  
  5663.              Removes all installed printer ports. This routine is
  5664.              automatically called on remove_tasker if ports were
  5665.              installed.
  5666.  
  5667.  
  5668.         void  prt_change_control (int port, byte control);
  5669.  
  5670.              Changes the printer control output lines of the port. The
  5671.              value for "control" may be combined from the following
  5672.              values defined in "prt.h":
  5673.  
  5674.                   AUTOFEED  will enable printer auto feed if set
  5675.                   INIT      will initialise (prime) the printer if clear
  5676.                   SELECT    will select the printer if set
  5677.  
  5678.  
  5679.         int prt_write (int port, byte ch, dword timeout);
  5680.  
  5681.              Write a byte to the printer. A timeout may be given.
  5682.  
  5683.              Returns 0 on success, TIMEOUT on timeout, WAKE on wake.
  5684.  
  5685.  
  5686.         int prt_status (int port);
  5687.  
  5688.              Returns the current printer status lines, combined from the
  5689.              values
  5690.  
  5691.                   BUSY      Printer is busy when 0
  5692.                   ACK       Acknowledge (pulsed 0)
  5693.                   PEND      Paper End detected when 0
  5694.                   SELIN     Printer is selected (on line) when 1
  5695.                   ERROR     Printer error when 0
  5696.  
  5697.  
  5698.         int prt_complete (int port);
  5699.  
  5700.              Returns 1 if the printer buffer has been completely
  5701.              transmitted, 0 otherwise.
  5702.  
  5703.  
  5704.         int prt_wait_complete (int port, dword timeout);
  5705.  
  5706.              Waits for printer output to complete.
  5707.  
  5708.              Returns 0 on success, else TIMEOUT on timeout, WAKE on wake.
  5709.  
  5710.         void  prt_flush (int port)
  5711.  
  5712.              Flushes the output pipe of the printer. Tasks waiting for
  5713.              print completion are made eligible.
  5714.         
  5715.         
  5716.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 95
  5717.  
  5718.  
  5719.                             Support Modules
  5720.  
  5721.                             Memory Allocation Interface
  5722.  
  5723.  
  5724.         The file tskalloc.c contains routines that interface CTask to the
  5725.         standard C memory allocation routines. Since the CTask kernel is
  5726.         model independent, it can not use the runtime routines directly.
  5727.         Also, to avoid crashes, CTask routines allocating memory must use
  5728.         a resource to channel access to the memory allocator, since the
  5729.         standard routines are not reentrant. All memory allocation in
  5730.         tasks should use the CTask allocation functions instead of the
  5731.         standard ones. See the chapter on memory allocation for more
  5732.         information.
  5733.  
  5734.         farptr tsk_alloc (word size);
  5735.  
  5736.              Replacement function for the standard malloc.
  5737.  
  5738.  
  5739.         farptr tsk_calloc (word item, word size);
  5740.  
  5741.              Replacement function for the standard calloc.
  5742.  
  5743.  
  5744.         farptr tsk_free (farptr item);
  5745.  
  5746.              Replacement function for the standard free. This routine
  5747.              always returns LNULL.
  5748.  
  5749.  
  5750.         farptr tsk_realloc (farptr item, word size);
  5751.  
  5752.              Replacement function for the standard realloc.
  5753.  
  5754.  
  5755.         Global variables:
  5756.  
  5757.              resource alloc_resource;
  5758.  
  5759.                   Is the memory allocation routine access resource. If
  5760.                   you use other allocator routines, or want to allocate
  5761.                   several items in a row, you may enclose the calls to
  5762.                   the standard C functions in calls to request_resource
  5763.                   (&alloc_resource) and free_resource (&alloc_resource).
  5764.  
  5765.  
  5766.  
  5767.  
  5768.  
  5769.  
  5770.  
  5771.  
  5772.         
  5773.         
  5774.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 96
  5775.  
  5776.  
  5777.                             Printf Replacements
  5778.  
  5779.  
  5780.         Version 2.1 adds several functions that can (at least in most
  5781.         cases) replace the standard C printf family functions. Apart from
  5782.         being a lot faster and smaller, the routines do not assume
  5783.         DS==SS, are reentrant and completely self-contained, and thus can
  5784.         be used independent of the memory model in use. They use no CTask
  5785.         kernel functions, and could also be used in non-CTask
  5786.         applications, for example in Assembler modules, or device
  5787.         drivers/DLLs for DOS and Windows. The routines support direct
  5788.         access to the secondary screen in a dual monitor system.
  5789.  
  5790.  
  5791.         int tsk_sprintf (farptr str, farptr fmt, ...);
  5792.         int tsk_vsprintf (farptr str, farptr fmt, farptr arg);
  5793.  
  5794.              Print to string. Replacement for sprintf and vsprintf.
  5795.              Returns number of character written, not counting the
  5796.              terminating zero character.
  5797.  
  5798.  
  5799.         void  tsk_rprintf (farptr fmt, ...);
  5800.         void  tsk_vrprintf (farptr fmt, farptr arg);
  5801.  
  5802.              Output directly to screen regen hardware buffer. Allows
  5803.              printing to the secondary monitor in dual-screen systems,
  5804.              and is extremely fast.
  5805.  
  5806.  
  5807.         void  tsk_printf (farptr fmt, ...);
  5808.         void  tsk_vprintf (farptr fmt, farptr arg);
  5809.  
  5810.              Print to console. Uses INT 10 calls, so it's faster than
  5811.              standard printf, but can't be redirected.
  5812.  
  5813.  
  5814.         void  tsk_fprintf (int handle, farptr fmt, ...);
  5815.         void  tsk_vfprintf (int handle, farptr fmt, farptr arg);
  5816.  
  5817.              Print to file. Note that this is no direct replacement for
  5818.              fprintf/vfprintf, since the parameter is a DOS file handle,
  5819.              not a FILE *. Use with files opened through the low-level
  5820.              open functions, or use the standard fileno() function to get
  5821.              the handle of a stream file. Stream files should be flushed
  5822.              before use if other C functions were used to write to the
  5823.              file.
  5824.  
  5825.  
  5826.         void  tsk_putc (char c);
  5827.  
  5828.              Put character to screen using INT 10.
  5829.  
  5830.         
  5831.         
  5832.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 97
  5833.  
  5834.  
  5835.         void  tsk_puts (farptr str);
  5836.  
  5837.              Put string to screen using INT 10. A new line is started
  5838.              after output.
  5839.  
  5840.  
  5841.         void  tsk_rputc (char c);
  5842.  
  5843.              Put character directly to screen hardware regen buffer.
  5844.  
  5845.  
  5846.         void  tsk_rputs (farptr str);
  5847.  
  5848.              Put string directly to screen hardware regen buffer. A new
  5849.              line is started after output.
  5850.  
  5851.  
  5852.         word  tsk_set_dualdis (void);
  5853.  
  5854.              Initialize the hardware regen output to go to the secondary
  5855.              monitor. Returns the regen buffer address, or 0 if no
  5856.              secondary adapter was found.
  5857.  
  5858.  
  5859.         word  tsk_set_currdis (void);
  5860.  
  5861.              Initialize the hardware regen output to go to the primary
  5862.              monitor. Returns the regen buffer address, or 0 on error.
  5863.  
  5864.  
  5865.         void  tsk_set_colour (int rows, int cols);
  5866.  
  5867.              Initialize the hardware regen output to go to the colour
  5868.              monitor with the given number of screen rows and columns.
  5869.  
  5870.  
  5871.         void  tsk_set_mono (int rows, int cols);
  5872.  
  5873.              Initialize the hardware regen output to go to the monochrome
  5874.              monitor with the given number of screen rows and columns.
  5875.  
  5876.  
  5877.  
  5878.  
  5879.  
  5880.  
  5881.  
  5882.  
  5883.  
  5884.  
  5885.  
  5886.  
  5887.  
  5888.         
  5889.         
  5890.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 98
  5891.  
  5892.  
  5893.         void  tsk_set_regen (int regenseg, int port, int rows, int cols);
  5894.  
  5895.              Initialize the hardware regen output to go to the specified
  5896.              monitor address. You have to specify
  5897.  
  5898.                   regenseg  The segment address of the regen buffer.
  5899.  
  5900.                   port      The 6845 display controller port. If zero,
  5901.                             you can still write to the screen, but the
  5902.                             cursor will not be moved.
  5903.  
  5904.                   rows      The number of rows on screen.
  5905.  
  5906.                   cols      The number of columns on screen.
  5907.  
  5908.              Note that you can use this function to restrict output to
  5909.              a smaller part of the screen by increasing the segment
  5910.              address and decreasing the number of rows.
  5911.  
  5912.  
  5913.         void  tsk_setpos (int row, int col);
  5914.  
  5915.              Set the cursor position for hardware output. Row and column are
  5916.              numbered starting at 0.
  5917.  
  5918.  
  5919.         void  tsk_set_attr (int attr);
  5920.  
  5921.              Set the screen display attribute byte for subsequent hardware
  5922.              output to "attr".
  5923.  
  5924.  
  5925.         Global variables:
  5926.  
  5927.              dword tsk_regen;
  5928.              word tsk_regen_o;
  5929.              word tsk_regen_s;
  5930.  
  5931.                   Contain the current hardware screen pointer.
  5932.                   tsk_regen_o contains the current offset, tsk_regen_s
  5933.                   the regen buffer segment. tsk_regen is a synonym for
  5934.                   doubleword access to both variables.
  5935.  
  5936.              word tsk_disport;
  5937.  
  5938.                   The hardware 6845 controller port address. If set to 0,
  5939.                   the display cursor will not be updated.
  5940.  
  5941.  
  5942.  
  5943.  
  5944.  
  5945.  
  5946.         
  5947.         
  5948.         Ctask Manual       - Version 2.2 - 90-10-12 -             Page 99
  5949.  
  5950.  
  5951.                             Snapshot Dump
  5952.  
  5953.  
  5954.         The snapshot dump module TSKSNAP.C provides a display of the
  5955.         current state of tasks and control structures. This display is
  5956.         rather extensive, and can easily exceed screen capacity. It may
  5957.         be useful to change the routines to suit your needs by omitting
  5958.         some  of the information, or displaying other than the standard
  5959.         info.
  5960.  
  5961.         Since display of the snapshot runs at high priority, the system
  5962.         will  slow down noticeably if snapshots are output with high
  5963.         frequency.
  5964.  
  5965.         The standard routines provided are
  5966.  
  5967.         void  screensnap (int rows);
  5968.  
  5969.              Output to hardware screen regen buffer. The hardware screen
  5970.              must have been initialised with a call to the
  5971.              tsk_set_dualdis or similar functions (see description of
  5972.              printf replacements). If the "rows" parameter is nonzero,
  5973.              the display will be truncated at the given number of rows.
  5974.  
  5975.         void  csnapshot (void);
  5976.  
  5977.              Output to console using INT 10.
  5978.  
  5979.         void  snapshot (FILE *f);
  5980.  
  5981.              Output to the given stream file.
  5982.  
  5983.  
  5984.  
  5985.  
  5986.  
  5987.  
  5988.  
  5989.  
  5990.  
  5991.  
  5992.  
  5993.  
  5994.  
  5995.  
  5996.  
  5997.  
  5998.  
  5999.  
  6000.  
  6001.  
  6002.  
  6003.  
  6004.         
  6005.         
  6006.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 100
  6007.  
  6008.  
  6009.                                  Advanced Topics
  6010.  
  6011.                           Primary and Secondary Kernels
  6012.  
  6013.         Version 2.0 officially introduced support for CTask programs
  6014.         going TSR and spawning. Version 2.1 adds some features to make
  6015.         this  safer (especially in EMS systems), and to save code in
  6016.         secondary applications.
  6017.  
  6018.         The manual often refers to the terms "primary" and "secondary"
  6019.         kernel. The primary kernel is the first installation of CTask.
  6020.         This  kernel installs all basic interrupt handlers, the DOS and
  6021.         keyboard support, and the system tasks (timer, killer). It basi-
  6022.         cally is nothing else than a normal, stand-alone CTask
  6023.         installation.
  6024.  
  6025.         A secondary kernel is installed by a CTask program run "on top"
  6026.         of the primary. This, naturally, is only possible if the primary
  6027.         program has gone resident (TSR), or has spawned another program
  6028.         (for  example COMMAND.COM). A secondary kernel automatically de-
  6029.         tects that a primary copy of CTask is already installed, and does
  6030.         not attempt to re-install the interrupt handlers and system
  6031.         tasks. Instead, it uses a pointer to the global variable block in
  6032.         the primary to access all global CTask data. This results in both
  6033.         CTask copies cooperating such that all events, tasks, and other
  6034.         structures, are common to both invocations, and share all global
  6035.         resources. The names of control structures are visible accross
  6036.         the copies, so that a secondary can access control blocks of the
  6037.         primary, and vice versa.
  6038.  
  6039.         There is a separate control structure, the "group control block",
  6040.         for every invocation (or "task group"). This block links all con-
  6041.         trol  structures created by tasks inside the group together, so
  6042.         that  the system can remove those tasks and events from the system
  6043.         that  belong to the secondary, should the secondary terminate
  6044.         without cleaning up properly. The group control block additio-
  6045.         nally contains pointers to data structures and routines that can
  6046.         not be shared (like the memory allocation routines). The group
  6047.         control block is a static structure that is initialised when you
  6048.         call  install_tasker.
  6049.  
  6050.         This  primary/secondary structure can be completely invisible if
  6051.         you run CTask programs that could also run as standalone CTask
  6052.         applications. But the automatic data sharing also makes it
  6053.         possible to create multi-level programs, which use a resident
  6054.         part  to handle hardware interrupts (for example a com port) in
  6055.         the background, and an independently loadable program (which
  6056.         might even be a MS Windows program or driver) to control the
  6057.         resident part. If the controlling (secondary) program does not
  6058.         itself use multitasking features (i.e. create tasks), there is no
  6059.         need  for it to include a full-fledged CTask kernel with all the
  6060.         features, and no need to create a task group. But even if it
  6061.         creates tasks, but will never use the full CTask features if
  6062.         
  6063.         
  6064.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 101
  6065.  
  6066.  
  6067.         there is no background kernel, it will not need to include the
  6068.         code  for the basic (primary) interrupt handlers and tasks.
  6069.  
  6070.         CTask 2.1 includes several options for cooperating CTask appli-
  6071.         cations to save code in a secondary program. With all these
  6072.         options, the generated program will not be able to use CTask if
  6073.         there is no primary kernel installed.
  6074.  
  6075.         The first option is to use the "stskmain" object created by
  6076.         compiling tskmain.c with SECONDARY defined. With this define, the
  6077.         install_tasker and remove_tasker routines will only reference the
  6078.         second-level group creation routines. All references to the
  6079.         primary task installation routines, which in turn reference the
  6080.         interrupt handlers and system tasks, are eliminated.
  6081.         Install_tasker returns an error code if there is no primary
  6082.         kernel installed, but all other aspects of CTask will work as
  6083.         usual. A task group is created.
  6084.  
  6085.         The second option is to not call install_tasker at all in the
  6086.         secondary. You need not link either tskmain or stskmain. Calling
  6087.         "ctask_resident" will establish the data link. This link enables
  6088.         CTask to work without a task group, such that everything you do
  6089.         in the secondary appears as if it were executed in the primary
  6090.         kernel. This, however, means that you should not create any CTask
  6091.         control structures in the secondary (or at least you should not
  6092.         allow them to be linked into the name chain). If the secondary
  6093.         terminates without removing all control structures and tasks it
  6094.         created, the pointers chained into the primary links will point
  6095.         to some other program loaded later, which may be destroyed if any
  6096.         action causes those pointers to be referenced. You also may not
  6097.         use dynamic allocation in the secondary, since this would try to
  6098.         allocate memory in the primary applications data space.
  6099.  
  6100.         The third option is to use code sharing with the "stskmain"
  6101.         object. Code sharing requires the primary kernel to be compiled
  6102.         with  the CODE_SHARING and LOAD_DS configuration options set to
  6103.         TRUE. With Microsoft C, setting those options in tskconf.h is
  6104.         sufficient. With Turbo C, which does not have the "_loadds"
  6105.         keyword, the primary must be compiled in Huge memory model, and
  6106.         the TC_HUGE option must be TRUE. The reason for this is that the
  6107.         routines can now be called from an application with completely
  6108.         different segment setup. If a routine in the primary kernel is
  6109.         called from a secondary, the data segment register will point to
  6110.         the secondary's data segment. The offsets to CTask structures in
  6111.         the primary code will point to some other data in the secondary.
  6112.         So all routines that could be accessed from the outside must set
  6113.         up the data segment register to point to the primary data.
  6114.  
  6115.         Code  sharing uses a "stub table" and an "entry table" for a
  6116.         primitive form of run-time linking. The entry table simply
  6117.         contains the addresses of all global routines present in the
  6118.         primary in fixed order. The stub table contains short "stub"
  6119.         routines that access the entry table through the global variable
  6120.         
  6121.         
  6122.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 102
  6123.  
  6124.  
  6125.         pointer, and jump to the address corresponding to the called stub
  6126.         routine. Both tables are generated from one source,
  6127.         "tskstub.asm". You must first decide which routines should be
  6128.         included in the primary, and edit the stub definitions in this
  6129.         file  accordingly. The file is then assembled twice. The copy to
  6130.         be included with the primary is assembled with GEN_JTAB defined
  6131.         (this is automatically done by the standard makefile). The stub
  6132.         table copy for the secondary is assembled without this define.
  6133.         Install_tasker returns an error code if there is no primary
  6134.         kernel installed, but all other aspects of CTask will work as
  6135.         usual. The link_ctask routine can be used before calling
  6136.         install_tasker to verify that the primary kernel is installed and
  6137.         has code sharing enabled. A task group is created. The primary
  6138.         kernel will be slightly larger due to the additional code
  6139.         required to load the data segment on function entry, but the
  6140.         secondary will need to link only those CTask routines that are
  6141.         not defined as entry stubs.
  6142.  
  6143.         The fourth option is to use code sharing with no call to
  6144.         install_tasker. This requires nearly zero code in the secondary,
  6145.         but the same restrictions mentioned with the second option apply.
  6146.  
  6147.  
  6148.         There is one restriction on cooperating applications, whether
  6149.         they  use code sharing or not: The control structures for both
  6150.         primary and secondary must be identical. This requires that the
  6151.         following configuration options are identical on compilation of
  6152.         both  kernels:
  6153.  
  6154.            TSK_DYNAMIC
  6155.            TSK_NAMED
  6156.            EMS
  6157.            NDP
  6158.            HOTKEYS
  6159.  
  6160.            IBM, DOS, GROUPS (must be TRUE for groups to work at all)
  6161.  
  6162.         If you change those options, the sizes of the global structures,
  6163.         and the location of some fields within them, change, making it
  6164.         impossible to share structures. Linking two kernels with
  6165.         different configurations will not work.
  6166.  
  6167.         You may, however, change all other configurations. It is
  6168.         perfectly legal to compile the primary in large model, and the
  6169.         secondary in small (NEAR_CODE set to TRUE), even if you are using
  6170.         code  sharing. The secondary does not have to set the CODE_SHARING
  6171.         option, this option is only required in the primary.
  6172.  
  6173.  
  6174.  
  6175.  
  6176.  
  6177.  
  6178.         
  6179.         
  6180.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 103
  6181.  
  6182.  
  6183.         Secondary application link examples (Microsoft C Large model):
  6184.  
  6185.           Option 1: link myprog+stskmain,,,ctaskms+ctsupmsl/NOE
  6186.           Option 2: link myprog,,,ctaskms+ctsupmsl
  6187.           Option 3: link myprog+stskmain+tskstub,,,ctaskms+ctsupmsl/NOE
  6188.           Option 4: link myprog+tskstub,,,ctaskms+ctsupmsl/NOE
  6189.  
  6190.         Note  that the "tskstub" object linked with options 3 and 4 is the
  6191.         one assembled without the GEN_JTAB define. It is not the
  6192.         tskstub.obj created by the standard makefile.
  6193.  
  6194.         The /NOE switch is required for the Microsoft linker, since the
  6195.         entry points in stskmain and tskstub duplicate entries in the
  6196.         standard CTask library.
  6197.  
  6198.  
  6199.                               TSR, Spawning, and EMS
  6200.  
  6201.         If you are writing a CTask application that should stay resident
  6202.         or spawn DOS, you will be hard pressed to reduce the space
  6203.         required to a minimum. One option to consider is replacing the
  6204.         standard startup code. This code calls a number of routines to
  6205.         setup parameters and the environment copy, and requests a lot of
  6206.         memory, that most likely will never be used by your program. The
  6207.         source for the startup code is included with MS and Turbo C.
  6208.  
  6209.         Another space saver is the included printf replacement. If you
  6210.         don't need the floating point output, tsk_printf and its cousins
  6211.         give  you all the capabilities you'll normally need at greatly
  6212.         reduced space (if you need printf at all in your TSR).
  6213.  
  6214.         In general, memory allocation is not needed in a TSR or spawning
  6215.         program, since you can't allocate once you are resident.
  6216.         Ommitting the memory allocation routines saves another chunk of
  6217.         code. The TSK_DYNLOAD define may be set to FALSE to prevent
  6218.         reference to the memory allocator routines from the CTask kernel
  6219.         even  when TSK_DYNAMIC is TRUE to support secondary kernels.
  6220.         Again, you may have to change the C startup code to prevent it
  6221.         from  calling routines that allocate memory.
  6222.  
  6223.         The final option is putting some of your code and/or data in EMS
  6224.         memory. CTask 2.1 switches EMS on a task basis, and saves the EMS
  6225.         configuration when a task is created. It would thus be possible
  6226.         to move tasks and their local data into an EMS bank (in the 64k
  6227.         LIM 3.2 page frame), and call create_task with the required page
  6228.         configuration activated. Whenever the task is scheduled in, the
  6229.         EMS page will have been switched correctly.  The only restriction
  6230.         is that the task control block itself, and all CTask data
  6231.         structures (event control blocks etc.) must be in common memory.
  6232.         All other data, and even the task's stack, may be in EMS
  6233.         (although having stacks in EMS is generally not recommended).
  6234.         This  may be hard to do with C programs, but could possibly be
  6235.         achieved with the use of overlay techniques.
  6236.         
  6237.         
  6238.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 104
  6239.  
  6240.  
  6241.                        Functions called by Kernel Routines
  6242.  
  6243.         User-defined functions called from the kernel are the task
  6244.         save/restore functions, the functions activated with timers,
  6245.         watches and hotkeys, and the "remove" functions. Some
  6246.         restrictions apply to those functions.
  6247.  
  6248.         For calling functions on a timeout, hotkey, or watch, the
  6249.         following must be noted:
  6250.  
  6251.            -  Timeout/watch functions should be as short as possible,
  6252.              since they run at the highest priority.
  6253.  
  6254.            -  The stack area is the area of the timer task, which is
  6255.              relatively small. Do not use large automatic variables.
  6256.  
  6257.            -  Timeout/watch functions may not use any functions that could
  6258.              cause the timer task to be made waiting.
  6259.  
  6260.         Since version 2.0, timeout/watch functions are called with
  6261.         interrupts enabled. The definition of the timeout/watch/hotkey
  6262.         function is
  6263.  
  6264.              void Taskfunc funcname (tlinkptr elem)
  6265.  
  6266.         The function is called with a pointer to the timer control block.
  6267.         The user parameter passed to the create_xxx routines is
  6268.         accessible through this pointer (elem->user_parm). The data
  6269.         segment is set to the segment address of the timer control block.
  6270.  
  6271.         Hotkey functions are equal to timeout/watch functions, but they
  6272.         are called from inside the keyboard hardware interrupt. The stack
  6273.         is a  local interrupt stack, and the function must not use any
  6274.         CTask routines that could cause a task to be made waiting or to
  6275.         be killed.
  6276.  
  6277.         Remove functions may be called at a time when the state of the
  6278.         system is unstable, i.e. during the "emergency exit". To avoid
  6279.         problems, you should not call any DOS functions, and also refrain
  6280.         from  using CTask functions. Remove functions should only be used
  6281.         to uninstall interrupt handlers and do similar cleanups. The
  6282.         functions are called with a pointer to the call chain block, and
  6283.         the data segment is set to the segment address of this block. The
  6284.         definition is
  6285.  
  6286.              void Taskfunc funcname (callchainptr chain)
  6287.  
  6288.  
  6289.         Two functions may be set in the TCB that are called whenever the
  6290.         task  defining them is scheduled out (the "save" function) or
  6291.         scheduled in (the "restore" function). The main use for those
  6292.         functions is to save and restore static state variables that are
  6293.         shared among tasks. A windowing package, for example, may have
  6294.         
  6295.         
  6296.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 105
  6297.  
  6298.  
  6299.         global variables describing the current window. If you want to
  6300.         output to different windows from different tasks, you may have to
  6301.         save  the current state whenever the task changes. A better way
  6302.         than  to copy a number of variables would be to make the windowing
  6303.         package "CTask aware", for example by letting it reference those
  6304.         variables through the user pointer in the TCB. This solution,
  6305.         however, may not be feasible with third-party libraries. That's
  6306.         where the save/restore functions come into play. Both functions
  6307.         are defined as
  6308.  
  6309.                 void Taskfunc funcname (tcbptr tcb)
  6310.  
  6311.         i.e.  they do not return a value, and receive a pointer to the
  6312.         current TCB (the task control block defining the function). The
  6313.         data  segment register is set to the segment address of the TCB.
  6314.  
  6315.  
  6316.         The data segment that all those functions are entered with is not
  6317.         necessarily the same segment as the normal data segment of your
  6318.         program. Especially with far data memory models in Microsoft C,
  6319.         the huge model in Turbo C, or dynamically allocated blocks, you
  6320.         can not rely on the data segment having the correct value, unless
  6321.         you make sure that the control block is located in the same
  6322.         segment. To allow you to access global variables from your code,
  6323.         you should either use the _loadds keyword with Microsoft C, or
  6324.         compile the routine in a separate module with all data references
  6325.         defined extern with Turbo C huge model. The safest way is to
  6326.         collect all data the routine should modify in a single structure,
  6327.         and pass the address of this structure as the user pointer/user
  6328.         parameter. If all data you reference is located in the same file
  6329.         as the control block, it is reasonably safe to assume that this
  6330.         data  is in the same segment, and thus accessible without special
  6331.         precautions. You may have to take care not to set the "data
  6332.         threshold" with Microsoft C too low, however, since this may
  6333.         cause data items in the same file to be placed in different
  6334.         segments. The same_seg pragma can be used to avoid this.
  6335.  
  6336.  
  6337.  
  6338.  
  6339.  
  6340.  
  6341.  
  6342.  
  6343.  
  6344.  
  6345.  
  6346.  
  6347.  
  6348.  
  6349.  
  6350.  
  6351.  
  6352.         
  6353.         
  6354.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 106
  6355.  
  6356.  
  6357.                       Some notes on potential trouble spots
  6358.  
  6359.                               Turbo C console output
  6360.  
  6361.         As mentioned in the manual, console output should generally be
  6362.         done  only from one task, or be protected with resources. This is
  6363.         especially true for Turbo C (Version 1.5 and later), because the
  6364.         putch function is NOT REENTRANT. Since other console output also
  6365.         uses  putch in the end, you have to be extremely careful not to
  6366.         crash your system by entering the putch routine concurrently. You
  6367.         should use the "conout" module provided with CTask to channel
  6368.         console output through a buffer. If you own the Turbo C library
  6369.         source code, you could replace the "_VideoInt" routine in file
  6370.         "crtinit.cas" with an (inline) assembler equivalent that pushes
  6371.         BP on the stack instead of storing it into a static variable.
  6372.  
  6373.  
  6374.                                 The timer tick EOI
  6375.  
  6376.         To allow CTask to run concurrently with other background programs
  6377.         that  might steal the timer tick interrupt, and to enable high
  6378.         priority tasks to override timer ticks, the tick interrupt
  6379.         handler issues an EOI before calling the scheduler. Later, the
  6380.         tick  task will (possibly indirectly) call the original BIOS tick
  6381.         handler, which again issues an EOI for an interrupt that is no
  6382.         longer pending. Although this should practically not pose any
  6383.         problems, since no other interrupts could normally be pending at
  6384.         this  time, and the EOI is not stored, some experts believe it is
  6385.         theoretically possible for interrupts to be falsely acknowledged.
  6386.  
  6387.         However, according to the INTEL documentation of the 8259
  6388.         interrupt controller, the additional EOI can not cause any harm.
  6389.         What  the EOI does is to reset the highest priority ISR (Interrupt
  6390.         under Service Register) bit in the PIC. According to Intel's
  6391.         specs, it will never dismiss an interrupt that is not being
  6392.         serviced, since only the INTAK sequence will cause the ISR to be
  6393.         set in the first place. If there is an interrupt under service,
  6394.         the scheduler is not invoked, so the timer chain can't issue an
  6395.         EOI whilst in the middle of another interrupt.  So I think it's
  6396.         safe  to issue multiple EOIs, and I haven't had any adverse
  6397.         effects with INT8_LATE enabled, even while running serial comms
  6398.         with  19200 bps on a networked machine (which should generate a
  6399.         lot of INTs).
  6400.  
  6401.         If you experience problems in special applications anyway
  6402.         (especially if interrupt priorities have been reprogrammed), you
  6403.         may use the IFL_INT8_DIR installation flag. This flag changes the
  6404.         logic in the timer interrupt handler such that the original
  6405.         interrupt is called first, and no additional EOI is issued. You
  6406.         could also replace the timer-chaining logic with a routine that
  6407.         substitutes the BIOS timekeeping (use the BIOS listing as a
  6408.         reference). This, however, would preclude chaining to TSR's that
  6409.         have  hooked the timer tick.
  6410.         
  6411.         
  6412.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 107
  6413.  
  6414.  
  6415.                                     Debugging
  6416.  
  6417.         Debugging CTask programs can be surprising. The debugger can't
  6418.         know  about the task structure of your program, and you can easily
  6419.         sit and wonder for hours why the debugger is behaving so
  6420.         strangely until it finally sinks down: the debugger itself can be
  6421.         preempted.
  6422.  
  6423.         The keyboard and timer interrupts are the main culprits. Both can
  6424.         hit during execution of debugger routines, so that data may be
  6425.         different from what you expect it to be. For example, if you are
  6426.         tracing through code that reads or writes a global variable that
  6427.         is also modified by another task, you may find that this variable
  6428.         has a completely different value when you dump it from the value
  6429.         that  was just loaded into a register on the last instruction
  6430.         trace. If you are using Periscope, be sure to let Periscope
  6431.         restore the INT 8 and INT 9 entries. This is not exactly pleasant
  6432.         when  you're using a foreign keyboard, but it can avoid a lot of
  6433.         trouble. If you're debugging at the application level, those
  6434.         precautions may not be necessary, but if you want to trace into
  6435.         the kernel routines, you must be extremely careful not to trash
  6436.         the debugger.
  6437.  
  6438.  
  6439.  
  6440.  
  6441.  
  6442.  
  6443.  
  6444.  
  6445.  
  6446.  
  6447.  
  6448.  
  6449.  
  6450.  
  6451.  
  6452.  
  6453.  
  6454.  
  6455.  
  6456.  
  6457.  
  6458.  
  6459.  
  6460.  
  6461.  
  6462.  
  6463.  
  6464.  
  6465.  
  6466.  
  6467.  
  6468.         
  6469.         
  6470.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 108
  6471.  
  6472.  
  6473.                           Changes from Previous Versions
  6474.  
  6475.         When  upgrading from previous versions, you have to recompile all
  6476.         modules that use any CTask functions or data structures. Due to
  6477.         the changes in the control blocks, just re-linking is not
  6478.         sufficient.
  6479.  
  6480.                            Changes for CTask 2.1 to 2.2
  6481.  
  6482.         Version 2.2 mainly is a maintenance release. Several bugs, some
  6483.         of them severe, were introduced into 2.1 by a number of last-
  6484.         minute changes. Most bugs were reported by S. Worthington.
  6485.  
  6486.         Bugs  fixed include
  6487.  
  6488.            -  The Microsoft C 5.1 and 6.0 compilers generated incorrect
  6489.              code for the va_arg macro used to access the optional user
  6490.              parameter in the create_timer/watch/hotkey routines. The
  6491.              definition of the last parameter before the "..." as "byte"
  6492.              caused MSC to access an incorrect (odd) offset for the
  6493.              parameter. The "rept" parameter for the create_xxx calls has
  6494.              been redefined as "int" to circumvent this.
  6495.  
  6496.            -  Enabling the interrupts early in the scheduler could lead to
  6497.              race conditions if a task was made waiting, but then made
  6498.              runable before the scheduler had enqueued it. This could
  6499.              lead to unpredictable behaviour. The fix eliminates the race
  6500.              condition by enqueueing the task into the appropriate queue
  6501.              immediately, instead of waiting for the scheduler to do it.
  6502.  
  6503.            -  The keyboard handler installation caused problems with some
  6504.              older BIOSes, since it assumed too easily that an extended
  6505.              keyboard was present. This caused keyboard input to hang on
  6506.              some machines with non-extended keyboard BIOS. The check has
  6507.              now been made more robust.
  6508.  
  6509.            -  The hotkey detection logic would cause an immediate schedule
  6510.              if a hotkey match occurred, without checking for other
  6511.              active interrupts. This could lead to problems if the
  6512.              keyboard interrupt had interrupted another, timing critical,
  6513.              interrupt. The interrupt active check has been added.
  6514.  
  6515.            -  The "CALL_PASCAL" configuration option did not work. Half of
  6516.              the implementation was missing in the Assembler parts. This
  6517.              has been corrected, with Assembler routines using a slightly
  6518.              different procedure header, and different public/external
  6519.              pseudo-ops. Assembler routines now can be defined with
  6520.              Pascal calling sequence, and the test file "minres.asm" has
  6521.              been updated to use the new definitions.
  6522.  
  6523.  
  6524.  
  6525.  
  6526.         
  6527.         
  6528.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 109
  6529.  
  6530.  
  6531.            -  The TC_HUGE option would not work when given in the
  6532.              assembler command line only, without changing the LOAD_DS
  6533.              option. Also, the ctaskh.tc make-file had an incorrect
  6534.              dependency, causing the tskint17 module to be omitted from
  6535.              the assembly. Both errors have been corrected, you can again
  6536.              specify TC_HUGE without editing tskconf.h. The change also
  6537.              eliminates pass dependency warnings with Tasm 2.0.
  6538.  
  6539.            -  Some key definitions in "kbd.h" were incorrect, and some
  6540.              were missing. This has been corrected.
  6541.  
  6542.            -  The tsk_switch_stack routine used an incorrect DS in several
  6543.              places if the ROM_CODE option was defined TRUE. This has
  6544.              been fixed, the ROM_CODE option now works as expected.
  6545.  
  6546.            -  If a task waiting for a memory/port watch or hotkey was made
  6547.              runable by tsk_wake or a similar action, some locations in
  6548.              the next queue element or the queue header could be
  6549.              destroyed. The logic to identify timer elements has been
  6550.              changed to avoid this problem.
  6551.  
  6552.            -  Hotkeys, watches, timeout elements, and tickers created by a
  6553.              secondary invocation were not automatically removed on
  6554.              termination. This would lead to crashes is there was no
  6555.              explicit delete_xxx call. The elements are now chained,
  6556.              removal is automatic.
  6557.  
  6558.            -  Some routine prototypes were missing in tsk.h, and the
  6559.              add_event_name function was actually defined as add_name.
  6560.  
  6561.            -  The interface between the t_read_key and t_wait_key
  6562.              functions and the INT 16 handler in tskkbd.h was using the
  6563.              wrong DS, which would lead to crashes in secondary
  6564.              invocations. (Fixed in 2.1a)
  6565.  
  6566.            -  The "ticker" structure was defined differently in tsk.h and
  6567.              tsk.mac. This would cause problems for programs defining
  6568.              tickers in Assembler modules. (Fixed in 2.1b)
  6569.  
  6570.         Other changes:
  6571.  
  6572.         An optional "checking" mode has been implemented. If CHECKING is
  6573.         defined TRUE in tskconf.h, all task and event pointers are
  6574.         checked for validity on entry to task functions and other
  6575.         strategic points. Although some errors can still go undetected,
  6576.         most  memory overwrites or uninitialised pointers that would cause
  6577.         a catastrophic crash will now be caught, and the system will stop
  6578.         with  an error message before anything vital is destroyed. The
  6579.         checking also includes a task stack check, which is performed on
  6580.         every scheduler entry. The stack of a task is initialized to a
  6581.         defined pattern (0..FF repeated) on a create_task, and the
  6582.         scheduler checks for the pattern to be present in the bottom
  6583.         eight bytes of the current tasks stack. If this pattern was
  6584.         
  6585.         
  6586.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 110
  6587.  
  6588.  
  6589.         overwritten, the system is stopped. This feature can also be used
  6590.         to determine the maximum amount of stack actually used by a task.
  6591.         The tsksnap module will display the number of unused bytes of
  6592.         stack for all tasks if checking is enabled.
  6593.  
  6594.         The CLOCK_MSEC option, which allows all timeouts to be specified
  6595.         in milliseconds rather than timer ticks, has been changed to no
  6596.         longer require floating point support. The routine to convert
  6597.         milliseconds into ticks was provided by Chris Blum, who also
  6598.         supplied some fixes to other modules required to correctly handle
  6599.         the CLOCK_MSEC option.
  6600.  
  6601.         Timeout elements, watches, and hotkeys can now be created without
  6602.         being activated. Separate enable/disable routines are provided to
  6603.         avoid the overhead involved in creating and deleting elements
  6604.         when  switching hotkey-sets or watches.
  6605.  
  6606.         If multiple hotkey entries for the same key/flag combination were
  6607.         created, version 2.1 always activated the first entry entered.
  6608.         Version 2.2 will activate hotkeys in a round-robin fashion.
  6609.  
  6610.         The hotkey checking code now uses the keyboard intercept entry in
  6611.         INT 15 if the BIOS supports it. This should increase portability,
  6612.         since the routine no longer needs to access the keyboard hardware
  6613.         ports directly.
  6614.  
  6615.  
  6616.                           Version 2.2 Interface Changes
  6617.  
  6618.         New functions:
  6619.  
  6620.            create_timer_elem
  6621.            create_hotkey_elem
  6622.            create_memory_watch_elem
  6623.            create_port_watch_elem
  6624.  
  6625.               These routines are similar to the old-style create_xxx
  6626.               routines, but they do not activate the created element.
  6627.  
  6628.            enable_timer
  6629.            enable_watch
  6630.            enable_hotkey
  6631.  
  6632.               Enable timer/watch/hotkey elements
  6633.  
  6634.            disable timer
  6635.            disable_watch
  6636.            disable_hotkey
  6637.  
  6638.               Disable, i.e. temporarily suspend, timer/watch/hotkey
  6639.               elements. This is different from the delete_xxx calls,
  6640.               which will release dynamically allocated elements.
  6641.  
  6642.         
  6643.         
  6644.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 111
  6645.  
  6646.  
  6647.         Internal changes:
  6648.  
  6649.         The queue handling logic has been slightly changed to allow run-
  6650.         time  structure type checking. The queue head is no longer marked
  6651.         by a  zero "kind" field, bit 7 (define Q_HEAD) of this field is
  6652.         now set in a queue head instead. This should not interfere with
  6653.         your  programs unless you are traversing internal CTask queues
  6654.         yourself (for example in a modified tsksnap module).
  6655.  
  6656.         The structure and handling of timer/watch/hotkey elements has
  6657.         changed. The link kind now identifies the kind of the element
  6658.         itself, a new struckind field specifies the type of the structure
  6659.         "strucp" points to. The element state is no longer needed, the
  6660.         field was eliminated. To allow automatic removal on termination
  6661.         of a  secondary invocation, the elements are now chained.
  6662.  
  6663.  
  6664.                            Changes for CTask 2.0 to 2.1
  6665.  
  6666.         Several bugs were fixed. The fixes include
  6667.  
  6668.            -  Killing the current task could crash the system if the task
  6669.              had a dynamically allocated TCB and/or stack. A new "killer"
  6670.              task was introduced to free those blocks after scheduling is
  6671.              complete.
  6672.  
  6673.            -  Killing a task with a dynamically allocated stack would try
  6674.              to free an invalid pointer.
  6675.  
  6676.            -  Timers and watches with the TKIND_WAKE attribute ignored the
  6677.              repeat specification.
  6678.  
  6679.            -  Debugging CTask routines in single-step mode would sometimes
  6680.              unexpectedly step into interrupt handlers, because the Trap
  6681.              flag in the flag word on the interrupt stack would be
  6682.              restored inside the stack switch routine, long before
  6683.              exiting the handler.
  6684.  
  6685.            -  Timer/watch function calls were supposed to receive the user
  6686.              parameter when called. Actually, the address of the
  6687.              timer/watch control block is, and always was, passed. The
  6688.              documentation has been corrected.
  6689.  
  6690.            -  The INT 15 wait/post handler could be overrun by fast disk
  6691.              controllers, resulting in disk timeouts.
  6692.  
  6693.            -  When compiling for embedded systems, i.e. with GROUPS, DOS,
  6694.              and IBM disabled, some statements would not compile, since
  6695.              they referenced undefined field names.
  6696.  
  6697.            -  The prototype for c_schedule was missing.
  6698.  
  6699.  
  6700.         
  6701.         
  6702.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 112
  6703.  
  6704.  
  6705.            -  The resource for INT 10 could be released prematurely if the
  6706.              video routines used recursive calls. The request_cresource
  6707.              is now used to catch this.
  6708.  
  6709.         The routine get_priority now returns the initial, not the current
  6710.         priority. With variable priority enabled, saving and restoring
  6711.         the priority could lead to a tasks priority gradually increasing.
  6712.  
  6713.         The keyboard handler now supports the extended INT 16 functions.
  6714.         The t_read_key, t_wait_key, and t_keyhit routines use the
  6715.         extended functions if available. The timer interrupt now checks
  6716.         the BIOS keyboard buffer, and sets the key_avail flag to wake up
  6717.         tasks waiting for the keyboard. This supports keyboard stuffers
  6718.         putting characters directly into the buffer.
  6719.  
  6720.         The TURBOC and MSC defines caused conflicts with other libraries.
  6721.         They  were renamed to TSK_TURBOC and TSK_MSC.
  6722.  
  6723.         Resources, flags, counters, mailboxes, and pipes can now be
  6724.         initialized statically, i.e. at compile time. This eliminates the
  6725.         need  to call the create_xxx routine. The only restriction is that
  6726.         such  events are not automatically linked into the name chain. A
  6727.         new function, add_event_name, was created for this purpose.
  6728.  
  6729.         Version 2.1 introduces keyboard hotkeys, which are similar to the
  6730.         timer control blocks and the memory/port watches. Keyboard
  6731.         hotkeys are trapped in the keyboard interrupt handler, and can
  6732.         activate tasks or functions, or set flags, whenever a particular
  6733.         key/shift-key combination is hit.
  6734.  
  6735.         Timer control blocks, watchpoints, and keyboard hotkeys can now
  6736.         specify counter decrementing in addition to counter incrementing.
  6737.         A dec_counter function was added to explicitly decrement a
  6738.         counter.
  6739.  
  6740.         Support for EMS and 80x87 numeric coprocessors was added. The EMS
  6741.         support saves and restores the EMS page map state on every task
  6742.         switch to avoid problems with resident utilities, especially EMS-
  6743.         based disk cachers. The 80x87 support saves and restores the
  6744.         state of the coprocessor on a task switch.
  6745.  
  6746.         The scheduler module was revisited, and interrupts are now
  6747.         enabled most of the time. This should help to reduce interrupt
  6748.         latency. In this context, checks for operations which are illegal
  6749.         in interrupt handlers (task wait, kill current task) were added
  6750.         to help diagnosing problems. Previous versions would usually
  6751.         crash silently in those situations. The task switch save/restore
  6752.         functions are now entered with interrupts enabled, and with DS
  6753.         set to the data segment of the active task control block.
  6754.  
  6755.         A replacement printf module was added. This assembler printf
  6756.         replacement is faster than the standard C printf, and is not
  6757.         model dependent. It can also output to the secondary screen in a
  6758.         
  6759.         
  6760.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 113
  6761.  
  6762.  
  6763.         dual-monitor system. This printf is used in the tsksnap module,
  6764.         which is now model independent except for the snapshot() routine,
  6765.         which uses two C runtime routines (flush and fileno). tsksnap
  6766.         also  was fixed to work with small model (some pointers had to be
  6767.         explicitly forced to FAR). Some calls to the snapshot dump
  6768.         routines now need different parameters.
  6769.  
  6770.         A debugging mode provides real-time active task display, and on-
  6771.         screen counters for the scheduler, plus counters for timer and
  6772.         keyboard interrupts and internal interrupt stack usage. The
  6773.         precompiled libraries do not provide debugging, you will have to
  6774.         recompile with the DEBUG option in tskdeb.h changed.
  6775.  
  6776.         The attributes for internal and external functions are now
  6777.         #defined, and can thus easily be changed. This should ease
  6778.         porting to other compilers that require different keywords. Also,
  6779.         the attributes can now be defined for near code, allowing all
  6780.         CTask functions to be compiled in small model if desired. Data
  6781.         pointers still have to be far. All calls from Assembler routines
  6782.         have  been converted to macro calls, to allow customizing the
  6783.         calling sequence. Several customization options have been added
  6784.         to better support code-sharing and mixed model compilation and
  6785.         assembly.
  6786.  
  6787.         Secondary kernels now can share the CTask code with the primary
  6788.         invocation. A jump-table linking external modules to installed
  6789.         CTask code can be created, so that foreground programs
  6790.         communicating with background CTask TSRs do not have to link in
  6791.         the full CTask kernel code. A new function, "link_ctask", has
  6792.         been  added to check for code sharing installed in a primary
  6793.         kernel. Several changes were necessary to allow access to
  6794.         functions and variables local to a group from shared code. The
  6795.         change also allows applications to call CTask functions from a
  6796.         primary kernel without installing their own secondary kernel.
  6797.  
  6798.         The mechanism for removing interrupt handlers upon group/kernel
  6799.         termination was generalized. Previously, only two "remove"
  6800.         routines (for the SIO and printer handlers) could be set. Version
  6801.         2.1 introduces the "chain_removefunc" and "unchain_removefunc"
  6802.         functions to allow multiple clean-up routines.
  6803.  
  6804.         Some  modules were split up, and IFDEF's added to TSKMAIN to allow
  6805.         "secondary-only" programs. This change is intended for programs
  6806.         that  communicate with a background copy of CTask, and don't
  6807.         intend to install the Kernel if that background copy does not
  6808.         exist. The make-files create a "secondary" tskmain,
  6809.         "stskmain.obj", which is not included in the library. Linking
  6810.         with  this stripped-down TSKMAIN saves 6-7k of program code.
  6811.  
  6812.         A few other modules also were split up, and routines were
  6813.         shuffled around, to avoid linking unreferenced routines. The
  6814.         tsk.h and tsklocal.h files were amended to include the module
  6815.         name  defining the routine to make it easier to locate routines.
  6816.         
  6817.         
  6818.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 114
  6819.  
  6820.  
  6821.         Name  pointers for tasks and structures may now be NULL.
  6822.         Structures with NULL name pointers are not linked into the name
  6823.         chain. This is useful for applications linking into CTask without
  6824.         creating their own task group.
  6825.  
  6826.         Name  parameters are now specified using the #defined macro "TN".
  6827.         This  eliminates the need for explicit #if statements on each and
  6828.         every name parameter. This change makes the code a lot more
  6829.         readable.
  6830.  
  6831.         Minor changes, mostly type-casts, were done in several modules to
  6832.         eliminate compiler warnings.
  6833.  
  6834.         The make-files for the support routines were changed to add the
  6835.         model-letter to the filename for both object and library files.
  6836.         This  avoids confusion when you use more than one model. The
  6837.         Turbo-Make files for the support routines and the sample
  6838.         applications were updated to allow model modification from the
  6839.         command line. The special ctsuph.tc make-file is no longer
  6840.         needed.
  6841.  
  6842.                           Version 2.1 Interface Changes
  6843.  
  6844.         The interface to the global kernel functions has not changed in
  6845.         version 2.1. Note, however, that the v24_remove_func and
  6846.         prt_remove_func entries have been replaced by the new remove
  6847.         chaining, so this will require changes if you used one of those
  6848.         entries to enter your own remove processing.
  6849.  
  6850.         The global variable "ticks_per_sec" was moved to the global
  6851.         variable block. Since this variable is no longer directly
  6852.         accessible, the "ticks_per_sec" function was added.
  6853.  
  6854.         If you were using task save/restore routines, or timer/watch
  6855.         functions, please note the different handling of DS. DS is now
  6856.         set to the data segment of the associated control block, which
  6857.         normally, but not always, is equal to the segment created by the
  6858.         file  the block was defined in. See the "Advanced topics" chapter
  6859.         in the manual for more information.
  6860.  
  6861.         For timer/watch/hotkey functions, the parameter passed is a
  6862.         pointer to the timer element, not the user parameter, as
  6863.         erroneously specified in previous versions of the manual.
  6864.         Interrupts are enabled on entry to all functions, including task
  6865.         save/restore functions.
  6866.  
  6867.         The "screensnap" function in the support module "tsksnap.c" was
  6868.         changed. Previously, you had to specify the screen buffer address
  6869.         and dimensions with the call to screensnap.  The new version
  6870.         requires initialising the screen driver with a call to
  6871.         tsk_set_regen or tsk_set_dualdis before calling screensnap, which
  6872.         now only accepts a screen length parameter. The function
  6873.         "csnapshot" has been added to output to the screen using standard
  6874.         
  6875.         
  6876.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 115
  6877.  
  6878.  
  6879.         INT 10 calls. The "snapshot" function still takes a FILE *
  6880.         parameter, but should preferably no longer be used to output the
  6881.         snapshot dump to the screen, since it is significantly slower,
  6882.         and requires DOS access. It should only be used to write the dump
  6883.         to a  file or a different device.
  6884.  
  6885.  
  6886.                            Changes for CTask 1.2 to 2.0
  6887.  
  6888.         CTask 2.0 unifies the queue concept, and uses doubly-linked lists
  6889.         for all queues, including the task and timer queues. Although the
  6890.         overhead is slightly higher when inserting elements, the overall
  6891.         logic is greatly simplified, and removing elements from arbitrary
  6892.         points in a queue is a snap. To avoid a timing penalty for the
  6893.         new functionality, all low-level queue handling code was
  6894.         implemented in assembler.
  6895.  
  6896.         The new concept allows better support for the yield() operation,
  6897.         and it also allows an improved handling of timeout elements. With
  6898.         the 1.1/1.2 algorithm, it was not completely safe to process the
  6899.         timeout queue with interrupts enabled, and changes to the queue
  6900.         required great care. The new handling of the timeout queue, which
  6901.         is now sorted, and stores the tick difference to the previous
  6902.         element instead of an absolute count, decreases the amount of
  6903.         time  spent in the timeout loop. Watch elements, which still
  6904.         require stepping through all queue elements, have been separated
  6905.         from  timeouts. While the processing of the queue still has to be
  6906.         done  with interrupts disabled, the timeout/watch action now is
  6907.         completely uncritical.
  6908.  
  6909.         The changes to the queue structures required changes in nearly
  6910.         all modules. The main changes were in the tsksub, tsktimer, and
  6911.         tskasm modules, the tskque module was added.
  6912.  
  6913.         Minor corrections were added 89-12-29 to fix a bug in
  6914.         tsk_remove_int17 (file TSKINT17.ASM), and minor typos in the
  6915.         documentation. The documentation was again fixed 90-01-02, and a
  6916.         warning about TASM 1.0 incompatibilities was added to READ.ME.
  6917.  
  6918.  
  6919.                           Version 2.0 Interface Changes
  6920.  
  6921.         Version 2.0 introduces some changes in the interface. Since the
  6922.         changes only affect installation and previously unavailable
  6923.         functions, the impact on your programs should be minimal. If
  6924.         you're using a 1.2 pre-release, watch out for the changes in the
  6925.         name  search and ticker functions. The affected routines are
  6926.  
  6927.                 install_tasker
  6928.                         Two new parameters added. Late 1.2 pre-releases
  6929.                         implemented but ignored the "flags" parameter,
  6930.                         and recommended setting it to zero. This is no
  6931.                         longer true.
  6932.         
  6933.         
  6934.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 116
  6935.  
  6936.  
  6937.                 ctask_resident
  6938.                         New routine to check if CTask is already
  6939.                         resident.
  6940.  
  6941.                 find_name
  6942.                         Name changed from tsk_find_name, values for
  6943.                         "kind" parameter changed.
  6944.  
  6945.                 find_group_name
  6946.                         New routine for 1.1, in 1.2 this was called
  6947.                         tsk_find_group_name. Searches names within a
  6948.                         group. The "kind" parameter values changed.
  6949.  
  6950.                 yield
  6951.                         New routine, schedules with minimal priority.
  6952.                         Version 1.2 also had this, but using it could
  6953.                         lead to task starvation under certain conditions.
  6954.  
  6955.                 get_priority
  6956.                 set_funcs
  6957.                 set_user_ptr
  6958.                 get_user_ptr
  6959.                         New routines to access fields in the TCB.
  6960.  
  6961.                 create_ticker
  6962.                 delete_ticker
  6963.                 set_ticker
  6964.                 get_ticker
  6965.                         New routines for a simplistic time counter. Late
  6966.                         versions of 1.2 had similar functions with
  6967.                         different names, and different parameters.
  6968.  
  6969.                 create_timer
  6970.                         New optional parameter.
  6971.  
  6972.                 create_memory_watch
  6973.                 create_port_watch
  6974.                         New routines to create memory/port watch entries.
  6975.                         Some pre-release versions of 1.2 don't support
  6976.                         the last, optional, user pointer parameter.
  6977.  
  6978.                 wait_memory
  6979.                 wait_port
  6980.                         New routines to wait for memory/port changes.
  6981.  
  6982.                 delete_watch
  6983.                         New routine to delete watch element. Pre-release
  6984.                         versions of 1.2 equated this to delete_timer,
  6985.                         version 2.0 requires delete_watch to be
  6986.                         different.
  6987.  
  6988.                 set_counter
  6989.                         New routine to set counter to given value.
  6990.         
  6991.         
  6992.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 117
  6993.  
  6994.  
  6995.                 v24_flush_transmit
  6996.                         New routine in serial handler to flush transmit
  6997.                         pipe.
  6998.  
  6999.                 prt_flush
  7000.                         New routine in printer handler to flush output
  7001.                         pipe.
  7002.  
  7003.  
  7004.                 timout functions
  7005.                         The timeout function now is passed a parameter,
  7006.                         and is called with interrupts enabled.
  7007.  
  7008.                 assembler interface
  7009.                         All entry points now start with the usual
  7010.                         underline, since the extended language-specific
  7011.                         procedure definitions are used. The "scheduler"
  7012.                         entry was renamed to _tsk_scheduler to avoid
  7013.                         catastrophic results of typos.
  7014.  
  7015.                 internal functions
  7016.                         Previous versions defined most internal CTask
  7017.                         functions as far. This allowed calling them from
  7018.                         outside the CTask kernel (although that was never
  7019.                         recommended). The new version no longer allows
  7020.                         this, since internal functions are near relative
  7021.                         to the common CTask code segment.
  7022.  
  7023.  
  7024.                           Changes for CTask 1.1b to 1.2
  7025.  
  7026.         The never released version 1.2 added the concept of task groups,
  7027.         and the save/restore of internal DOS variables, to support
  7028.         spawning and TSR'ing CTask programs. The TSKDOS module went
  7029.         through several changes in the pre-release copies.
  7030.  
  7031.         All relevant global variables of CTask were grouped into a single
  7032.         structure, and are indirectly accessed through a pointer. This
  7033.         allows linkage between multiple copies of CTask, with automatic
  7034.         detection of other copies.
  7035.  
  7036.         This  change required adding new structures, and changing the task
  7037.         control block to accommodate the new group linkage and the space
  7038.         for the DOS variable swap.
  7039.  
  7040.         Also  new in 1.2 was the addition of a stack switch on entry to
  7041.         all interrupt handlers. This change was required to eliminate
  7042.         problems with TSR's, especially networks, and to support spawned
  7043.         programs that supply only a minimal amount of stack. CTask now
  7044.         allocates local stacks from a stack pool to hardware and software
  7045.         interrupt handlers. On entry to the scheduler, the task registers
  7046.         are no longer pushed on the stack, but instead are stored in the
  7047.         task  control block. This again mandated a change to the TCB.
  7048.         
  7049.         
  7050.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 118
  7051.  
  7052.  
  7053.         Support for memory and port watches that check the state of a
  7054.         memory location or an I/O port on every tick was added.
  7055.  
  7056.         A "ticker" structure that allows simple timeouts in polling tasks
  7057.         was introduced.
  7058.  
  7059.         Task  switch save/restore functions were added.
  7060.  
  7061.         The printer output driver was reworked, an an INT 17 interface
  7062.         driver has been added. The INT 15 printer output support was
  7063.         dropped.
  7064.  
  7065.         Resources to protect concurrent access to INT 10 and INT 13 were
  7066.         added in the TSKDOS module.
  7067.  
  7068.         The timer tick interrupt now supports both early and late INT 8
  7069.         chaining (and the INT9 stuff has finally been renamed to INT8).
  7070.         This  change was required to support network software that would
  7071.         time  out without really having waited long enough if the INT 8
  7072.         task  was postponed, and ticked a number of ticks at once. It can
  7073.         also  avoid incompatibilities with other software that does
  7074.         strange things in the timer interrupt. Installation of the new
  7075.         INT 8 handling is optional.
  7076.  
  7077.         Installation flags now allow on-line customization of some
  7078.         functions, especially the installation of some of the BIOS
  7079.         interrupts, and the INT 8 algorithm.
  7080.  
  7081.         The name-searching functions were augmented to better support
  7082.         searching local to groups, and searching groups.
  7083.  
  7084.         The make-files were cleaned up, and the Turbo C make-files
  7085.         changed to work with Borland's make.
  7086.  
  7087.         Support for the Turbo C Huge model was added, assembler files now
  7088.         load  the DS register when necessary.
  7089.  
  7090.         The placement of external definitions in the assembler files was
  7091.         changed to avoid the fixup errors that appeared when assembling
  7092.         with  TASM instead of MASM (thanks for H.J. Haug for pointing this
  7093.         out).
  7094.  
  7095.         All CTask routines are now allocated in a common code segment.
  7096.         This  allows calling local functions with a near call.
  7097.  
  7098.         All files were polished a bit, with a version number and change
  7099.         date  at the top. Comments have again been added. No warnings
  7100.         remain for Turbo and Microsoft with all warnings enabled.
  7101.  
  7102.         All files were affected, and some new files were added.
  7103.  
  7104.  
  7105.  
  7106.         
  7107.         
  7108.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 119
  7109.  
  7110.  
  7111.                           Changes for CTask 1.1 to 1.1b
  7112.  
  7113.         Release 1.1b fixed a minor bug in tskmain.c which prevented the
  7114.         main  task from being delayed. Thanks to Kent J. Quirk for
  7115.         reporting the bug.
  7116.  
  7117.         Release 1.1a was necessary to fix three severe and some minor
  7118.         bugs  in release 1.1. The bugs corrected in 1.1a were
  7119.  
  7120.            -  tskasm.asm:  Interrupts enabled too early in the scheduler
  7121.            -  tskdos.asm:  Registers swapped in DOS version test
  7122.            -  tsksio.c:    Incorrect loop variable in v24_sio_initialise
  7123.            -  tskmain.c:   Function tsk_dis_preempt missing
  7124.            -  tsksnap.c:   Incorrect format specification for continuation
  7125.                           line
  7126.            -  tskasm.asm:  Task state incorrect for eligible tasks
  7127.  
  7128.         Also  some minor changes to eliminate warnings, and changes to the
  7129.         test  files so they no longer use concurrent console output.
  7130.  
  7131.         A console output task was added ("conout.c" and "conout.h") as a
  7132.         sample for channeling console output through a single task.
  7133.  
  7134.         Some  changes suggested by Stephen Worthington were incorporated
  7135.         (pipe flush functions, better SIO transmit interrupt handling).
  7136.  
  7137.         Thanks to Peter Heinrich, Stephen Worthington, and Burt Bicksler
  7138.         for reporting the bugs.
  7139.  
  7140.  
  7141.                            Changes for CTask 0.1 to 1.1
  7142.  
  7143.         Thanks to Peter Heinrich, Tron Hvaring, and Dave Goodwin for
  7144.         their suggestions and the bug reports.
  7145.  
  7146.         The main changes, apart from bug fixes, were
  7147.  
  7148.            -  Support for named control blocks
  7149.            -  Support for dynamic allocation of control blocks and
  7150.              buffers
  7151.            -  Task state display support (snapshot dump)
  7152.            -  More flexible timer handling, interrupt disable times
  7153.              reduced
  7154.            -  SIO support extended for shared IRQ's and on-line
  7155.              definition of ports; save and restore of control
  7156.              registers
  7157.  
  7158.  
  7159.  
  7160.  
  7161.  
  7162.  
  7163.  
  7164.         
  7165.         
  7166.         Ctask Manual       - Version 2.2 - 90-10-12 -            Page 120
  7167.  
  7168.  
  7169.                                       Index
  7170.  
  7171.  
  7172.            add_event_name                     58
  7173.            alloc_resource                     96
  7174.            AT_BIOS                            19
  7175.            BIOS                               25
  7176.            buffer                             52
  7177.            bufferptr                          52
  7178.            byte                               36
  7179.            byteptr                            36
  7180.            CALL_PASCAL                        16
  7181.            chain_removefunc                   58
  7182.            change_timer                       68
  7183.            CHECKING                           20
  7184.            check_buffer                       87
  7185.            check_counter                      81
  7186.            check_flag                         79
  7187.            check_mailbox                      83
  7188.            check_pipe                         85
  7189.            check_resource                     77
  7190.            check_wpipe                        85
  7191.            clear_counter                      80
  7192.            clear_flag                         78
  7193.            clear_flag_wait_set                79
  7194.            CLOCK_MSEC                         18
  7195.            CLOCK_MSEC                         64
  7196.            code sharing                      102
  7197.            code sharing                      103
  7198.            CODE_SHARING                       15
  7199.            CODE_SHARING                      102
  7200.            console                            25
  7201.            counter                            50
  7202.            counterptr                         50
  7203.            create_buffer                      86
  7204.            create_counter                     79
  7205.            create_flag                        77
  7206.            create_hotkey_elem                 72
  7207.            create_hotkey_entry                74
  7208.            create_mailbox                     82
  7209.            create_memory_watch                69
  7210.            create_memory_watch_elem           68
  7211.            create_pipe                        83
  7212.            create_port_watch                  71
  7213.            create_port_watch_elem             70
  7214.            create_resource                    75
  7215.            create_task                        62
  7216.            create_ticker                      65
  7217.            create_timer                       67
  7218.            create_timer_elem                  67
  7219.            create_wpipe                       83
  7220.            CRITICAL                           61
  7221.            ctask_active                       54
  7222.              
  7223.              
  7224.              Ctask Manual     - Version 2.2 - 90-10-12 -          Index 1
  7225.  
  7226.  
  7227.            ctask_resident                     56
  7228.            ctask_resident                    102
  7229.            curr_task                          64
  7230.            C_ENTER                            61
  7231.            C_LEAVE                            61
  7232.            c_read_buffer                      87
  7233.            c_read_pipe                        84
  7234.            c_read_wpipe                       84
  7235.            c_request_resource                 77
  7236.            c_schedule                         60
  7237.            c_wait_mail                        83
  7238.            c_write_buffer                     87
  7239.            c_write_pipe                       85
  7240.            c_write_wpipe                      85
  7241.            dec_counter                        81
  7242.            DEF_COUNTER                        80
  7243.            DEF_FLAG                           78
  7244.            DEF_MAILBOX                        82
  7245.            DEF_PIPE                           84
  7246.            DEF_RESOURCE                       76
  7247.            DEF_WPIPE                          84
  7248.            DEF_xxx                            36
  7249.            delete_buffer                      86
  7250.            delete_counter                     80
  7251.            delete_flag                        78
  7252.            delete_hotkey                      74
  7253.            delete_mailbox                     82
  7254.            delete_pipe                        84
  7255.            delete_resource                    76
  7256.            delete_ticker                      65
  7257.            delete_timer                       68
  7258.            delete_watch                       72
  7259.            delete_wpipe                       84
  7260.            disable_hotkey                     74
  7261.            disable_timer                      68
  7262.            disable_watch                      72
  7263.            DOS                                19
  7264.            DOS                                25
  7265.            DOS                               103
  7266.            dword                              36
  7267.            EMS                                20
  7268.            EMS                               103
  7269.            EMS_SAVE_SIZE                      20
  7270.            enable_hotkey                      74
  7271.            enable_timer                       68
  7272.            enable_watch                       72
  7273.            entry table                       102
  7274.            farptr                             36
  7275.            FAR_STACK                          17
  7276.            find_group_name                    58
  7277.            find_name                          57
  7278.            flag                               50
  7279.            flagptr                            50
  7280.              
  7281.              
  7282.              Ctask Manual     - Version 2.2 - 90-10-12 -          Index 2
  7283.  
  7284.  
  7285.            flush_pipe                         85
  7286.            flush_wpipe                        85
  7287.            funcptr                            36
  7288.            funcptr_dword                      36
  7289.            funcptr_int                        36
  7290.            funcptr_void                       36
  7291.            F_CRIT                             48
  7292.            F_STTEMP                           47
  7293.            F_TEMP                             47
  7294.            F_USES_NDP                         48
  7295.            GEN_JTAB                          102
  7296.            get_priority                       63
  7297.            get_ticker                         65
  7298.            get_user_ptr                       64
  7299.            group control block               101
  7300.            GROUPS                             18
  7301.            GROUPS                            103
  7302.            group_rec                          49
  7303.            Hotkey functions                  105
  7304.            HOTKEYS                            20
  7305.            HOTKEYS                           103
  7306.            IBM                                19
  7307.            IBM                               103
  7308.            IFL_DISK                           55
  7309.            IFL_INT15                          56
  7310.            IFL_INT8_DIR                       55
  7311.            IFL_NODOSVARS                      56
  7312.            IFL_NOEXITCHECK                    56
  7313.            IFL_PRINTER                        56
  7314.            IFL_VIDEO                          55
  7315.            inc_counter                        81
  7316.            installation flags                 55
  7317.            install_tasker                     54
  7318.            INT8_EARLY                         19
  7319.            INT8_LATE                          19
  7320.            intprocptr                         36
  7321.            kbflag                             42
  7322.            keyboard                           25
  7323.            kill_task                          62
  7324.            link_ctask                         57
  7325.            link_ctask                        103
  7326.            LNULL                              35
  7327.            LOAD_DS                            16
  7328.            LOAD_DS                           102
  7329.            LOCALS_FAR                         16
  7330.            mailbox                            51
  7331.            mailboxptr                         51
  7332.            msgptr                             51
  7333.            msg_header                         51
  7334.            NAMELENGTH                         43
  7335.            nameptr                            43
  7336.            namerec                            43
  7337.            NDP                                20
  7338.              
  7339.              
  7340.              Ctask Manual     - Version 2.2 - 90-10-12 -          Index 3
  7341.  
  7342.  
  7343.            NDP                               103
  7344.            NEAR_CODE                          16
  7345.            NEAR_CODE                         103
  7346.            pipe                               52
  7347.            pipeptr                            52
  7348.            pipe_free                          85
  7349.            preempt_off                        59
  7350.            preempt_on                         59
  7351.            primary                           101
  7352.            primary kernel                    101
  7353.            PRI_INT8                           19
  7354.            PRI_STD                            18
  7355.            PRI_TIMER                          18
  7356.            prt_change_control                 95
  7357.            prt_complete                       95
  7358.            prt_flush                          95
  7359.            prt_install                        94
  7360.            prt_remove                         94
  7361.            prt_remove_all                     95
  7362.            prt_status                         95
  7363.            prt_wait_complete                  95
  7364.            prt_write                          95
  7365.            qelem_pri                          37
  7366.            queheadptr                         38
  7367.            queptr                             37
  7368.            queue                              38
  7369.            queue_head                         38
  7370.            read_buffer                        87
  7371.            read_pipe                          84
  7372.            read_wpipe                         84
  7373.            release_resource                   76
  7374.            remove function                   105
  7375.            remove routine                     59
  7376.            remove_tasker                      56
  7377.            request_cresource                  77
  7378.            request_resource                   76
  7379.            resource                           51
  7380.            resourceptr                        51
  7381.            restore function                   44
  7382.            restore function                  105
  7383.            ROM_CODE                           17
  7384.            save function                      44
  7385.            save function                     105
  7386.            schedule                           60
  7387.            sched_int                          60
  7388.            secondary                         101
  7389.            SECONDARY                         102
  7390.            secondary kernel                  101
  7391.            send_mail                          82
  7392.            set_counter                        81
  7393.            set_flag                           78
  7394.            set_funcs                          64
  7395.            set_priority                       63
  7396.              
  7397.              
  7398.              Ctask Manual     - Version 2.2 - 90-10-12 -          Index 4
  7399.  
  7400.  
  7401.            set_task_flags                     63
  7402.            set_ticker                         65
  7403.            set_user_ptr                       64
  7404.            SINGLE_DATA                        20
  7405.            spawn                              26
  7406.            start_task                         62
  7407.            stop_task                          63
  7408.            stub table                        102
  7409.            ST_DELAYED                         46
  7410.            ST_ELIGIBLE                        46
  7411.            ST_KILLED                          46
  7412.            ST_RUNNING                         46
  7413.            ST_STOPPED                         46
  7414.            ST_WAITING                         46
  7415.            tcb                                46
  7416.            tcbptr                             45
  7417.            tcb_rec                            45
  7418.            TCMP_CHG                           40
  7419.            TCMP_EQ                            40
  7420.            TCMP_GE                            40
  7421.            TCMP_GES                           40
  7422.            TCMP_LE                            40
  7423.            TCMP_LES                           40
  7424.            TCMP_NE                            40
  7425.            TC_HUGE                            16
  7426.            TC_HUGE                           102
  7427.            TELEM_HOTKEY                       40
  7428.            telem_hotkey                       42
  7429.            TELEM_MEM                          39
  7430.            telem_memwatch                     42
  7431.            TELEM_PORT                         39
  7432.            telem_portwatch                    42
  7433.            telem_timeout                      42
  7434.            TELEM_TIMER                        39
  7435.            TFLAG_BUSY                         41
  7436.            TFLAG_ENQUEUE                      41
  7437.            TFLAG_REMOVE                       41
  7438.            TFLAG_REPEAT                       41
  7439.            TFLAG_TEMP                         41
  7440.            TFLAG_UNQUEUE                      41
  7441.            TFP_OFF                            35
  7442.            TFP_SEG                            35
  7443.            ticker                             50
  7444.            ticker                             65
  7445.            ticks_per_sec                      64
  7446.            tick_ptr                           50
  7447.            TIMEOUT                            37
  7448.            Timeout/watch functions           105
  7449.            Timeouts                           64
  7450.            TKIND_COUNTDEC                     39
  7451.            TKIND_COUNTER                      39
  7452.            TKIND_FLAG                         39
  7453.            TKIND_PROC                         39
  7454.              
  7455.              
  7456.              Ctask Manual     - Version 2.2 - 90-10-12 -          Index 5
  7457.  
  7458.  
  7459.            TKIND_TASK                         39
  7460.            TKIND_WAKE                         39
  7461.            tlink                              42
  7462.            tlinkptr                           42
  7463.            TMK_FP                             35
  7464.            TN                                 36
  7465.            tsk_alloc                          96
  7466.            tsk_calloc                         96
  7467.            tsk_cli                            61
  7468.            tsk_disport                        99
  7469.            tsk_dis_int                        60
  7470.            tsk_dis_preempt                    59
  7471.            TSK_DYNAMIC                        17
  7472.            TSK_DYNAMIC                       103
  7473.            TSK_DYNLOAD                        17
  7474.            tsk_ena_int                        61
  7475.            tsk_ena_preempt                    59
  7476.            tsk_fprintf                        97
  7477.            tsk_free                           96
  7478.            tsk_inp                            61
  7479.            TSK_NAMED                          18
  7480.            TSK_NAMED                         103
  7481.            TSK_NAMEPAR                        17
  7482.            TSK_OFFSETOF                       35
  7483.            tsk_outp                           61
  7484.            tsk_printf                         97
  7485.            tsk_putc                           97
  7486.            tsk_puts                           98
  7487.            tsk_realloc                        96
  7488.            tsk_regen                          99
  7489.            tsk_regen_o                        99
  7490.            tsk_regen_s                        99
  7491.            tsk_rprintf                        97
  7492.            tsk_rputc                          98
  7493.            tsk_rputs                          98
  7494.            tsk_scheduler                      60
  7495.            tsk_setpos                         99
  7496.            tsk_set_attr                       99
  7497.            tsk_set_colour                     98
  7498.            tsk_set_currdis                    98
  7499.            tsk_set_dualdis                    98
  7500.            tsk_set_mono                       98
  7501.            tsk_set_regen                      99
  7502.            tsk_sprintf                        97
  7503.            tsk_sti                            61
  7504.            TSK_STRUCTOP                       35
  7505.            tsk_use_ndp                        54
  7506.            tsk_vfprintf                       97
  7507.            tsk_vprintf                        97
  7508.            tsk_vrprintf                       97
  7509.            tsk_vsprintf                       97
  7510.            TSR                                26
  7511.            TTIMEOUT                           37
  7512.              
  7513.              
  7514.              Ctask Manual     - Version 2.2 - 90-10-12 -          Index 6
  7515.  
  7516.  
  7517.            TWAKE                              37
  7518.            TWATCH                             37
  7519.            TYP_BUFFER                         43
  7520.            TYP_COUNTER                        43
  7521.            TYP_FLAG                           43
  7522.            TYP_GROUP                          43
  7523.            TYP_HOTKEY                         43
  7524.            TYP_MAILBOX                        43
  7525.            TYP_PIPE                           43
  7526.            TYP_RESOURCE                       43
  7527.            TYP_TCB                            43
  7528.            TYP_TIMER                          43
  7529.            TYP_WATCH                          43
  7530.            TYP_WPIPE                          43
  7531.            t_delay                            66
  7532.            t_keyhit                           88
  7533.            t_read_key                         88
  7534.            t_wait_key                         88
  7535.            unchain_removefunc                 59
  7536.            user pointer                       44
  7537.            v24_change_baud                    90
  7538.            v24_change_dtr                     90
  7539.            v24_change_parity                  91
  7540.            v24_change_rts                     90
  7541.            v24_change_stopbits                91
  7542.            v24_change_wordlength              91
  7543.            v24_check                          92
  7544.            v24_complete                       93
  7545.            v24_define_port                    88
  7546.            v24_flush_receive                  93
  7547.            v24_flush_transmit                 93
  7548.            v24_install                        89
  7549.            v24_modem_status                   93
  7550.            v24_overrun                        93
  7551.            v24_protocol                       92
  7552.            v24_receive                        92
  7553.            v24_remove                         90
  7554.            v24_remove_all                     90
  7555.            v24_send                           92
  7556.            v24_wait_complete                  93
  7557.            v24_watch_modem                    91
  7558.            wait_counter_clear                 80
  7559.            wait_counter_set                   80
  7560.            wait_flag_clear                    78
  7561.            wait_flag_set                      78
  7562.            wait_hotkey                        74
  7563.            wait_mail                          82
  7564.            wait_memory                        70
  7565.            wait_pipe_empty                    85
  7566.            wait_port                          72
  7567.            wait_wpipe_empty                   85
  7568.            WAKE                               37
  7569.            wake_task                          63
  7570.              
  7571.              
  7572.              Ctask Manual     - Version 2.2 - 90-10-12 -          Index 7
  7573.  
  7574.  
  7575.            WATCH                              37
  7576.            word                               36
  7577.            wordptr                            36
  7578.            wpipe                              52
  7579.            wpipeptr                           52
  7580.            wpipe_free                         85
  7581.            write_buffer                       87
  7582.            write_pipe                         85
  7583.            write_wpipe                        85
  7584.            yield                              60
  7585.  
  7586.  
  7587.  
  7588.  
  7589.  
  7590.  
  7591.  
  7592.  
  7593.  
  7594.  
  7595.  
  7596.  
  7597.  
  7598.  
  7599.  
  7600.  
  7601.  
  7602.  
  7603.  
  7604.  
  7605.  
  7606.  
  7607.  
  7608.  
  7609.  
  7610.  
  7611.  
  7612.  
  7613.  
  7614.  
  7615.  
  7616.  
  7617.  
  7618.  
  7619.  
  7620.  
  7621.  
  7622.  
  7623.  
  7624.  
  7625.  
  7626.  
  7627.  
  7628.              
  7629.              
  7630.              Ctask Manual     - Version 2.2 - 90-10-12 -          Index 8
  7631.