📄 nb.c
字号:
/* * This source code is a product of Sun Microsystems, Inc. and is provided * for unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users * may copy or modify this source code without charge, but are not authorized * to license or distribute it to anyone else except as part of a product or * program developed by the user. * * THIS PROGRAM CONTAINS SOURCE CODE COPYRIGHTED BY SUN MICROSYSTEMS, INC. * AND IS LICENSED TO SUNSOFT, INC., A SUBSIDIARY OF SUN MICROSYSTEMS, INC. * SUN MICROSYSTEMS, INC., MAKES NO REPRESENTATIONS ABOUT THE SUITABLITY * OF SUCH SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT * EXPRESS OR IMPLIED WARRANTY OF ANY KIND. SUN MICROSYSTEMS, INC. DISCLAIMS * ALL WARRANTIES WITH REGARD TO SUCH SOURCE CODE, INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN * NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM USE OF SUCH SOURCE CODE, REGARDLESS OF THE THEORY OF LIABILITY. * * This source code is provided with no support and without any obligation on * the part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS * SOURCE CODE OR ANY PART THEREOF. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */#include <stdio.h>#include <sys/types.h>#include <sys/param.h>#include <sys/time.h>#include <sys/file.h>#include <sys/socket.h>#include <sys/wait.h>#include <netinet/in.h>#include <signal.h>#include <fcntl.h>#include <errno.h>#include <sys/ioctl.h>#include <rpc/types.h>#include <lwp/lwp.h>#include <lwp/lwperror.h>#include <lwp/lwpmachdep.h>#include <lwp/stackdep.h>#include <syscall.h>#include "../queue.h"extern int errno;/* @(#) nb.c 1.1 92/07/30 Copyr 1987 Sun Micro *//* * UNIX functions that can block. * This library maps all potentially blocking system calls * into non-blocking ones. This provides some temporary help * for threads that use system calls until kernel thread support is available. * Because underlying descriptors are marked NB and ASYNCH in UNIX, * this library doesn't work well with other unix processes * sharing descriptors. Also, problems with kill -9 * since you can't catch this to reset a descriptor. * We don't do exit processing (see on_exit) if a default signal action * kills the pod either. * We mark C library special context for threads using system calls. * This preserves errno for these threads. * File descriptors are treated as global state: if two threads * try to open/close the same descriptor, no guarantees hold. * XXX We could improve things by using special contexts to hold * the per-thread info. The only disadvantage is that this could * slow down scheduling slightly for threads that don't use special contexts. *//* * we don't handle flock(2), or sigpause(2). * readv and writev are rarely used so we don't bother with them. * These are the guys we support: * * open(), socket(), pipe(), close(), * read(), write(), * send(), sendto(), sendmsg(), recv(), recvfom(), recvmsg(), * accept(), connect(), * select(); * wait(); */#define READ 0#define WRITE 1#define EXCEPT 2/* info about a descriptor */typedef struct nb_t { int issocket; /* TRUE if descriptor is a socket */ int old_flag; /* previous value of descriptor flags */} nb_t;/* info about an agent used to monitor a descriptor */typedef struct agent_t { struct agent_t *agt_next; thread_t agt_lwpid; int agt_event; caddr_t agt_mem; thread_t agt_aid;} agent_t;#define AGT_TYPES 2#define AGT_SIGIO 0#define AGT_SIGCHLD 1static nb_t NbDesc[NOFILE];static qheader_t NbAgt[AGT_TYPES];static NbInit = FALSE;static int NbSet[NOFILE];static mon_t AgtMon;#define INIT() {if (!NbInit) nbio_init(); }static int MyPid; /* for adding signals to process group */static int NDesc; /* Number of file descriptors UNIX supports *//* * Initialize non-blocking lwp library. */static voidnbio_init(){ int i; extern void nbio_lastrites(); extern void fdreset(); static stkalign_t stack[2000]; for (i = 0; i< NOFILE; i++) { NbDesc[i].issocket = FALSE; NbDesc[i].old_flag = 0; NbSet[i] = FALSE; } for (i = 0; i < AGT_TYPES; i++) INIT_QUEUE(&(NbAgt[i])); MyPid = -getpid(); (void) lwp_create((thread_t *)0, nbio_lastrites, MINPRIO, (LWPSERVER | LWPNOLASTRITES), STKTOP(stack), 0); mon_create(&AgtMon); NDesc = getdtablesize(); NbInit = TRUE; on_exit(fdreset, 0); /* XX should catch signals too? */}/* * Get an agent for a thread to receive unblocking signals on. * There is one agent per event per lwp - agents are stored on a linked list - * probably should be a hash table. * We don't create a new agent each time for two reasons: 1) if we create * and destroy an agent, we may drop signals before having a chance to * create a new one for the new IO, and 2) for efficiency. * Threads must check that the event they receive was really for them: e.g., * see if some IO is really available. * We also mark this thread as a C-library thread so it doesn't drop errno. */static voidget_agent(agent, agt_type) thread_t *agent; int agt_type;{ agent_t *agt; thread_t self; MONITOR(AgtMon); lwp_self(&self); for (agt = (agent_t *)FIRSTQ(&(NbAgt[agt_type])); agt != (agent_t *)0; agt = agt->agt_next) { if (SAMETHREAD(agt->agt_lwpid, self)) { *agent = agt->agt_aid; return; } } lwp_libcset(self); agt = (agent_t *)malloc(sizeof (agent_t)); agt->agt_lwpid = self; agt->agt_event = agt_type; agt->agt_mem = (agt_type == AGT_SIGIO) ? malloc(sizeof (eventinfo_t)) : malloc(sizeof (sigchldev_t)); agt_create(&agt->agt_aid, agt_type == AGT_SIGIO ? SIGIO : SIGCHLD, agt->agt_mem); INS_QUEUE(&(NbAgt[agt_type]), agt); *agent = agt->agt_aid;}/* * Called each time a client thread dies. * Reclaim its nbio resources. */static voidnbio_lastrites() { thread_t aid; eventinfo_t *event; int argsz; eventinfo_t lastrites; thread_t tid; /* dying thread */ register agent_t *agt; (void) agt_create(&aid, LASTRITES, (caddr_t)&lastrites); for (;;) { (void) msg_recv(&aid, (caddr_t *)&event, &argsz, (caddr_t *)0, (int *)0, INFINITY); tid = event->eventinfo_victimid; msg_reply(aid); /* * Search for all nbio agents belonging to tid * and remove them and their agent memory. * The REMX_ITEM is inefficient: should * do the search and removal together. */ mon_enter(AgtMon); for (agt = (agent_t *)FIRSTQ(&(NbAgt[AGT_SIGIO])); agt != (struct agent_t *)0; agt = agt->agt_next) { if (SAMETHREAD(agt->agt_lwpid, tid)) { free(agt->agt_mem); REMX_ITEM(&(NbAgt[AGT_SIGIO]), agt); free((caddr_t)agt); break; } } for (agt = (agent_t *)FIRSTQ(&(NbAgt[AGT_SIGCHLD])); agt != (struct agent_t *)0; agt = agt->agt_next) { if (SAMETHREAD(agt->agt_lwpid, tid)) { free(agt->agt_mem); REMX_ITEM(&(NbAgt[AGT_SIGCHLD]), agt); free((caddr_t)agt); break; } } mon_exit(AgtMon); }}/* * mark a descriptor non-blocking. * don't reset descriptor after each IO since another thread * may be using the descriptor. Monitor protection won't solve * the problem since there is no way to atomically release the monitor * upon entry into the kernel. */static intnblk_io(desc, issock) int desc; int issock;{ int res; if (NbSet[desc]) return (0); /* must set process group for sock io explicitly */ if (issock) { NbDesc[desc].issocket = TRUE; if (ioctl(desc, SIOCSPGRP, &MyPid) == -1) return (-1); } if ((res = fcntl(desc, F_GETFL, 0)) == -1) { return (-1); } else { NbDesc[desc].old_flag = res; } if (fcntl(desc, F_SETFL, FASYNC|FNDELAY) == -1) return (-1); NbSet[desc] = TRUE; return (0);}/* * Reset all descriptors upon pod termination. */static voidfdreset(){ register int fd; for (fd = 0; fd < NOFILE; fd++) { if (NbSet[fd]) { (void)fcntl(fd, F_SETFL, NbDesc[fd].old_flag); NbSet[fd] = FALSE; } }}/* * Await IO on a descriptor. */static voidblock_io(desc, operation) int desc; int operation;{ fd_set rmask, wmask, emask; register int nready; FD_ZERO(&rmask); FD_ZERO(&wmask); FD_ZERO(&emask); switch (operation){ case READ : FD_SET(desc, &rmask); break; case WRITE : FD_SET(desc, &wmask); break; } FD_SET(desc, &emask); /* always catch exceptions */ errno = 0; nready = block_until_notified(NDesc, &rmask, &wmask, &emask, INFINITY); if (nready <= 0) { if (lwp_geterr() != LE_NOERROR) lwp_perror("block"); if (errno != 0) perror("block"); }}/* Copy masks for select (which alters its arguments) */static voidset_masks(rmask, wmask, emask, c_rmask, c_wmask, c_emask) fd_set *rmask, *wmask, *emask, *c_rmask, *c_wmask, *c_emask;{ if (c_rmask != (fd_set *)NULL) { if (rmask == (fd_set *)NULL) { FD_ZERO(c_rmask); } else { bcopy((caddr_t)rmask, (caddr_t)c_rmask, sizeof (fd_set)); } } if (c_wmask != (fd_set *)NULL) { if (wmask == (fd_set *)NULL) { FD_ZERO(c_wmask); } else { bcopy((caddr_t)wmask, (caddr_t)c_wmask, sizeof (fd_set)); } } if (c_emask != (fd_set *)NULL) { if (emask == (fd_set *)NULL) { FD_ZERO(c_emask); } else { bcopy((caddr_t)emask, (caddr_t)c_emask, sizeof (fd_set)); } }}/* 'or' together a set of masks into "mask" */static voidor_masks(mask, rmask, wmask, emask) fd_set *mask, *rmask, *wmask, *emask;{ register int i; register caddr_t m = (caddr_t)mask; fd_set temp; FD_ZERO(&temp); m = (caddr_t)mask; if (rmask == (fd_set *)NULL) rmask = &temp; if (wmask == (fd_set *)NULL) wmask = &temp; if (emask == (fd_set *)NULL) emask = &temp; for (i = 0; i < sizeof (fd_set); i++) { m[i] = ((caddr_t)rmask)[i] | ((caddr_t)wmask)[i] | ((caddr_t)emask)[i]; }}/* return TRUE if any descriptors in src appear in dst */intmask_match(src, dst) fd_set *src; fd_set *dst;{ register int i; for (i = 0; i < sizeof (fd_set); i++) { if (((caddr_t)src)[i] & ((caddr_t)dst)[i]) { return (TRUE); } } return (FALSE);}/* * Count the number of bits set in a mask. */static intcountbits(mask, width) fd_set *mask; int width;{ register int i; register int total = 0; register int nbytes; nbytes = (width - 1 + NBBY) / NBBY; for (i = 0; i < sizeof (fd_set); i++) { total += count(((caddr_t)mask)[i]); } return (total);}/* count the number of bits in a byte. should really be a table */static intcount(n) char n;{ register int tocount = (n & 0xff); register int bits = 0; while (tocount) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -