diff --git a/commands/Makefile b/commands/Makefile index bfe16beb3..d05df16d8 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -7,10 +7,10 @@ SUBDIR= add_route arp ash at backup btrace \ chmod chown ci cleantmp cmp co \ comm compress cp crc cron crontab cut \ dd decomp16 DESCRIBE devmand devsize df dhcpd \ - dhrystone diff diskctl dumpcore \ + dhrystone diff diskctl \ eject env factor fbdctl \ find fix fold format fortune fsck.mfs \ - gcore gcov-pull getty grep hexdump host \ + gcov-pull getty grep hexdump host \ hostaddr id ifconfig ifdef \ intr ipcrm ipcs irdpd isoread last \ less loadkeys loadramdisk logger look lp \ diff --git a/commands/dumpcore/Makefile b/commands/dumpcore/Makefile deleted file mode 100644 index 3b469fb13..000000000 --- a/commands/dumpcore/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -PROG= dumpcore -CPPFLAGS+= -I${NETBSDSRCDIR} -MAN= - -.include diff --git a/commands/dumpcore/dumpcore.c b/commands/dumpcore/dumpcore.c deleted file mode 100644 index ca6b70bc6..000000000 --- a/commands/dumpcore/dumpcore.c +++ /dev/null @@ -1,71 +0,0 @@ -/* dumpcore - create core file of running process */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "kernel/proc.h" - -#define CLICK_WORDS (CLICK_SIZE / sizeof(unsigned long)) - -int main(int argc, char *argv[]) -{ - pid_t pid; - int r, status; - - if(argc != 2) { - printf("usage: %s \n", argv[0]); - return 1; - } - - pid = atoi(argv[1]); - - if (ptrace(T_ATTACH, pid, 0, 0) != 0) { - perror("ptrace(T_ATTACH)"); - return 1; - } - - if (waitpid(pid, &status, 0) != pid) { - perror("waitpid"); - return 1; - } - - while (WIFSTOPPED(status) && WSTOPSIG(status) != SIGSTOP) { - /* whatever happens here is fine */ - ptrace(T_RESUME, pid, 0, WSTOPSIG(status)); - - if (waitpid(pid, &status, 0) != pid) { - perror("waitpid"); - return 1; - } - } - - if (!WIFSTOPPED(status)) { - fprintf(stderr, "process died while attaching\n"); - return 1; - } - - if (ptrace(T_DUMPCORE, pid, 0, 0) != 0) { - fprintf(stderr, "warning, dumpcore failed (%s)\n", - strerror(errno)); - } - - if (ptrace(T_DETACH, pid, 0, 0)) { - fprintf(stderr, "warning, detaching failed (%s)\n", - strerror(errno)); - } - - return r; -} diff --git a/commands/gcore/Makefile b/commands/gcore/Makefile deleted file mode 100644 index 4ad31cc0e..000000000 --- a/commands/gcore/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -PROG= gcore -MAN= - -.include diff --git a/commands/gcore/gcore.c b/commands/gcore/gcore.c deleted file mode 100644 index d07d9c0b2..000000000 --- a/commands/gcore/gcore.c +++ /dev/null @@ -1,58 +0,0 @@ -/* gcore - create core file of running process */ - -#include -#include -#include -#include -#include -#include -#include -#include - -int main(int argc, char *argv[]) -{ - pid_t pid; - int status; - - if(argc != 2) { - printf("usage: %s \n", argv[0]); - return 1; - } - - pid = atoi(argv[1]); - - if (ptrace(T_ATTACH, pid, 0, 0) != 0) { - perror("ptrace(T_ATTACH)"); - return 1; - } - - if (waitpid(pid, &status, 0) != pid) { - perror("waitpid"); - return 1; - } - - while (WIFSTOPPED(status) && WSTOPSIG(status) != SIGSTOP) { - /* whatever happens here is fine */ - ptrace(T_RESUME, pid, 0, WSTOPSIG(status)); - - if (waitpid(pid, &status, 0) != pid) { - perror("waitpid"); - return 1; - } - } - - if (!WIFSTOPPED(status)) { - fprintf(stderr, "process died while attaching\n"); - return 1; - } - - if (ptrace(T_DUMPCORE, pid, 0, 0)) { - fprintf(stderr, "warning, dumpcore failed (%s)\n", strerror(errno)); - } - - if (ptrace(T_DETACH, pid, 0, 0)) { - fprintf(stderr, "warning, detaching failed (%s)\n", strerror(errno)); - } - - return 0; -} diff --git a/commands/ps/ps.c b/commands/ps/ps.c index c421c7ab9..0b69eb21a 100644 --- a/commands/ps/ps.c +++ b/commands/ps/ps.c @@ -203,7 +203,6 @@ static char *prrecv(struct pstat *ps) case FSTATE_LOCK: blkstr = "flock"; break; case FSTATE_POPEN: blkstr = "popen"; break; case FSTATE_SELECT: blkstr = "select"; break; - case FSTATE_DOPEN: blkstr = "dopen"; break; case FSTATE_TASK: blkstr = taskname(ps->ps_ftask); break; default: blkstr = "??"; break; } diff --git a/commands/service/service.c b/commands/service/service.c index 09a4f4c1c..0d504cf79 100644 --- a/commands/service/service.c +++ b/commands/service/service.c @@ -334,10 +334,10 @@ static int parse_arguments(int argc, char **argv, u32_t *rss_flags) } } else if (strcmp(argv[i], ARG_DEVSTYLE)==0) { - char* dev_style_keys[] = { "STYLE_DEV", "STYLE_DEVA", "STYLE_TTY", - "STYLE_CTTY", "STYLE_CLONE", "STYLE_CLONE_A", NULL }; - int dev_style_values[] = { STYLE_DEV, STYLE_DEVA, STYLE_TTY, - STYLE_CTTY, STYLE_CLONE, STYLE_CLONE_A }; + char* dev_style_keys[] = { "STYLE_DEV", "STYLE_TTY", + "STYLE_CTTY", "STYLE_CLONE", NULL }; + int dev_style_values[] = { STYLE_DEV, STYLE_TTY, + STYLE_CTTY, STYLE_CLONE }; for(j=0;dev_style_keys[j]!=NULL;j++) { if(!strcmp(dev_style_keys[j], argv[i+1])) { break; diff --git a/distrib/sets/lists/minix/mi b/distrib/sets/lists/minix/mi index 726e1778d..8e5a1bae3 100644 --- a/distrib/sets/lists/minix/mi +++ b/distrib/sets/lists/minix/mi @@ -285,7 +285,7 @@ ./usr/bin/dirname minix-sys ./usr/bin/diskctl minix-sys ./usr/bin/du minix-sys -./usr/bin/dumpcore minix-sys +./usr/bin/dumpcore minix-sys obsolete ./usr/bin/egrep minix-sys ./usr/bin/eject minix-sys ./usr/bin/elfedit minix-sys binutils @@ -314,7 +314,7 @@ ./usr/bin/ftp minix-sys ./usr/bin/g++ minix-sys gcccmds ./usr/bin/gcc minix-sys gcccmds -./usr/bin/gcore minix-sys +./usr/bin/gcore minix-sys obsolete ./usr/bin/gcov minix-sys gcccmds ./usr/bin/gcov-pull minix-sys ./usr/bin/gcpp minix-sys gcccmds @@ -1828,7 +1828,7 @@ ./usr/man/man1/dosread.1 minix-sys ./usr/man/man1/doswrite.1 minix-sys ./usr/man/man1/du.1 minix-sys -./usr/man/man1/dumpcore.1 minix-sys +./usr/man/man1/dumpcore.1 minix-sys obsolete ./usr/man/man1/echo.1 minix-sys ./usr/man/man1/ed.1 minix-sys ./usr/man/man1/egrep.1 minix-sys @@ -5364,6 +5364,8 @@ ./usr/tests/minix-posix/test73 minix-sys ./usr/tests/minix-posix/test74 minix-sys ./usr/tests/minix-posix/test75 minix-sys +./usr/tests/minix-posix/test76 minix-sys +./usr/tests/minix-posix/test77 minix-sys ./usr/tests/minix-posix/test8 minix-sys ./usr/tests/minix-posix/test9 minix-sys ./usr/tests/minix-posix/testinterp minix-sys diff --git a/drivers/bmp085/bmp085.c b/drivers/bmp085/bmp085.c index 40cd0aaba..08d14d915 100644 --- a/drivers/bmp085/bmp085.c +++ b/drivers/bmp085/bmp085.c @@ -791,7 +791,7 @@ main(int argc, char *argv[]) sef_local_startup(); - chardriver_task(&bmp085_tab, CHARDRIVER_SYNC); + chardriver_task(&bmp085_tab); return 0; } diff --git a/drivers/fb/fb.c b/drivers/fb/fb.c index 52c08fce7..07038006b 100644 --- a/drivers/fb/fb.c +++ b/drivers/fb/fb.c @@ -382,7 +382,7 @@ main(int argc, char *argv[]) fb_edid_args_parse(); sef_local_startup(); - chardriver_task(&fb_tab, CHARDRIVER_SYNC); + chardriver_task(&fb_tab); return OK; } diff --git a/drivers/hello/hello.c b/drivers/hello/hello.c index 0dd6a27e4..fb1b4acf0 100644 --- a/drivers/hello/hello.c +++ b/drivers/hello/hello.c @@ -181,7 +181,7 @@ int main(void) /* * Run the main loop. */ - chardriver_task(&hello_tab, CHARDRIVER_SYNC); + chardriver_task(&hello_tab); return OK; } diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c index 36d8af324..101ad579d 100644 --- a/drivers/i2c/i2c.c +++ b/drivers/i2c/i2c.c @@ -549,7 +549,7 @@ main(int argc, char *argv[]) memset(i2cdev, '\0', sizeof(i2cdev)); sef_local_startup(); - chardriver_task(&i2c_tab, CHARDRIVER_SYNC); + chardriver_task(&i2c_tab); return OK; } diff --git a/drivers/log/log.c b/drivers/log/log.c index 5de3d89df..7c6cbf228 100644 --- a/drivers/log/log.c +++ b/drivers/log/log.c @@ -29,7 +29,6 @@ static int log_transfer(endpoint_t endpt, int opcode, u64_t position, static int log_do_open(message *m_ptr); static int log_cancel(message *m_ptr); static int log_select(message *m_ptr); -static int log_other(message *m_ptr); static int subread(struct logdevice *log, int count, endpoint_t endpt, cp_grant_id_t grant, size_t); @@ -44,7 +43,7 @@ static struct chardriver log_dtab = { nop_alarm, /* no alarm */ log_cancel, /* CANCEL request */ log_select, /* DEV_SELECT request */ - log_other /* Unrecognized messages */ + NULL /* Unrecognized messages */ }; /* SEF functions and variables. */ @@ -64,7 +63,7 @@ int main(void) sef_local_startup(); /* Call the generic receive loop. */ - chardriver_task(&log_dtab, CHARDRIVER_ASYNC); + chardriver_task(&log_dtab); return(OK); } @@ -282,7 +281,7 @@ static int log_transfer( iovec_t *iov, /* pointer to read or write request vector */ unsigned int nr_req, /* length of request vector */ endpoint_t user_endpt, /* endpoint of user process */ - unsigned int UNUSED(flags) + unsigned int flags ) { /* Read or write one the driver's minor devices. */ @@ -317,6 +316,8 @@ static int log_transfer( if (!log->log_size) { if(accumulated_read) return OK; + if (flags & FLG_OP_NONBLOCK) + return EAGAIN; /* No data available; let caller block. */ log->log_source = endpt; log->log_iosize = count; @@ -368,48 +369,25 @@ static int log_do_open(message *m_ptr) static int log_cancel(message *m_ptr) { int d; - d = m_ptr->TTY_LINE; + d = m_ptr->DEVICE; if(d < 0 || d >= NR_DEVS) return EINVAL; + if (m_ptr->USER_ENDPT != logdevices[d].log_proc_nr) + return EDONTREPLY; + if ((cp_grant_id_t) m_ptr->IO_GRANT != logdevices[d].log_user_grant) + return EDONTREPLY; logdevices[d].log_proc_nr = NONE; logdevices[d].log_revive_alerted = 0; return(OK); } -/*============================================================================* - * log_other * - *============================================================================*/ -static int log_other(message *m_ptr) -{ - int r; - - /* This function gets messages that the generic driver doesn't - * understand. - */ - if (is_notify(m_ptr->m_type)) { - return EINVAL; - } - - switch(m_ptr->m_type) { - case DEV_STATUS: { - printf("log_other: unexpected DEV_STATUS request\n"); - r = EDONTREPLY; - break; - } - default: - r = EINVAL; - break; - } - return r; -} - /*============================================================================* * log_select * *============================================================================*/ static int log_select(message *m_ptr) { int d, ready_ops = 0, ops = 0; - d = m_ptr->TTY_LINE; + d = m_ptr->DEV_MINOR; if(d < 0 || d >= NR_DEVS) { #if LOG_DEBUG printf("line %d? EINVAL\n", d); @@ -417,10 +395,10 @@ static int log_select(message *m_ptr) return EINVAL; } - ops = m_ptr->USER_ENDPT & (SEL_RD|SEL_WR|SEL_ERR); + ops = m_ptr->DEV_SEL_OPS & (SEL_RD|SEL_WR|SEL_ERR); /* Read blocks when there is no log. */ - if((m_ptr->USER_ENDPT & SEL_RD) && logdevices[d].log_size > 0) { + if((m_ptr->DEV_SEL_OPS & SEL_RD) && logdevices[d].log_size > 0) { #if LOG_DEBUG printf("log can read; size %d\n", logdevices[d].log_size); #endif @@ -428,13 +406,13 @@ static int log_select(message *m_ptr) } /* Write never blocks. */ - if(m_ptr->USER_ENDPT & SEL_WR) ready_ops |= SEL_WR; + if(m_ptr->DEV_SEL_OPS & SEL_WR) ready_ops |= SEL_WR; /* Enable select calback if no operations were * ready to go, but operations were requested, * and notify was enabled. */ - if((m_ptr->USER_ENDPT & SEL_NOTIFY) && ops && !ready_ops) { + if((m_ptr->DEV_SEL_OPS & SEL_NOTIFY) && ops && !ready_ops) { logdevices[d].log_selected |= ops; logdevices[d].log_select_proc = m_ptr->m_source; #if LOG_DEBUG diff --git a/drivers/memory/memory.c b/drivers/memory/memory.c index d42167864..d985b2efb 100644 --- a/drivers/memory/memory.c +++ b/drivers/memory/memory.c @@ -117,8 +117,7 @@ int main(void) if (IS_BDEV_RQ(msg.m_type)) blockdriver_process(&m_bdtab, &msg, ipc_status); else - chardriver_process(&m_cdtab, CHARDRIVER_SYNC, &msg, - ipc_status); + chardriver_process(&m_cdtab, &msg, ipc_status); } return(OK); diff --git a/drivers/printer/liveupdate.c b/drivers/printer/liveupdate.c index 1f3655569..232e4e29c 100644 --- a/drivers/printer/liveupdate.c +++ b/drivers/printer/liveupdate.c @@ -2,7 +2,6 @@ /* State management variables. */ EXTERN int writing; -EXTERN int is_status_msg_expected; /* Custom states definition. */ #define PR_STATE_WRITE_PROTOCOL_FREE (SEF_LU_STATE_CUSTOM_BASE + 0) @@ -24,7 +23,7 @@ int sef_cb_lu_prepare(int state) break; case SEF_LU_STATE_PROTOCOL_FREE: - is_ready = (!writing && !is_status_msg_expected); + is_ready = (!writing); break; /* Custom states. */ @@ -52,15 +51,13 @@ void sef_cb_lu_state_dump(int state) { sef_lu_dprint("printer: live update state = %d\n", state); sef_lu_dprint("printer: writing = %d\n", writing); - sef_lu_dprint("printer: is_status_msg_expected = %d\n", - is_status_msg_expected); sef_lu_dprint("printer: SEF_LU_STATE_WORK_FREE(%d) reached = %d\n", SEF_LU_STATE_WORK_FREE, TRUE); sef_lu_dprint("printer: SEF_LU_STATE_REQUEST_FREE(%d) reached = %d\n", SEF_LU_STATE_REQUEST_FREE, TRUE); sef_lu_dprint("printer: SEF_LU_STATE_PROTOCOL_FREE(%d) reached = %d\n", - SEF_LU_STATE_PROTOCOL_FREE, (!writing && !is_status_msg_expected)); + SEF_LU_STATE_PROTOCOL_FREE, (!writing)); sef_lu_dprint("printer: PR_STATE_WRITE_PROTOCOL_FREE(%d) reached = %d\n", PR_STATE_WRITE_PROTOCOL_FREE, (!writing)); } diff --git a/drivers/printer/printer.c b/drivers/printer/printer.c index 5ab2a9491..bccc6af48 100644 --- a/drivers/printer/printer.c +++ b/drivers/printer/printer.c @@ -14,15 +14,13 @@ * DEV_WRITE: a process wants to write on a terminal * CANCEL: terminate a previous incomplete system call immediately * - * m_type TTY_LINE USER_ENDPT COUNT ADDRESS + * m_type DEVICE USER_ENDPT COUNT ADDRESS * |-------------+---------+---------+---------+---------| * | DEV_OPEN | | | | | * |-------------+---------+---------+---------+---------| * | DEV_CLOSE | | proc nr | | | - * ------------------------------------------------------- - * | HARD_INT | | | | | * |-------------+---------+---------+---------+---------| - * | SYS_EVENT | | | | | + * | HARD_INT | | | | | * |-------------+---------+---------+---------+---------| * | DEV_WRITE |minor dev| proc nr | count | buf ptr | * |-------------+---------+---------+---------+---------| @@ -87,8 +85,6 @@ */ static endpoint_t caller; /* process to tell when printing done (FS) */ -static int revive_pending; /* set to true if revive is pending */ -static int revive_status; /* revive status */ static int done_status; /* status of last output completion */ static int oleft; /* bytes of output left in obuf */ static unsigned char obuf[128]; /* output buffer */ @@ -105,11 +101,11 @@ static int irq_hook_id; /* id of irq hook at kernel */ static void do_cancel(message *m_ptr); static void output_done(void); static void do_write(message *m_ptr); -static void do_status(message *m_ptr); static void prepare_output(void); static int do_probe(void); static void do_initialize(void); -static void reply(int code,int replyee,int proc,int status); +static void reply(int code, endpoint_t replyee, endpoint_t proc, + cp_grant_id_t grant, int status); static void do_printer_output(void); /* SEF functions and variables. */ @@ -118,7 +114,6 @@ static int sef_cb_init_fresh(int type, sef_init_info_t *info); EXTERN int sef_cb_lu_prepare(int state); EXTERN int sef_cb_lu_state_isvalid(int state); EXTERN void sef_cb_lu_state_dump(int state); -int is_status_msg_expected = FALSE; /*===========================================================================* * printer_task * @@ -142,26 +137,25 @@ int main(void) case HARDWARE: do_printer_output(); break; - default: - reply(TASK_REPLY, pr_mess.m_source, - pr_mess.USER_ENDPT, EINVAL); } continue; } switch(pr_mess.m_type) { case DEV_OPEN: - do_initialize(); /* initialize */ - /* fall through */ + do_initialize(); /* initialize */ + reply(DEV_OPEN_REPL, pr_mess.m_source, pr_mess.USER_ENDPT, + (cp_grant_id_t) pr_mess.IO_GRANT, OK); + break; case DEV_CLOSE: - reply(TASK_REPLY, pr_mess.m_source, pr_mess.USER_ENDPT, OK); + reply(DEV_CLOSE_REPL, pr_mess.m_source, pr_mess.USER_ENDPT, + (cp_grant_id_t) pr_mess.IO_GRANT, OK); break; case DEV_WRITE_S: do_write(&pr_mess); break; - case DEV_STATUS: do_status(&pr_mess); break; case CANCEL: do_cancel(&pr_mess); break; default: - reply(TASK_REPLY, pr_mess.m_source, pr_mess.USER_ENDPT, - EINVAL); + reply(DEV_REVIVE, pr_mess.m_source, pr_mess.USER_ENDPT, + (cp_grant_id_t) pr_mess.IO_GRANT, EINVAL); } } } @@ -213,23 +207,21 @@ register message *m_ptr; /* pointer to the newly arrived message */ { /* The printer is used by sending DEV_WRITE messages to it. Process one. */ - register int r = SUSPEND; + int r = OK; int retries; u32_t status; /* Reject command if last write is not yet finished, the count is not * positive, or the user address is bad. */ - if (writing) r = EIO; - else if (m_ptr->COUNT <= 0) r = EINVAL; + if (writing) r = EIO; + else if (m_ptr->COUNT <= 0) r = EINVAL; + else if (m_ptr->FLAGS & FLG_OP_NONBLOCK) r = EAGAIN; /* not supported */ - /* Reply to FS, no matter what happened, possible SUSPEND caller. */ - reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r); - - /* If no errors occurred, continue printing with SUSPENDED caller. + /* If no errors occurred, continue printing with the caller. * First wait until the printer is online to prevent stupid errors. */ - if (SUSPEND == r) { + if (r == OK) { caller = m_ptr->m_source; proc_nr = m_ptr->USER_ENDPT; user_left = m_ptr->COUNT; @@ -254,6 +246,9 @@ register message *m_ptr; /* pointer to the newly arrived message */ /* If we reach this point, the printer was not online in time. */ done_status = status; output_done(); + } else { + reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT, + (cp_grant_id_t) m_ptr->IO_GRANT, r); } } @@ -266,6 +261,7 @@ static void output_done() * Otherwise, reply to caller (FS). */ register int status; + message m; if (!writing) return; /* probably leftover interrupt */ if (done_status != OK) { /* printer error occurred */ @@ -291,32 +287,15 @@ static void output_done() else { /* done! report back to FS */ status = orig_count; } - is_status_msg_expected = TRUE; - revive_pending = TRUE; - revive_status = status; - notify(caller); -} -/*===========================================================================* - * do_status * - *===========================================================================*/ -static void do_status(m_ptr) -register message *m_ptr; /* pointer to the newly arrived message */ -{ - if (revive_pending) { - m_ptr->m_type = DEV_REVIVE; /* build message */ - m_ptr->REP_ENDPT = proc_nr; - m_ptr->REP_STATUS = revive_status; - m_ptr->REP_IO_GRANT = grant_nr; + memset(&m, 0, sizeof(m)); + m.m_type = DEV_REVIVE; /* build message */ + m.REP_ENDPT = proc_nr; + m.REP_STATUS = status; + m.REP_IO_GRANT = grant_nr; + send(caller, &m); - writing = FALSE; /* unmark event */ - revive_pending = FALSE; /* unmark event */ - } else { - m_ptr->m_type = DEV_NO_STATUS; - - is_status_msg_expected = FALSE; - } - send(m_ptr->m_source, m_ptr); /* send the message */ + writing = FALSE; /* unmark event */ } /*===========================================================================* @@ -331,30 +310,32 @@ register message *m_ptr; /* pointer to the newly arrived message */ * but rely on FS to handle the EINTR reply and de-suspension properly. */ - if (writing && m_ptr->USER_ENDPT == proc_nr) { + if (writing && m_ptr->USER_ENDPT == proc_nr && + (cp_grant_id_t) m_ptr->IO_GRANT == grant_nr) { oleft = 0; /* cancel output by interrupt handler */ writing = FALSE; - revive_pending = FALSE; + reply(DEV_REVIVE, m_ptr->m_source, proc_nr, grant_nr, EINTR); } - reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, EINTR); } /*===========================================================================* * reply * *===========================================================================*/ -static void reply(code, replyee, process, status) -int code; /* TASK_REPLY or REVIVE */ -int replyee; /* destination for message (normally FS) */ -int process; /* which user requested the printing */ +static void reply(code, replyee, process, grant, status) +int code; /* DEV_OPEN_REPL, DEV_CLOSE_REPL, DEV_REVIVE */ +endpoint_t replyee; /* destination for message (normally FS) */ +endpoint_t process; /* which user requested the printing */ +cp_grant_id_t grant; /* which grant was involved */ int status; /* number of chars printed or error code */ { /* Send a reply telling FS that printing has started or stopped. */ message pr_mess; - pr_mess.m_type = code; /* TASK_REPLY or REVIVE */ + pr_mess.m_type = code; /* reply code */ pr_mess.REP_STATUS = status; /* count or EIO */ - pr_mess.REP_ENDPT = process; /* which user does this pertain to */ + pr_mess.REP_ENDPT = process; /* which user does this pertain to */ + pr_mess.REP_IO_GRANT = grant; /* the grant */ send(replyee, &pr_mess); /* send the message */ } diff --git a/drivers/random/main.c b/drivers/random/main.c index 18ed36d34..24376bca0 100644 --- a/drivers/random/main.c +++ b/drivers/random/main.c @@ -59,7 +59,7 @@ int main(void) sef_local_startup(); /* Call the generic receive loop. */ - chardriver_task(&r_dtab, CHARDRIVER_ASYNC); + chardriver_task(&r_dtab); return(OK); } diff --git a/drivers/sht21/sht21.c b/drivers/sht21/sht21.c index cb9f327d2..4f2ce3889 100644 --- a/drivers/sht21/sht21.c +++ b/drivers/sht21/sht21.c @@ -612,7 +612,7 @@ main(int argc, char *argv[]) sef_local_startup(); - chardriver_task(&sht21_tab, CHARDRIVER_SYNC); + chardriver_task(&sht21_tab); return 0; } diff --git a/drivers/tps65217/tps65217.c b/drivers/tps65217/tps65217.c index 63d943f6a..12baa0ea8 100644 --- a/drivers/tps65217/tps65217.c +++ b/drivers/tps65217/tps65217.c @@ -434,7 +434,6 @@ int main(int argc, char *argv[]) { int r; - endpoint_t user, caller; message m; int ipc_status; @@ -485,26 +484,8 @@ main(int argc, char *argv[]) continue; } - caller = m.m_source; - user = m.USER_ENDPT; - - /* - * Handle Message - * - * So far this driver only deals with notifications - * so it always replies to non-notifications with EINVAL. - */ - - /* Send Reply */ - m.m_type = TASK_REPLY; - m.REP_ENDPT = user; - m.REP_STATUS = EINVAL; - - r = sendnb(caller, &m); - if (r != OK) { - log_warn(&log, "sendnb() failed\n"); - continue; - } + log_warn(&log, "Ignoring message 0x%x from 0x%x\n", m.m_type, + m.m_source); } return 0; diff --git a/drivers/tsl2550/tsl2550.c b/drivers/tsl2550/tsl2550.c index 06cc31d7c..6e1b33723 100644 --- a/drivers/tsl2550/tsl2550.c +++ b/drivers/tsl2550/tsl2550.c @@ -561,7 +561,7 @@ main(int argc, char *argv[]) sef_local_startup(); - chardriver_task(&tsl2550_tab, CHARDRIVER_SYNC); + chardriver_task(&tsl2550_tab); return 0; } diff --git a/drivers/tty/arch/earm/keyboard.c b/drivers/tty/arch/earm/keyboard.c index 3c6c1e570..7ab1ef158 100644 --- a/drivers/tty/arch/earm/keyboard.c +++ b/drivers/tty/arch/earm/keyboard.c @@ -33,12 +33,6 @@ kb_init_once(void) { } -int -kbd_status(message *m) -{ - return 0; -} - int kbd_loadmap(message *m) { diff --git a/drivers/tty/arch/earm/rs232.c b/drivers/tty/arch/earm/rs232.c index 432d2d9cf..732dfcdf6 100644 --- a/drivers/tty/arch/earm/rs232.c +++ b/drivers/tty/arch/earm/rs232.c @@ -268,27 +268,20 @@ rs_write(register tty_t *tp, int try) tp->tty_outcum += count; if ((tp->tty_outleft -= count) == 0) { /* Output is finished, reply to the writer. */ - if(tp->tty_outrepcode == TTY_REVIVE) { - notify(tp->tty_outcaller); - tp->tty_outrevived = 1; - } else { - tty_reply(tp->tty_outrepcode, tp->tty_outcaller, - tp->tty_outproc, tp->tty_outcum); - tp->tty_outcum = 0; - } + tty_reply(DEV_REVIVE, tp->tty_outcaller, + tp->tty_outproc, tp->tty_outgrant, + tp->tty_outcum); + tp->tty_outcum = 0; + tp->tty_outgrant = GRANT_INVALID; } } if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) { /* Oops, the line has hung up. */ - if(tp->tty_outrepcode == TTY_REVIVE) { - notify(tp->tty_outcaller); - tp->tty_outrevived = 1; - } else { - tty_reply(tp->tty_outrepcode, tp->tty_outcaller, - tp->tty_outproc, EIO); - tp->tty_outleft = tp->tty_outcum = 0; - } + tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc, + tp->tty_outgrant, EIO); + tp->tty_outleft = tp->tty_outcum = 0; + tp->tty_outgrant = GRANT_INVALID; } return 1; diff --git a/drivers/tty/arch/i386/console.c b/drivers/tty/arch/i386/console.c index b18b853f4..16652bf30 100644 --- a/drivers/tty/arch/i386/console.c +++ b/drivers/tty/arch/i386/console.c @@ -215,14 +215,10 @@ int try; /* Reply to the writer if all output is finished or if an error occured. */ if (tp->tty_outleft == 0 || result != OK) { - if(tp->tty_outrepcode == TTY_REVIVE) { - notify(tp->tty_outcaller); - tp->tty_outrevived = 1; - } else { - tty_reply(tp->tty_outrepcode, tp->tty_outcaller, - tp->tty_outproc, tp->tty_outcum); - tp->tty_outcum = 0; - } + tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc, + tp->tty_outgrant, result != OK ? result : tp->tty_outcum); + tp->tty_outcum = tp->tty_outleft = 0; + tp->tty_outgrant = GRANT_INVALID; } return 0; @@ -825,14 +821,16 @@ void do_video(message *m) case DEV_OPEN: /* Should grant IOPL */ disable_console(); - r= OK; - break; + tty_reply(DEV_OPEN_REPL, m->m_source, m->USER_ENDPT, + (cp_grant_id_t) m->IO_GRANT, OK); + return; case DEV_CLOSE: reenable_console(); - r= OK; - break; + tty_reply(DEV_CLOSE_REPL, m->m_source, m->USER_ENDPT, + (cp_grant_id_t) m->IO_GRANT, OK); + return; case DEV_IOCTL_S: - switch(m->TTY_REQUEST) { + switch(m->REQUEST) { case TIOCMAPMEM: case TIOCUNMAPMEM: { int r, do_map; @@ -847,9 +845,7 @@ void do_video(message *m) if (r != OK) { printf("tty: sys_safecopyfrom failed\n"); - tty_reply(TASK_REPLY, m->m_source, - m->USER_ENDPT, r); - return; + break; } /* In safe ioctl mode, the POSITION field contains @@ -870,20 +866,22 @@ void do_video(message *m) r = vm_unmap_phys(m->POSITION, mapreqvm.vaddr, mapreqvm.size); } - tty_reply(TASK_REPLY, m->m_source, m->USER_ENDPT, r); - return; - } + break; + } + default: + r= ENOTTY; + break; } - r= ENOTTY; break; - default: + default: printf( "Warning, TTY(video) got unexpected request %d from %d\n", m->m_type, m->m_source); r= EINVAL; } - tty_reply(TASK_REPLY, m->m_source, m->USER_ENDPT, r); + tty_reply(DEV_REVIVE, m->m_source, m->USER_ENDPT, + (cp_grant_id_t) m->IO_GRANT, r); } diff --git a/drivers/tty/arch/i386/keyboard.c b/drivers/tty/arch/i386/keyboard.c index fb02ce2a8..6a737fa34 100644 --- a/drivers/tty/arch/i386/keyboard.c +++ b/drivers/tty/arch/i386/keyboard.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "tty.h" #include "kernel/const.h" #include "kernel/config.h" @@ -134,6 +135,7 @@ static struct kbd int incaller; int select_ops; int select_proc; + int select_minor; /* sanity check only, can be removed */ } kbd, kbdaux; /* Data that is to be sent to the keyboard. Each byte is ACKed by the @@ -154,7 +156,6 @@ static long debug_fkeys = 1; static timer_t tmr_kbd_wd; static void handle_req(struct kbd *kbdp, message *m); -static int handle_status(struct kbd *kbdp, message *m); static void kbc_cmd0(int cmd); static void kbc_cmd1(int cmd, int data); static int kbc_read(void); @@ -186,20 +187,6 @@ void do_kbd(message *m) } -/*===========================================================================* - * kbd_status * - *===========================================================================*/ -int kbd_status(message *m) -{ - int r; - - r= handle_status(&kbd, m); - if (r) - return r; - return handle_status(&kbdaux, m); -} - - /*===========================================================================* * do_kbdaux * *===========================================================================*/ @@ -224,8 +211,9 @@ message *m; switch (m->m_type) { case DEV_OPEN: kbdp->nr_open++; - r= OK; - break; + tty_reply(DEV_OPEN_REPL, m->m_source, m->USER_ENDPT, + (cp_grant_id_t) m->IO_GRANT, OK); + return; case DEV_CLOSE: kbdp->nr_open--; if (kbdp->nr_open < 0) @@ -235,8 +223,9 @@ message *m; } if (kbdp->nr_open == 0) kbdp->avail= 0; - r= OK; - break; + tty_reply(DEV_CLOSE_REPL, m->m_source, m->USER_ENDPT, + (cp_grant_id_t) m->IO_GRANT, OK); + return; case DEV_READ_S: if (kbdp->req_size) { @@ -246,14 +235,17 @@ message *m; } if (kbdp->avail == 0) { + if (m->FLAGS & FLG_OP_NONBLOCK) { + r = EAGAIN; + break; + } /* Should record proc */ kbdp->req_size= m->COUNT; kbdp->req_proc= m->USER_ENDPT; kbdp->req_grant= (cp_grant_id_t) m->IO_GRANT; kbdp->req_addr_offset= 0; kbdp->incaller= m->m_source; - r= SUSPEND; - break; + return; } /* Handle read request */ @@ -302,11 +294,11 @@ message *m; case CANCEL: kbdp->req_size= 0; - r= OK; + r= EAGAIN; break; case DEV_SELECT: - ops = m->USER_ENDPT & (SEL_RD|SEL_WR|SEL_ERR); - watch = (m->USER_ENDPT & SEL_NOTIFY) ? 1 : 0; + ops = m->DEV_SEL_OPS & (SEL_RD|SEL_WR|SEL_ERR); + watch = (m->DEV_SEL_OPS & SEL_NOTIFY) ? 1 : 0; r= 0; if (kbdp->avail && (ops & SEL_RD)) @@ -319,10 +311,13 @@ message *m; { kbdp->select_ops |= ops; kbdp->select_proc= m->m_source; + kbdp->select_minor= m->DEV_MINOR; } - break; + assert(kbdp->minor == m->DEV_MINOR); + select_reply(DEV_SEL_REPL1, m->m_source, m->DEV_MINOR, r); + return; case DEV_IOCTL_S: - if (kbdp == &kbd && m->TTY_REQUEST == KIOCSLEDS) + if (kbdp == &kbd && m->REQUEST == KIOCSLEDS) { kio_leds_t leds; unsigned char b; @@ -358,7 +353,7 @@ message *m; r= OK; break; } - if (kbdp == &kbd && m->TTY_REQUEST == KIOCBELL) + if (kbdp == &kbd && m->REQUEST == KIOCBELL) { kio_bell_t bell; clock_t ticks; @@ -386,59 +381,8 @@ message *m; m->m_type, m->m_source); r= EINVAL; } - tty_reply(TASK_REPLY, m->m_source, m->USER_ENDPT, r); -} - - -/*===========================================================================* - * handle_status * - *===========================================================================*/ -static int handle_status(kbdp, m) -struct kbd *kbdp; -message *m; -{ - int n, r; - - if (kbdp->avail && kbdp->req_size && m->m_source == kbdp->incaller && - kbdp->req_grant != GRANT_INVALID) - { - /* Handle read request */ - n= kbdp->avail; - if (n > kbdp->req_size) - n= kbdp->req_size; - if (kbdp->offset + n > KBD_BUFSZ) - n= KBD_BUFSZ-kbdp->offset; - if (n <= 0) - panic("kbd_status: bad n: %d", n); - kbdp->req_size= 0; - r= sys_safecopyto(kbdp->incaller, kbdp->req_grant, 0, - (vir_bytes)&kbdp->buf[kbdp->offset], n); - if (r == OK) - { - kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ; - kbdp->avail -= n; - r= n; - } else printf("copy in revive kbd failed: %d\n", r); - - m->m_type = DEV_REVIVE; - m->REP_ENDPT= kbdp->req_proc; - m->REP_IO_GRANT= kbdp->req_grant; - m->REP_STATUS= r; - kbdp->req_grant = GRANT_INVALID; - return 1; - } - if (kbdp->avail && (kbdp->select_ops & SEL_RD) && - m->m_source == kbdp->select_proc) - { - m->m_type = DEV_IO_READY; - m->DEV_MINOR = kbdp->minor; - m->DEV_SEL_OPS = SEL_RD; - - kbdp->select_ops &= ~SEL_RD; - return 1; - } - - return 0; + tty_reply(DEV_REVIVE, m->m_source, m->USER_ENDPT, + (cp_grant_id_t) m->IO_GRANT, r); } @@ -486,7 +430,7 @@ int scode; void kbd_interrupt(message *UNUSED(m_ptr)) { /* A keyboard interrupt has occurred. Process it. */ - int o, isaux; + int n, r, o, isaux; unsigned char scode; struct kbd *kbdp; @@ -512,15 +456,40 @@ void kbd_interrupt(message *UNUSED(m_ptr)) #endif return; /* Buffer is full */ } - o= (kbdp->offset + kbdp->avail) % KBD_BUFSZ; - kbdp->buf[o]= scode; - kbdp->avail++; - if (kbdp->req_size) { - notify(kbdp->incaller); - } - if (kbdp->select_ops & SEL_RD) - notify(kbdp->select_proc); - return; + o= (kbdp->offset + kbdp->avail) % KBD_BUFSZ; + kbdp->buf[o]= scode; + kbdp->avail++; + if (kbdp->req_size) { + /* Reply to read request */ + n= kbdp->avail; + if (n > kbdp->req_size) + n= kbdp->req_size; + if (kbdp->offset + n > KBD_BUFSZ) + n= KBD_BUFSZ-kbdp->offset; + if (n <= 0) + panic("kbd_interrupt: bad n: %d", n); + kbdp->req_size= 0; + r= sys_safecopyto(kbdp->incaller, kbdp->req_grant, 0, + (vir_bytes)&kbdp->buf[kbdp->offset], n); + if (r == OK) + { + kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ; + kbdp->avail -= n; + r= n; + } else printf("copy in revive kbd failed: %d\n", r); + + tty_reply(DEV_REVIVE, kbdp->incaller, kbdp->req_proc, + kbdp->req_grant, r); + kbdp->req_grant = GRANT_INVALID; + } + /* Only satisfy pending select if characters weren't just read. */ + if (kbdp->avail && (kbdp->select_ops & SEL_RD)) { + assert(kbdp->select_minor == kbdp->minor); + select_reply(DEV_SEL_REPL2, kbdp->select_proc, kbdp->minor, + SEL_RD); + kbdp->select_ops &= ~SEL_RD; + } + return; } /* Store the scancode in memory so the task can get at it later. */ diff --git a/drivers/tty/arch/i386/rs232.c b/drivers/tty/arch/i386/rs232.c index d7b2472dd..21821627d 100644 --- a/drivers/tty/arch/i386/rs232.c +++ b/drivers/tty/arch/i386/rs232.c @@ -269,26 +269,18 @@ static int rs_write(register tty_t *tp, int try) tp->tty_outcum += count; if ((tp->tty_outleft -= count) == 0) { /* Output is finished, reply to the writer. */ - if(tp->tty_outrepcode == TTY_REVIVE) { - notify(tp->tty_outcaller); - tp->tty_outrevived = 1; - } else { - tty_reply(tp->tty_outrepcode, tp->tty_outcaller, - tp->tty_outproc, tp->tty_outcum); - tp->tty_outcum = 0; - } + tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc, + tp->tty_outgrant, tp->tty_outcum); + tp->tty_outcum = 0; + tp->tty_outgrant = GRANT_INVALID; } } if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) { /* Oops, the line has hung up. */ - if(tp->tty_outrepcode == TTY_REVIVE) { - notify(tp->tty_outcaller); - tp->tty_outrevived = 1; - } else { - tty_reply(tp->tty_outrepcode, tp->tty_outcaller, - tp->tty_outproc, EIO); - tp->tty_outleft = tp->tty_outcum = 0; - } + tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc, + tp->tty_outgrant, EIO); + tp->tty_outleft = tp->tty_outcum = 0; + tp->tty_outgrant = GRANT_INVALID; } return 1; diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 72e4724eb..8b6bc30ef 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -33,7 +33,6 @@ typedef struct pty { char state; /* flags: busy, closed, ... */ /* Read call on /dev/ptypX. */ - char rdsendreply; /* send a reply (instead of notify) */ int rdcaller; /* process making the call (usually FS) */ int rdproc; /* process that wants to read from the pty */ cp_grant_id_t rdgrant; /* grant for readers address space */ @@ -42,7 +41,6 @@ typedef struct pty { int rdcum; /* # bytes written so far */ /* Write call to /dev/ptypX. */ - char wrsendreply; /* send a reply (instead of notify) */ int wrcaller; /* process making the call (usually FS) */ int wrproc; /* process that wants to write to the pty */ cp_grant_id_t wrgrant; /* grant for writers address space */ @@ -56,14 +54,15 @@ typedef struct pty { char obuf[2048]; /* buffer for bytes going to the pty reader */ /* select() data. */ - int select_ops, /* Which operations do we want to know about? */ - select_proc, /* Who wants to know about it? */ - select_ready_ops; /* For callback. */ + int select_ops; /* Which operations do we want to know about? */ + int select_proc; /* Who wants to know about it? */ + dev_t select_minor; /* sanity check only, can be removed */ } pty_t; -#define PTY_ACTIVE 0x01 /* pty is open/active */ -#define TTY_CLOSED 0x02 /* tty side has closed down */ -#define PTY_CLOSED 0x04 /* pty side has closed down */ +#define TTY_ACTIVE 0x01 /* tty is open/active */ +#define PTY_ACTIVE 0x02 /* pty is open/active */ +#define TTY_CLOSED 0x04 /* tty side has closed down */ +#define PTY_CLOSED 0x08 /* pty side has closed down */ static pty_t pty_table[NR_PTYS]; /* PTY bookkeeping */ @@ -75,7 +74,7 @@ static int pty_read(tty_t *tp, int try); static int pty_close(tty_t *tp, int try); static int pty_icancel(tty_t *tp, int try); static int pty_ocancel(tty_t *tp, int try); -static int pty_select(tty_t *tp, message *m); +static void pty_select(tty_t *tp, message *m); /*===========================================================================* * do_pty * @@ -105,7 +104,6 @@ void do_pty(tty_t *tp, message *m_ptr) r = ENOBUFS; break; } - pp->rdsendreply = TRUE; pp->rdcaller = m_ptr->m_source; pp->rdproc = m_ptr->USER_ENDPT; pp->rdgrant = (cp_grant_id_t) m_ptr->IO_GRANT; @@ -118,9 +116,12 @@ void do_pty(tty_t *tp, message *m_ptr) return; /* already done */ } - { - r = SUSPEND; /* do suspend */ - pp->rdsendreply = FALSE; + if (m_ptr->FLAGS & FLG_OP_NONBLOCK) { + r = pp->rdcum > 0 ? pp->rdcum : EAGAIN; + pp->rdleft = pp->rdcum = 0; + pp->rdgrant = GRANT_INVALID; + } else { + return; /* do suspend */ } break; @@ -142,7 +143,6 @@ void do_pty(tty_t *tp, message *m_ptr) r = ENOBUFS; break; } - pp->wrsendreply = TRUE; pp->wrcaller = m_ptr->m_source; pp->wrproc = m_ptr->USER_ENDPT; pp->wrgrant = (cp_grant_id_t) m_ptr->IO_GRANT; @@ -154,32 +154,43 @@ void do_pty(tty_t *tp, message *m_ptr) return; /* already done */ } - { - pp->wrsendreply = FALSE; /* do suspend */ - r = SUSPEND; + if (m_ptr->FLAGS & FLG_OP_NONBLOCK) { + r = pp->wrcum > 0 ? pp->wrcum : EAGAIN; + pp->wrleft = pp->wrcum = 0; + pp->wrgrant = GRANT_INVALID; + r = EAGAIN; + } else { + return; /* do suspend */ } break; case DEV_OPEN: - r = pp->state != 0 ? EIO : OK; - pp->state |= PTY_ACTIVE; - pp->rdcum = 0; - pp->wrcum = 0; - break; + if (!(pp->state & PTY_ACTIVE)) { + pp->state |= PTY_ACTIVE; + pp->rdcum = 0; + pp->wrcum = 0; + r = OK; + } else { + r = EIO; + } + tty_reply(DEV_OPEN_REPL, m_ptr->m_source, m_ptr->USER_ENDPT, + (cp_grant_id_t) m_ptr->IO_GRANT, r); + return; case DEV_CLOSE: - r = OK; - if (pp->state & TTY_CLOSED) { + if ((pp->state & (TTY_ACTIVE | TTY_CLOSED)) != TTY_ACTIVE) { pp->state = 0; } else { pp->state |= PTY_CLOSED; sigchar(tp, SIGHUP, 1); } - break; + tty_reply(DEV_CLOSE_REPL, m_ptr->m_source, m_ptr->USER_ENDPT, + (cp_grant_id_t) m_ptr->IO_GRANT, OK); + return; case DEV_SELECT: - r = pty_select(tp, m_ptr); - break; + pty_select(tp, m_ptr); + return; case CANCEL: r = EINTR; @@ -200,7 +211,8 @@ void do_pty(tty_t *tp, message *m_ptr) default: r = EINVAL; } - tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r); + tty_reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT, + (cp_grant_id_t) m_ptr->IO_GRANT, r); } /*===========================================================================* @@ -219,14 +231,10 @@ static int pty_write(tty_t *tp, int try) if (pp->state & PTY_CLOSED) { if (try) return 1; if (tp->tty_outleft > 0) { - if(tp->tty_outrepcode == TTY_REVIVE) { - notify(tp->tty_outcaller); - tp->tty_outrevived = 1; - } else { - tty_reply(tp->tty_outrepcode, tp->tty_outcaller, - tp->tty_outproc, EIO); - tp->tty_outleft = tp->tty_outcum = 0; - } + tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc, + tp->tty_outgrant, EIO); + tp->tty_outleft = tp->tty_outcum = 0; + tp->tty_outgrant = GRANT_INVALID; } return 0; } @@ -272,14 +280,10 @@ static int pty_write(tty_t *tp, int try) tp->tty_outcum += count; if ((tp->tty_outleft -= count) == 0) { /* Output is finished, reply to the writer. */ - if(tp->tty_outrepcode == TTY_REVIVE) { - notify(tp->tty_outcaller); - tp->tty_outrevived = 1; - } else { - tty_reply(tp->tty_outrepcode, tp->tty_outcaller, - tp->tty_outproc, tp->tty_outcum); - tp->tty_outcum = 0; - } + tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc, + tp->tty_outgrant, tp->tty_outcum); + tp->tty_outcum = 0; + tp->tty_outgrant = GRANT_INVALID; } } pty_finish(pp); @@ -349,12 +353,10 @@ static void pty_finish(pty_t *pp) * transferred. */ if (pp->rdcum > 0) { - if (pp->rdsendreply) { - tty_reply(TASK_REPLY, pp->rdcaller, pp->rdproc, pp->rdcum); - pp->rdleft = pp->rdcum = 0; - } - else - notify(pp->rdcaller); + tty_reply(DEV_REVIVE, pp->rdcaller, pp->rdproc, pp->rdgrant, + pp->rdcum); + pp->rdleft = pp->rdcum = 0; + pp->rdgrant = GRANT_INVALID; } } @@ -373,14 +375,10 @@ static int pty_read(tty_t *tp, int try) if (pp->state & PTY_CLOSED) { if (try) return 1; if (tp->tty_inleft > 0) { - if(tp->tty_inrepcode == TTY_REVIVE) { - notify(tp->tty_incaller); - tp->tty_inrevived = 1; - } else { - tty_reply(tp->tty_inrepcode, tp->tty_incaller, - tp->tty_inproc, tp->tty_incum); - tp->tty_inleft = tp->tty_incum = 0; - } + tty_reply(DEV_REVIVE, tp->tty_incaller, tp->tty_inproc, + tp->tty_ingrant, tp->tty_incum); + tp->tty_inleft = tp->tty_incum = 0; + tp->tty_ingrant = GRANT_INVALID; } return 1; } @@ -408,19 +406,34 @@ static int pty_read(tty_t *tp, int try) /* PTY writer bookkeeping. */ pp->wrcum++; if (--pp->wrleft == 0) { - if (pp->wrsendreply) { - tty_reply(TASK_REPLY, pp->wrcaller, pp->wrproc, - pp->wrcum); - pp->wrcum = 0; - } - else - notify(pp->wrcaller); + tty_reply(DEV_REVIVE, pp->wrcaller, pp->wrproc, pp->wrgrant, + pp->wrcum); + pp->wrcum = 0; + pp->wrgrant = GRANT_INVALID; } } return 0; } +/*===========================================================================* + * pty_open * + *===========================================================================*/ +static int pty_open(tty_t *tp, int UNUSED(try)) +{ +/* The tty side has been opened. */ + pty_t *pp = tp->tty_priv; + + /* TTY_ACTIVE may already be set, which would indicate that the slave is + * reopened after being fully closed while the master is still open. In that + * case TTY_CLOSED will also be set, so clear that one. + */ + pp->state |= TTY_ACTIVE; + pp->state &= ~TTY_CLOSED; + + return 0; +} + /*===========================================================================* * pty_close * *===========================================================================*/ @@ -432,16 +445,21 @@ static int pty_close(tty_t *tp, int UNUSED(try)) if (!(pp->state & PTY_ACTIVE)) return 0; if (pp->rdleft > 0) { - assert(!pp->rdsendreply); - notify(pp->rdcaller); + tty_reply(DEV_REVIVE, pp->rdcaller, pp->rdproc, pp->rdgrant, + pp->rdcum); + pp->rdleft = pp->rdcum = 0; + pp->rdgrant = GRANT_INVALID; } if (pp->wrleft > 0) { - assert(!pp->wrsendreply); - notify(pp->wrcaller); + tty_reply(DEV_REVIVE, pp->wrcaller, pp->wrproc, pp->wrgrant, + pp->wrcum); + pp->wrcum = 0; + pp->wrgrant = GRANT_INVALID; } - if (pp->state & PTY_CLOSED) pp->state = 0; else pp->state |= TTY_CLOSED; + if (pp->state & PTY_CLOSED) pp->state = 0; + else pp->state |= TTY_CLOSED; return 0; } @@ -455,9 +473,10 @@ static int pty_icancel(tty_t *tp, int UNUSED(try)) pty_t *pp = tp->tty_priv; if (pp->wrleft > 0) { - pp->wrcum += pp->wrleft; - pp->wrleft= 0; - notify(pp->wrcaller); + tty_reply(DEV_REVIVE, pp->wrcaller, pp->wrproc, pp->wrgrant, + pp->wrcum + pp->wrleft); + pp->wrcum = pp->wrleft = 0; + pp->wrgrant = GRANT_INVALID; } return 0; @@ -502,64 +521,11 @@ void pty_init(tty_t *tp) tp->tty_echo = pty_echo; tp->tty_icancel = pty_icancel; tp->tty_ocancel = pty_ocancel; + tp->tty_open = pty_open; tp->tty_close = pty_close; tp->tty_select_ops = 0; } -/*===========================================================================* - * pty_status * - *===========================================================================*/ -int pty_status(message *m_ptr) -{ - int i, event_found; - pty_t *pp; - - event_found = 0; - for (i= 0, pp = pty_table; istate & TTY_CLOSED) && pp->rdleft > 0) || - pp->rdcum > 0) && - pp->rdcaller == m_ptr->m_source) - { - m_ptr->m_type = DEV_REVIVE; - m_ptr->REP_ENDPT = pp->rdproc; - m_ptr->REP_IO_GRANT = pp->rdgrant; - m_ptr->REP_STATUS = pp->rdcum; - pp->rdleft = pp->rdcum = 0; - pp->rdgrant = GRANT_INVALID; - event_found = 1; - break; - } - - if ((((pp->state & TTY_CLOSED) && pp->wrleft > 0) || - pp->wrcum > 0) && - pp->wrcaller == m_ptr->m_source) - { - m_ptr->m_type = DEV_REVIVE; - m_ptr->REP_ENDPT = pp->wrproc; - m_ptr->REP_IO_GRANT = pp->wrgrant; - if (pp->wrcum == 0) - m_ptr->REP_STATUS = EIO; - else - m_ptr->REP_STATUS = pp->wrcum; - - pp->wrleft = pp->wrcum = 0; - pp->wrgrant = GRANT_INVALID; - event_found = 1; - break; - } - - if (pp->select_ready_ops && pp->select_proc == m_ptr->m_source) { - m_ptr->m_type = DEV_IO_READY; - m_ptr->DEV_MINOR = PTYPX_MINOR + i; - m_ptr->DEV_SEL_OPS = pp->select_ready_ops; - pp->select_ready_ops = 0; - event_found = 1; - break; - } - } - return event_found; -} - /*===========================================================================* * select_try_pty * *===========================================================================*/ @@ -591,35 +557,38 @@ static int select_try_pty(tty_t *tp, int ops) void select_retry_pty(tty_t *tp) { pty_t *pp = tp->tty_priv; + dev_t minor; int r; /* See if the pty side of a pty is ready to return a select. */ if (pp->select_ops && (r=select_try_pty(tp, pp->select_ops))) { + minor = PTYPX_MINOR + (int) (pp - pty_table); + assert(minor == pp->select_minor); + select_reply(DEV_SEL_REPL2, pp->select_proc, minor, r); pp->select_ops &= ~r; - pp->select_ready_ops |= r; - notify(pp->select_proc); } } /*===========================================================================* * pty_select * *===========================================================================*/ -static int pty_select(tty_t *tp, message *m) +static void pty_select(tty_t *tp, message *m) { pty_t *pp = tp->tty_priv; int ops, ready_ops = 0, watch; - ops = m->USER_ENDPT & (SEL_RD|SEL_WR|SEL_ERR); - watch = (m->USER_ENDPT & SEL_NOTIFY) ? 1 : 0; + ops = m->DEV_SEL_OPS & (SEL_RD|SEL_WR|SEL_ERR); + watch = (m->DEV_SEL_OPS & SEL_NOTIFY) ? 1 : 0; ready_ops = select_try_pty(tp, ops); if (!ready_ops && ops && watch) { pp->select_ops |= ops; pp->select_proc = m->m_source; + pp->select_minor = m->DEV_MINOR; } - return ready_ops; + select_reply(DEV_SEL_REPL1, m->m_source, m->DEV_MINOR, ready_ops); } #endif /* NR_PTYS > 0 */ diff --git a/drivers/tty/tty.c b/drivers/tty/tty.c index 8c28b0927..5465366a7 100644 --- a/drivers/tty/tty.c +++ b/drivers/tty/tty.c @@ -27,28 +27,25 @@ * DEV_OPEN: a tty line has been opened * DEV_CLOSE: a tty line has been closed * DEV_SELECT: start select notification request - * DEV_STATUS: FS wants to know status for SELECT or REVIVE * CANCEL: terminate a previous incomplete system call immediately * - * m_type TTY_LINE USER_ENDPT COUNT TTY_SPEKS IO_GRANT + * m_type DEVICE USER_ENDPT COUNT POSITION IO_GRANT * ----------------------------------------------------------------- * | HARD_INT | | | | | | * |-------------+---------+---------+---------+---------+---------| - * | SYS_SIG | sig set | | | | | - * |-------------+---------+---------+---------+---------+---------| * | DEV_READ |minor dev| proc nr | count | | grant | * |-------------+---------+---------+---------+---------+---------| * | DEV_WRITE |minor dev| proc nr | count | | grant | * |-------------+---------+---------+---------+---------+---------| - * | DEV_IOCTL |minor dev| proc nr |func code|erase etc| | + * | DEV_IOCTL |minor dev| proc nr |func code|user proc| | * |-------------+---------+---------+---------+---------+---------| * | DEV_OPEN |minor dev| proc nr | O_NOCTTY| | | * |-------------+---------+---------+---------+---------+---------| * | DEV_CLOSE |minor dev| proc nr | | | | * |-------------+---------+---------+---------+---------+---------| - * | DEV_STATUS | | | | | | - * |-------------+---------+---------+---------+---------+---------| * | CANCEL |minor dev| proc nr | | | | + * |-------------+---------+---------+---------+---------+---------| + * | DEV_SELECT |minor dev| sel ops | | | | * ----------------------------------------------------------------- * * Changes: @@ -111,7 +108,6 @@ static void do_close(tty_t *tp, message *m_ptr); static void do_read(tty_t *tp, message *m_ptr); static void do_write(tty_t *tp, message *m_ptr); static void do_select(tty_t *tp, message *m_ptr); -static void do_status(message *m_ptr); static void in_transfer(tty_t *tp); static int tty_echo(tty_t *tp, int ch); static void rawecho(tty_t *tp, int ch); @@ -164,7 +160,7 @@ int main(void) message tty_mess; /* buffer for all incoming messages */ int ipc_status; unsigned line; - int r; + int r, code; register tty_t *tp; /* SEF local startup. */ @@ -231,21 +227,16 @@ int main(void) ; /* do nothing; end switch */ } - /* Only device requests should get to this point. All requests, - * except DEV_STATUS, have a minor device number. Check this - * exception and get the minor device number otherwise. + /* Only device requests should get to this point. + * All requests have a minor device number. */ - if (tty_mess.m_type == DEV_STATUS) { - do_status(&tty_mess); - continue; - } - line = tty_mess.TTY_LINE; + line = tty_mess.DEVICE; if (line == CONS_MINOR || line == LOG_MINOR) { /* /dev/log output goes to /dev/console */ if (consoleline != CONS_MINOR) { /* Console output must redirected */ line = consoleline; - tty_mess.TTY_LINE = line; + tty_mess.DEVICE = line; } } if (line == KBD_MINOR) { @@ -274,10 +265,20 @@ int main(void) /* If the device doesn't exist or is not configured return ENXIO. */ if (tp == NULL || ! tty_active(tp)) { - if (tty_mess.m_source != LOG_PROC_NR) { - tty_reply(TASK_REPLY, tty_mess.m_source, - tty_mess.USER_ENDPT, ENXIO); + if (tty_mess.m_source == LOG_PROC_NR) + continue; + + /* Can all of these occur? Probably not. We're by far most + * likely to see DEV_OPEN, but better safe than sorry.. + */ + switch (tty_mess.m_type) { + case DEV_OPEN: code = DEV_OPEN_REPL; break; + case DEV_CLOSE: code = DEV_CLOSE_REPL; break; + default: code = DEV_REVIVE; break; } + + tty_reply(code, tty_mess.m_source, tty_mess.USER_ENDPT, + (cp_grant_id_t) tty_mess.IO_GRANT, ENXIO); continue; } @@ -293,8 +294,8 @@ int main(void) default: printf("Warning, TTY got unexpected request %d from %d\n", tty_mess.m_type, tty_mess.m_source); - tty_reply(TASK_REPLY, tty_mess.m_source, - tty_mess.USER_ENDPT, EINVAL); + tty_reply(DEV_REVIVE, tty_mess.m_source, tty_mess.USER_ENDPT, + (cp_grant_id_t) tty_mess.IO_GRANT, EINVAL); } } @@ -309,6 +310,7 @@ set_color(tty_t *tp, int color) buf[0] = '\033'; snprintf(&buf[1], sizeof(buf) - 1, "[1;%dm", color); + memset(&msg, 0, sizeof(msg)); msg.m_source = KERNEL; msg.IO_GRANT = buf; msg.COUNT = sizeof(buf); @@ -324,6 +326,7 @@ reset_color(tty_t *tp) #define SGR_COLOR_RESET 39 buf[0] = '\033'; snprintf(&buf[1], sizeof(buf) - 1, "[0;%dm", SGR_COLOR_RESET); + memset(&msg, 0, sizeof(msg)); msg.m_source = KERNEL; msg.IO_GRANT = buf; msg.COUNT = sizeof(buf); @@ -499,6 +502,7 @@ do_new_kmess(void) if (kernel_msg_color != 0) set_color(tp, kernel_msg_color); + memset(&print_kmsg, 0, sizeof(print_kmsg)); print_kmsg.m_source = KERNEL; print_kmsg.IO_GRANT = kernel_buf_copy; print_kmsg.COUNT = bytes; @@ -534,97 +538,6 @@ static void sef_cb_signal_handler(int signo) } } -/*===========================================================================* - * do_status * - *===========================================================================*/ -static void do_status(m_ptr) -message *m_ptr; -{ - register struct tty *tp; - int event_found; - int status; - int ops; - - /* Check for select or revive events on any of the ttys. If we found an, - * event return a single status message for it. The FS will make another - * call to see if there is more. - */ - event_found = 0; - for (tp = FIRST_TTY; tp < END_TTY; tp++) { - if ((ops = select_try(tp, tp->tty_select_ops)) && - tp->tty_select_proc == m_ptr->m_source) { - - /* I/O for a selected minor device is ready. */ - m_ptr->m_type = DEV_IO_READY; - m_ptr->DEV_MINOR = tp->tty_minor; - m_ptr->DEV_SEL_OPS = ops; - - tp->tty_select_ops &= ~ops; /* unmark select event */ - event_found = 1; - break; - } - else if (tp->tty_inrevived && tp->tty_incaller == m_ptr->m_source) { - - /* Suspended request finished. Send a REVIVE. */ - m_ptr->m_type = DEV_REVIVE; - m_ptr->REP_ENDPT = tp->tty_inproc; - m_ptr->REP_IO_GRANT = tp->tty_ingrant; - m_ptr->REP_STATUS = tp->tty_incum; - - tp->tty_inleft = tp->tty_incum = 0; - tp->tty_inrevived = 0; /* unmark revive event */ - tp->tty_ingrant = GRANT_INVALID; - event_found = 1; - break; - } - else if (tp->tty_outrevived && tp->tty_outcaller == m_ptr->m_source) { - - /* Suspended request finished. Send a REVIVE. */ - m_ptr->m_type = DEV_REVIVE; - m_ptr->REP_ENDPT = tp->tty_outproc; - m_ptr->REP_IO_GRANT = tp->tty_outgrant; - m_ptr->REP_STATUS = tp->tty_outcum; - - tp->tty_outcum = 0; - tp->tty_outrevived = 0; /* unmark revive event */ - tp->tty_outgrant = GRANT_INVALID; - event_found = 1; - break; - } - else if (tp->tty_iorevived && tp->tty_iocaller == m_ptr->m_source) { - - /* Suspended request finished. Send a REVIVE. */ - m_ptr->m_type = DEV_REVIVE; - m_ptr->REP_ENDPT = tp->tty_ioproc; - m_ptr->REP_IO_GRANT = tp->tty_iogrant; - m_ptr->REP_STATUS = tp->tty_iostatus; - tp->tty_iorevived = 0; /* unmark revive event */ - tp->tty_iogrant = GRANT_INVALID; - event_found = 1; - break; - } - } - -#if NR_PTYS > 0 - if (!event_found) - event_found = pty_status(m_ptr); -#endif - if (!event_found) - event_found= kbd_status(m_ptr); - - if (! event_found) { - /* No events of interest were found. Return an empty message. */ - m_ptr->m_type = DEV_NO_STATUS; - } - - /* Almost done. Send back the reply message to the caller. */ - status = send(m_ptr->m_source, m_ptr); - if (status != OK) { - printf("tty`do_status: send to %d failed: %d\n", - m_ptr->m_source, status); - } -} - /*===========================================================================* * do_read * *===========================================================================*/ @@ -651,7 +564,6 @@ register message *m_ptr; /* pointer to message sent to the task */ r = ENOBUFS; } else { /* Copy information from the message to the tty struct. */ - tp->tty_inrepcode = TASK_REPLY; tp->tty_incaller = m_ptr->m_source; tp->tty_inproc = m_ptr->USER_ENDPT; tp->tty_ingrant = (cp_grant_id_t) m_ptr->IO_GRANT; @@ -685,13 +597,18 @@ register message *m_ptr; /* pointer to message sent to the task */ return; /* already done */ } - /* There were no bytes in the input queue available, so suspend - * the caller. - */ - r = SUSPEND; /* suspend the caller */ - tp->tty_inrepcode = TTY_REVIVE; + /* There were no bytes in the input queue available. */ + if (m_ptr->FLAGS & FLG_OP_NONBLOCK) { + tty_icancel(tp); + r = tp->tty_incum > 0 ? tp->tty_incum : EAGAIN; + tp->tty_inleft = tp->tty_incum = 0; + tp->tty_ingrant = GRANT_INVALID; + } else { + return; /* suspend the caller */ + } } - tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r); + tty_reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT, + (cp_grant_id_t) m_ptr->IO_GRANT, r); if (tp->tty_select_ops) select_retry(tp); } @@ -716,7 +633,6 @@ register message *m_ptr; /* pointer to message sent to the task */ r = EINVAL; } else { /* Copy message parameters to the tty structure. */ - tp->tty_outrepcode = TASK_REPLY; tp->tty_outcaller = m_ptr->m_source; tp->tty_outproc = m_ptr->USER_ENDPT; tp->tty_outgrant = (cp_grant_id_t) m_ptr->IO_GRANT; @@ -728,13 +644,17 @@ register message *m_ptr; /* pointer to message sent to the task */ if (tp->tty_outleft == 0) return; /* already done */ - /* None or not all the bytes could be written, so suspend the - * caller. - */ - r = SUSPEND; /* suspend the caller */ - tp->tty_outrepcode = TTY_REVIVE; + /* None or not all the bytes could be written. */ + if (m_ptr->FLAGS & FLG_OP_NONBLOCK) { + r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN; + tp->tty_outleft = tp->tty_outcum = 0; + tp->tty_outgrant = GRANT_INVALID; + } else { + return; /* suspend the caller */ + } } - tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r); + tty_reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT, + (cp_grant_id_t) m_ptr->IO_GRANT, r); } /*===========================================================================* @@ -755,7 +675,7 @@ message *m_ptr; /* pointer to message sent to task */ size_t size; /* Size of the ioctl parameter. */ - switch (m_ptr->TTY_REQUEST) { + switch (m_ptr->REQUEST) { case TCGETS: /* Posix tcgetattr function */ case TCSETS: /* Posix tcsetattr function, TCSANOW option */ case TCSETSW: /* Posix tcsetattr function, TCSADRAIN option */ @@ -789,7 +709,7 @@ message *m_ptr; /* pointer to message sent to task */ } r = OK; - switch (m_ptr->TTY_REQUEST) { + switch (m_ptr->REQUEST) { case TCGETS: /* Get the termios attributes. */ r = sys_safecopyto(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT, 0, @@ -800,16 +720,20 @@ message *m_ptr; /* pointer to message sent to task */ case TCSETSF: case TCDRAIN: if (tp->tty_outleft > 0) { - /* Wait for all ongoing output processing to finish. */ - tp->tty_iocaller = m_ptr->m_source; - tp->tty_ioproc = m_ptr->USER_ENDPT; - tp->tty_ioreq = m_ptr->REQUEST; - tp->tty_iogrant = (cp_grant_id_t) m_ptr->IO_GRANT; - r = SUSPEND; + if (m_ptr->FLAGS & FLG_OP_NONBLOCK) { + r = EAGAIN; + } else { + /* Wait for all ongoing output processing to finish. */ + tp->tty_iocaller = m_ptr->m_source; + tp->tty_ioproc = m_ptr->USER_ENDPT; + tp->tty_ioreq = m_ptr->REQUEST; + tp->tty_iogrant = (cp_grant_id_t) m_ptr->IO_GRANT; + return; + } break; } - if (m_ptr->TTY_REQUEST == TCDRAIN) break; - if (m_ptr->TTY_REQUEST == TCSETSF) tty_icancel(tp); + if (m_ptr->REQUEST == TCDRAIN) break; + if (m_ptr->REQUEST == TCSETSF) tty_icancel(tp); /*FALL THROUGH*/ case TCSETS: /* Set the termios attributes. */ @@ -890,7 +814,8 @@ message *m_ptr; /* pointer to message sent to task */ } /* Send the reply. */ - tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r); + tty_reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT, + (cp_grant_id_t) m_ptr->IO_GRANT, r); } /*===========================================================================* @@ -906,7 +831,7 @@ message *m_ptr; /* pointer to message sent to task */ */ int r = OK; - if (m_ptr->TTY_LINE == LOG_MINOR) { + if (m_ptr->DEVICE == LOG_MINOR) { /* The log device is a write-only diagnostics device. */ if (m_ptr->COUNT & R_BIT) r = EACCES; } else { @@ -920,7 +845,8 @@ message *m_ptr; /* pointer to message sent to task */ (*tp->tty_open)(tp, 0); } } - tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r); + tty_reply(DEV_OPEN_REPL, m_ptr->m_source, m_ptr->USER_ENDPT, + (cp_grant_id_t) m_ptr->IO_GRANT, r); } /*===========================================================================* @@ -932,7 +858,7 @@ message *m_ptr; /* pointer to message sent to task */ { /* A tty line has been closed. Clean up the line if it is the last close. */ - if (m_ptr->TTY_LINE != LOG_MINOR && --tp->tty_openct == 0) { + if (m_ptr->DEVICE != LOG_MINOR && --tp->tty_openct == 0) { tp->tty_pgrp = 0; tty_icancel(tp); (*tp->tty_ocancel)(tp, 0); @@ -941,7 +867,8 @@ message *m_ptr; /* pointer to message sent to task */ tp->tty_winsize = winsize_defaults; setattr(tp); } - tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, OK); + tty_reply(DEV_CLOSE_REPL, m_ptr->m_source, m_ptr->USER_ENDPT, + (cp_grant_id_t) m_ptr->IO_GRANT, OK); } /*===========================================================================* @@ -954,35 +881,39 @@ message *m_ptr; /* pointer to message sent to task */ /* A signal has been sent to a process that is hanging trying to read or write. * The pending read or write must be finished off immediately. */ - - int proc_nr; + endpoint_t proc_nr; + cp_grant_id_t grant; int mode; - int r = EINTR; + int r = EDONTREPLY; /* Check the parameters carefully, to avoid cancelling twice. */ proc_nr = m_ptr->USER_ENDPT; + grant = (cp_grant_id_t) m_ptr->IO_GRANT; mode = m_ptr->COUNT; if ((mode & R_BIT) && tp->tty_inleft != 0 && proc_nr == tp->tty_inproc && - tp->tty_ingrant == (cp_grant_id_t) m_ptr->IO_GRANT) { + tp->tty_ingrant == grant) { /* Process was reading when killed. Clean up input. */ tty_icancel(tp); r = tp->tty_incum > 0 ? tp->tty_incum : EAGAIN; - tp->tty_inleft = tp->tty_incum = tp->tty_inrevived = 0; + tp->tty_inleft = tp->tty_incum = 0; tp->tty_ingrant = GRANT_INVALID; } if ((mode & W_BIT) && tp->tty_outleft != 0 && proc_nr == tp->tty_outproc && - tp->tty_outgrant == (cp_grant_id_t) m_ptr->IO_GRANT) { + tp->tty_outgrant == grant) { /* Process was writing when killed. Clean up output. */ r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN; - tp->tty_outleft = tp->tty_outcum = tp->tty_outrevived = 0; + tp->tty_outleft = tp->tty_outcum = 0; tp->tty_outgrant = GRANT_INVALID; } if (tp->tty_ioreq != 0 && proc_nr == tp->tty_ioproc) { /* Process was waiting for output to drain. */ tp->tty_ioreq = 0; + r = EINTR; } tp->tty_events = 1; - tty_reply(TASK_REPLY, m_ptr->m_source, proc_nr, r); + /* Only reply if we found a matching request. */ + if (r != EDONTREPLY) + tty_reply(DEV_REVIVE, m_ptr->m_source, proc_nr, grant, r); } int select_try(struct tty *tp, int ops) @@ -1021,8 +952,14 @@ int select_try(struct tty *tp, int ops) int select_retry(struct tty *tp) { - if (tp->tty_select_ops && select_try(tp, tp->tty_select_ops)) - notify(tp->tty_select_proc); + int ops; + + if (tp->tty_select_ops && (ops = select_try(tp, tp->tty_select_ops))) { + assert(tp->tty_select_minor == tp->tty_minor); + select_reply(DEV_SEL_REPL2, tp->tty_select_proc, tp->tty_minor, + ops); + tp->tty_select_ops &= ~ops; + } return OK; } @@ -1064,16 +1001,10 @@ tty_t *tp; /* TTY to check for events. */ /* Reply if enough bytes are available. */ if (tp->tty_incum >= tp->tty_min && tp->tty_inleft > 0) { - if (tp->tty_inrepcode == TTY_REVIVE) { - notify(tp->tty_incaller); - tp->tty_inrevived = 1; - } else { - tty_reply(tp->tty_inrepcode, tp->tty_incaller, - tp->tty_inproc, tp->tty_incum); - tp->tty_inleft = tp->tty_incum = 0; - tp->tty_inrevived = 0; - tp->tty_ingrant = GRANT_INVALID; - } + tty_reply(DEV_REVIVE, tp->tty_incaller, tp->tty_inproc, + tp->tty_ingrant, tp->tty_incum); + tp->tty_inleft = tp->tty_incum = 0; + tp->tty_ingrant = GRANT_INVALID; } if (tp->tty_select_ops) { @@ -1146,16 +1077,10 @@ register tty_t *tp; /* pointer to terminal to read from */ /* Usually reply to the reader, possibly even if incum == 0 (EOF). */ if (tp->tty_inleft == 0) { - if (tp->tty_inrepcode == TTY_REVIVE) { - notify(tp->tty_incaller); - tp->tty_inrevived = 1; - } else { - tty_reply(tp->tty_inrepcode, tp->tty_incaller, - tp->tty_inproc, tp->tty_incum); - tp->tty_inleft = tp->tty_incum = 0; - tp->tty_inrevived = 0; - tp->tty_ingrant = GRANT_INVALID; - } + tty_reply(DEV_REVIVE, tp->tty_incaller, tp->tty_inproc, + tp->tty_ingrant, tp->tty_incum); + tp->tty_inleft = tp->tty_incum = 0; + tp->tty_ingrant = GRANT_INVALID; } } @@ -1585,9 +1510,9 @@ tty_t *tp; if (result == OK) setattr(tp); } tp->tty_ioreq = 0; - notify(tp->tty_iocaller); - tp->tty_iorevived = 1; - tp->tty_iostatus = result; + tty_reply(DEV_REVIVE, tp->tty_iocaller, tp->tty_ioproc, tp->tty_iogrant, + result); + tp->tty_iogrant = GRANT_INVALID; } /*===========================================================================* @@ -1651,25 +1576,52 @@ tty_t *tp; *===========================================================================*/ void tty_reply_f( -file, line, code, replyee, proc_nr, status) +file, line, code, replyee, proc_nr, grant, status) char *file; int line; -int code; /* TASK_REPLY or REVIVE */ -int replyee; /* destination address for the reply */ -int proc_nr; /* to whom should the reply go? */ +int code; /* DEV_OPEN_REPL, DEV_CLOSE_REPL, DEV_REVIVE */ +endpoint_t replyee; /* destination address for the reply */ +endpoint_t proc_nr; /* to whom should the reply go? */ +cp_grant_id_t grant; /* which grant was involved? */ int status; /* reply code */ { -/* Send a reply to a process that wanted to read or write data. */ - assert(code == TASK_REPLY); + message m; + + assert(code == DEV_OPEN_REPL || code == DEV_CLOSE_REPL || code == DEV_REVIVE); /* Don't reply to KERNEL (kernel messages) */ if (replyee == KERNEL) return; - status = send_taskreply(replyee, proc_nr, status); + memset(&m, 0, sizeof(m)); + + m.REP_ENDPT = proc_nr; + m.REP_IO_GRANT = grant; + m.REP_STATUS = status; + + status = _sendcall(replyee, code, &m); if (status != OK) printf("tty`tty_reply: send to %d failed: %d\n", replyee, status); } +/*===========================================================================* + * select_reply * + *===========================================================================*/ +void select_reply(int code, endpoint_t replyee, dev_t minor, int ops) +{ + message m; + int status; + + memset(&m, 0, sizeof(m)); + + m.DEV_MINOR = minor; + m.DEV_SEL_OPS = ops; + + status = _sendcall(replyee, code, &m); + if (status != OK) + printf("tty`select_reply: send to %d failed: %d\n", replyee, status); +} + + /*===========================================================================* * sigchar * *===========================================================================*/ @@ -1808,18 +1760,17 @@ register message *m_ptr; /* pointer to message sent to the task */ { int ops, ready_ops = 0, watch; - ops = m_ptr->USER_ENDPT & (SEL_RD|SEL_WR|SEL_ERR); - watch = (m_ptr->USER_ENDPT & SEL_NOTIFY) ? 1 : 0; + ops = m_ptr->DEV_SEL_OPS & (SEL_RD|SEL_WR|SEL_ERR); + watch = (m_ptr->DEV_SEL_OPS & SEL_NOTIFY) ? 1 : 0; ready_ops = select_try(tp, ops); if (!ready_ops && ops && watch) { tp->tty_select_ops |= ops; tp->tty_select_proc = m_ptr->m_source; + tp->tty_select_minor = m_ptr->DEV_MINOR; } - tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, ready_ops); - - return; + assert(tp->tty_minor == m_ptr->DEV_MINOR); + select_reply(DEV_SEL_REPL1, m_ptr->m_source, tp->tty_minor, ready_ops); } - diff --git a/drivers/tty/tty.h b/drivers/tty/tty.h index 9bf4147de..1933692df 100644 --- a/drivers/tty/tty.h +++ b/drivers/tty/tty.h @@ -5,8 +5,6 @@ #undef lock #undef unlock -#define TTY_REVIVE 6767 - /* First minor numbers for the various classes of TTY devices. */ #define CONS_MINOR 0 #define LOG_MINOR 15 @@ -63,16 +61,12 @@ typedef struct tty { char tty_openct; /* count of number of opens of this tty */ /* Information about incomplete I/O requests is stored here. */ - int tty_inrepcode; /* reply code, TASK_REPLY or REVIVE */ - char tty_inrevived; /* set to 1 if revive callback is pending */ endpoint_t tty_incaller; /* process that made the call (usually VFS) */ endpoint_t tty_inproc; /* process that wants to read from tty */ cp_grant_id_t tty_ingrant; /* grant where data is to go */ vir_bytes tty_inoffset; /* offset into grant */ int tty_inleft; /* how many chars are still needed */ int tty_incum; /* # chars input so far */ - int tty_outrepcode; /* reply code, TASK_REPLY or REVIVE */ - int tty_outrevived; /* set to 1 if revive callback is pending */ endpoint_t tty_outcaller; /* process that made the call (usually VFS) */ endpoint_t tty_outproc; /* process that wants to write to tty */ cp_grant_id_t tty_outgrant; /* grant where data comes from */ @@ -80,15 +74,14 @@ typedef struct tty { int tty_outleft; /* # chars yet to be output */ int tty_outcum; /* # chars output so far */ endpoint_t tty_iocaller; /* process that made the call (usually VFS) */ - int tty_iorevived; /* set to 1 if revive callback is pending */ endpoint_t tty_ioproc; /* process that wants to do an ioctl */ - int tty_iostatus; /* result */ int tty_ioreq; /* ioctl request code */ cp_grant_id_t tty_iogrant; /* virtual address of ioctl buffer or grant */ /* select() data */ int tty_select_ops; /* which operations are interesting */ endpoint_t tty_select_proc; /* which process wants notification */ + dev_t tty_select_minor; /* sanity check only, can be removed */ /* Miscellaneous. */ devfun_t tty_ioctl; /* set line speed, etc. at the device level */ @@ -146,9 +139,10 @@ int in_process(struct tty *tp, char *buf, int count, int scode); void out_process(struct tty *tp, char *bstart, char *bpos, char *bend, int *icount, int *ocount); void tty_wakeup(clock_t now); -#define tty_reply(c, r, p, s) tty_reply_f(__FILE__, __LINE__, (c), (r), (p), (s)) -void tty_reply_f(char *f, int l, int code, int replyee, int proc_nr, int - status); +#define tty_reply(c, r, p, g, s) tty_reply_f(__FILE__, __LINE__, (c), (r), (p), (g), (s)) +void tty_reply_f(char *f, int l, int code, endpoint_t replyee, + endpoint_t proc_nr, cp_grant_id_t grant, int status); +void select_reply(int code, endpoint_t replyee, dev_t minor, int ops); int select_try(struct tty *tp, int ops); int select_retry(struct tty *tp); @@ -175,11 +169,8 @@ void kbd_interrupt(message *m); void do_kbd(message *m); void do_kb_inject(message *m); void do_kbdaux(message *m); -int kbd_status(message *m_ptr); /* pty.c */ void do_pty(struct tty *tp, message *m_ptr); void pty_init(struct tty *tp); void select_retry_pty(struct tty *tp); -int pty_status(message *m_ptr); - diff --git a/etc/rs.inet b/etc/rs.inet index 57c458827..8eb1529a0 100755 --- a/etc/rs.inet +++ b/etc/rs.inet @@ -65,7 +65,7 @@ kill_by_name syslogd sleep 3 if [ X`/bin/sysenv lwip` = Xyes ] then - service up /usr/sbin/lwip -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE_A + service up /usr/sbin/lwip -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE dhcpd --lwip & else service up /usr/sbin/inet -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE diff --git a/etc/usr/rc b/etc/usr/rc index 51f802a98..6156294e5 100644 --- a/etc/usr/rc +++ b/etc/usr/rc @@ -167,7 +167,7 @@ start) # Start servers and drivers set at the boot monitor. echo -n "Starting services:" - up -n random -dev /dev/random -devstyle STYLE_DEVA -period 3HZ + up -n random -dev /dev/random -period 3HZ # load random number generator if [ -f $RANDOM_FILE ] @@ -188,9 +188,9 @@ start) done if [ X`/bin/sysenv lwip` = Xyes ] then - up lwip -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE_A + up lwip -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE else - up inet -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE + up inet -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE fi up -n ipc diff --git a/include/minix/callnr.h b/include/minix/callnr.h index 629f04ec2..898c8a3d9 100644 --- a/include/minix/callnr.h +++ b/include/minix/callnr.h @@ -109,8 +109,5 @@ #define VFS_VMCALL 117 -#define TASK_REPLY 121 /* to VFS: reply code from drivers, not - * really a standalone call. - */ #define MAPDRIVER 122 /* to VFS, map a device */ #define GETRUSAGE 123 /* to PM, VFS */ diff --git a/include/minix/chardriver.h b/include/minix/chardriver.h index a7a594f67..c2146d1a8 100644 --- a/include/minix/chardriver.h +++ b/include/minix/chardriver.h @@ -19,17 +19,12 @@ struct chardriver { int(*cdr_other) (message *m_ptr); }; -#define CHARDRIVER_SYNC 0 /* use the synchronous protocol */ -#define CHARDRIVER_ASYNC 1 /* use the asynchronous protocol */ - -#define IS_CDEV_MINOR_RQ(type) (IS_DEV_RQ(type) && (type) != DEV_STATUS) - /* Functions defined by libchardriver. */ void chardriver_announce(void); -void chardriver_process(struct chardriver *cdp, int driver_type, message - *m_ptr, int ipc_status); +void chardriver_process(struct chardriver *cdp, message *m_ptr, + int ipc_status); void chardriver_terminate(void); -void chardriver_task(struct chardriver *cdp, int driver_type); +void chardriver_task(struct chardriver *cdp); int do_nop(message *m_ptr); void nop_cleanup(void); diff --git a/include/minix/com.h b/include/minix/com.h index 3100c2ac5..d6c805817 100644 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -196,7 +196,6 @@ #define DEV_OPEN (DEV_RQ_BASE + 6) /* open a minor device */ #define DEV_CLOSE (DEV_RQ_BASE + 7) /* close a minor device */ #define DEV_SELECT (DEV_RQ_BASE + 12) /* request select() attention */ -#define DEV_STATUS (DEV_RQ_BASE + 13) /* request driver status */ #define DEV_REOPEN (DEV_RQ_BASE + 14) /* reopen a minor device */ #define DEV_READ_S (DEV_RQ_BASE + 20) /* (safecopy) read from minor */ @@ -208,8 +207,6 @@ #define IS_DEV_RQ(type) (((type) & ~0xff) == DEV_RQ_BASE) #define DEV_REVIVE (DEV_RS_BASE + 2) /* driver revives process */ -#define DEV_IO_READY (DEV_RS_BASE + 3) /* selected device ready */ -#define DEV_NO_STATUS (DEV_RS_BASE + 4) /* empty status reply */ #define DEV_REOPEN_REPL (DEV_RS_BASE + 5) /* reply to DEV_REOPEN */ #define DEV_CLOSE_REPL (DEV_RS_BASE + 6) /* reply to DEV_CLOSE */ #define DEV_SEL_REPL1 (DEV_RS_BASE + 7) /* first reply to DEV_SELECT */ @@ -241,12 +238,6 @@ #define REP_IO_GRANT m2_i3 /* DEV_REVIVE: grant by which I/O was done */ # define SUSPEND -998 /* status to suspend caller, reply later */ -/* Field names for messages to TTY driver. */ -#define TTY_LINE DEVICE /* message parameter: terminal line */ -#define TTY_REQUEST COUNT /* message parameter: ioctl request code */ -#define TTY_SPEK POSITION/* message parameter: ioctl speed, erasing */ -#define TTY_PGRP m2_i3 /* message parameter: process group */ - /*===========================================================================* * Messages for networking layer * *===========================================================================*/ @@ -825,7 +816,6 @@ /* Additional parameters for PM_DUMPCORE */ # define PM_TERM_SIG m7_i2 /* process's termination signal */ -# define PM_TRACED_PROC m7_i3 /* required for T_DUMPCORE */ /* Parameters for the EXEC_NEWMEM call */ #define EXC_NM_PROC m1_i1 /* process that needs new map */ @@ -911,6 +901,11 @@ #define STATVFS_NAME m1_p1 #define STATVFS_BUF m1_p2 +/* Field names for the ioctl(2) call. */ +#define VFS_IOCTL_FD m2_i1 +#define VFS_IOCTL_REQ m2_i3 +#define VFS_IOCTL_ARG m2_p1 + /*===========================================================================* * Messages for VM server * *===========================================================================*/ diff --git a/include/minix/dmap.h b/include/minix/dmap.h index b041ee3e7..2387267fa 100644 --- a/include/minix/dmap.h +++ b/include/minix/dmap.h @@ -4,12 +4,8 @@ #include #include -enum dev_style { STYLE_NDEV, STYLE_DEV, STYLE_DEVA, STYLE_TTY, STYLE_CTTY, - STYLE_CLONE, STYLE_CLONE_A }; -#define IS_DEV_STYLE(s) (s>=STYLE_NDEV && s<=STYLE_CLONE_A) - -#define dev_style_asyn(devstyle) ((devstyle) == STYLE_DEVA || \ - (devstyle) == STYLE_CLONE_A) +enum dev_style { STYLE_NDEV, STYLE_DEV, STYLE_TTY, STYLE_CTTY, STYLE_CLONE }; +#define IS_DEV_STYLE(s) (s>=STYLE_NDEV && s<=STYLE_CLONE) /*===========================================================================* * Major and minor device numbers * diff --git a/include/minix/procfs.h b/include/minix/procfs.h index fec097b61..eb6733644 100644 --- a/include/minix/procfs.h +++ b/include/minix/procfs.h @@ -35,7 +35,6 @@ #define FSTATE_LOCK 'L' #define FSTATE_POPEN 'O' #define FSTATE_SELECT 'S' -#define FSTATE_DOPEN 'D' #define FSTATE_TASK 'T' #define FSTATE_UNKNOWN '?' diff --git a/include/minix/syslib.h b/include/minix/syslib.h index 0d1a922da..2a34c97e5 100644 --- a/include/minix/syslib.h +++ b/include/minix/syslib.h @@ -159,8 +159,6 @@ int sys_umap_data_fb(endpoint_t proc_ep, vir_bytes vir_addr, vir_bytes int sys_umap_remote(endpoint_t proc_ep, endpoint_t grantee, int seg, vir_bytes vir_addr, vir_bytes bytes, phys_bytes *phys_addr); -int send_taskreply(endpoint_t who, endpoint_t endpoint, int status); - /* Shorthands for sys_getinfo() system call. */ #define sys_getkinfo(dst) sys_getinfo(GET_KINFO, dst, 0,0,0) #define sys_getloadinfo(dst) sys_getinfo(GET_LOADINFO, dst, 0,0,0) diff --git a/lib/libaudiodriver/audio_fw.c b/lib/libaudiodriver/audio_fw.c index 34ae2f5e8..13a1bde5f 100644 --- a/lib/libaudiodriver/audio_fw.c +++ b/lib/libaudiodriver/audio_fw.c @@ -20,11 +20,7 @@ * |-------------+---------+---------+---------+---------+---------| * | DEV_IOCTL_S | device | proc nr |func code| | buf ptr | * |-------------+---------+---------+---------+---------+---------| - * | DEV_STATUS | | | | | | - * |-------------+---------+---------+---------+---------+---------| * | HARD_INT | | | | | | - * |-------------+---------+---------+---------+---------+---------| - * | SIG_STOP | | | | | | * ----------------------------------------------------------------- * * The file contains one entry point: @@ -81,7 +77,6 @@ static void sef_cb_signal_handler(int signo); EXTERN int sef_cb_lu_prepare(int state); EXTERN int sef_cb_lu_state_isvalid(int state); EXTERN void sef_cb_lu_state_dump(int state); -int is_status_msg_expected = FALSE; int main(void) { @@ -121,8 +116,10 @@ int main(void) case DEV_OPEN: /* open the special file ( = parameter) */ r = msg_open(mess.DEVICE); - repl_mess.m_type = DEV_REVIVE; + repl_mess.m_type = DEV_OPEN_REPL; repl_mess.REP_ENDPT = mess.USER_ENDPT; + repl_mess.REP_IO_GRANT = + (cp_grant_id_t) mess.IO_GRANT; repl_mess.REP_STATUS = r; send(caller, &repl_mess); @@ -133,6 +130,8 @@ int main(void) r = msg_close(mess.DEVICE); repl_mess.m_type = DEV_CLOSE_REPL; repl_mess.REP_ENDPT = mess.USER_ENDPT; + repl_mess.REP_IO_GRANT = + (cp_grant_id_t) mess.IO_GRANT; repl_mess.REP_STATUS = r; send(caller, &repl_mess); @@ -146,7 +145,7 @@ int main(void) repl_mess.m_type = DEV_REVIVE; repl_mess.REP_ENDPT = mess.USER_ENDPT; repl_mess.REP_IO_GRANT = - (unsigned)mess.IO_GRANT; + (cp_grant_id_t) mess.IO_GRANT; repl_mess.REP_STATUS = r; send(caller, &repl_mess); } @@ -156,13 +155,13 @@ int main(void) msg_read(&mess); continue; /* don't reply */ case DEV_WRITE_S: msg_write(&mess); continue; /* don't reply */ - case DEV_STATUS: - msg_status(&mess);continue; /* don't reply */ case DEV_REOPEN: /* reopen the special file ( = parameter) */ r = msg_open(mess.DEVICE); repl_mess.m_type = DEV_REOPEN_REPL; repl_mess.REP_ENDPT = mess.USER_ENDPT; + repl_mess.REP_IO_GRANT = + (cp_grant_id_t) mess.IO_GRANT; repl_mess.REP_STATUS = r; send(caller, &repl_mess); continue; @@ -626,35 +625,6 @@ static void msg_hardware(void) { } -static void msg_status(message *m_ptr) -{ - int i; - - for (i = 0; i < drv.NrOfSubDevices; i++) { - - if(sub_dev[i].ReadyToRevive) - { - m_ptr->m_type = DEV_REVIVE; /* build message */ - m_ptr->REP_ENDPT = sub_dev[i].ReviveProcNr; - m_ptr->REP_IO_GRANT = sub_dev[i].ReviveGrant; - m_ptr->REP_STATUS = sub_dev[i].ReviveStatus; - send(m_ptr->m_source, m_ptr); /* send the message */ - - /* reset variables */ - sub_dev[i].ReadyToRevive = FALSE; - sub_dev[i].RevivePending = 0; - - is_status_msg_expected = TRUE; - return; /* stop after one mess, - file system will get back for other processes */ - } - } - m_ptr->m_type = DEV_NO_STATUS; - m_ptr->REP_STATUS = 0; - send(m_ptr->m_source, m_ptr); /* send DEV_NO_STATUS message */ - is_status_msg_expected = FALSE; -} - /* handle interrupt for specified sub device; DmaMode == DEV_WRITE_S*/ static void handle_int_write(int sub_dev_nr) { @@ -712,6 +682,7 @@ static void handle_int_write(int sub_dev_nr) static void handle_int_read(int sub_dev_nr) { sub_dev_t *sub_dev_ptr; + message m; sub_dev_ptr = &sub_dev[sub_dev_nr]; @@ -729,9 +700,14 @@ static void handle_int_read(int sub_dev_nr) printf("All buffers full, we have a problem.\n"); drv_stop(sub_dev_nr); /* stop the sub device */ sub_dev_ptr->DmaBusy = FALSE; - sub_dev_ptr->ReviveStatus = 0; /* no data for user, - this is a sad story */ - sub_dev_ptr->ReadyToRevive = TRUE; /* wake user up */ + sub_dev_ptr->ReviveStatus = 0; /* no data for user, + * this is a sad story + */ + m.m_type = DEV_REVIVE; + m.REP_ENDPT = sub_dev_ptr->ReviveProcNr; + m.REP_IO_GRANT = sub_dev_ptr->ReviveGrant; + m.REP_STATUS = sub_dev_ptr->ReviveStatus; + send(sub_dev_ptr->SourceProcNr, &m); return; } else { /* dma full, still room in extra buf; @@ -790,9 +766,6 @@ static void data_from_user(sub_dev_t *subdev) if (!subdev->RevivePending) return; /* no new data waiting to be copied */ - if (subdev->RevivePending && - subdev->ReadyToRevive) return; /* we already got this data */ - if (subdev->DmaLength < subdev->NrOfDmaFragments) { /* room in dma buf */ r = sys_safecopyfrom(subdev->SourceProcNr, @@ -835,7 +808,6 @@ static void data_from_user(sub_dev_t *subdev) } subdev->ReviveStatus = subdev->FragSize; - subdev->ReadyToRevive = TRUE; m.m_type = DEV_REVIVE; /* build message */ m.REP_ENDPT = subdev->ReviveProcNr; @@ -849,7 +821,6 @@ static void data_from_user(sub_dev_t *subdev) } /* reset variables */ - subdev->ReadyToRevive = FALSE; subdev->RevivePending = 0; } @@ -860,7 +831,6 @@ static void data_to_user(sub_dev_t *sub_dev_ptr) message m; if (!sub_dev_ptr->RevivePending) return; /* nobody is wating for data */ - if (sub_dev_ptr->ReadyToRevive) return;/* we already filled user's buffer */ if (sub_dev_ptr->BufLength == 0 && sub_dev_ptr->DmaLength == 0) return; /* no data for user */ @@ -896,7 +866,6 @@ static void data_to_user(sub_dev_t *sub_dev_ptr) } sub_dev_ptr->ReviveStatus = sub_dev_ptr->FragSize; - sub_dev_ptr->ReadyToRevive = TRUE; /* drv_status will send REVIVE mess to FS*/ m.m_type = DEV_REVIVE; /* build message */ @@ -911,7 +880,6 @@ static void data_to_user(sub_dev_t *sub_dev_ptr) } /* reset variables */ - sub_dev_ptr->ReadyToRevive = FALSE; sub_dev_ptr->RevivePending = 0; } diff --git a/lib/libaudiodriver/liveupdate.c b/lib/libaudiodriver/liveupdate.c index 96b8a35fe..19364c1b3 100644 --- a/lib/libaudiodriver/liveupdate.c +++ b/lib/libaudiodriver/liveupdate.c @@ -1,7 +1,5 @@ #include -/* State management variables. */ -EXTERN int is_status_msg_expected; /* * - From audio_fw.h: * EXTERN drv_t drv; @@ -60,8 +58,7 @@ int sef_cb_lu_prepare(int state) break; case SEF_LU_STATE_PROTOCOL_FREE: - is_ready = (!is_read_pending && !is_write_pending - && !is_status_msg_expected); + is_ready = (!is_read_pending && !is_write_pending); break; /* Custom states. */ @@ -95,8 +92,6 @@ void sef_cb_lu_state_dump(int state) load_state_info(); sef_lu_dprint("audio: live update state = %d\n", state); - sef_lu_dprint("audio: is_status_msg_expected = %d\n", - is_status_msg_expected); sef_lu_dprint("audio: is_read_pending = %d\n", is_read_pending); sef_lu_dprint("audio: is_write_pending = %d\n", is_write_pending); @@ -105,8 +100,7 @@ void sef_cb_lu_state_dump(int state) sef_lu_dprint("audio: SEF_LU_STATE_REQUEST_FREE(%d) reached = %d\n", SEF_LU_STATE_REQUEST_FREE, (!is_read_pending && !is_write_pending)); sef_lu_dprint("audio: SEF_LU_STATE_PROTOCOL_FREE(%d) reached = %d\n", - SEF_LU_STATE_PROTOCOL_FREE, (!is_read_pending && !is_write_pending - && !is_status_msg_expected)); + SEF_LU_STATE_PROTOCOL_FREE, (!is_read_pending && !is_write_pending)); sef_lu_dprint("audio: AUDIO_STATE_READ_REQUEST_FREE(%d) reached = %d\n", AUDIO_STATE_READ_REQUEST_FREE, (!is_read_pending)); sef_lu_dprint("audio: AUDIO_STATE_WRITE_REQUEST_FREE(%d) reached = %d\n", diff --git a/lib/libc/sys-minix/ioctl.c b/lib/libc/sys-minix/ioctl.c index c61478473..fa2d00f94 100644 --- a/lib/libc/sys-minix/ioctl.c +++ b/lib/libc/sys-minix/ioctl.c @@ -73,9 +73,9 @@ void *data; break; } - m.TTY_LINE = fd; - m.TTY_REQUEST = request; - m.ADDRESS = (char *) addr; + m.VFS_IOCTL_FD = fd; + m.VFS_IOCTL_REQ = request; + m.VFS_IOCTL_ARG = (char *) addr; r = _syscall(VFS_PROC_NR, IOCTL, &m); diff --git a/lib/libchardriver/chardriver.c b/lib/libchardriver/chardriver.c index 13fa620b0..178ff1394 100644 --- a/lib/libchardriver/chardriver.c +++ b/lib/libchardriver/chardriver.c @@ -28,6 +28,7 @@ * driver_receive: message receive interface for drivers * * Changes: + * Oct 20, 2013 retire synchronous protocol (D.C. van Moolenbroek) * Oct 16, 2011 split character and block protocol (D.C. van Moolenbroek) * Aug 27, 2011 move common functions into driver.c (A. Welzel) * Jul 25, 2005 added SYS_SIG type for signals (Jorrit N. Herder) @@ -117,16 +118,19 @@ void chardriver_announce(void) } /*===========================================================================* - * async_reply * + * send_reply * *===========================================================================*/ -static void async_reply(message *mess, int r) +static void send_reply(message *mess, int ipc_status, int r) { -/* Send a reply using the asynchronous character device protocol. */ +/* Prepare and send a reply message. */ message reply_mess; - /* Do not reply with ERESTART in this protocol. The only possible caller, - * VFS, will find out through other means when we have restarted, and is not - * (fully) ready to deal with ERESTART errors. + if (r == EDONTREPLY) + return; + + /* Do not reply with ERESTART. The only possible caller, VFS, will find out + * through other means when we have restarted, and is not (fully) ready to + * deal with ERESTART errors. */ if (r == ERESTART) return; @@ -150,7 +154,7 @@ static void async_reply(message *mess, int r) case DEV_WRITE_S: case DEV_IOCTL_S: if (r == SUSPEND) - printf("driver_task: reviving %d (%d) with SUSPEND\n", + printf("chardriver_task: reviving %d (%d) with SUSPEND\n", mess->m_source, mess->USER_ENDPT); reply_mess.m_type = DEV_REVIVE; @@ -170,60 +174,22 @@ static void async_reply(message *mess, int r) break; default: - reply_mess.m_type = TASK_REPLY; + reply_mess.m_type = DEV_REVIVE; reply_mess.REP_ENDPT = mess->USER_ENDPT; /* Status is # of bytes transferred or error code. */ reply_mess.REP_STATUS = r; break; } - r = asynsend(mess->m_source, &reply_mess); - - if (r != OK) - printf("asyn_reply: unable to asynsend reply to %d: %d\n", - mess->m_source, r); -} - -/*===========================================================================* - * sync_reply * - *===========================================================================*/ -static void sync_reply(message *m_ptr, int ipc_status, int reply) -{ -/* Reply to a message sent to the driver. */ - endpoint_t caller_e, user_e; - int r; - - caller_e = m_ptr->m_source; - user_e = m_ptr->USER_ENDPT; - - m_ptr->m_type = TASK_REPLY; - m_ptr->REP_ENDPT = user_e; - m_ptr->REP_STATUS = reply; - /* If we would block sending the message, send it asynchronously. */ if (IPC_STATUS_CALL(ipc_status) == SENDREC) - r = sendnb(caller_e, m_ptr); + r = sendnb(mess->m_source, &reply_mess); else - r = asynsend(caller_e, m_ptr); + r = asynsend3(mess->m_source, &reply_mess, AMF_NOREPLY); if (r != OK) - printf("driver_reply: unable to send reply to %d: %d\n", caller_e, r); -} - -/*===========================================================================* - * send_reply * - *===========================================================================*/ -static void send_reply(int type, message *m_ptr, int ipc_status, int reply) -{ -/* Prepare and send a reply message. */ - - if (reply == EDONTREPLY) - return; - - if (type == CHARDRIVER_ASYNC) - async_reply(m_ptr, reply); - else - sync_reply(m_ptr, ipc_status, reply); + printf("send_reply: unable to send reply to %d: %d\n", + mess->m_source, r); } /*===========================================================================* @@ -343,7 +309,7 @@ static int handle_request(struct chardriver *cdp, message *m_ptr) * requests on devices that have not previously been opened, signaling the * caller that something went wrong. */ - if (IS_CDEV_MINOR_RQ(m_ptr->m_type) && !is_open_dev(m_ptr->DEVICE)) { + if (IS_DEV_RQ(m_ptr->m_type) && !is_open_dev(m_ptr->DEVICE)) { /* Reply ERESTART to spurious requests for unopened devices. */ if (m_ptr->m_type != DEV_OPEN) return ERESTART; @@ -380,8 +346,7 @@ static int handle_request(struct chardriver *cdp, message *m_ptr) /*===========================================================================* * chardriver_process * *===========================================================================*/ -void chardriver_process(struct chardriver *cdp, int driver_type, - message *m_ptr, int ipc_status) +void chardriver_process(struct chardriver *cdp, message *m_ptr, int ipc_status) { /* Handle the given received message. */ int r; @@ -394,14 +359,14 @@ void chardriver_process(struct chardriver *cdp, int driver_type, } else { r = handle_request(cdp, m_ptr); - send_reply(driver_type, m_ptr, ipc_status, r); + send_reply(m_ptr, ipc_status, r); } } /*===========================================================================* * chardriver_task * *===========================================================================*/ -void chardriver_task(struct chardriver *cdp, int driver_type) +void chardriver_task(struct chardriver *cdp) { /* Main program of any device driver task. */ int r, ipc_status; @@ -416,7 +381,7 @@ void chardriver_task(struct chardriver *cdp, int driver_type) if ((r = sef_receive_status(ANY, &mess, &ipc_status)) != OK) panic("driver_receive failed: %d", r); - chardriver_process(cdp, driver_type, &mess, ipc_status); + chardriver_process(cdp, &mess, ipc_status); } } diff --git a/lib/libddekit/src/msg_queue.c b/lib/libddekit/src/msg_queue.c index 3ea82708b..a68e6cf10 100644 --- a/lib/libddekit/src/msg_queue.c +++ b/lib/libddekit/src/msg_queue.c @@ -93,19 +93,14 @@ _ddekit_minix_queue_msg ( full = ddekit_sem_down_try(mq->msg_w_sem); if (full) { - /* Our message queue is full... inform the sender. */ + /* Our message queue is full... */ int result; - DDEBUG_MSG_WARN("Receive queue is full. Ommiting ingoing msg.\n"); - - m->m_type = TASK_REPLY; - m->REP_STATUS = EAGAIN; - result = asynsend(m->m_source, m); - - if (result != 0) { - ddekit_panic("unable to send reply to %d: %d\n", - m->m_source, result); - } + DDEBUG_MSG_WARN("Receive queue is full. Dropping request.\n"); + /* XXX should reply to the sender with EIO or so, but for that + * we would need to look at the request and find a suitable + * reply code.. + */ } else { /* queue the message */ memcpy(&mq->messages[mq->msg_w_pos], m, sizeof(message)); diff --git a/lib/libmthread/misc.c b/lib/libmthread/misc.c index 86c8800ac..51c99c8ab 100644 --- a/lib/libmthread/misc.c +++ b/lib/libmthread/misc.c @@ -122,10 +122,14 @@ void mthread_stacktrace(mthread_thread_t t) mcontext_t *mtx; struct stackframe_s *frame; - printf("thread %d: ", t); - tcb = mthread_find_tcb(t); ctx = &tcb->m_context; + + if (t != MAIN_THREAD && ctx->uc_stack.ss_size == 0) + return; /* no stack, no stacktrace */ + + printf("thread %d: ", t); + mtx = &ctx->uc_mcontext; frame = &mtx->mc_p_reg; bp = frame->fp; diff --git a/lib/libsys/Makefile b/lib/libsys/Makefile index 9b2ec3d36..711152d35 100644 --- a/lib/libsys/Makefile +++ b/lib/libsys/Makefile @@ -76,7 +76,6 @@ SRCS+= \ sys_vsafecopy.c \ sys_vtimer.c \ sys_vumap.c \ - send_taskreply.c \ taskcall.c \ tickdelay.c \ timers.c \ diff --git a/lib/libsys/send_taskreply.c b/lib/libsys/send_taskreply.c deleted file mode 100644 index c14daf573..000000000 --- a/lib/libsys/send_taskreply.c +++ /dev/null @@ -1,20 +0,0 @@ - -#include - -#include "syslib.h" - -/*===========================================================================* - * sys_taskreply * - *===========================================================================*/ -int send_taskreply(endpoint_t who, endpoint_t endpoint, int status) -{ - message m; - - memset(&m, 0, sizeof(m)); - - m.REP_ENDPT = endpoint; - m.REP_STATUS = status; - - return _sendcall(who, TASK_REPLY, &m); -} - diff --git a/man/man1/Makefile b/man/man1/Makefile index 2e7f2b231..b85201a27 100644 --- a/man/man1/Makefile +++ b/man/man1/Makefile @@ -3,8 +3,7 @@ MAN= ash.1 at.1 \ chmod.1 cmp.1 comm.1 compress.1 \ cp.1 crc.1 crontab.1 dd.1 \ df.1 dhrystone.1 dosdir.1 dosread.1 doswrite.1 \ - dumpcore.1 eject.1 \ - env.1 factor.1 \ + eject.1 env.1 factor.1 \ flexdoc.1 fold.1 format.1 fortune.1 \ fsck.mfs.1 host.1 hostaddr.1 ifdef.1 \ isodir.1 isoinfo.1 isoread.1 \ diff --git a/man/man1/dumpcore.1 b/man/man1/dumpcore.1 deleted file mode 100644 index 2f3926a93..000000000 --- a/man/man1/dumpcore.1 +++ /dev/null @@ -1,29 +0,0 @@ -.TH DUMPCORE 1 -.SH NAME -dumpcore \- generate core file of running process -.SH SYNOPSIS -dumpcore \fIpid\fR -.br -.de FL -.TP -\\fB\\$1\\fR -\\$2 -.. -.de EX -.TP 20 -\\fB\\$1\\fR -# \\$2 -.. -.SH DESCRIPTION -The \fBdumpcore\fR utility generates a core file for a running process, based -on that process's process ID (\fIpid\fP). The resulting core file will be -stored under the name "core" in the current working directory. Any previous -file with that name will be overwritten. -.PP -The resulting core file can be used with for example -.BR mdb (1). -.SH BUGS -The process of generating the core file is currently very rudimentary, and -the generated core file does not contain for example memory mapped areas. -.SH "SEE ALSO" -.BR mdb (1). diff --git a/servers/inet/sr.c b/servers/inet/sr.c index a84792c45..cd82917b7 100644 --- a/servers/inet/sr.c +++ b/servers/inet/sr.c @@ -25,31 +25,10 @@ * | DEV_SELECT | minor dev | ops | | | * |-------------+-----------+-----------+-----------+-----------| * - * m_type - * --------------| - * | DEV_STATUS | - * |-------------| - * * m_type DEVICE USER_ENDPT COUNT * --------------------------------------------------| * | CANCEL | minor dev | proc nr | mode | * |-------------+-----------+-----------+-----------| - * - * Replies: - * - * m_type REP_ENDPT REP_STATUS REP_IO_GRANT - * -------------------------------------------------------| - * | TASK_REPLY | proc nr | status | grant ID | - * |---------------+-----------+-----------+--------------| - * - * m_type REP_ENDPT REP_STATUS REP_IO_GRANT - * ----------------+-----------+--------------------------| - * | DEV_REVIVE | proc nr | | grant ID | - * |---------------+-----------+-----------+--------------| - * | DEV_IO_READY | minor dev | sel ops | | - * |---------------+-----------+-----------+--------------| - * | DEV_NO_STATUS | | | | - * |---------------+-----------+-----------+--------------| */ #include "inet.h" @@ -72,7 +51,6 @@ THIS_FILE sr_fd_t sr_fd_table[FD_NR]; -static mq_t *repl_queue, *repl_queue_tail; static struct vscp_vec s_cp_req[SCPVEC_NR]; static int sr_open(message *m); @@ -82,16 +60,14 @@ static int sr_restart_read(sr_fd_t *fdp); static int sr_restart_write(sr_fd_t *fdp); static int sr_restart_ioctl(sr_fd_t *fdp); static int sr_cancel(message *m); -static int sr_select(message *m); -static void sr_status(message *m); -static void sr_reply_(mq_t *m, int reply, int is_revive); +static void sr_select(message *m); +static void sr_reply_(mq_t *m, int code, int reply, int is_revive); static sr_fd_t *sr_getchannel(int minor); static acc_t *sr_get_userdata(int fd, size_t offset, size_t count, int for_ioctl); static int sr_put_userdata(int fd, size_t offset, acc_t *data, int for_ioctl); static void sr_select_res(int fd, unsigned ops); -static int sr_repl_queue(int proc, int ref, int operation); static int walk_queue(sr_fd_t *sr_fd, mq_t **q_head_ptr, mq_t **q_tail_ptr, int type, int proc_nr, int ref, int first_flag); static void sr_event(event_t *evp, ev_arg_t arg); @@ -111,44 +87,26 @@ void sr_init() ev_init(&sr_fd_table[i].srf_read_ev); ev_init(&sr_fd_table[i].srf_write_ev); } - repl_queue= NULL; } void sr_rec(m) mq_t *m; { - int result; + int code = DEV_REVIVE, result; int send_reply = 0, free_mess = 0; - if (repl_queue) - { - if (m->mq_mess.m_type == CANCEL) - { - result= sr_repl_queue(m->mq_mess.USER_ENDPT, - (int)m->mq_mess.IO_GRANT, 0); - - if (result) - { - mq_free(m); - return; /* canceled request in queue */ - } - } -#if 0 - else - sr_repl_queue(ANY, 0, 0); -#endif - } - switch (m->mq_mess.m_type) { case DEV_OPEN: result= sr_open(&m->mq_mess); + code= DEV_OPEN_REPL; send_reply= 1; free_mess= 1; break; case DEV_CLOSE: sr_close(&m->mq_mess); result= OK; + code= DEV_CLOSE_REPL; send_reply= 1; free_mess= 1; break; @@ -156,25 +114,19 @@ mq_t *m; case DEV_WRITE_S: case DEV_IOCTL_S: result= sr_rwio(m); - assert(result == OK || result == SUSPEND); - send_reply= (result == SUSPEND); - free_mess= 0; + assert(result == OK || result == EAGAIN || result == EINTR || + result == SUSPEND); + send_reply= (result == EAGAIN); + free_mess= (result == EAGAIN); break; case CANCEL: result= sr_cancel(&m->mq_mess); - assert(result == OK || result == EINTR); + assert(result == OK || result == EINTR || result == SUSPEND); send_reply= (result == EINTR); free_mess= 1; - m->mq_mess.m_type= 0; break; case DEV_SELECT: - result= sr_select(&m->mq_mess); - send_reply= 1; - free_mess= 1; - break; - case DEV_STATUS: - sr_status(&m->mq_mess); - result= OK; /* Satisfy lint. */ + sr_select(&m->mq_mess); send_reply= 0; free_mess= 1; break; @@ -184,7 +136,7 @@ mq_t *m; } if (send_reply) { - sr_reply_(m, result, FALSE /* !is_revive */); + sr_reply_(m, code, result, FALSE /* !is_revive */); } if (free_mess) mq_free(m); @@ -323,6 +275,9 @@ mq_t *m; assert(sr_fd->srf_flags & susp_flag); assert(*q_head_ptr); + if (m->mq_mess.FLAGS & FLG_OP_NONBLOCK) + return EAGAIN; + (*q_tail_ptr)->mq_next= m; *q_tail_ptr= m; return SUSPEND; @@ -368,9 +323,14 @@ mq_t *m; assert(r == OK || r == SUSPEND || (printf("r= %d\n", r), 0)); - if (r == SUSPEND) + if (r == SUSPEND) { sr_fd->srf_flags |= susp_flag; - else + if (m->mq_mess.FLAGS & FLG_OP_NONBLOCK) { + r= sr_cancel(&m->mq_mess); + assert(r == OK); /* must have been head of queue */ + return EINTR; + } + } else mq_free(m); return r; } @@ -460,7 +420,6 @@ message *m; int result; int proc_nr, ref; - result=EINTR; proc_nr= m->USER_ENDPT; ref= (int)m->IO_GRANT; sr_fd= sr_getchannel(m->DEVICE); @@ -484,27 +443,24 @@ message *m; if (result != EAGAIN) return result; - ip_panic(( -"request not found: from %d, type %d, MINOR= %d, PROC= %d, REF= %d", - m->m_source, m->m_type, m->DEVICE, - m->USER_ENDPT, (int) m->IO_GRANT)); - - return result; + /* We already replied to the request, so don't reply to the CANCEL. */ + return SUSPEND; } -static int sr_select(m) +static void sr_select(m) message *m; { + message m_reply; sr_fd_t *sr_fd; int r; unsigned m_ops, i_ops; - sr_fd= sr_getchannel(m->DEVICE); + sr_fd= sr_getchannel(m->DEV_MINOR); assert (sr_fd); sr_fd->srf_select_proc= m->m_source; - m_ops= m->USER_ENDPT; + m_ops= m->DEV_SEL_OPS; i_ops= 0; if (m_ops & SEL_RD) i_ops |= SR_SELECT_READ; if (m_ops & SEL_WR) i_ops |= SR_SELECT_WRITE; @@ -512,72 +468,22 @@ message *m; if (!(m_ops & SEL_NOTIFY)) i_ops |= SR_SELECT_POLL; r= (*sr_fd->srf_select)(sr_fd->srf_fd, i_ops); - if (r < 0) - return r; - m_ops= 0; - if (r & SR_SELECT_READ) m_ops |= SEL_RD; - if (r & SR_SELECT_WRITE) m_ops |= SEL_WR; - if (r & SR_SELECT_EXCEPTION) m_ops |= SEL_ERR; - - return m_ops; -} - -static void sr_status(m) -message *m; -{ - int fd, result; - unsigned m_ops; - sr_fd_t *sr_fd; - mq_t *mq; - - mq= repl_queue; - if (mq != NULL) - { - repl_queue= mq->mq_next; - - mq->mq_mess.m_type= DEV_REVIVE; - result= send(mq->mq_mess.m_source, &mq->mq_mess); - if (result != OK) - ip_panic(("unable to send")); - mq_free(mq); - - return; - } - - for (fd=0, sr_fd= sr_fd_table; fdsrf_flags & - (SFF_SELECT_R|SFF_SELECT_W|SFF_SELECT_X)) == 0) - { - /* Nothing to report */ - continue; - } - if (sr_fd->srf_select_proc != m->m_source) - { - /* Wrong process */ - continue; - } - + if (r < 0) { + m_ops= r; + } else { m_ops= 0; - if (sr_fd->srf_flags & SFF_SELECT_R) m_ops |= SEL_RD; - if (sr_fd->srf_flags & SFF_SELECT_W) m_ops |= SEL_WR; - if (sr_fd->srf_flags & SFF_SELECT_X) m_ops |= SEL_ERR; - - sr_fd->srf_flags &= ~(SFF_SELECT_R|SFF_SELECT_W|SFF_SELECT_X); - - m->m_type= DEV_IO_READY; - m->DEV_MINOR= fd; - m->DEV_SEL_OPS= m_ops; - - result= send(m->m_source, m); - if (result != OK) - ip_panic(("unable to send")); - return; + if (r & SR_SELECT_READ) m_ops |= SEL_RD; + if (r & SR_SELECT_WRITE) m_ops |= SEL_WR; + if (r & SR_SELECT_EXCEPTION) m_ops |= SEL_ERR; } - m->m_type= DEV_NO_STATUS; - result= send(m->m_source, m); - if (result != OK) + memset(&m_reply, 0, sizeof(m_reply)); + m_reply.m_type= DEV_SEL_REPL1; + m_reply.DEV_MINOR= m->DEV_MINOR; + m_reply.DEV_SEL_OPS= m_ops; + + r= send(m->m_source, &m_reply); + if (r != OK) ip_panic(("unable to send")); } @@ -642,8 +548,9 @@ int minor; return loc_fd; } -static void sr_reply_(mq, status, is_revive) +static void sr_reply_(mq, code, status, is_revive) mq_t *mq; +int code; int status; int is_revive; { @@ -658,30 +565,12 @@ int is_revive; else mp= &reply; - mp->m_type= TASK_REPLY; + mp->m_type= code; mp->REP_ENDPT= proc; mp->REP_STATUS= status; mp->REP_IO_GRANT= ref; - if (is_revive) - { - notify(mq->mq_mess.m_source); - result= ELOCKED; - } - else - { - result= send(mq->mq_mess.m_source, mp); - } + result= send(mq->mq_mess.m_source, mp); - if (result == ELOCKED && is_revive) - { - mq->mq_next= NULL; - if (repl_queue) - repl_queue_tail->mq_next= mq; - else - repl_queue= mq; - repl_queue_tail= mq; - return; - } if (result != OK) ip_panic(("unable to send")); if (is_revive) @@ -730,7 +619,7 @@ int for_ioctl; *head_ptr= mq; result= (int)offset; is_revive= !(loc_fd->srf_flags & first_flag); - sr_reply_(m, result, is_revive); + sr_reply_(m, DEV_REVIVE, result, is_revive); suspended= (loc_fd->srf_flags & susp_flag); loc_fd->srf_flags &= ~(ip_flag|susp_flag); if (suspended) @@ -791,7 +680,7 @@ int for_ioctl; *head_ptr= mq; result= (int)offset; is_revive= !(loc_fd->srf_flags & first_flag); - sr_reply_(m, result, is_revive); + sr_reply_(m, DEV_REVIVE, result, is_revive); suspended= (loc_fd->srf_flags & susp_flag); loc_fd->srf_flags &= ~(ip_flag|susp_flag); if (suspended) @@ -811,15 +700,26 @@ int for_ioctl; static void sr_select_res(int fd, unsigned ops) { + message m; sr_fd_t *sr_fd; + unsigned int m_ops; + int result; sr_fd= &sr_fd_table[fd]; - - if (ops & SR_SELECT_READ) sr_fd->srf_flags |= SFF_SELECT_R; - if (ops & SR_SELECT_WRITE) sr_fd->srf_flags |= SFF_SELECT_W; - if (ops & SR_SELECT_EXCEPTION) sr_fd->srf_flags |= SFF_SELECT_X; - notify(sr_fd->srf_select_proc); + m_ops= 0; + if (ops & SR_SELECT_READ) m_ops |= SEL_RD; + if (ops & SR_SELECT_WRITE) m_ops |= SEL_WR; + if (ops & SR_SELECT_EXCEPTION) m_ops |= SEL_ERR; + + memset(&m, 0, sizeof(m)); + m.m_type= DEV_SEL_REPL2; + m.DEV_MINOR= fd; + m.DEV_SEL_OPS= m_ops; + + result= send(sr_fd->srf_select_proc, &m); + if (result != OK) + ip_panic(("unable to send")); } static void sr_event(evp, arg) @@ -989,45 +889,6 @@ vir_bytes offset; return OK; } -static int sr_repl_queue(proc, ref, operation) -int proc; -int ref; -int operation; -{ - mq_t *m, *m_cancel, *m_tmp; - mq_t *new_queue; - int result; - - m_cancel= NULL; - new_queue= NULL; - - for (m= repl_queue; m;) - { - if (m->mq_mess.REP_ENDPT == proc && - m->mq_mess.REP_IO_GRANT == ref) - { - assert(!m_cancel); - m_cancel= m; - m= m->mq_next; - continue; - } - m_tmp= m; - m= m->mq_next; - m_tmp->mq_next= new_queue; - new_queue= m_tmp; - } - repl_queue= new_queue; - if (m_cancel) - { - result= send(m_cancel->mq_mess.m_source, &m_cancel->mq_mess); - if (result != OK) - ip_panic(("unable to send: %d", result)); - mq_free(m_cancel); - return 1; - } - return 0; -} - /* * $PchId: sr.c,v 1.17 2005/06/28 14:26:16 philip Exp $ */ diff --git a/servers/inet/sr_int.h b/servers/inet/sr_int.h index 0a5494ecd..4699c9da4 100644 --- a/servers/inet/sr_int.h +++ b/servers/inet/sr_int.h @@ -43,9 +43,6 @@ typedef struct sr_fd #define SFF_IOCTL_FIRST 0x200 #define SFF_READ_FIRST 0x400 #define SFF_WRITE_FIRST 0x800 -#define SFF_SELECT_R 0x1000 -#define SFF_SELECT_W 0x2000 -#define SFF_SELECT_X 0x4000 EXTERN sr_fd_t sr_fd_table[FD_NR]; diff --git a/servers/is/dmp_fs.c b/servers/is/dmp_fs.c index ee486c99d..b12bfb268 100644 --- a/servers/is/dmp_fs.c +++ b/servers/is/dmp_fs.c @@ -74,11 +74,9 @@ static char * dmap_style(int dev_style) { switch(dev_style) { case STYLE_DEV: return "STYLE_DEV"; - case STYLE_DEVA: return "STYLE_DEVA"; case STYLE_TTY: return "STYLE_TTY"; case STYLE_CTTY: return "STYLE_CTTY"; case STYLE_CLONE: return "STYLE_CLONE"; - case STYLE_CLONE_A: return "STYLE_CLONE_A"; default: return "UNKNOWN"; } } diff --git a/servers/pfs/dev_uds.c b/servers/pfs/dev_uds.c index cada761a5..6664a3aaf 100644 --- a/servers/pfs/dev_uds.c +++ b/servers/pfs/dev_uds.c @@ -152,7 +152,7 @@ int uds_open(message *dev_m_in, message *dev_m_out) uds_fd_table[minor].suspended = UDS_NOT_SUSPENDED; /* and the socket doesn't have an I/O grant initially */ - uds_fd_table[minor].io_gr = (cp_grant_id_t) 0; + uds_fd_table[minor].io_gr = GRANT_INVALID; /* since there is no I/O grant it effectively has no size either */ uds_fd_table[minor].io_gr_size = 0; @@ -813,6 +813,13 @@ int uds_ioctl(message *dev_m_in, message *dev_m_out) /* update the owner endpoint - yes it's really stored in POSITION */ uds_fd_table[minor].owner = dev_m_in->POSITION; + /* update the process endpoint, which may well be different */ + uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT; + + /* save I/O Grant info */ + uds_fd_table[minor].io_gr = (cp_grant_id_t) dev_m_in->IO_GRANT; + uds_fd_table[minor].io_gr_size = 0; /* should not be used here */ + switch (dev_m_in->COUNT) { /* Handle the ioctl(2) command */ case NWIOSUDSCONN: @@ -1074,14 +1081,8 @@ int uds_cancel(message *dev_m_in, message *dev_m_out) minor = uds_minor(dev_m_in); if (uds_fd_table[minor].state != UDS_INUSE) { - - /* attempted to close a socket that hasn't been opened -- - * something is very wrong :( - */ - uds_set_reply(dev_m_out, DEV_NO_STATUS, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); - - return EINVAL; + /* attempted to cancel an unknown request - this happens */ + return SUSPEND; } /* Update the process endpoint. */ @@ -1184,8 +1185,7 @@ int uds_cancel(message *dev_m_in, message *dev_m_out) uds_fd_table[minor].syscall_done = 1; } - - uds_set_reply(dev_m_out, DEV_NO_STATUS, dev_m_in->USER_ENDPT, + uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT, (cp_grant_id_t) dev_m_in->IO_GRANT, EINTR); return EINTR; diff --git a/servers/pfs/table.c b/servers/pfs/table.c index ff3e62da3..af1e754ca 100644 --- a/servers/pfs/table.c +++ b/servers/pfs/table.c @@ -61,10 +61,10 @@ int (*dev_call_vec[])(message *dev_m_in, message *dev_m_out) = { uds_close, /* 7 DEV_CLOSE */ no_sys, /* 8 */ no_sys, /* 9 */ - no_sys, /* 10 TTY_SETPGRP */ - no_sys, /* 11 TTY_EXIT */ + no_sys, /* 10 */ + no_sys, /* 11 */ uds_select, /* 12 DEV_SELECT */ - no_sys, /* 13 DEV_STATUS */ + no_sys, /* 13 */ uds_open, /* 14 DEV_REOPEN */ no_sys, /* 15 */ no_sys, /* 16 */ diff --git a/servers/pm/forkexit.c b/servers/pm/forkexit.c index 6e01f41ee..8cc065af5 100644 --- a/servers/pm/forkexit.c +++ b/servers/pm/forkexit.c @@ -320,11 +320,10 @@ int dump_core; /* flag indicating whether to dump core */ /* Tell VFS about the exiting process. */ m.m_type = dump_core ? PM_DUMPCORE : PM_EXIT; m.PM_PROC = rmp->mp_endpoint; - m.PM_TRACED_PROC = rmp->mp_endpoint; if (dump_core) { - m.PM_TERM_SIG = rmp->mp_sigstatus; - m.PM_PATH = rmp->mp_name; + m.PM_TERM_SIG = rmp->mp_sigstatus; + m.PM_PATH = rmp->mp_name; } tell_vfs(rmp, &m); diff --git a/servers/pm/main.c b/servers/pm/main.c index ace611bf4..19b972c34 100644 --- a/servers/pm/main.c +++ b/servers/pm/main.c @@ -447,15 +447,7 @@ static void handle_vfs_reply() if (m_in.PM_STATUS == OK) rmp->mp_sigstatus |= DUMPED; - if (m_in.PM_PROC == m_in.PM_TRACED_PROC) - /* The reply is to a core dump request - * for a killed process */ - exit_restart(rmp, TRUE /*dump_core*/); - else - /* The reply is to a core dump request - * for a traced process (T_DUMPCORE) */ - /* Wake up the original caller */ - setreply(rmp-mproc, rmp->mp_procgrp); + exit_restart(rmp, TRUE /*dump_core*/); break; diff --git a/servers/pm/trace.c b/servers/pm/trace.c index 522a401f0..17d4e1d9b 100644 --- a/servers/pm/trace.c +++ b/servers/pm/trace.c @@ -91,27 +91,6 @@ int do_trace() mp->mp_reply.reply_trace = 0; return(OK); - case T_DUMPCORE: - if ((child = find_proc(m_in.pid)) == NULL) return(ESRCH); - - /* Allow dumpcore only if traced! */ - if (child->mp_tracer != who_p) return(EPERM); - - /* Tell VFS to dump the core. */ - m.m_type = PM_DUMPCORE; - m.PM_PROC = mp->mp_endpoint; - m.PM_TRACED_PROC = child->mp_endpoint; - /* Note that m.PM_PROC != m.PM_TRACED_PROC - * (we use this to differentiate between a VFS core dump reply for a - * an exiting process and the one for a traced process) */ - - m.PM_TERM_SIG = child->mp_sigstatus; - m.PM_PATH = child->mp_name; - - tell_vfs(mp, &m); - - return(SUSPEND); /* Suspend the process until we receive reply from VFS */ - case T_STOP: /* stop the process */ /* This call is not exposed to user programs, because its effect can be * achieved better by sending the traced process a signal with kill(2). diff --git a/servers/procfs/pid.c b/servers/procfs/pid.c index f37e049a1..b6e7becc9 100644 --- a/servers/procfs/pid.c +++ b/servers/procfs/pid.c @@ -136,7 +136,6 @@ static void pid_psinfo(int i) case FP_BLOCKED_ON_LOCK: f_state = FSTATE_LOCK; break; case FP_BLOCKED_ON_POPEN: f_state = FSTATE_POPEN; break; case FP_BLOCKED_ON_SELECT: f_state = FSTATE_SELECT; break; - case FP_BLOCKED_ON_DOPEN: f_state = FSTATE_DOPEN; break; case FP_BLOCKED_ON_OTHER: f_state = FSTATE_TASK; break; default: f_state = FSTATE_UNKNOWN; } diff --git a/servers/rs/table.c b/servers/rs/table.c index 4bcb40dfb..80595dcb1 100644 --- a/servers/rs/table.c +++ b/servers/rs/table.c @@ -47,8 +47,8 @@ struct boot_image_dev boot_image_dev_table[] = { /*endpoint, flags, dev_nr, dev_style, dev_style2 */ { TTY_PROC_NR, SRV_DF, TTY_MAJOR, STYLE_TTY, STYLE_CTTY }, { MEM_PROC_NR, SRV_DF, MEMORY_MAJOR, STYLE_DEV, STYLE_NDEV }, - { LOG_PROC_NR, SRV_DF, LOG_MAJOR, STYLE_DEVA, STYLE_NDEV }, - { PFS_PROC_NR, SRV_DF, UDS_MAJOR, STYLE_CLONE_A,STYLE_NDEV }, + { LOG_PROC_NR, SRV_DF, LOG_MAJOR, STYLE_DEV, STYLE_NDEV }, + { PFS_PROC_NR, SRV_DF, UDS_MAJOR, STYLE_CLONE,STYLE_NDEV }, { DEFAULT_BOOT_NR, SRV_DF, 0, STYLE_NDEV, STYLE_NDEV } /* default * entry */ diff --git a/servers/vfs/README b/servers/vfs/README index a6ee74d5e..cf5b82ea1 100644 --- a/servers/vfs/README +++ b/servers/vfs/README @@ -106,83 +106,87 @@ know the details of the protocol. Upon start up, VFS spawns a configurable amount of worker threads. The main thread fetches requests and replies, and hands them off to idle or reply-pending workers, respectively. If no worker threads are available, -the request is queued. There are 3 types of worker threads: normal, a system -worker, and a deadlock resolver. All standard system calls are handled by -normal worker threads. Jobs from PM and notifications from the kernel are taken -care of by the system worker. The deadlock resolver handles jobs from system +the request is queued. All standard system calls are handled by such worker +threads. One of the threads is reserved to handle new requests from system processes (i.e., File Servers and drivers) when there are no normal worker threads available; all normal threads might be blocked on a single worker thread that caused a system process to send a request on its own. To unblock -all normal threads, we need to reserve one thread to handle that situation. -VFS drives all File Servers and drivers asynchronously. While waiting for -a reply, a worker thread is blocked and other workers can keep processing -requests. Upon reply the worker thread is unblocked. -As mentioned above, the main thread is responsible for retrieving new jobs and -replies to current jobs and start or unblock the proper worker thread. Given -how many sources for new jobs and replies there are, the work for the main -thread is quite complicated. Consider Table 1. -{{{ ---------------------------------------------------------- -| From | normal | deadlock | system | ---------------------------------------------------------- - msg is new job ---------------------------------------------------------- -| PM | | | X | -+----------------------+----------+----------+----------+ -| Notification from | | | | -| the kernel | | | X | -+----------------------+----------+----------+----------+ -| Notification from | | | | -| DS or system process | X | X | | -+----------------------+----------+----------+----------+ -| User process | X | | | -+----------------------+----------+----------+----------+ -| Unsuspended process | X | | | ---------------------------------------------------------- - msg is reply ---------------------------------------------------------- -| File Server reply | resume | | | -+----------------------+----------+----------+----------+ -| Sync. driver reply | resume | | | -+----------------------+----------+----------+----------+ -| Async. driver reply | resume/X | X | | ---------------------------------------------------------- -}}} -Table 1: VFS' message fetching main loop. X means 'start thread'. +all normal threads, we need to reserve one spare thread to handle that +situation. VFS drives all File Servers and drivers asynchronously. While +waiting for a reply, a worker thread is blocked and other workers can keep +processing requests. Upon reply the worker thread is unblocked. -The reason why asynchronous driver replies get their own thread is for the -following. In some cases, a reply has a thread blocked waiting for it which -can be resumed (e.g., open). In another case there's a lot of work to be -done which involves sending new messages (e.g., select replies). Finally, -DEV_REVIVE replies unblock suspended processes which in turn generate new jobs -to be handled by the main loop (e.g., suspended reads and writes). So depending -on the reply a new thread has to be started. Having all this logic in the main -loop is messy, so we start a thread regardless of the actual reply contents. -When there are no worker threads available and there is no need to invoke -the deadlock resolver (i.e., normal system calls), the request is queued in -the fproc table. This works because a process can send only one system call -at a time. When implementing kernel threads, one has to take this assumption -into account. -The protocol PM speaks with VFS is asynchronous and PM is allowed to -send as many request to VFS as it wants. It is impossible to use the same -queueing mechanism as normal processes use, because that would allow for -just 1 queued message. Instead, the system worker maintains a linked list -of pending requests. Moreover, this queueing mechanism is also the reason -why notifications from the kernel are handled by the system worker; the -kernel has no corresponding fproc table entry (so we can't store it there) -and the linked list has no dependencies on that table. -Communication with drivers is asynchronous even when the driver uses the -synchronous driver protocol. However, to guarantee identical behavior, -access to synchronous drivers is serialized. File Servers are treated -differently. VFS was designed to be able to send requests concurrently to -File Servers, although at the time of writing there are no File Servers that -can actually make use of that functionality. To identify which reply from an -FS belongs to which worker thread, all requests have an embedded transaction -identification number (a magic number + thread id encoded in the mtype field -of a message) which the FS has to echo upon reply. Because the range of valid -transaction IDs is isolated from valid system call numbers, VFS can use that -ID to differentiate between replies from File Servers and actual new system -calls from FSes. Using this mechanism VFS is able to support FUSE and ProcFS. +As mentioned above, the main thread is responsible for retrieving new jobs and +replies to current jobs and start or unblock the proper worker thread. +Driver replies are processed directly from the main thread. As a consequence, +these processing routines may not block their calling thread. In some cases, +these routines may resume a thread that is blocked waiting for the reply. This +is always the case for block driver replies, and may or may not be the case for +character driver replies. The character driver reply processing routines may +also unblock suspended processes which in turn generate new jobs to be handled +by the main loop (e.g., suspended reads and writes on pipes). So depending +on the reply a new thread may have to be started. + +Worker threads are strictly tied to a process, and each process can have at +most one worker thread running for it. Generally speaking, there are two types +of work supported by worker threads: normal work, and work from PM. The main +subtype of normal work is the handling of a system call made by the process +itself. The process is blocked while VFS is handling the system call, so no new +system call can arrive from a process while VFS has not completed a previous +system call from that process. For that reason, if there are no worker threads +available to handle the work, the work is queued in the corresponding process +entry of the fproc table. + +The other main type of work consists of requests from PM. The protocol PM +speaks with VFS is asynchronous. PM is allowed to send up to one request per +process to VFS, in addition to a request to initiate a reboot. Most jobs from +PM are taken care of immediately by the main thread, but some jobs require a +worker thread context (to be able to sleep) and/or serialization with normal +work. Therefore, each process may have a PM request queued for execution, also +in the fproc table. Managing proper queuing, addition, and execution of both +normal and PM work is the responsibility of the worker thread infrastructure. + +There are several special tasks that require a worker thread, and these are +implemented as normal work associated with a certain special process that does +not make regular VFS calls anyway. For example, the initial ramdisk mount +procedure and the post-crash filp garbage collector use a thread associated +with the VFS process. Some of these special tasks require protection against +being started multiple times at once, as this is not only undesirable but also +disallowed. The full list of worker thread task types and subtypes is shown in +Table 1. + +{{{ +------------------------------------------------------------------------- +| Worker thread task | Type | Association | May use spare? | ++---------------------------+--------+-----------------+----------------+ +| system call from process | normal | calling process | if system proc | ++---------------------------+--------+-----------------+----------------+ +| resumed pipe operation | normal | calling process | no | ++---------------------------+--------+-----------------+----------------+ +| postponed PM request | PM | target process | no | ++---------------------------+--------+-----------------+----------------+ +| DS event notification | normal | DS | yes | ++---------------------------+--------+-----------------+----------------+ +| filp garbage collection | normal | VFS | no | ++---------------------------+--------+-----------------+----------------+ +| initial ramdisk mounting | normal | VFS | no | ++---------------------------+--------+-----------------+----------------+ +| reboot sequence | normal | PM | no | +------------------------------------------------------------------------- +}}} +Table 1: worker thread work types and subtypes + +Communication with block drivers is asynchronous, but at this time, access to +these drivers is serialized on a per-driver basis. File Servers are treated +differently. VFS was designed to be able to send requests concurrently to File +Servers, although at the time of writing there are no File Servers that can +actually make use of that functionality. To identify which reply from an FS +belongs to which worker thread, all requests have an embedded transaction +identification number (a magic number + thread id encoded in the mtype field of +a message) which the FS has to echo upon reply. Because the range of valid +transaction IDs is isolated from valid system call numbers, VFS can use that ID +to differentiate between replies from File Servers and actual new system calls +from FSes. Using this mechanism VFS is able to support FUSE and ProcFS. == Locking == ## 4 Locking @@ -306,22 +310,42 @@ fproc, vmnt, vnode, and filp objects. To prevent deadlocks as a result of object locking, we need to define a strict locking order. In VFS we use the following order: -fproc -> [exec] -> vmnt -> vnode -> filp -> [block special file] -> [dmap] +{{{ +fproc > [exec] > vmnt > vnode > filp > [block special file] > [dmap] +}}} That is, no thread may lock an fproc object while holding a vmnt lock, and no thread may lock a vmnt object while holding an (associated) vnode, etc. + Fproc needs protection because processes themselves can initiate system calls, but also PM can cause system calls that have to be executed in their name. For example, a process might be busy reading from a character device and another process sends a termination signal. The exit(2) that follows is sent by PM and is to be executed by the to-be-killed process itself. At this point there is contention for the fproc object that belongs to the process, -hence the need for protection. -The exec(2) call is protected by a mutex for the following reason. VFS uses a -number of variables on the heap to read ELF headers. They are on the heap due -to their size; putting them on the stack would increase stack size demands for -worker threads. The exec call does blocking read calls and thus needs exclusive -access to these variables. However, only the exec(2) syscall needs this lock. +hence the need for protection. This problem is solved in a simple way. Recall +that all worker threads are bound to a process. This also forms the basis of +fproc locking: each worker thread acquires and holds the fproc lock for its +associated process for as long as it is processing work for that process. + +There are two cases where a worker thread may hold the lock to more than one +process. First, as mentioned, the reboot procedure is executed from a worker +thread set in the context of the PM process, thus with the PM process entry +lock held. The procedure itself then acquires a temporary lock on every other +process in turn, in order to clean it up without interference. Thus, the PM +process entry is higher up in the locking order than all other process entries. + +Second, the exec(2) call is protected by a lock, and this exec lock is +currently implemented as a lock on the VM process entry. The exec lock is +acquired by a worker thread for the process performing the exec(2) call, and +thus, the VM process entry is below all other process entries in the locking +order. The exec(2) call is protected by a lock for the following reason. VFS +uses a number of variables on the heap to read ELF headers. They are on the +heap due to their size; putting them on the stack would increase stack size +demands for worker threads. The exec call does blocking read calls and thus +needs exclusive access to these variables. However, only the exec(2) syscall +needs this lock. + Access to block special files needs to be exclusive. File Servers are responsible for handling reads from and writes to block special files; if a block special file is on a device that is mounted, the FS responsible for diff --git a/servers/vfs/comm.c b/servers/vfs/comm.c index 41760827f..9e8ab8a74 100644 --- a/servers/vfs/comm.c +++ b/servers/vfs/comm.c @@ -1,7 +1,4 @@ #include "fs.h" -#include "glo.h" -#include "vmnt.h" -#include "fproc.h" #include #include diff --git a/servers/vfs/const.h b/servers/vfs/const.h index 7262aee70..7373bd47f 100644 --- a/servers/vfs/const.h +++ b/servers/vfs/const.h @@ -6,7 +6,7 @@ #define NR_LOCKS 8 /* # slots in the file locking table */ #define NR_MNTS 16 /* # slots in mount table */ #define NR_VNODES 1024 /* # slots in vnode table */ -#define NR_WTHREADS 8 /* # slots in worker thread table */ +#define NR_WTHREADS 9 /* # slots in worker thread table */ #define NR_NONEDEVS NR_MNTS /* # slots in nonedev bitmap */ @@ -20,15 +20,14 @@ #define FP_BLOCKED_ON_LOCK 2 /* susp'd on lock */ #define FP_BLOCKED_ON_POPEN 3 /* susp'd on pipe open */ #define FP_BLOCKED_ON_SELECT 4 /* susp'd on select */ -#define FP_BLOCKED_ON_DOPEN 5 /* susp'd on device open */ -#define FP_BLOCKED_ON_OTHER 6 /* blocked on other process, check +#define FP_BLOCKED_ON_OTHER 5 /* blocked on other process, check fp_task to find out */ /* test if the process is blocked on something */ #define fp_is_blocked(fp) ((fp)->fp_blocked_on != FP_BLOCKED_ON_NONE) /* test if reply is a driver reply */ -#define IS_DRV_REPLY(x) (IS_DEV_RS(x) || IS_BDEV_RS(x) || (x) == TASK_REPLY) +#define IS_DRV_REPLY(x) (IS_DEV_RS(x) || IS_BDEV_RS(x)) #define DUP_MASK 0100 /* mask to distinguish dup2 from dup */ #define LOOK_UP 0 /* tells search_dir to lookup string */ @@ -43,10 +42,4 @@ * M3_LONG_STRING. */ -/* Args to dev_io */ -#define VFS_DEV_READ 2001 -#define VFS_DEV_WRITE 2002 -#define VFS_DEV_IOCTL 2005 -#define VFS_DEV_SELECT 2006 - #endif diff --git a/servers/vfs/coredump.c b/servers/vfs/coredump.c index 578d43df5..f1a3f800d 100644 --- a/servers/vfs/coredump.c +++ b/servers/vfs/coredump.c @@ -1,7 +1,6 @@ #include "fs.h" #include #include -#include "fproc.h" #include #include #include diff --git a/servers/vfs/device.c b/servers/vfs/device.c index ab42a2238..59a1f49b8 100644 --- a/servers/vfs/device.c +++ b/servers/vfs/device.c @@ -5,12 +5,13 @@ * dev_open: open a character device * dev_reopen: reopen a character device after a driver crash * dev_close: close a character device + * cdev_reply: process the result of a character driver request * bdev_open: open a block device * bdev_close: close a block device + * bdev_reply: process the result of a block driver request * dev_io: FS does a read or write on a device - * dev_status: FS processes callback request alert - * gen_opcl: generic call to a task to perform an open/close - * gen_io: generic call to a task to perform an I/O operation + * gen_opcl: generic call to a character driver to perform an open/close + * gen_io: generic call to a character driver to initiate I/O * no_dev: open/close processing for devices that don't exist * no_dev_io: i/o processing for devices that don't exist * tty_opcl: perform tty-specific processing for open/close @@ -18,6 +19,8 @@ * ctty_io: perform controlling-tty-specific processing for I/O * pm_setsid: perform VFS's side of setsid system call * do_ioctl: perform the IOCTL system call + * dev_select: initiate a select call on a device + * dev_cancel: cancel an I/O request, blocking until it has been cancelled */ #include "fs.h" @@ -31,7 +34,6 @@ #include #include #include "file.h" -#include "fproc.h" #include "scratchpad.h" #include "dmap.h" #include @@ -39,13 +41,14 @@ #include "vmnt.h" #include "param.h" +static int block_io(endpoint_t driver_e, message *mess_ptr); +static cp_grant_id_t make_grant(endpoint_t driver_e, endpoint_t user_e, int op, + void *buf, size_t size); static void restart_reopen(int major); -static int safe_io_conversion(endpoint_t, cp_grant_id_t *, int *, - endpoint_t *, void **, size_t, u32_t *); +static void reopen_reply(message *m_ptr); static int dummyproc; - /*===========================================================================* * dev_open * *===========================================================================*/ @@ -158,10 +161,9 @@ static int bdev_ioctl(dev_t dev, endpoint_t proc_e, int req, void *buf) { /* Perform an I/O control operation on a block device. */ struct dmap *dp; - u32_t dummy; cp_grant_id_t gid; message dev_mess; - int op, major_dev, minor_dev; + int major_dev, minor_dev; major_dev = major(dev); minor_dev = minor(dev); @@ -169,14 +171,12 @@ static int bdev_ioctl(dev_t dev, endpoint_t proc_e, int req, void *buf) /* Determine task dmap. */ dp = &dmap[major_dev]; if (dp->dmap_driver == NONE) { - printf("VFS: dev_io: no driver for major %d\n", major_dev); + printf("VFS: bdev_ioctl: no driver for major %d\n", major_dev); return(ENXIO); } /* Set up a grant if necessary. */ - op = VFS_DEV_IOCTL; - (void) safe_io_conversion(dp->dmap_driver, &gid, &op, &proc_e, &buf, req, - &dummy); + gid = make_grant(dp->dmap_driver, proc_e, BDEV_IOCTL, buf, req); /* Set up the message passed to the task. */ memset(&dev_mess, 0, sizeof(dev_mess)); @@ -188,7 +188,7 @@ static int bdev_ioctl(dev_t dev, endpoint_t proc_e, int req, void *buf) dev_mess.BDEV_ID = 0; /* Call the task. */ - (*dp->dmap_io)(dp->dmap_driver, &dev_mess); + block_io(dp->dmap_driver, &dev_mess); /* Clean up. */ if (GRANT_VALID(gid)) cpf_revoke(gid); @@ -206,7 +206,7 @@ static int bdev_ioctl(dev_t dev, endpoint_t proc_e, int req, void *buf) /*===========================================================================* * find_suspended_ep * *===========================================================================*/ -endpoint_t find_suspended_ep(endpoint_t driver, cp_grant_id_t g) +static endpoint_t find_suspended_ep(endpoint_t driver, cp_grant_id_t g) { /* A process is suspended on a driver for which VFS issued a grant. Find out * which process it was. @@ -216,9 +216,11 @@ endpoint_t find_suspended_ep(endpoint_t driver, cp_grant_id_t g) if(rfp->fp_pid == PID_FREE) continue; - if(rfp->fp_blocked_on == FP_BLOCKED_ON_OTHER && - rfp->fp_task == driver && rfp->fp_grant == g) + if (rfp->fp_task == driver && rfp->fp_grant == g) { + assert(!fp_is_blocked(rfp) || + rfp->fp_blocked_on == FP_BLOCKED_ON_OTHER); return(rfp->fp_endpoint); + } } return(NONE); @@ -226,105 +228,29 @@ endpoint_t find_suspended_ep(endpoint_t driver, cp_grant_id_t g) /*===========================================================================* - * dev_status * + * make_grant * *===========================================================================*/ -void dev_status(endpoint_t drv_e) +static cp_grant_id_t make_grant(endpoint_t driver_e, endpoint_t user_e, int op, + void *buf, size_t bytes) { -/* A device sent us a notification it has something for us. Retrieve it. */ - - message st; - int major, get_more = 1; - endpoint_t endpt; - - for (major = 0; major < NR_DEVICES; major++) - if (dmap_driver_match(drv_e, major)) - break; /* 'major' is the device that sent the message */ - - if (major >= NR_DEVICES) /* Device endpoint not found; nothing to do */ - return; - - if (dev_style_asyn(dmap[major].dmap_style)) { - printf("VFS: not doing dev_status for async driver %d\n", drv_e); - return; - } - - /* Continuously send DEV_STATUS messages until the device has nothing to - * say to us anymore. */ - do { - int r; - st.m_type = DEV_STATUS; - r = drv_sendrec(drv_e, &st); - if (r == OK && st.REP_STATUS == ERESTART) r = EDEADEPT; - if (r != OK) { - printf("VFS: DEV_STATUS failed to %d: %d\n", drv_e, r); - if (r == EDEADSRCDST || r == EDEADEPT) return; - panic("VFS: couldn't sendrec for DEV_STATUS: %d", r); - } - - switch(st.m_type) { - case DEV_REVIVE: - /* We've got results for a read/write/ioctl call to a - * synchronous character driver */ - endpt = st.REP_ENDPT; - if (endpt == VFS_PROC_NR) { - endpt = find_suspended_ep(drv_e, st.REP_IO_GRANT); - if (endpt == NONE) { - printf("VFS: proc with grant %d from %d not found\n", - st.REP_IO_GRANT, st.m_source); - continue; - } - } - revive(endpt, st.REP_STATUS); - break; - case DEV_IO_READY: - /* Reply to a select request: driver is ready for I/O */ - select_reply2(st.m_source, st.DEV_MINOR, st.DEV_SEL_OPS); - break; - default: - printf("VFS: unrecognized reply %d to DEV_STATUS\n",st.m_type); - /* Fall through. */ - case DEV_NO_STATUS: - get_more = 0; - break; - } - } while(get_more); -} - -/*===========================================================================* - * safe_io_conversion * - *===========================================================================*/ -static int safe_io_conversion(driver, gid, op, io_ept, buf, bytes, pos_lo) -endpoint_t driver; -cp_grant_id_t *gid; -int *op; -endpoint_t *io_ept; -void **buf; -size_t bytes; -u32_t *pos_lo; -{ -/* Convert operation to the 'safe' variant (i.e., grant based) if applicable. - * If no copying of data is involved, there is also no need to convert. */ - - int access = 0; +/* Create a magic grant for the given operation and buffer. */ + cp_grant_id_t gid; + int access; size_t size; - *gid = GRANT_INVALID; /* Grant to buffer */ - - switch(*op) { - case VFS_DEV_READ: - case VFS_DEV_WRITE: - /* Change to safe op. */ - *op = (*op == VFS_DEV_READ) ? DEV_READ_S : DEV_WRITE_S; - *gid = cpf_grant_magic(driver, *io_ept, (vir_bytes) *buf, bytes, - *op == DEV_READ_S ? CPF_WRITE : CPF_READ); - if (*gid < 0) - panic("VFS: cpf_grant_magic of READ/WRITE buffer failed"); + switch (op) { + case DEV_READ_S: + case DEV_WRITE_S: + gid = cpf_grant_magic(driver_e, user_e, (vir_bytes) buf, bytes, + op == DEV_READ_S ? CPF_WRITE : CPF_READ); break; - case VFS_DEV_IOCTL: - *pos_lo = *io_ept; /* Old endpoint in POSITION field. */ - *op = DEV_IOCTL_S; + + case DEV_IOCTL_S: + case BDEV_IOCTL: /* For IOCTLs, the bytes parameter encodes requested access method - * and buffer size */ + * and buffer size + */ + access = 0; if(_MINIX_IOCTL_IOR(bytes)) access |= CPF_WRITE; if(_MINIX_IOCTL_IOW(bytes)) access |= CPF_READ; if(_MINIX_IOCTL_BIG(bytes)) @@ -335,65 +261,27 @@ u32_t *pos_lo; /* Grant access to the buffer even if no I/O happens with the ioctl, in * order to disambiguate requests with DEV_IOCTL_S. */ - *gid = cpf_grant_magic(driver, *io_ept, (vir_bytes) *buf, size, access); - if (*gid < 0) - panic("VFS: cpf_grant_magic IOCTL buffer failed"); + gid = cpf_grant_magic(driver_e, user_e, (vir_bytes) buf, size, access); + break; - break; - case VFS_DEV_SELECT: - *op = DEV_SELECT; - break; - default: - panic("VFS: unknown operation %d for safe I/O conversion", *op); + default: + panic("VFS: unknown operation %d", op); } - /* If we have converted to a safe operation, I/O endpoint becomes VFS if it - * wasn't already. - */ - if(GRANT_VALID(*gid)) { - *io_ept = VFS_PROC_NR; - return(1); - } + if (!GRANT_VALID(gid)) + panic("VFS: cpf_grant_magic failed"); - /* Not converted to a safe operation (because there is no copying involved in - * this operation). - */ - return(0); + return gid; } -static int cancel_nblock(struct dmap * dp, - int minor, - int call, - endpoint_t ioproc, - cp_grant_id_t gid) -{ - message dev_mess; - - dev_mess.m_type = CANCEL; - dev_mess.USER_ENDPT = ioproc; - dev_mess.IO_GRANT = (char *) gid; - - /* This R_BIT/W_BIT check taken from suspend()/unpause() - * logic. Mode is expected in the COUNT field. - */ - dev_mess.COUNT = 0; - if (call == READ) - dev_mess.COUNT = R_BIT; - else if (call == WRITE) - dev_mess.COUNT = W_BIT; - dev_mess.DEVICE = minor; - (*dp->dmap_io)(dp->dmap_driver, &dev_mess); - - return dev_mess.REP_STATUS; -} /*===========================================================================* * dev_io * *===========================================================================*/ int dev_io( - int op, /* DEV_READ, DEV_WRITE, DEV_IOCTL, etc. */ + int op, /* DEV_READ_S, DEV_WRITE_S, or DEV_IOCTL_S */ dev_t dev, /* major-minor device number */ - endpoint_t proc_e, /* in whose address space is buf? */ + endpoint_t proc_e, /* in whose address space is buf? */ void *buf, /* virtual address of the buffer */ u64_t pos, /* byte position */ size_t bytes, /* how many bytes to transfer */ @@ -401,22 +289,17 @@ int dev_io( int suspend_reopen /* Just suspend the process */ ) { -/* Read from or write to a device. The parameter 'dev' tells which one. */ +/* Initiate a read, write, or ioctl to a device. */ struct dmap *dp; - u32_t pos_lo, pos_high; message dev_mess; - cp_grant_id_t gid = GRANT_INVALID; - int safe, minor_dev, major_dev; - void *buf_used; - endpoint_t ioproc; - int ret, is_asyn; + cp_grant_id_t gid; + int r, minor_dev, major_dev; - pos_lo = ex64lo(pos); - pos_high = ex64hi(pos); - major_dev = major(dev); - minor_dev = minor(dev); + assert(op == DEV_READ_S || op == DEV_WRITE_S || op == DEV_IOCTL_S); /* Determine task dmap. */ + major_dev = major(dev); + minor_dev = minor(dev); dp = &dmap[major_dev]; /* See if driver is roughly valid. */ @@ -437,82 +320,42 @@ int dev_io( return(ENXIO); } - /* By default, these are right. */ - dev_mess.USER_ENDPT = proc_e; - dev_mess.ADDRESS = buf; + /* Create a grant for the buffer provided by the user process. */ + gid = make_grant(dp->dmap_driver, proc_e, op, buf, bytes); - /* Convert DEV_* to DEV_*_S variants. */ - buf_used = buf; - safe = safe_io_conversion(dp->dmap_driver, &gid, &op, - (endpoint_t *) &dev_mess.USER_ENDPT, &buf_used, - bytes, &pos_lo); - - is_asyn = dev_style_asyn(dp->dmap_style); - - /* If the safe conversion was done, set the IO_GRANT to - * the grant id. - */ - if(safe) dev_mess.IO_GRANT = (char *) gid; - - /* Set up the rest of the message passed to task. */ + /* Set up the rest of the message that will be sent to the driver. */ dev_mess.m_type = op; dev_mess.DEVICE = minor_dev; - dev_mess.POSITION = pos_lo; - dev_mess.COUNT = bytes; - dev_mess.HIGHPOS = pos_high; + if (op == DEV_IOCTL_S) { + dev_mess.REQUEST = bytes; + dev_mess.POSITION = proc_e; + } else { + dev_mess.POSITION = ex64lo(pos); + dev_mess.COUNT = bytes; + } + dev_mess.HIGHPOS = ex64hi(pos); + dev_mess.USER_ENDPT = VFS_PROC_NR; + dev_mess.IO_GRANT = (void *) gid; dev_mess.FLAGS = 0; - if (flags & O_NONBLOCK) dev_mess.FLAGS |= FLG_OP_NONBLOCK; - /* This will be used if the i/o is suspended. */ - ioproc = dev_mess.USER_ENDPT; + /* Send the request to the driver. */ + r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess); - /* Call the task. */ - (*dp->dmap_io)(dp->dmap_driver, &dev_mess); + if (r != OK) { + cpf_revoke(gid); - if(dp->dmap_driver == NONE) { - /* Driver has vanished. */ - printf("VFS: driver gone?!\n"); - if(safe) cpf_revoke(gid); - return(EIO); + return r; } - ret = dev_mess.REP_STATUS; + /* Suspend the calling process until a reply arrives. */ + wait_for(dp->dmap_driver); + assert(!GRANT_VALID(fp->fp_grant)); + fp->fp_grant = gid; /* revoke this when unsuspended. */ + fp->fp_ioproc = VFS_PROC_NR; - /* Task has completed. See if call completed. */ - if (ret == SUSPEND) { - if ((flags & O_NONBLOCK) && !is_asyn) { - /* Not supposed to block. */ - ret = cancel_nblock(dp, minor_dev, job_call_nr, ioproc, gid); - if (ret == EINTR) - ret = EAGAIN; - } else { - /* select() will do suspending itself. */ - if(op != DEV_SELECT) { - /* Suspend user. */ - wait_for(dp->dmap_driver); - } - assert(!GRANT_VALID(fp->fp_grant)); - fp->fp_grant = gid; /* revoke this when unsuspended. */ - fp->fp_ioproc = ioproc; - - if ((flags & O_NONBLOCK) && !is_asyn) { - /* Not supposed to block, send cancel message */ - cancel_nblock(dp, minor_dev, job_call_nr, ioproc, gid); - /* - * FIXME Should do something about EINTR -> EAGAIN - * mapping - */ - } - return(SUSPEND); - } - } - - /* No suspend, or cancelled suspend, so I/O is over and can be cleaned up. */ - if(safe) cpf_revoke(gid); - - return ret; + return SUSPEND; } /*===========================================================================* @@ -545,20 +388,30 @@ int gen_opcl( dev_mess.BDEV_MINOR = minor_dev; dev_mess.BDEV_ACCESS = flags; dev_mess.BDEV_ID = 0; + + /* Call the task. */ + r = block_io(dp->dmap_driver, &dev_mess); } else { dev_mess.m_type = op; dev_mess.DEVICE = minor_dev; dev_mess.USER_ENDPT = proc_e; dev_mess.COUNT = flags; + + /* Call the task. */ + r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess); } - /* Call the task. */ - r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess); if (r != OK) return(r); - if (op == DEV_OPEN && dp->dmap_style == STYLE_DEVA) { + if (op == DEV_OPEN) { fp->fp_task = dp->dmap_driver; + self->w_task = dp->dmap_driver; + self->w_drv_sendrec = &dev_mess; + worker_wait(); + + self->w_task = NONE; + self->w_drv_sendrec = NULL; } if (is_bdev) @@ -662,9 +515,9 @@ int do_ioctl(message *UNUSED(m_out)) dev_t dev; void *argx; - scratch(fp).file.fd_nr = job_m_in.ls_fd; - ioctlrequest = job_m_in.REQUEST; - argx = job_m_in.ADDRESS; + scratch(fp).file.fd_nr = job_m_in.VFS_IOCTL_FD; + ioctlrequest = job_m_in.VFS_IOCTL_REQ; + argx = job_m_in.VFS_IOCTL_ARG; if ((f = get_filp(scratch(fp).file.fd_nr, VNODE_READ)) == NULL) return(err_code); @@ -680,7 +533,7 @@ int do_ioctl(message *UNUSED(m_out)) if (S_ISBLK(vp->v_mode)) r = bdev_ioctl(dev, who_e, ioctlrequest, argx); else - r = dev_io(VFS_DEV_IOCTL, dev, who_e, argx, ((u64_t)(0)), + r = dev_io(DEV_IOCTL_S, dev, who_e, argx, 0, ioctlrequest, f->filp_flags, suspend_reopen); } @@ -691,31 +544,100 @@ int do_ioctl(message *UNUSED(m_out)) /*===========================================================================* - * gen_io * + * dev_select * *===========================================================================*/ -int gen_io(driver_e, mess_ptr) -endpoint_t driver_e; /* which endpoint to call */ -message *mess_ptr; /* pointer to message for task */ +int dev_select(dev_t dev, int ops) { -/* All file system I/O ultimately comes down to I/O on major/minor device - * pairs. These lead to calls on the following routines via the dmap table. +/* Initiate a select call on a device. Return OK iff the request was sent. */ + int major_dev, minor_dev; + message dev_mess; + struct dmap *dp; + + major_dev = major(dev); + minor_dev = minor(dev); + dp = &dmap[major_dev]; + + if (dp->dmap_driver == NONE) return ENXIO; + + memset(&dev_mess, 0, sizeof(dev_mess)); + + dev_mess.m_type = DEV_SELECT; + dev_mess.DEV_MINOR = minor_dev; + dev_mess.DEV_SEL_OPS = ops; + + /* Call the task. */ + return (*dp->dmap_io)(dp->dmap_driver, &dev_mess); +} + + +/*===========================================================================* + * dev_cancel * + *===========================================================================*/ +int dev_cancel(dev_t dev) +{ +/* Cancel an I/O request, blocking until it has been cancelled. */ + int r, minor_dev, major_dev; + message dev_mess; + struct dmap *dp; + + major_dev = major(dev); + minor_dev = minor(dev); + dp = &dmap[major_dev]; + + memset(&dev_mess, 0, sizeof(dev_mess)); + + dev_mess.m_type = CANCEL; + dev_mess.DEVICE = minor_dev; + dev_mess.USER_ENDPT = fp->fp_ioproc; + dev_mess.IO_GRANT = (char *) fp->fp_grant; + + /* Tell driver R or W. Mode is from current call, not open. */ + /* FIXME: ioctls also pass through here! */ + dev_mess.COUNT = fp->fp_block_callnr == READ ? R_BIT : W_BIT; + + r = (*dp->dmap_io)(fp->fp_task, &dev_mess); + if (r != OK) return r; /* ctty_io returned an error? should be impossible */ + + /* Suspend this thread until we have received the response. */ + fp->fp_task = dp->dmap_driver; + self->w_task = dp->dmap_driver; + self->w_drv_sendrec = &dev_mess; + + worker_wait(); + + self->w_task = NONE; + self->w_drv_sendrec = NULL; + + /* Clean up and return the result (note: the request may have completed). */ + if (GRANT_VALID(fp->fp_grant)) { + (void) cpf_revoke(fp->fp_grant); + fp->fp_grant = GRANT_INVALID; + } + + r = dev_mess.REP_STATUS; + return (r == EAGAIN) ? EINTR : r; +} + + +/*===========================================================================* + * block_io * + *===========================================================================*/ +static int block_io(endpoint_t driver_e, message *mess_ptr) +{ +/* Perform I/O on a block device. The current thread is suspended until a reply + * comes in from the driver. */ - int r, status = OK, proc_e = NONE, is_bdev, retry_count; + int r, status, retry_count; message mess_retry; - is_bdev = IS_BDEV_RQ(mess_ptr->m_type); + assert(IS_BDEV_RQ(mess_ptr->m_type)); mess_retry = *mess_ptr; retry_count = 0; - if (!is_bdev) proc_e = mess_ptr->USER_ENDPT; - do { r = drv_sendrec(driver_e, mess_ptr); if (r == OK) { - if (is_bdev) - status = mess_ptr->BDEV_STATUS; - else - status = mess_ptr->REP_STATUS; + status = mess_ptr->BDEV_STATUS; if (status == ERESTART) { r = EDEADEPT; *mess_ptr = mess_retry; @@ -739,41 +661,26 @@ message *mess_ptr; /* pointer to message for task */ printf("VFS: ELOCKED talking to %d\n", driver_e); return(r); } - panic("call_task: can't send/receive: %d", r); + panic("block_io: can't send/receive: %d", r); } - /* Did the process we did the sendrec() for get a result? */ - if (!is_bdev && mess_ptr->REP_ENDPT != proc_e && mess_ptr->m_type != EIO) { - printf("VFS: strange device reply from %d, type = %d, " - "proc = %d (not %d) (2) ignored\n", mess_ptr->m_source, - mess_ptr->m_type, proc_e, mess_ptr->REP_ENDPT); - - return(EIO); - } else if (!IS_DRV_REPLY(mess_ptr->m_type)) - return(EIO); - return(OK); } /*===========================================================================* - * asyn_io * + * gen_io * *===========================================================================*/ -int asyn_io(endpoint_t drv_e, message *mess_ptr) +int gen_io(endpoint_t drv_e, message *mess_ptr) { -/* All file system I/O ultimately comes down to I/O on major/minor device - * pairs. These lead to calls on the following routines via the dmap table. - */ - +/* Initiate I/O to a character driver. Do not wait for the reply. */ int r; assert(!IS_BDEV_RQ(mess_ptr->m_type)); - self->w_drv_sendrec = mess_ptr; /* Remember where result should be stored */ - self->w_task = drv_e; r = asynsend3(drv_e, mess_ptr, AMF_NOREPLY); - if (r != OK) panic("VFS: asynsend in asyn_io failed: %d", r); + if (r != OK) panic("VFS: asynsend in gen_io failed: %d", r); /* Fake a SUSPEND */ mess_ptr->REP_STATUS = SUSPEND; @@ -798,7 +705,7 @@ int ctty_io( if (fp->fp_tty == 0) { /* No controlling tty present anymore, return an I/O error. */ - mess_ptr->REP_STATUS = EIO; + return(EIO); } else { /* Substitute the controlling terminal device. */ dp = &dmap[major(fp->fp_tty)]; @@ -814,10 +721,8 @@ int ctty_io( return(EIO); } - (*dp->dmap_io)(dp->dmap_driver, mess_ptr); + return (*dp->dmap_io)(dp->dmap_driver, mess_ptr); } - - return(OK); } @@ -889,10 +794,16 @@ int clone_opcl( r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess); if (r != OK) return(r); - if (op == DEV_OPEN && dev_style_asyn(dp->dmap_style)) { - /* Wait for reply when driver is asynchronous */ + if (op == DEV_OPEN) { + /* Wait for the reply. */ fp->fp_task = dp->dmap_driver; + self->w_task = dp->dmap_driver; + self->w_drv_sendrec = &dev_mess; + worker_wait(); + + self->w_task = NONE; + self->w_drv_sendrec = NULL; } if (op == DEV_OPEN && dev_mess.REP_STATUS >= 0) { @@ -1011,30 +922,10 @@ void cdev_up(int maj) { /* A new character device driver has been mapped in. */ - int needs_reopen, fd_nr; + int needs_reopen; struct filp *rfilp; - struct fproc *rfp; struct vnode *vp; - /* Look for processes that are suspended in an OPEN call. Set FP_SUSP_REOPEN - * to indicate that this process was suspended before the call to dev_up. - */ - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - if(rfp->fp_pid == PID_FREE) continue; - if(rfp->fp_blocked_on != FP_BLOCKED_ON_DOPEN) continue; - - fd_nr = scratch(rfp).file.fd_nr; - printf("VFS: dev_up: found process in FP_BLOCKED_ON_DOPEN, fd %d\n", - fd_nr); - rfilp = rfp->fp_filp[fd_nr]; - vp = rfilp->filp_vno; - if (!vp) panic("VFS: cdev_up: no vp"); - if (!S_ISCHR(vp->v_mode)) continue; - if (major(vp->v_sdev) != maj) continue; - - rfp->fp_flags |= FP_SUSP_REOPEN; - } - needs_reopen= FALSE; for (rfilp = filp; rfilp < &filp[NR_FILPS]; rfilp++) { if (rfilp->filp_count < 1 || !(vp = rfilp->filp_vno)) continue; @@ -1052,32 +943,122 @@ void cdev_up(int maj) /*===========================================================================* * open_reply * *===========================================================================*/ -void open_reply(void) +static void open_reply(message *m_ptr) { +/* A character driver has replied to an open request. This function MUST NOT + * block its calling thread. + */ struct fproc *rfp; struct worker_thread *wp; endpoint_t proc_e; int slot; - proc_e = job_m_in.REP_ENDPT; + proc_e = m_ptr->REP_ENDPT; if (isokendpt(proc_e, &slot) != OK) return; rfp = &fproc[slot]; - wp = worker_get(rfp->fp_wtid); + wp = rfp->fp_worker; if (wp == NULL || wp->w_task != who_e) { printf("VFS: no worker thread waiting for a reply from %d\n", who_e); return; } - *wp->w_drv_sendrec = job_m_in; - wp->w_drv_sendrec = NULL; - wp->w_task = NONE; + *wp->w_drv_sendrec = *m_ptr; worker_signal(wp); /* Continue open */ } + /*===========================================================================* - * dev_reply * + * task_reply * *===========================================================================*/ -void dev_reply(struct dmap *dp) +static void task_reply(message *m_ptr) { +/* A character driver has results for a read, write, or ioctl call. There may + * be a thread waiting for these results as part of an ongoing dev_cancel call. + * If so, wake up that thread; if not, send a reply to the requesting process. + * This function MUST NOT block its calling thread. + */ + struct fproc *rfp; + struct worker_thread *wp; + endpoint_t proc_e; + int slot; + + proc_e = m_ptr->REP_ENDPT; + if (proc_e == VFS_PROC_NR) + proc_e = find_suspended_ep(m_ptr->m_source, m_ptr->REP_IO_GRANT); + else + printf("VFS: endpoint %u from %u is not VFS\n", + proc_e, m_ptr->m_source); + + if (proc_e == NONE) { + printf("VFS: proc with grant %d from %d not found\n", + m_ptr->REP_IO_GRANT, m_ptr->m_source); + } else if (m_ptr->REP_STATUS == SUSPEND) { + printf("VFS: got SUSPEND on DEV_REVIVE: not reviving proc\n"); + } else { + /* If there is a thread active for this process, we assume that this + * thread aims to cancel the ongoing operation. In that case, wake up + * the thread to let it finish unpausing the process. Otherwise, revive + * the process as usual. + */ + if (isokendpt(proc_e, &slot) != OK) return; + rfp = &fproc[slot]; + wp = rfp->fp_worker; + if (wp != NULL && wp->w_task == who_e) { + assert(!fp_is_blocked(rfp)); + *wp->w_drv_sendrec = *m_ptr; + worker_signal(wp); /* Continue cancel */ + } else { + revive(proc_e, m_ptr->REP_STATUS); + } + } +} + + +/*===========================================================================* + * close_reply * + *===========================================================================*/ +static void close_reply(message *m_ptr __unused) +{ +/* A character driver replied to a close request. There is no need to do + * anything here, because we cheat: we assume that the close operation will + * succeed anyway, so we don't wait for the reply. + */ + + /* Nothing. */ +} + + +/*===========================================================================* + * cdev_reply * + *===========================================================================*/ +void cdev_reply(void) +{ +/* A character driver has results for us. */ + + switch (call_nr) { + case DEV_OPEN_REPL: open_reply(&m_in); break; + case DEV_REOPEN_REPL: reopen_reply(&m_in); break; + case DEV_CLOSE_REPL: close_reply(&m_in); break; + case DEV_REVIVE: task_reply(&m_in); break; + case DEV_SEL_REPL1: + select_reply1(m_in.m_source, m_in.DEV_MINOR, m_in.DEV_SEL_OPS); + break; + case DEV_SEL_REPL2: + select_reply2(m_in.m_source, m_in.DEV_MINOR, m_in.DEV_SEL_OPS); + break; + default: + printf("VFS: char driver %u sent unknown reply %x\n", who_e, call_nr); + } +} + + +/*===========================================================================* + * bdev_reply * + *===========================================================================*/ +void bdev_reply(struct dmap *dp) +{ +/* A block driver has results for a call. There must be a thread waiting for + * these results - wake it up. This function MUST NOT block its calling thread. + */ struct worker_thread *wp; assert(dp != NULL); @@ -1096,13 +1077,27 @@ void dev_reply(struct dmap *dp) worker_signal(wp); } +/*===========================================================================* + * filp_gc_thread * + *===========================================================================*/ +static void filp_gc_thread(void) +{ +/* Filp garbage collection thread function. Since new filps may be invalidated + * while the actual garbage collection procedure is running, we repeat the + * procedure until it can not find any more work to do. + */ + + while (do_filp_gc()) + /* simply repeat */; +} + /*===========================================================================* * restart_reopen * *===========================================================================*/ static void restart_reopen(maj) int maj; { - int n, r, minor_dev, major_dev, fd_nr; + int n, r, minor_dev, major_dev; endpoint_t driver_e; struct vnode *vp; struct filp *rfilp; @@ -1143,9 +1138,14 @@ int maj; /* We have to clean up this filp and vnode, but can't do that yet as * it's locked by a worker thread. Start a new job to garbage collect - * invalidated filps associated with this device driver. + * invalidated filps associated with this device driver. This thread + * is associated with a process that we know is idle otherwise: VFS. + * Be careful that we don't start two threads or lose work, though. */ - sys_worker_start(do_filp_gc); + if (worker_can_start(fproc_addr(VFS_PROC_NR))) { + worker_start(fproc_addr(VFS_PROC_NR), filp_gc_thread, + &m_out /*unused*/, FALSE /*use_spare*/); + } } /* Nothing more to re-open. Restart suspended processes */ @@ -1159,41 +1159,13 @@ int maj; reply(&m_out, rfp->fp_endpoint, ERESTART); } } - - /* Look for processes that are suspened in an OPEN call */ - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - if (rfp->fp_pid == PID_FREE) continue; - if (rfp->fp_blocked_on == FP_BLOCKED_ON_DOPEN || - !(rfp->fp_flags & FP_SUSP_REOPEN)) continue; - - fd_nr = scratch(rfp).file.fd_nr; - printf("VFS: restart_reopen: process in FP_BLOCKED_ON_DOPEN fd=%d\n", - fd_nr); - rfilp = rfp->fp_filp[fd_nr]; - - if (!rfilp) { - /* Open failed, and automatic reopen was not requested */ - rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - FD_CLR(fd_nr, &rfp->fp_filp_inuse); - reply(&m_out, rfp->fp_endpoint, EIO); - continue; - } - - vp = rfilp->filp_vno; - if (!vp) panic("VFS: restart_reopen: no vp"); - if (!S_ISCHR(vp->v_mode)) continue; - if (major(vp->v_sdev) != maj) continue; - - rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - reply(&m_out, rfp->fp_endpoint, fd_nr); - } } /*===========================================================================* * reopen_reply * *===========================================================================*/ -void reopen_reply() +static void reopen_reply(message *m_ptr) { endpoint_t driver_e; int filp_no, status, maj; @@ -1201,9 +1173,9 @@ void reopen_reply() struct vnode *vp; struct dmap *dp; - driver_e = job_m_in.m_source; - filp_no = job_m_in.REP_ENDPT; - status = job_m_in.REP_STATUS; + driver_e = m_ptr->m_source; + filp_no = m_ptr->REP_ENDPT; + status = m_ptr->REP_STATUS; if (filp_no < 0 || filp_no >= NR_FILPS) { printf("VFS: reopen_reply: bad filp number %d from driver %d\n", diff --git a/servers/vfs/dmap.c b/servers/vfs/dmap.c index 7f0b513be..c12407a31 100644 --- a/servers/vfs/dmap.c +++ b/servers/vfs/dmap.c @@ -11,8 +11,6 @@ #include #include #include -#include "fproc.h" -#include "dmap.h" #include "param.h" /* The order of the entries in the table determines the mapping between major @@ -24,9 +22,6 @@ struct dmap dmap[NR_DEVICES]; -#define DT_EMPTY { no_dev, no_dev_io, NONE, "", 0, STYLE_NDEV, NULL, NONE, \ - 0, NULL, 0} - /*===========================================================================* * lock_dmap * *===========================================================================*/ @@ -34,20 +29,17 @@ void lock_dmap(struct dmap *dp) { /* Lock a driver */ struct worker_thread *org_self; - struct fproc *org_fp; int r; assert(dp != NULL); assert(dp->dmap_driver != NONE); - org_fp = fp; - org_self = self; + org_self = worker_suspend(); if ((r = mutex_lock(dp->dmap_lock_ref)) != 0) panic("unable to get a lock on dmap: %d\n", r); - fp = org_fp; - self = org_self; + worker_resume(org_self); } /*===========================================================================* @@ -182,10 +174,6 @@ int flags; /* device flags */ dp->dmap_opcl = gen_opcl; dp->dmap_io = gen_io; break; - case STYLE_DEVA: - dp->dmap_opcl = gen_opcl; - dp->dmap_io = asyn_io; - break; case STYLE_TTY: dp->dmap_opcl = tty_opcl; dp->dmap_io = gen_io; @@ -198,10 +186,6 @@ int flags; /* device flags */ dp->dmap_opcl = clone_opcl; dp->dmap_io = gen_io; break; - case STYLE_CLONE_A: - dp->dmap_opcl = clone_opcl; - dp->dmap_io = asyn_io; - break; default: return(EINVAL); } @@ -289,10 +273,16 @@ void init_dmap() { /* Initialize the table with empty device <-> driver mappings. */ int i; - struct dmap dmap_default = DT_EMPTY; - for (i = 0; i < NR_DEVICES; i++) - dmap[i] = dmap_default; + memset(dmap, 0, sizeof(dmap)); + + for (i = 0; i < NR_DEVICES; i++) { + dmap[i].dmap_opcl = no_dev; + dmap[i].dmap_io = no_dev_io; + dmap[i].dmap_driver = NONE; + dmap[i].dmap_style = STYLE_NDEV; + dmap[i].dmap_servicing = NONE; + } } /*===========================================================================* diff --git a/servers/vfs/dmap.h b/servers/vfs/dmap.h index cd15a1cc4..4520d577f 100644 --- a/servers/vfs/dmap.h +++ b/servers/vfs/dmap.h @@ -20,6 +20,7 @@ extern struct dmap { char dmap_label[LABEL_MAX]; int dmap_flags; int dmap_style; + int dmap_sel_busy; struct filp *dmap_sel_filp; endpoint_t dmap_servicing; mutex_t dmap_lock; diff --git a/servers/vfs/exec.c b/servers/vfs/exec.c index 638d1d404..71e251979 100644 --- a/servers/vfs/exec.c +++ b/servers/vfs/exec.c @@ -26,7 +26,6 @@ #include #include #include -#include "fproc.h" #include "path.h" #include "param.h" #include "vnode.h" @@ -53,8 +52,6 @@ struct vfs_exec_info { int vmfd_used; }; -static void lock_exec(void); -static void unlock_exec(void); static int patch_stack(struct vnode *vp, char stack[ARG_MAX], size_t *stk_bytes, char path[PATH_MAX]); static int is_script(struct vfs_exec_info *execi); @@ -82,36 +79,8 @@ static const struct exec_loaders exec_loaders[] = { { NULL, NULL } }; -/*===========================================================================* - * lock_exec * - *===========================================================================*/ -static void lock_exec(void) -{ - struct fproc *org_fp; - struct worker_thread *org_self; - - /* First try to get it right off the bat */ - if (mutex_trylock(&exec_lock) == 0) - return; - - org_fp = fp; - org_self = self; - - if (mutex_lock(&exec_lock) != 0) - panic("Could not obtain lock on exec"); - - fp = org_fp; - self = org_self; -} - -/*===========================================================================* - * unlock_exec * - *===========================================================================*/ -static void unlock_exec(void) -{ - if (mutex_unlock(&exec_lock) != 0) - panic("Could not release lock on exec"); -} +#define lock_exec() lock_proc(fproc_addr(VM_PROC_NR)) +#define unlock_exec() unlock_proc(fproc_addr(VM_PROC_NR)) /*===========================================================================* * get_read_vp * @@ -212,17 +181,15 @@ static int vfs_memmap(struct exec_info *execi, /*===========================================================================* * pm_exec * *===========================================================================*/ -int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, - vir_bytes frame, size_t frame_len, vir_bytes *pc, - vir_bytes *newsp, int user_exec_flags) +int pm_exec(vir_bytes path, size_t path_len, vir_bytes frame, size_t frame_len, + vir_bytes *pc, vir_bytes *newsp, int user_exec_flags) { /* Perform the execve(name, argv, envp) call. The user library builds a * complete stack image, including pointers, args, environ, etc. The stack * is copied to a buffer inside VFS, and then to the new core image. */ - int r, slot; + int r; vir_bytes vsp; - struct fproc *rfp; int extrabase = 0; static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */ struct vfs_exec_info execi; @@ -232,14 +199,13 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, firstexec[PATH_MAX], finalexec[PATH_MAX]; struct lookup resolve; - struct fproc *vmfp = &fproc[VM_PROC_NR]; + struct fproc *vmfp = fproc_addr(VM_PROC_NR); stackhook_t makestack = NULL; static int n; n++; struct filp *newfilp = NULL; lock_exec(); - lock_proc(vmfp, 0); /* unset execi values are 0. */ memset(&execi, 0, sizeof(execi)); @@ -250,10 +216,8 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, execi.args.stack_high = kinfo.user_sp; execi.args.stack_size = DEFAULT_STACK_LIMIT; - okendpt(proc_e, &slot); - rfp = fp = &fproc[slot]; - rfp->text_size = 0; - rfp->data_size = 0; + fp->text_size = 0; + fp->data_size = 0; lookup_init(&resolve, fullpath, PATH_NOFLAGS, &execi.vmp, &execi.vp); @@ -264,7 +228,7 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, if (frame_len > ARG_MAX) FAILCHECK(ENOMEM); /* stack too big */ - r = sys_datacopy(proc_e, (vir_bytes) frame, SELF, (vir_bytes) mbuf, + r = sys_datacopy(fp->fp_endpoint, (vir_bytes) frame, SELF, (vir_bytes) mbuf, (size_t) frame_len); if (r != OK) { /* can't fetch stack (e.g. bad virtual addr) */ printf("VFS: pm_exec: sys_datacopy failed\n"); @@ -272,8 +236,8 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, } /* The default is to keep the original user and group IDs */ - execi.args.new_uid = rfp->fp_effuid; - execi.args.new_gid = rfp->fp_effgid; + execi.args.new_uid = fp->fp_effuid; + execi.args.new_gid = fp->fp_effgid; /* Get the exec file name. */ FAILCHECK(fetch_name(path, path_len, fullpath)); @@ -369,7 +333,7 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, execi.args.allocmem_ondemand = libexec_alloc_mmap_ondemand; execi.args.opaque = &execi; - execi.args.proc_e = proc_e; + execi.args.proc_e = fp->fp_endpoint; execi.args.frame_len = frame_len; execi.args.filesize = execi.vp->v_size; @@ -382,7 +346,7 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, FAILCHECK(r); /* Inform PM */ - FAILCHECK(libexec_pm_newexec(proc_e, &execi.args)); + FAILCHECK(libexec_pm_newexec(fp->fp_endpoint, &execi.args)); /* Save off PC */ *pc = execi.args.pc; @@ -393,25 +357,25 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, /* Patch up stack and copy it from VFS to new core image. */ libexec_patch_ptr(mbuf, vsp + extrabase); - FAILCHECK(sys_datacopy(SELF, (vir_bytes) mbuf, proc_e, (vir_bytes) vsp, - (phys_bytes)frame_len)); + FAILCHECK(sys_datacopy(SELF, (vir_bytes) mbuf, fp->fp_endpoint, + (vir_bytes) vsp, (phys_bytes)frame_len)); /* Return new stack pointer to caller */ *newsp = vsp; - clo_exec(rfp); + clo_exec(fp); if (execi.args.allow_setuid) { /* If after loading the image we're still allowed to run with * setuid or setgid, change credentials now */ - rfp->fp_effuid = execi.args.new_uid; - rfp->fp_effgid = execi.args.new_gid; + fp->fp_effuid = execi.args.new_uid; + fp->fp_effgid = execi.args.new_gid; } /* Remember the new name of the process */ - strlcpy(rfp->fp_name, execi.args.progname, PROC_NAME_LEN); - rfp->text_size = execi.args.text_size; - rfp->data_size = execi.args.data_size; + strlcpy(fp->fp_name, execi.args.progname, PROC_NAME_LEN); + fp->text_size = execi.args.text_size; + fp->data_size = execi.args.data_size; pm_execfinal: if(newfilp) unlock_filp(newfilp); @@ -426,7 +390,6 @@ pm_execfinal: } } - unlock_proc(vmfp); unlock_exec(); return(r); diff --git a/servers/vfs/file.h b/servers/vfs/file.h index f28001249..5180fea1f 100644 --- a/servers/vfs/file.h +++ b/servers/vfs/file.h @@ -19,6 +19,7 @@ EXTERN struct filp { /* the following fields are for select() and are owned by the generic * select() code (i.e., fd-type-specific select() code can't touch these). + * These fields may be changed without holding the filp lock. */ int filp_selectors; /* select()ing processes blocking on this fd */ int filp_select_ops; /* interested in these SEL_* operations */ diff --git a/servers/vfs/filedes.c b/servers/vfs/filedes.c index c8c5f4c77..3e833ce5b 100644 --- a/servers/vfs/filedes.c +++ b/servers/vfs/filedes.c @@ -22,7 +22,6 @@ #include #include "fs.h" #include "file.h" -#include "fproc.h" #include "vnode.h" @@ -77,16 +76,22 @@ void check_filp_locks(void) } /*===========================================================================* - * do_filp_gc * + * do_filp_gc * *===========================================================================*/ -void *do_filp_gc(void *UNUSED(arg)) +int do_filp_gc(void) { +/* Perform filp garbage collection. Return whether at least one invalidated + * filp was found, in which case the entire procedure will be invoked again. + */ struct filp *f; struct vnode *vp; + int found = FALSE; for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { if (!(f->filp_state & FS_INVALIDATED)) continue; + found = TRUE; + if (f->filp_mode == FILP_CLOSED || f->filp_vno == NULL) { /* File was already closed before gc could kick in */ assert(f->filp_count <= 0); @@ -125,12 +130,11 @@ void *do_filp_gc(void *UNUSED(arg)) f->filp_state &= ~FS_INVALIDATED; } - thread_cleanup(NULL); - return(NULL); + return found; } /*===========================================================================* - * init_filps * + * init_filps * *===========================================================================*/ void init_filps(void) { @@ -320,7 +324,6 @@ void lock_filp(filp, locktype) struct filp *filp; tll_access_t locktype; { - struct fproc *org_fp; struct worker_thread *org_self; struct vnode *vp; @@ -350,14 +353,12 @@ tll_access_t locktype; if (mutex_trylock(&filp->filp_lock) != 0) { /* Already in use, let's wait for our turn */ - org_fp = fp; - org_self = self; + org_self = worker_suspend(); if (mutex_lock(&filp->filp_lock) != 0) panic("unable to obtain lock on filp"); - fp = org_fp; - self = org_self; + worker_resume(org_self); } } diff --git a/servers/vfs/fproc.h b/servers/vfs/fproc.h index 3f9ff28e9..444d99968 100644 --- a/servers/vfs/fproc.h +++ b/servers/vfs/fproc.h @@ -43,8 +43,11 @@ EXTERN struct fproc { mode_t fp_umask; /* mask set by umask system call */ mutex_t fp_lock; /* mutex to lock fproc object */ - struct job fp_job; /* pending job */ - thread_t fp_wtid; /* Thread ID of worker */ + struct worker_thread *fp_worker;/* active worker thread, or NULL */ + void (*fp_func)(); /* handler function for pending work */ + message fp_msg; /* pending or active message from process */ + message fp_pm_msg; /* pending/active postponed PM request */ + char fp_name[PROC_NAME_LEN]; /* Last exec() */ #if LOCK_DEBUG int fp_vp_rdlocks; /* number of read-only locks on vnodes */ @@ -64,9 +67,8 @@ EXTERN struct fproc { #define FP_SESLDR 0004 /* Set if process is session leader */ #define FP_PENDING 0010 /* Set if process has pending work */ #define FP_EXITING 0020 /* Set if process is exiting */ -#define FP_PM_PENDING 0040 /* Set if process has pending PM request */ +#define FP_PM_WORK 0040 /* Set if process has a postponed PM request */ #define FP_SRV_PROC 0100 /* Set if process is a service */ -#define FP_DROP_WORK 0200 /* Set if process won't accept new work */ /* Field values. */ #define NOT_REVIVING 0xC0FFEEE /* process is not being revived */ diff --git a/servers/vfs/fs.h b/servers/vfs/fs.h index 3c95e26d5..9286f385f 100644 --- a/servers/vfs/fs.h +++ b/servers/vfs/fs.h @@ -30,5 +30,6 @@ #include "glo.h" #include "comm.h" #include "vmnt.h" +#include "fproc.h" #endif diff --git a/servers/vfs/gcov.c b/servers/vfs/gcov.c index 683a2bf82..642fe558a 100644 --- a/servers/vfs/gcov.c +++ b/servers/vfs/gcov.c @@ -1,7 +1,6 @@ #include "fs.h" #include "file.h" -#include "fproc.h" int gcov_flush(cp_grant_id_t grantid, size_t size ); diff --git a/servers/vfs/glo.h b/servers/vfs/glo.h index be48c1ba3..09009c450 100644 --- a/servers/vfs/glo.h +++ b/servers/vfs/glo.h @@ -25,24 +25,17 @@ EXTERN u32_t system_hz; /* system clock frequency. */ /* The parameters of the call are kept here. */ EXTERN message m_in; /* the input message itself */ # define who_p ((int) (fp - fproc)) -# define isokslot(p) (p >= 0 && \ - p < (int)(sizeof(fproc) / sizeof(struct fproc))) -# define who_e (self != NULL && fp != NULL ? fp->fp_endpoint : \ - m_in.m_source) +# define fproc_addr(e) (&fproc[_ENDPOINT_P(e)]) +# define who_e (self != NULL ? fp->fp_endpoint : m_in.m_source) # define call_nr (m_in.m_type) -# define job_m_in (self->w_job.j_m_in) +# define job_m_in (self->w_msg) # define job_call_nr (job_m_in.m_type) # define super_user (fp->fp_effuid == SU_UID ? 1 : 0) # define scratch(p) (scratchpad[((int) ((p) - fproc))]) EXTERN struct worker_thread *self; -EXTERN int force_sync; /* toggle forced synchronous communication */ EXTERN int deadlock_resolving; -EXTERN mutex_t exec_lock; EXTERN mutex_t bsf_lock;/* Global lock for access to block special files */ EXTERN struct worker_thread workers[NR_WTHREADS]; -EXTERN struct worker_thread sys_worker; -EXTERN struct worker_thread dl_worker; -EXTERN thread_t invalid_thread_id; EXTERN char mount_label[LABEL_MAX]; /* label of file system to mount */ /* The following variables are used for returning results to the caller. */ diff --git a/servers/vfs/job.h b/servers/vfs/job.h deleted file mode 100644 index 046a11b30..000000000 --- a/servers/vfs/job.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __VFS_WORK_H__ -#define __VFS_WORK_H__ - -struct job { - struct fproc *j_fp; - message j_m_in; - int j_err_code; - void *(*j_func)(void *arg); - struct job *j_next; -}; - -#endif diff --git a/servers/vfs/link.c b/servers/vfs/link.c index 8ffc03ee0..6a4fe25e9 100644 --- a/servers/vfs/link.c +++ b/servers/vfs/link.c @@ -20,7 +20,6 @@ #include #include #include "file.h" -#include "fproc.h" #include "path.h" #include "vnode.h" #include "param.h" diff --git a/servers/vfs/lock.c b/servers/vfs/lock.c index 0551a8401..5484a31ce 100644 --- a/servers/vfs/lock.c +++ b/servers/vfs/lock.c @@ -11,7 +11,6 @@ #include #include #include "file.h" -#include "fproc.h" #include "scratchpad.h" #include "lock.h" #include "vnode.h" diff --git a/servers/vfs/main.c b/servers/vfs/main.c index 0bf2624f3..de70074ac 100644 --- a/servers/vfs/main.c +++ b/servers/vfs/main.c @@ -27,12 +27,9 @@ #include #include #include "file.h" -#include "dmap.h" -#include "fproc.h" #include "scratchpad.h" #include "vmnt.h" #include "vnode.h" -#include "job.h" #include "param.h" #if ENABLE_SYSCALL_STATS @@ -40,26 +37,18 @@ EXTERN unsigned long calls_stats[NCALLS]; #endif /* Thread related prototypes */ -static void *do_async_dev_result(void *arg); -static void *do_control_msgs(void *arg); -static void *do_dev_event(void *arg); -static void *do_fs_reply(struct job *job); -static void *do_work(void *arg); -static void *do_pm(void *arg); -static void *do_init_root(void *arg); -static void handle_work(void *(*func)(void *arg)); +static void do_fs_reply(struct worker_thread *wp); +static void do_work(void); +static void do_init_root(void); +static void handle_work(void (*func)(void)); static void get_work(void); -static void lock_pm(void); -static void unlock_pm(void); static void service_pm(void); -static void service_pm_postponed(void); static int unblock(struct fproc *rfp); /* SEF functions and variables. */ static void sef_local_startup(void); static int sef_cb_init_fresh(int type, sef_init_info_t *info); -static mutex_t pm_lock; static endpoint_t receive_from; /*===========================================================================* @@ -72,7 +61,7 @@ int main(void) * the reply. This loop never terminates as long as the file system runs. */ int transid; - struct job *job; + struct worker_thread *wp; /* SEF local startup. */ sef_local_startup(); @@ -86,38 +75,46 @@ int main(void) while (TRUE) { yield_all(); /* let other threads run */ self = NULL; - job = NULL; send_work(); get_work(); transid = TRNS_GET_ID(m_in.m_type); if (IS_VFS_FS_TRANSID(transid)) { - job = worker_getjob( (thread_t) transid - VFS_TRANSID); - if (job == NULL) { + wp = worker_get((thread_t) transid - VFS_TRANSID); + if (wp == NULL || wp->w_fp == NULL) { printf("VFS: spurious message %d from endpoint %d\n", m_in.m_type, m_in.m_source); continue; } m_in.m_type = TRNS_DEL_ID(m_in.m_type); - } - - if (job != NULL) { - do_fs_reply(job); + do_fs_reply(wp); continue; } else if (who_e == PM_PROC_NR) { /* Calls from PM */ /* Special control messages from PM */ - sys_worker_start(do_pm); + service_pm(); continue; } else if (is_notify(call_nr)) { /* A task notify()ed us */ - if (who_e == DS_PROC_NR) - handle_work(ds_event); - else if (who_e == KERNEL) + switch (who_e) { + case DS_PROC_NR: + /* Start a thread to handle DS events, if no thread + * is pending or active for it already. DS is not + * supposed to issue calls to VFS or be the subject of + * postponed PM requests, so this should be no problem. + */ + if (worker_can_start(fp)) + handle_work(ds_event); + break; + case KERNEL: mthread_stacktraces(); - else if (fp != NULL && (fp->fp_flags & FP_SRV_PROC)) - handle_work(do_dev_event); - else - sys_worker_start(do_control_msgs); + break; + case CLOCK: + /* Timer expired. Used only for select(). Check it. */ + expire_timers(m_in.NOTIFY_TIMESTAMP); + break; + default: + printf("VFS: ignoring notification from %d\n", who_e); + } continue; } else if (who_p < 0) { /* i.e., message comes from a task */ /* We're going to ignore this message. Tasks should @@ -140,15 +137,15 @@ int main(void) dp = get_dmap(who_e); if (dp != NULL) { - if (dev_style_asyn(dp->dmap_style)) { - handle_work(do_async_dev_result); + if (!IS_BDEV_RS(call_nr)) { + cdev_reply(); } else { if (dp->dmap_servicing == NONE) { printf("Got spurious dev reply from %d", who_e); } else { - dev_reply(dp); + bdev_reply(dp); } } continue; @@ -166,217 +163,73 @@ int main(void) /*===========================================================================* * handle_work * *===========================================================================*/ -static void handle_work(void *(*func)(void *arg)) +static void handle_work(void (*func)(void)) { /* Handle asynchronous device replies and new system calls. If the originating * endpoint is an FS endpoint, take extra care not to get in deadlock. */ struct vmnt *vmp = NULL; endpoint_t proc_e; + int use_spare = FALSE; proc_e = m_in.m_source; if (fp->fp_flags & FP_SRV_PROC) { vmp = find_vmnt(proc_e); if (vmp != NULL) { - /* A call back or dev result from an FS - * endpoint. Set call back flag. Can do only - * one call back at a time. - */ + /* A callback from an FS endpoint. Can do only one at once. */ if (vmp->m_flags & VMNT_CALLBACK) { replycode(proc_e, EAGAIN); return; } + /* Already trying to resolve a deadlock? Can't handle more. */ + if (worker_available() == 0) { + replycode(proc_e, EAGAIN); + return; + } + /* A thread is available. Set callback flag. */ vmp->m_flags |= VMNT_CALLBACK; if (vmp->m_flags & VMNT_MOUNTING) { vmp->m_flags |= VMNT_FORCEROOTBSF; } } - if (worker_available() == 0) { - if (!deadlock_resolving) { - deadlock_resolving = 1; - dl_worker_start(func); - return; - } - - if (vmp != NULL) { - /* Already trying to resolve a deadlock, can't - * handle more, sorry */ - - replycode(proc_e, EAGAIN); - return; - } - } + /* Use the spare thread to handle this request if needed. */ + use_spare = TRUE; } - worker_start(func); + worker_start(fp, func, &m_in, use_spare); } -/*===========================================================================* - * do_async_dev_result * - *===========================================================================*/ -static void *do_async_dev_result(void *arg) -{ - endpoint_t endpt; - struct job my_job; - - my_job = *((struct job *) arg); - fp = my_job.j_fp; - - /* An asynchronous character driver has results for us */ - if (job_call_nr == DEV_REVIVE) { - endpt = job_m_in.REP_ENDPT; - if (endpt == VFS_PROC_NR) - endpt = find_suspended_ep(job_m_in.m_source, - job_m_in.REP_IO_GRANT); - - if (endpt == NONE) { - printf("VFS: proc with grant %d from %d not found\n", - job_m_in.REP_IO_GRANT, job_m_in.m_source); - } else if (job_m_in.REP_STATUS == SUSPEND) { - printf("VFS: got SUSPEND on DEV_REVIVE: not reviving proc\n"); - } else - revive(endpt, job_m_in.REP_STATUS); - } - else if (job_call_nr == DEV_OPEN_REPL) open_reply(); - else if (job_call_nr == DEV_REOPEN_REPL) reopen_reply(); - else if (job_call_nr == DEV_CLOSE_REPL) close_reply(); - else if (job_call_nr == DEV_SEL_REPL1) - select_reply1(job_m_in.m_source, job_m_in.DEV_MINOR, - job_m_in.DEV_SEL_OPS); - else if (job_call_nr == DEV_SEL_REPL2) - select_reply2(job_m_in.m_source, job_m_in.DEV_MINOR, - job_m_in.DEV_SEL_OPS); - - thread_cleanup(fp); - return(NULL); -} - -/*===========================================================================* - * do_control_msgs * - *===========================================================================*/ -static void *do_control_msgs(void *arg) -{ - struct job my_job; - - my_job = *((struct job *) arg); - fp = my_job.j_fp; - - /* Check for special control messages. */ - if (job_m_in.m_source == CLOCK) { - /* Alarm timer expired. Used only for select(). Check it. */ - expire_timers(job_m_in.NOTIFY_TIMESTAMP); - } - - thread_cleanup(NULL); - return(NULL); -} - -/*===========================================================================* - * do_dev_event * - *===========================================================================*/ -static void *do_dev_event(void *arg) -{ -/* Device notifies us of an event. */ - struct job my_job; - - my_job = *((struct job *) arg); - fp = my_job.j_fp; - - dev_status(job_m_in.m_source); - - thread_cleanup(fp); - return(NULL); -} /*===========================================================================* * do_fs_reply * *===========================================================================*/ -static void *do_fs_reply(struct job *job) +static void do_fs_reply(struct worker_thread *wp) { struct vmnt *vmp; - struct worker_thread *wp; if ((vmp = find_vmnt(who_e)) == NULL) panic("Couldn't find vmnt for endpoint %d", who_e); - wp = worker_get(job->j_fp->fp_wtid); - - if (wp == NULL) { - printf("VFS: spurious reply from %d\n", who_e); - return(NULL); - } - if (wp->w_task != who_e) { printf("VFS: expected %d to reply, not %d\n", wp->w_task, who_e); - return(NULL); + return; } *wp->w_fs_sendrec = m_in; wp->w_task = NONE; vmp->m_comm.c_cur_reqs--; /* We've got our reply, make room for others */ worker_signal(wp); /* Continue this thread */ - return(NULL); -} - -/*===========================================================================* - * lock_pm * - *===========================================================================*/ -static void lock_pm(void) -{ - struct fproc *org_fp; - struct worker_thread *org_self; - - /* First try to get it right off the bat */ - if (mutex_trylock(&pm_lock) == 0) - return; - - org_fp = fp; - org_self = self; - - if (mutex_lock(&pm_lock) != 0) - panic("Could not obtain lock on pm\n"); - - fp = org_fp; - self = org_self; -} - -/*===========================================================================* - * unlock_pm * - *===========================================================================*/ -static void unlock_pm(void) -{ - if (mutex_unlock(&pm_lock) != 0) - panic("Could not release lock on pm"); -} - -/*===========================================================================* - * do_pm * - *===========================================================================*/ -static void *do_pm(void *arg __unused) -{ - lock_pm(); - service_pm(); - unlock_pm(); - - thread_cleanup(NULL); - return(NULL); } /*===========================================================================* * do_pending_pipe * *===========================================================================*/ -static void *do_pending_pipe(void *arg) +static void do_pending_pipe(void) { int r, op; - struct job my_job; struct filp *f; tll_access_t locktype; - my_job = *((struct job *) arg); - fp = my_job.j_fp; - - lock_proc(fp, 1 /* force lock */); - f = scratch(fp).file.filp; assert(f != NULL); scratch(fp).file.filp = NULL; @@ -391,48 +244,18 @@ static void *do_pending_pipe(void *arg) replycode(fp->fp_endpoint, r); unlock_filp(f); - thread_cleanup(fp); - unlock_proc(fp); - return(NULL); -} - -/*===========================================================================* - * do_dummy * - *===========================================================================*/ -void *do_dummy(void *arg) -{ - struct job my_job; - int r; - - my_job = *((struct job *) arg); - fp = my_job.j_fp; - - if ((r = mutex_trylock(&fp->fp_lock)) == 0) { - thread_cleanup(fp); - unlock_proc(fp); - } else { - /* Proc is busy, let that worker thread carry out the work */ - thread_cleanup(NULL); - } - return(NULL); } /*===========================================================================* * do_work * *===========================================================================*/ -static void *do_work(void *arg) +static void do_work(void) { int error; - struct job my_job; message m_out; memset(&m_out, 0, sizeof(m_out)); - my_job = *((struct job *) arg); - fp = my_job.j_fp; - - lock_proc(fp, 0); /* This proc is busy */ - if (job_call_nr == MAPDRIVER) { error = do_mapdriver(); } else if (job_call_nr == COMMON_GETSYSINFO) { @@ -468,10 +291,6 @@ static void *do_work(void *arg) /* Copy the results back to the user and send reply. */ if (error != SUSPEND) reply(&m_out, fp->fp_endpoint, error); - - thread_cleanup(fp); - unlock_proc(fp); - return(NULL); } /*===========================================================================* @@ -500,7 +319,6 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info) message mess; struct rprocpub rprocpub[NR_BOOT_PROCS]; - force_sync = 0; receive_from = ANY; self = NULL; verbose = 0; @@ -541,8 +359,6 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info) s = send(PM_PROC_NR, &mess); /* send synchronization message */ /* All process table entries have been set. Continue with initialization. */ - fp = &fproc[_ENDPOINT_P(VFS_PROC_NR)];/* During init all communication with - * FSes is on behalf of myself */ init_dmap(); /* Initialize device table. */ system_hz = sys_hz(); @@ -564,28 +380,28 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info) if (s != OK) panic("VFS: can't subscribe to driver events (%d)", s); /* Initialize worker threads */ - for (i = 0; i < NR_WTHREADS; i++) { - worker_init(&workers[i]); - } - worker_init(&sys_worker); /* exclusive system worker thread */ - worker_init(&dl_worker); /* exclusive worker thread to resolve deadlocks */ + worker_init(); /* Initialize global locks */ - if (mthread_mutex_init(&pm_lock, NULL) != 0) - panic("VFS: couldn't initialize pm lock mutex"); - if (mthread_mutex_init(&exec_lock, NULL) != 0) - panic("VFS: couldn't initialize exec lock"); if (mthread_mutex_init(&bsf_lock, NULL) != 0) panic("VFS: couldn't initialize block special file lock"); - /* Initialize event resources for boot procs and locks for all procs */ + /* Initialize locks and initial values for all processes. */ for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { if (mutex_init(&rfp->fp_lock, NULL) != 0) panic("unable to initialize fproc lock"); + rfp->fp_worker = NULL; #if LOCK_DEBUG rfp->fp_vp_rdlocks = 0; rfp->fp_vmnt_rdlocks = 0; #endif + + /* Initialize process directories. mount_fs will set them to the + * correct values. + */ + FD_ZERO(&(rfp->fp_filp_inuse)); + rfp->fp_rd = NULL; + rfp->fp_wd = NULL; } init_dmap_locks(); /* init dmap locks */ @@ -594,9 +410,11 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info) init_select(); /* init select() structures */ init_filps(); /* Init filp structures */ mount_pfs(); /* mount Pipe File Server */ - worker_start(do_init_root); /* mount initial ramdisk as file system root */ - yield(); /* force do_init_root to start */ - self = NULL; + + /* Mount initial ramdisk as file system root. */ + receive_from = MFS_PROC_NR; + worker_start(fproc_addr(VFS_PROC_NR), do_init_root, &mess /*unused*/, + FALSE /*use_spare*/); return(OK); } @@ -604,66 +422,34 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info) /*===========================================================================* * do_init_root * *===========================================================================*/ -static void *do_init_root(void *arg) +static void do_init_root(void) { - struct fproc *rfp; - struct job my_job; int r; char *mount_label = "fs_imgrd"; /* FIXME: obtain this from RS */ - my_job = *((struct job *) arg); - fp = my_job.j_fp; - - lock_proc(fp, 1 /* force lock */); /* This proc is busy */ - lock_pm(); - - /* Initialize process directories. mount_fs will set them to the correct - * values */ - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - FD_ZERO(&(rfp->fp_filp_inuse)); - rfp->fp_rd = NULL; - rfp->fp_wd = NULL; - } - - receive_from = MFS_PROC_NR; r = mount_fs(DEV_IMGRD, "bootramdisk", "/", MFS_PROC_NR, 0, mount_label); if (r != OK) panic("Failed to initialize root"); receive_from = ANY; - - unlock_pm(); - thread_cleanup(fp); - unlock_proc(fp); - return(NULL); } /*===========================================================================* * lock_proc * *===========================================================================*/ -void lock_proc(struct fproc *rfp, int force_lock) +void lock_proc(struct fproc *rfp) { int r; - struct fproc *org_fp; struct worker_thread *org_self; r = mutex_trylock(&rfp->fp_lock); - - /* Were we supposed to obtain this lock immediately? */ - if (force_lock) { - assert(r == 0); - return; - } - if (r == 0) return; - org_fp = fp; - org_self = self; + org_self = worker_suspend(); if ((r = mutex_lock(&rfp->fp_lock)) != 0) panic("unable to lock fproc lock: %d", r); - fp = org_fp; - self = org_self; + worker_resume(org_self); } /*===========================================================================* @@ -680,48 +466,23 @@ void unlock_proc(struct fproc *rfp) /*===========================================================================* * thread_cleanup * *===========================================================================*/ -void thread_cleanup(struct fproc *rfp) +void thread_cleanup(void) { -/* Clean up worker thread. Skip parts if this thread is not associated - * with a particular process (i.e., rfp is NULL) */ +/* Perform cleanup actions for a worker thread. */ #if LOCK_DEBUG - if (rfp != NULL) { - check_filp_locks_by_me(); - check_vnode_locks_by_me(rfp); - check_vmnt_locks_by_me(rfp); - } + check_filp_locks_by_me(); + check_vnode_locks_by_me(fp); + check_vmnt_locks_by_me(fp); #endif - if (rfp != NULL && rfp->fp_flags & FP_PM_PENDING) { /* Postponed PM call */ - job_m_in = rfp->fp_job.j_m_in; - rfp->fp_flags &= ~FP_PM_PENDING; - service_pm_postponed(); - } + if (fp->fp_flags & FP_SRV_PROC) { + struct vmnt *vmp; -#if LOCK_DEBUG - if (rfp != NULL) { - check_filp_locks_by_me(); - check_vnode_locks_by_me(rfp); - check_vmnt_locks_by_me(rfp); - } -#endif - - if (rfp != NULL) { - rfp->fp_flags &= ~FP_DROP_WORK; - if (rfp->fp_flags & FP_SRV_PROC) { - struct vmnt *vmp; - - if ((vmp = find_vmnt(rfp->fp_endpoint)) != NULL) { - vmp->m_flags &= ~VMNT_CALLBACK; - } + if ((vmp = find_vmnt(fp->fp_endpoint)) != NULL) { + vmp->m_flags &= ~VMNT_CALLBACK; } } - - if (deadlock_resolving) { - if (self->w_tid == dl_worker.w_tid) - deadlock_resolving = 0; - } } /*===========================================================================* @@ -831,80 +592,81 @@ void replycode(endpoint_t whom, int result) /*===========================================================================* * service_pm_postponed * *===========================================================================*/ -static void service_pm_postponed(void) +void service_pm_postponed(void) { - int r; - vir_bytes pc, newsp; + int r, term_signal; + vir_bytes core_path; + vir_bytes exec_path, stack_frame, pc, newsp; + size_t exec_path_len, stack_frame_len; + endpoint_t proc_e; message m_out; memset(&m_out, 0, sizeof(m_out)); switch(job_call_nr) { - case PM_EXEC: - { - endpoint_t proc_e; - vir_bytes exec_path, stack_frame; - size_t exec_path_len, stack_frame_len; + case PM_EXEC: + proc_e = job_m_in.PM_PROC; + exec_path = (vir_bytes) job_m_in.PM_PATH; + exec_path_len = (size_t) job_m_in.PM_PATH_LEN; + stack_frame = (vir_bytes) job_m_in.PM_FRAME; + stack_frame_len = (size_t) job_m_in.PM_FRAME_LEN; - proc_e = job_m_in.PM_PROC; - exec_path = (vir_bytes) job_m_in.PM_PATH; - exec_path_len = (size_t) job_m_in.PM_PATH_LEN; - stack_frame = (vir_bytes) job_m_in.PM_FRAME; - stack_frame_len = (size_t) job_m_in.PM_FRAME_LEN; + assert(proc_e == fp->fp_endpoint); - r = pm_exec(proc_e, exec_path, exec_path_len, stack_frame, - stack_frame_len, &pc, &newsp, job_m_in.PM_EXECFLAGS); + r = pm_exec(exec_path, exec_path_len, stack_frame, stack_frame_len, + &pc, &newsp, job_m_in.PM_EXECFLAGS); + + /* Reply status to PM */ + m_out.m_type = PM_EXEC_REPLY; + m_out.PM_PROC = proc_e; + m_out.PM_PC = (void*) pc; + m_out.PM_STATUS = r; + m_out.PM_NEWSP = (void *) newsp; - /* Reply status to PM */ - m_out.m_type = PM_EXEC_REPLY; - m_out.PM_PROC = proc_e; - m_out.PM_PC = (void*) pc; - m_out.PM_STATUS = r; - m_out.PM_NEWSP = (void *) newsp; - } break; - case PM_EXIT: - { - endpoint_t proc_e; - proc_e = job_m_in.PM_PROC; + case PM_EXIT: + proc_e = job_m_in.PM_PROC; - pm_exit(proc_e); + assert(proc_e == fp->fp_endpoint); + + pm_exit(); + + /* Reply dummy status to PM for synchronization */ + m_out.m_type = PM_EXIT_REPLY; + m_out.PM_PROC = proc_e; - /* Reply dummy status to PM for synchronization */ - m_out.m_type = PM_EXIT_REPLY; - m_out.PM_PROC = proc_e; - } break; - case PM_DUMPCORE: - { - endpoint_t proc_e, traced_proc_e; - int term_signal; - vir_bytes core_path; + case PM_DUMPCORE: + proc_e = job_m_in.PM_PROC; + term_signal = job_m_in.PM_TERM_SIG; + core_path = (vir_bytes) job_m_in.PM_PATH; - proc_e = job_m_in.PM_PROC; - traced_proc_e = job_m_in.PM_TRACED_PROC; - if(job_m_in.PM_PROC != job_m_in.PM_TRACED_PROC) { - /* dumpcore request */ - term_signal = 0; - } else { - /* dumpcore on exit */ - term_signal = job_m_in.PM_TERM_SIG; - } - core_path = (vir_bytes) job_m_in.PM_PATH; + assert(proc_e == fp->fp_endpoint); - r = pm_dumpcore(proc_e, term_signal, core_path); + r = pm_dumpcore(term_signal, core_path); + + /* Reply status to PM */ + m_out.m_type = PM_CORE_REPLY; + m_out.PM_PROC = proc_e; + m_out.PM_STATUS = r; - /* Reply status to PM */ - m_out.m_type = PM_CORE_REPLY; - m_out.PM_PROC = proc_e; - m_out.PM_TRACED_PROC = traced_proc_e; - m_out.PM_STATUS = r; - } break; - default: + case PM_UNPAUSE: + proc_e = job_m_in.PM_PROC; + + assert(proc_e == fp->fp_endpoint); + + unpause(); + + m_out.m_type = PM_UNPAUSE_REPLY; + m_out.PM_PROC = proc_e; + + break; + + default: panic("Unhandled postponed PM call %d", job_m_in.m_type); } @@ -916,22 +678,34 @@ static void service_pm_postponed(void) /*===========================================================================* * service_pm * *===========================================================================*/ -static void service_pm() +static void service_pm(void) { +/* Process a request from PM. This function is called from the main thread, and + * may therefore not block. Any requests that may require blocking the calling + * thread must be executed in a separate thread. Aside from PM_REBOOT, all + * requests from PM involve another, target process: for example, PM tells VFS + * that a process is performing a setuid() call. For some requests however, + * that other process may not be idle, and in that case VFS must serialize the + * PM request handling with any operation is it handling for that target + * process. As it happens, the requests that may require blocking are also the + * ones where the target process may not be idle. For both these reasons, such + * requests are run in worker threads associated to the target process. + */ + struct fproc *rfp; int r, slot; message m_out; memset(&m_out, 0, sizeof(m_out)); - switch (job_call_nr) { + switch (call_nr) { case PM_SETUID: { endpoint_t proc_e; uid_t euid, ruid; - proc_e = job_m_in.PM_PROC; - euid = job_m_in.PM_EID; - ruid = job_m_in.PM_RID; + proc_e = m_in.PM_PROC; + euid = m_in.PM_EID; + ruid = m_in.PM_RID; pm_setuid(proc_e, euid, ruid); @@ -945,9 +719,9 @@ static void service_pm() endpoint_t proc_e; gid_t egid, rgid; - proc_e = job_m_in.PM_PROC; - egid = job_m_in.PM_EID; - rgid = job_m_in.PM_RID; + proc_e = m_in.PM_PROC; + egid = m_in.PM_EID; + rgid = m_in.PM_RID; pm_setgid(proc_e, egid, rgid); @@ -960,7 +734,7 @@ static void service_pm() { endpoint_t proc_e; - proc_e = job_m_in.PM_PROC; + proc_e = m_in.PM_PROC; pm_setsid(proc_e); m_out.m_type = PM_SETSID_REPLY; @@ -971,39 +745,22 @@ static void service_pm() case PM_EXEC: case PM_EXIT: case PM_DUMPCORE: + case PM_UNPAUSE: { - endpoint_t proc_e = job_m_in.PM_PROC; + endpoint_t proc_e = m_in.PM_PROC; if(isokendpt(proc_e, &slot) != OK) { printf("VFS: proc ep %d not ok\n", proc_e); return; } - fp = &fproc[slot]; - - if (fp->fp_flags & FP_PENDING) { - /* This process has a request pending, but PM wants it - * gone. Forget about the pending request and satisfy - * PM's request instead. Note that a pending request - * AND an EXEC request are mutually exclusive. Also, PM - * should send only one request/process at a time. - */ - assert(fp->fp_job.j_m_in.m_source != PM_PROC_NR); - } + rfp = &fproc[slot]; /* PM requests on behalf of a proc are handled after the * system call that might be in progress for that proc has - * finished. If the proc is not busy, we start a dummy call. + * finished. If the proc is not busy, we start a new thread. */ - if (!(fp->fp_flags & FP_PENDING) && - mutex_trylock(&fp->fp_lock) == 0) { - mutex_unlock(&fp->fp_lock); - worker_start(do_dummy); - fp->fp_flags |= FP_DROP_WORK; - } - - fp->fp_job.j_m_in = job_m_in; - fp->fp_flags |= FP_PM_PENDING; + worker_start(rfp, NULL, &m_in, FALSE /*use_spare*/); return; } @@ -1015,16 +772,16 @@ static void service_pm() uid_t reuid; gid_t regid; - pproc_e = job_m_in.PM_PPROC; - proc_e = job_m_in.PM_PROC; - child_pid = job_m_in.PM_CPID; - reuid = job_m_in.PM_REUID; - regid = job_m_in.PM_REGID; + pproc_e = m_in.PM_PPROC; + proc_e = m_in.PM_PROC; + child_pid = m_in.PM_CPID; + reuid = m_in.PM_REUID; + regid = m_in.PM_REGID; pm_fork(pproc_e, proc_e, child_pid); m_out.m_type = PM_FORK_REPLY; - if (job_call_nr == PM_SRV_FORK) { + if (call_nr == PM_SRV_FORK) { m_out.m_type = PM_SRV_FORK_REPLY; pm_setuid(proc_e, reuid, reuid); pm_setgid(proc_e, regid, regid); @@ -1039,9 +796,9 @@ static void service_pm() int group_no; gid_t *group_addr; - proc_e = job_m_in.PM_PROC; - group_no = job_m_in.PM_GROUP_NO; - group_addr = (gid_t *) job_m_in.PM_GROUP_ADDR; + proc_e = m_in.PM_PROC; + group_no = m_in.PM_GROUP_NO; + group_addr = (gid_t *) m_in.PM_GROUP_ADDR; pm_setgroups(proc_e, group_no, group_addr); @@ -1050,29 +807,21 @@ static void service_pm() } break; - case PM_UNPAUSE: - { - endpoint_t proc_e; - - proc_e = job_m_in.PM_PROC; - - unpause(proc_e); - - m_out.m_type = PM_UNPAUSE_REPLY; - m_out.PM_PROC = proc_e; - } - break; - case PM_REBOOT: - pm_reboot(); + /* Reboot requests are not considered postponed PM work and are instead + * handled from a separate worker thread that is associated with PM's + * process. PM makes no regular VFS calls, and thus, from VFS's + * perspective, PM is always idle. Therefore, we can safely do this. + * We do assume that PM sends us only one PM_REBOOT message at once, + * or ever for that matter. :) + */ + worker_start(fproc_addr(PM_PROC_NR), pm_reboot, &m_in, + FALSE /*use_spare*/); - /* Reply dummy status to PM for synchronization */ - m_out.m_type = PM_REBOOT_REPLY; - - break; + return; default: - printf("VFS: don't know how to handle PM request %d\n", job_call_nr); + printf("VFS: don't know how to handle PM request %d\n", call_nr); return; } @@ -1080,7 +829,6 @@ static void service_pm() r = send(PM_PROC_NR, &m_out); if (r != OK) panic("service_pm: send failed: %d", r); - } @@ -1090,33 +838,41 @@ static void service_pm() static int unblock(rfp) struct fproc *rfp; { +/* Unblock a process that was previously blocked on a pipe or a lock. This is + * done by reconstructing the original request and continuing/repeating it. + * This function returns TRUE when it has restored a request for execution, and + * FALSE if the caller should continue looking for work to do. + */ int blocked_on; - fp = rfp; blocked_on = rfp->fp_blocked_on; + + assert(blocked_on == FP_BLOCKED_ON_PIPE || blocked_on == FP_BLOCKED_ON_LOCK); + + /* READ, WRITE, FCNTL requests all use the same message layout. */ m_in.m_source = rfp->fp_endpoint; m_in.m_type = rfp->fp_block_callnr; - m_in.fd = scratch(fp).file.fd_nr; - m_in.buffer = scratch(fp).io.io_buffer; - m_in.nbytes = scratch(fp).io.io_nbytes; + m_in.fd = scratch(rfp).file.fd_nr; + m_in.buffer = scratch(rfp).io.io_buffer; + m_in.nbytes = scratch(rfp).io.io_nbytes; rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; /* no longer blocked */ rfp->fp_flags &= ~FP_REVIVED; reviving--; assert(reviving >= 0); - /* This should be a pipe I/O, not a device I/O. If it is, it'll 'leak' - * grants. - */ + /* This should not be device I/O. If it is, it'll 'leak' grants. */ assert(!GRANT_VALID(rfp->fp_grant)); - /* Pending pipe reads/writes can be handled directly */ + /* Pending pipe reads/writes cannot be repeated as is, and thus require a + * special resumption procedure. + */ if (blocked_on == FP_BLOCKED_ON_PIPE) { - worker_start(do_pending_pipe); - yield(); /* Give thread a chance to run */ - self = NULL; - return(0); /* Retrieve more work */ + worker_start(rfp, do_pending_pipe, &m_in, FALSE /*use_spare*/); + return(FALSE); /* Retrieve more work */ } - return(1); /* We've unblocked a process */ + /* A lock request. Repeat the original request as though it just came in. */ + fp = rfp; + return(TRUE); /* We've unblocked a process */ } diff --git a/servers/vfs/misc.c b/servers/vfs/misc.c index 8d1a4499c..4118f538c 100644 --- a/servers/vfs/misc.c +++ b/servers/vfs/misc.c @@ -32,9 +32,7 @@ #include #include #include "file.h" -#include "fproc.h" #include "scratchpad.h" -#include "dmap.h" #include #include "vnode.h" #include "vmnt.h" @@ -47,14 +45,7 @@ unsigned long calls_stats[NCALLS]; #endif -static void free_proc(struct fproc *freed, int flags); -/* -static int dumpcore(int proc_e, struct mem_map *seg_ptr); -static int write_bytes(struct inode *rip, off_t off, char *buf, size_t - bytes); -static int write_seg(struct inode *rip, off_t off, int proc_e, int seg, - off_t seg_off, phys_bytes seg_bytes); -*/ +static void free_proc(int flags); /*===========================================================================* * do_getsysinfo * @@ -316,7 +307,7 @@ int dupvm(struct fproc *rfp, int pfd, int *vmfd, struct filp **newfilp) { int result, procfd; struct filp *f = NULL; - struct fproc *vmf = &fproc[VM_PROC_NR]; + struct fproc *vmf = fproc_addr(VM_PROC_NR); *newfilp = NULL; @@ -391,7 +382,7 @@ int do_vm_call(message *m_out) if(isokendpt(ep, &slot) != OK) rfp = NULL; else rfp = &fproc[slot]; - vmf = &fproc[VM_PROC_NR]; + vmf = fproc_addr(VM_PROC_NR); assert(fp == vmf); assert(rfp != vmf); @@ -487,9 +478,14 @@ reqdone: *===========================================================================*/ void pm_reboot() { -/* Perform the VFS side of the reboot call. */ - int i; - struct fproc *rfp; +/* Perform the VFS side of the reboot call. This call is performed from the PM + * process context. + */ + message m_out; + int i, r; + struct fproc *rfp, *pmfp; + + pmfp = fp; sync_fses(); @@ -499,15 +495,25 @@ void pm_reboot() * them the chance to unmount (which should be possible as all normal * processes have no open files anymore). */ + /* This is the only place where we allow special modification of "fp". The + * reboot procedure should really be implemented as a PM message broadcasted + * to all processes, so that each process will be shut down cleanly by a + * thread operating on its behalf. Doing everything here is simpler, but it + * requires an exception to the strict model of having "fp" be the process + * that owns the current worker thread. + */ for (i = 0; i < NR_PROCS; i++) { rfp = &fproc[i]; /* Don't just free the proc right away, but let it finish what it was * doing first */ - lock_proc(rfp, 0); - if (rfp->fp_endpoint != NONE && find_vmnt(rfp->fp_endpoint) == NULL) - free_proc(rfp, 0); - unlock_proc(rfp); + if (rfp != fp) lock_proc(rfp); + if (rfp->fp_endpoint != NONE && find_vmnt(rfp->fp_endpoint) == NULL) { + worker_set_proc(rfp); /* temporarily fake process context */ + free_proc(0); + worker_set_proc(pmfp); /* restore original process context */ + } + if (rfp != fp) unlock_proc(rfp); } sync_fses(); @@ -519,15 +525,25 @@ void pm_reboot() /* Don't just free the proc right away, but let it finish what it was * doing first */ - lock_proc(rfp, 0); - if (rfp->fp_endpoint != NONE) - free_proc(rfp, 0); - unlock_proc(rfp); + if (rfp != fp) lock_proc(rfp); + if (rfp->fp_endpoint != NONE) { + worker_set_proc(rfp); /* temporarily fake process context */ + free_proc(0); + worker_set_proc(pmfp); /* restore original process context */ + } + if (rfp != fp) unlock_proc(rfp); } sync_fses(); unmount_all(1 /* Force */); + /* Reply to PM for synchronization */ + memset(&m_out, 0, sizeof(m_out)); + + m_out.m_type = PM_REBOOT_REPLY; + + if ((r = send(PM_PROC_NR, &m_out)) != OK) + panic("pm_reboot: send failed: %d", r); } /*===========================================================================* @@ -597,7 +613,7 @@ void pm_fork(endpoint_t pproc, endpoint_t cproc, pid_t cpid) /*===========================================================================* * free_proc * *===========================================================================*/ -static void free_proc(struct fproc *exiter, int flags) +static void free_proc(int flags) { int i; register struct fproc *rfp; @@ -605,46 +621,43 @@ static void free_proc(struct fproc *exiter, int flags) register struct vnode *vp; dev_t dev; - if (exiter->fp_endpoint == NONE) + if (fp->fp_endpoint == NONE) panic("free_proc: already free"); - if (fp_is_blocked(exiter)) - unpause(exiter->fp_endpoint); + if (fp_is_blocked(fp)) + unpause(); /* Loop on file descriptors, closing any that are open. */ for (i = 0; i < OPEN_MAX; i++) { - (void) close_fd(exiter, i); + (void) close_fd(fp, i); } /* Release root and working directories. */ - if (exiter->fp_rd) { put_vnode(exiter->fp_rd); exiter->fp_rd = NULL; } - if (exiter->fp_wd) { put_vnode(exiter->fp_wd); exiter->fp_wd = NULL; } + if (fp->fp_rd) { put_vnode(fp->fp_rd); fp->fp_rd = NULL; } + if (fp->fp_wd) { put_vnode(fp->fp_wd); fp->fp_wd = NULL; } /* The rest of these actions is only done when processes actually exit. */ if (!(flags & FP_EXITING)) return; - exiter->fp_flags |= FP_EXITING; + fp->fp_flags |= FP_EXITING; /* Check if any process is SUSPENDed on this driver. * If a driver exits, unmap its entries in the dmap table. * (unmapping has to be done after the first step, because the * dmap table is used in the first step.) */ - unsuspend_by_endpt(exiter->fp_endpoint); - dmap_unmap_by_endpt(exiter->fp_endpoint); + unsuspend_by_endpt(fp->fp_endpoint); + dmap_unmap_by_endpt(fp->fp_endpoint); - worker_stop_by_endpt(exiter->fp_endpoint); /* Unblock waiting threads */ - vmnt_unmap_by_endpt(exiter->fp_endpoint); /* Invalidate open files if this + worker_stop_by_endpt(fp->fp_endpoint); /* Unblock waiting threads */ + vmnt_unmap_by_endpt(fp->fp_endpoint); /* Invalidate open files if this * was an active FS */ - /* Invalidate endpoint number for error and sanity checks. */ - exiter->fp_endpoint = NONE; - /* If a session leader exits and it has a controlling tty, then revoke * access to its controlling tty from all other processes using it. */ - if ((exiter->fp_flags & FP_SESLDR) && exiter->fp_tty != 0) { - dev = exiter->fp_tty; + if ((fp->fp_flags & FP_SESLDR) && fp->fp_tty != 0) { + dev = fp->fp_tty; for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { if(rfp->fp_pid == PID_FREE) continue; if (rfp->fp_tty == dev) rfp->fp_tty = 0; @@ -666,25 +679,21 @@ static void free_proc(struct fproc *exiter, int flags) } /* Exit done. Mark slot as free. */ - exiter->fp_pid = PID_FREE; - if (exiter->fp_flags & FP_PENDING) - pending--; /* No longer pending job, not going to do it */ - exiter->fp_flags = FP_NOFLAGS; + fp->fp_endpoint = NONE; + fp->fp_pid = PID_FREE; + fp->fp_flags = FP_NOFLAGS; } /*===========================================================================* * pm_exit * *===========================================================================*/ -void pm_exit(proc) -endpoint_t proc; +void pm_exit(void) { -/* Perform the file system portion of the exit(status) system call. */ - int exitee_p; +/* Perform the file system portion of the exit(status) system call. + * This function is called from the context of the exiting process. + */ - /* Nevertheless, pretend that the call came from the user. */ - okendpt(proc, &exitee_p); - fp = &fproc[exitee_p]; - free_proc(fp, FP_EXITING); + free_proc(FP_EXITING); } /*===========================================================================* @@ -850,21 +859,18 @@ int do_svrctl(message *UNUSED(m_out)) /*===========================================================================* * pm_dumpcore * *===========================================================================*/ -int pm_dumpcore(endpoint_t proc_e, int csig, vir_bytes exe_name) +int pm_dumpcore(int csig, vir_bytes exe_name) { - int slot, r = OK, core_fd; + int r = OK, core_fd; struct filp *f; char core_path[PATH_MAX]; char proc_name[PROC_NAME_LEN]; - okendpt(proc_e, &slot); - fp = &fproc[slot]; - /* if a process is blocked, scratch(fp).file.fd_nr holds the fd it's blocked * on. free it up for use by common_open(). */ if (fp_is_blocked(fp)) - unpause(fp->fp_endpoint); + unpause(); /* open core file */ snprintf(core_path, PATH_MAX, "%s.%d", CORE_NAME, fp->fp_pid); @@ -884,15 +890,15 @@ int pm_dumpcore(endpoint_t proc_e, int csig, vir_bytes exe_name) core_exit: if(csig) - free_proc(fp, FP_EXITING); + free_proc(FP_EXITING); return(r); } /*===========================================================================* * ds_event * *===========================================================================*/ -void * -ds_event(void *arg) +void +ds_event(void) { char key[DS_MAX_KEYLEN]; char *blkdrv_prefix = "drv.blk."; @@ -901,11 +907,6 @@ ds_event(void *arg) int type, r, is_blk; endpoint_t owner_endpoint; - struct job my_job; - - my_job = *((struct job *) arg); - fp = my_job.j_fp; - /* Get the event and the owner from DS. */ while ((r = ds_check(key, &type, &owner_endpoint)) == OK) { /* Only check for block and character driver up events. */ @@ -928,9 +929,6 @@ ds_event(void *arg) } if (r != ENOENT) printf("VFS: ds_event: ds_check failed: %d\n", r); - - thread_cleanup(NULL); - return(NULL); } /* A function to be called on panic(). */ diff --git a/servers/vfs/mount.c b/servers/vfs/mount.c index 6db6b379d..62b8f14ec 100644 --- a/servers/vfs/mount.c +++ b/servers/vfs/mount.c @@ -24,8 +24,6 @@ #include #include #include "file.h" -#include "fproc.h" -#include "dmap.h" #include #include "vnode.h" #include "vmnt.h" diff --git a/servers/vfs/open.c b/servers/vfs/open.c index 2d0dde200..bb90e11ea 100644 --- a/servers/vfs/open.c +++ b/servers/vfs/open.c @@ -19,9 +19,7 @@ #include #include #include "file.h" -#include "fproc.h" #include "scratchpad.h" -#include "dmap.h" #include "lock.h" #include "param.h" #include @@ -161,9 +159,8 @@ int common_open(char path[PATH_MAX], int oflags, mode_t omode) dev = (dev_t) vp->v_sdev; /* TTY needs to know about the O_NOCTTY flag. */ r = dev_open(dev, who_e, bits | (oflags & O_NOCTTY)); - if (r == SUSPEND) suspend(FP_BLOCKED_ON_DOPEN); - else vp = filp->filp_vno; /* Might be updated by - * dev_open/clone_opcl */ + vp = filp->filp_vno; /* Might be updated by + * dev_open/clone_opcl */ break; case S_IFBLK: @@ -767,11 +764,3 @@ int fd_nr; return(OK); } - -/*===========================================================================* - * close_reply * - *===========================================================================*/ -void close_reply() -{ - /* No need to do anything */ -} diff --git a/servers/vfs/path.c b/servers/vfs/path.c index 3d94215db..2b3d6b69e 100644 --- a/servers/vfs/path.c +++ b/servers/vfs/path.c @@ -18,11 +18,9 @@ #include #include #include -#include "threads.h" #include "vmnt.h" #include "vnode.h" #include "path.h" -#include "fproc.h" #include "param.h" /* Set to following define to 1 if you really want to use the POSIX definition diff --git a/servers/vfs/pipe.c b/servers/vfs/pipe.c index 8f4fd7036..57c2378b8 100644 --- a/servers/vfs/pipe.c +++ b/servers/vfs/pipe.c @@ -27,9 +27,7 @@ #include #include #include "file.h" -#include "fproc.h" #include "scratchpad.h" -#include "dmap.h" #include "param.h" #include #include "vnode.h" @@ -436,7 +434,6 @@ int count; /* max number of processes to release */ */ if (rp->fp_blocked_on == FP_BLOCKED_ON_POPEN || - rp->fp_blocked_on == FP_BLOCKED_ON_DOPEN || rp->fp_blocked_on == FP_BLOCKED_ON_LOCK || rp->fp_blocked_on == FP_BLOCKED_ON_OTHER) { if (!FD_ISSET(scratch(rp).file.fd_nr, @@ -469,12 +466,12 @@ int count; /* max number of processes to release */ void revive(endpoint_t proc_e, int returned) { /* Revive a previously blocked process. When a process hangs on tty, this - * is the way it is eventually released. + * is the way it is eventually released. For processes blocked on _SELECT and + * _OTHER, this function MUST NOT block its calling thread. */ struct fproc *rfp; int blocked_on; int fd_nr, slot; - struct filp *fil_ptr; if (proc_e == NONE || isokendpt(proc_e, &slot) != OK) return; @@ -492,26 +489,6 @@ void revive(endpoint_t proc_e, int returned) /* Revive a process suspended on a pipe or lock. */ rfp->fp_flags |= FP_REVIVED; reviving++; /* process was waiting on pipe or lock */ - } else if (blocked_on == FP_BLOCKED_ON_DOPEN) { - rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - scratch(rfp).file.fd_nr = 0; - if (returned < 0) { - fil_ptr = rfp->fp_filp[fd_nr]; - lock_filp(fil_ptr, VNODE_OPCL); - rfp->fp_filp[fd_nr] = NULL; - FD_CLR(fd_nr, &rfp->fp_filp_inuse); - if (fil_ptr->filp_count != 1) { - panic("VFS: revive: bad count in filp: %d", - fil_ptr->filp_count); - } - fil_ptr->filp_count = 0; - unlock_filp(fil_ptr); - put_vnode(fil_ptr->filp_vno); - fil_ptr->filp_vno = NULL; - replycode(proc_e, returned); - } else { - replycode(proc_e, fd_nr); - } } else { rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; scratch(rfp).file.fd_nr = 0; @@ -544,97 +521,77 @@ void revive(endpoint_t proc_e, int returned) /*===========================================================================* * unpause * *===========================================================================*/ -void unpause(endpoint_t proc_e) +void unpause(void) { /* A signal has been sent to a user who is paused on the file system. * Abort the system call with the EINTR error message. */ - - register struct fproc *rfp, *org_fp; - int slot, blocked_on, fild, status = EINTR, major_dev, minor_dev; + int blocked_on, fild, status = EINTR; struct filp *f; dev_t dev; - message mess; int wasreviving = 0; - if (isokendpt(proc_e, &slot) != OK) { - printf("VFS: ignoring unpause for bogus endpoint %d\n", proc_e); - return; - } + if (!fp_is_blocked(fp)) return; + blocked_on = fp->fp_blocked_on; - rfp = &fproc[slot]; - if (!fp_is_blocked(rfp)) return; - blocked_on = rfp->fp_blocked_on; + /* Clear the block status now. The procedure below might make blocking calls + * and it is imperative that while at least dev_cancel() is executing, other + * parts of VFS do not perceive this process as blocked on something. + */ + fp->fp_blocked_on = FP_BLOCKED_ON_NONE; - if (rfp->fp_flags & FP_REVIVED) { - rfp->fp_flags &= ~FP_REVIVED; + if (fp->fp_flags & FP_REVIVED) { + fp->fp_flags &= ~FP_REVIVED; reviving--; wasreviving = 1; } switch (blocked_on) { case FP_BLOCKED_ON_PIPE:/* process trying to read or write a pipe */ + /* If the operation succeeded partially, return the bytes + * processed so far, and clear the remembered state. Otherwise, + * return EINTR as usual. + */ + if (fp->fp_cum_io_partial > 0) { + status = fp->fp_cum_io_partial; + + fp->fp_cum_io_partial = 0; + } break; case FP_BLOCKED_ON_LOCK:/* process trying to set a lock with FCNTL */ break; case FP_BLOCKED_ON_SELECT:/* process blocking on select() */ - select_forget(proc_e); + select_forget(); break; case FP_BLOCKED_ON_POPEN: /* process trying to open a fifo */ break; - case FP_BLOCKED_ON_DOPEN:/* process trying to open a device */ - /* Don't cancel OPEN. Just wait until the open completes. */ - return; - case FP_BLOCKED_ON_OTHER:/* process trying to do device I/O (e.g. tty)*/ - if (rfp->fp_flags & FP_SUSP_REOPEN) { + if (fp->fp_flags & FP_SUSP_REOPEN) { /* Process is suspended while waiting for a reopen. * Just reply EINTR. */ - rfp->fp_flags &= ~FP_SUSP_REOPEN; + fp->fp_flags &= ~FP_SUSP_REOPEN; status = EINTR; break; } - fild = scratch(rfp).file.fd_nr; + fild = scratch(fp).file.fd_nr; if (fild < 0 || fild >= OPEN_MAX) panic("file descriptor out-of-range"); - f = rfp->fp_filp[fild]; + f = fp->fp_filp[fild]; if(!f) { - sys_sysctl_stacktrace(rfp->fp_endpoint); + sys_sysctl_stacktrace(fp->fp_endpoint); panic("process %d blocked on empty fd %d", - rfp->fp_endpoint, fild); + fp->fp_endpoint, fild); } dev = (dev_t) f->filp_vno->v_sdev; /* device hung on */ - major_dev = major(dev); - minor_dev = minor(dev); - mess.TTY_LINE = minor_dev; - mess.USER_ENDPT = rfp->fp_ioproc; - mess.IO_GRANT = (char *) rfp->fp_grant; - /* Tell kernel R or W. Mode is from current call, not open. */ - mess.COUNT = rfp->fp_block_callnr == READ ? R_BIT : W_BIT; - mess.m_type = CANCEL; + status = dev_cancel(dev); - org_fp = fp; - fp = rfp; /* hack - ctty_io uses fp */ - (*dmap[major_dev].dmap_io)(rfp->fp_task, &mess); - fp = org_fp; - status = mess.REP_STATUS; - if (status == SUSPEND) - return; /* Process will be revived at a - * later time. - */ - - if (status == EAGAIN) status = EINTR; - if (GRANT_VALID(rfp->fp_grant)) { - (void) cpf_revoke(rfp->fp_grant); - rfp->fp_grant = GRANT_INVALID; - } break; default : panic("VFS: unknown block reason: %d", blocked_on); @@ -645,9 +602,5 @@ void unpause(endpoint_t proc_e) susp_count--; } - if(rfp->fp_blocked_on != FP_BLOCKED_ON_NONE) { - rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - replycode(proc_e, status); /* signal interrupted call */ - } + replycode(fp->fp_endpoint, status); /* signal interrupted call */ } - diff --git a/servers/vfs/protect.c b/servers/vfs/protect.c index 4f76bc9e2..d719e3e07 100644 --- a/servers/vfs/protect.c +++ b/servers/vfs/protect.c @@ -14,7 +14,6 @@ #include #include #include "file.h" -#include "fproc.h" #include "path.h" #include "param.h" #include diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h index 6a048c25d..6a8fdebbc 100644 --- a/servers/vfs/proto.h +++ b/servers/vfs/proto.h @@ -31,15 +31,15 @@ void send_work(void); /* device.c */ int dev_open(dev_t dev, endpoint_t proc_e, int flags); int dev_reopen(dev_t dev, int filp_no, int flags); -void dev_reply(struct dmap *dp); int dev_close(dev_t dev, int filp_no); +void cdev_reply(void); int bdev_open(dev_t dev, int access); int bdev_close(dev_t dev); +void bdev_reply(struct dmap *dp); int dev_io(int op, dev_t dev, endpoint_t proc_e, void *buf, u64_t pos, size_t bytes, int flags, int suspend_reopen); int gen_opcl(int op, dev_t dev, endpoint_t task_nr, int flags); -int gen_io(endpoint_t driver_e, message *mess_ptr); -int asyn_io(endpoint_t drv_e, message *mess_ptr); +int gen_io(endpoint_t drv_e, message *mess_ptr); int no_dev(int op, dev_t dev, endpoint_t proc, int flags); int no_dev_io(endpoint_t, message *); int tty_opcl(int op, dev_t dev, endpoint_t proc, int flags); @@ -47,13 +47,11 @@ int ctty_opcl(int op, dev_t dev, endpoint_t proc, int flags); int clone_opcl(int op, dev_t dev, endpoint_t proc, int flags); int ctty_io(endpoint_t task_nr, message *mess_ptr); int do_ioctl(message *m_out); +int dev_select(dev_t dev, int ops); +int dev_cancel(dev_t dev); void pm_setsid(endpoint_t proc_e); -void dev_status(endpoint_t drv_e); void bdev_up(int major); void cdev_up(int major); -endpoint_t find_suspended_ep(endpoint_t driver, cp_grant_id_t g); -void reopen_reply(void); -void open_reply(void); /* dmap.c */ void lock_dmap(struct dmap *dp); @@ -77,11 +75,11 @@ int map_service(struct rprocpub *rpub); void write_elf_core_file(struct filp *f, int csig, char *exe_name); /* exec.c */ -int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, vir_bytes frame, - size_t frame_len, vir_bytes *pc, vir_bytes *newsp, int flags); +int pm_exec(vir_bytes path, size_t path_len, vir_bytes frame, size_t frame_len, + vir_bytes *pc, vir_bytes *newsp, int flags); /* filedes.c */ -void *do_filp_gc(void *arg); +int do_filp_gc(void); void check_filp_locks(void); void check_filp_locks_by_me(void); void init_filps(void); @@ -125,14 +123,15 @@ void lock_revive(void); /* main.c */ int main(void); -void lock_proc(struct fproc *rfp, int force_lock); +void lock_proc(struct fproc *rfp); +void unlock_proc(struct fproc *rfp); void reply(message *m_out, endpoint_t whom, int result); void replycode(endpoint_t whom, int result); -void thread_cleanup(struct fproc *rfp); -void unlock_proc(struct fproc *rfp); +void service_pm_postponed(void); +void thread_cleanup(void); /* misc.c */ -void pm_exit(endpoint_t proc); +void pm_exit(void); int do_fcntl(message *m_out); void pm_fork(endpoint_t pproc, endpoint_t cproc, pid_t cpid); void pm_setgid(endpoint_t proc_e, int egid, int rgid); @@ -144,8 +143,8 @@ void pm_reboot(void); int do_svrctl(message *m_out); int do_getsysinfo(void); int do_vm_call(message *m_out); -int pm_dumpcore(endpoint_t proc_e, int sig, vir_bytes exe_name); -void * ds_event(void *arg); +int pm_dumpcore(int sig, vir_bytes exe_name); +void ds_event(void); int dupvm(struct fproc *fp, int pfd, int *vmfd, struct filp **f); int do_getrusage(message *m_out); @@ -163,7 +162,6 @@ void unmount_all(int force); /* open.c */ int do_close(message *m_out); int close_fd(struct fproc *rfp, int fd_nr); -void close_reply(void); int common_open(char path[PATH_MAX], int oflags, mode_t omode); int do_creat(void); int do_lseek(message *m_out); @@ -193,7 +191,7 @@ int do_check_perms(message *m_out); int do_pipe(message *m_out); int do_pipe2(message *m_out); int map_vnode(struct vnode *vp, endpoint_t fs_e); -void unpause(endpoint_t proc_e); +void unpause(void); int pipe_check(struct filp *filp, int rw_flag, int oflags, int bytes, int notouch); void release(struct vnode *vp, int op, int count); @@ -359,22 +357,24 @@ int do_gcov_flush(void); int do_select(message *m_out); void init_select(void); void select_callback(struct filp *, int ops); -void select_forget(endpoint_t proc_e); +void select_forget(void); void select_reply1(endpoint_t driver_e, int minor, int status); void select_reply2(endpoint_t driver_e, int minor, int status); void select_timeout_check(timer_t *); void select_unsuspend_by_endpt(endpoint_t proc); /* worker.c */ +void worker_init(void); int worker_available(void); struct worker_thread *worker_get(thread_t worker_tid); -struct job *worker_getjob(thread_t worker_tid); -void worker_init(struct worker_thread *worker); void worker_signal(struct worker_thread *worker); -void worker_start(void *(*func)(void *arg)); +int worker_can_start(struct fproc *rfp); +void worker_start(struct fproc *rfp, void (*func)(void), message *m_ptr, + int use_spare); void worker_stop(struct worker_thread *worker); void worker_stop_by_endpt(endpoint_t proc_e); void worker_wait(void); -void sys_worker_start(void *(*func)(void *arg)); -void dl_worker_start(void *(*func)(void *arg)); +struct worker_thread *worker_suspend(void); +void worker_resume(struct worker_thread *org_self); +void worker_set_proc(struct fproc *rfp); #endif diff --git a/servers/vfs/read.c b/servers/vfs/read.c index a96f07066..0e45ffbaa 100644 --- a/servers/vfs/read.c +++ b/servers/vfs/read.c @@ -16,7 +16,6 @@ #include #include #include "file.h" -#include "fproc.h" #include "scratchpad.h" #include "param.h" #include @@ -41,20 +40,17 @@ int do_read(message *UNUSED(m_out)) *===========================================================================*/ void lock_bsf(void) { - struct fproc *org_fp; struct worker_thread *org_self; if (mutex_trylock(&bsf_lock) == 0) return; - org_fp = fp; - org_self = self; + org_self = worker_suspend(); if (mutex_lock(&bsf_lock) != 0) panic("unable to lock block special file lock"); - fp = org_fp; - self = org_self; + worker_resume(org_self); } /*===========================================================================* @@ -150,7 +146,7 @@ int read_write(struct fproc *rfp, int rw_flag, struct filp *f, if (size > SSIZE_MAX) return(EINVAL); - op = (rw_flag == READING ? VFS_DEV_READ : VFS_DEV_WRITE); + op = (rw_flag == READING ? DEV_READ_S : DEV_WRITE_S); if (S_ISFIFO(vp->v_mode)) { /* Pipes */ if (rfp->fp_cum_io_partial != 0) { @@ -164,7 +160,7 @@ int read_write(struct fproc *rfp, int rw_flag, struct filp *f, } else if (S_ISCHR(vp->v_mode)) { /* Character special files. */ dev_t dev; int suspend_reopen; - int op = (rw_flag == READING ? VFS_DEV_READ : VFS_DEV_WRITE); + int op = (rw_flag == READING ? DEV_READ_S : DEV_WRITE_S); if(rw_flag == PEEKING) { printf("read_write: peek on char device makes no sense\n"); diff --git a/servers/vfs/request.c b/servers/vfs/request.c index 71ea86ae2..2831cf2bc 100644 --- a/servers/vfs/request.c +++ b/servers/vfs/request.c @@ -18,7 +18,6 @@ #include #include #include -#include "fproc.h" #include "vmnt.h" #include "vnode.h" #include "path.h" diff --git a/servers/vfs/select.c b/servers/vfs/select.c index 53f183bf9..073d1cea3 100644 --- a/servers/vfs/select.c +++ b/servers/vfs/select.c @@ -4,6 +4,14 @@ * do_select: perform the SELECT system call * select_callback: notify select system of possible fd operation * select_unsuspend_by_endpt: cancel a blocking select on exiting driver + * + * The select code uses minimal locking, so that the replies from character + * drivers can be processed without blocking. Filps are locked only for pipes. + * We make the assumption that any other structures and fields are safe to + * check (and possibly change) as long as we know that a process is blocked on + * a select(2) call, meaning that all involved filps are guaranteed to stay + * open until either we finish the select call, it the process gets interrupted + * by a signal. */ #include "fs.h" @@ -17,8 +25,6 @@ #include #include "file.h" -#include "fproc.h" -#include "dmap.h" #include "vnode.h" /* max. number of simultaneously pending select() calls */ @@ -37,13 +43,12 @@ static struct selectentry { int nfds, nreadyfds; int error; char block; + char starting; clock_t expiry; timer_t timer; /* if expiry > 0 */ } selecttab[MAXSELECTS]; -static int copy_fdsets(struct selectentry *se, int nfds, int - direction); -static int do_select_request(struct selectentry *se, int fd, int *ops); +static int copy_fdsets(struct selectentry *se, int nfds, int direction); static void filp_status(struct filp *fp, int status); static int is_deferred(struct selectentry *se); static void restart_proc(struct selectentry *se); @@ -52,11 +57,9 @@ static int is_regular_file(struct filp *f); static int is_pipe(struct filp *f); static int is_supported_major(struct filp *f); static void select_lock_filp(struct filp *f, int ops); -static int select_request_async(struct filp *f, int *ops, int block); static int select_request_file(struct filp *f, int *ops, int block); static int select_request_major(struct filp *f, int *ops, int block); static int select_request_pipe(struct filp *f, int *ops, int block); -static int select_request_sync(struct filp *f, int *ops, int block); static void select_cancel_all(struct selectentry *e); static void select_cancel_filp(struct filp *f); static void select_return(struct selectentry *); @@ -88,13 +91,15 @@ int do_select(message *UNUSED(m_out)) { /* Implement the select(nfds, readfds, writefds, errorfds, timeout) system * call. First we copy the arguments and verify their sanity. Then we check - * whether there are file descriptors that satisfy the select call right of the - * bat. If so, or if there are no ready file descriptors but the process + * whether there are file descriptors that satisfy the select call right off + * the bat. If so, or if there are no ready file descriptors but the process * requested to return immediately, we return the result. Otherwise we set a * timeout and wait for either the file descriptors to become ready or the - * timer to go off. If no timeout value was provided, we wait indefinitely. */ - + * timer to go off. If no timeout value was provided, we wait indefinitely. + */ int r, nfds, do_timeout = 0, fd, s; + struct filp *f; + unsigned int type, ops; struct timeval timeout; struct selectentry *se; vir_bytes vtimeout; @@ -153,11 +158,14 @@ int do_select(message *UNUSED(m_out)) se->block = 0; se->expiry = 0; /* no timer set (yet) */ + /* We are going to lock filps, and that means that while locking a second + * filp, we might already get the results for the first one. In that case, + * the incoming results must not cause the select call to finish prematurely. + */ + se->starting = TRUE; + /* Verify that file descriptors are okay to select on */ for (fd = 0; fd < nfds; fd++) { - struct filp *f; - unsigned int type, ops; - /* Because the select() interface implicitly includes file descriptors * you might not want to select on, we have to figure out whether we're * interested in them. Typically, these file descriptors include fd's @@ -210,9 +218,6 @@ int do_select(message *UNUSED(m_out)) /* Check all file descriptors in the set whether one is 'ready' now */ for (fd = 0; fd < nfds; fd++) { - int ops, r; - struct filp *f; - /* Again, check for involuntarily selected fd's */ if (!(ops = tab2ops(fd, se))) continue; /* No operations set; nothing to do for this fd */ @@ -224,9 +229,15 @@ int do_select(message *UNUSED(m_out)) int wantops; wantops = (f->filp_select_ops |= ops); - r = do_select_request(se, fd, &wantops); - if (r != OK && r != SUSPEND) + type = se->type[fd]; + select_lock_filp(f, wantops); + r = fdtypes[type].select_request(f, &wantops, se->block); + unlock_filp(f); + if (r != OK && r != SUSPEND) { + se->error = r; + se->block = 0; /* Stop blocking to return asap */ break; /* Error or bogus return code; abort */ + } /* The select request above might have turned on/off some * operations because they were 'ready' or not meaningful. @@ -236,6 +247,9 @@ int do_select(message *UNUSED(m_out)) } } + /* At this point there won't be any blocking calls anymore. */ + se->starting = FALSE; + if ((se->nreadyfds > 0 || !se->block) && !is_deferred(se)) { /* fd's were found that were ready to go right away, and/or * we were instructed not to block at all. Must return @@ -291,6 +305,9 @@ static int is_deferred(struct selectentry *se) int fd; struct filp *f; + /* The select call must have finished its initialization at all. */ + if (se->starting) return(TRUE); + for (fd = 0; fd < se->nfds; fd++) { if ((f = se->filps[fd]) == NULL) continue; if (f->filp_select_flags & (FSF_UPDATE|FSF_BUSY)) return(TRUE); @@ -322,7 +339,10 @@ static int is_pipe(struct filp *f) *===========================================================================*/ static int is_supported_major(struct filp *f) { -/* See if this filp is a handle on a device on which we support select() */ +/* See if this filp is a handle on a character device on which we support + * select(). This function MUST NOT block its calling thread. The given filp + * may or may not be locked. + */ unsigned int m; if (!(f && f->filp_vno)) return(FALSE); @@ -336,13 +356,21 @@ static int is_supported_major(struct filp *f) } /*===========================================================================* - * select_request_async * + * select_request_major * *===========================================================================*/ -static int select_request_async(struct filp *f, int *ops, int block) +static int select_request_major(struct filp *f, int *ops, int block) { +/* Check readiness status on a supported character device. Unless suitable + * results are available right now, this will only initiate the polling + * process, causing result processing to be deferred. This function MUST NOT + * block its calling thread. The given filp may or may not be locked. + */ int r, rops, major; struct dmap *dp; + major = major(f->filp_vno->v_sdev); + if (major < 0 || major >= NR_DEVICES) return(ENXIO); + rops = *ops; /* By default, nothing to do */ @@ -375,21 +403,16 @@ static int select_request_async(struct filp *f, int *ops, int block) if (f->filp_select_flags & FSF_BUSY) return(SUSPEND); - major = major(f->filp_vno->v_sdev); - if (major < 0 || major >= NR_DEVICES) return(ENXIO); dp = &dmap[major]; - if (dp->dmap_sel_filp) + if (dp->dmap_sel_busy) return(SUSPEND); f->filp_select_flags &= ~FSF_UPDATE; - r = dev_io(VFS_DEV_SELECT, f->filp_vno->v_sdev, rops, NULL, - ((u64_t)(0)), 0, 0, FALSE); - if (r < 0 && r != SUSPEND) + r = dev_select(f->filp_vno->v_sdev, rops); + if (r != OK) return(r); - if (r != SUSPEND) - panic("select_request_asynch: expected SUSPEND got: %d", r); - + dp->dmap_sel_busy = TRUE; dp->dmap_sel_filp = f; f->filp_select_flags |= FSF_BUSY; @@ -406,47 +429,14 @@ static int select_request_file(struct filp *UNUSED(f), int *UNUSED(ops), return(OK); } -/*===========================================================================* - * select_request_major * - *===========================================================================*/ -static int select_request_major(struct filp *f, int *ops, int block) -{ - int major, r; - - major = major(f->filp_vno->v_sdev); - if (major < 0 || major >= NR_DEVICES) return(ENXIO); - - if (dmap[major].dmap_style == STYLE_DEVA || - dmap[major].dmap_style == STYLE_CLONE_A) - r = select_request_async(f, ops, block); - else - r = select_request_sync(f, ops, block); - - return(r); -} - -/*===========================================================================* - * select_request_sync * - *===========================================================================*/ -static int select_request_sync(struct filp *f, int *ops, int block) -{ - int rops; - - rops = *ops; - if (block) rops |= SEL_NOTIFY; - *ops = dev_io(VFS_DEV_SELECT, f->filp_vno->v_sdev, rops, NULL, - ((u64_t)(0)), 0, 0, FALSE); - if (*ops < 0) - return(*ops); - - return(OK); -} - /*===========================================================================* * select_request_pipe * *===========================================================================*/ static int select_request_pipe(struct filp *f, int *ops, int block) { +/* Check readiness status on a pipe. The given filp is locked. This function + * may block its calling thread if necessary. + */ int orig_ops, r = 0, err; orig_ops = *ops; @@ -538,6 +528,9 @@ static void ops2tab(int ops, int fd, struct selectentry *e) *===========================================================================*/ static int copy_fdsets(struct selectentry *se, int nfds, int direction) { +/* Copy FD sets from or to the user process calling select(2). This function + * MUST NOT block the calling thread. + */ int r; size_t fd_setsize; endpoint_t src_e, dst_e; @@ -589,7 +582,9 @@ static int copy_fdsets(struct selectentry *se, int nfds, int direction) *===========================================================================*/ static void select_cancel_all(struct selectentry *se) { -/* Cancel select. Decrease select usage and cancel timer */ +/* Cancel select, possibly on success. Decrease select usage and cancel timer. + * This function MUST NOT block its calling thread. + */ int fd; struct filp *f; @@ -613,14 +608,14 @@ static void select_cancel_all(struct selectentry *se) *===========================================================================*/ static void select_cancel_filp(struct filp *f) { -/* Reduce number of select users of this filp */ +/* Reduce the number of select users of this filp. This function MUST NOT block + * its calling thread. + */ + dev_t major; assert(f); - assert(f->filp_selectors >= 0); - if (f->filp_selectors == 0) return; - if (f->filp_count == 0) return; - - select_lock_filp(f, f->filp_select_ops); + assert(f->filp_selectors > 0); + assert(f->filp_count > 0); f->filp_selectors--; if (f->filp_selectors == 0) { @@ -628,9 +623,18 @@ static void select_cancel_filp(struct filp *f) f->filp_select_ops = 0; f->filp_select_flags = 0; f->filp_pipe_select_ops = 0; - } - unlock_filp(f); + /* If this filp is the subject of an ongoing select query to a + * character device, mark the query as stale, so that this filp will + * not be checked when the result arrives. + */ + if (is_supported_major(f)) { + major = major(f->filp_vno->v_sdev); + if (dmap[major].dmap_sel_busy && + dmap[major].dmap_sel_filp == f) + dmap[major].dmap_sel_filp = NULL; /* leave _busy set */ + } + } } /*===========================================================================* @@ -638,6 +642,9 @@ static void select_cancel_filp(struct filp *f) *===========================================================================*/ static void select_return(struct selectentry *se) { +/* Return the results of a select call to the user process and revive the + * process. This function MUST NOT block its calling thread. + */ int r, r1; assert(!is_deferred(se)); /* Not done yet, first wait for async reply */ @@ -661,6 +668,11 @@ static void select_return(struct selectentry *se) *===========================================================================*/ void select_callback(struct filp *f, int status) { +/* The status of a filp has changed, with the given ready operations or error. + * This function is currently called only for pipes, and holds the lock to + * the filp. + */ + filp_status(f, status); } @@ -679,24 +691,27 @@ void init_select(void) /*===========================================================================* * select_forget * *===========================================================================*/ -void select_forget(endpoint_t proc_e) +void select_forget(void) { -/* Something has happened (e.g. signal delivered that interrupts select()). - * Totally forget about the select(). */ - +/* The calling thread's associated process is expected to be unpaused, due to + * a signal that is supposed to interrupt the current system call. Totally + * forget about the select(). This function may block its calling thread if + * necessary (but it doesn't). + */ int slot; struct selectentry *se; for (slot = 0; slot < MAXSELECTS; slot++) { se = &selecttab[slot]; - if (se->requestor != NULL && se->req_endpt == proc_e) + if (se->requestor == fp) break; } if (slot >= MAXSELECTS) return; /* Entry not found */ - se->error = EINTR; - if (is_deferred(se)) return; /* Still awaiting initial reply */ + assert(se->starting == FALSE); + + /* Do NOT test on is_deferred here. We can safely cancel ongoing queries. */ select_cancel_all(se); } @@ -706,6 +721,9 @@ void select_forget(endpoint_t proc_e) *===========================================================================*/ void select_timeout_check(timer_t *timer) { +/* An alarm has gone off for one of the select queries. This function MUST NOT + * block its calling thread. + */ int s; struct selectentry *se; @@ -714,7 +732,6 @@ void select_timeout_check(timer_t *timer) se = &selecttab[s]; if (se->requestor == NULL) return; - fp = se->requestor; if (se->expiry <= 0) return; /* Strange, did we even ask for a timeout? */ se->expiry = 0; if (is_deferred(se)) return; /* Wait for initial replies to DEV_SELECT */ @@ -769,8 +786,9 @@ endpoint_t driver_e; int minor; int status; { -/* Handle reply to DEV_SELECT request */ - +/* Handle the initial reply to DEV_SELECT request. This function MUST NOT + * block its calling thread. + */ int major; dev_t dev; struct filp *f; @@ -784,20 +802,25 @@ int status; dev = makedev(major, minor); /* Get filp belonging to character special file */ - if ((f = dp->dmap_sel_filp) == NULL) { + if (!dp->dmap_sel_busy) { printf("VFS (%s:%d): major %d was not expecting a DEV_SELECT reply\n", __FILE__, __LINE__, major); return; } - /* Is the filp still in use and busy waiting for a reply? The owner might - * have vanished before the driver was able to reply. */ - if (f->filp_count >= 1 && (f->filp_select_flags & FSF_BUSY)) { + /* The select filp may have been set to NULL if the requestor has been + * unpaused in the meantime. In that case, we ignore the result, but we do + * look for other filps to restart later. + */ + if ((f = dp->dmap_sel_filp) != NULL) { /* Find vnode and check we got a reply from the device we expected */ vp = f->filp_vno; assert(vp != NULL); assert(S_ISCHR(vp->v_mode)); if (vp->v_sdev != dev) { + /* This should never happen. The driver may be misbehaving. + * For now we assume that the reply we want will arrive later.. + */ printf("VFS (%s:%d): expected reply from dev %d not %d\n", __FILE__, __LINE__, vp->v_sdev, dev); return; @@ -805,13 +828,14 @@ int status; } /* No longer waiting for a reply from this device */ + dp->dmap_sel_busy = FALSE; dp->dmap_sel_filp = NULL; - /* Process select result only if requestor is still around. That is, the - * corresponding filp is still in use. - */ - if (f->filp_count >= 1) { - select_lock_filp(f, f->filp_select_ops); + /* Process the select result only if the filp is valid. */ + if (f != NULL) { + assert(f->filp_count >= 1); + assert(f->filp_select_flags & FSF_BUSY); + f->filp_select_flags &= ~FSF_BUSY; /* The select call is done now, except when @@ -845,7 +869,6 @@ int status; } } - unlock_filp(f); filp_status(f, status); /* Tell filp owners about the results */ } @@ -862,7 +885,9 @@ int minor; int status; { /* Handle secondary reply to DEV_SELECT request. A secondary reply occurs when - * the select request is 'blocking' until an operation becomes ready. */ + * the select request is 'blocking' until an operation becomes ready. This + * function MUST NOT block its calling thread. + */ int major, slot, fd; dev_t dev; struct filp *f; @@ -896,7 +921,6 @@ int status; if (!S_ISCHR(vp->v_mode)) continue; if (vp->v_sdev != dev) continue; - select_lock_filp(f, f->filp_select_ops); if (status > 0) { /* Operations ready */ /* Clear the replied bits from the request * mask unless FSF_UPDATE is set. @@ -915,7 +939,6 @@ int status; f->filp_select_flags &= ~FSF_BLOCKED; ops2tab(SEL_RD|SEL_WR|SEL_ERR, fd, se); } - unlock_filp(f); if (se->nreadyfds > 0) restart_proc(se); } } @@ -926,11 +949,14 @@ int status; /*===========================================================================* * select_restart_filps * *===========================================================================*/ -static void select_restart_filps() +static void select_restart_filps(void) { +/* We got a result from a character driver, and now we need to check if we can + * restart deferred polling operations. This function MUST NOT block its + * calling thread. + */ int fd, slot; struct filp *f; - struct vnode *vp; struct selectentry *se; /* Locate filps that can be restarted */ @@ -954,44 +980,25 @@ static void select_restart_filps() if (!(f->filp_select_flags & FSF_UPDATE)) /* Must be in */ continue; /* 'update' state */ + /* This function is suitable only for character devices. In + * particular, checking pipes the same way would introduce a + * serious locking problem. + */ + assert(is_supported_major(f)); + wantops = ops = f->filp_select_ops; - vp = f->filp_vno; - assert(S_ISCHR(vp->v_mode)); - r = do_select_request(se, fd, &wantops); - if (r != OK && r != SUSPEND) + r = select_request_major(f, &wantops, se->block); + if (r != OK && r != SUSPEND) { + se->error = r; + se->block = 0; /* Stop blocking to return asap */ + restart_proc(se); break; /* Error or bogus return code; abort */ + } if (wantops & ops) ops2tab(wantops, fd, se); } } } -/*===========================================================================* - * do_select_request * - *===========================================================================*/ -static int do_select_request(se, fd, ops) -struct selectentry *se; -int fd; -int *ops; -{ -/* Perform actual select request for file descriptor fd */ - - int r, type; - struct filp *f; - - type = se->type[fd]; - f = se->filps[fd]; - select_lock_filp(f, *ops); - r = fdtypes[type].select_request(f, ops, se->block); - unlock_filp(f); - if (r != OK && r != SUSPEND) { - se->error = EINTR; - se->block = 0; /* Stop blocking to return asap */ - if (!is_deferred(se)) select_cancel_all(se); - } - - return(r); -} - /*===========================================================================* * filp_status * *===========================================================================*/ @@ -999,7 +1006,9 @@ static void filp_status(f, status) struct filp *f; int status; { -/* Tell processes that need to know about the status of this filp */ +/* Tell processes that need to know about the status of this filp. This + * function MUST NOT block its calling thread. + */ int fd, slot; struct selectentry *se; @@ -1025,7 +1034,8 @@ static void restart_proc(se) struct selectentry *se; { /* Tell process about select results (if any) unless there are still results - * pending. */ + * pending. This function MUST NOT block its calling thread. + */ if ((se->nreadyfds > 0 || !se->block) && !is_deferred(se)) select_return(se); @@ -1055,8 +1065,10 @@ static void wipe_select(struct selectentry *se) *===========================================================================*/ static void select_lock_filp(struct filp *f, int ops) { -/* Lock a filp and vnode based on which operations are requested */ - tll_access_t locktype;; +/* Lock a filp and vnode based on which operations are requested. This function + * may block its calling thread, obviously. + */ + tll_access_t locktype; locktype = VNODE_READ; /* By default */ diff --git a/servers/vfs/stadir.c b/servers/vfs/stadir.c index 09763f41b..e02ba9b1d 100644 --- a/servers/vfs/stadir.c +++ b/servers/vfs/stadir.c @@ -19,7 +19,6 @@ #include #include #include "file.h" -#include "fproc.h" #include "path.h" #include "param.h" #include diff --git a/servers/vfs/table.c b/servers/vfs/table.c index 586c055d5..ba8b92cf1 100644 --- a/servers/vfs/table.c +++ b/servers/vfs/table.c @@ -8,7 +8,6 @@ #include #include #include "file.h" -#include "fproc.h" #include "lock.h" #include "scratchpad.h" #include "vnode.h" diff --git a/servers/vfs/threads.h b/servers/vfs/threads.h index cddb73e9a..93ca0be34 100644 --- a/servers/vfs/threads.h +++ b/servers/vfs/threads.h @@ -1,7 +1,6 @@ #ifndef __VFS_WORKERS_H__ #define __VFS_WORKERS_H__ #include -#include "job.h" #define thread_t mthread_thread_t #define mutex_t mthread_mutex_t @@ -23,12 +22,15 @@ #define cond_wait mthread_cond_wait #define cond_signal mthread_cond_signal +struct fproc; + struct worker_thread { thread_t w_tid; mutex_t w_event_mutex; cond_t w_event; - struct job w_job; struct fproc *w_fp; + message w_msg; + int w_err_code; message *w_fs_sendrec; message *w_drv_sendrec; endpoint_t w_task; diff --git a/servers/vfs/time.c b/servers/vfs/time.c index d3b42669b..4de1cd747 100644 --- a/servers/vfs/time.c +++ b/servers/vfs/time.c @@ -13,7 +13,6 @@ #include #include #include "file.h" -#include "fproc.h" #include "path.h" #include "param.h" #include "vnode.h" diff --git a/servers/vfs/utility.c b/servers/vfs/utility.c index 687b53d95..b35d2809d 100644 --- a/servers/vfs/utility.c +++ b/servers/vfs/utility.c @@ -20,7 +20,6 @@ #include #include #include "file.h" -#include "fproc.h" #include "param.h" #include "vmnt.h" diff --git a/servers/vfs/vmnt.c b/servers/vfs/vmnt.c index 00e9a7dc0..b7e3d6567 100644 --- a/servers/vfs/vmnt.c +++ b/servers/vfs/vmnt.c @@ -3,11 +3,9 @@ */ #include "fs.h" -#include "threads.h" #include "vmnt.h" #include #include -#include "fproc.h" static int is_vmnt_locked(struct vmnt *vmp); static void clear_vmnt(struct vmnt *vmp); diff --git a/servers/vfs/vnode.c b/servers/vfs/vnode.c index 022711748..438c057ba 100644 --- a/servers/vfs/vnode.c +++ b/servers/vfs/vnode.c @@ -9,10 +9,8 @@ */ #include "fs.h" -#include "threads.h" #include "vnode.h" #include "vmnt.h" -#include "fproc.h" #include "file.h" #include #include diff --git a/servers/vfs/worker.c b/servers/vfs/worker.c index 8b9f20f27..2eb74c270 100644 --- a/servers/vfs/worker.c +++ b/servers/vfs/worker.c @@ -1,18 +1,10 @@ #include "fs.h" -#include "glo.h" -#include "fproc.h" -#include "threads.h" -#include "job.h" #include -static void append_job(struct job *job, void *(*func)(void *arg)); -static void get_work(struct worker_thread *worker); +static void worker_get_work(void); static void *worker_main(void *arg); -static void worker_sleep(struct worker_thread *worker); +static void worker_sleep(void); static void worker_wake(struct worker_thread *worker); -static int worker_waiting_for(struct worker_thread *worker, endpoint_t - proc_e); -static int init = 0; static mthread_attr_t tattr; #ifdef MKCOVERAGE @@ -21,66 +13,60 @@ static mthread_attr_t tattr; # define TH_STACKSIZE (28 * 1024) #endif -#define ASSERTW(w) assert((w) == &sys_worker || (w) == &dl_worker || \ - ((w) >= &workers[0] && (w) < &workers[NR_WTHREADS])); +#define ASSERTW(w) assert((w) >= &workers[0] && (w) < &workers[NR_WTHREADS]) /*===========================================================================* * worker_init * *===========================================================================*/ -void worker_init(struct worker_thread *wp) +void worker_init(void) { /* Initialize worker thread */ - if (!init) { - threads_init(); - if (mthread_attr_init(&tattr) != 0) - panic("failed to initialize attribute"); - if (mthread_attr_setstacksize(&tattr, TH_STACKSIZE) != 0) - panic("couldn't set default thread stack size"); - if (mthread_attr_setdetachstate(&tattr, MTHREAD_CREATE_DETACHED) != 0) - panic("couldn't set default thread detach state"); - invalid_thread_id = mthread_self(); /* Assuming we're the main thread*/ - pending = 0; - init = 1; + struct worker_thread *wp; + int i; + + threads_init(); + if (mthread_attr_init(&tattr) != 0) + panic("failed to initialize attribute"); + if (mthread_attr_setstacksize(&tattr, TH_STACKSIZE) != 0) + panic("couldn't set default thread stack size"); + if (mthread_attr_setdetachstate(&tattr, MTHREAD_CREATE_DETACHED) != 0) + panic("couldn't set default thread detach state"); + pending = 0; + + for (i = 0; i < NR_WTHREADS; i++) { + wp = &workers[i]; + + wp->w_fp = NULL; /* Mark not in use */ + wp->w_next = NULL; + if (mutex_init(&wp->w_event_mutex, NULL) != 0) + panic("failed to initialize mutex"); + if (cond_init(&wp->w_event, NULL) != 0) + panic("failed to initialize conditional variable"); + if (mthread_create(&wp->w_tid, &tattr, worker_main, (void *) wp) != 0) + panic("unable to start thread"); } - ASSERTW(wp); - - wp->w_job.j_func = NULL; /* Mark not in use */ - wp->w_next = NULL; - if (mutex_init(&wp->w_event_mutex, NULL) != 0) - panic("failed to initialize mutex"); - if (cond_init(&wp->w_event, NULL) != 0) - panic("failed to initialize conditional variable"); - if (mthread_create(&wp->w_tid, &tattr, worker_main, (void *) wp) != 0) - panic("unable to start thread"); - yield(); + /* Let all threads get ready to accept work. */ + yield_all(); } /*===========================================================================* - * get_work * + * worker_get_work * *===========================================================================*/ -static void get_work(struct worker_thread *worker) +static void worker_get_work(void) { /* Find new work to do. Work can be 'queued', 'pending', or absent. In the - * latter case wait for new work to come in. */ - - struct job *new_job; + * latter case wait for new work to come in. + */ struct fproc *rfp; - ASSERTW(worker); - self = worker; - /* Do we have queued work to do? */ - if ((new_job = worker->w_job.j_next) != NULL) { - worker->w_job = *new_job; - free(new_job); - return; - } else if (worker != &sys_worker && worker != &dl_worker && pending > 0) { + if (pending > 0) { /* Find pending work */ for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { if (rfp->fp_flags & FP_PENDING) { - worker->w_job = rfp->fp_job; - rfp->fp_job.j_func = NULL; + self->w_fp = rfp; + rfp->fp_worker = self; rfp->fp_flags &= ~FP_PENDING; /* No longer pending */ pending--; assert(pending >= 0); @@ -91,11 +77,11 @@ static void get_work(struct worker_thread *worker) } /* Wait for work to come to us */ - worker_sleep(worker); + worker_sleep(); } /*===========================================================================* - * worker_available * + * worker_available * *===========================================================================*/ int worker_available(void) { @@ -103,7 +89,7 @@ int worker_available(void) busy = 0; for (i = 0; i < NR_WTHREADS; i++) { - if (workers[i].w_job.j_func != NULL) + if (workers[i].w_fp != NULL) busy++; } @@ -116,151 +102,207 @@ int worker_available(void) static void *worker_main(void *arg) { /* Worker thread main loop */ - struct worker_thread *me; - me = (struct worker_thread *) arg; - ASSERTW(me); + self = (struct worker_thread *) arg; + ASSERTW(self); while(TRUE) { - get_work(me); + worker_get_work(); - /* Register ourselves in fproc table if possible */ - if (me->w_job.j_fp != NULL) { - me->w_job.j_fp->fp_wtid = me->w_tid; + fp = self->w_fp; + assert(fp->fp_worker == self); + + /* Lock the process. */ + lock_proc(fp); + + /* The following two blocks could be run in a loop until both the + * conditions are no longer met, but it is currently impossible that + * more normal work is present after postponed PM work has been done. + */ + + /* Perform normal work, if any. */ + if (fp->fp_func != NULL) { + self->w_msg = fp->fp_msg; + err_code = OK; + + fp->fp_func(); + + fp->fp_func = NULL; /* deliberately unset AFTER the call */ } - /* Carry out work */ - me->w_job.j_func(&me->w_job); + /* Perform postponed PM work, if any. */ + if (fp->fp_flags & FP_PM_WORK) { + self->w_msg = fp->fp_pm_msg; - /* Deregister if possible */ - if (me->w_job.j_fp != NULL) { - me->w_job.j_fp->fp_wtid = invalid_thread_id; + service_pm_postponed(); + + fp->fp_flags &= ~FP_PM_WORK; } - /* Mark ourselves as done */ - me->w_job.j_func = NULL; - me->w_job.j_fp = NULL; + /* Perform cleanup actions. */ + thread_cleanup(); + + unlock_proc(fp); + + fp->fp_worker = NULL; + self->w_fp = NULL; } return(NULL); /* Unreachable */ } /*===========================================================================* - * dl_worker_start * + * worker_can_start * *===========================================================================*/ -void dl_worker_start(void *(*func)(void *arg)) +int worker_can_start(struct fproc *rfp) { -/* Start the deadlock resolving worker. This worker is reserved to run in case - * all other workers are busy and we have to have an additional worker to come - * to the rescue. */ - assert(dl_worker.w_job.j_func == NULL); +/* Return whether normal (non-PM) work can be started for the given process. + * This function is used to serialize invocation of "special" procedures, and + * not entirely safe for other cases, as explained in the comments below. + */ + int is_pending, is_active, has_normal_work, has_pm_work; - if (dl_worker.w_job.j_func == NULL) { - dl_worker.w_job.j_fp = fp; - dl_worker.w_job.j_m_in = m_in; - dl_worker.w_job.j_func = func; - worker_wake(&dl_worker); - } + is_pending = (rfp->fp_flags & FP_PENDING); + is_active = (rfp->fp_worker != NULL); + has_normal_work = (rfp->fp_func != NULL); + has_pm_work = (rfp->fp_flags & FP_PM_WORK); + + /* If there is no work scheduled for the process, we can start work. */ + if (!is_pending && !is_active) return TRUE; + + /* If there is already normal work scheduled for the process, we cannot add + * more, since we support only one normal job per process. + */ + if (has_normal_work) return FALSE; + + /* If this process has pending PM work but no normal work, we can add the + * normal work for execution before the worker will start. + */ + if (is_pending) return TRUE; + + /* However, if a worker is active for PM work, we cannot add normal work + * either, because the work will not be considered. For this reason, we can + * not use this function for processes that can possibly get postponed PM + * work. It is still safe for core system processes, though. + */ + return FALSE; } /*===========================================================================* - * sys_worker_start * + * worker_try_activate * *===========================================================================*/ -void sys_worker_start(void *(*func)(void *arg)) +static void worker_try_activate(struct fproc *rfp, int use_spare) { -/* Carry out work for the system (i.e., kernel or PM). If this thread is idle - * do it right away, else create new job and append it to the queue. */ - - if (sys_worker.w_job.j_func == NULL) { - sys_worker.w_job.j_fp = fp; - sys_worker.w_job.j_m_in = m_in; - sys_worker.w_job.j_func = func; - worker_wake(&sys_worker); - } else { - append_job(&sys_worker.w_job, func); - } -} - -/*===========================================================================* - * append_job * - *===========================================================================*/ -static void append_job(struct job *job, void *(*func)(void *arg)) -{ -/* Append a job */ - - struct job *new_job, *tail; - - /* Create new job */ - new_job = calloc(1, sizeof(struct job)); - assert(new_job != NULL); - new_job->j_fp = fp; - new_job->j_m_in = m_in; - new_job->j_func = func; - new_job->j_next = NULL; - new_job->j_err_code = OK; - - /* Append to queue */ - tail = job; - while (tail->j_next != NULL) tail = tail->j_next; - tail->j_next = new_job; -} - -/*===========================================================================* - * worker_start * - *===========================================================================*/ -void worker_start(void *(*func)(void *arg)) -{ -/* Find an available worker or wait for one */ - int i; +/* See if we can wake up a thread to do the work scheduled for the given + * process. If not, mark the process as having pending work for later. + */ + int i, available, needed; struct worker_thread *worker; - if (fp->fp_flags & FP_DROP_WORK) { - return; /* This process is not allowed to accept new work */ - } + /* Use the last available thread only if requested. Otherwise, leave at least + * one spare thread for deadlock resolution. + */ + needed = use_spare ? 1 : 2; worker = NULL; - for (i = 0; i < NR_WTHREADS; i++) { - if (workers[i].w_job.j_func == NULL) { - worker = &workers[i]; - break; + for (i = available = 0; i < NR_WTHREADS; i++) { + if (workers[i].w_fp == NULL) { + if (worker == NULL) + worker = &workers[i]; + if (++available >= needed) + break; } } - if (worker != NULL) { - worker->w_job.j_fp = fp; - worker->w_job.j_m_in = m_in; - worker->w_job.j_func = func; - worker->w_job.j_next = NULL; - worker->w_job.j_err_code = OK; + if (available >= needed) { + assert(worker != NULL); + rfp->fp_worker = worker; + worker->w_fp = rfp; worker_wake(worker); - return; - } - - /* No worker threads available, let's wait for one to finish. */ - /* If this process already has a job scheduled, forget about this new - * job; - * - the new job is do_dummy and we have already scheduled an actual job - * - the new job is an actual job and we have already scheduled do_dummy in - * order to exit this proc, so doing the new job is pointless. */ - if (fp->fp_job.j_func == NULL) { - assert(!(fp->fp_flags & FP_PENDING)); - fp->fp_job.j_fp = fp; - fp->fp_job.j_m_in = m_in; - fp->fp_job.j_func = func; - fp->fp_job.j_next = NULL; - fp->fp_job.j_err_code = OK; - fp->fp_flags |= FP_PENDING; + } else { + rfp->fp_flags |= FP_PENDING; pending++; } } +/*===========================================================================* + * worker_start * + *===========================================================================*/ +void worker_start(struct fproc *rfp, void (*func)(void), message *m_ptr, + int use_spare) +{ +/* Schedule work to be done by a worker thread. The work is bound to the given + * process. If a function pointer is given, the work is considered normal work, + * and the function will be called to handle it. If the function pointer is + * NULL, the work is considered postponed PM work, and service_pm_postponed + * will be called to handle it. The input message will be a copy of the given + * message. Optionally, the last spare (deadlock-resolving) thread may be used + * to execute the work immediately. + */ + int is_pm_work, is_pending, is_active, has_normal_work, has_pm_work; + + assert(rfp != NULL); + + is_pm_work = (func == NULL); + is_pending = (rfp->fp_flags & FP_PENDING); + is_active = (rfp->fp_worker != NULL); + has_normal_work = (rfp->fp_func != NULL); + has_pm_work = (rfp->fp_flags & FP_PM_WORK); + + /* Sanity checks. If any of these trigger, someone messed up badly! */ + if (is_pending || is_active) { + if (is_pending && is_active) + panic("work cannot be both pending and active"); + + /* The process cannot make more than one call at once. */ + if (!is_pm_work && has_normal_work) + panic("process has two calls (%x, %x)", + rfp->fp_msg.m_type, m_ptr->m_type); + + /* PM will not send more than one job per process to us at once. */ + if (is_pm_work && has_pm_work) + panic("got two calls from PM (%x, %x)", + rfp->fp_pm_msg.m_type, m_ptr->m_type); + + /* Despite PM's sys_delay_stop() system, it is possible that normal + * work (in particular, do_pending_pipe) arrives after postponed PM + * work has been scheduled for execution, so we don't check for that. + */ +#if 0 + printf("VFS: adding %s work to %s thread\n", + is_pm_work ? "PM" : "normal", + is_pending ? "pending" : "active"); +#endif + } else { + /* Some cleanup step forgotten somewhere? */ + if (has_normal_work || has_pm_work) + panic("worker administration error"); + } + + /* Save the work to be performed. */ + if (!is_pm_work) { + rfp->fp_msg = *m_ptr; + rfp->fp_func = func; + } else { + rfp->fp_pm_msg = *m_ptr; + rfp->fp_flags |= FP_PM_WORK; + } + + /* If we have not only added to existing work, go look for a free thread. + * Note that we won't be using the spare thread for normal work if there is + * already PM work pending, but that situation will never occur in practice. + */ + if (!is_pending && !is_active) + worker_try_activate(rfp, use_spare); +} + /*===========================================================================* * worker_sleep * *===========================================================================*/ -static void worker_sleep(struct worker_thread *worker) +static void worker_sleep(void) { + struct worker_thread *worker = self; ASSERTW(worker); - assert(self == worker); if (mutex_lock(&worker->w_event_mutex) != 0) panic("unable to lock event mutex"); if (cond_wait(&worker->w_event, &worker->w_event_mutex) != 0) @@ -285,16 +327,55 @@ static void worker_wake(struct worker_thread *worker) panic("unable to unlock event mutex"); } +/*===========================================================================* + * worker_suspend * + *===========================================================================*/ +struct worker_thread *worker_suspend(void) +{ +/* Suspend the current thread, saving certain thread variables. Return a + * pointer to the thread's worker structure for later resumption. + */ + + ASSERTW(self); + assert(fp != NULL); + assert(self->w_fp == fp); + assert(fp->fp_worker == self); + + self->w_err_code = err_code; + + return self; +} + +/*===========================================================================* + * worker_resume * + *===========================================================================*/ +void worker_resume(struct worker_thread *org_self) +{ +/* Resume the current thread after suspension, restoring thread variables. */ + + ASSERTW(org_self); + + self = org_self; + + fp = self->w_fp; + assert(fp != NULL); + + err_code = self->w_err_code; +} + /*===========================================================================* * worker_wait * *===========================================================================*/ void worker_wait(void) { - self->w_job.j_err_code = err_code; - worker_sleep(self); +/* Put the current thread to sleep until woken up by the main thread. */ + + (void) worker_suspend(); /* worker_sleep already saves and restores 'self' */ + + worker_sleep(); + /* We continue here after waking up */ - fp = self->w_job.j_fp; /* Restore global data */ - err_code = self->w_job.j_err_code; + worker_resume(self); assert(self->w_next == NULL); } @@ -323,7 +404,9 @@ void worker_stop(struct worker_thread *worker) panic("reply storage consistency error"); /* Oh dear */ } } else { - worker->w_job.j_m_in.m_type = EIO; + /* This shouldn't happen at all... */ + printf("VFS: stopping worker not blocked on any task?\n"); + util_stacktrace(); } worker_wake(worker); } @@ -338,12 +421,9 @@ void worker_stop_by_endpt(endpoint_t proc_e) if (proc_e == NONE) return; - if (worker_waiting_for(&sys_worker, proc_e)) worker_stop(&sys_worker); - if (worker_waiting_for(&dl_worker, proc_e)) worker_stop(&dl_worker); - for (i = 0; i < NR_WTHREADS; i++) { worker = &workers[i]; - if (worker_waiting_for(worker, proc_e)) + if (worker->w_fp != NULL && worker->w_task == proc_e) worker_stop(worker); } } @@ -354,52 +434,36 @@ void worker_stop_by_endpt(endpoint_t proc_e) struct worker_thread *worker_get(thread_t worker_tid) { int i; - struct worker_thread *worker; - worker = NULL; - if (worker_tid == sys_worker.w_tid) - worker = &sys_worker; - else if (worker_tid == dl_worker.w_tid) - worker = &dl_worker; - else { - for (i = 0; i < NR_WTHREADS; i++) { - if (workers[i].w_tid == worker_tid) { - worker = &workers[i]; - break; - } - } - } - - return(worker); -} - -/*===========================================================================* - * worker_getjob * - *===========================================================================*/ -struct job *worker_getjob(thread_t worker_tid) -{ - struct worker_thread *worker; - - if ((worker = worker_get(worker_tid)) != NULL) - return(&worker->w_job); + for (i = 0; i < NR_WTHREADS; i++) + if (workers[i].w_tid == worker_tid) + return(&workers[i]); return(NULL); } /*===========================================================================* - * worker_waiting_for * + * worker_set_proc * *===========================================================================*/ -static int worker_waiting_for(struct worker_thread *worker, endpoint_t proc_e) +void worker_set_proc(struct fproc *rfp) { - ASSERTW(worker); /* Make sure we have a valid thread */ +/* Perform an incredibly ugly action that completely violates the threading + * model: change the current working thread's process context to another + * process. The caller is expected to hold the lock to both the calling and the + * target process, and neither process is expected to continue regular + * operation when done. This code is here *only* and *strictly* for the reboot + * code, and *must not* be used for anything else. + */ - if (worker->w_job.j_func != NULL) { - if (worker->w_task != NONE) - return(worker->w_task == proc_e); - else if (worker->w_job.j_fp != NULL) { - return(worker->w_job.j_fp->fp_task == proc_e); - } - } + if (fp == rfp) return; - return(0); + if (rfp->fp_worker != NULL) + panic("worker_set_proc: target process not idle"); + + fp->fp_worker = NULL; + + fp = rfp; + + self->w_fp = rfp; + fp->fp_worker = self; } diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h index 59c1a442a..b829771a4 100644 --- a/sys/sys/ptrace.h +++ b/sys/sys/ptrace.h @@ -23,7 +23,6 @@ #define T_SETOPT 13 /* set trace options */ #define T_GETRANGE 14 /* get range of values */ #define T_SETRANGE 15 /* set range of values */ -#define T_DUMPCORE 16 /* dumps the core for the process with the given pid */ #define T_READB_INS 100 /* Read a byte from the text segment of an * untraced process (only for root) diff --git a/test/Makefile b/test/Makefile index ffeda323e..d930b3d5b 100644 --- a/test/Makefile +++ b/test/Makefile @@ -31,6 +31,8 @@ COPTS.test68.c= -O0 # Some have special libraries LDADD.test59= -lmthread +LDADD.test76= -lutil +LDADD.test77= -lutil # Some have an extra file OBJS.test57= test57loop.o @@ -53,7 +55,7 @@ MINIX_TESTS= \ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \ 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \ 41 42 43 44 45 46 48 49 50 52 53 54 55 56 58 59 60 \ -61 64 65 66 67 68 69 70 71 72 73 74 75 +61 64 65 66 67 68 69 70 71 72 73 74 75 76 77 .if ${MACHINE_ARCH} == "i386" MINIX_TESTS+= \ @@ -111,7 +113,6 @@ OBJS.${o} += common.o # LSC Make sure there is not leftover after a failed testrun clean: .PHONY .MAKE - $(MAKE) -C select clean rm -rf DIR* .include diff --git a/test/run b/test/run index ec0b821b0..9b3167513 100755 --- a/test/run +++ b/test/run @@ -19,12 +19,12 @@ badones= # list of tests that failed # Tests which require setuid setuids="test11 test33 test43 test44 test46 test56 test60 test61 test65 \ - test69" # test73" + test69 test76 test77" # test73" alltests=" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \ 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \ 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \ - 61 62 63 64 65 66 67 68 69 70 71 72 75 \ + 61 62 63 64 65 66 67 68 69 70 71 72 75 76 77 \ sh1.sh sh2.sh interp.sh" tests_no=`expr 0` diff --git a/test/select/Makefile b/test/select/Makefile deleted file mode 100644 index 5b776dec3..000000000 --- a/test/select/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -# Makefile for the tests - -CC = exec cc -CFLAGS = -Wall - -PROG = speed test00 test01 test02 test03 test04_srv test04_cli test05_srv \ - test05_cli test06_srv test06_cli test07_srv test07_cli test08_srv \ - test08_cli test09 test10 test11 test12 test13a test13b test14 - -all: $(PROG) - -$(PROG): - $(CC) $(CFLAGS) -o $@ $@.c -lutil - -clean: - rm -f *.o $(PROG) - -speed: speed.c -test00: test00.c -test01: test01.c -test02: test02.c -test03: test03.c -test04_cli: test04_cli.c -test04_srv: test04_srv.c -test05_cli: test05_cli.c -test05_srv: test05_srv.c -test06_cli: test06_cli.c -test06_srv: test06_srv.c -test07_cli: test07_cli.c -test07_srv: test07_srv.c -test08_cli: test08_cli.c -test08_srv: test08_srv.c -test09: test09.c -test10: test10.c -test11: test11.c -test12: test12.c -test13a: test13a.c -test13b: test13b.c -test14: test14.c diff --git a/test/select/speed.c b/test/select/speed.c deleted file mode 100644 index 46956b181..000000000 --- a/test/select/speed.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Test name: speed.c - * - * Objetive: Test the time it takes for select to run. - * - * Description: This tests creates a number of udp connections and performs - * a select call waiting on them for reading with timeout of 0. - * This is done 10,000 thousands of times and then the average time it takes - * is computed - * - * Jose M. Gomez - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define NUMBER 12 - -int main(int argc, char *argv[]) -{ - char *udp_device; - int fd[NUMBER]; - fd_set fds_write; - struct timeval timeout; - time_t start_time, end_time; - int i; - - FD_ZERO(&fds_write); - for (i = 0; i < NUMBER; i++) { - fd[i] = open("/dev/tty", O_RDWR); - if (fd[i] < 0) { - fprintf(stderr, "Error opening tty %d\n", i); - exit(-1); - } - FD_SET(fd[i], &fds_write); - } - - printf("Select will send 1 msg to terminal and %d to inet: \n", NUMBER); - timeout.tv_sec = 0; - timeout.tv_usec = 0; - /* get initial time */ - start_time = time(NULL); - for (i = 0; i < 32000; i++) { - select(NUMBER + 4, NULL, &fds_write, NULL, &timeout); - } - /* get final time */ - end_time = time(NULL); - printf("The select call took on average: %f\n", (float)(end_time - start_time) / 32000.0); - for (i = 0; i < NUMBER; i++) { - close(fd[i]); - } - return 0; -} diff --git a/test/select/test00.c b/test/select/test00.c deleted file mode 100644 index f25a9cd8c..000000000 --- a/test/select/test00.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Test name: test00.c - * - * Objetive: The purpose of this test is to make sure that the bitmap - * manipulation macros work without problems. - * - * Description: This tests first fills a fd_set bit by bit, and shows it, then - * it clears the fd_set bit by bit as well. - * - * Jose M. Gomez - */ - -#include -#include -#include -#include -#include -#include -#include - -int main(int argc, char *argv[]) { - fd_set fds; - int i,j; - - FD_ZERO(&fds); - for (i=0;i -#include -#include -#include -#include -#include -#include - -#define SECONDS 3 -#define USECONDS 3000000L - -int main(void) { - int r; - time_t start, end; /* variables for timing */ - struct timeval timeout; /* timeout structure */ - - /* Set timeout for 3 seconds */ - timeout.tv_sec = SECONDS; - timeout.tv_usec = 0; - printf("Sleeping now for %d seconds...\n", SECONDS); - /* Record time before starting */ - start = time(NULL); - r = select(0, NULL, NULL, NULL, &timeout); - printf("select return code: %d error: %s\n", - r, strerror(errno)); - end = time(NULL); - printf("For a timeout with select of %d seconds, it took %d actual seconds\n", - SECONDS, end-start); - - /* Set timeout for 3 seconds , but specified in microseconds */ - - timeout.tv_sec = 0; - timeout.tv_usec = USECONDS; - printf("\n***************************\n"); - printf("Sleeping now for %ld microseconds...\n", USECONDS); - /* Record time before starting */ - start = time(NULL); - r = select(0, NULL, NULL, NULL, &timeout); - printf("select return code: %d error: %s\n", - r, strerror(errno)); - end = time(NULL); - printf("For a timeout with select of %ld useconds, it took %d actual seconds\n", - USECONDS, end-start); - - /* Set timeout for 1.5 seconds, but specified in microseconds */ - - timeout.tv_sec = 0; - timeout.tv_usec = USECONDS/2; - printf("\n***************************\n"); - printf("Sleeping now for %ld microseconds...\n", USECONDS/2); - /* Record time before starting */ - start = time(NULL); - r = select(0, NULL, NULL, NULL, &timeout); - printf("select return code: %d error: %s\n", - r, strerror(errno)); - end = time(NULL); - printf("For a timeout with select of %ld useconds, it took %d actual seconds\n", - USECONDS/2, end-start); - return 0; -} diff --git a/test/select/test02.c b/test/select/test02.c deleted file mode 100644 index 338565734..000000000 --- a/test/select/test02.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Test name: test02.c - * - * Objetive: The purpose of this test is to make sure that select works - * when working with files. - * - * Description: This tests first creates six dummy files with different - * modes and performs select calls on them evaluating the input and resulting - * bitmaps. - * - * Jose M. Gomez - */ - -#include -#include -#include -#include -#include -#include -#include - -void dump_fdset(fd_set *set) { - int i; - for (i = 0; i < OPEN_MAX; i++) - if (FD_ISSET(i, set)) - printf(" %d->1 ", i); - else - printf(" %d->0 ", i); - printf("\n"); -} - -int main(int argc, char *argv[]) -{ - int fd1, fd2, fd3, fd4, fd5, fd6; /* file descriptors of files */ - fd_set fds_read, fds_write; - int retval; - - /* Creates the dummy files with different modes */ - fd1 = open("dummy1.txt", O_CREAT | O_RDONLY); - if (fd1 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd2 = open("dummy2.txt", O_CREAT | O_RDONLY); - if (fd2 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd3 = open("dummy3.txt", O_CREAT | O_WRONLY); - if (fd3 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd4 = open("dummy4.txt", O_CREAT | O_WRONLY); - if (fd4 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd5 = open("dummy5.txt", O_CREAT | O_RDWR); - if (fd5 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd6 = open("dummy6.txt", O_CREAT | O_RDWR); - if (fd6 < 0) { - perror("Error opening file"); - exit(-1); - } - - /* Create the fd_set structures */ - FD_ZERO(&fds_read); - FD_ZERO(&fds_write); - FD_SET(fd1, &fds_read); /* fd1 => O_RDONLY */ - FD_SET(fd2, &fds_read); /* fd2 => O_RDONLY */ - FD_SET(fd3, &fds_write); /* fd3 => O_WRONLY */ - FD_SET(fd4, &fds_write); /* fd4 => O_WRONLY */ - FD_SET(fd5, &fds_read); /* fd5 => O_RDWR */ - FD_SET(fd5, &fds_write); /* fd5 => O_RDWR */ - FD_SET(fd6, &fds_read); /* fd6 => O_RDWR */ - FD_SET(fd6, &fds_write); /* fd6 => O_RDWR */ - - printf("* Dump INPUT fds_read:\n"); - dump_fdset(&fds_read); - printf("* Dump INPUT fds_write:\n"); - dump_fdset(&fds_write); - - retval=select(9, &fds_read, &fds_write, NULL, NULL); - printf("\n***********************\n"); - printf("After select: \n"); - printf("Return value: %d\n", retval); - printf("* Dump RESULTING fds_read:\n"); - dump_fdset(&fds_read); - printf("* Dump RESULTING fds_write:\n"); - dump_fdset(&fds_write); - /* close and delete dummy files */ - close(fd1); - close(fd2); - close(fd3); - close(fd4); - close(fd5); - close(fd6); - unlink("dummy1.txt"); - unlink("dummy2.txt"); - unlink("dummy3.txt"); - unlink("dummy4.txt"); - unlink("dummy5.txt"); - unlink("dummy6.txt"); - return 0; -} diff --git a/test/select/test03.c b/test/select/test03.c deleted file mode 100644 index 14e2eba8d..000000000 --- a/test/select/test03.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Test name: test03.c - * - * Objetive: The purpose of this test is to make sure that select works - * when working with files. - * - * Description: This test shows more cases than in test02.c, where every - * descriptor is ready. Here in one select call only half of the fd's will - * be ready and in the next one none of them will be ready. - * - * Jose M. Gomez - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -void dump_fdset(fd_set *set) { - int i; - for (i = 0; i < OPEN_MAX; i++) - if (FD_ISSET(i, set)) - printf(" %d ", i); - printf("\n"); -} - -int main(int argc, char *argv[]) -{ - int fd1, fd2, fd3, fd4, fd5, fd6; /* file descriptors of files */ - fd_set fds_read, fds_write; /* bit maps */ - struct timeval timeout; /* timeout */ - int retval; /* ret value */ - - /* Creates the dummy files with different modes */ - fd1 = open("dummy1.txt", O_CREAT | O_RDONLY); - if (fd1 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd2 = open("dummy2.txt", O_CREAT | O_RDONLY); - if (fd2 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd3 = open("dummy3.txt", O_CREAT | O_WRONLY); - if (fd3 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd4 = open("dummy4.txt", O_CREAT | O_WRONLY); - if (fd4 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd5 = open("dummy5.txt", O_CREAT | O_RDWR); - if (fd5 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd6 = open("dummy6.txt", O_CREAT | O_RDWR); - if (fd6 < 0) { - perror("Error opening file"); - exit(-1); - } - - /* Create the fd_set structures */ - FD_ZERO(&fds_read); - FD_ZERO(&fds_write); - FD_SET(fd1, &fds_write); /* fd1 => O_RDONLY */ - FD_SET(fd2, &fds_write); /* fd2 => O_RDONLY */ - FD_SET(fd3, &fds_read); /* fd3 => O_WRONLY */ - FD_SET(fd4, &fds_read); /* fd4 => O_WRONLY */ - FD_SET(fd5, &fds_read); /* fd5 => O_RDWR */ - FD_SET(fd5, &fds_write); /* fd5 => O_RDWR */ - FD_SET(fd6, &fds_read); /* fd6 => O_RDWR */ - FD_SET(fd6, &fds_write); /* fd6 => O_RDWR */ - - printf("* Dump INPUT fds_read:\n"); - dump_fdset(&fds_read); - printf("* Dump INPUT fds_write:\n"); - dump_fdset(&fds_write); - - retval=select(9, &fds_read, &fds_write, NULL, NULL); - printf("\n***********************\n"); - printf("After select: \n"); - printf("Return value: %d\n", retval); - printf("* Dump RESULTING fds_read:\n"); - dump_fdset(&fds_read); - printf("* Dump RESULTING fds_write:\n"); - dump_fdset(&fds_write); - - /* make a select call where none of them are ready (don't use fd5 and fd6) */ - - FD_ZERO(&fds_read); - FD_ZERO(&fds_write); - FD_SET(fd1, &fds_write); /* fd1 => O_RDONLY */ - FD_SET(fd2, &fds_write); /* fd2 => O_RDONLY */ - FD_SET(fd3, &fds_read); /* fd3 => O_WRONLY */ - FD_SET(fd4, &fds_read); /* fd4 => O_WRONLY */ - - /* make a select call where none of them are ready (don't use fd5 and fd6) */ - /* create a timeout as well */ - timeout.tv_sec = 5; - timeout.tv_usec = 0; - retval=select(7, &fds_read, &fds_write, NULL, NULL); - printf("\n***********************\n"); - printf("After select: \n"); - printf("Return value: %d\n", retval); - printf("* Dump RESULTING fds_read:\n"); - dump_fdset(&fds_read); - printf("* Dump RESULTING fds_write:\n"); - dump_fdset(&fds_write); - - /* close and delete dummy files */ - close(fd1); - close(fd2); - close(fd3); - close(fd4); - close(fd5); - close(fd6); - unlink("dummy1.txt"); - unlink("dummy2.txt"); - unlink("dummy3.txt"); - unlink("dummy4.txt"); - unlink("dummy5.txt"); - unlink("dummy6.txt"); - return 0; -} diff --git a/test/select/test04_cli.c b/test/select/test04_cli.c deleted file mode 100644 index db92f930c..000000000 --- a/test/select/test04_cli.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Test name: test04_cli.c - * - * Objective: Test a simple UDP client - * - * Description: Implements a simple echo client using the UDP protocol. First - * it waits until it is possible to write (which is always). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6000L - -/* Type for received data */ -typedef struct -{ - udp_io_hdr_t header; - char data[1024]; -} udp_buffer_t; - -int udp_conf(char *host, long port, udp_io_hdr_t *header) -{ - /* configures UDP connection */ - char *udp_device; - struct hostent *hp; - int netfd; - nwio_udpopt_t udpopt; - ipaddr_t dirhost; - int result; - - /* get host address */ - if ((hp = gethostbyname(host)) == (struct hostent*) NULL) - { - fprintf(stderr,"Unknown host\n"); - return(-1); - } - memcpy((char *)&dirhost, (char *)hp->h_addr, hp->h_length); - - /* Get UDP device */ - if (( udp_device = getenv("UDP_DEVICE") ) == NULL) - udp_device = UDP_DEVICE; - - /* Get UDP connection */ - if ((netfd = open(udp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening UDP device\n"); - return -1; - } - - /* Configure UDP connection */ - udpopt.nwuo_flags = NWUO_COPY | NWUO_LP_SEL | NWUO_EN_LOC | NWUO_DI_BROAD - | NWUO_RP_SET | NWUO_RA_SET | NWUO_RWDATALL | NWUO_DI_IPOPT; - udpopt.nwuo_remaddr = dirhost; - udpopt.nwuo_remport = (udpport_t) htons(port); - - if ((result = ioctl(netfd, NWIOSUDPOPT, &udpopt) ) <0) - { - fprintf(stderr, "Error establishing communication\n"); - printf("Error: %d\n",result); - close(netfd); - return -1; - } - - /* Get configuration for UDP comm */ - if ((result = ioctl(netfd, NWIOGUDPOPT, &udpopt) ) < 0) - { - fprintf(stderr,"Error getting configuration\n"); - printf("Error: %d\n", result); - close(netfd); - return -1; - } - - header->uih_src_addr = udpopt.nwuo_locaddr; - header->uih_dst_addr = udpopt.nwuo_remaddr; - header->uih_src_port = udpopt.nwuo_locport; - header->uih_dst_port = udpopt.nwuo_remport; - - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - udp_buffer_t buffer_send, buffer_rec; - fd_set fds_write; - int ret; - - /* Check parameters */ - if (argc !=2) { - fprintf(stderr,"Usage: %s host\n", argv[0]); - exit(-1); - } - - if ((fd = udp_conf(argv[1], PORT, &buffer_send.header) ) < 0) - exit(-1); - - /* init fd_set */ - FD_ZERO(&fds_write); - FD_SET(fd, &fds_write); - - while (1) - { - /* Wait until it is possible to write with select */ - - ret = select(4, NULL, &fds_write, NULL, NULL); - if (ret < 0) { - fprintf(stderr, "Error on select waiting for write: %d\n", errno); - exit(-1); - } - if (!FD_ISSET(fd, &fds_write)) { - fprintf(stderr, "Error: The net connection is not ready for writing (?)\n"); - exit(-1); - } - - /* Get a string and send it */ - printf("Ready to write...\n"); - printf("Send data: "); - gets(buffer_send.data); - write(fd, &buffer_send, sizeof(udp_buffer_t)); - - /* If data sent is exit then break */ - if (!strcmp(buffer_send.data,"exit")) - break; - - /* Get server response */ - data_read = read(fd, &buffer_rec, sizeof(udp_buffer_t)); - printf("Received: %s\n\n", buffer_rec.data); - } - - /* Close UDP communication */ - close(fd); -} diff --git a/test/select/test04_srv.c b/test/select/test04_srv.c deleted file mode 100644 index b6fc6a5c4..000000000 --- a/test/select/test04_srv.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Test name: test04_srv.c - * - * Objective: Test a simple UDP server - * - * Description: Implements a simple echo server using the UDP protocol. Instead - * of blocking on read(), it performs a select call first blocking there - * until there is data to be read - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6000L - -/* type for received data */ -typedef struct -{ - udp_io_hdr_t header; - char data[1024]; -} udp_buffer_t; - -int udp_conf(long port) { - - char *udp_device; - int netfd; - nwio_udpopt_t udpopt; - - /* Get default UDP device */ - if ((udp_device = getenv("UDP_DEVICE")) == NULL) - udp_device = UDP_DEVICE; - - /* Open UDP connection */ - if ((netfd = open(udp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening UDP connection\n"); - return -1; - } - - /* Configure UDP connection */ - udpopt.nwuo_flags = NWUO_COPY | NWUO_LP_SET | NWUO_EN_LOC | NWUO_DI_BROAD - | NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL | NWUO_DI_IPOPT; - - udpopt.nwuo_locport = (udpport_t) htons(port); - - if ((ioctl(netfd, NWIOSUDPOPT, &udpopt))<0) - { - fprintf(stderr,"Error configuring the connection\n"); - close(netfd); - return -1; - } - - /* Get conf options */ - if ((ioctl(netfd, NWIOGUDPOPT, &udpopt))<0) - { - fprintf(stderr,"Error getting the conf\n"); - close(netfd); - return -1; - } - - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - udp_buffer_t buffer; - ipaddr_t tmp_addr; - udpport_t tmp_port; - int ret; - fd_set fds_read; - - if ((fd = udp_conf(PORT)) < 0) { - fprintf(stderr, "Error configuring UDP connection\n"); - exit(-1); - } - printf("Waiting for messages on port: %ld\n", PORT); - fflush(stdout); - /* Initialize fd_set */ - FD_ZERO(&fds_read); - FD_SET(fd, &fds_read); - - while (1) - { - /* Wait for data available to be read (no timeout) */ - ret = select(4, &fds_read, NULL, NULL, NULL); - if (ret < 0) { - fprintf(stderr, "Error on select: %d", errno); - exit(-1); - } - if (!FD_ISSET(fd, &fds_read)) { - printf("Error: network fd is not ready (?)\n"); - exit(-1); - } - printf("Ready to receive...\n"); - /* Read received data */ - data_read = read(fd, &buffer, sizeof(udp_buffer_t)); - printf("Received data: %s\n", buffer.data); - - /* Can exit if the received string == exit */ - if (!strcmp(buffer.data,"exit")) - break; - - /* Send data back, swap addresses */ - tmp_addr = buffer.header.uih_src_addr; - buffer.header.uih_src_addr = buffer.header.uih_dst_addr; - buffer.header.uih_dst_addr = tmp_addr; - - /* Swap ports */ - tmp_port = buffer.header.uih_src_port; - buffer.header.uih_src_port = buffer.header.uih_dst_port; - buffer.header.uih_dst_port = tmp_port; - - /* Write the same back */ - write(fd, &buffer, data_read); - } - - close(fd); -} diff --git a/test/select/test05_cli.c b/test/select/test05_cli.c deleted file mode 100644 index aad9bf0e6..000000000 --- a/test/select/test05_cli.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Test name: test05_cli.c - * - * Objective: Test a impatient UDP client with timeout and incoming data from - * network and terminal. - * - * Description: Implements a echo client using the UDP protocol. It is - * based on test04_cli, but the difference is that it uses timeout and waits - * for data both from terminal (stdin) and network connection. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6000L - -/* Type for received data */ -typedef struct -{ - udp_io_hdr_t header; - char data[1024]; -} udp_buffer_t; - -int udp_conf(char *host, long port, udp_io_hdr_t *header) -{ - /* configures UDP connection */ - char *udp_device; - struct hostent *hp; - int netfd; - nwio_udpopt_t udpopt; - ipaddr_t dirhost; - int result; - - /* get host address */ - if ((hp = gethostbyname(host)) == (struct hostent*) NULL) - { - fprintf(stderr,"Unknown host\n"); - return(-1); - } - memcpy((char *)&dirhost, (char *)hp->h_addr, hp->h_length); - - /* Get UDP device */ - if (( udp_device = getenv("UDP_DEVICE") ) == NULL) - udp_device = UDP_DEVICE; - - /* Get UDP connection */ - if ((netfd = open(udp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening UDP device\n"); - return -1; - } - - /* Configure UDP connection */ - udpopt.nwuo_flags = NWUO_COPY | NWUO_LP_SEL | NWUO_EN_LOC | NWUO_DI_BROAD - | NWUO_RP_SET | NWUO_RA_SET | NWUO_RWDATALL | NWUO_DI_IPOPT; - udpopt.nwuo_remaddr = dirhost; - udpopt.nwuo_remport = (udpport_t) htons(port); - - if ((result = ioctl(netfd, NWIOSUDPOPT, &udpopt) ) <0) - { - fprintf(stderr, "Error establishing communication\n"); - printf("Error: %d\n",result); - close(netfd); - return -1; - } - - /* Get configuration for UDP comm */ - if ((result = ioctl(netfd, NWIOGUDPOPT, &udpopt) ) < 0) - { - fprintf(stderr,"Error getting configuration\n"); - printf("Error: %d\n", result); - close(netfd); - return -1; - } - - header->uih_src_addr = udpopt.nwuo_locaddr; - header->uih_dst_addr = udpopt.nwuo_remaddr; - header->uih_src_port = udpopt.nwuo_locport; - header->uih_dst_port = udpopt.nwuo_remport; - - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - udp_buffer_t buffer_send, buffer_rec; - fd_set fds_read; - int ret; - struct timeval timeout; - - /* Check parameters */ - if (argc !=2) { - fprintf(stderr,"Usage: %s host\n", argv[0]); - exit(-1); - } - - if ((fd = udp_conf(argv[1], PORT, &buffer_send.header) ) < 0) - exit(-1); - - while (1) - { - - /* init fd_set */ - FD_ZERO(&fds_read); - FD_SET(0, &fds_read); - FD_SET(fd, &fds_read); - - /* set timeval */ - timeout.tv_sec = 5; - timeout.tv_usec = 0; - printf("Send data: "); - fflush(stdout); - /* Wait until it is possible to write with select */ - ret = select(4, &fds_read, NULL, NULL, &timeout); - if (ret < 0) { - fprintf(stderr, "Error on select waiting for read: %d\n", errno); - exit(-1); - } - if (ret == 0) { - printf("\nClient says: Hey! I want to send data!!\n"); - fflush(stdout); - continue; - } - /* if got message from server */ - if (FD_ISSET(fd, &fds_read)) { - data_read = read(fd, &buffer_rec, sizeof(udp_buffer_t)); - printf("Server says: %s\n\n", buffer_rec.data); - fflush(stdout); - } - /* if got data from terminal */ - if (FD_ISSET(0, &fds_read)) { - /* Get a string and send it */ - gets(buffer_send.data); - write(fd, &buffer_send, sizeof(udp_buffer_t)); - - /* If data sent is exit then break */ - if (!strcmp(buffer_send.data,"exit")) - break; - /* Get server response */ - data_read = read(fd, &buffer_rec, sizeof(udp_buffer_t)); - printf("Received: %s\n\n", buffer_rec.data); - fflush(stdout); - } - } - - /* Close UDP communication */ - close(fd); -} diff --git a/test/select/test05_srv.c b/test/select/test05_srv.c deleted file mode 100644 index a88526b28..000000000 --- a/test/select/test05_srv.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Test name: test05_srv.c - * - * Objective: Test an impatient UDP server with timeouts - * - * Description: Implements an echo server using the UDP protocol. It is - * based on test04_srv, but it has a timeout value. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6000L - -/* type for received data */ -typedef struct -{ - udp_io_hdr_t header; - char data[1024]; -} udp_buffer_t; - -int udp_conf(long port) { - - char *udp_device; - int netfd; - nwio_udpopt_t udpopt; - - /* Get default UDP device */ - if ((udp_device = getenv("UDP_DEVICE")) == NULL) - udp_device = UDP_DEVICE; - - /* Open UDP connection */ - if ((netfd = open(udp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening UDP connection\n"); - return -1; - } - - /* Configure UDP connection */ - udpopt.nwuo_flags = NWUO_COPY | NWUO_LP_SET | NWUO_EN_LOC | NWUO_DI_BROAD - | NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL | NWUO_DI_IPOPT; - - udpopt.nwuo_locport = (udpport_t) htons(port); - - if ((ioctl(netfd, NWIOSUDPOPT, &udpopt))<0) - { - fprintf(stderr,"Error configuring the connection\n"); - close(netfd); - return -1; - } - - /* Get conf options */ - if ((ioctl(netfd, NWIOGUDPOPT, &udpopt))<0) - { - fprintf(stderr,"Error getting the conf\n"); - close(netfd); - return -1; - } - - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - udp_buffer_t buffer; - ipaddr_t tmp_addr; - udpport_t tmp_port; - int ret; - fd_set fds_read; - struct timeval timeout; - ipaddr_t client_addr, this_addr; - udpport_t client_port; - - if ((fd = udp_conf(PORT)) < 0) { - fprintf(stderr, "Error configuring UDP connection\n"); - exit(-1); - } - printf("Waiting for messages on port: %ld\n", PORT); - fflush(stdout); - - /* get a first message so we know who is the client and we can harass it - afterwards */ - - /* Initialize fd_set */ - FD_ZERO(&fds_read); - FD_SET(fd, &fds_read); - /* Set timeout structure */ - timeout.tv_sec = 3; - timeout.tv_usec = 0; - ret = select(4, &fds_read, NULL, NULL, NULL); - - if (ret < 0) { - fprintf(stderr, "Error in select\n"); - exit(-1); - } - if (!FD_ISSET(fd, &fds_read)) { - fprintf(stderr, "Error: Should be receiving some data from network(?)\n"); - exit(-1); - } - printf("Ready to receive...\n"); - /* Read received data */ - data_read = read(fd, &buffer, sizeof(udp_buffer_t)); - printf("Received data: %s\n", buffer.data); - - /* Can exit if the received string == exit */ - if (!strcmp(buffer.data,"exit")) - exit(0); - - /* Send data back, swap addresses */ - tmp_addr = buffer.header.uih_src_addr; - buffer.header.uih_src_addr = buffer.header.uih_dst_addr; - buffer.header.uih_dst_addr = tmp_addr; - /* save address of both ends */ - client_addr = tmp_addr; - this_addr = buffer.header.uih_src_addr; - - /* Swap ports */ - tmp_port = buffer.header.uih_src_port; - buffer.header.uih_src_port = buffer.header.uih_dst_port; - buffer.header.uih_dst_port = tmp_port; - /* save client port */ - client_port = tmp_port; - - /* Write the same back */ - write(fd, &buffer, data_read); - - while (1) - { - - /* Initialize fd_set */ - FD_ZERO(&fds_read); - FD_SET(fd, &fds_read); - /* Set timeout structure */ - timeout.tv_sec = 3; - timeout.tv_usec = 0; - /* Wait for data available to be read (timeout) */ - ret = select(4, &fds_read, NULL, NULL, &timeout); - if (ret < 0) { - fprintf(stderr, "Error on select: %d", errno); - exit(-1); - } - /* if timeout */ - if (ret == 0) { - /* Send angry msg to client asking for more */ - printf("Tired of waiting, send client an angry message\n"); - buffer.header.uih_src_addr = this_addr; - buffer.header.uih_dst_addr = client_addr; - buffer.header.uih_src_port = PORT; - buffer.header.uih_dst_port = client_port; - strcpy(buffer.data, "Hey! I want to receive some data!\n"); - write(fd, &buffer, sizeof(udp_buffer_t)); - } - /* If receive data from network */ - if (FD_ISSET(fd, &fds_read)) { - printf("Ready to receive...\n"); - /* Read received data */ - data_read = read(fd, &buffer, sizeof(udp_buffer_t)); - printf("Received data: %s\n", buffer.data); - - /* Can exit if the received string == exit */ - if (!strcmp(buffer.data,"exit")) - break; - - /* Send data back, swap addresses */ - tmp_addr = buffer.header.uih_src_addr; - buffer.header.uih_src_addr = buffer.header.uih_dst_addr; - buffer.header.uih_dst_addr = tmp_addr; - - /* Swap ports */ - tmp_port = buffer.header.uih_src_port; - buffer.header.uih_src_port = buffer.header.uih_dst_port; - buffer.header.uih_dst_port = tmp_port; - - /* Write the same back */ - write(fd, &buffer, data_read); - } - } - close(fd); -} diff --git a/test/select/test06_cli.c b/test/select/test06_cli.c deleted file mode 100644 index 05f072337..000000000 --- a/test/select/test06_cli.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Test name: test06_cli.c - * - * Objective: Test a simple TCP client - * - * Description: Implements a simple echo client using the TCP protocol. First - * it waits until it is possible to write (which is always). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6060L - -int tcp_connect(char *host, long port) -{ - /* creates a tcp connection with specified host and port */ - char *tcp_device; - struct hostent *hp; - int netfd; - nwio_tcpcl_t tcpcopt; - nwio_tcpconf_t tcpconf; - ipaddr_t dirhost; - int tries; - int result; - - /* get host address */ - if ((hp = gethostbyname(host)) == (struct hostent*) NULL) - { - fprintf(stderr,"Unknown host\n"); - return(-1); - } - memcpy((char *)&dirhost, (char *)hp->h_addr, hp->h_length); - - /* Get default TCP device */ - if (( tcp_device = getenv("TCP_DEVICE") ) == NULL) - tcp_device = TCP_DEVICE; - - /* Establish TCP connection */ - if ((netfd = open(tcp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening TCP device\n"); - return -1; - } - - /* Configure TCP connection */ - tcpconf.nwtc_flags=NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP; - tcpconf.nwtc_remaddr = dirhost; - tcpconf.nwtc_remport = (tcpport_t) htons(port); - - if ((result = ioctl(netfd, NWIOSTCPCONF, &tcpconf) ) <0) - { - fprintf(stderr, "Error establishing communication\n"); - printf("Error: %d\n",result); - close(netfd); - return -1; - } - - /* Get configuration for TCP comm */ - if ((result = ioctl(netfd, NWIOGTCPCONF, &tcpconf) ) < 0) - { - fprintf(stderr,"Error getting configuration\n"); - printf("Error: %d\n", result); - close(netfd); - return -1; - } - - /* Establish connection */ - tcpcopt.nwtcl_flags = 0; - tries = 0; - while (tries < 10) { - if ( (result = ioctl(netfd, NWIOTCPCONN, &tcpcopt)) < 0 ) { - if (errno != EAGAIN) - { - fprintf(stderr, "Server is not listening\n"); - close(netfd); - return(-1); - } - fprintf(stderr, "Unable to connect\n"); - sleep(1); - tries++; - } - else - break; /* Connection */ - } - /* Check result value */ - if (result < 0) { - fprintf(stderr, "Error connecting\n"); - fprintf(stderr, "Error: %d\n", result); - printf("Number of tries: %d\n", tries); - printf("Error: %d\n", errno); - close(netfd); - return -1; - } - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - char send_buf[1024]; - char recv_buf[1024]; - fd_set fds_write; - int ret; - - /* Check parameters */ - if (argc !=2) { - fprintf(stderr,"Usage: %s host\n", argv[0]); - exit(-1); - } - - if ((fd = tcp_connect(argv[1], PORT) ) < 0) - exit(-1); - printf("Connected to server\n"); - /* init fd_set */ - FD_ZERO(&fds_write); - FD_SET(fd, &fds_write); - while (1) - { - /* Wait until it is possible to write with select */ - ret = select(4, NULL, &fds_write, NULL, NULL); - if (ret < 0) { - fprintf(stderr, "Error on select waiting for write: %d\n", errno); - exit(-1); - } - if (!FD_ISSET(fd, &fds_write)) { - fprintf(stderr, "Error: The net connection is not ready for writing (?)\n"); - exit(-1); - } - - /* Get a string and send it */ - printf("Ready to write...\n"); - printf("Send data: "); - gets(send_buf); - write(fd, &send_buf, strlen(send_buf)+1); - - /* If data sent is exit then break */ - if (!strcmp(send_buf,"exit")) - break; - - /* Get server response */ - data_read = read(fd, &recv_buf, 1024); - printf("Received: %s\n\n", recv_buf); - } - - /* Close TCP communication */ - close(fd); -} diff --git a/test/select/test06_srv.c b/test/select/test06_srv.c deleted file mode 100644 index 4834e555a..000000000 --- a/test/select/test06_srv.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Test name: test06_srv.c - * - * Objective: Test a simple TCP server - * - * Description: Implements a simple echo server using the TCP protocol. Instead - * of blocking on read(), it performs a select call first blocking there - * until there is data to be read - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6060L - -int my_listen(long port) { - - char *tcp_device; - int netfd; - nwio_tcpconf_t tcpconf; - nwio_tcpcl_t tcplistenopt; - - /* Get default UDP device */ - if ((tcp_device = getenv("TCP_DEVICE")) == NULL) - tcp_device = TCP_DEVICE; - - /* Open TCP connection */ - if ((netfd = open(tcp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening TCP connection\n"); - return -1; - } - - /* Configure TCP connection */ - tcpconf.nwtc_flags = NWTC_LP_SET | NWTC_UNSET_RA | NWTC_UNSET_RP; - tcpconf.nwtc_locport = (tcpport_t) htons(port); - - if ((ioctl(netfd, NWIOSTCPCONF, &tcpconf))<0) - { - fprintf(stderr,"Error configuring the connection\n"); - close(netfd); - return -1; - } - - /* Get communication options */ - if ((ioctl(netfd, NWIOGTCPCONF, &tcpconf)) < 0) { - fprintf(stderr, "Error getting configuration\n"); - close(netfd); - return -1; - } - - /* Set conf options */ - tcplistenopt.nwtcl_flags = 0; - printf("Waiting for connections...\n"); - while ((ioctl(netfd, NWIOTCPLISTEN, &tcplistenopt)) == -1) - { - if (errno != EAGAIN) - { - fprintf(stderr,"Unable to listen for connections\n"); - close(netfd); - } - sleep(-1); - } - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - char buffer[1024]; - int ret; - fd_set fds_read; - - if ((fd = my_listen(PORT)) < 0) { - exit(-1); - } - printf("Waiting for messages on port: %ld\n", PORT); - fflush(stdout); - /* Initialize fd_set */ - FD_ZERO(&fds_read); - FD_SET(fd, &fds_read); - - while (1) - { - /* Wait for data available to be read (no timeout) */ - - ret = select(4, &fds_read, NULL, NULL, NULL); - if (ret < 0) { - fprintf(stderr, "Error on select: %d\n", errno); - exit(-1); - } - if (!FD_ISSET(fd, &fds_read)) { - printf("Error: network fd is not ready (?)\n"); - exit(-1); - } - - printf("Ready to receive...\n"); - /* Read received data */ - data_read = read(fd, &buffer, 1024); - printf("Received data: %s\n", buffer); - - /* Can exit if the received string == exit */ - if (!strcmp(buffer,"exit")) - break; - - /* Write the same back */ - write(fd, &buffer, data_read); - } - printf("Connection finished\n"); - close(fd); -} diff --git a/test/select/test07_cli.c b/test/select/test07_cli.c deleted file mode 100644 index 8bc21010a..000000000 --- a/test/select/test07_cli.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Test name: test07_cli.c - * - * Objective: Test an impatient TCP client with timeout which waits input both - * from the terminal and from the network connection. - * - * Description: Implements a echo client using the TCP protocol with a timeout - * value. It waites for data on both the terminal and the network connection and - * prints an angry message asking for more data if there is a timeout. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6060L - -int tcp_connect(char *host, long port) -{ - /* creates a tcp connection with specified host and port */ - char *tcp_device; - struct hostent *hp; - int netfd; - nwio_tcpcl_t tcpcopt; - nwio_tcpconf_t tcpconf; - ipaddr_t dirhost; - int tries; - int result; - - /* get host address */ - if ((hp = gethostbyname(host)) == (struct hostent*) NULL) - { - fprintf(stderr,"Unknown host\n"); - return(-1); - } - memcpy((char *)&dirhost, (char *)hp->h_addr, hp->h_length); - - /* Get default TCP device */ - if (( tcp_device = getenv("TCP_DEVICE") ) == NULL) - tcp_device = TCP_DEVICE; - - /* Establish TCP connection */ - if ((netfd = open(tcp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening TCP device\n"); - return -1; - } - - /* Configure TCP connection */ - tcpconf.nwtc_flags=NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP; - tcpconf.nwtc_remaddr = dirhost; - tcpconf.nwtc_remport = (tcpport_t) htons(port); - - if ((result = ioctl(netfd, NWIOSTCPCONF, &tcpconf) ) <0) - { - fprintf(stderr, "Error establishing communication\n"); - printf("Error: %d\n",result); - close(netfd); - return -1; - } - - /* Get configuration for TCP comm */ - if ((result = ioctl(netfd, NWIOGTCPCONF, &tcpconf) ) < 0) - { - fprintf(stderr,"Error getting configuration\n"); - printf("Error: %d\n", result); - close(netfd); - return -1; - } - - /* Establish connection */ - tcpcopt.nwtcl_flags = 0; - tries = 0; - while (tries < 10) { - if ( (result = ioctl(netfd, NWIOTCPCONN, &tcpcopt)) < 0 ) { - if (errno != EAGAIN) - { - fprintf(stderr, "Server is not listening\n"); - close(netfd); - return(-1); - } - fprintf(stderr, "Unable to connect\n"); - sleep(1); - tries++; - } - else - break; /* Connection */ - } - /* Check result value */ - if (result < 0) { - fprintf(stderr, "Error connecting\n"); - fprintf(stderr, "Error: %d\n", result); - printf("Number of tries: %d\n", tries); - printf("Error: %d\n", errno); - close(netfd); - return -1; - } - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - char send_buf[1024]; - char recv_buf[1024]; - fd_set fds_read; - int ret; - struct timeval timeout; - - /* Check parameters */ - if (argc !=2) { - fprintf(stderr,"Usage: %s host\n", argv[0]); - exit(-1); - } - - if ((fd = tcp_connect(argv[1], PORT) ) < 0) - exit(-1); - printf("Connected to server\n"); - - while (1) - { - - /* init fd_set */ - FD_ZERO(&fds_read); - FD_SET(0, &fds_read); /* stdin */ - FD_SET(fd, &fds_read); - /* set timeout */ - timeout.tv_sec = 3; - timeout.tv_usec = 0; - - printf("Send data: "); - fflush(stdout); - /* Wait until it is possible to read with select */ - ret = select(4, &fds_read, NULL, NULL, &timeout); - if (ret < 0) { - fprintf(stderr, "Error on select waiting for write: %d\n", errno); - exit(-1); - } - /* timeout */ - if (ret == 0) { - printf("\nClient says: Hey! I want to send some data!!\n"); - continue; - } - /* handle data from network */ - if (FD_ISSET(fd, &fds_read)) { - data_read = read(fd, &recv_buf, 1024); - printf("Server says: %s\n\n", recv_buf); - } - /* handle data from terminal */ - if (FD_ISSET(0, &fds_read)) { - /* Get a string and send it */ - gets(send_buf); - write(fd, &send_buf, strlen(send_buf)+1); - - /* If data sent is exit then break */ - if (!strcmp(send_buf,"exit")) - break; - - /* Get server response */ - data_read = read(fd, &recv_buf, 1024); - printf("Received: %s\n\n", recv_buf); - } - } - - /* Close TCP communication */ - close(fd); -} diff --git a/test/select/test07_srv.c b/test/select/test07_srv.c deleted file mode 100644 index b0cffba36..000000000 --- a/test/select/test07_srv.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Test name: test07_srv.c - * - * Objective: Test an impatient TCP server with a timeout. - * - * Description: Implements an echo server using the TCP protocol. It is - * based on test06_srv.c but has a timeout for receiving data from a client - * and if the time is up it sends an angry message to the client requesting - * for more information. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6060L - -int my_listen(long port) { - - char *tcp_device; - int netfd; - nwio_tcpconf_t tcpconf; - nwio_tcpcl_t tcplistenopt; - - /* Get default UDP device */ - if ((tcp_device = getenv("TCP_DEVICE")) == NULL) - tcp_device = TCP_DEVICE; - - /* Open TCP connection */ - if ((netfd = open(tcp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening TCP connection\n"); - return -1; - } - - /* Configure TCP connection */ - tcpconf.nwtc_flags = NWTC_LP_SET | NWTC_UNSET_RA | NWTC_UNSET_RP; - tcpconf.nwtc_locport = (tcpport_t) htons(port); - - if ((ioctl(netfd, NWIOSTCPCONF, &tcpconf))<0) - { - fprintf(stderr,"Error configuring the connection\n"); - close(netfd); - return -1; - } - - /* Get communication options */ - if ((ioctl(netfd, NWIOGTCPCONF, &tcpconf)) < 0) { - fprintf(stderr, "Error getting configuration\n"); - close(netfd); - return -1; - } - - /* Set conf options */ - tcplistenopt.nwtcl_flags = 0; - printf("Waiting for connections...\n"); - while ((ioctl(netfd, NWIOTCPLISTEN, &tcplistenopt)) == -1) - { - if (errno != EAGAIN) - { - fprintf(stderr,"Unable to listen for connections\n"); - close(netfd); - } - sleep(-1); - } - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - char buffer[1024]; - int ret; - fd_set fds_read; - struct timeval timeout; - - if ((fd = my_listen(PORT)) < 0) { - exit(-1); - } - printf("Waiting for messages on port: %ld\n", PORT); - fflush(stdout); - while (1) - { - - /* Initialize fd_set */ - FD_ZERO(&fds_read); - FD_SET(fd, &fds_read); - /* set timeout */ - timeout.tv_sec = 3; - timeout.tv_usec = 0; - /* Wait for data available to be read (no timeout) */ - ret = select(4, &fds_read, NULL, NULL, &timeout); - if (ret < 0) { - fprintf(stderr, "Error on select: %d\n", errno); - exit(-1); - } - /* timeout */ - if (ret == 0) { - strcpy(buffer, "I want to get some data!!\n"); - write(fd, &buffer, 1024); - continue; - } - - /* data received from client */ - if (FD_ISSET(fd, &fds_read)) { - printf("Ready to receive...\n"); - /* Read received data */ - data_read = read(fd, &buffer, 1024); - printf("Received data: %s\n", buffer); - - /* Can exit if the received string == exit */ - if (!strcmp(buffer,"exit")) - break; - - /* Write the same back */ - write(fd, &buffer, data_read); - } - } - printf("Connection finished\n"); - close(fd); -} diff --git a/test/select/test08_cli.c b/test/select/test08_cli.c deleted file mode 100644 index 20a8cedf1..000000000 --- a/test/select/test08_cli.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Test name: test08_cli.c - * - * Objective: Test select on urgent data. TCP client. - * - * Description: It is based on test06_cli but sends urgent data. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6060L - -int tcp_connect(char *host, long port) -{ - /* creates a tcp connection with specified host and port */ - char *tcp_device; - struct hostent *hp; - int netfd; - nwio_tcpcl_t tcpcl; - nwio_tcpopt_t tcpopt; - nwio_tcpconf_t tcpconf; - ipaddr_t dirhost; - int tries; - int result; - - /* get host address */ - if ((hp = gethostbyname(host)) == (struct hostent*) NULL) - { - fprintf(stderr,"Unknown host\n"); - return(-1); - } - memcpy((char *)&dirhost, (char *)hp->h_addr, hp->h_length); - - /* Get default TCP device */ - if (( tcp_device = getenv("TCP_DEVICE") ) == NULL) - tcp_device = TCP_DEVICE; - - /* Establish TCP connection */ - if ((netfd = open(tcp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening TCP device\n"); - return -1; - } - - /* Configure TCP connection */ - tcpconf.nwtc_flags=NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP; - tcpconf.nwtc_remaddr = dirhost; - tcpconf.nwtc_remport = (tcpport_t) htons(port); - - if ((result = ioctl(netfd, NWIOSTCPCONF, &tcpconf) ) <0) - { - fprintf(stderr, "Error establishing communication\n"); - printf("Error: %d\n",result); - close(netfd); - return -1; - } - - /* Get configuration for TCP comm */ - if ((result = ioctl(netfd, NWIOGTCPCONF, &tcpconf) ) < 0) - { - fprintf(stderr,"Error getting configuration\n"); - printf("Error: %d\n", result); - close(netfd); - return -1; - } - - /* Establish connection options (send URG data) */ - tcpopt.nwto_flags = NWTO_SND_URG_MASK; - - /* Set options for TCP comm */ - if ((result = ioctl(netfd, NWIOSTCPOPT, &tcpopt) ) < 0) - { - fprintf(stderr,"Error getting configuration\n"); - printf("Error: %d\n", result); - close(netfd); - return -1; - } - - /* Get configuration for TCP comm */ - if ((result = ioctl(netfd, NWIOGTCPOPT, &tcpopt) ) < 0) - { - fprintf(stderr,"Error getting options\n"); - printf("Error: %d\n", result); - close(netfd); - return -1; - } - - tcpcl.nwtcl_flags = 0; - tries = 0; - while (tries < 10) { - if ( (result = ioctl(netfd, NWIOTCPCONN, &tcpcl)) < 0 ) { - if (errno != EAGAIN) - { - fprintf(stderr, "Server is not listening\n"); - close(netfd); - return(-1); - } - fprintf(stderr, "Unable to connect\n"); - sleep(1); - tries++; - } - else - break; /* Connection */ - } - /* Check result value */ - if (result < 0) { - fprintf(stderr, "Error connecting\n"); - fprintf(stderr, "Error: %d\n", result); - printf("Number of tries: %d\n", tries); - printf("Error: %d\n", errno); - close(netfd); - return -1; - } - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - char send_buf[1024]; - char recv_buf[1024]; - fd_set fds_write; - int ret; - - /* Check parameters */ - if (argc !=2) { - fprintf(stderr,"Usage: %s host\n", argv[0]); - exit(-1); - } - - if ((fd = tcp_connect(argv[1], PORT) ) < 0) - exit(-1); - printf("Connected to server\n"); - /* init fd_set */ - FD_ZERO(&fds_write); - FD_SET(fd, &fds_write); - while (1) - { - /* Wait until it is possible to write with select */ - ret = select(4, NULL, &fds_write, NULL, NULL); - if (ret < 0) { - fprintf(stderr, "Error on select waiting for write: %d\n", errno); - exit(-1); - } - if (!FD_ISSET(fd, &fds_write)) { - fprintf(stderr, "Error: The net connection is not ready for writing (?)\n"); - exit(-1); - } - - /* Get a string and send it */ - printf("Ready to write...\n"); - printf("Send data: "); - gets(send_buf); - write(fd, &send_buf, strlen(send_buf)+1); - - /* If data sent is exit then break */ - if (!strcmp(send_buf,"exit")) - break; - - /* Get server response */ - data_read = read(fd, &recv_buf, 1024); - printf("Received: %s\n\n", recv_buf); - } - - /* Close UDP communication */ - close(fd); -} diff --git a/test/select/test08_srv.c b/test/select/test08_srv.c deleted file mode 100644 index fa4f6f8fb..000000000 --- a/test/select/test08_srv.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Test name: test08_srv.c - * - * Objective: Test a simple TCP server waiting for urgent data. - * - * Description: Implements a echo TCP server as in test06_srv but waits - * for urgent data, using select on exception. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6060L - -int my_listen(long port) { - - char *tcp_device; - int netfd; - nwio_tcpconf_t tcpconf; - nwio_tcpcl_t tcpcl; - nwio_tcpopt_t tcpopt; - - /* Get default UDP device */ - if ((tcp_device = getenv("TCP_DEVICE")) == NULL) - tcp_device = TCP_DEVICE; - - /* Open TCP connection */ - if ((netfd = open(tcp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening TCP connection\n"); - return -1; - } - - /* Configure TCP connection */ - tcpconf.nwtc_flags = NWTC_LP_SET | NWTC_UNSET_RA | NWTC_UNSET_RP; - tcpconf.nwtc_locport = (tcpport_t) htons(port); - - if ((ioctl(netfd, NWIOSTCPCONF, &tcpconf))<0) - { - fprintf(stderr,"Error configuring the connection\n"); - close(netfd); - return -1; - } - - /* Get communication conf*/ - if ((ioctl(netfd, NWIOGTCPCONF, &tcpconf)) < 0) { - fprintf(stderr, "Error getting configuration\n"); - close(netfd); - return -1; - } - - /* Set comm options */ - tcpopt.nwto_flags = NWTO_RCV_URG; - - if ((ioctl(netfd, NWIOSTCPOPT, &tcpopt))<0) - { - fprintf(stderr,"Error configuring the connection\n"); - close(netfd); - return -1; - } - - /* Get communication opt*/ - if ((ioctl(netfd, NWIOGTCPOPT, &tcpopt)) < 0) { - fprintf(stderr, "Error getting options\n"); - close(netfd); - return -1; - } - - /* Set conn options */ - tcpcl.nwtcl_flags = 0; - printf("Waiting for connections...\n"); - while ((ioctl(netfd, NWIOTCPLISTEN, &tcpcl)) == -1) - { - if (errno != EAGAIN) - { - fprintf(stderr,"Unable to listen for connections\n"); - close(netfd); - } - sleep(-1); - } - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - char buffer[1024]; - int ret; - fd_set fds_excep; - - if ((fd = my_listen(PORT)) < 0) { - exit(-1); - } - printf("Waiting for messages on port: %ld\n", PORT); - fflush(stdout); - /* Initialize fd_set */ - FD_ZERO(&fds_excep); - FD_SET(fd, &fds_excep); - - while (1) - { - /* Wait for data available to be read (no timeout) */ - - ret = select(4, NULL, NULL, &fds_excep, NULL); - if (ret < 0) { - fprintf(stderr, "Error on select: %d\n", errno); - exit(-1); - } - if (!FD_ISSET(fd, &fds_excep)) { - printf("Error: no URG data received (?)\n"); - exit(-1); - } - - printf("Ready to receive...\n"); - /* Read received data */ - data_read = read(fd, &buffer, 1024); - printf("Received data: %s\n", buffer); - - /* Can exit if the received string == exit */ - if (!strcmp(buffer,"exit")) - break; - - /* Write the same back */ - write(fd, &buffer, data_read); - } - printf("Connection finished\n"); - close(fd); -} diff --git a/test/select/test09.c b/test/select/test09.c deleted file mode 100644 index 3fc9ecf4c..000000000 --- a/test/select/test09.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Test name: test09.c - * - * Objetive: The purpose of this test is to make sure that select works - * when working with the terminal. - * - * Description: This tests wait entry from stdin using select and displays - * it again in stdout when it is ready to write (which is always) - * - * Jose M. Gomez - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -void main(void) { - fd_set fds_read, fds_write; - int retval; - char data[1024]; - - FD_ZERO(&fds_read); - FD_ZERO(&fds_write); - FD_SET(0, &fds_read); /* stdin */ - FD_SET(1, &fds_write); /* stdout */ - - while(1) { - printf("Input some data: "); - fflush(stdout); - retval=select(3, &fds_read, NULL, NULL, NULL); - if (retval < 0) { - fprintf(stderr, "Error while executing select\n"); - exit(-1); - } - printf("select retval: %d\n", retval); - if (!FD_ISSET(0, &fds_read)) { - fprintf(stderr, "Error: stdin not ready (?)\n"); - exit(-1); - } - printf("gets..\n"); - gets(data); - printf("gets done..\n"); - if (!strcmp(data, "exit")) - exit(0); - printf("Try to write it back\n"); - retval=select(3, NULL, &fds_write, NULL, NULL); - if (retval < 0) { - fprintf(stderr, "Error while executing select\n"); - exit(-1); - } - if (!FD_ISSET(1, &fds_write)) { - fprintf(stderr, "Error: stdout not ready (?)\n"); - exit(-1); - } - printf("Data: %s\n", data); - } -} diff --git a/test/select/test10.c b/test/select/test10.c deleted file mode 100644 index 6f68c8490..000000000 --- a/test/select/test10.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Test name: test10.c - * - * Objetive: The purpose of this test is to make sure that select works - * when working with the terminal with timeouts - * - * Description: This tests wait entry from stdin using select and displays - * it again in stdout when it is ready to write (which is always). It has - * a timeout value as well. - * - * Jose M. Gomez - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int main(int argc, char *argv[]) -{ - fd_set fds_read, fds_write; - int retval; - char data[1024]; - struct timeval timeout; - - while(1) { - timeout.tv_sec = 3; - timeout.tv_usec = 0; - FD_ZERO(&fds_read); - FD_ZERO(&fds_write); - FD_SET(0, &fds_read); - FD_SET(1, &fds_write); - printf("Input some data: "); - fflush(stdout); - retval=select(3, &fds_read, NULL, NULL, &timeout); - if (retval < 0) { - fprintf(stderr, "Error while executing select\n"); - exit(-1); - } - if (retval == 0) { - printf("\n Hey! Feed me some data!\n"); - fflush(stdout); - continue; - } - if (!FD_ISSET(0, &fds_read)) { - fprintf(stderr, "Error: stdin not ready (?)\n"); - exit(-1); - } - gets(data); - if (!strcmp(data, "exit")) - exit(0); - printf("Try to write it back\n"); - retval=select(3, NULL, &fds_write, NULL, NULL); - if (retval < 0) { - fprintf(stderr, "Error while executing select\n"); - exit(-1); - } - if (!FD_ISSET(1, &fds_write)) { - fprintf(stderr, "Error: stdout not ready (?)\n"); - exit(-1); - } - printf("Data: %s\n", data); - } - return 1; -} diff --git a/test/select/test11.c b/test/select/test11.c deleted file mode 100644 index 99c8381b8..000000000 --- a/test/select/test11.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Test name: test11.c - * - * Objetive: The purpose of this test is to make sure that select works - * with pipes. - * - * Description: The select checks are divided in checks on writing for the - * parent process, which has the writing end of the pipe, and checks on reading - * and exception on the child process, which has the reading end of pipe. So - * when the first process is ready to write to the pipe it will request a string - * from the terminal and send it through the pipe. If the string is 'exit' then - * the pipe is closed. The child process is blocked in a select checking for read - * and exception. If there is data to be read then it will perform the read and - * prints the read data. If the pipe is closed (user typed 'exit'), the child - * process finishes. - * - * Jose M. Gomez - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void pipehandler(int sig) -{ - -} - -void do_child(int data_pipe[]) -{ - /* reads from pipe and prints out the data */ - char data[2048]; - int retval; - fd_set fds_read; - fd_set fds_exception; - struct timeval timeout; - - signal(SIGPIPE, pipehandler); - signal(SIGUSR1, pipehandler); - - /* first, close the write part of the pipe, since it is not needed */ - close(data_pipe[1]); - - while(1) { - FD_ZERO(&fds_read); - FD_ZERO(&fds_exception); - FD_SET(data_pipe[0], &fds_read); - FD_SET(data_pipe[0], &fds_exception); - timeout.tv_sec = 5; - timeout.tv_usec = 0; - retval = select(data_pipe[0]+1, &fds_read, NULL, &fds_exception, &timeout); - if (retval == -1) { - perror("select"); - fprintf(stderr, "child: Error in select\n"); - continue; - } else printf("child select: %d\n", retval); - if (FD_ISSET(data_pipe[0], &fds_exception)) { - printf("child: exception fd set. quitting.\n"); - break; - } - if (FD_ISSET(data_pipe[0], &fds_read)) { - printf("child: read fd set. reading.\n"); - if ((retval = read(data_pipe[0], data, sizeof(data))) < 0) { - perror("read"); - fprintf(stderr, "child: couldn't read from pipe\n"); - exit(-1); - } - if(retval == 0) { - fprintf(stderr, "child: eof on pipe\n"); - break; - } - data[retval] = '\0'; - printf("pid %d Pipe reads (%d): %s\n", getpid(), retval, data); - } else printf("child: no fd set\n"); - } - - /* probably pipe was broken, or got EOF via the pipe. */ - exit(0); -} - -void do_parent(int data_pipe[]) -{ - char data[1024]; - int retval; - fd_set fds_write; - - signal(SIGPIPE, pipehandler); - signal(SIGUSR1, pipehandler); - - /* first, close the read part of pipe, since it is not needed */ - close(data_pipe[0]); - - /* now enter a loop of read user input, and writing it to the pipe */ - while (1) { - FD_ZERO(&fds_write); - FD_SET(data_pipe[1], &fds_write); - printf("pid %d Waiting for pipe ready to write...\n", getpid()); - retval = select(data_pipe[1]+1, NULL, &fds_write, NULL, NULL); - if (retval == -1) { - perror("select"); - fprintf(stderr, "Parent: Error in select\n"); - exit(-1); - } - - printf("Input data: "); - if(!gets(data)) { - printf("parent: eof; exiting\n"); - break; - } - if (!strcmp(data, "exit")) - break; - if (!FD_ISSET(data_pipe[1], &fds_write)) { - fprintf(stderr, "parent: write fd not set?! retrying\n"); - continue; - } - retval = write(data_pipe[1], &data, 1024); - if (retval == -1) { - perror("write"); - fprintf(stderr, "Error writing on pipe\n"); - exit(-1); - } - } - - /* got exit from user */ - close(data_pipe[1]); /* close pipe, let child know we're done */ - wait(&retval); - printf("Child exited with status: %d\n", retval); - exit(0); -} - -int main(int argc, char *argv[]) -{ - int pipes[2]; - int retval; - int pid; - - /* create the pipe */ - retval = pipe(pipes); - if (retval == -1) { - perror("pipe"); - fprintf(stderr, "Error creating the pipe\n"); - exit(-1); - } - pid = fork(); - if (pid == -1) { - fprintf(stderr, "Error forking\n"); - exit(-1); - } - - if (pid == 0) /* child proc */ - do_child(pipes); - else - do_parent(pipes); - return 0; -} diff --git a/test/select/test12.c b/test/select/test12.c deleted file mode 100644 index f69d876da..000000000 --- a/test/select/test12.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Test name: test12.c - * - * Objective: The purpose of this check the behaviour when a signal is received - * and there is a handler. - * - * Description: The program handles SIGHUP and expects the user to actually send - * the signal from other terminal with 'kill -1 pid' - - * Jose M. Gomez - */ - -#include -#include -#include -#include -#include -#include -#include - -#define SECONDS 15 - -void catch_hup(int sig_num) -{ - /* don't need to reset signal handler */ - printf("Received a SIGHUP, inside the handler now\n"); -} - -int main(void) { - int ret; /* return value */ - - /* set the HUP sginal handler to 'catch_hup' */ - signal(SIGHUP, catch_hup); - /* Get proc_id and print it */ - printf("Send a signal from other terminal with: kill -1 %d\n", getpid()); - printf("Blocking now on select...\n", SECONDS); - ret = select(0, NULL, NULL, NULL, NULL); - printf("Errno: %d\n", errno); -} diff --git a/test/select/test13a.c b/test/select/test13a.c deleted file mode 100644 index 9b76bd801..000000000 --- a/test/select/test13a.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Test name: test13a.c - * - * Objective: The purpose of this tests is to show how a select can - * get into a race condition when dealing with signals. - * - * Description: The program waits for SIGHUP or input in the terminal - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -int got_sighup = 0; - -void catch_hup(int sig_num) -{ - printf("Received a SIGHUP, set global vble \n"); - got_sighup = 1; -} - -int main(void) { - int ret; /* return value */ - fd_set read_fds; - char data[1024]; - - /* Init read fd_set */ - FD_ZERO(&read_fds); - FD_SET(0, &read_fds); - - /* set the HUP signal handler to 'catch_hup' */ - signal(SIGHUP, catch_hup); - - /* Get proc_id and print it */ - printf("Send a signal from other terminal with: kill -1 %d\n", getpid()); - printf("Going to sleep for 5 seconds, if the signal arrives meanwhile\n"); - printf("the process will be blocked until there is input in the keyboard\n"); - printf("if the signal arrives after the timeout and while in select, it will\n"); - printf("behave as it should.\n"); - printf("Sleeping for 5 secs\n"); - sleep(5); - - printf("Blocking now on select...\n"); - ret = select(1, &read_fds, NULL, NULL, NULL); - if (got_sighup) { - printf("We have a sighup signal so exit the program\n"); - exit(0); - } - gets(data); - printf("Got entry for terminal then, bye\n"); -} diff --git a/test/select/test13b.c b/test/select/test13b.c deleted file mode 100644 index 8d14a0523..000000000 --- a/test/select/test13b.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Test name: test13b.c - * - * Objective: The purpose of this tests is to show how pselect() - * solves the situation shown in test13a.c - * - * Description: The program waits for SIGHUP or input in the terminal - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -int got_sighup = 0; - -void catch_hup(int sig_num) -{ - printf("Received a SIGHUP, set global vble \n"); - got_sighup = 1; -} - -int main(void) { - int ret; /* return value */ - fd_set read_fds; - sigset_t sigmask, orig_sigmask; - char data[1024]; - - /* Init read fd_set */ - FD_ZERO(&read_fds); - FD_SET(0, &read_fds); - - /* set the signal masks */ - sigemptyset(&sigmask); - sigaddset(&sigmask, SIGHUP); - sigprocmask( SIG_BLOCK, &sigmask, &orig_sigmask); - - /* set the HUP signal handler to 'catch_hup' */ - signal(SIGHUP, catch_hup); - - /* Get proc_id and print it */ - printf("Send a signal from other terminal with: kill -1 %d\n", getpid()); - printf("Going to sleep for 5 seconds, if the signal arrives meanwhile\n"); - printf("the process will be blocked until there is input in the keyboard\n"); - printf("if the signal arrives after the timeout and while in select, it will\n"); - printf("behave as it should.\n"); - printf("Sleeping for 5 secs\n"); - sleep(5); - - printf("Blocking now on select...\n"); -#if 0 - ret = pselect(1, &read_fds, NULL, NULL, NULL, &orig_sigmask); -#else - ret = -1; -#endif - if (got_sighup) { - printf("We have a sighup signal so exit the program\n"); - exit(0); - } - gets(data); - printf("Got entry for terminal then, bye\n"); - -} diff --git a/test/select/test14.c b/test/select/test14.c deleted file mode 100644 index 99cc009a3..000000000 --- a/test/select/test14.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Test name: test14.c - * - * Objetive: The purpose of this test is to make sure that select works - * with ptys. - * - * Adapted from test11.c (pipe test). - * - * Ben Gras - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -char name[100]; -void pipehandler(int sig) -{ -} -#define CHILDFD 1 -#define PARENTFD 0 -void do_child(int pty_fds[]) -{ - /* reads from pipe and prints out the data */ - char data[2048]; - int retval; - fd_set fds_read; - fd_set fds_exception; - struct timeval timeout; - signal(SIGPIPE, pipehandler); - signal(SIGUSR1, pipehandler); - /* first, close the write part, since it is not needed */ - close(pty_fds[PARENTFD]); - - while(1) { - FD_ZERO(&fds_read); - FD_ZERO(&fds_exception); - FD_SET(pty_fds[CHILDFD], &fds_read); - FD_SET(pty_fds[CHILDFD], &fds_exception); - timeout.tv_sec = 5; - timeout.tv_usec = 0; - retval = select(pty_fds[CHILDFD]+2, &fds_read, NULL, &fds_exception, &timeout); - if (retval == -1) { - perror("select"); - fprintf(stderr, "child: Error in select\n"); - continue; - } else printf("child select: %d\n", retval); - if (FD_ISSET(pty_fds[CHILDFD], &fds_exception)) { - printf("child: exception fd set. quitting.\n"); - break; - } - if (FD_ISSET(pty_fds[CHILDFD], &fds_read)) { - printf("child: read fd set. reading.\n"); - if ((retval = read(pty_fds[CHILDFD], data, sizeof(data))) < 0) { - perror("read"); - fprintf(stderr, "child: couldn't read from pty\n"); - exit(-1); - } - if(retval == 0) { - fprintf(stderr, "child: eof on pty\n"); - break; - } - data[retval] = '\0'; - printf("pid %d pty reads (%d): %s\n", getpid(), retval, data); - } else printf("child: no fd set\n"); - } - - exit(0); -} -void do_parent(int pty_fds[]) -{ - char data[1024]; - int retval; - fd_set fds_write; - signal(SIGPIPE, pipehandler); - signal(SIGUSR1, pipehandler); - /* first, close the read part of pty, since it is not needed */ - close(pty_fds[CHILDFD]); - /* now enter a loop of read user input, and writing it to the pty */ - while (1) { - FD_ZERO(&fds_write); - FD_SET(pty_fds[PARENTFD], &fds_write); - printf("pid %d Waiting for pty ready to write on %s...\n", - getpid(), name); - retval = select(pty_fds[PARENTFD]+2, NULL, &fds_write, NULL, NULL); - if (retval == -1) { - perror("select"); - fprintf(stderr, "Parent: Error in select\n"); - exit(-1); - } - printf("Input data: "); - if(!gets(data)) { - printf("parent: eof; exiting\n"); - break; - } - if (!strcmp(data, "exit")) - break; - if (!FD_ISSET(pty_fds[PARENTFD], &fds_write)) { - fprintf(stderr, "parent: write fd not set?! retrying\n"); - continue; - } - retval = write(pty_fds[PARENTFD], data, 1024); - if (retval == -1) { - perror("write"); - fprintf(stderr, "Error writing on pty\n"); - exit(-1); - } else printf("wrote %d\n", retval); - } - /* got exit from user */ - close(pty_fds[PARENTFD]); /* close pty, let child know we're done */ - wait(&retval); - printf("Child exited with status: %d\n", retval); - exit(0); -} -int main(int argc, char *argv[]) -{ - int ptys[2]; - int retval; - int pid; - if(openpty(&ptys[0], &ptys[1], name, NULL, NULL) < 0) { - perror("openpty"); - return 1; - } - printf("Using %s\n", name); - pid = fork(); - if (pid == -1) { - fprintf(stderr, "Error forking\n"); - exit(-1); - } - if (pid == 0) /* child proc */ - do_child(ptys); - else - do_parent(ptys); - /* not reached */ - return 0; -} diff --git a/test/test76.c b/test/test76.c new file mode 100644 index 000000000..062ccf4ce --- /dev/null +++ b/test/test76.c @@ -0,0 +1,446 @@ +/* Tests for interrupting VFS calls - by D.C. van Moolenbroek */ +/* This test needs to be run as root; otherwise, openpty() won't work. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ITERATIONS 1 + +#include "common.h" + +/* + * This signal handler does nothing. It just needs to be triggered, so that + * PM will tell VFS to unpause this process. + */ +static void dummy_handler(int sig) +{ + /* Nothing. */ +} + +/* + * Interrupt a select(2) call. + */ +static void +test76a(void) +{ + struct sigaction act, oact; + struct itimerval it; + struct sockaddr_in sin; + struct timeval tv; + fd_set set; + int tfd[2], pfd[2], sfd, maxfd; + + subtest = 1; + + act.sa_handler = dummy_handler; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(SIGALRM, &act, &oact) < 0) e(1); + + memset(&it, 0, sizeof(it)); + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 10000; + if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(2); + + /* First try without any file descriptors. */ + tv.tv_sec = 1; + tv.tv_usec = 0; + if (select(0, NULL, NULL, NULL, &tv) >= 0) e(3); + if (errno != EINTR) e(4); + + /* Then try with different types of file descriptors, all blocking. */ + if (openpty(&tfd[0], &tfd[1], NULL, NULL, NULL) < 0) e(5); + + FD_ZERO(&set); + FD_SET(tfd[0], &set); /* reading from the PTY master should block */ + maxfd = tfd[0]; + + if (pipe(pfd) < 0) e(6); + FD_SET(pfd[0], &set); /* reading from an empty pipe should block */ + if (maxfd < pfd[0]) maxfd = pfd[0]; + + if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) e(7); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + /* Binding to an arbitrary port is fine. */ + if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) e(8); + + if (listen(sfd, 1) < 0) e(9); + + FD_SET(sfd, &set); /* reading from a listening socket should block */ + if (maxfd < sfd) maxfd = sfd; + + memset(&it, 0, sizeof(it)); + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 100000; + if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(10); + + tv.tv_sec = 1; + tv.tv_usec = 0; + if (select(maxfd + 1, &set, NULL, NULL, &tv) >= 0) e(11); + if (errno != EINTR) e(12); + + if (close(tfd[0]) < 0) e(13); + if (close(tfd[1]) < 0) e(14); + if (close(pfd[0]) < 0) e(15); + if (close(pfd[1]) < 0) e(16); + if (close(sfd) < 0) e(17); + + if (sigaction(SIGUSR1, &oact, NULL) < 0) e(18); +} + +/* + * Interrupt reads and writes to a pipe. POSIX states that if the operation + * was partially successful, the number of bytes written so far should be + * returned; otherwise, the we should get the normal EINTR. + */ +static void +test76b(void) +{ + struct sigaction act, oact; + struct itimerval it; + char *buf; + int pfd[2]; + + subtest = 2; + + if ((buf = malloc(PIPE_BUF * 2)) == NULL) e(1); + + if (pipe(pfd) < 0) e(2); + + act.sa_handler = dummy_handler; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(SIGALRM, &act, &oact) < 0) e(3); + + memset(&it, 0, sizeof(it)); + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 10000; + if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(4); + + /* + * This write is too large for the pipe, so it will block until the + * signal arrives. When being interrupted, it should return the pipe + * size, as that is the part that has been filled successfully so far. + */ + if (write(pfd[1], buf, PIPE_BUF * 2) != PIPE_BUF) e(5); + + /* + * Since the write partially succeeded, we should be able to read all + * we wrote so far, without blocking. + */ + if (read(pfd[0], buf, PIPE_BUF) != PIPE_BUF) e(6); + + /* We should now be able to fill the pipe up to its full size again. */ + if (write(pfd[1], buf, PIPE_BUF) != PIPE_BUF) e(7); + + memset(&it, 0, sizeof(it)); + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 10000; + if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(8); + + /* Now interrupt a write attempt on a full pipe. */ + if (write(pfd[1], buf, 1) >= 0) e(9); + if (errno != EINTR) e(10); + + /* Empty the pipe again. */ + if (read(pfd[0], buf, PIPE_BUF) != PIPE_BUF) e(11); + + memset(&it, 0, sizeof(it)); + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 10000; + if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(12); + + /* Now interrupt a read on an empty pipe. */ + if (read(pfd[0], buf, PIPE_BUF) >= 0) e(13); + if (errno != EINTR) e(14); + + if (close(pfd[0]) < 0) e(15); + if (close(pfd[1]) < 0) e(16); + + if (sigaction(SIGUSR1, &oact, NULL) < 0) e(17); + + free(buf); +} + +/* + * Interrupt an ioctl(2) call. We use an alarm to interrupt an accept(3) call + * on a TCP socket - the accept procedure is (currently) implemented using + * ioctl(2) calls. + */ +static void +test76c(void) +{ + struct sigaction act, oact; + struct itimerval it; + struct sockaddr_in sin; + socklen_t len; + int sfd; + + subtest = 3; + + if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) e(1); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + /* Binding to an arbitrary port is fine. */ + if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) e(2); + + if (listen(sfd, 1) < 0) e(3); + + act.sa_handler = dummy_handler; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(SIGALRM, &act, &oact) < 0) e(4); + + memset(&it, 0, sizeof(it)); + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 10000; + if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(5); + + /* This will block until the timer fires. */ + len = sizeof(sin); + if (accept(sfd, (struct sockaddr *)&sin, &len) >= 0) e(6); + if (errno != EINTR) e(7); + + if (close(sfd) < 0) e(8); + + if (sigaction(SIGUSR1, &oact, NULL) < 0) e(9); +} + +/* + * Try to trigger semi-concurrent processing of normal system calls and + * postponed PM requests for a single process within VFS. + */ +static void +test76d(void) +{ + struct utsname name; + struct sigaction act, oact; + struct itimerval it; + int r, fd, pfd[2], count, status; + time_t stime, etime, runtime = 30 /*seconds*/; + char buf[3], *pbuf; + + subtest = 4; + + /* This test would kill wimpy platforms such as ARM. */ + if (uname(&name) < 0) e(1); + if (!strcmp(name.machine, "arm")) return; + + act.sa_handler = dummy_handler; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(SIGALRM, &act, &oact) < 0) e(2); + + if (pipe(pfd) < 0) e(3); + + /* Pre-fill the pipe. */ + if ((pbuf = malloc(PIPE_BUF - 1)) == NULL) e(4); + + if (write(pfd[1], pbuf, PIPE_BUF - 1) != PIPE_BUF - 1) e(5); + + free(pbuf); + + switch (fork()) { + case 0: + if (close(pfd[1]) < 0) e(6); + + /* Read from the pipe, but more slowly than the writer. */ + while ((r = read(pfd[0], buf, 2)) != 0) + if (r < 0) e(7); + + exit(0); + case -1: + e(8); + default: + break; + } + + switch (fork()) { + case 0: + if (close(pfd[0]) < 0) e(9); + + time(&stime); + + /* Start an alarm mayhem. */ + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 1; + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 1; + if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(10); + + /* + * Then start writing to the pipe, in such a way that the + * write operation will be suspended in every so many cases. + */ + do { + if (write(pfd[1], buf, 3) < 0 && errno != EINTR) + e(11); + + time(&etime); + } while ((int)(etime - stime) < runtime); + + exit(0); + case -1: + e(12); + default: + break; + } + + if (close(pfd[0]) < 0) e(13); + if (close(pfd[1]) < 0) e(14); + + /* + * First give the two processes a while to run regularly. Then start + * creating additional noise to keep the VFS worker threads busy. + */ + runtime /= 2; + + sleep(runtime); + + /* + * As of writing, VFS has less than 20 worker threads. Create more + * processes than that. + */ + for (count = 2; count < 20; count++) { + switch (fork()) { + case 0: + time(&stime); + + do { + /* + * Opening a character device blocks the + * calling thread, hopefully causing work to be + * queued. Sadly, in practice, the high + * priorities of system processes prevent this + * case from occurring frequently. It works + * better with a driver that has a priority + * below that of of user processes. + */ + if ((fd = open("/dev/null", O_WRONLY)) < 0) + e(15); + + close(fd); + + time(&etime); + } while ((int)(etime - stime) < runtime); + + exit(0); + case -1: + e(16); + default: + break; + } + } + + /* Wait for all children to shut down. */ + while (count-- > 0) { + if (wait(&status) <= 0) e(17); + if (!WIFEXITED(status)) e(18); + if (WEXITSTATUS(status) != 0) e(19); + } + + if (sigaction(SIGUSR1, &oact, NULL) < 0) e(20); +} + +/* + * Try to get a nonblocking select(2) call to be interrupted by a signal. + * In the future, VFS should prevent this from happening at all; for now, we + * just want to make sure it does not result in disaster when it does happen. + */ +static void +test76e(void) +{ + struct utsname name; + struct sigaction act, oact; + struct itimerval it; + struct timeval tv; + fd_set set; + int tfd[2], left; + + subtest = 5; + + /* This test would kill wimpy platforms such as ARM. */ + if (uname(&name) < 0) e(1); + if (!strcmp(name.machine, "arm")) return; + + if (openpty(&tfd[0], &tfd[1], NULL, NULL, NULL) < 0) e(2); + + act.sa_handler = dummy_handler; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(SIGALRM, &act, &oact) < 0) e(3); + + /* + * Start an alarm mayhem. We have to try to get a signal in between + * VFS sending a select request to TTY, and TTY replying to VFS with + * initial results. + */ + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 1; + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 1; + if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(4); + + /* + * Now issue nonblocking selects until we get interrupted, or until + * we have gone through a hardcoded maximum of attempts. + */ + left = 100000; + do { + if (--left == 0) break; + + FD_ZERO(&set); + FD_SET(tfd[0], &set); /* reading from master should block */ + + tv.tv_sec = 0; + tv.tv_usec = 0; + } while (select(2, &set, NULL, NULL, &tv) >= 0); + + if (left > 0 && errno != EINTR) e(5); + + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 0; + if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(6); + + /* The call failed, so the set must be unmodified. */ + if (left > 0 && !FD_SET(tfd[0], &set)) e(7); + + if (close(tfd[0]) < 0) e(8); + if (close(tfd[1]) < 0) e(9); + + if (sigaction(SIGUSR1, &oact, NULL) < 0) e(10); +} + +int +main(int argc, char **argv) +{ + int i, m; + + start(76); + + if (argc == 2) + m = atoi(argv[1]); + else + m = 0xFF; + + for (i = 0; i < ITERATIONS; i++) { + if (m & 0x01) test76a(); + if (m & 0x02) test76b(); + if (m & 0x04) test76c(); + if (m & 0x08) test76d(); + if (m & 0x10) test76e(); + } + + quit(); +} diff --git a/test/test77.c b/test/test77.c new file mode 100644 index 000000000..babd05993 --- /dev/null +++ b/test/test77.c @@ -0,0 +1,373 @@ +/* Tests for opening/closing pseudo terminals - by D.C. van Moolenbroek */ +/* This test needs to be run as root; otherwise, openpty() won't work. */ +#include +#include +#include +#include +#include +#include +#include + +#define ITERATIONS 10 + +#include "common.h" + +/* + * Set the slave side of the pseudo terminal to raw mode. This simplifies + * testing communication. + */ +static void +make_raw(int slavefd) +{ + struct termios tios; + + if (tcgetattr(slavefd, &tios) < 0) e(100); + + cfmakeraw(&tios); + + if (tcsetattr(slavefd, TCSANOW, &tios) < 0) e(101); +} + +/* + * See if the given pseudo terminal can successfully perform basic + * communication between master and slave. + */ +static void +test_comm(int masterfd, int slavefd) +{ + char c; + + make_raw(slavefd); + + c = 'A'; + if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(200); + if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(201); + if (c != 'A') e(202); + + c = 'B'; + if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(203); + if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(204); + if (c != 'B') e(205); + + c = 'C'; + if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(206); + if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(207); + if (c != 'C') e(208); + + c = 'D'; + if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(209); + if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(210); + if (c != 'D') e(211); +} + +/* + * Get device node names for the master and slave end of a free pseudo + * terminal. We don't want to replicate the entire openpty(3) logic here, so + * start by letting openpty(3) do the work for us. We make the assumption that + * nobody snatches the pair while we are running. + */ +static void +get_names(char pname[PATH_MAX], char tname[PATH_MAX]) +{ + int len, masterfd, slavefd; + + if (openpty(&masterfd, &slavefd, tname, NULL, NULL) < 0) e(300); + + /* + * openpty(3) gives us only the slave name, but we also need the master + * name. + */ + strlcpy(pname, tname, PATH_MAX); + len = strlen(_PATH_DEV); + + if (strncmp(pname, _PATH_DEV, len)) e(301); + + /* If this fails, this test needs to be updated. */ + if (pname[len] != 't') e(302); + + pname[len] = 'p'; + + test_comm(masterfd, slavefd); + + if (close(masterfd) < 0) e(303); + if (close(slavefd) < 0) e(304); +} + +/* + * Test various orders of opening and closing the master and slave sides of a + * pseudo terminal, as well as opening/closing one side without ever opening + * the other. + */ +static void +test77a(void) +{ + char pname[PATH_MAX], tname[PATH_MAX]; + int masterfd, slavefd; + + subtest = 1; + + get_names(pname, tname); + + /* Try opening and then closing the master. */ + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(1); + + if (close(masterfd) < 0) e(2); + + /* Now see if we can reopen the master as well as the slave. */ + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(3); + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(4); + + test_comm(masterfd, slavefd); + + /* In the meantime, test different closing orders. This is order A. */ + if (close(slavefd) < 0) e(5); + if (close(masterfd) < 0) e(6); + + /* Now try opening the pair again. */ + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(7); + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(8); + + test_comm(masterfd, slavefd); + + if (close(slavefd) < 0) e(9); + + /* + * Try reopening the slave after closing it. It is not very important + * that this works, but the TTY driver should currently support it. + */ + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(10); + + test_comm(masterfd, slavefd); + + /* This is closing order B. */ + if (close(masterfd) < 0) e(11); + if (close(slavefd) < 0) e(12); + + /* Try the normal open procedure. */ + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(13); + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(14); + + test_comm(masterfd, slavefd); + + if (close(masterfd) < 0) e(15); + if (close(slavefd) < 0) e(16); + + /* Try reopening and closing the slave, without opening the master. */ + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(17); + + if (close(slavefd) < 0) e(18); + + /* Again, try the normal open procedure. */ + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(19); + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(20); + + test_comm(masterfd, slavefd); + + if (close(masterfd) < 0) e(21); + if (close(slavefd) < 0) e(22); + + /* Finally, try opening the slave first. */ + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(23); + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(24); + + test_comm(masterfd, slavefd); + + if (close(masterfd) < 0) e(25); + if (close(slavefd) < 0) e(26); +} + +/* + * Test opening a single side multiple times. + */ +static void +test77b(void) +{ + char pname[PATH_MAX], tname[PATH_MAX]; + int masterfd, slavefd, extrafd; + + subtest = 2; + + get_names(pname, tname); + + /* It must not be possible to open the master multiple times. */ + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(1); + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(2); + + test_comm(masterfd, slavefd); + + if ((extrafd = open(pname, O_RDWR | O_NOCTTY)) >= 0) e(3); + if (errno != EIO) e(4); + + test_comm(masterfd, slavefd); + + if (close(masterfd) < 0) e(5); + if (close(slavefd) < 0) e(6); + + /* The slave can be opened multiple times, though. */ + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(7); + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(8); + + test_comm(masterfd, slavefd); + + if ((extrafd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(9); + + test_comm(masterfd, extrafd); + test_comm(masterfd, slavefd); + + if (close(masterfd) < 0) e(10); + if (close(slavefd) < 0) e(11); + if (close(extrafd) < 0) e(12); +} + +/* + * Test communication on half-open pseudo terminals. + */ +static void +test77c(void) +{ + char pname[PATH_MAX], tname[PATH_MAX]; + int masterfd, slavefd; + char c; + + subtest = 3; + + get_names(pname, tname); + + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(1); + + /* Writes to the master should be buffered until there is a slave. */ + c = 'E'; + if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(2); + + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(3); + + make_raw(slavefd); + + if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(4); + if (c != 'E') e(5); + + /* Discard the echo on the master. */ + if (tcflush(slavefd, TCOFLUSH) != 0) e(6); + + test_comm(masterfd, slavefd); + + if (close(slavefd) < 0) e(7); + + /* Writes to the master after the slave has been closed should fail. */ + if (write(masterfd, &c, sizeof(c)) >= 0) e(8); + if (errno != EIO) e(9); + + if (close(masterfd) < 0) e(10); + + /* Writes to the slave should be buffered until there is a master. */ + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(11); + + make_raw(slavefd); + + c = 'F'; + if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(12); + + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(13); + + if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(14); + if (c != 'F') e(15); + + test_comm(masterfd, slavefd); + + if (close(masterfd) < 0) e(16); + + if (write(slavefd, &c, sizeof(c)) >= 0) e(17); + if (errno != EIO) e(18); + + if (close(slavefd) < 0) e(19); +} + +/* + * Test opening the slave side with and without the O_NOCTTY flag. + */ +static void +test77d(void) +{ + char pname[PATH_MAX], tname[PATH_MAX]; + int masterfd, slavefd; + + subtest = 4; + + get_names(pname, tname); + + /* Make ourselves process group leader if we aren't already. */ + (void) setsid(); + + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(1); + + /* + * Opening the slave with O_NOCTTY should not change its controlling + * terminal. + */ + switch (fork()) { + case 0: + if (setsid() < 0) e(2); + + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(3); + + if (open("/dev/tty", O_RDWR) >= 0) e(4); + if (errno != ENXIO) e(5); + + exit(0); + case -1: + e(6); + default: + break; + } + + if (wait(NULL) <= 0) e(7); + + if (close(masterfd) < 0) e(8); + + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(9); + + /* + * Opening the slave without O_NOCTTY should change its controlling + * terminal, though. + */ + switch (fork()) { + case 0: + if (setsid() < 0) e(10); + + if ((slavefd = open(tname, O_RDWR)) < 0) e(11); + + if (open("/dev/tty", O_RDWR) < 0) e(12); + + exit(0); + case -1: + e(13); + default: + break; + } + + if (wait(NULL) <= 0) e(14); + + if (close(masterfd) < 0) e(15); +} + +int +main(int argc, char **argv) +{ + int i, m; + + start(77); + + if (argc == 2) + m = atoi(argv[1]); + else + m = 0xFF; + + for (i = 0; i < ITERATIONS; i++) { + if (m & 0x01) test77a(); + if (m & 0x02) test77b(); + if (m & 0x04) test77c(); + if (m & 0x08) test77d(); + } + + quit(); +}