home *** CD-ROM | disk | FTP | other *** search
/ Frostbyte's 1980s DOS Shareware Collection / floppyshareware.zip / floppyshareware / DOOG / CTASK.ZIP / TSKDOS.ASM < prev    next >
Assembly Source File  |  1989-12-22  |  32KB  |  1,576 lines

  1. ;
  2. ;    --- Version 2.0 89-12-13 17:57 ---
  3. ;
  4. ;    CTask - DOS access module.
  5. ;
  6. ;    Public Domain Software written by
  7. ;        Thomas Wagner
  8. ;        Patschkauer Weg 31
  9. ;        D-1000 Berlin 33
  10. ;        West Germany
  11. ;
  12. ;
  13. ; The DOS interrupt (and the related direct disk I/O interrupts) are
  14. ; not reentrant. Access to DOS thus has to be channelled such that no
  15. ; two tasks use DOS services simultaneously. However, there is one
  16. ; exception to this rule. Whenever DOS is waiting for the keyboard, it
  17. ; issues a special interrupt, INT 28h, to signal that background
  18. ; processing for functions > 0Ch may be performed. This is used in the
  19. ; DOS interface for CTask in the following manner:
  20. ;
  21. ;   A task issuing a DOS interrupt will request one of two resources:
  22. ;   "lower_dos" for functions <= 0C, "upper_dos" for functions > 0C.
  23. ;   If a task gets access to "lower_dos", it will also request the
  24. ;   "upper_dos" resource to lock out other tasks from interrupting.
  25. ;   This "upper_dos" resource is shortly released on each INT 28, and
  26. ;   then immediately reclaimed, with task priority temporarily raised
  27. ;   to the maximum value. The first task waiting to execute a 
  28. ;   function > 0C will thus be scheduled to execute the request, but
  29. ;   the resource will be reassigned to the INT 28 handler as soon as
  30. ;   this request terminates, so the waiting task will not be delayed too
  31. ;   long.
  32. ;
  33. ; There are two additional safety measures which have to be taken to
  34. ; avoid getting into conflicts with other resident background programs,
  35. ; especially the DOS PRINT background spooler:
  36. ;
  37. ;   Before requesting any resource, the status of the DOS critical section
  38. ;   flag is checked. If this flag is set, the task is made waiting for
  39. ;   the flag to be cleared.
  40. ;   Only the task that set the flag will be allowed access to DOS.
  41. ;
  42. ;   Before actually executing the request, the status of the DOS in-use
  43. ;   flag is checked. If this flag is set, the task enters a busy waiting
  44. ;   loop, calling the scheduler so that the processor is not tied up.
  45. ;
  46. ; NOTE: The method for checking the status of DOS is described in-depth
  47. ;    in the book "The MS-DOS Encyclopedia" from Microsoft Press, in
  48. ;    the chapter on TSR programming. The logic in this module was
  49. ;    developed without the help of this book, so if you compare
  50. ;    the code here with the routines in the Encyclopedia, you may
  51. ;    notice that not all re-entry conditions are checked here.
  52. ;    According to my experience with debugging TSR's and CTask, the
  53. ;    logic should be sufficient for all but the most obscure TSR's.
  54. ;    If you want to be completely on the safe side, you might consider
  55. ;    adding the more thorough checks listed in the Encyclopedia.
  56. ;
  57. ;
  58.     name    tskdos
  59. ;
  60.     .model    large,c
  61. ;
  62.     public    tsk_install_dos
  63.     public    tsk_remove_dos
  64.     public    tsk_resident
  65.     public    tsk_emergency_exit
  66.     public    tsk_free_mem
  67. ;
  68.     include    tsk.mac
  69. ;
  70.     extrn    create_resource: far
  71.     extrn    delete_resource: far
  72.     extrn    request_resource: far
  73.     extrn    release_resource: far
  74.     extrn    create_flag: far
  75.     extrn    delete_flag: far
  76.     extrn    set_flag: far
  77.     extrn    clear_flag: far
  78.     extrn    wait_flag_clear: far
  79.     extrn    tsk_scheduler: far
  80. ;
  81.     extrn    tsk_dgroup: word
  82. ;
  83. ;
  84. CSECT        =    2ah    ; Critical Section Interrupt
  85. get_in_use_flag    =    34h    ; DOS-function to get in_use_flag address
  86. get_invars    =    5d06h    ; DOS-function to get DOS-variables area
  87. ;
  88. psp_offset    =    10h    ; Offset of current PSP in DOS save area
  89. ;
  90. ;    Structure of the start of a PSP, including undocumented fields
  91. ;
  92. psp_record    struc
  93. ;
  94.         dw    ?    ; INT 20
  95.         dw    ?    ; alloc block end
  96.         db    ?    ; reserved
  97.         db    5 dup(?) ; system call
  98. psp_exit_addr    dd    ?    ; exit routine address
  99. psp_ctlc_addr    dd    ?    ; control C routine address
  100. psp_cerr_addr    dd    ?    ; critical error routine address
  101. parent_psp    dw    ?    ; PSP of parent process
  102.         db    20 dup(?) ; files table
  103. psp_envseg    dw    ?    ; environment segment
  104. psp_ustack    dd    ?    ; ss/sp of caller
  105.         dw    ?    ; file table length
  106.         dd    ?    ; file table pointer
  107.         dd    ?    ; pointer to nested PSP (?)
  108. ;
  109. psp_record    ends
  110. ;
  111. ;
  112. ; Structure of a DOS MCB (Memory Control Block)
  113. ;
  114. mcbstruc    struc
  115. ;
  116. mcb_id        db    ?
  117. mcb_owner    dw    ?
  118. mcb_len        dw    ?
  119. ;
  120. mcbstruc    ends
  121. ;
  122. ;
  123. intseg    segment at 0
  124.         org    10h*4
  125. vidoff        dw    ?    ; video interrupt
  126. vidseg        dw    ?
  127.         org    13h*4
  128. diskoff        dw    ?    ; disk i/o interrupt
  129. diskseg        dw    ?
  130.         org    20h*4
  131. termoff        dw    ?    ; program terminate vector
  132. termseg        dw    ?
  133.         org    21h*4
  134. idosoff        dw    ?    ; dos interrupt
  135. idosseg        dw    ?
  136.         org    25h*4
  137. absreadoff    dw    ?    ; absolute disk read
  138. absreadseg    dw    ?
  139.         org    26h*4
  140. abswriteoff    dw    ?    ; absolute disk write
  141. abswriteseg    dw    ?
  142.         org    27h*4
  143. keepoff        dw    ?    ; Terminate but stay resident
  144. keepseg        dw    ?
  145.         org    28h*4
  146. idleoff        dw    ?    ; dos idle interrupt
  147. idleseg        dw    ?
  148.         org    CSECT*4
  149. csectoff    dw    ?    ; dos critical section
  150. csectseg    dw    ?
  151. ;
  152. intseg    ends
  153. ;
  154. ;----------------------------------------------------------------------------
  155. ;
  156. ;    Variables
  157. ;
  158.     .tsk_data
  159. ;
  160.     extrn    tsk_glob_rec: word    ; glob_rec
  161.     extrn    tsk_global: dword
  162.     extrn    tsk_instflags: word
  163.     extrn    tsk_version: byte
  164. ;
  165. term_err_msg    db    0dh,0ah,"Program terminated - CTask uninstalled"
  166.         db    0dh,0ah,'$'
  167. ;
  168. group_term_msg    db    0dh,0ah,"Program terminated - Task Group removed"
  169.         db    0dh,0ah,'$'
  170. ;
  171. gcb_mixup_err    db    0dh,0ah,"Group chain damaged - System halted"
  172.         db    07h,'$'
  173. ;
  174. idle_active    db    0            ; Idle-Interrupt active
  175. dos310        db    0        ; DOS version >= 3.10
  176. ;
  177.     IF    TSK_NAMEPAR
  178. udos_name    db    "DOSUPPER",0
  179. ldos_name    db    "DOSLOWER",0
  180. cdos_name    db    "DOSCRIT",0
  181. hdio_name    db    "HARDDISK",0
  182. fdio_name    db    "FLEXDISK",0
  183. vid_name    db    "VIDEO",0
  184.     ENDIF
  185. ;
  186. ;
  187. in_use        dd    ?        ; Adress of DOS in-use-flag
  188. in_error    dd    ?        ; Adress of DOS error-mode-flag
  189. ;
  190. lower_dos    resource <>
  191. upper_dos    resource <>
  192. hdisk_io    resource <>
  193. fdisk_io    resource <>
  194. video        resource <>
  195. critical    flag    <>
  196. ;
  197. ;
  198.     .tsk_edata
  199.     .tsk_code
  200. ;
  201.     extrn    tsk_switch_stack: near
  202.     extrn    tsk_old_stack: near
  203.     extrn    tsk_remove_group: near
  204. ;
  205. ;---------------------------------------------------------------------------
  206. ;
  207. ;    Original Interrupt-Entries
  208. ;
  209. savvid        label    dword        ; original Video entry
  210. savvidoff    dw    ?
  211. savvidseg    dw    ?
  212. ;
  213. savdisk        label    dword        ; original Disk I/O entry
  214. savdiskoff    dw    ?
  215. savdiskseg    dw    ?
  216. ;
  217. savtermoff    dw    ?        ; Terminate vector save
  218. savtermseg    dw    ?
  219. ;
  220. savdos        label    dword        ; original DOS-Entry
  221. savdosoff    dw    ?
  222. savdosseg    dw    ?
  223. ;
  224. savidle        label    dword        ; original IDLE-Entry
  225. savidleoff    dw    ?
  226. savidleseg    dw    ?
  227. ;
  228. savcsect    label    dword        ; Critical Section save
  229. savcsectoff    dw    ?
  230. savcsectseg    dw    ?
  231. ;
  232. savabsread    label    dword        ; Absolute Disk Read save
  233. savabsreadoff    dw    ?
  234. savabsreadseg    dw    ?
  235. ;
  236. savabswrite    label    dword        ; Absolute Disk Write save
  237. savabswriteoff    dw    ?
  238. savabswriteseg    dw    ?
  239. ;
  240. savkeepoff    dw    ?        ; Terminate resident vector save
  241. savkeepseg    dw    ?
  242. ;
  243. critsect_active    db    0        ; DOS Critical Section active
  244. ctask_active    db    0        ; CTask DOS call active
  245. crit_task    dd    ?        ; Task requesting critical section
  246. ;
  247. dos_version    dw    ?        ; DOS version
  248. ;
  249. temp_1        dw    ?
  250. temp_2        dw    ?
  251. temp_3        dw    ?
  252. ;
  253. xsp_sp        dw    ?
  254. xsp_ss        dw    ?
  255. xsp_ip        dw    ?
  256. xsp_cs        dw    ?
  257. ;
  258. ;
  259. calldos    macro
  260.     pushf
  261.     cli
  262.     call    cs:savdos
  263.     endm
  264. ;
  265. ;---------------------------------------------------------------------------
  266. ;
  267. tsk_resident    proc near uses si di ds
  268. ;
  269.     mov    ds,cs:tsk_dgroup
  270. ;
  271.     mov    dx,offset tsk_version
  272.     mov    bx,1234h
  273.     mov    ax,3000h
  274.     int    21h
  275.     mov    di,bx
  276.     mov    es,cx
  277.     mov    si,offset tsk_version
  278.     mov    cx,8
  279.     repe cmpsb
  280.     jcxz    tr_is_res
  281.     xor    bx,bx
  282.     mov    es,bx
  283. tr_is_res:
  284.     mov    ax,bx
  285.     mov    dx,es
  286.     ret
  287. ;
  288. tsk_resident    endp
  289. ;
  290. ;---------------------------------------------------------------------------
  291. ;
  292. ;    void tsk_install_dos (void)
  293. ;
  294. ;        Install DOS handler
  295. ;
  296. tsk_install_dos    proc    near uses ds
  297. ;
  298. ;    create needed resources & flags
  299. ;
  300.     mov    ds,cs:tsk_dgroup
  301. ;
  302.     IF    TSK_NAMEPAR
  303.     mov    ax,offset udos_name
  304.     push    ds
  305.     push    ax
  306.     ENDIF
  307.     mov    ax,offset upper_dos
  308.     push    ds
  309.     push    ax
  310.     call    create_resource
  311.     IF    TSK_NAMEPAR
  312.     add    sp,8
  313.     ELSE
  314.     add    sp,4
  315.     ENDIF
  316. ;
  317.     IF    TSK_NAMEPAR
  318.     mov    ax,offset ldos_name
  319.     push    ds
  320.     push    ax
  321.     ENDIF
  322.     mov    ax,offset lower_dos
  323.     push    ds
  324.     push    ax
  325.     call    create_resource
  326.     IF    TSK_NAMEPAR
  327.     add    sp,8
  328.     ELSE
  329.     add    sp,4
  330.     ENDIF
  331. ;
  332.     test    tsk_instflags,IFL_DISK
  333.     jz    inst_nodsk1
  334.     IF    TSK_NAMEPAR
  335.     mov    ax,offset hdio_name
  336.     push    ds
  337.     push    ax
  338.     ENDIF
  339.     mov    ax,offset hdisk_io
  340.     push    ds
  341.     push    ax
  342.     call    create_resource
  343.     IF    TSK_NAMEPAR
  344.     add    sp,8
  345.     ELSE
  346.     add    sp,4
  347.     ENDIF
  348. ;
  349.     IF    TSK_NAMEPAR
  350.     mov    ax,offset fdio_name
  351.     push    ds
  352.     push    ax
  353.     ENDIF
  354.     mov    ax,offset fdisk_io
  355.     push    ds
  356.     push    ax
  357.     call    create_resource
  358.     IF    TSK_NAMEPAR
  359.     add    sp,8
  360.     ELSE
  361.     add    sp,4
  362.     ENDIF
  363. ;
  364. inst_nodsk1:
  365.     test    tsk_instflags,IFL_VIDEO
  366.     jz    inst_novid1
  367.     IF    TSK_NAMEPAR
  368.     mov    ax,offset vid_name
  369.     push    ds
  370.     push    ax
  371.     ENDIF
  372.     mov    ax,offset video
  373.     push    ds
  374.     push    ax
  375.     call    create_resource
  376.     IF    TSK_NAMEPAR
  377.     add    sp,8
  378.     ELSE
  379.     add    sp,4
  380.     ENDIF
  381. ;
  382. inst_novid1:
  383.     IF    TSK_NAMEPAR
  384.     mov    ax,offset cdos_name
  385.     push    ds
  386.     push    ax
  387.     ENDIF
  388.     mov    ax,offset critical
  389.     push    ds
  390.     push    ax
  391.     call    create_flag
  392.     IF    TSK_NAMEPAR
  393.     add    sp,8
  394.     ELSE
  395.     add    sp,4
  396.     ENDIF
  397. ;
  398. ;    Get address and length of the DOS internal variable area.
  399. ;    This call is not documented, and not available in versions
  400. ;    prior to 3.1. It returns the address of the area in DS:SI,
  401. ;    and the length of the area that must be swapped between calls
  402. ;    from different groups in DX.
  403. ;    Additionally, the total length of the area, including
  404. ;    the DOS-stacks, minus the length in DX, is returned in CX.
  405. ;
  406.     mov    tsk_glob_rec.l_swap,0
  407.     test    tsk_instflags,IFL_NODOSVARS
  408.     jnz    no_invars
  409. ;
  410.     push    ds
  411.     mov    ax,get_invars
  412.     int    21h
  413.     mov    ax,ds
  414.     pop    ds
  415.     mov    word ptr tsk_glob_rec.dos_vars,si
  416.     mov    word ptr tsk_glob_rec.dos_vars+2,ax
  417.     mov    tsk_glob_rec.l_swap,dx
  418. ;
  419. ;    Get the address of DOS's in_use-flag. This flag indicates that
  420. ;    DOS is already active. This might happen if there are other
  421. ;    background tasks, like popups or print spoolers, active in
  422. ;    parallel to CTask.
  423. ;    This is also the address of the critical error flag in DOS. Beginning 
  424. ;    with DOS 3.10 the flag is located one byte before the in_use_flag.
  425. ;    With older DOS versions, we would have to search through DOS for the 
  426. ;    address. This is omitted here, but you could include the code
  427. ;    for pre 3.1 versions from pages 378-379 of the MS-DOS Encyclopedia.
  428. ;
  429. no_invars:
  430.     mov    ah,get_in_use_flag
  431.     int    21h
  432.     mov    word ptr in_use,bx
  433.     mov    word ptr in_use+2,es
  434.     mov    word ptr in_error+2,es
  435. ;
  436.     push    bx
  437.     mov    ah,30h
  438.     int    21h
  439.     pop    bx
  440.     mov    cs:dos_version,ax
  441.     cmp    al,3
  442.     jb    not_dos3
  443.     cmp    al,0ah
  444.     je    not_dos3    ; OS/2 compatibility box
  445.         cmp     al,3
  446.         jne     is_dos3         ; DOS 4.x 
  447.     cmp    ah,10
  448.     jb    not_dos3
  449. is_dos3:
  450.     inc    dos310
  451.     dec    bx
  452.     mov    word ptr in_error,bx
  453.     jmp    short save_ints
  454. ;
  455. not_dos3:
  456. ;
  457. ;    Save old interrupt vectors
  458. ;
  459. save_ints:
  460.         push    es
  461.     xor    ax,ax
  462.     mov    es,ax
  463. ;
  464.         assume  es:intseg
  465. ;
  466.     test    tsk_instflags,IFL_VIDEO
  467.     jz    inst_novid2
  468.     mov    ax,vidoff        ; video
  469.     mov    savvidoff,ax
  470.     mov    ax,vidseg
  471.     mov    savvidseg,ax
  472. ;
  473. inst_novid2:
  474.     test    tsk_instflags,IFL_DISK
  475.     jz    inst_nodsk2
  476.     mov    ax,diskoff        ; Disk I/O
  477.     mov    savdiskoff,ax
  478.     mov    ax,diskseg
  479.     mov    savdiskseg,ax
  480. ;
  481. inst_nodsk2:
  482.     mov    ax,termoff        ; DOS
  483.     mov    savtermoff,ax
  484.     mov    ax,termseg
  485.     mov    savtermseg,ax
  486. ;
  487.     mov    ax,idosoff        ; DOS
  488.     mov    savdosoff,ax
  489.     mov    ax,idosseg
  490.     mov    savdosseg,ax
  491. ;
  492.     mov    ax,idleoff        ; IDLE
  493.     mov    savidleoff,ax
  494.     mov    ax,idleseg
  495.     mov    savidleseg,ax
  496. ;
  497.     mov    ax,csectoff        ; Critical Section
  498.     mov    savcsectoff,ax
  499.     mov    ax,csectseg
  500.     mov    savcsectseg,ax
  501. ;
  502.     mov    ax,absreadoff        ; Absolute Disk read
  503.     mov    savabsreadoff,ax
  504.     mov    ax,absreadseg
  505.     mov    savabsreadseg,ax
  506. ;
  507.     mov    ax,abswriteoff        ; Absolute Disk write
  508.     mov    savabswriteoff,ax
  509.     mov    ax,abswriteseg
  510.     mov    savabswriteseg,ax
  511. ;
  512.     mov    ax,keepoff        ; Terminate Resident
  513.     mov    savkeepoff,ax
  514.     mov    ax,keepseg
  515.     mov    savkeepseg,ax
  516. ;
  517. ;    Enter new Interrupt-Entries
  518. ;
  519.     cli
  520.     test    tsk_instflags,IFL_VIDEO
  521.     jz    inst_novid3
  522.     mov    vidoff,offset videntry        ; Video Entry
  523.     mov    vidseg,cs
  524. ;
  525. inst_novid3:
  526.     test    tsk_instflags,IFL_DISK
  527.     jz    inst_nodsk3
  528.     mov    diskoff,offset diskentry    ; Disk I/O Entry
  529.     mov    diskseg,cs
  530. ;
  531. inst_nodsk3:
  532.     mov    idosoff,offset dosentry        ; DOS-Entry
  533.     mov    idosseg,cs
  534.     mov    idleoff,offset idleentry    ; Idle-Entry
  535.     mov    idleseg,cs
  536.     mov    termoff,offset terminate_int    ; Terminate Process Entry
  537.     mov    termseg,cs
  538.     mov    csectoff,offset critsectint    ; Critical Section Entry
  539.     mov    csectseg,cs
  540.     mov    keepoff,offset keep_int        ; Keep Process Entry
  541.     mov    keepseg,cs
  542.     mov    absreadoff,offset absread_int    ; Absolute Disk Read Entry
  543.     mov    absreadseg,cs
  544.     mov    abswriteoff,offset abswrite_int    ; Absolute Disk Write Entry
  545.     mov    abswriteseg,cs
  546.     sti
  547. ;
  548.     assume    es:nothing
  549. ;
  550.         pop     es
  551.     ret
  552. ;
  553. ;
  554. tsk_install_dos    endp
  555. ;
  556. ;
  557. ;    void tsk_remove_dos (void)
  558. ;
  559. ;        Un-install DOS handler
  560. ;
  561. tsk_remove_dos    proc    near uses ds
  562. ;
  563.     mov    ds,cs:tsk_dgroup
  564. ;
  565. ;    Delete resources & flags
  566. ;
  567.     mov    ax,offset upper_dos
  568.     push    ds
  569.     push    ax
  570.     call    delete_resource
  571.     add    sp,4
  572. ;
  573.     mov    ax,offset lower_dos
  574.     push    ds
  575.     push    ax
  576.     call    delete_resource
  577.     add    sp,4
  578. ;
  579.     test    tsk_instflags,IFL_DISK
  580.     jz    rem_nodsk1
  581.     mov    ax,offset hdisk_io
  582.     push    ds
  583.     push    ax
  584.     call    delete_resource
  585.     add    sp,4
  586. ;
  587.     mov    ax,offset fdisk_io
  588.     push    ds
  589.     push    ax
  590.     call    delete_resource
  591.     add    sp,4
  592. ;
  593. rem_nodsk1:
  594.     test    tsk_instflags,IFL_VIDEO
  595.     jz    rem_novid1
  596.     mov    ax,offset video
  597.     push    ds
  598.     push    ax
  599.     call    delete_resource
  600.     add    sp,4
  601. ;
  602. rem_novid1:
  603.     mov    ax,offset critical
  604.     push    ds
  605.     push    ax
  606.     call    delete_flag
  607.     add    sp,4
  608. ;
  609.         push    es
  610.     xor    ax,ax
  611.     mov    es,ax
  612. ;
  613.         assume  es:intseg
  614. ;
  615. ;    Restore interrupt entries
  616. ;
  617.     cli
  618.     test    tsk_instflags,IFL_VIDEO
  619.     jz    rem_novid2
  620.     mov    ax,savvidoff
  621.     mov    vidoff,ax
  622.     mov    ax,savvidseg
  623.     mov    vidseg,ax
  624. ;
  625. rem_novid2:
  626.     test    tsk_instflags,IFL_DISK
  627.     jz    rem_nodsk2
  628.     mov    ax,savdiskoff
  629.     mov    diskoff,ax
  630.     mov    ax,savdiskseg
  631.     mov    diskseg,ax
  632. ;
  633. rem_nodsk2:
  634.     mov    ax,savtermoff
  635.     mov    termoff,ax
  636.     mov    ax,savtermseg
  637.     mov    termseg,ax
  638. ;
  639.     mov    ax,savdosoff
  640.     mov    idosoff,ax
  641.     mov    ax,savdosseg
  642.     mov    idosseg,ax
  643. ;
  644.     mov    ax,savidleoff
  645.     mov    idleoff,ax
  646.     mov    ax,savidleseg
  647.     mov    idleseg,ax
  648. ;
  649.     mov    ax,savcsectoff
  650.     mov    csectoff,ax
  651.     mov    ax,savcsectseg
  652.     mov    csectseg,ax
  653. ;
  654.     mov    ax,savabsreadoff
  655.     mov    absreadoff,ax
  656.     mov    ax,savabsreadseg
  657.     mov    absreadseg,ax
  658. ;
  659.     mov    ax,savabswriteoff
  660.     mov    abswriteoff,ax
  661.     mov    ax,savabswriteseg
  662.     mov    abswriteseg,ax
  663. ;
  664.     mov    ax,savkeepoff
  665.     mov    keepoff,ax
  666.     mov    ax,savkeepseg
  667.     mov    keepseg,ax
  668. ;
  669.     sti
  670. ;
  671.         pop     es
  672.     ret
  673. ;
  674.     assume    es:nothing
  675. ;
  676. tsk_remove_dos    endp
  677. ;
  678. ;
  679. ;---------------------------------------------------------------------------
  680. ;---------------------------------------------------------------------------
  681. ;
  682. ;
  683. ;    INT 10: Video BIOS interrupt
  684. ;
  685. videntry    proc    far
  686. ;
  687.     call    tsk_switch_stack
  688.     xor    ax,ax
  689.     push    ax
  690.     push    ax
  691.     push    ds
  692.     mov    ax,offset video
  693.     push    ax
  694.     call    request_resource
  695.     add    sp,8
  696.     push    caller_flags[bp]
  697.     popf
  698.     call    tsk_old_stack
  699.     pushf
  700.     cli
  701.     call    savvid
  702.     call    tsk_switch_stack
  703.     mov    ax,entry_flags[bp]
  704.     mov    caller_flags[bp],ax
  705.     push    ds
  706.     mov    ax,offset video
  707.     push    ax
  708.     call    release_resource
  709.     add    sp,4
  710.     iret
  711. ;
  712. videntry    endp
  713. ;
  714. ;---------------------------------------------------------------------------
  715. ;
  716. ;
  717. ;    INT 13: Disk I/O BIOS interrupt
  718. ;
  719. diskentry    proc    far
  720. ;
  721.     call    tsk_switch_stack
  722.     xor    ax,ax
  723.     push    ax
  724.     push    ax
  725.     push    ds
  726.     test    dl,80h            ; fixed disk ?
  727.     jz    disk_floppy        ; jump if not
  728.     mov    ax,offset hdisk_io
  729.     push    ax
  730.     call    request_resource
  731.     add    sp,8
  732.     push    caller_flags[bp]
  733.     popf
  734.     call    tsk_old_stack
  735.     pushf
  736.     cli
  737.     call    savdisk
  738.     call    tsk_switch_stack
  739.     mov    ax,entry_flags[bp]
  740.     mov    caller_flags[bp],ax
  741.     push    ds
  742.     mov    ax,offset hdisk_io
  743.     push    ax
  744.     call    release_resource
  745.     add    sp,4
  746.     iret
  747. ;
  748. disk_floppy:
  749.     mov    ax,offset fdisk_io
  750.     push    ax
  751.     call    request_resource
  752.     add    sp,8
  753.     push    caller_flags[bp]
  754.     popf
  755.     call    tsk_old_stack
  756.     pushf
  757.     cli
  758.     call    savdisk
  759.     call    tsk_switch_stack
  760.     mov    ax,entry_flags[bp]
  761.     mov    caller_flags[bp],ax
  762.     push    ds
  763.     mov    ax,offset fdisk_io
  764.     push    ax
  765.     call    release_resource
  766.     add    sp,4
  767.     iret
  768. ;
  769. diskentry    endp
  770. ;
  771. ;---------------------------------------------------------------------------
  772. ;
  773. ;    Stack-Offsets relative to BP
  774. ;
  775. d_func    =    -2
  776. ;
  777. ;---------------------------------------------------------------------------
  778. ;
  779. ;    INT 25: Absolute Disk Read 
  780. ;
  781. ;    This interrupt is channeled through the normal DOS-function
  782. ;    processing, with function = 0x25 and special flag set.
  783. ;    It is re-translated later after the necessary resources
  784. ;    have been requested.
  785. ;    Interrupts 25 und 26 leave the flag-word on the stack.
  786. ;    Since flags are removed in normal processing, the flag-word
  787. ;    has to be duplicated on the stack here.
  788. ;
  789. absread_int:
  790.     sti
  791.     push    bp            ; reserve space
  792.     push    bp            ; save BP
  793.     mov    bp,sp
  794.     push    ax
  795.     mov    ax,4[bp]        ; Move return offset, segment down
  796.     mov    2[bp],ax
  797.     mov    ax,6[bp]
  798.     mov    4[bp],ax
  799.     mov    ax,8[bp]        ; duplicate flags
  800.     mov    6[bp],ax
  801.     pop    ax
  802.     pop    bp
  803.     call    tsk_switch_stack
  804.     mov    ax,2501h
  805.     mov    cx,ax
  806.     jmp    short dosentry_2
  807. ;
  808. ;
  809. ;---------------------------------------------------------------------------
  810. ;
  811. ;    INT 26: Absolute Disk Write
  812. ;
  813. ;    This interrupt is channeled through the normal DOS-function
  814. ;    processing, with function = 0x26 and special flag set.
  815. ;    It is re-translated later after the necessary resources
  816. ;    have been requested.
  817. ;    Interrupts 25 und 26 leave the flag-word on the stack.
  818. ;    Since flags are removed in normal processing, the flag-word
  819. ;    has to be duplicated on the stack here.
  820. ;
  821. abswrite_int:
  822.     sti
  823.     push    bp            ; reserve space
  824.     push    bp            ; save BP
  825.     mov    bp,sp
  826.     push    ax
  827.     mov    ax,4[bp]        ; Move return offset, segment down
  828.     mov    2[bp],ax
  829.     mov    ax,6[bp]
  830.     mov    4[bp],ax
  831.     mov    ax,8[bp]        ; duplicate flags
  832.     mov    6[bp],ax
  833.     pop    ax
  834.     pop    bp
  835.     call    tsk_switch_stack
  836.     mov    ax,2601h
  837.     mov    cx,ax
  838.     jmp    short dosentry_2
  839. ;
  840. ;---------------------------------------------------------------------------
  841. ;
  842. ;    INT 27: Terminate But Stay Resident Interrupt
  843. ;
  844. ;    This interrupt is translated to INT 21, function 31.
  845. ;
  846. keep_int:
  847.     call    tsk_switch_stack
  848. ;
  849.     add    dx,0fh            ; last addr + 0f to round
  850.     sub    dx,caller_cs[bp]    ; minus CS (= PSP)
  851.     mov    cl,4
  852.     shr    dx,cl            ; div 16 = paragraphs
  853.  
  854.     mov    ax,3100h        ; Keep process
  855.     mov    save_ax[bp],ax
  856.     mov    cx,ax
  857.     jmp    short dosentry_2
  858. ;
  859. ;---------------------------------------------------------------------------
  860. ;
  861. ;    INT 20: Terminate Program interrupt
  862. ;
  863. ;    This interrupt is translated to INT 21, function 4c.
  864. ;
  865. terminate_int:
  866.     call    tsk_switch_stack
  867.     mov    ax,4c00h
  868.     mov    save_ax[bp],ax
  869.     mov    cx,ax
  870.     jmp    short dosentry_2
  871. ;
  872. ;---------------------------------------------------------------------------
  873. ;
  874. ;    INT 21: DOS-Interrupt
  875. ;
  876. dosentry        proc    far
  877. ;
  878.     call    tsk_switch_stack
  879.     xor    cl,cl
  880.     mov    ch,ah
  881. ;
  882. dosentry_2:
  883.     push    cx        ; BP-2: func in CH, special flag in CL
  884. ;
  885. ;    Check if this is a special 'get dos version' call.
  886. ;
  887.     or    cl,cl
  888.     jnz    dosent_x    ; no function check if special
  889.     cmp    ax,3000h
  890.     jne    no_spdos
  891.     cmp    bx,1234h
  892.     jne    no_spdos
  893.     push    ds
  894.     mov    si,dx
  895.     mov    ds,save_ds[bp]
  896.     mov    di,offset tsk_glob_rec
  897.     mov    cx,8
  898.     repe cmpsb
  899.     pop    ds
  900.     jcxz    is_spdos
  901.     jmp    short no_spdos
  902. ;
  903. ;    Special version call returns global variable block address
  904. ;
  905. is_spdos:
  906.     add    sp,2
  907.     call    tsk_old_stack
  908.     mov    ax,cs:dos_version
  909.     mov    bx,offset tsk_glob_rec
  910.     mov    cx,cs:tsk_dgroup
  911.     iret
  912. ;
  913. ;    Here we check if the DOS critical region is active.
  914. ;    If yes, this means that some outside background process has
  915. ;    started DOS (most likely DOS PRINT).
  916. ;    To avoid busy waiting, we wait for the "critical" flag to be
  917. ;    cleared, if this is *not* the task that set the flag.
  918. ;    The task that set the critical flag is *not* made waiting.
  919. ;
  920. no_spdos:
  921.     mov    ax,d_func[bp]
  922.         or    ah,ah            ; terminate?
  923.         jne     dosent_x
  924.         mov     save_ax[bp],4c00h    ; translate to fn 4c, retcode 0
  925.         mov     d_func[bp],4c00h
  926. dosent_x:
  927. ;
  928.     cmp    cs:critsect_active,0
  929.     je    no_crit
  930.     mov    ax,word ptr cs:crit_task
  931.     cmp    word ptr tsk_glob_rec.current_task,ax
  932.     jne    wait_crit
  933.     mov    ax,word ptr cs:crit_task+2
  934.     cmp    word ptr tsk_glob_rec.current_task+2,ax
  935.     je    no_crit
  936. ;
  937. wait_crit:
  938.     xor    ax,ax
  939.     push    ax
  940.     push    ax
  941.     mov    ax,offset critical
  942.     push    ds
  943.     push    ax
  944.     call    wait_flag_clear
  945.     add    sp,8
  946. ;
  947. no_crit:
  948.     mov    cs:ctask_active,1    ; mark that we are active
  949.     sti                ; Interrupts allowed now
  950. ;
  951. ;
  952. ;    Now let's check if the current task owns one of the dos-resources.
  953. ;    This may happen on
  954. ;        - terminate (TSR or normal)
  955. ;        - spawn process
  956. ;        - critical error/break
  957. ;        - redirection of INT 28 to out-of-CTask routine
  958. ;    If the task owns one, and the dos-flags are clear,
  959. ;    the resource is released.
  960. ;    If the dos-flags are nonzero, the resource is not
  961. ;    released, but the task is allowed access to DOS regardless of
  962. ;    resource and flag states.
  963. ;    DL is used as an "emergency" marker. If nonzero, no resources
  964. ;    are to be requested, and the in-dos flag is not checked.
  965. ;
  966.     xor    dl,dl
  967.     les    bx,tsk_glob_rec.current_task
  968.     cli
  969.     cmp    es:t_indos[bx],0
  970.     je    no_reenter
  971. ;
  972.     les    bx,in_error
  973.     mov    dl,es:byte ptr [bx]
  974.     les    bx,in_use
  975.     or    dl,es:byte ptr [bx]
  976.     jnz    no_reenter
  977. ;
  978.     les    bx,tsk_glob_rec.current_task
  979.     and    es:t_indos[bx],NOT SPAWNING
  980.     jz    no_reenter
  981. ;
  982.     test    es:t_indos[bx],OWN_UPPER
  983.     jz    rel_lower
  984.     xor    es:t_indos[bx],OWN_UPPER
  985.     mov    bx,offset upper_dos
  986.     push    ds        ; resource address
  987.     push    bx
  988.     call    release_resource
  989.     add    sp,4
  990.     xor    dl,dl
  991.     les    bx,tsk_glob_rec.current_task
  992. rel_lower:
  993.     test    es:t_indos[bx],OWN_LOWER
  994.     jz    no_reenter
  995.     xor    es:t_indos[bx],OWN_LOWER
  996.     mov    bx,offset lower_dos
  997.     push    ds        ; resource address
  998.     push    bx
  999.     call    release_resource
  1000.     add    sp,4
  1001.     xor    dl,dl
  1002. ;
  1003. no_reenter:
  1004.     sti
  1005.     mov    ax,d_func[bp]
  1006.     cmp    ah,0ch
  1007.     jbe    lower_funcs
  1008.     jmp    upper_funcs
  1009. ;
  1010. ;
  1011. ;    Functions 00-0C
  1012. ;
  1013. lower_funcs:
  1014. ;
  1015. ;    first, request the "lower_dos" resource
  1016. ;
  1017.     or    dl,dl
  1018.     jnz    lower_emergency
  1019.     mov    bx,offset lower_dos
  1020.     xor    cx,cx
  1021.     push    cx        ; no timeout
  1022.     push    cx
  1023.     push    ds        ; resource address
  1024.     push    bx
  1025.     call    request_resource
  1026.     add    sp,8
  1027. ;
  1028. ;    we have it, now let's get the upper_dos resource, too
  1029. ;
  1030.     mov    bx,offset upper_dos
  1031.     xor    cx,cx
  1032.     push    cx        ; no timeout
  1033.     push    cx
  1034.     push    ds        ; resource address
  1035.     push    bx
  1036.     call    request_resource
  1037.     add    sp,8
  1038. ;
  1039.     les    bx,tsk_glob_rec.current_task
  1040.     mov    es:t_indos[bx],OWN_UPPER or OWN_LOWER
  1041. ;
  1042. ;    both resources gained, now we may execute the function if dos is free
  1043. ;
  1044.     call    wait_dos_free
  1045. ;
  1046. lower_emergency:
  1047.     add    sp,2
  1048.     push    caller_flags[bp]
  1049.     popf
  1050.     call    tsk_old_stack
  1051. ;
  1052.     calldos                ; execute function
  1053. ;
  1054. ;    Now we have to release the resources.
  1055. ;
  1056.     call    tsk_switch_stack
  1057. ;
  1058.     les    bx,in_error
  1059.     cmp    es:byte ptr [bx],0
  1060.     jne    no_relc
  1061. ;
  1062.     mov    bx,offset upper_dos
  1063.     push    ds        ; resource address
  1064.     push    bx
  1065.     call    release_resource
  1066.     add    sp,4
  1067. ;
  1068.     mov    bx,offset lower_dos
  1069.     push    ds        ; resource address
  1070.     push    bx
  1071.     call    release_resource
  1072.     add    sp,4
  1073. ;
  1074.     les    bx,tsk_glob_rec.current_task
  1075.     mov    es:t_indos[bx],0
  1076. ;
  1077. ;    If both resources are free now, clear the ctask_active flag to
  1078. ;    allow other background processes to gain access to DOS.
  1079. ;
  1080.     cli
  1081.     cmp    upper_dos.rcount,0
  1082.         jne    no_relc
  1083.     cmp    lower_dos.rcount,0
  1084.     jne    no_relc
  1085.     mov    cs:ctask_active,0
  1086. no_relc:
  1087. ;
  1088. ;    All done, restore registers and return.
  1089. ;
  1090.     mov    ax,entry_flags[bp]
  1091.     mov    caller_flags[bp],ax
  1092.     iret
  1093. ;
  1094. ;--------------------------------------------------------------------------
  1095. ;
  1096. ;    Functions 0D and above
  1097. ;
  1098. upper_funcs:
  1099.     or    dl,dl
  1100.     jnz    upper_emergency
  1101. ;
  1102.     mov    bx,offset upper_dos
  1103.     xor    cx,cx
  1104.     push    cx        ; no timeout
  1105.     push    cx
  1106.     push    ds        ; resource address
  1107.     push    bx
  1108.     call    request_resource
  1109.     add    sp,8
  1110. ;
  1111.     les    bx,tsk_glob_rec.current_task
  1112.     mov    es:t_indos[bx],OWN_UPPER
  1113. ;
  1114. ;    resource gained, now we may execute the function if dos is free
  1115. ;
  1116.     call    wait_dos_free
  1117. ;
  1118. upper_emergency:
  1119.     cmp    byte ptr d_func[bp],0
  1120.     jne    no_term
  1121.     mov    ax,save_ax[bp]
  1122.     cmp    ah,31h        ; terminate resident?
  1123.     jne    ckfunc1
  1124.     jmp    term_resident
  1125. ckfunc1:
  1126.     cmp    ax,4b00h    ; spawn new process?
  1127.     jne    ckfunc2
  1128.     jmp    terminate
  1129. ckfunc2:
  1130.     cmp    ah,4ch        ; terminate program?
  1131.     jne    no_term
  1132.     jmp    terminate
  1133. ;
  1134. no_term:
  1135. ;
  1136. ;    Filter special-functions 25/26 (Absolute Read/Write)
  1137. ;
  1138.     pop    ax
  1139.     cmp    ax,2501h
  1140.     jne    uf_exec1
  1141.     push    caller_flags[bp]
  1142.     popf
  1143.     call    tsk_old_stack
  1144.     pushf
  1145.     cli
  1146.     call    cs:savabsread
  1147.     pop    cs:temp_1        ; remove flags
  1148.     jmp    short uf_complete
  1149. ;
  1150. uf_exec1:
  1151.     cmp    ax,2601h
  1152.     jne    uf_exec2
  1153.     push    caller_flags[bp]
  1154.     popf
  1155.     call    tsk_old_stack
  1156.     pushf
  1157.     cli
  1158.     call    cs:savabswrite
  1159.     pop    cs:temp_1        ; remove flags
  1160.     jmp    short uf_complete
  1161. ;
  1162. uf_exec2:
  1163.     push    caller_flags[bp]
  1164.     popf
  1165.     call    tsk_old_stack
  1166. ;
  1167.     calldos                ; execute function
  1168. ;
  1169. ;    Now we have to release the resources.
  1170. ;
  1171. uf_complete:
  1172.     call    tsk_switch_stack
  1173.     mov    ax,entry_flags[bp]
  1174.     mov    caller_flags[bp],ax
  1175. ;
  1176. ;    if in_error or in_use is set, we do not release the resources.
  1177. ;
  1178. uf_relres:
  1179.     les    bx,in_error
  1180.     cmp    es:byte ptr [bx],0
  1181.     jne    no_relc1
  1182.     les    bx,in_use
  1183.     cmp    es:byte ptr [bx],0
  1184.     jne    no_relc1
  1185. ;
  1186.     mov    bx,offset upper_dos
  1187.     push    ds                ; resource address
  1188.     push    bx
  1189.     call    release_resource
  1190.     add    sp,4
  1191. ;
  1192.     les    bx,tsk_glob_rec.current_task
  1193.     mov    es:t_indos[bx],0
  1194. ;
  1195. ;    If both resources are free now, clear the ctask_active flag to
  1196. ;    allow other background processes to gain access to DOS.
  1197. ;
  1198.     cli
  1199.     cmp    upper_dos.rcount,0
  1200.         jne    no_relc1
  1201.     cmp    lower_dos.rcount,0
  1202.     jne    no_relc1
  1203.     mov    cs:ctask_active,0
  1204. ;
  1205. ;    All done, restore registers and return.
  1206. ;
  1207. no_relc1:
  1208.     iret
  1209. ;
  1210. ;--------------------------------------------------------------------------
  1211. ;
  1212. ;    Terminate, TSR and Spawn calls go directly to DOS.
  1213. ;    TSR has to reset the exit address if it's the PSP of the 
  1214. ;    current group, so the group is not deleted.
  1215. ;
  1216. term_resident:
  1217.     les    bx,tsk_glob_rec.dos_vars
  1218.     mov    ax,es:[bx+psp_offset]        ; current PSP
  1219.     les    bx,tsk_glob_rec.current_task
  1220.     les    bx,es:tgroup[bx]
  1221.     cmp    es:gcreate_psp[bx],ax
  1222.     jne    terminate
  1223.     push    ds
  1224.     mov    ds,ax
  1225.     mov    ax,word ptr es:grp_exit_addr[bx]
  1226.     mov    word ptr ds:psp_exit_addr,ax
  1227.     mov    ax,word ptr es:grp_exit_addr+2[bx]
  1228.     mov    word ptr ds:psp_exit_addr+2,ax
  1229.     pop    ds
  1230. ;
  1231. terminate:
  1232.     add    sp,2
  1233.     push    caller_flags[bp]
  1234.     popf
  1235.     call    tsk_old_stack
  1236.     cli
  1237.     jmp    cs:savdos
  1238. ;
  1239. dosentry    endp
  1240. ;
  1241. ;--------------------------------------------------------------------------
  1242. ;
  1243. wait_dos_free    proc    near
  1244. ;
  1245. in_use_loop:
  1246.     cmp    dos310,0        ; dos version < 3.10?
  1247.     je    no_in_error        ; then we don't check for in_error
  1248.     les    bx,in_error
  1249.     cmp    byte ptr es:[bx],0
  1250.     jne    is_in_use
  1251. no_in_error:
  1252.     cmp    idle_active,0        ; idle interrupt active?
  1253.     je    ck_inuse        ; check for flag if no
  1254.     ret                ; else return immediately
  1255. ;
  1256. ck_inuse:
  1257.     les    bx,in_use
  1258.     cmp    byte ptr es:[bx],0
  1259.     jne    is_in_use
  1260.     ret
  1261. ;
  1262. is_in_use:
  1263.     pushf
  1264.     call    tsk_scheduler
  1265.     jmp    in_use_loop
  1266. ;
  1267. wait_dos_free    endp
  1268. ;
  1269. ;----------------------------------------------------------------------------
  1270. ;
  1271. ;    INT 28: DOS Idle Interrupt
  1272. ;
  1273. idleentry    proc    far
  1274. ;
  1275.     call    tsk_switch_stack
  1276. ;
  1277. ;    Check if someone is waiting for upper_dos. If not, we can return
  1278. ;    immediately.
  1279. ;
  1280.     les    bx,upper_dos.rwaiting.q_first
  1281.     cmp    es:q_kind[bx],0
  1282.     je    idle_exit
  1283. ;
  1284. ;    Also make sure this is not a second invocation of INT 28.
  1285. ;    Normally, this should never happen, but better safe than sorry.
  1286. ;
  1287.     cmp    idle_active,0
  1288.     jne    idle_exit
  1289.     inc    idle_active
  1290. ;
  1291. ;    someone is waiting, let's please him by releasing the resource
  1292. ;
  1293. ;    temporarily increase priority
  1294. ;
  1295.     les    bx,tsk_glob_rec.current_task
  1296.     push    es:cqueue.q_el.q_prior[bx]
  1297.     push    es:cqueue.q_el.q_ini_prior[bx]
  1298.     mov    es:cqueue.q_el.q_prior[bx],0ffffh
  1299.     mov    es:cqueue.q_el.q_ini_prior[bx],0ffffh
  1300.     push    bx
  1301.     push    es
  1302. ;
  1303. ;    release resource & request it again
  1304. ;
  1305.     mov    ax,ds
  1306.     mov    es,ax
  1307.     mov    bx,offset upper_dos
  1308.     push    ds
  1309.     push    bx
  1310.     call    release_resource
  1311.     add    sp,4
  1312. ;
  1313.     mov    bx,offset upper_dos
  1314.     xor    cx,cx
  1315.     push    cx
  1316.     push    cx
  1317.     push    ds
  1318.     push    bx
  1319.     call    request_resource
  1320.     add    sp,8
  1321. ;
  1322. ;    ready, restore priority
  1323. ;
  1324.     cli
  1325.     pop    es
  1326.     pop    bx
  1327.     pop    es:cqueue.q_el.q_ini_prior[bx]
  1328.     pop    es:cqueue.q_el.q_prior[bx]
  1329. ;
  1330.     mov    idle_active,0
  1331. ;
  1332. idle_exit:
  1333.     push    caller_flags[bp]
  1334.     popf
  1335.     call    tsk_old_stack
  1336.     cli
  1337. ;
  1338.     jmp    cs:savidle        ; chain to original interrupt
  1339. ;
  1340. idleentry    endp
  1341. ;
  1342. ;---------------------------------------------------------------------------
  1343. ;
  1344. ;    INT 2A: DOS Critical Section Interrupt.
  1345. ;
  1346. ;    Not documented.
  1347. ;    Is used by DOS PRINT to mark Critical Regions.
  1348. ;    Usage by PRINT:
  1349. ;        AX = 8700 - Begin Critical Region
  1350. ;                Returns:
  1351. ;                Carry set if already active.
  1352. ;        AX = 8701 - End Critical Region
  1353. ;
  1354. ;    Both these functions are handled here.
  1355. ;
  1356. ;    Other usage in DOS, function unknown:
  1357. ;        AH = 82 (AL undefined)
  1358. ;            seems to be called on DOS-Functions > 0C
  1359. ;        AH = 84 (AL undefined)
  1360. ;            seems to be called when DOS is idle
  1361. ;
  1362. ;    These functions are currently ignored.
  1363. ;
  1364. critsectint    proc    far
  1365.  
  1366.     cmp    ax,8700h    ; Enter critical region
  1367.     jne    csi1
  1368.     cmp    cs:critsect_active,0
  1369.     stc
  1370.     jnz    critsect_end
  1371.     cmp    cs:ctask_active,0
  1372.     stc
  1373.     jnz    critsect_end
  1374. ;
  1375.     inc    cs:critsect_active
  1376.     push    ax
  1377.     push    bx
  1378.     push    cx
  1379.     push    dx
  1380.     push    ds
  1381.     push    es
  1382.     mov    ds,cs:tsk_dgroup
  1383.     les    bx,tsk_glob_rec.current_task
  1384.     mov    word ptr cs:crit_task,bx
  1385.     mov    word ptr cs:crit_task+2,es
  1386. ;    or    es:flags[bx],F_CRIT    ;??
  1387.     mov    ax,offset critical
  1388.     push    ds
  1389.     push    ax
  1390.     call    set_flag
  1391.     add    sp,4
  1392.     pop    es
  1393.     pop    ds
  1394.     pop    dx
  1395.     pop    cx
  1396.     pop    bx
  1397.     pop    ax
  1398.     clc
  1399. critsect_end:
  1400.     ret    2
  1401. ;
  1402. csi1:
  1403.     cmp    ax,8701h    ; Leave critical region
  1404.     jne    csi2
  1405.     mov    cs:critsect_active,0
  1406.     push    ax
  1407.     push    bx
  1408.     push    cx
  1409.     push    dx
  1410.     push    ds
  1411.     push    es
  1412.     mov    ds,cs:tsk_dgroup
  1413.     les    bx,tsk_glob_rec.current_task
  1414. ;    and    es:flags[bx],NOT F_CRIT
  1415.     mov    ax,offset critical
  1416.     push    ds
  1417.     push    ax
  1418.     call    clear_flag
  1419.     add    sp,4
  1420.     pop    es
  1421.     pop    ds
  1422.     pop    dx
  1423.     pop    cx
  1424.     pop    bx
  1425.     pop    ax
  1426. csi2:
  1427.     iret
  1428. ;
  1429. critsectint    endp
  1430. ;
  1431. ;---------------------------------------------------------------------------
  1432. ;---------------------------------------------------------------------------
  1433. ;
  1434. ;    tsk_emergency_exit is entered by DOS when a task group exits
  1435. ;    without releasing the current group.
  1436. ;    Registers are set up, remove_group is called, and the program
  1437. ;    is terminated by jumping to the terminate_address.
  1438. ;
  1439. tsk_emergency_exit    proc    far
  1440. ;
  1441.     pushf
  1442.     sub    sp,4        ; make room for return addr
  1443.     push    bp
  1444.     mov    bp,sp
  1445.     push    ax
  1446.     push    bx
  1447.     push    cx
  1448.     push    dx
  1449.     push    si
  1450.     push    di
  1451.     push    ds
  1452.     push    es
  1453.     mov    ds,cs:tsk_dgroup
  1454. ;
  1455.     les    bx,tsk_global
  1456.     les    bx,es:current_task[bx] 
  1457.     les    bx,es:tgroup[bx]
  1458.     mov    ax,word ptr es:grp_exit_addr[bx]
  1459.     mov    2[bp],ax
  1460.     mov    ax,word ptr es:grp_exit_addr+2[bx]
  1461.     mov    4[bp],ax
  1462. ;
  1463.     xor    ax,ax
  1464.     push    ax
  1465.     push    es
  1466.     push    bx
  1467.     call    tsk_remove_group
  1468.     add    sp,6
  1469. ;
  1470.     mov    dx,offset group_term_msg
  1471.         cmp    ax,0
  1472.     je    emergency_end
  1473.     jb    pg_fatal
  1474.     mov    dx,offset term_err_msg
  1475. ;
  1476. emergency_end:
  1477. ;
  1478.     mov    ah,9
  1479.     int    21h
  1480. ;
  1481.     pop    es
  1482.     pop    ds
  1483.     pop    di
  1484.     pop    si
  1485.     pop    dx
  1486.     pop    cx
  1487.     pop    bx
  1488.     pop    ax
  1489.     pop    bp
  1490.     iret
  1491. ;
  1492. pg_fatal:
  1493.     mov    si,offset gcb_mixup_err
  1494.     jmp    short fatal_error
  1495. ;
  1496. tsk_emergency_exit    endp
  1497. ;
  1498. ;--------------------------------------------------------------------------
  1499. ;
  1500. ;    fatal_error can be called if the system can't continue for
  1501. ;    some reason. It issues an error message and halts the system.
  1502. ;    DS:SI must point to the '$'-terminated error message.
  1503. ;
  1504. fatal_error:
  1505.     IF    IBM
  1506.     xor    ax,ax
  1507.     int    10h        ; re-init display
  1508. fatal_loop:
  1509.     lodsb
  1510.     cmp    al,'$'
  1511.     je    fatal_end
  1512.         mov     bx,7
  1513.         mov     ah,14
  1514.     int    10h
  1515.     jmp    fatal_loop
  1516.     ELSE
  1517.     mov    dx,si
  1518.     mov    ah,9
  1519.     calldos
  1520.     ENDIF
  1521. fatal_end:
  1522.     sti
  1523.     jmp    fatal_end
  1524. ;
  1525. ;---------------------------------------------------------------
  1526. ;
  1527. tsk_free_mem    proc    near owner: word
  1528. ;
  1529.     mov    ah,51h
  1530.     int    21h
  1531.     push    bx            ; save current PSP
  1532.     mov    bx,owner
  1533.     mov    ah,50h
  1534.     int    21h            ; set new PSP
  1535. ;
  1536. free_beg:
  1537.     mov    ah,52h
  1538.     int    21h            ; get DOS invars
  1539.     mov    dx,es:[bx-2]        ; start of MCB chain
  1540.     mov    bx,owner
  1541. ;
  1542. free_loop:
  1543.     mov    es,dx
  1544.     cmp    es:[mcb_owner],bx
  1545.     jne    free_next
  1546. ;
  1547. ;    If we have released a block, we restart at the beginning of the
  1548. ;    MCB chain, since DOS might merge blocks, thereby invalidating
  1549. ;    our pointers. In the current versions of DOS, this seems to be
  1550. ;    an unneccessary precaution, but you never know...
  1551. ;
  1552.     inc    dx
  1553.     mov    es,dx
  1554.     mov    ah,49h            ; free memory block
  1555.     int    21h
  1556.     jmp    free_beg
  1557. ;
  1558. free_next:
  1559.     cmp    es:[mcb_id],'Z'        ; end of chain ?
  1560.     je    free_end        ; then exit
  1561.     add    dx,es:[mcb_len]
  1562.     inc    dx            ; point to next
  1563.     jmp    free_loop
  1564. ;
  1565. free_end:
  1566.     pop    bx
  1567.     mov    ah,50h
  1568.     int    21h            ; restore PSP
  1569.     ret
  1570. ;
  1571. tsk_free_mem    endp
  1572. ;
  1573.     .tsk_ecode
  1574.         end
  1575.  
  1576.