Newer
Older
uBix-Retro / dump / oa-2.0.9 / lib6502 / libexec.a65

/****************************************************************************
   
    OS/A65 Version 2.0.0
    Multitasking Operating System for 6502 Computers

    Copyright (C) 1989-1998 Andre Fachat 

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

****************************************************************************/

/**********************************************************************
 * Exec handling for lib6502
 * exports
 * 	Exec, Forkto, Forkthread, Term, Kill, Getpid
 *
 */

	.(

/**********************************************************************
 * Forkto forks a new thread and executes the executable given.
 * No open files are inherited. 
 * 
 * It forks a new OS task and sets it to run at a library routine
 * that communicates with the local library routine by a stream.
 * The task environment is transfered this way. 
 *
 * The forked task then opens the executable and invokes the 
 * exec code to start the new executable.
 *
 * The forked task closes the comm. stream without error if everything
 * went right, or sets the error bits if there was an error. If there
 * was an error, the forked task writes the error code to the stream
 * which the forking task can read before closing it.
 *
 */

	.(
strerr	rts

&&Forkto
	sta zth
	sty zth+1

	jsr GETSTR
	bcs strerr
	txa
	pha

	ldx #SEM_SENDBUF
	clc
	jsr PSEM		; get the sendbuf which we need to FORK

	pla
	sta PCBUF+FORK_NAME	; - no name, give comm stream as parameter
	pha			; save for later

	ldy #0
	lda (zth),y
	tax
	jsr checkfd_r
	bcs ferr2
	stx PCBUF+FORK_STDIN

	ldy #1
	lda (zth),y
	tax
	jsr checkfd_w
	bcs ferr2
	stx PCBUF+FORK_STDOUT

	ldy #2
	lda (zth),y
	tax
	jsr checkfd_w
ferr2	bcs ferr
	stx PCBUF+FORK_STDERR

	ldx PCBUF+FORK_STDIN
	lda #SC_REG_RD
	jsr STRCMD
	ldx PCBUF+FORK_STDOUT
	lda #SC_REG_WR
	jsr STRCMD
	ldx PCBUF+FORK_STDERR
	lda #SC_REG_WR
	jsr STRCMD

	pla
&&init_forkto_i			; this is a ROM entry only for init
				; which has to start lib6502 progs without
				; too much support
	pha

	ldy #3
	ldx #FORK_NAME+1	; copy cmdline + parameter
l0	lda (zth),y
l1	sta PCBUF,x
	iny
	inx
	beq lerr
	cmp #0
	bne l0
	cpx #FORK_NAME+2	; first char
	beq l0
	lda PCBUF-2,x
	bne l0

	pla
&&mon_forkto_i			; this is a ROM entry for the monitor
				; ac = comm stream, xr = length of fork
				; struct in PCBUF. First byte of filename
				; is comm stream
	pha

	lda #>Memend		; initial RAM size
	sta PCBUF+FORK_SIZE
	lda #0
	sta PCBUF+FORK_PRIORITY
#ifndef LIB6502_SHAREDZERO
	lda #>-ROMSTART		; shared ROM size
#endif
	sta PCBUF+FORK_SHARED

	lda #<libfork
	sta PCBUF+FORK_ADDR
	lda #>libfork
	sta PCBUF+FORK_ADDR+1

	txa
	tay
;.byt 2
	jsr FORK
;.byt 2
	bcc ok
	pha

	ldx PCBUF+FORK_STDIN
	lda #SC_NUL
	jsr STRCMD
	ldx PCBUF+FORK_STDOUT
	lda #SC_EOF
	jsr STRCMD
	ldx PCBUF+FORK_STDERR
	lda #SC_EOF
	jsr STRCMD
	
	pla
	.byt $2c
lerr	lda #E_FNAMLEN
ferr
	pha
	ldx #SEM_SENDBUF
	jsr VSEM
	pla
	tay
	pla
	tax
	jsr FRESTR
	tya
	sec
	rts
ok	
	pla			; stream number
	sta zth
	stx zth+1

	; copy cwd to communication stream
	lda zta		; check if task is lib6502, otherwise 
	ora zta+1	; just send empty path (when called from init)
	bne initd

	lda #0
	ldx zth
	jsr eputc	; empty path (drive byte + zero-length path)
	jsr eputc
	jsr eputc	; empty environment
	jsr eputc
;.byt 2
	jmp l2
initd
	ldy #LT_PATH
	lda (zta),y
	ldx zth
	jsr eputc

ll	iny
	lda (zta),y
	jsr eputc
	cmp #0
	bne ll

	; copy env to communication stream 

	lda zth
	tax
	pha
	lda zth+1
	pha
	lda zta
	clc
	adc #<LT_ENV
	sta zth
	lda zta+1
	adc #>LT_ENV
	sta zth+1

	ldy #0
	lda (zth),y	
	jsr eputc
le	iny
	lda (zth),y
	jsr eputc
	cmp #0
	bne le
	dey
	lda (zth),y
	beq lee
	iny
	jmp le
lee	
	pla
	sta zth+1
	pla
	sta zth

l2	jsr YIELD
	; wait till forked thread returns error code - indicated by PUSH flag.
	ldx zth
	lda #SC_ESTAT
	jsr STRCMD
	tya
	and #SCE_PUSH
	beq l2

	ldx zth
	jsr GETC
	pha

	; close comm. stream
	ldx zth
	lda #SC_NUL
	jsr STRCMD

	pla
	ldx zth+1
	ldy #0
	cmp #1
	rts

eputc	.(
	pha
	jsr PUTC
	bcc eok
	cmp #E_NUL
	beq cerr
	jsr YIELD
	pla
	jmp eputc
cerr	
eok	pla
	rts
	.)

egetc	.(
	jsr GETC
	bcc eok
	cmp #E_EOF
	beq cerr
	jsr YIELD
	jmp egetc
cerr	
eok	rts
	.)


libfork .(		/* this is the routine where the new task is started */
	cli
	lda PCBUF+FORK_NAME
	pha
;.byt 2
	jsr taskinit
;.byt 2
			; read cwd from parent
	pla
	pha
	tax
	jsr egetc
	ldy #LT_PATH	; drive byte
	sta (zta),y
rd	iny
	jsr egetc	; nullbyte terminated path
	sta (zta),y
	cmp #0
	bne rd
			; read env from parent
	lda zta
	clc
	adc #<LT_ENV
	sta zth
	lda zta+1
	adc #>LT_ENV
	sta zth+1
	pla
	pha
	tax
	ldy #0
	jsr egetc
	sta (zth),y	; at least one byte long - now dey below always works
re	iny
	jsr egetc
	sta (zth),y
	cmp #0
	bne re
	dey
	lda (zth),y
	beq endenv	; last one was zero too -> end of environment
	iny
	jmp re
endenv
			; call exec routine
	lda #<PCBUF+FORK_NAME+1
	ldy #>PCBUF+FORK_NAME+1
	jsr doload
;.byt 2
	tax

	pla
	sta zth		; comm stream number
	txa

	php
	pha
	tya
	pha
	bcc noerr
	txa
	.byt $2c
noerr	lda #0

	ldx zth
	jsr PUTC
	ldy #SCE_PUSH
	lda #SC_SSTAT
	jsr STRCMD
	lda #SC_EOF
	jsr STRCMD

	pla
	sta zth+1
	pla
	sta zth
	plp
	bcs loaderr

	lda #>term-1
	pha
	lda #<term-1
	pha

	lda zta
	clc
	adc #<LT_CMDPARS
	pha
	lda zta+1
	adc #>LT_CMDPARS
	tay
	pla			; pointer to cmd line
	jmp (zth)

loaderr
;.byt 2
	jsr GETPID
	jsr bcleanpid		; free all memory allocated by this task
	jmp TERM
	
	.)

	.)

/**********************************************************************
 *
 */

&Forkthread .(
	sta zth
	sty zth+1
	ldy #LT_NTHREADS
	lda (zta),y
	clc
	adc #1
	sta (zta),y
	
	lda zth
	ldy zth+1
	jsr FORKT
	bcs error
	rts
error	pha
	ldy #LT_NTHREADS
	lda (zta),y
	sec
	sbc #1
	sta (zta),y
	pla
	sec
	rts
	.)

&Kill	.(
	cpx #<MYTASK
	bne nosuicide
	cpy #>MYTASK
	beq Term
nosuicide
	lda #E_NOTIMP
	sec
	rts
	.)

&Term	.(
	pha
	jsr taskinit		; well, if necessary...?
	ldy #LT_NTHREADS
	lda (zta),y
	beq errzero
	sec
	sbc #1
	sta (zta),y
	beq cleanup
errzero	pla
	jmp TERM
cleanup
	ldy #LT_FTAB
l0	lda (zta),y
	bne closefd
l1	iny
	cpy #LT_FTAB+MAXFILES
	bcc l0

	jsr GETPID
	jsr bcleanpid		; free all memory allocated by this task
	pha
	jmp TERM

closefd	
	and #5
	beq nord
	tya
	pha
	clc
	adc #MAXFILES
	tay
	lda (zta),y
	tax
	lda #SC_NUL
	jsr STRCMD
	pla
	tay
nord	lda (zta),y
	and #2
	beq nowr
	tya
	pha
	clc
	adc #2*MAXFILES
	tay
	lda (zta),y
	tax
	lda #SC_EOF
	jsr STRCMD
	pla
	tay
nowr	lda #0
	sta (zta),y
	beq l1
	.)

&Getpid	.(
	jsr GETPID
	ldy #0
	rts
	.)

doload	.(
	.zero
cp	.word
	.text

	sta zth
	sty zth+1	

	/* copy parameter to save area */
	lda #LSEM_EXEC
	jsr llock

	lda zta
	clc
	adc #<LT_CMDPARS
	sta cp
	lda zta+1
	adc #>LT_CMDPARS
	sta cp+1

	ldy #0
c0	lda (zth),y
	sta (cp),y
	iny
	cpy #CMDLEN
	bcc c0

	lda #LSEM_EXEC
	jsr lunlock

	ldx #0
	jsr fopen2	; like fopen, does not release PCBUF


	php
	txa
	pha
	ldx #SEM_SENDBUF
	jsr VSEM
	pla
	plp

	bcs ende
	pha
	tax

	jsr loader

	sta zth
	pla
	tax
	lda zth

	php
	pha
	tya
	pha
	jsr fclose
	pla
	tay
	pla
	plp
ende	rts
	.)

&Exec	.(
	sta zth
	sty zth+1

	jsr GETPID

	ldy #LT_INISTACK
	lda (zta),y
	tax
	txs

	lda zta
	ldy zta+1
;.byt 2
	jsr bcleanpida	; clean all allocated mem except addr in a/y

	lda zth
	ldy zth+1

	jsr doload
	bcs end
;.byt 2
	sty zth+1
	sta zth
	jsr doit
	jmp term
doit
	jmp (zth)

end 
	rts
	.)

	.)