From 7e6b2824d32b972cbccc0860a8f0f825decd76b3 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Sat, 12 May 2012 01:29:39 -0400 Subject: [PATCH] fix select(2) --- mselect.c | 180 +++++++++++++++++++++++++++++++++--------------------- table.c | 46 +++++++++++++- 2 files changed, 153 insertions(+), 73 deletions(-) diff --git a/mselect.c b/mselect.c index 7855c80..012198e 100644 --- a/mselect.c +++ b/mselect.c @@ -1,6 +1,7 @@ #include "marignotti.h" #include #include +#include #include "s16debug.h" @@ -11,14 +12,79 @@ * return value is ignored. * */ + + + /* + * select is rather ugly... + * listen and connect pass in a select wakeup function which + * takes two parameters, a collision flag and the pid to awaken. + * + * when select is called, it returns immediately, in the affirmative + * if possible. Otherwise, it stores the pid and the collision flag. + * When the condition is met, the select wakeup function is called + * and the pid and collision flag are cleared. + * + * exceptions (which really mean OOB) are not supported. + * write currently always returns immediately, in the affirmative. + * for a server, "read" means a connection is pending. + * otherwise, it means the read will not block (ie, data is available + * or the connection has closed. + * + * this is all based on looking at the select.asm and driver source + * code, so it could be wrong... + */ + -static boolean readable(Entry *e) +boolean readable(Entry *e) { + + Word state; + Word terr; + Word t; + + state = e->sr.srState; + + // hmm.. read will return 0 immediately. if (e->_SHUT_RD) - return false; - - if (e->sr.srState > TCPSESTABLISHED && e->sr.srRcvQueued) return true; + + if (e->_TYPE == SOCK_DGRAM) + { + Word count; + /* + udpVars uv; + IncBusy(); + TCPIPStatusUDP(e->ipid, &uv); + //t = _toolErr; + DecBusy(); + + return uv.uvQueueSize > 0; + */ + IncBusy(); + count = TCPIPGetDatagramCount(e->ipid, protocolUDP); + DecBusy(); + + return count > 0; + } + + + IncBusy(); + terr = TCPIPStatusTCP(e->ipid, &e->sr); + t = _toolErr; + if (t) terr = t; + e->terr = terr; + DecBusy(); + + // for a server, "read" means "accept". + if (state == TCPSLISTEN) + { + return e->sr.srAcceptCount > 0; + } + + // eof means readable. + if (state == TCPSCLOSED || state > TCPSESTABLISHED) + return true; + if (e->sr.srRcvQueued >= e->_RCVLOWAT) return true; @@ -42,29 +108,8 @@ static boolean writable(Entry *e) static boolean exceptable(Entry *e) { - - switch (e->terr) - { - case tcperrOK: - break; - case tcperrConClosing: - case tcperrClosing: - case tcperrConReset: - if (!e->sr.srRcvQueued) - return true; - break; - } - - if (e->sr.srRcvQueued) - return false; - - if (e->sr.srNetworkError) - return true; - - if (e->sr.srState > TCPSESTABLISHED) - return true; - - return false; + return 0; + // never. } int mselect(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5) @@ -74,57 +119,50 @@ int mselect(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5) int pid = *(int *)p2; int flag = *(int *)p3; - - *(int *)p3 = 0; + int *outflag = (int *)p3; + + *outflag = 0; if (Debug > 0) { - s16_debug_printf("select pid = %5d flag = %d", pid, flag); + s16_debug_printf("select pid = %d flag = %d", pid, flag); } - IncBusy(); - terr = TCPIPStatusTCP(e->ipid, &e->sr); - t = _toolErr; - if (t) terr = t; - e->terr = terr; - DecBusy(); + switch (flag) + { + case 0: + if (readable(e)) + { + *outflag = 1; + return 0; + } + break; + case 1: + //always writable. [?] + *outflag = 1; + return 0; + break; + case 2: + // no exceptions. + return 0; + break; + default: + return 0; + break; + } + + + // main loop will call sel flag when readable. + + SEI(); + + if (e->select_rd_pid == 0xffff) + e->select_rd_pid = pid; + else if (e->select_rd_pid != pid) + e->select_rd_collision = 1; - if (e->sr.srState == TCPSLISTEN) - { - // for a listen socket, "read" means "accept". - switch (flag) - { - case 0: - if (e->sr.srAcceptCount) - *(int *)p3 = 1; - break; - } - - } - else - { - switch (flag) - { - case 0: - // readable. - *(int *)p3 = readable(e); - break; - - case 1: - // writable. - *(int *)p3 = writable(e); - break; - - case 2: - // exception. - *(int *)p3 = exceptable(e); - break; - - } - - } - + CLI(); return 0; } \ No newline at end of file diff --git a/table.c b/table.c index 8d2448b..3ae017b 100644 --- a/table.c +++ b/table.c @@ -8,6 +8,9 @@ #pragma optimize 79 #pragma noroot + +extern boolean readable(Entry *e); + #define TABLE_SIZE 16 #define TABLE_MASK 15 static struct Entry *table[TABLE_SIZE]; @@ -106,7 +109,10 @@ Entry *create_entry(Word ipid) e->_OOBINLINE = 1; e->_SNDLOWAT = 1024; e->_RCVLOWAT = 1; - + + e->select_rd_pid = 0xffff; + e->select_wr_pid = 0xffff; + SEI(); e->next = table[ipid & TABLE_MASK]; table[ipid & TABLE_MASK] = e; @@ -136,6 +142,39 @@ void process_table(void) Word command; next = e->next; + + // select. + // do this first ... a close would invalidate. + if (e->select_rd_pid != 0xffff) + { + if (readable(e)) + { + Word coll; + Word pid; + + SEI() + + coll = e->select_rd_collision; + pid = e->select_rd_pid; + + e->select_rd_pid = 0xffff; + e->select_rd_collision = 0; + + CLI() + if (e->select_fx) + e->select_fx(coll, pid); + + if (Debug > 0) + { + s16_debug_printf("select/read wakeup."); + } + + } + + } + + + command = e->command; if (command) { @@ -241,7 +280,10 @@ void process_table(void) DecBusy(); } // e->command - + + + + if (e) prev = e; e = next; }