home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_progs / prog_c / suplib.lzh / SUPLIB / SRC / LWP.ASM < prev    next >
Assembly Source File  |  1991-08-16  |  16KB  |  469 lines

  1.  
  2.         ;   LWP.ASM V1.03 22 December 1988
  3.         ;   Matthew Dillon
  4.         ;
  5.         ;   Light Weight Processes
  6.         ;
  7.         ;   Note:   Only AlertLWP() is asynchronously reentrant
  8.         ;        (callable from interrupts and other tasks)
  9.  
  10.         INCLUDE "exec/types.i"
  11.         INCLUDE "exec/ports.i"
  12.         INCLUDE "exec/ables.i"
  13.  
  14. LW_NODE     equ    0        ;minimal node, 8 bytes
  15. LW_STACK    equ    8        ;stack ptr used when deallocating it
  16. LW_STACKSIZE    equ    12        ;stack size used when deallocating it
  17. LW_ALERT    equ    16        ;first byte used out of a short
  18. LW_PC        equ    18        ;pc saved on context switch
  19. LW_REGS     equ    22        ;regs saved on context switch
  20. LW_SIZE     equ    22+48        ;12 registers = 48 bytes (D2-D7/A2-A7) to end
  21.  
  22. LW_A2        equ    24        ;relative to LW_REGS (D2-D7 == 24 bytes)
  23. LW_A3        equ    LW_A2+4
  24. LW_A4        equ    LW_A3+4
  25. LW_A5        equ    LW_A4+4
  26. LW_A6        equ    LW_A5+4
  27. LW_A7        equ    LW_A6+4
  28.  
  29. LB_ALERT    equ    0
  30. LB_LIMBO    equ    1
  31.  
  32.         section DATA,DATA
  33.  
  34.         ;   note: _LastLWPMem takes into account malloc's overhead
  35.         ;      by guessing it is 8 bytes.  This is not entirely
  36.         ;      correct if one changes to AllocMem()
  37.  
  38.         XDEF    _ThisLWP    ; user readable (current lwp)
  39.         XDEF    _LastLWPMem    ; user readable (user information)
  40.         XDEF    _CoreLWPStack    ; user modifiable
  41.         XDEF    _LWPAlloc    ; user modifiable memory allocator
  42.         XDEF    _LWPFree    ; user modifiable memory freer
  43.         XDEF    _LWPTask    ; user modifiable 'task'
  44.  
  45.         XREF    _lmalloc    ; default memory routines used
  46.                     ; NOTE: must use 'lmalloc', a routine
  47.                     ; which takes a LONGWORD argument,
  48.                     ; so this module can be used with
  49.                     ; either 16/32 bit integer compiler
  50.                     ; options.
  51.         XREF    _free
  52.  
  53. _LWPAlloc    dc.l    _lmalloc    ; allocate/free function, can also
  54. _LWPFree    dc.l    _free        ;  set to AllocMem/FreeMem
  55. _LWPTask    dc.l    0        ; main task
  56. _LastLWPMem    dc.l    0        ; Last ForkLWP() allocated this much
  57. _ThisLWP    dc.l    0        ; Current LWP.    Also indicates LWPs running
  58. _CoreLWPStack    dc.l    92+8+3        ; 92 for EXEC, 8 for LWP calls if user
  59.                     ;  specified 0, 3 for long word align
  60.  
  61.                     ; AutoAlert ptrs to LWPs for each signal bit
  62. _LWPAutoAlert    dc.l    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  63.         dc.l    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  64. _MasterStack    dc.l    0        ; Global Stack (as of call to RunLWP())
  65. _ReadyList    dc.l    _ReadyList+4    ; LWPs ready to run (list header)
  66.         dc.l    0
  67.         dc.l    _ReadyList
  68.  
  69.         section CODE
  70.  
  71.         ;    All routines marked by A 'R' for 'REENTRANT' can be called
  72.         ;    from an LWP.  These must work even if the programmer
  73.         ;    specifies a 0 stack size.  In this case, currently only
  74.         ;    8 extra bytes are available.  Thus, these routines must
  75.         ;    work with only 8 bytes of stack.  These are synchronously
  76.         ;    reentrant only.
  77.  
  78.         XREF    _LVOInsert
  79.         XREF    _LVORemove
  80.         XREF    _LVOSignal
  81.         XREF    _intena
  82.  
  83.         XDEF    _ForkLWP        ; R
  84.         XDEF    _SwitchLWP        ; R
  85.         XDEF    _WaitLWP        ; R
  86.         XDEF    _AlertLWP        ; R
  87.         XDEF    _RunLWP        ;
  88.         XDEF    _AutoAlertLWP    ; R (set auto alert LWP for port)
  89.         XDEF    _CallBigStack    ; R
  90.  
  91.         ;    CallBigStack(function, argbytes, args ....)
  92.         ;               8(A2)     12(A2)   16(A2)
  93.  
  94. _CallBigStack:
  95.         link    A2,#0
  96.         move.l  _MasterStack,sp    ; use master stack pointer
  97.         move.l  12(A2),D0           ; # bytes (must be even)
  98.         lea     16(A2,D0.L),A0      ; A0 = points past last argument
  99.         lsr.l   #1,D0        ; D0 = # of words to txfer
  100.         bra     .ms20
  101. .ms10        move.w  -(A0),-(sp)         ; copy args
  102. .ms20        dbf     D0,.ms10
  103.         move.l  8(A2),A0            ; function
  104.         jsr     (A0)                ; call it
  105.         unlk    A2            ; restore old stack
  106.         rts
  107.  
  108.         ;    AutoAlertLWP(port, lwp/NULL)
  109.         ;
  110.         ;    Port must have mp_SigBit setup
  111.         ;    this call modifies mp_Flags & mp_Task
  112.  
  113. _AutoAlertLWP:
  114.         link    A2,#0
  115.         tst.l   _ThisLWP            ; running under an LWP?
  116.         beq     .aa10
  117.         move.l  _MasterStack,sp        ; yes, use master stack
  118. .aa10        move.l  A6,-(sp)                    ; save A6
  119.         move.l  4,A6
  120.         move.l  ThisTask(A6),_LWPTask       ; remember the calling task!
  121.         lea     _LWPAutoAlert,A1
  122.         move.l  8(A2),A0                    ; port to modify
  123.         move.l  12(A2),D0                   ; lwp to alert
  124.         move.b  MP_SIGBIT(A0),D1            ; D1.W is signal bit
  125.         and.w   #31,D1
  126.         asl.w   #2,D1            ; x 4 array index
  127.         move.l  D0,0(A1,D1.W)               ; save the LWP to alert
  128.         beq     .aa50
  129.                         ; SETUP LWP
  130.         move.b  #2,MP_FLAGS(A0)             ; Temp. Ignore
  131.         move.l  #PortAlert,MP_SIGTASK(A0)   ; special call routine
  132.         move.b  #3,MP_FLAGS(A0)             ; call mode
  133.         move.l  MP_MSGLIST(A0),A1           ; get head
  134.         tst.l   (A1)
  135.         beq     .aa20            ; call alert?
  136.         DISABLE
  137.         move.l  A0,A1
  138.         bsr     PortAlert
  139.         ENABLE
  140. .aa20        move.l  (sp)+,A6
  141.         unlk    A2
  142.         rts
  143.  
  144. .aa50
  145.         move.b  #2,MP_FLAGS(A0)             ; Temp. Ignore
  146.         move.l  ThisTask(A6),MP_SIGTASK(A0) ; setup task field
  147.         move.b  #0,MP_FLAGS(A0)             ; setup flags to PA_SIGNAL
  148.         move.l  MP_MSGLIST(A0),A1
  149.         tst.l   (A1)                        ; messages exist on list
  150.         beq     .aa60
  151.         move.l  MP_SIGTASK(A0),A1           ; Signal(A1,D0)
  152.         move.b  MP_SIGBIT(A0),D1
  153.         moveq.l #0,D0
  154.         bset    D1,D0            ; D0 = 1 << mp_SigBit
  155.         jsr     _LVOSignal(A6)
  156. .aa60        move.l  (sp)+,A6                    ; restore A6
  157.         unlk    A2                ; restore stack
  158.         rts
  159.  
  160.         ;    Called by exec with interrupts disabled, port in A1, EXEC
  161.         ;    base reg in A6.  lookup LWP and alert it.
  162.  
  163. PortAlert:  move.b  MP_SIGBIT(A1),D0
  164.         tst.l   _ThisLWP            ; is the LWP system running?
  165.         bne     .pal1
  166.         move.w  D0,D1            ; no, set EXEC signal
  167.         moveq.l #0,D0
  168.         bset    D1,D0
  169.         move.w  D1,-(sp)                    ; D1 = sigbit, 0 = mask
  170.         move.l  _LWPTask,A1         ; A1 = destination task
  171.         jsr     _LVOSignal(A6)              ; Signal(A1,D0)
  172.         move.w  (sp)+,D0                    ; D0 = sigbit
  173.  
  174.                         ; yes, alert LWP and do NOT
  175.                         ; set EXEC signal
  176. .pal1        lea     _LWPAutoAlert,A0        ; array base
  177.         and.w   #31,D0
  178.         asl.w   #2,D0
  179.         move.l  0(A0,D0.W),D0               ; LWP to alert
  180.         beq     .pal50
  181.         move.l  D0,A0
  182.         bclr.b  #LB_LIMBO,LW_ALERT(A0)      ; in limbo?
  183.         beq     .pal10            ; no, already on ready list
  184.         lea.l   _ReadyList,A1        ; yes, add to ready list
  185.         move.l  (A1),(A0)                   ; node->succ = list->head
  186.         move.l  A1,4(A0)                    ; node->pred = &list->head
  187.         move.l  A0,(A1)                     ; list->head = node
  188.         move.l  (A0),A1                     ; node->succ ...
  189.         move.l  A0,4(A1)                    ; node->succ->pred = node
  190. .pal10        bset.b  #LB_ALERT,LW_ALERT(A0)      ; set alert bit
  191. .pal50        rts
  192.  
  193.  
  194.         ;    RunLWP()
  195.         ;
  196.         ;    run all active LWPs until none ready to run.  Returns 0
  197.         ;    if there are no LWPs ready to run, 1 if there were LWPs
  198.         ;    run.  This call does not return until the ReadyList is
  199.         ;    empty (no LWPs ready to run or all deleted)
  200.  
  201. _RunLWP:    tst.l   _ThisLWP        ; can't call RunLWP from an LWP.
  202.         bne     .rl9
  203.         move.l  _ReadyList,A1
  204.         tst.l   (A1)
  205.         bne     .rl10
  206.         moveq.l #0,D0
  207. .rl9        rts             ; no lwp's ready to run
  208. .rl10        movem.l D2-D7/A2-A6,-(sp)   ; save registers
  209.         pea     _RunReturn
  210.         move.l  sp,_MasterStack
  211.         bra     CtxA1        ; one sided context switch
  212. _RunReturn: movem.l (sp)+,D2-D7/A2-A6   ; no lwp's to run, but some ran
  213.         clr.l   _ThisLWP        ; set _ThisLWP to NULL
  214.         move.l  _ReadyList,A1    ; then re-test if any ready to go
  215.                     ; (required to close timing window)
  216.         tst.l   (A1)
  217.         bne     .rl10
  218.         moveq.l #1,D0        ; LWP did run
  219.         rts
  220.  
  221.         ;    ForkLWP(stack, arglen)
  222.         ;
  223.         ;    This call converts the subroutine that called it into an
  224.         ;    LWP by allocating an LWP descriptor and new stack of size
  225.         ;    stack+arglen+LOCAL where LOCAL is the stack required by
  226.         ;    the subroutine's local variables and saved registers, etc..
  227.         ;    (essentially, anything allocated when ForkLWP() was called).
  228.         ;
  229.         ;    Note: the subroutine that calls this routine must use the
  230.         ;    link/unlk convention with A5 for the link register, and
  231.         ;    in addition must NOT destroy any register D2-D7/A2-A6 before
  232.         ;    making this call because ForkLWP() will return to the caller
  233.         ;    of the subroutine when done rather than the subroutine itself
  234.         ;    (the context is setup so when the new LWP is run, it starts
  235.         ;     at the point where ForkLWP() would have otherwised normally
  236.         ;     returned to the subroutine.
  237.         ;
  238.         ;    ForkLWP() may be called by a LWP which effectively replaces
  239.         ;    that LWP's stack with another one.  In this case, since a
  240.         ;    create-new-delete-old sequence occurs, the addresses of
  241.         ;    local variables will be different and the old LWP descriptor
  242.         ;    will be invalid.
  243.  
  244. _ForkLWP:   link    A2,#0        ; 4(A2)=ret addr 8(a2)=stk 12(a2)=arglen
  245.         tst.l   _ThisLWP
  246.         beq     .il1        ; use master stack if called from a LWP
  247.         move.l  _MasterStack,sp
  248.  
  249. .il1        clr.l   _LastLWPMem
  250.         movem.l D2-D7/A2-A6,-(sp)   ; Save regs.
  251.         move.l  4,A6        ; ExecBase
  252.  
  253.         move.l  8(A2),D0            ; next longword sized stack.
  254.         add.l   _CoreLWPStack,D0    ; required minimum stack, includes 3
  255.                     ;  for LW align.
  256.         and.b   #$FC,D0
  257.         move.l  D0,8(A2)
  258.         move.l  12(A2),D0           ; next longword sized arglen.
  259.         addq.l  #3,D0
  260.         and.b   #$FC,D0
  261.         move.l  D0,12(A2)
  262.  
  263.         move.l  #LW_SIZE,D0     ; AllocMem the LWP structure
  264.         bsr     AllocMyMem
  265.         beq     .ilfail
  266.         move.l  D0,A3        ; A3 == LWP structure pointer
  267.         clr.b   LW_ALERT(A3)
  268.  
  269.         move.w  #44-4,D0        ; copy 11 registers to context
  270. .il5        move.l  0(sp,D0.W),LW_REGS(A3,D0.W)
  271.         subq.w  #4,D0
  272.         bcc     .il5
  273.         move.l  (A2),LW_REGS+LW_A2(A3)
  274.  
  275.         move.l  A5,D2
  276.         sub.l   A2,D2
  277.         add.l   12(A2),D2           ; D2 = copysize (A5 - A2 + arglen)
  278.         move.l  8(A2),D0
  279.         add.l   D2,D0        ; D0 = total stack size
  280.         move.l  D0,LW_STACKSIZE(A3) ; save into lwp structure
  281.         bsr     AllocMyMem
  282.         beq     .ilfail2
  283.         move.l  LW_STACKSIZE(A3),_LastLWPMem
  284.         add.l   #LW_SIZE+8,_LastLWPMem
  285.         move.l  D0,LW_STACK(A3)     ; save into lwp structure
  286.         move.l  D0,A0        ; A0 = pointer to stack start
  287.         add.l   8(A2),A0            ; A0 = start of dest copy area
  288.         move.l  A0,-(sp)            ; (save start of dest copy area)
  289.         lea     8(A2),A1            ; A1 source
  290.         move.l  D2,D0
  291.         lsr.l   #1,D0        ; D0 = # of words, at least 4
  292. .il10        move.w  (A1)+,(A0)+
  293.         subq.l  #1,D0
  294.         bne     .il10        ; when done, A0 will be at stack end.
  295.  
  296.         move.l  A0,A1
  297.         sub.l   12(A2),A1           ; A1 skip back to lwp subr's ret addr
  298.         move.l  #_DeleteLWP,-(A1)   ; set ret addr to lwp killer
  299.         move.l  A0,-(A1)            ; garbage, not required
  300.         move.l  A1,LW_REGS+LW_A5(A3) ; lwp subr's A5 reg.
  301.  
  302.         move.l  (sp)+,A0            ; A0 now start of copy area
  303.         move.l  A0,LW_REGS+LW_A7(A3) ; ..is stack ptr on lwp resume
  304.  
  305.         move.l  4(A2),LW_PC(A3)     ; ..set pc to ret addr of this routine
  306.  
  307.         lea     _ReadyList,A0    ; list
  308.         move.l  A3,A1        ; node
  309.         move.l  _ThisLWP,A2     ; insert after (ensures this is next run lwp)
  310.         jsr     _LVOInsert(A6)      ; now a valid lwp.
  311.  
  312. .ilret        move.l  A3,D0        ; return the LWP descriptor
  313.         movem.l (sp)+,D2-D7/A2-A6   ; restore registers note
  314.         unlk    A2            ; unlink
  315.         rts             ; and return (lwp desc)
  316.  
  317. .ilfail2:   move.l  A3,A1        ; failure, free the LWP descriptor
  318.         move.l  #LW_SIZE,D0
  319.         bsr     FreeMyMem
  320.  
  321. .ilfail:    sub.l   A3,A3        ; return NULL
  322.         bra     .ilret
  323.  
  324.         ;    SwitchLWP()
  325.         ;
  326.         ;    Switch to next ready LWP (used to share the CPU in tight
  327.         ;    loops).  Is a fast nop if no other LWPs ready.
  328.         ;
  329.         ;    returns 1 if nobody to switch to (the fast nop), 0 otherwise
  330.  
  331. _SwitchLWP: move.l  _ThisLWP,A0     ; current lwp
  332.         move.l  LN_SUCC(A0),A1  ; next lwp
  333.         tst.l   (A1)            ; end of list?
  334.         bne     CtxA0A1
  335.         move.l  -4(A1),A1       ; yes, get head
  336.         cmp.l   A0,A1
  337.         bne     CtxA0A1
  338.         moveq.l #1,D0
  339.         rts             ; only one lwp ready, let it run
  340. CtxA0A1     move.l  (sp)+,LW_PC(A0) ; switch to next ready lwp
  341.         movem.l D2-D7/A2-A7,LW_REGS(A0)
  342. CtxA1        movem.l LW_REGS(A1),D2-D7/A2-A7
  343.         move.l  LW_PC(A1),A0
  344.         move.l  A1,_ThisLWP
  345.         moveq.l #0,D0        ; return 0 (so ForkLWP() returns 0)
  346.         jmp     (A0)
  347.  
  348.         ;    DeleteLWP() is called from an lwp context.  Since we are
  349.         ;    deleting it, we can trash any register but A4 which is used
  350.         ;    for the small data model base pointer.
  351.         ;
  352.         ;    note that we use the MasterStack because we will be making
  353.         ;    EXEC calls and do not know how much stack we actually have
  354.         ;    left in the LWP.
  355.  
  356. _DeleteLWP: move.l  _MasterStack,sp        ; use the master stack since we
  357.         move.l  4,A6            ;  will deallocate the LWPs
  358.         move.l  _ThisLWP,A2
  359.         DISABLE
  360.         move.l  A2,A1            ; Remove the lwp
  361.         move.l  (A2),A3                 ; A3 = next lwp
  362.         jsr     _LVORemove(A6)
  363.         ENABLE
  364.         move.l  LW_STACK(A2),A1         ; then free its stack
  365.         move.l  LW_STACKSIZE(A2),D0
  366.         bsr     FreeMyMem
  367.         move.l  A2,A1
  368.         move.l  #LW_SIZE,D0
  369.         bsr     FreeMyMem
  370.  
  371.         move.l  A3,A1
  372.         tst.l   (A1)                    ; valid next lwp
  373.         bne     CtxA1
  374.         move.l  _ReadyList,A1        ; no next, get list head
  375.         tst.l   (A1)
  376.         bne     CtxA1
  377.         rts                 ; RTS from MasterStack -> RunLWP
  378.  
  379.         ;    WaitLWP()
  380.         ;
  381.         ;    Wait until alerted.  If already alerted this call is
  382.         ;    equivalent to a SwitchLWP().  Otherwise, unlink and
  383.         ;    then do a SwitchLWP().
  384.         ;
  385.         ;    Note that if there are no LWPs ready to run after unlinking,
  386.         ;    we return to the overall RunLWP() routine via an RTS from
  387.         ;    MasterStack.
  388.  
  389. _WaitLWP:   move.l  A6,-(sp)
  390.         move.l  4,A6
  391.         DISABLE
  392.         move.l  _ThisLWP,A0
  393.         bclr.b  #LB_ALERT,LW_ALERT(A0)  ; if lwp already alerted
  394.         beq     .wl5
  395.         ENABLE
  396.         move.l  (sp)+,A6
  397.         bra     _SwitchLWP
  398.  
  399. .wl5        bset.b  #LB_LIMBO,LW_ALERT(A0)  ; not, set flag as being in limbo
  400.         move.l  A0,-(sp)                ; Remove(A0)
  401.         move.l  LN_SUCC(A0),A1          ; A1 = successor to run
  402.         move.l  LN_PRED(A0),A0
  403.         move.l  A0,LN_PRED(A1)
  404.         move.l  A1,LN_SUCC(A0)
  405.  
  406.         ENABLE
  407.         move.l  (sp)+,A0                ; A0 = guy just removed, now in limbo
  408.         move.l  (sp)+,A6
  409.         tst.l   (A1)                    ; A1 = successor.  valid node?
  410.         bne     .wl10            ; yes, switch to new context
  411.         move.l  -4(A1),A1               ; no, circular list, get head
  412.         tst.l   (A1)                    ; empty list?
  413.         bne     .wl10            ; no, switch to new context
  414.         move.l  _MasterStack,sp        ; yes, nobody to switch to
  415.         rts
  416. .wl10        move.l  A0,-(sp)
  417.         bsr     CtxA0A1
  418.         move.l  (sp)+,A0                ; (on return)
  419.         bclr.b  #LB_ALERT,LW_ALERT(A0)  ; clear LB_ALERT again for efficiency
  420.         rts
  421.  
  422.         ;    AlertLWP(lwp:4(sp))
  423.         ;
  424.         ;    This routine alerts a light weight process, causing it to
  425.         ;    be placed on the ready list and also setting the alert
  426.         ;    flag so the next WaitLWP() call made by the lwp will fall
  427.         ;    through (if it is not already waiting)
  428.  
  429. _AlertLWP:  move.l  4(sp),D0                ; LWP to alert
  430.         beq     .al40
  431.         move.l  A6,-(sp)
  432.         move.l  4,A6
  433.         DISABLE
  434.         move.l  D0,A0
  435.         bclr.b  #LB_LIMBO,LW_ALERT(A0)  ; in limbo?
  436.         beq     .al10            ; no, already on ready list
  437.         lea.l   _ReadyList,A1        ; yes, add to ready list
  438.         move.l  (A1),(A0)               ; node->succ = list->head
  439.         move.l  A1,4(A0)                ; node->pred = &list->head
  440.         move.l  A0,(A1)                 ; list->head = node
  441.         move.l  (A0),A1                 ; node->succ->pred = node
  442.         move.l  A0,4(A1)
  443. .al10        bset.b  #LB_ALERT,LW_ALERT(A0)  ; set alert bit
  444.         ENABLE
  445.         move.l  (sp)+,A6
  446. .al40        rts
  447.  
  448. AllocMyMem: movem.l D2/D3/A6,-(sp)
  449.         clr.l   -(sp)               ; for AllocMem
  450.         move.l  D0,-(sp)            ; for malloc/AllocMem
  451.         move.l  _LWPAlloc,A0
  452.         jsr     (A0)
  453.         addq.l  #8,sp
  454.         movem.l (sp)+,D2/D3/A6
  455.         tst.l   D0
  456.         rts
  457.  
  458. FreeMyMem:  movem.l D2/D3/A6,-(sp)
  459.         move.l  D0,-(sp)
  460.         move.l  A1,-(sp)
  461.         move.l  _LWPFree,A0
  462.         jsr     (A0)
  463.         addq.l  #8,sp
  464.         movem.l (sp)+,D2/D3/A6
  465.         rts
  466.  
  467.         END
  468.  
  469.