home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 199.lha / LWP_v1.02 / lwp.asm < prev    next >
Encoding:
Assembly Source File  |  1988-12-27  |  11.2 KB  |  329 lines

  1.  
  2.         ;   LWP.ASM V1.02 18 December 1988
  3.         ;   Matthew Dillon
  4.         ;
  5.         ;   note: will require some changes for non Aztec assemblers.
  6.         ;
  7.         ;   Light Weight Processes
  8.         ;
  9.         ;   Note: Calls are not *asynchronously* reentrant.  Calls
  10.         ;   ARE synchronously reentrant.  Please read the docs.
  11.  
  12. LN_SUCC     equ    0
  13. LN_PRED     equ    4
  14.  
  15. LW_NODE     equ    0        ;minimal node, 8 bytes
  16. LW_STACK    equ    8        ;stack ptr used when deallocating it
  17. LW_STACKSIZE    equ    12        ;stack size used when deallocating it
  18. LW_ALERT    equ    16        ;first byte used out of a short
  19. LW_PC        equ    18        ;pc saved on context switch
  20. LW_REGS     equ    22        ;regs saved on context switch
  21. LW_SIZE     equ    22+48        ;12 registers = 48 bytes (D2-D7/A2-A7) to end
  22.  
  23. LW_A2        equ    24        ;relative to LW_REGS (D2-D7 == 24 bytes)
  24. LW_A3        equ    LW_A2+4
  25. LW_A4        equ    LW_A3+4
  26. LW_A5        equ    LW_A4+4
  27. LW_A6        equ    LW_A5+4
  28. LW_A7        equ    LW_A6+4
  29.  
  30. LB_ALERT    equ    0
  31. LB_LIMBO    equ    1
  32.  
  33.         dseg
  34.  
  35.         ;   note: _LastLWPMem takes into account malloc's overhead
  36.         ;      by guessing it is 8 bytes.
  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.  
  44.         XREF    _lmalloc    ; default memory routines used
  45.         XREF    _free
  46.  
  47. _LWPAlloc    dc.l    _lmalloc    ; allocate/free function, can also
  48. _LWPFree    dc.l    _free        ;  set to AllocMem/FreeMem
  49. _LastLWPMem    dc.l    0        ; Last ForkLWP() allocated this much
  50. _ThisLWP    dc.l    0        ; Current LWP
  51. _CoreLWPStack    dc.l    92+8+3        ; 92 for EXEC, 8 for LWP calls if user
  52.                     ;  specified 0, 3 for long word align
  53. _MasterStack    dc.l    0        ; Global Stack
  54. _ReadyList    dc.l    _ReadyList+4    ; LWPs ready to run (list header)
  55.         dc.l    0
  56.         dc.l    _ReadyList
  57.  
  58.         cseg
  59.  
  60.         ;    All routines marked by A 'R' for 'REENTRANT' can be called
  61.         ;    from an LWP.  These must work even if the programmer
  62.         ;    specifies a 0 stack size.  In this case, currently only
  63.         ;    8 extra bytes are available.  Thus, these routines must
  64.         ;    work with only 8 bytes of stack.  These are synchronously
  65.         ;    reentrant only.
  66.  
  67.         XREF    _LVOInsert
  68.         XREF    _LVORemove
  69.         XDEF    _ForkLWP        ; R
  70.         XDEF    _SwitchLWP        ; R
  71.         XDEF    _WaitLWP        ; R
  72.         XDEF    _AlertLWP        ; R
  73.         XDEF    _RunLWP        ;
  74.  
  75.         ;    RunLWP()
  76.         ;
  77.         ;    run all active LWPs until none ready to run.  Returns 0
  78.         ;    if there are no LWPs ready to run, 1 if there were LWPs
  79.         ;    run.  This call does not return until the ReadyList is
  80.         ;    empty (no LWPs ready to run or all deleted)
  81.  
  82. _RunLWP:    tst.l   _ThisLWP        ; can't call RunLWP from an LWP.
  83.         bne     .rl9
  84.         move.l  _ReadyList,A1
  85.         tst.l   (A1)
  86.         bne     .rl10
  87.         moveq.l #0,D0
  88. .rl9        rts             ; no lwp's ready to run
  89. .rl10        movem.l D2-D7/A2-A6,-(sp)   ; save registers
  90.         pea     _RunReturn
  91.         move.l  sp,_MasterStack
  92.         bra     CtxA1        ; one sided context switch
  93. _RunReturn: movem.l (sp)+,D2-D7/A2-A6   ; no lwp's to run, but some ran
  94.         moveq.l #1,D0
  95.         clr.l   _ThisLWP        ; set _ThisLWP to NULL
  96.         rts
  97.  
  98.         ;    ForkLWP(stack, arglen)
  99.         ;
  100.         ;    This call converts the subroutine that called it into an
  101.         ;    LWP by allocating an LWP descriptor and new stack of size
  102.         ;    stack+arglen+LOCAL where LOCAL is the stack required by
  103.         ;    the subroutine's local variables and saved registers, etc..
  104.         ;    (essentially, anything allocated when ForkLWP() was called).
  105.         ;
  106.         ;    Note: the subroutine that calls this routine must use the
  107.         ;    link/unlk convention with A5 for the link register, and
  108.         ;    in addition must NOT destroy any register D2-D7/A2-A6 before
  109.         ;    making this call because ForkLWP() will return to the caller
  110.         ;    of the subroutine when done rather than the subroutine itself
  111.         ;    (the context is setup so when the new LWP is run, it starts
  112.         ;     at the point where ForkLWP() would have otherwised normally
  113.         ;     returned to the subroutine.
  114.         ;
  115.         ;    ForkLWP() may be called by a LWP which effectively replaces
  116.         ;    that LWP's stack with another one.  In this case, since a
  117.         ;    create-new-delete-old sequence occurs, the addresses of
  118.         ;    local variables will be different and the old LWP descriptor
  119.         ;    will be invalid.
  120.  
  121. _ForkLWP:   link    A2,#0        ; 4(A2)=ret addr 8(a2)=stk 12(a2)=arglen
  122.         tst.l   _ThisLWP
  123.         beq     .il1        ; use master stack if called from a LWP
  124.         move.l  _MasterStack,sp
  125.  
  126. .il1        clr.l   _LastLWPMem
  127.         movem.l D2-D7/A2-A6,-(sp)   ; Save regs.
  128.         move.l  4,A6        ; ExecBase
  129.  
  130.         move.l  8(A2),D0            ; next longword sized stack.
  131.         add.l   _CoreLWPStack,D0    ; required minimum stack, includes 3
  132.                     ;  for LW align.
  133.         and.b   #$FC,D0
  134.         move.l  D0,8(A2)
  135.         move.l  12(A2),D0           ; next longword sized arglen.
  136.         addq.l  #3,D0
  137.         and.b   #$FC,D0
  138.         move.l  D0,12(A2)
  139.  
  140.         move.l  #LW_SIZE,D0     ; AllocMem the LWP structure
  141.         bsr     AllocMyMem
  142.         beq     .ilfail
  143.         move.l  D0,A3        ; A3 == LWP structure pointer
  144.         clr.b   LW_ALERT(A3)
  145.  
  146.         move.w  #44-4,D0        ; copy 11 registers to context
  147. .il5        move.l  (sp,D0.W),LW_REGS(A3,D0.W)
  148.         subq.w  #4,D0
  149.         bcc     .il5
  150.         move.l  (A2),LW_REGS+LW_A2(A3)
  151.  
  152.         move.l  A5,D2
  153.         sub.l   A2,D2
  154.         add.l   12(A2),D2           ; D2 = copysize (A5 - A2 + arglen)
  155.         move.l  8(A2),D0
  156.         add.l   D2,D0        ; D0 = total stack size
  157.         move.l  D0,LW_STACKSIZE(A3) ; save into lwp structure
  158.         bsr     AllocMyMem
  159.         beq     .ilfail2
  160.         move.l  LW_STACKSIZE(A3),_LastLWPMem
  161.         add.l   #LW_SIZE+8,_LastLWPMem
  162.         move.l  D0,LW_STACK(A3)     ; save into lwp structure
  163.         move.l  D0,A0        ; A0 = pointer to stack start
  164.         add.l   8(A2),A0            ; A0 = start of dest copy area
  165.         move.l  A0,-(sp)            ; (save start of dest copy area)
  166.         lea     8(A2),A1            ; A1 source
  167.         move.l  D2,D0
  168.         lsr.l   #1,D0        ; D0 = # of words, at least 4
  169. .il10        move.w  (A1)+,(A0)+
  170.         subq.l  #1,D0
  171.         bne     .il10        ; when done, A0 will be at stack end.
  172.  
  173.         move.l  A0,A1
  174.         sub.l   12(A2),A1           ; A1 skip back to lwp subr's ret addr
  175.         move.l  #_DeleteLWP,-(A1)   ; set ret addr to lwp killer
  176.         move.l  A0,-(A1)            ; garbage, not required
  177.         move.l  A1,LW_REGS+LW_A5(A3); lwp subr's A5 reg.
  178.  
  179.         move.l  (sp)+,A0            ; A0 now start of copy area
  180.         move.l  A0,LW_REGS+LW_A7(A3); ..is stack ptr on lwp resume
  181.  
  182.         move.l  4(A2),LW_PC(A3)     ; ..set pc to ret addr of this routine
  183.  
  184.         lea     _ReadyList,A0    ; list
  185.         move.l  A3,A1        ; node
  186.         move.l  _ThisLWP,A2     ; insert after (ensures this is next run lwp)
  187.         jsr     _LVOInsert(A6)      ; now a valid lwp.
  188.  
  189. .ilret        move.l  A3,D0        ; return the LWP descriptor
  190.         movem.l (sp)+,D2-D7/A2-A6   ; restore registers note
  191.         unlk    A2            ; unlink
  192.         rts             ; and return (lwp desc)
  193.  
  194. .ilfail2:   move.l  A3,A1        ; failure, free the LWP descriptor
  195.         move.l  #LW_SIZE,D0
  196.         bsr     FreeMyMem
  197.  
  198. .ilfail:    sub.l   A3,A3        ; return NULL
  199.         bra     .ilret
  200.  
  201.         ;    SwitchLWP()
  202.         ;
  203.         ;    Switch to next ready LWP (used to share the CPU in tight
  204.         ;    loops).  Is a fast nop if no other LWPs ready.
  205.         ;
  206.         ;    returns 1 if nobody to switch to (the fast nop), 0 otherwise
  207.  
  208. _SwitchLWP: move.l  _ThisLWP,A0     ; current lwp
  209.         move.l  LN_SUCC(A0),A1  ; next lwp
  210.         tst.l   (A1)            ; end of list?
  211.         bne     CtxA0A1
  212.         move.l  -4(A1),A1       ; yes, get head
  213.         cmp.l   A0,A1
  214.         bne     CtxA0A1
  215.         moveq.l #1,D0
  216.         rts             ; only one lwp ready, let it run
  217. CtxA0A1     move.l  (sp)+,LW_PC(A0) ; switch to next ready lwp
  218.         movem.l D2-D7/A2-A7,LW_REGS(A0)
  219. CtxA1        movem.l LW_REGS(A1),D2-D7/A2-A7
  220.         move.l  LW_PC(A1),A0
  221.         move.l  A1,_ThisLWP
  222.         moveq.l #0,D0        ; return 0 (so ForkLWP() returns 0)
  223.         jmp     (A0)
  224.  
  225.         ;    DeleteLWP() is called from an lwp context.  Since we are
  226.         ;    deleting it, we can trash any register but A4 which is used
  227.         ;    for the small data model base pointer.
  228.         ;
  229.         ;    note that we use the MasterStack because we will be making
  230.         ;    EXEC calls and do not know how much stack we actually have
  231.         ;    left in the LWP.
  232.  
  233. _DeleteLWP: move.l  _MasterStack,sp        ; use the master stack since we
  234.         move.l  4,A6            ;  will deallocate the LWPs
  235.         move.l  _ThisLWP,A2
  236.         move.l  A2,A1            ; Remove the lwp
  237.         move.l  (A2),A3                 ; A3 = next lwp
  238.         jsr     _LVORemove(A6)
  239.         move.l  LW_STACK(A2),A1         ; then free its stack
  240.         move.l  LW_STACKSIZE(A2),D0
  241.         bsr     FreeMyMem
  242.         move.l  A2,A1
  243.         move.l  #LW_SIZE,D0
  244.         bsr     FreeMyMem
  245.  
  246.         move.l  A3,A1
  247.         tst.l   (A1)                    ; valid next lwp
  248.         bne     CtxA1
  249.         move.l  _ReadyList,A1        ; no next, get list head
  250.         tst.l   (A1)
  251.         bne     CtxA1
  252.         rts                 ; RTS from MasterStack -> RunLWP
  253.  
  254.         ;    WaitLWP()
  255.         ;
  256.         ;    Wait until alerted.  If already alerted this call is
  257.         ;    equivalent to a SwitchLWP().  Otherwise, unlink and
  258.         ;    then do a SwitchLWP().
  259.         ;
  260.         ;    Note that if there are no LWPs ready to run after unlinking,
  261.         ;    we return to the overall RunLWP() routine via an RTS from
  262.         ;    MasterStack.
  263.  
  264. _WaitLWP:   move.l  _ThisLWP,A0
  265.         bclr.b  #LB_ALERT,LW_ALERT(A0)  ; if lwp already alerted
  266.         bne     _SwitchLWP            ; yes, don't remove from ready
  267.                         ;  list, just switch.
  268.         bset.b  #LB_LIMBO,LW_ALERT(A0)  ; flag as being in limbo
  269.         move.l  A0,-(sp)                ; Remove(A0)
  270.         move.l  LN_SUCC(A0),A1          ; A1 = successor to run
  271.         move.l  LN_PRED(A0),A0
  272.         move.l  A0,LN_PRED(A1)
  273.         move.l  A1,LN_SUCC(A0)
  274.         move.l  (sp),A0                 ; A0 = guy just removed, now in limbo
  275.         tst.l   (A1)                    ; successor exists?
  276.         bne     .wl10            ; yes, switch to new context
  277.         move.l  -4(A1),A1               ; no, circular list, get head
  278.         tst.l   (A1)                    ; empty list?
  279.         bne     .wl10            ; no, switch to new context
  280.         move.l  _MasterStack,sp        ; yes, nobody to switch to
  281.         rts
  282. .wl10        bsr     CtxA0A1
  283.         move.l  (sp)+,A0                ; (on return)
  284.         bclr.b  #LB_ALERT,LW_ALERT(A0)  ; clear LB_ALERT again for efficiency
  285.         rts
  286.  
  287.         ;    AlertLWP(lwp:4(sp))
  288.         ;
  289.         ;    This routine alerts a light weight process, causing it to
  290.         ;    be placed on the ready list and also setting the alert
  291.         ;    flag so the next WaitLWP() call made by the lwp will fall
  292.         ;    through (if it is not already waiting)
  293.  
  294. _AlertLWP:  move.l  4(sp),D0                ; LWP to alert
  295.         beq     .al40
  296.         move.l  D0,A0
  297.         bclr.b  #LB_LIMBO,LW_ALERT(A0)  ; in limbo?
  298.         beq     .al10            ; no, already on ready list
  299.         lea.l   _ReadyList,A1        ; yes, add to ready list
  300.         move.l  (A1),(A0)               ; node->succ = list->head
  301.         move.l  A1,4(A0)                ; node->pred = &list->head
  302.         move.l  A0,(A1)                 ; list->head = node
  303.         move.l  (A0),A1                 ; node->succ->pred = node
  304.         move.l  A0,4(A1)
  305. .al10        bset.b  #LB_ALERT,LW_ALERT(A0)  ; set alert bit
  306. .al40        rts
  307.  
  308. AllocMyMem: movem.l D2/D3/A6,-(sp)
  309.         clr.l   -(sp)               ; for AllocMem
  310.         move.l  D0,-(sp)            ; for malloc/AllocMem
  311.         move.l  _LWPAlloc,A0
  312.         jsr     (A0)
  313.         addq.l  #8,sp
  314.         movem.l (sp)+,D2/D3/A6
  315.         tst.l   D0
  316.         rts
  317.  
  318. FreeMyMem:  movem.l D2/D3/A6,-(sp)
  319.         move.l  D0,-(sp)
  320.         move.l  A1,-(sp)
  321.         move.l  _LWPFree,A0
  322.         jsr     (A0)
  323.         addq.l  #8,sp
  324.         movem.l (sp)+,D2/D3/A6
  325.         rts
  326.  
  327.         END
  328.  
  329.