1/* exp_select.c - select() interface for Expect 2 3Written by: Don Libes, NIST, 2/6/90 4 5Design and implementation of this program was paid for by U.S. tax 6dollars. Therefore it is public domain. However, the author and NIST 7would appreciate credit if this program or parts of it are used. 8 9*/ 10 11/* suppress file-empty warnings produced by some compilers */ 12void exp_unused() {} 13 14#if 0 /* WHOLE FILE!!!! */ 15#include "expect_cf.h" 16#include <stdio.h> 17#include <errno.h> 18#include <sys/types.h> 19 20#ifdef HAVE_SYS_WAIT_H 21#include <sys/wait.h> 22#endif 23 24#ifdef HAVE_SYS_TIME_H 25#include <sys/time.h> 26#endif 27 28#ifdef HAVE_SYSSELECT_H 29# include <sys/select.h> /* Intel needs this for timeval */ 30#endif 31 32#ifdef HAVE_PTYTRAP 33# include <sys/ptyio.h> 34#endif 35 36#ifdef HAVE_UNISTD_H 37# include <unistd.h> 38#endif 39 40#ifdef _AIX 41/* AIX has some unusual definition of FD_SET */ 42#include <sys/select.h> 43#endif 44 45#if !defined( FD_SET ) && defined( HAVE_SYS_BSDTYPES_H ) 46 /* like AIX, ISC has it's own definition of FD_SET */ 47# include <sys/bsdtypes.h> 48#endif /* ! FD_SET && HAVE_SYS_BSDTYPES_H */ 49 50#include "tcl.h" 51#include "exp_prog.h" 52#include "exp_command.h" /* for struct exp_f defs */ 53#include "exp_event.h" 54 55#ifdef HAVE_SYSCONF_H 56#include <sys/sysconfig.h> 57#endif 58 59#ifndef FD_SET 60#define FD_SET(fd,fdset) (fdset)->fds_bits[0] |= (1<<(fd)) 61#define FD_CLR(fd,fdset) (fdset)->fds_bits[0] &= ~(1<<(fd)) 62#define FD_ZERO(fdset) (fdset)->fds_bits[0] = 0 63#define FD_ISSET(fd,fdset) (((fdset)->fds_bits[0]) & (1<<(fd))) 64#ifndef AUX2 65typedef struct fd_set { 66 long fds_bits[1]; 67 /* any implementation so pathetic as to not define FD_SET will just */ 68 /* have to suffer with only 32 bits worth of fds */ 69} fd_set; 70#endif /* AUX2 */ 71#endif 72 73static struct timeval zerotime = {0, 0}; 74static struct timeval anytime = {0, 0}; /* can be changed by user */ 75 76/* returns status, one of EOF, TIMEOUT, ERROR or DATA */ 77int 78exp_get_next_event(interp,masters, n,master_out,timeout,key) 79Tcl_Interp *interp; 80int *masters; 81int n; /* # of masters */ 82int *master_out; /* 1st event master, not set if none */ 83int timeout; /* seconds */ 84int key; 85{ 86 static rr = 0; /* round robin ptr */ 87 88 int i; /* index into in-array */ 89 struct timeval *t; 90 91 fd_set rdrs; 92 fd_set excep; 93/* FIXME: This is really gross, but the folks at Lynx said their select is 94 * way hosed and to ignore all exceptions. 95 */ 96#ifdef __Lynx__ 97#define EXCEP 0 98#else 99#define EXCEP &excep 100#endif 101 102 for (i=0;i<n;i++) { 103 struct exp_f *f; 104 int m; 105 106 rr++; 107 if (rr >= n) rr = 0; 108 109 m = masters[rr]; 110 f = exp_fs + m; 111 112 if (f->key != key) { 113 f->key = key; 114 f->force_read = FALSE; 115 *master_out = m; 116 return(EXP_DATA_OLD); 117 } else if ((!f->force_read) && (f->size != 0)) { 118 *master_out = m; 119 return(EXP_DATA_OLD); 120 } 121 } 122 123 if (timeout >= 0) { 124 t = &anytime; 125 t->tv_sec = timeout; 126 } else { 127 t = NULL; 128 } 129 130 restart: 131 if (Tcl_AsyncReady()) { 132 int rc = Tcl_AsyncInvoke(interp,TCL_OK); 133 if (rc != TCL_OK) return(exp_tcl2_returnvalue(rc)); 134 135 /* anything in the environment could have changed */ 136 return EXP_RECONFIGURE; 137 } 138 139 FD_ZERO(&rdrs); 140 FD_ZERO(&excep); 141 for (i = 0;i < n;i++) { 142 FD_SET(masters[i],&rdrs); 143 FD_SET(masters[i],&excep); 144 } 145 146 /* The reason all fd masks are (seemingly) redundantly cast to */ 147 /* SELECT_MASK_TYPE is that the HP defines its mask in terms of */ 148 /* of int * and yet defines FD_SET in terms of fd_set. */ 149 150 if (-1 == select(exp_fd_max+1, 151 (SELECT_MASK_TYPE *)&rdrs, 152 (SELECT_MASK_TYPE *)0, 153 (SELECT_MASK_TYPE *)EXCEP, 154 t)) { 155 /* window refreshes trigger EINTR, ignore */ 156 if (errno == EINTR) goto restart; 157 else if (errno == EBADF) { 158 /* someone is rotten */ 159 for (i=0;i<n;i++) { 160 fd_set suspect; 161 FD_ZERO(&suspect); 162 FD_SET(masters[i],&suspect); 163 if (-1 == select(exp_fd_max+1, 164 (SELECT_MASK_TYPE *)&suspect, 165 (SELECT_MASK_TYPE *)0, 166 (SELECT_MASK_TYPE *)0, 167 &zerotime)) { 168 exp_error(interp,"invalid spawn_id (%d)\r",masters[i]); 169 return(EXP_TCLERROR); 170 } 171 } 172 } else { 173 /* not prepared to handle anything else */ 174 exp_error(interp,"select: %s\r",Tcl_PosixError(interp)); 175 return(EXP_TCLERROR); 176 } 177 } 178 179 for (i=0;i<n;i++) { 180 rr++; 181 if (rr >= n) rr = 0; /* ">" catches previous readys that */ 182 /* used more fds then we're using now */ 183 184 if (FD_ISSET(masters[rr],&rdrs)) { 185 *master_out = masters[rr]; 186 return(EXP_DATA_NEW); 187/*#ifdef HAVE_PTYTRAP*/ 188 } else if (FD_ISSET(masters[rr], &excep)) { 189#ifndef HAVE_PTYTRAP 190 *master_out = masters[rr]; 191 return(EXP_EOF); 192#else 193 struct request_info ioctl_info; 194 if (ioctl(masters[rr],TIOCREQCHECK,&ioctl_info) < 0) { 195 exp_DiagLog("ioctl error on TIOCREQCHECK: %s",Tcl_ErrnoMsg(errno)); 196 break; 197 } 198 if (ioctl_info.request == TIOCCLOSE) { 199 /* eof */ 200 *master_out = masters[rr]; 201 return(EXP_EOF); 202 } 203 if (ioctl(masters[rr], TIOCREQSET, &ioctl_info) < 0) 204 expDiagLog("ioctl error on TIOCREQSET after ioctl or open on slave: %s", Tcl_ErrnoMsg(errno)); 205 /* presumably, we trapped an open here */ 206 goto restart; 207#endif /* HAVE_PTYTRAP */ 208 } 209 } 210 return(EXP_TIMEOUT); 211} 212 213/*ARGSUSED*/ 214int 215exp_get_next_event_info(interp,fd,ready_mask) 216Tcl_Interp *interp; 217int fd; 218int ready_mask; 219{ 220 /* this function is only used when running with Tk */ 221 /* hence, it is merely a stub in this file but to */ 222 /* pacify lint, return something */ 223 return 0; 224} 225 226int /* returns TCL_XXX */ 227exp_dsleep(interp,sec) 228Tcl_Interp *interp; 229double sec; 230{ 231 struct timeval t; 232 233 t.tv_sec = sec; 234 t.tv_usec = (sec - t.tv_sec) * 1000000L; 235 restart: 236 if (Tcl_AsyncReady()) { 237 int rc = Tcl_AsyncInvoke(interp,TCL_OK); 238 if (rc != TCL_OK) return rc; 239 } 240 if (-1 == select(1, 241 (SELECT_MASK_TYPE *)0, 242 (SELECT_MASK_TYPE *)0, 243 (SELECT_MASK_TYPE *)0, 244 &t) 245 && errno == EINTR) 246 goto restart; 247 return TCL_OK; 248} 249 250#if 0 251int /* returns TCL_XXX */ 252exp_usleep(interp,usec) 253Tcl_Interp *interp; 254long usec; /* microseconds */ 255{ 256 struct timeval t; 257 258 t.tv_sec = usec/1000000L; 259 t.tv_usec = usec%1000000L; 260 restart: 261 if (Tcl_AsyncReady()) { 262 int rc = Tcl_AsyncInvoke(interp,TCL_OK); 263 if (rc != TCL_OK) return(exp_tcl2_returnvalue(rc)); 264 } 265 if (-1 == select(1, 266 (SELECT_MASK_TYPE *)0, 267 (SELECT_MASK_TYPE *)0, 268 (SELECT_MASK_TYPE *)0, 269 &t) 270 && errno == EINTR) 271 goto restart; 272 return TCL_OK; 273} 274#endif /*0*/ 275 276/* set things up for later calls to event handler */ 277void 278exp_init_event() 279{ 280#if 0 281#ifdef _SC_OPEN_MAX 282 maxfds = sysconf(_SC_OPEN_MAX); 283#else 284 maxfds = getdtablesize(); 285#endif 286#endif 287 288 exp_event_exit = 0; 289} 290#endif /* WHOLE FILE !!!! */ 291