home *** CD-ROM | disk | FTP | other *** search
- ;
- ; --- Version 2.0 89-12-13 17:57 ---
- ;
- ; CTask - DOS access module.
- ;
- ; Public Domain Software written by
- ; Thomas Wagner
- ; Patschkauer Weg 31
- ; D-1000 Berlin 33
- ; West Germany
- ;
- ;
- ; The DOS interrupt (and the related direct disk I/O interrupts) are
- ; not reentrant. Access to DOS thus has to be channelled such that no
- ; two tasks use DOS services simultaneously. However, there is one
- ; exception to this rule. Whenever DOS is waiting for the keyboard, it
- ; issues a special interrupt, INT 28h, to signal that background
- ; processing for functions > 0Ch may be performed. This is used in the
- ; DOS interface for CTask in the following manner:
- ;
- ; A task issuing a DOS interrupt will request one of two resources:
- ; "lower_dos" for functions <= 0C, "upper_dos" for functions > 0C.
- ; If a task gets access to "lower_dos", it will also request the
- ; "upper_dos" resource to lock out other tasks from interrupting.
- ; This "upper_dos" resource is shortly released on each INT 28, and
- ; then immediately reclaimed, with task priority temporarily raised
- ; to the maximum value. The first task waiting to execute a
- ; function > 0C will thus be scheduled to execute the request, but
- ; the resource will be reassigned to the INT 28 handler as soon as
- ; this request terminates, so the waiting task will not be delayed too
- ; long.
- ;
- ; There are two additional safety measures which have to be taken to
- ; avoid getting into conflicts with other resident background programs,
- ; especially the DOS PRINT background spooler:
- ;
- ; Before requesting any resource, the status of the DOS critical section
- ; flag is checked. If this flag is set, the task is made waiting for
- ; the flag to be cleared.
- ; Only the task that set the flag will be allowed access to DOS.
- ;
- ; Before actually executing the request, the status of the DOS in-use
- ; flag is checked. If this flag is set, the task enters a busy waiting
- ; loop, calling the scheduler so that the processor is not tied up.
- ;
- ; NOTE: The method for checking the status of DOS is described in-depth
- ; in the book "The MS-DOS Encyclopedia" from Microsoft Press, in
- ; the chapter on TSR programming. The logic in this module was
- ; developed without the help of this book, so if you compare
- ; the code here with the routines in the Encyclopedia, you may
- ; notice that not all re-entry conditions are checked here.
- ; According to my experience with debugging TSR's and CTask, the
- ; logic should be sufficient for all but the most obscure TSR's.
- ; If you want to be completely on the safe side, you might consider
- ; adding the more thorough checks listed in the Encyclopedia.
- ;
- ;
- name tskdos
- ;
- .model large,c
- ;
- public tsk_install_dos
- public tsk_remove_dos
- public tsk_resident
- public tsk_emergency_exit
- public tsk_free_mem
- ;
- include tsk.mac
- ;
- extrn create_resource: far
- extrn delete_resource: far
- extrn request_resource: far
- extrn release_resource: far
- extrn create_flag: far
- extrn delete_flag: far
- extrn set_flag: far
- extrn clear_flag: far
- extrn wait_flag_clear: far
- extrn tsk_scheduler: far
- ;
- extrn tsk_dgroup: word
- ;
- ;
- CSECT = 2ah ; Critical Section Interrupt
- get_in_use_flag = 34h ; DOS-function to get in_use_flag address
- get_invars = 5d06h ; DOS-function to get DOS-variables area
- ;
- psp_offset = 10h ; Offset of current PSP in DOS save area
- ;
- ; Structure of the start of a PSP, including undocumented fields
- ;
- psp_record struc
- ;
- dw ? ; INT 20
- dw ? ; alloc block end
- db ? ; reserved
- db 5 dup(?) ; system call
- psp_exit_addr dd ? ; exit routine address
- psp_ctlc_addr dd ? ; control C routine address
- psp_cerr_addr dd ? ; critical error routine address
- parent_psp dw ? ; PSP of parent process
- db 20 dup(?) ; files table
- psp_envseg dw ? ; environment segment
- psp_ustack dd ? ; ss/sp of caller
- dw ? ; file table length
- dd ? ; file table pointer
- dd ? ; pointer to nested PSP (?)
- ;
- psp_record ends
- ;
- ;
- ; Structure of a DOS MCB (Memory Control Block)
- ;
- mcbstruc struc
- ;
- mcb_id db ?
- mcb_owner dw ?
- mcb_len dw ?
- ;
- mcbstruc ends
- ;
- ;
- intseg segment at 0
- org 10h*4
- vidoff dw ? ; video interrupt
- vidseg dw ?
- org 13h*4
- diskoff dw ? ; disk i/o interrupt
- diskseg dw ?
- org 20h*4
- termoff dw ? ; program terminate vector
- termseg dw ?
- org 21h*4
- idosoff dw ? ; dos interrupt
- idosseg dw ?
- org 25h*4
- absreadoff dw ? ; absolute disk read
- absreadseg dw ?
- org 26h*4
- abswriteoff dw ? ; absolute disk write
- abswriteseg dw ?
- org 27h*4
- keepoff dw ? ; Terminate but stay resident
- keepseg dw ?
- org 28h*4
- idleoff dw ? ; dos idle interrupt
- idleseg dw ?
- org CSECT*4
- csectoff dw ? ; dos critical section
- csectseg dw ?
- ;
- intseg ends
- ;
- ;----------------------------------------------------------------------------
- ;
- ; Variables
- ;
- .tsk_data
- ;
- extrn tsk_glob_rec: word ; glob_rec
- extrn tsk_global: dword
- extrn tsk_instflags: word
- extrn tsk_version: byte
- ;
- term_err_msg db 0dh,0ah,"Program terminated - CTask uninstalled"
- db 0dh,0ah,'$'
- ;
- group_term_msg db 0dh,0ah,"Program terminated - Task Group removed"
- db 0dh,0ah,'$'
- ;
- gcb_mixup_err db 0dh,0ah,"Group chain damaged - System halted"
- db 07h,'$'
- ;
- idle_active db 0 ; Idle-Interrupt active
- dos310 db 0 ; DOS version >= 3.10
- ;
- IF TSK_NAMEPAR
- udos_name db "DOSUPPER",0
- ldos_name db "DOSLOWER",0
- cdos_name db "DOSCRIT",0
- hdio_name db "HARDDISK",0
- fdio_name db "FLEXDISK",0
- vid_name db "VIDEO",0
- ENDIF
- ;
- ;
- in_use dd ? ; Adress of DOS in-use-flag
- in_error dd ? ; Adress of DOS error-mode-flag
- ;
- lower_dos resource <>
- upper_dos resource <>
- hdisk_io resource <>
- fdisk_io resource <>
- video resource <>
- critical flag <>
- ;
- ;
- .tsk_edata
- .tsk_code
- ;
- extrn tsk_switch_stack: near
- extrn tsk_old_stack: near
- extrn tsk_remove_group: near
- ;
- ;---------------------------------------------------------------------------
- ;
- ; Original Interrupt-Entries
- ;
- savvid label dword ; original Video entry
- savvidoff dw ?
- savvidseg dw ?
- ;
- savdisk label dword ; original Disk I/O entry
- savdiskoff dw ?
- savdiskseg dw ?
- ;
- savtermoff dw ? ; Terminate vector save
- savtermseg dw ?
- ;
- savdos label dword ; original DOS-Entry
- savdosoff dw ?
- savdosseg dw ?
- ;
- savidle label dword ; original IDLE-Entry
- savidleoff dw ?
- savidleseg dw ?
- ;
- savcsect label dword ; Critical Section save
- savcsectoff dw ?
- savcsectseg dw ?
- ;
- savabsread label dword ; Absolute Disk Read save
- savabsreadoff dw ?
- savabsreadseg dw ?
- ;
- savabswrite label dword ; Absolute Disk Write save
- savabswriteoff dw ?
- savabswriteseg dw ?
- ;
- savkeepoff dw ? ; Terminate resident vector save
- savkeepseg dw ?
- ;
- critsect_active db 0 ; DOS Critical Section active
- ctask_active db 0 ; CTask DOS call active
- crit_task dd ? ; Task requesting critical section
- ;
- dos_version dw ? ; DOS version
- ;
- temp_1 dw ?
- temp_2 dw ?
- temp_3 dw ?
- ;
- xsp_sp dw ?
- xsp_ss dw ?
- xsp_ip dw ?
- xsp_cs dw ?
- ;
- ;
- calldos macro
- pushf
- cli
- call cs:savdos
- endm
- ;
- ;---------------------------------------------------------------------------
- ;
- tsk_resident proc near uses si di ds
- ;
- mov ds,cs:tsk_dgroup
- ;
- mov dx,offset tsk_version
- mov bx,1234h
- mov ax,3000h
- int 21h
- mov di,bx
- mov es,cx
- mov si,offset tsk_version
- mov cx,8
- repe cmpsb
- jcxz tr_is_res
- xor bx,bx
- mov es,bx
- tr_is_res:
- mov ax,bx
- mov dx,es
- ret
- ;
- tsk_resident endp
- ;
- ;---------------------------------------------------------------------------
- ;
- ; void tsk_install_dos (void)
- ;
- ; Install DOS handler
- ;
- tsk_install_dos proc near uses ds
- ;
- ; create needed resources & flags
- ;
- mov ds,cs:tsk_dgroup
- ;
- IF TSK_NAMEPAR
- mov ax,offset udos_name
- push ds
- push ax
- ENDIF
- mov ax,offset upper_dos
- push ds
- push ax
- call create_resource
- IF TSK_NAMEPAR
- add sp,8
- ELSE
- add sp,4
- ENDIF
- ;
- IF TSK_NAMEPAR
- mov ax,offset ldos_name
- push ds
- push ax
- ENDIF
- mov ax,offset lower_dos
- push ds
- push ax
- call create_resource
- IF TSK_NAMEPAR
- add sp,8
- ELSE
- add sp,4
- ENDIF
- ;
- test tsk_instflags,IFL_DISK
- jz inst_nodsk1
- IF TSK_NAMEPAR
- mov ax,offset hdio_name
- push ds
- push ax
- ENDIF
- mov ax,offset hdisk_io
- push ds
- push ax
- call create_resource
- IF TSK_NAMEPAR
- add sp,8
- ELSE
- add sp,4
- ENDIF
- ;
- IF TSK_NAMEPAR
- mov ax,offset fdio_name
- push ds
- push ax
- ENDIF
- mov ax,offset fdisk_io
- push ds
- push ax
- call create_resource
- IF TSK_NAMEPAR
- add sp,8
- ELSE
- add sp,4
- ENDIF
- ;
- inst_nodsk1:
- test tsk_instflags,IFL_VIDEO
- jz inst_novid1
- IF TSK_NAMEPAR
- mov ax,offset vid_name
- push ds
- push ax
- ENDIF
- mov ax,offset video
- push ds
- push ax
- call create_resource
- IF TSK_NAMEPAR
- add sp,8
- ELSE
- add sp,4
- ENDIF
- ;
- inst_novid1:
- IF TSK_NAMEPAR
- mov ax,offset cdos_name
- push ds
- push ax
- ENDIF
- mov ax,offset critical
- push ds
- push ax
- call create_flag
- IF TSK_NAMEPAR
- add sp,8
- ELSE
- add sp,4
- ENDIF
- ;
- ; Get address and length of the DOS internal variable area.
- ; This call is not documented, and not available in versions
- ; prior to 3.1. It returns the address of the area in DS:SI,
- ; and the length of the area that must be swapped between calls
- ; from different groups in DX.
- ; Additionally, the total length of the area, including
- ; the DOS-stacks, minus the length in DX, is returned in CX.
- ;
- mov tsk_glob_rec.l_swap,0
- test tsk_instflags,IFL_NODOSVARS
- jnz no_invars
- ;
- push ds
- mov ax,get_invars
- int 21h
- mov ax,ds
- pop ds
- mov word ptr tsk_glob_rec.dos_vars,si
- mov word ptr tsk_glob_rec.dos_vars+2,ax
- mov tsk_glob_rec.l_swap,dx
- ;
- ; Get the address of DOS's in_use-flag. This flag indicates that
- ; DOS is already active. This might happen if there are other
- ; background tasks, like popups or print spoolers, active in
- ; parallel to CTask.
- ; This is also the address of the critical error flag in DOS. Beginning
- ; with DOS 3.10 the flag is located one byte before the in_use_flag.
- ; With older DOS versions, we would have to search through DOS for the
- ; address. This is omitted here, but you could include the code
- ; for pre 3.1 versions from pages 378-379 of the MS-DOS Encyclopedia.
- ;
- no_invars:
- mov ah,get_in_use_flag
- int 21h
- mov word ptr in_use,bx
- mov word ptr in_use+2,es
- mov word ptr in_error+2,es
- ;
- push bx
- mov ah,30h
- int 21h
- pop bx
- mov cs:dos_version,ax
- cmp al,3
- jb not_dos3
- cmp al,0ah
- je not_dos3 ; OS/2 compatibility box
- cmp al,3
- jne is_dos3 ; DOS 4.x
- cmp ah,10
- jb not_dos3
- is_dos3:
- inc dos310
- dec bx
- mov word ptr in_error,bx
- jmp short save_ints
- ;
- not_dos3:
- ;
- ; Save old interrupt vectors
- ;
- save_ints:
- push es
- xor ax,ax
- mov es,ax
- ;
- assume es:intseg
- ;
- test tsk_instflags,IFL_VIDEO
- jz inst_novid2
- mov ax,vidoff ; video
- mov savvidoff,ax
- mov ax,vidseg
- mov savvidseg,ax
- ;
- inst_novid2:
- test tsk_instflags,IFL_DISK
- jz inst_nodsk2
- mov ax,diskoff ; Disk I/O
- mov savdiskoff,ax
- mov ax,diskseg
- mov savdiskseg,ax
- ;
- inst_nodsk2:
- mov ax,termoff ; DOS
- mov savtermoff,ax
- mov ax,termseg
- mov savtermseg,ax
- ;
- mov ax,idosoff ; DOS
- mov savdosoff,ax
- mov ax,idosseg
- mov savdosseg,ax
- ;
- mov ax,idleoff ; IDLE
- mov savidleoff,ax
- mov ax,idleseg
- mov savidleseg,ax
- ;
- mov ax,csectoff ; Critical Section
- mov savcsectoff,ax
- mov ax,csectseg
- mov savcsectseg,ax
- ;
- mov ax,absreadoff ; Absolute Disk read
- mov savabsreadoff,ax
- mov ax,absreadseg
- mov savabsreadseg,ax
- ;
- mov ax,abswriteoff ; Absolute Disk write
- mov savabswriteoff,ax
- mov ax,abswriteseg
- mov savabswriteseg,ax
- ;
- mov ax,keepoff ; Terminate Resident
- mov savkeepoff,ax
- mov ax,keepseg
- mov savkeepseg,ax
- ;
- ; Enter new Interrupt-Entries
- ;
- cli
- test tsk_instflags,IFL_VIDEO
- jz inst_novid3
- mov vidoff,offset videntry ; Video Entry
- mov vidseg,cs
- ;
- inst_novid3:
- test tsk_instflags,IFL_DISK
- jz inst_nodsk3
- mov diskoff,offset diskentry ; Disk I/O Entry
- mov diskseg,cs
- ;
- inst_nodsk3:
- mov idosoff,offset dosentry ; DOS-Entry
- mov idosseg,cs
- mov idleoff,offset idleentry ; Idle-Entry
- mov idleseg,cs
- mov termoff,offset terminate_int ; Terminate Process Entry
- mov termseg,cs
- mov csectoff,offset critsectint ; Critical Section Entry
- mov csectseg,cs
- mov keepoff,offset keep_int ; Keep Process Entry
- mov keepseg,cs
- mov absreadoff,offset absread_int ; Absolute Disk Read Entry
- mov absreadseg,cs
- mov abswriteoff,offset abswrite_int ; Absolute Disk Write Entry
- mov abswriteseg,cs
- sti
- ;
- assume es:nothing
- ;
- pop es
- ret
- ;
- ;
- tsk_install_dos endp
- ;
- ;
- ; void tsk_remove_dos (void)
- ;
- ; Un-install DOS handler
- ;
- tsk_remove_dos proc near uses ds
- ;
- mov ds,cs:tsk_dgroup
- ;
- ; Delete resources & flags
- ;
- mov ax,offset upper_dos
- push ds
- push ax
- call delete_resource
- add sp,4
- ;
- mov ax,offset lower_dos
- push ds
- push ax
- call delete_resource
- add sp,4
- ;
- test tsk_instflags,IFL_DISK
- jz rem_nodsk1
- mov ax,offset hdisk_io
- push ds
- push ax
- call delete_resource
- add sp,4
- ;
- mov ax,offset fdisk_io
- push ds
- push ax
- call delete_resource
- add sp,4
- ;
- rem_nodsk1:
- test tsk_instflags,IFL_VIDEO
- jz rem_novid1
- mov ax,offset video
- push ds
- push ax
- call delete_resource
- add sp,4
- ;
- rem_novid1:
- mov ax,offset critical
- push ds
- push ax
- call delete_flag
- add sp,4
- ;
- push es
- xor ax,ax
- mov es,ax
- ;
- assume es:intseg
- ;
- ; Restore interrupt entries
- ;
- cli
- test tsk_instflags,IFL_VIDEO
- jz rem_novid2
- mov ax,savvidoff
- mov vidoff,ax
- mov ax,savvidseg
- mov vidseg,ax
- ;
- rem_novid2:
- test tsk_instflags,IFL_DISK
- jz rem_nodsk2
- mov ax,savdiskoff
- mov diskoff,ax
- mov ax,savdiskseg
- mov diskseg,ax
- ;
- rem_nodsk2:
- mov ax,savtermoff
- mov termoff,ax
- mov ax,savtermseg
- mov termseg,ax
- ;
- mov ax,savdosoff
- mov idosoff,ax
- mov ax,savdosseg
- mov idosseg,ax
- ;
- mov ax,savidleoff
- mov idleoff,ax
- mov ax,savidleseg
- mov idleseg,ax
- ;
- mov ax,savcsectoff
- mov csectoff,ax
- mov ax,savcsectseg
- mov csectseg,ax
- ;
- mov ax,savabsreadoff
- mov absreadoff,ax
- mov ax,savabsreadseg
- mov absreadseg,ax
- ;
- mov ax,savabswriteoff
- mov abswriteoff,ax
- mov ax,savabswriteseg
- mov abswriteseg,ax
- ;
- mov ax,savkeepoff
- mov keepoff,ax
- mov ax,savkeepseg
- mov keepseg,ax
- ;
- sti
- ;
- pop es
- ret
- ;
- assume es:nothing
- ;
- tsk_remove_dos endp
- ;
- ;
- ;---------------------------------------------------------------------------
- ;---------------------------------------------------------------------------
- ;
- ;
- ; INT 10: Video BIOS interrupt
- ;
- videntry proc far
- ;
- call tsk_switch_stack
- xor ax,ax
- push ax
- push ax
- push ds
- mov ax,offset video
- push ax
- call request_resource
- add sp,8
- push caller_flags[bp]
- popf
- call tsk_old_stack
- pushf
- cli
- call savvid
- call tsk_switch_stack
- mov ax,entry_flags[bp]
- mov caller_flags[bp],ax
- push ds
- mov ax,offset video
- push ax
- call release_resource
- add sp,4
- iret
- ;
- videntry endp
- ;
- ;---------------------------------------------------------------------------
- ;
- ;
- ; INT 13: Disk I/O BIOS interrupt
- ;
- diskentry proc far
- ;
- call tsk_switch_stack
- xor ax,ax
- push ax
- push ax
- push ds
- test dl,80h ; fixed disk ?
- jz disk_floppy ; jump if not
- mov ax,offset hdisk_io
- push ax
- call request_resource
- add sp,8
- push caller_flags[bp]
- popf
- call tsk_old_stack
- pushf
- cli
- call savdisk
- call tsk_switch_stack
- mov ax,entry_flags[bp]
- mov caller_flags[bp],ax
- push ds
- mov ax,offset hdisk_io
- push ax
- call release_resource
- add sp,4
- iret
- ;
- disk_floppy:
- mov ax,offset fdisk_io
- push ax
- call request_resource
- add sp,8
- push caller_flags[bp]
- popf
- call tsk_old_stack
- pushf
- cli
- call savdisk
- call tsk_switch_stack
- mov ax,entry_flags[bp]
- mov caller_flags[bp],ax
- push ds
- mov ax,offset fdisk_io
- push ax
- call release_resource
- add sp,4
- iret
- ;
- diskentry endp
- ;
- ;---------------------------------------------------------------------------
- ;
- ; Stack-Offsets relative to BP
- ;
- d_func = -2
- ;
- ;---------------------------------------------------------------------------
- ;
- ; INT 25: Absolute Disk Read
- ;
- ; This interrupt is channeled through the normal DOS-function
- ; processing, with function = 0x25 and special flag set.
- ; It is re-translated later after the necessary resources
- ; have been requested.
- ; Interrupts 25 und 26 leave the flag-word on the stack.
- ; Since flags are removed in normal processing, the flag-word
- ; has to be duplicated on the stack here.
- ;
- absread_int:
- sti
- push bp ; reserve space
- push bp ; save BP
- mov bp,sp
- push ax
- mov ax,4[bp] ; Move return offset, segment down
- mov 2[bp],ax
- mov ax,6[bp]
- mov 4[bp],ax
- mov ax,8[bp] ; duplicate flags
- mov 6[bp],ax
- pop ax
- pop bp
- call tsk_switch_stack
- mov ax,2501h
- mov cx,ax
- jmp short dosentry_2
- ;
- ;
- ;---------------------------------------------------------------------------
- ;
- ; INT 26: Absolute Disk Write
- ;
- ; This interrupt is channeled through the normal DOS-function
- ; processing, with function = 0x26 and special flag set.
- ; It is re-translated later after the necessary resources
- ; have been requested.
- ; Interrupts 25 und 26 leave the flag-word on the stack.
- ; Since flags are removed in normal processing, the flag-word
- ; has to be duplicated on the stack here.
- ;
- abswrite_int:
- sti
- push bp ; reserve space
- push bp ; save BP
- mov bp,sp
- push ax
- mov ax,4[bp] ; Move return offset, segment down
- mov 2[bp],ax
- mov ax,6[bp]
- mov 4[bp],ax
- mov ax,8[bp] ; duplicate flags
- mov 6[bp],ax
- pop ax
- pop bp
- call tsk_switch_stack
- mov ax,2601h
- mov cx,ax
- jmp short dosentry_2
- ;
- ;---------------------------------------------------------------------------
- ;
- ; INT 27: Terminate But Stay Resident Interrupt
- ;
- ; This interrupt is translated to INT 21, function 31.
- ;
- keep_int:
- call tsk_switch_stack
- ;
- add dx,0fh ; last addr + 0f to round
- sub dx,caller_cs[bp] ; minus CS (= PSP)
- mov cl,4
- shr dx,cl ; div 16 = paragraphs
-
- mov ax,3100h ; Keep process
- mov save_ax[bp],ax
- mov cx,ax
- jmp short dosentry_2
- ;
- ;---------------------------------------------------------------------------
- ;
- ; INT 20: Terminate Program interrupt
- ;
- ; This interrupt is translated to INT 21, function 4c.
- ;
- terminate_int:
- call tsk_switch_stack
- mov ax,4c00h
- mov save_ax[bp],ax
- mov cx,ax
- jmp short dosentry_2
- ;
- ;---------------------------------------------------------------------------
- ;
- ; INT 21: DOS-Interrupt
- ;
- dosentry proc far
- ;
- call tsk_switch_stack
- xor cl,cl
- mov ch,ah
- ;
- dosentry_2:
- push cx ; BP-2: func in CH, special flag in CL
- ;
- ; Check if this is a special 'get dos version' call.
- ;
- or cl,cl
- jnz dosent_x ; no function check if special
- cmp ax,3000h
- jne no_spdos
- cmp bx,1234h
- jne no_spdos
- push ds
- mov si,dx
- mov ds,save_ds[bp]
- mov di,offset tsk_glob_rec
- mov cx,8
- repe cmpsb
- pop ds
- jcxz is_spdos
- jmp short no_spdos
- ;
- ; Special version call returns global variable block address
- ;
- is_spdos:
- add sp,2
- call tsk_old_stack
- mov ax,cs:dos_version
- mov bx,offset tsk_glob_rec
- mov cx,cs:tsk_dgroup
- iret
- ;
- ; Here we check if the DOS critical region is active.
- ; If yes, this means that some outside background process has
- ; started DOS (most likely DOS PRINT).
- ; To avoid busy waiting, we wait for the "critical" flag to be
- ; cleared, if this is *not* the task that set the flag.
- ; The task that set the critical flag is *not* made waiting.
- ;
- no_spdos:
- mov ax,d_func[bp]
- or ah,ah ; terminate?
- jne dosent_x
- mov save_ax[bp],4c00h ; translate to fn 4c, retcode 0
- mov d_func[bp],4c00h
- dosent_x:
- ;
- cmp cs:critsect_active,0
- je no_crit
- mov ax,word ptr cs:crit_task
- cmp word ptr tsk_glob_rec.current_task,ax
- jne wait_crit
- mov ax,word ptr cs:crit_task+2
- cmp word ptr tsk_glob_rec.current_task+2,ax
- je no_crit
- ;
- wait_crit:
- xor ax,ax
- push ax
- push ax
- mov ax,offset critical
- push ds
- push ax
- call wait_flag_clear
- add sp,8
- ;
- no_crit:
- mov cs:ctask_active,1 ; mark that we are active
- sti ; Interrupts allowed now
- ;
- ;
- ; Now let's check if the current task owns one of the dos-resources.
- ; This may happen on
- ; - terminate (TSR or normal)
- ; - spawn process
- ; - critical error/break
- ; - redirection of INT 28 to out-of-CTask routine
- ; If the task owns one, and the dos-flags are clear,
- ; the resource is released.
- ; If the dos-flags are nonzero, the resource is not
- ; released, but the task is allowed access to DOS regardless of
- ; resource and flag states.
- ; DL is used as an "emergency" marker. If nonzero, no resources
- ; are to be requested, and the in-dos flag is not checked.
- ;
- xor dl,dl
- les bx,tsk_glob_rec.current_task
- cli
- cmp es:t_indos[bx],0
- je no_reenter
- ;
- les bx,in_error
- mov dl,es:byte ptr [bx]
- les bx,in_use
- or dl,es:byte ptr [bx]
- jnz no_reenter
- ;
- les bx,tsk_glob_rec.current_task
- and es:t_indos[bx],NOT SPAWNING
- jz no_reenter
- ;
- test es:t_indos[bx],OWN_UPPER
- jz rel_lower
- xor es:t_indos[bx],OWN_UPPER
- mov bx,offset upper_dos
- push ds ; resource address
- push bx
- call release_resource
- add sp,4
- xor dl,dl
- les bx,tsk_glob_rec.current_task
- rel_lower:
- test es:t_indos[bx],OWN_LOWER
- jz no_reenter
- xor es:t_indos[bx],OWN_LOWER
- mov bx,offset lower_dos
- push ds ; resource address
- push bx
- call release_resource
- add sp,4
- xor dl,dl
- ;
- no_reenter:
- sti
- mov ax,d_func[bp]
- cmp ah,0ch
- jbe lower_funcs
- jmp upper_funcs
- ;
- ;
- ; Functions 00-0C
- ;
- lower_funcs:
- ;
- ; first, request the "lower_dos" resource
- ;
- or dl,dl
- jnz lower_emergency
- mov bx,offset lower_dos
- xor cx,cx
- push cx ; no timeout
- push cx
- push ds ; resource address
- push bx
- call request_resource
- add sp,8
- ;
- ; we have it, now let's get the upper_dos resource, too
- ;
- mov bx,offset upper_dos
- xor cx,cx
- push cx ; no timeout
- push cx
- push ds ; resource address
- push bx
- call request_resource
- add sp,8
- ;
- les bx,tsk_glob_rec.current_task
- mov es:t_indos[bx],OWN_UPPER or OWN_LOWER
- ;
- ; both resources gained, now we may execute the function if dos is free
- ;
- call wait_dos_free
- ;
- lower_emergency:
- add sp,2
- push caller_flags[bp]
- popf
- call tsk_old_stack
- ;
- calldos ; execute function
- ;
- ; Now we have to release the resources.
- ;
- call tsk_switch_stack
- ;
- les bx,in_error
- cmp es:byte ptr [bx],0
- jne no_relc
- ;
- mov bx,offset upper_dos
- push ds ; resource address
- push bx
- call release_resource
- add sp,4
- ;
- mov bx,offset lower_dos
- push ds ; resource address
- push bx
- call release_resource
- add sp,4
- ;
- les bx,tsk_glob_rec.current_task
- mov es:t_indos[bx],0
- ;
- ; If both resources are free now, clear the ctask_active flag to
- ; allow other background processes to gain access to DOS.
- ;
- cli
- cmp upper_dos.rcount,0
- jne no_relc
- cmp lower_dos.rcount,0
- jne no_relc
- mov cs:ctask_active,0
- no_relc:
- ;
- ; All done, restore registers and return.
- ;
- mov ax,entry_flags[bp]
- mov caller_flags[bp],ax
- iret
- ;
- ;--------------------------------------------------------------------------
- ;
- ; Functions 0D and above
- ;
- upper_funcs:
- or dl,dl
- jnz upper_emergency
- ;
- mov bx,offset upper_dos
- xor cx,cx
- push cx ; no timeout
- push cx
- push ds ; resource address
- push bx
- call request_resource
- add sp,8
- ;
- les bx,tsk_glob_rec.current_task
- mov es:t_indos[bx],OWN_UPPER
- ;
- ; resource gained, now we may execute the function if dos is free
- ;
- call wait_dos_free
- ;
- upper_emergency:
- cmp byte ptr d_func[bp],0
- jne no_term
- mov ax,save_ax[bp]
- cmp ah,31h ; terminate resident?
- jne ckfunc1
- jmp term_resident
- ckfunc1:
- cmp ax,4b00h ; spawn new process?
- jne ckfunc2
- jmp terminate
- ckfunc2:
- cmp ah,4ch ; terminate program?
- jne no_term
- jmp terminate
- ;
- no_term:
- ;
- ; Filter special-functions 25/26 (Absolute Read/Write)
- ;
- pop ax
- cmp ax,2501h
- jne uf_exec1
- push caller_flags[bp]
- popf
- call tsk_old_stack
- pushf
- cli
- call cs:savabsread
- pop cs:temp_1 ; remove flags
- jmp short uf_complete
- ;
- uf_exec1:
- cmp ax,2601h
- jne uf_exec2
- push caller_flags[bp]
- popf
- call tsk_old_stack
- pushf
- cli
- call cs:savabswrite
- pop cs:temp_1 ; remove flags
- jmp short uf_complete
- ;
- uf_exec2:
- push caller_flags[bp]
- popf
- call tsk_old_stack
- ;
- calldos ; execute function
- ;
- ; Now we have to release the resources.
- ;
- uf_complete:
- call tsk_switch_stack
- mov ax,entry_flags[bp]
- mov caller_flags[bp],ax
- ;
- ; if in_error or in_use is set, we do not release the resources.
- ;
- uf_relres:
- les bx,in_error
- cmp es:byte ptr [bx],0
- jne no_relc1
- les bx,in_use
- cmp es:byte ptr [bx],0
- jne no_relc1
- ;
- mov bx,offset upper_dos
- push ds ; resource address
- push bx
- call release_resource
- add sp,4
- ;
- les bx,tsk_glob_rec.current_task
- mov es:t_indos[bx],0
- ;
- ; If both resources are free now, clear the ctask_active flag to
- ; allow other background processes to gain access to DOS.
- ;
- cli
- cmp upper_dos.rcount,0
- jne no_relc1
- cmp lower_dos.rcount,0
- jne no_relc1
- mov cs:ctask_active,0
- ;
- ; All done, restore registers and return.
- ;
- no_relc1:
- iret
- ;
- ;--------------------------------------------------------------------------
- ;
- ; Terminate, TSR and Spawn calls go directly to DOS.
- ; TSR has to reset the exit address if it's the PSP of the
- ; current group, so the group is not deleted.
- ;
- term_resident:
- les bx,tsk_glob_rec.dos_vars
- mov ax,es:[bx+psp_offset] ; current PSP
- les bx,tsk_glob_rec.current_task
- les bx,es:tgroup[bx]
- cmp es:gcreate_psp[bx],ax
- jne terminate
- push ds
- mov ds,ax
- mov ax,word ptr es:grp_exit_addr[bx]
- mov word ptr ds:psp_exit_addr,ax
- mov ax,word ptr es:grp_exit_addr+2[bx]
- mov word ptr ds:psp_exit_addr+2,ax
- pop ds
- ;
- terminate:
- add sp,2
- push caller_flags[bp]
- popf
- call tsk_old_stack
- cli
- jmp cs:savdos
- ;
- dosentry endp
- ;
- ;--------------------------------------------------------------------------
- ;
- wait_dos_free proc near
- ;
- in_use_loop:
- cmp dos310,0 ; dos version < 3.10?
- je no_in_error ; then we don't check for in_error
- les bx,in_error
- cmp byte ptr es:[bx],0
- jne is_in_use
- no_in_error:
- cmp idle_active,0 ; idle interrupt active?
- je ck_inuse ; check for flag if no
- ret ; else return immediately
- ;
- ck_inuse:
- les bx,in_use
- cmp byte ptr es:[bx],0
- jne is_in_use
- ret
- ;
- is_in_use:
- pushf
- call tsk_scheduler
- jmp in_use_loop
- ;
- wait_dos_free endp
- ;
- ;----------------------------------------------------------------------------
- ;
- ; INT 28: DOS Idle Interrupt
- ;
- idleentry proc far
- ;
- call tsk_switch_stack
- ;
- ; Check if someone is waiting for upper_dos. If not, we can return
- ; immediately.
- ;
- les bx,upper_dos.rwaiting.q_first
- cmp es:q_kind[bx],0
- je idle_exit
- ;
- ; Also make sure this is not a second invocation of INT 28.
- ; Normally, this should never happen, but better safe than sorry.
- ;
- cmp idle_active,0
- jne idle_exit
- inc idle_active
- ;
- ; someone is waiting, let's please him by releasing the resource
- ;
- ; temporarily increase priority
- ;
- les bx,tsk_glob_rec.current_task
- push es:cqueue.q_el.q_prior[bx]
- push es:cqueue.q_el.q_ini_prior[bx]
- mov es:cqueue.q_el.q_prior[bx],0ffffh
- mov es:cqueue.q_el.q_ini_prior[bx],0ffffh
- push bx
- push es
- ;
- ; release resource & request it again
- ;
- mov ax,ds
- mov es,ax
- mov bx,offset upper_dos
- push ds
- push bx
- call release_resource
- add sp,4
- ;
- mov bx,offset upper_dos
- xor cx,cx
- push cx
- push cx
- push ds
- push bx
- call request_resource
- add sp,8
- ;
- ; ready, restore priority
- ;
- cli
- pop es
- pop bx
- pop es:cqueue.q_el.q_ini_prior[bx]
- pop es:cqueue.q_el.q_prior[bx]
- ;
- mov idle_active,0
- ;
- idle_exit:
- push caller_flags[bp]
- popf
- call tsk_old_stack
- cli
- ;
- jmp cs:savidle ; chain to original interrupt
- ;
- idleentry endp
- ;
- ;---------------------------------------------------------------------------
- ;
- ; INT 2A: DOS Critical Section Interrupt.
- ;
- ; Not documented.
- ; Is used by DOS PRINT to mark Critical Regions.
- ; Usage by PRINT:
- ; AX = 8700 - Begin Critical Region
- ; Returns:
- ; Carry set if already active.
- ; AX = 8701 - End Critical Region
- ;
- ; Both these functions are handled here.
- ;
- ; Other usage in DOS, function unknown:
- ; AH = 82 (AL undefined)
- ; seems to be called on DOS-Functions > 0C
- ; AH = 84 (AL undefined)
- ; seems to be called when DOS is idle
- ;
- ; These functions are currently ignored.
- ;
- critsectint proc far
-
- cmp ax,8700h ; Enter critical region
- jne csi1
- cmp cs:critsect_active,0
- stc
- jnz critsect_end
- cmp cs:ctask_active,0
- stc
- jnz critsect_end
- ;
- inc cs:critsect_active
- push ax
- push bx
- push cx
- push dx
- push ds
- push es
- mov ds,cs:tsk_dgroup
- les bx,tsk_glob_rec.current_task
- mov word ptr cs:crit_task,bx
- mov word ptr cs:crit_task+2,es
- ; or es:flags[bx],F_CRIT ;??
- mov ax,offset critical
- push ds
- push ax
- call set_flag
- add sp,4
- pop es
- pop ds
- pop dx
- pop cx
- pop bx
- pop ax
- clc
- critsect_end:
- ret 2
- ;
- csi1:
- cmp ax,8701h ; Leave critical region
- jne csi2
- mov cs:critsect_active,0
- push ax
- push bx
- push cx
- push dx
- push ds
- push es
- mov ds,cs:tsk_dgroup
- les bx,tsk_glob_rec.current_task
- ; and es:flags[bx],NOT F_CRIT
- mov ax,offset critical
- push ds
- push ax
- call clear_flag
- add sp,4
- pop es
- pop ds
- pop dx
- pop cx
- pop bx
- pop ax
- csi2:
- iret
- ;
- critsectint endp
- ;
- ;---------------------------------------------------------------------------
- ;---------------------------------------------------------------------------
- ;
- ; tsk_emergency_exit is entered by DOS when a task group exits
- ; without releasing the current group.
- ; Registers are set up, remove_group is called, and the program
- ; is terminated by jumping to the terminate_address.
- ;
- tsk_emergency_exit proc far
- ;
- pushf
- sub sp,4 ; make room for return addr
- push bp
- mov bp,sp
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es
- mov ds,cs:tsk_dgroup
- ;
- les bx,tsk_global
- les bx,es:current_task[bx]
- les bx,es:tgroup[bx]
- mov ax,word ptr es:grp_exit_addr[bx]
- mov 2[bp],ax
- mov ax,word ptr es:grp_exit_addr+2[bx]
- mov 4[bp],ax
- ;
- xor ax,ax
- push ax
- push es
- push bx
- call tsk_remove_group
- add sp,6
- ;
- mov dx,offset group_term_msg
- cmp ax,0
- je emergency_end
- jb pg_fatal
- mov dx,offset term_err_msg
- ;
- emergency_end:
- ;
- mov ah,9
- int 21h
- ;
- pop es
- pop ds
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- pop bp
- iret
- ;
- pg_fatal:
- mov si,offset gcb_mixup_err
- jmp short fatal_error
- ;
- tsk_emergency_exit endp
- ;
- ;--------------------------------------------------------------------------
- ;
- ; fatal_error can be called if the system can't continue for
- ; some reason. It issues an error message and halts the system.
- ; DS:SI must point to the '$'-terminated error message.
- ;
- fatal_error:
- IF IBM
- xor ax,ax
- int 10h ; re-init display
- fatal_loop:
- lodsb
- cmp al,'$'
- je fatal_end
- mov bx,7
- mov ah,14
- int 10h
- jmp fatal_loop
- ELSE
- mov dx,si
- mov ah,9
- calldos
- ENDIF
- fatal_end:
- sti
- jmp fatal_end
- ;
- ;---------------------------------------------------------------
- ;
- tsk_free_mem proc near owner: word
- ;
- mov ah,51h
- int 21h
- push bx ; save current PSP
- mov bx,owner
- mov ah,50h
- int 21h ; set new PSP
- ;
- free_beg:
- mov ah,52h
- int 21h ; get DOS invars
- mov dx,es:[bx-2] ; start of MCB chain
- mov bx,owner
- ;
- free_loop:
- mov es,dx
- cmp es:[mcb_owner],bx
- jne free_next
- ;
- ; If we have released a block, we restart at the beginning of the
- ; MCB chain, since DOS might merge blocks, thereby invalidating
- ; our pointers. In the current versions of DOS, this seems to be
- ; an unneccessary precaution, but you never know...
- ;
- inc dx
- mov es,dx
- mov ah,49h ; free memory block
- int 21h
- jmp free_beg
- ;
- free_next:
- cmp es:[mcb_id],'Z' ; end of chain ?
- je free_end ; then exit
- add dx,es:[mcb_len]
- inc dx ; point to next
- jmp free_loop
- ;
- free_end:
- pop bx
- mov ah,50h
- int 21h ; restore PSP
- ret
- ;
- tsk_free_mem endp
- ;
- .tsk_ecode
- end
-
-