--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/CSa32/CS.S Thu Nov 21 14:55:10 2019 +0100
@@ -0,0 +1,556 @@
+ .include "DS.S"
+#-----------------------------------------------
+# S T A T I C V A R I A B L E S
+#-----------------------------------------------
+ .data
+ .global C.csP
+C.csP: .int 0 # -->CS
+ .text
+#-----------------------------------------------
+# M A I N R O U T I N E
+#-----------------------------------------------
+# takes values from ENV, establishes task for comm nodes and waits for their completion
+ ARGS
+ DS prgP # -->progname
+# returns nothing
+ PROLOC
+ DL this, CSL # CS - top level attr vector
+ DL deP # -->Debug
+ DL status # status returned from wait
+ DL pid # PID returned from wait
+ DL bad # cummulative subtask rc
+ DL s, 256 # string buf
+ EPILOC
+#-----------------------------------------------
+ .global _start
+_start:
+ PROLOG
+ lea this(bp), b # -->CS
+ mov b, C.csP # save -->CS
+ lea C.debug(b), a # -->Debug
+ mov a, deP(bp)
+# initialize static debug vars
+ push prgP(bp) # argv[0] -->prgname
+ call D.init # initialize static debug vars
+ push D.prgNameP
+# indetify itself
+ DEBID "client/server demo"
+ movl $1, C.debMaxLev(b) # default debug level
+# initialize top level ctrl values vector
+ ShareA # allocate shared structure
+ mov C.csP, b
+ mov a, C.shP(b) # save -->shared struct in vector
+ movl $0, S.msgs(a) # init msg cntr
+ movl $0, S.conns(a) # init connection cntr
+ push $1 # initial semaphore value
+ push $1 # semaphore shared between processes
+ lea S.counter_sem(a), c
+ push c
+# call sem_init # initialize shared counters semaphore
+# cmp $0, a
+# jz 0f
+# SYSERR "sem_init of shared counters semaphore"
+#0:
+ SYS sem_init
+# set default values
+ mov C.csP, b
+ movl $3, C.ttl(b) # default TTL
+ movl $11000, C.rp0(b) # default bind port for the 1. node in ring
+ movl $12000, C.mp0(b) # default bind port for the 1. node in mash
+ movl $0, C.rn(b) # default # of nodes in ring
+ movl $0, C.mn(b) # default # of nodes in mash
+ movl $0, C.ssl(b) # default ssl switch - 0=noSSL
+ movl $77, C.connTh(b) # conn retries threshold
+ mov $0f, a
+ mov a, C.txtP(b) # default payload text
+ jmp 1f
+0: .ascii "bla bla\0"
+1:
+# get control values from ENV
+# get max debug level
+ GETINTENV "DEB"
+ mov C.csP, b
+ mov a, C.debMaxLev(b)
+ cmp $-1, a # debug level -1 means search subroutines
+ jne 0f
+ call D.subr
+ jmp C.ret
+0:
+# get message payload text
+ push $0f
+ call getenv
+ cmp $0, a
+ jz 1f
+ mov C.csP, b
+ mov a, C.txtP(b)
+ jmp 1f
+0: .asciz "T"
+1:
+# get TTL
+ GETINTENV "TTL"
+ jz 0f
+ mov a, C.ttl(b)
+0:
+# get # of nodes in each topology
+ GETINTENV "I"
+ jz 0f
+ mov a, C.rn(b)
+ mov a, C.mn(b)
+0:
+# get # of nodes in ring
+ GETINTENV "RN"
+ jz 0f
+ mov a, C.rn(b)
+0:
+# get # of nodes in mash
+ GETINTENV "MN"
+ jz 0f
+ mov a, C.mn(b)
+0:
+ add C.rn(b), a
+ cmp $3, C.ssl(b)
+ jne 1f
+ add a, a # double # of nodes when both SSL and nonSSL
+1: mov C.shP(b), c # -->shared counters
+ mov a, S.act(c) # save # of active nodes
+# get first ring node's bind port#
+ GETINTENV "RP0"
+ jz 0f
+ mov a, C.rp0(b)
+0:
+# get first mash node's bind port#
+ GETINTENV "MP0"
+ jz 0f
+ mov a, C.mp0(b)
+0:
+# get random() seed
+ GETINTENV "RS"
+ jz 0f
+ push a
+ call srandom
+0:
+# get pacing interval (real num in seconds)
+ movl $0, C.pace.tv_sec(b)
+ movl $0, C.pace.tv_nsec(b)
+ movl $0, C.pacing(b)
+ push $0f
+ call getenv
+ jmp 1f
+0: .asciz "P"
+1:
+ test a, a # env P set ?
+ jz 3f # no
+ push a
+ call atof # convert to double
+ fstl (sp) # tempor save
+ mov C.csP, b
+ fisttpl C.pace.tv_sec(b) # truncated integral part = secs
+ fldl (sp)
+ fisubl C.pace.tv_sec(b) # fraction part
+ fimull 1f # * 10^9 = nanosecs
+ fistl C.pace.tv_nsec(b)
+ jmp 2f
+0: .double 0
+1: .int 1000000000 # 10^9
+2:
+ cmp $0, C.pace.tv_sec(b)
+ jnz 0f
+ cmp $0, C.pace.tv_nsec(b)
+ jz 3f
+0: movl $1, C.pacing(b)
+3:
+# get ssl switch value and save it as mask
+# switch: 0 = noSSL, 1 = SSL, 2 = both
+# mask: 01B=noSSL, 10B=SSL, 11B=both
+ GETINTENV "SSL" # returned zero means SSL=0 or SSL by default 0
+ inc a # change switch to mask
+ mov a, C.ssl(b)
+ cmp $1, a
+ je C.cont # no SSL
+ cmp $2, a
+ je 0f # only SSL
+ mov C.shP(b), a # -->shared mem
+ shll $1, S.act(a) # double # of active nodes when running both SSL and nonSSL
+# get SSL CA cert dir path
+0:
+ push $0f
+ call getenv
+ jmp 1f
+0: .asciz "CAP"
+1:
+ test a, a
+ jnz 1f
+ mov $0f, a
+ jmp 1f
+0: .asciz "/home/local/etc/ssl/certs/"
+1:
+ mov C.csP, b
+ mov a, C.caPathP(b) # save -->SSL CA certs path
+# get SSL dir path
+ push $0f
+ call getenv
+ jmp 1f
+0: .asciz "CEP"
+1:
+ test a, a
+ jz 0f # ceP not set, try to determine
+ mov C.csP, b
+ mov a, C.cePathP(b) # save -->SSL dir path
+ jmp 1f
+# determine home path (needed to locate SSL keys & certificates)
+0:
+ push prgP(bp) # -->first parm - progname w/ path
+ call dirname # get prog dirname
+ push a
+ call strlen # dirname length
+ lea 1f-0f(a), a # + suffix length
+ sub a, sp # allocate space for cePath
+ mov C.csP, b
+ mov sp, C.cePathP(b) # save -->SSL path
+ push prgP(bp)
+ call dirname # get home dirname
+ push a # -->home dirname
+ mov C.csP, b
+ push C.cePathP(b) # -->SSL path
+ call strcpy # copy dirname to SSL path
+ call strlen # end of dirname
+ push $0f # -->suffix
+ mov C.csP, b
+ mov C.cePathP(b), c
+ lea (c, a), a # -->end of dirname
+ push a
+ call strcpy # copy suffix to SSL path
+ jmp 1f
+0: .asciz "/../CS/"
+1:
+# testing sandbox
+ mov C.csP, b
+ pushl C.debMaxLev(b)
+ cmp $9, C.debMaxLev(b)
+ jne C.cont
+
+ LOG 9, "debug=%u, testing...", 1
+ DebugA
+ mov a, deP(bp)
+ DEBID "TEST"
+ LOG 9, "progress"
+
+ mov C.csP, b
+ mov C.shP(b), a
+ push S.act(a)
+ LOG 9, "shared act=%u"
+
+ jmp C.ret
+# normal execution
+C.cont:
+ push C.debMaxLev(b)
+ push C.ssl(b)
+ push C.pace.tv_nsec(b)
+ push C.pace.tv_sec(b)
+ push C.ttl(b)
+ push C.rn(b)
+ push C.mn(b)
+ push D.prgNameP
+ LOG 1, "pgm=%s, mash nodes=%d, ring nodes=%d, ttl=%d, pacing=%ld.%09ld, SSL mask=0x%02x, debug=%u", 8
+ testl $2, C.ssl(b)
+ jz 0f
+ push C.caPathP(b)
+ push C.cePathP(b)
+ LOG 1, "SSL path=%s, SSL CA path=%s"
+0:
+# create constellation processes RING/MASH, nonSSL/SSL
+ mov $0, c # iter counter
+ mov C.ssl(b), d # SSL mask (01b = noSSL, 10b = SSL, 11b = both)
+# iterate on SSL variants
+C.iterateOnSsl:
+ test $1, d # check lowest bit of mask
+ jz C.nextSsslVar # next SSL variant
+ pusha
+# create RING
+ SYS fork
+ jnz 1f # parent
+ popa
+ pushl $Cn.ring # RING topology
+ push c # use iter ctr as SSL switch
+ call Constellation # create RING constellation
+1: push a
+ LOG 5, "RING started in process %d"
+ lea 4(sp), sp
+# create MASH
+ SYS fork
+ jnz 1f # parent
+ popa
+ pushl $Cn.mash # MASH topology
+ push c # use iter ctr as SSL switch
+ call Constellation # create MASH constellation
+1: push a
+ LOG 5, "MASH started in process %d"
+ lea 4(sp), sp
+
+ popa
+C.nextSsslVar:
+ shr $1, d # shift to test next SSL bit
+ inc c # incr ctr
+ cmp $2, c
+ jl C.iterateOnSsl
+# wait for constellation processes completion
+ LOG 5, "waiting for constellations to terminate"
+ movl $0, bad(bp) # clear cummulative rc
+C.iterateOnWait:
+ lea status(bp), a
+ push a # -->return status of task
+ call wait
+ mov a, pid(bp) # save pid
+ cmp $-1, a # a task ended?
+ jne 0f # yes
+ call __errno_location
+ cmp $10, (a) # error == ECHILD ?
+ je C.ret # yes, no other subtasks
+ SYSERR "wait"
+0:
+# push status(bp) # status of task
+# push a # pid
+# LOG 5, "status returned from task %u: 0x%08x"
+ mov status(bp), d
+ test $0x7f, d
+ jnz 1f # task killed, ABEND
+ and $0xff00, d # task exited, extract rc
+ shr $8, d
+ or d, bad(bp) # accumulate rc
+ push d # task rc
+ push pid(bp) # task pid
+ LOG 5, "constellation task %u ended with exit(%d)"
+ jmp C.iterateOnWait # wait for other tasks
+1: push d
+ push pid(bp)
+ LOG 5, "constellation task %u killed, status=0x%x", 2
+2:
+# ABEND
+ LOG 0, "ABEND, kill all tasks"
+ pushl $15 # SIGTERM
+ pushl $0 # all tasks
+# call kill
+ SYS kill
+ pushl $1
+ call exit
+# normal end
+C.ret: movl C.csP, b # -->CS vector
+ movl C.shP(b), b # -->Share
+ pushl S.conns(b) # no. of connections made
+ pushl S.msgs(b) # no. of messages sent
+ LOG 1, "END, forwards=%d, connections=%d", 2
+ push bad(bp)
+ call exit
+#-----------------------------------------------
+# C O N S T E L L A T I O N O P E R A T I O N S
+#-----------------------------------------------
+ ARGS
+ DS ssl # ssl switch
+ DS topo # topology
+# returns: nothing
+ PROLOC
+ DL this, ConstellationL # this Constellation instance
+ DL thisP # -->this Constellation
+ DL deP # -->Debug
+ DL last # last node#
+ DL pid # pid returned from wait
+ DL stat # stat returned from wait
+ DL bad # "some node BAD" exit indicator
+ DL catched # count of returned node tasks
+ DL killed # count of killed node tasks
+ EPILOC
+#-----------------------------------------------
+ .global Constellation
+Constellation:
+ PROLOG
+ lea this(bp), b # -->this Constellation
+ mov b, thisP(bp) # save -->this Constellation
+# set debid
+ lea Cn.debug(b), a # -->Debug
+ mov a, deP(bp) # save -->Debug locally
+ mov C.csP, c # -->CS
+ cmp $Cn.ring, topo(bp) # ring topology ?
+ je 0f
+ mov C.mn(c), a # num. of nodes
+ mov a, Cn.nodes(b)
+ mov C.mp0(c), a # port # of fist node
+ mov a, Cn.first(b)
+ movl $Cn.mash, Cn.topo(b)
+ push $8f
+ jmp 1f
+0: mov C.rn(c), a # num. of nodes
+ mov a, Cn.nodes(b)
+ mov C.rp0(c), a # port # of fist node
+ mov a, Cn.first(b)
+ movl $Cn.ring, Cn.topo(b)
+ push $7f
+1: cmp $0, ssl(bp) # SSL ?
+ jz 2f # no
+ movl $1, Cn.ssl(b)
+ addl $500, Cn.first(b) # first SSL port #
+ push $6f
+ jmp 9f
+2: movl $0, Cn.ssl(b)
+ push $5f
+ jmp 9f
+5: .ascii "non\0"
+6: .ascii "\0"
+7: .ascii "RING\0"
+8: .ascii "MASH\0"
+9: DEBID "%sSSL %s", 2
+# check # of nodes
+ movL $0, bad(bp)
+ cmp $1, Cn.nodes(b) # num of nodes
+ jl Cn.ret # < 1 ? nothing to do
+ jg 0f
+ LOG 0, "1 node configuration not implemented yet"
+ jmp Cn.ret
+0: LOG 5, "initializing..."
+# determine divisor for random next node choise
+ mov $1, a
+ shl $31, a
+ not a # MAX_INT
+ xor d, d
+ divl Cn.nodes(b)
+ mov a, Cn.div(b) # save divisor (MAX_INT / nodes)
+# allocate "forward" indicator shared by nodes in constellation
+ push $0
+ push $-1
+ push $0x21 # PROT_READ | PROT_WRITE
+ push $0x03 # MAP_SHARED | MAP_ANONYMOUS
+ push $4
+ push $0
+# call mmap
+# cmp $-1, a
+# jne 0f
+# SYSERR "mmap"
+#0: mov thisP(bp), b
+ SYS mmap
+ mov a, Cn.forwP(b) # save -->forw
+ movl $1, (a) # enable forwarding
+ push Cn.nodes(b)
+ LOG 1, "%u nodes starting..."
+# start processes for all nodes in constellation
+ mov Cn.first(b), d # first node#
+ mov d, c
+ add Cn.nodes(b), c # last node + 1
+Cn.iterateOnFork:
+ pusha
+# call fork
+ SYS fork
+ cmp $0, a
+ jnz 1f # parent
+ popa
+ push d # node's port#
+ push b # -->Cnstlln
+ call Node
+1: mov a, pid(bp)
+ popa
+ push pid(bp) # nodes's pid
+ push d # node's port#
+ LOG 4, "node %u established in process %u", 2
+ inc d
+ cmp d, c # last node ?
+ jg Cn.iterateOnFork # no, continue forking
+# wait for completion of node processes
+ LOG 2, "all nodes established, waiting for them to terminate..."
+ movl $0, bad(bp) # accumulated return status of node tasks
+ movl $0, killed(bp) # num. of killed node tasks
+ movl $0, catched(bp) # num. of returned node tasks
+ lea -12(sp), sp # prepare space for loop
+Cn.iterateOnWait:
+ cmp $0, bad(bp) # constellation status still OK ?
+ je 1f # yes
+ mov Cn.forwP(b), a # -->forwarding switch
+ movl $0, (a) # disable forwarding between nodes
+1:
+ lea stat(bp), c
+ mov c, (sp) # -->return status of task
+ call wait
+ mov thisP(bp), b
+ cmp $-1, a # normal return from wait?
+ jne 0f # yes
+ call __errno_location
+ cmp $10, (a) # error == ECHILD ?
+ je Cn.allFinished # yes, no subtasks
+ SYSERR "wait"
+0:
+ incl catched(bp)
+ mov a, pid(bp) # save subtask's pid
+ mov a, (sp)
+ mov stat(bp), c # subtask return status
+ mov c, 4(sp)
+ test $0x7f, c # subtask ended by exit ?
+ jnz 2f # no, killed
+ and $0xff00, c # extract subtask rc
+ jz 1f # rc = 0
+ movl $1, bad(bp) # non zero rc, turn on BAD switch
+1: shr $8, c
+ mov c, 4(sp) # rc
+ mov a, (sp) # pid
+ LOG 4, "node process %u ended by exit(%d)"
+ jmp Cn.iterateOnWait # continue waiting for other subtasks
+2: movl $1, bad(bp) # subtask killed, turn on BAD switch
+ incl killed(bp) # counter of killed
+ mov c, 4(sp) # status
+ mov a, (sp) # pid
+ LOG 4, "node process %u killed, status=0x%x"
+ jmp Cn.iterateOnWait # continue waiting for other subtasks
+
+# opers of all nodes finished
+Cn.allFinished:
+ push killed(bp)
+ push catched(bp)
+ mov thisP(bp), b
+ push Cn.nodes(b)
+ cmp $0, bad(bp) # all nodes ended OK ?
+ je 0f # yes
+ push $7f
+ jmp 9f
+0: push $8f
+ jmp 9f
+7: .ascii "with ERROR\0"
+8: .ascii "OK\0"
+9: LOG 1, "ENDED %s, %u spawned, %u catched, %u killed"
+Cn.ret:
+ push bad(bp)
+ call exit
+#-----------------------------------------------
+# G E T I N T V A L U E S F R O M E N V
+#-----------------------------------------------
+ ARGS
+ DS key # -->env key string
+# returns int value or 0 if not found
+ PROLOC
+ EPILOC
+#-----------------------------------------------
+C.getArg:
+ PROLOG
+ pushl key(bp) # -->env key string
+ call getenv # get value
+ test a, a
+ jz 0f # not found in ENV
+ push a
+ call atoi # convert to int
+0:
+ EPILOG_R
+#-----------------------------------------------
+# A B N O R M A L E N D
+#-----------------------------------------------
+ ARGS
+ DS deP # -->Debug
+ PROLOC
+ EPILOC
+#-----------------------------------------------
+ .globl C.abend
+C.abend:
+ PROLOG
+ LOG 0, "ABEND"
+ push $15 # SIGTERM
+ push $0 # kill all
+# call kill
+ SYS kill
+ push $1
+ call exit
+#-----------------------------------------------
+ .end