diff -r 000000000000 -r 5c129dd80d4f CSa32/CS.S --- /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