mod_export Heap new_heaps(void) { Heap h; queue_signals(); h = heaps; fheap = heaps = NULL; unqueue_signals(); #ifdef ZSH_HEAP_DEBUG if (heap_debug_verbosity & HDV_NEW) { fprintf(stderr, "HEAP DEBUG: heap " HEAPID_FMT " saved, new heaps created.\n", h->heap_id); } if (!heaps_saved) heaps_saved = znewlinklist(); zpushnode(heaps_saved, h); #endif return h; }
static int bin_zselect(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) { #ifdef HAVE_SELECT int i, fd, fdsetind = 0, fdmax = 0, fdcount; fd_set fdset[3]; const char fdchar[3] = "rwe"; struct timeval tv, *tvptr = NULL; char *outarray = "reply", **outdata, **outptr; char *outhash = NULL; LinkList fdlist; for (i = 0; i < 3; i++) FD_ZERO(fdset+i); for (; *args; args++) { char *argptr = *args, *endptr; zlong tempnum; if (*argptr == '-') { for (argptr++; *argptr; argptr++) { switch (*argptr) { /* * Array name for reply, if not $reply. * This gets set to e.g. `-r 0 -w 1' if 0 is ready * for reading and 1 is ready for writing. */ case 'a': case 'A': i = *argptr; if (argptr[1]) argptr++; else if (args[1]) { argptr = *++args; } else { zwarnnam(nam, "argument expected after -%c", *argptr); return 1; } if (idigit(*argptr) || !isident(argptr)) { zwarnnam(nam, "invalid array name: %s", argptr); return 1; } if (i == 'a') outarray = argptr; else outhash = argptr; /* set argptr to next to last char because of increment */ while (argptr[1]) argptr++; break; /* Following numbers indicate fd's for reading */ case 'r': fdsetind = 0; break; /* Following numbers indicate fd's for writing */ case 'w': fdsetind = 1; break; /* Following numbers indicate fd's for errors */ case 'e': fdsetind = 2; break; /* * Get a timeout value in hundredths of a second * (same units as KEYTIMEOUT). 0 means just poll. * If not given, blocks indefinitely. */ case 't': if (argptr[1]) argptr++; else if (args[1]) { argptr = *++args; } else { zwarnnam(nam, "argument expected after -%c", *argptr); return 1; } if (!idigit(*argptr)) { zwarnnam(nam, "number expected after -t"); return 1; } tempnum = zstrtol(argptr, &endptr, 10); if (*endptr) { zwarnnam(nam, "garbage after -t argument: %s", endptr); return 1; } /* timevalue now active */ tvptr = &tv; tv.tv_sec = (long)(tempnum / 100); tv.tv_usec = (long)(tempnum % 100) * 10000L; /* remember argptr is incremented at end of loop */ argptr = endptr - 1; break; /* Digits following option without arguments are fd's. */ default: if (handle_digits(nam, argptr, fdset+fdsetind, &fdmax)) return 1; } } } else if (handle_digits(nam, argptr, fdset+fdsetind, &fdmax)) return 1; } errno = 0; do { i = select(fdmax, (SELECT_ARG_2_T)fdset, (SELECT_ARG_2_T)(fdset+1), (SELECT_ARG_2_T)(fdset+2), tvptr); } while (i < 0 && errno == EINTR && !errflag); if (i <= 0) { if (i < 0) zwarnnam(nam, "error on select: %e", errno); /* else no fd's set. Presumably a timeout. */ return 1; } /* * Make a linked list of all file descriptors which are ready. * These go into an array preceded by -r, -w or -e for read, write, * error as appropriate. Typically there will only be one set * so this looks rather like overkill. */ fdlist = znewlinklist(); for (i = 0; i < 3; i++) { int doneit = 0; for (fd = 0; fd < fdmax; fd++) { if (FD_ISSET(fd, fdset+i)) { char buf[BDIGBUFSIZE]; if (outhash) { /* * Key/value pairs; keys are fd's (as strings), * value is a (possibly improper) subset of "rwe". */ LinkNode nptr; int found = 0; convbase(buf, fd, 10); for (nptr = firstnode(fdlist); nptr; nptr = nextnode(nextnode(nptr))) { if (!strcmp((char *)getdata(nptr), buf)) { /* Already there, add new character. */ void **dataptr = getaddrdata(nextnode(nptr)); char *data = (char *)*dataptr, *ptr; found = 1; if (!strchr(data, fdchar[i])) { strcpy(buf, data); for (ptr = buf; *ptr; ptr++) ; *ptr++ = fdchar[i]; *ptr = '\0'; zsfree(data); *dataptr = ztrdup(buf); } break; } } if (!found) { /* Add new key/value pair. */ zaddlinknode(fdlist, ztrdup(buf)); buf[0] = fdchar[i]; buf[1] = '\0'; zaddlinknode(fdlist, ztrdup(buf)); } } else { /* List of fd's preceded by -r, -w, -e. */ if (!doneit) { buf[0] = '-'; buf[1] = fdchar[i]; buf[2] = 0; zaddlinknode(fdlist, ztrdup(buf)); doneit = 1; } convbase(buf, fd, 10); zaddlinknode(fdlist, ztrdup(buf)); } } } } /* convert list to array */ fdcount = countlinknodes(fdlist); outptr = outdata = (char **)zalloc((fdcount+1)*sizeof(char *)); while (nonempty(fdlist)) *outptr++ = getlinknode(fdlist); *outptr = NULL; /* and store in array parameter */ if (outhash) sethparam(outhash, outdata); else setaparam(outarray, outdata); freelinklist(fdlist, NULL); return 0; #else /* TODO: use poll */ zerrnam(nam, "your system does not implement the select system call."); return 2; #endif }
static int raw_getbyte(long do_keytmout, char *cptr) { int ret; struct ztmout tmout; #if defined(HAS_TIO) && \ (defined(sun) || (!defined(HAVE_POLL) && !defined(HAVE_SELECT))) struct ttyinfo ti; #endif #ifndef HAVE_POLL # ifdef HAVE_SELECT fd_set foofd, errfd; FD_ZERO(&errfd); # endif #endif calc_timeout(&tmout, do_keytmout); /* * Handle timeouts and watched fd's. If a watched fd or a function * timeout triggers we restart any key timeout. This is likely to * be harmless: the combination is extremely rare and a function * is likely to occupy the user for a little while anyway. We used * to make timeouts take precedence, but we can't now that the * timeouts may be external, so we may have both a permanent watched * fd and a long-term timeout. */ if ((nwatch || tmout.tp != ZTM_NONE)) { #if defined(HAVE_SELECT) || defined(HAVE_POLL) int i, errtry = 0, selret; # ifdef HAVE_POLL int nfds; struct pollfd *fds; # endif # if defined(HAS_TIO) && defined(sun) /* * Yes, I know this is complicated. Yes, I know we * already have three bits of code to poll the terminal * down below. No, I don't want to do this either. * However, it turns out on certain OSes, specifically * Solaris, that you can't poll typeahead for love nor * money without actually trying to read it. But * if we are trying to select (and we need to if we * are watching other fd's) we won't pick that up. * So we just try and read it without blocking in * the time-honoured (i.e. absurdly baroque) termios * fashion. */ gettyinfo(&ti); ti.tio.c_cc[VMIN] = 0; settyinfo(&ti); winch_unblock(); ret = read(SHTTY, cptr, 1); winch_block(); ti.tio.c_cc[VMIN] = 1; settyinfo(&ti); if (ret > 0) return 1; # endif # ifdef HAVE_POLL nfds = 1 + nwatch; /* First pollfd is SHTTY, following are the nwatch fds */ fds = zalloc(sizeof(struct pollfd) * nfds); fds[0].fd = SHTTY; /* * POLLIN, POLLIN, POLLIN, * Keep those fd's POLLIN... */ fds[0].events = POLLIN; for (i = 0; i < nwatch; i++) { fds[i+1].fd = watch_fds[i].fd; fds[i+1].events = POLLIN; } # endif for (;;) { # ifdef HAVE_POLL int poll_timeout; if (tmout.tp != ZTM_NONE) poll_timeout = tmout.exp100ths * 10; else poll_timeout = -1; winch_unblock(); selret = poll(fds, errtry ? 1 : nfds, poll_timeout); winch_block(); # else int fdmax = SHTTY; struct timeval *tvptr; struct timeval expire_tv; FD_ZERO(&foofd); FD_SET(SHTTY, &foofd); if (!errtry) { for (i = 0; i < nwatch; i++) { int fd = watch_fds[i].fd; if (FD_ISSET(fd, &errfd)) continue; FD_SET(fd, &foofd); if (fd > fdmax) fdmax = fd; } } FD_ZERO(&errfd); if (tmout.tp != ZTM_NONE) { expire_tv.tv_sec = tmout.exp100ths / 100; expire_tv.tv_usec = (tmout.exp100ths % 100) * 10000L; tvptr = &expire_tv; } else tvptr = NULL; winch_unblock(); selret = select(fdmax+1, (SELECT_ARG_2_T) & foofd, NULL, NULL, tvptr); winch_block(); # endif /* * Make sure a user interrupt gets passed on straight away. */ if (selret < 0 && (errflag || retflag || breaks || exit_pending)) break; /* * Try to avoid errors on our special fd's from * messing up reads from the terminal. Try first * with all fds, then try unsetting the special ones. */ if (selret < 0 && !errtry) { errtry = 1; continue; } if (selret == 0) { /* * Nothing ready and no error, so we timed out. */ switch (tmout.tp) { case ZTM_NONE: /* keeps compiler happy if not debugging */ #ifdef DEBUG dputs("BUG: timeout fired with no timeout set."); #endif /* treat as if a key timeout triggered */ /*FALLTHROUGH*/ case ZTM_KEY: /* Special value -2 signals nothing ready */ selret = -2; break; case ZTM_FUNC: while (firstnode(timedfns)) { Timedfn tfdat = (Timedfn)getdata(firstnode(timedfns)); /* * It's possible a previous function took * a long time to run (though it can't * call zle recursively), so recalculate * the time on each iteration. */ time_t now = time(NULL); if (tfdat->when > now) break; tfdat->func(); } /* Function may have messed up the display */ if (resetneeded) zrefresh(); /* We need to recalculate the timeout */ /*FALLTHROUGH*/ case ZTM_MAX: /* * Reached the limit of our range, but not the * actual timeout; recalculate the timeout. * We're cheating with the key timeout here: * if one clashed with a function timeout we * reconsider the key timeout from scratch. * The effect of this is microscopic. */ calc_timeout(&tmout, do_keytmout); break; } /* * If we handled the timeout successfully, * carry on. */ if (selret == 0) continue; } /* If error or unhandled timeout, give up. */ if (selret < 0) break; /* * If there's user input handle it straight away. * This improves the user's ability to handle exceptional * conditions like runaway output. */ if ( # ifdef HAVE_POLL (fds[0].revents & POLLIN) # else FD_ISSET(SHTTY, &foofd) # endif ) break; if (nwatch && !errtry) { /* * Copy the details of the watch fds in case the * user decides to delete one from inside the * handler function. */ int lnwatch = nwatch; Watch_fd lwatch_fds = zalloc(lnwatch*sizeof(struct watch_fd)); memcpy(lwatch_fds, watch_fds, lnwatch*sizeof(struct watch_fd)); for (i = 0; i < lnwatch; i++) lwatch_fds[i].func = ztrdup(lwatch_fds[i].func); for (i = 0; i < lnwatch; i++) { Watch_fd lwatch_fd = lwatch_fds + i; if ( # ifdef HAVE_POLL (fds[i+1].revents & (POLLIN|POLLERR|POLLHUP|POLLNVAL)) # else FD_ISSET(lwatch_fd->fd, &foofd) || FD_ISSET(lwatch_fd->fd, &errfd) # endif ) { /* Handle the fd. */ char *fdbuf; { char buf[BDIGBUFSIZE]; convbase(buf, lwatch_fd->fd, 10); fdbuf = ztrdup(buf); } if (lwatch_fd->widget) { zlecallhook(lwatch_fd->func, fdbuf); zsfree(fdbuf); } else { LinkList funcargs = znewlinklist(); zaddlinknode(funcargs, ztrdup(lwatch_fd->func)); zaddlinknode(funcargs, fdbuf); # ifdef HAVE_POLL # ifdef POLLERR if (fds[i+1].revents & POLLERR) zaddlinknode(funcargs, ztrdup("err")); # endif # ifdef POLLHUP if (fds[i+1].revents & POLLHUP) zaddlinknode(funcargs, ztrdup("hup")); # endif # ifdef POLLNVAL if (fds[i+1].revents & POLLNVAL) zaddlinknode(funcargs, ztrdup("nval")); # endif # else if (FD_ISSET(lwatch_fd->fd, &errfd)) zaddlinknode(funcargs, ztrdup("err")); # endif callhookfunc(lwatch_fd->func, funcargs, 0, NULL); freelinklist(funcargs, freestr); } if (errflag) { /* No sensible way of handling errors here */ errflag &= ~ERRFLAG_ERROR; /* * Paranoia: don't run the hooks again this * time. */ errtry = 1; } } } /* Function may have invalidated the display. */ if (resetneeded) zrefresh(); for (i = 0; i < lnwatch; i++) zsfree(lwatch_fds[i].func); zfree(lwatch_fds, lnwatch*sizeof(struct watch_fd)); # ifdef HAVE_POLL /* Function may have added or removed handlers */ nfds = 1 + nwatch; if (nfds > 1) { fds = zrealloc(fds, sizeof(struct pollfd) * nfds); for (i = 0; i < nwatch; i++) { /* * This is imperfect because it assumes fds[] and * watch_fds[] remain in sync, which may be false * if handlers are shuffled. However, it should * be harmless (e.g., produce one extra pass of * the loop) in the event they fall out of sync. */ if (fds[i+1].fd == watch_fds[i].fd && (fds[i+1].revents & (POLLERR|POLLHUP|POLLNVAL))) { fds[i+1].events = 0; /* Don't poll this */ } else { fds[i+1].fd = watch_fds[i].fd; fds[i+1].events = POLLIN; } fds[i+1].revents = 0; } } # endif } } # ifdef HAVE_POLL zfree(fds, sizeof(struct pollfd) * nfds); # endif if (selret < 0) return selret; #else # ifdef HAS_TIO ti = shttyinfo; ti.tio.c_lflag &= ~ICANON; ti.tio.c_cc[VMIN] = 0; ti.tio.c_cc[VTIME] = tmout.exp100ths / 10; # ifdef HAVE_TERMIOS_H tcsetattr(SHTTY, TCSANOW, &ti.tio); # else ioctl(SHTTY, TCSETA, &ti.tio); # endif winch_unblock(); ret = read(SHTTY, cptr, 1); winch_block(); # ifdef HAVE_TERMIOS_H tcsetattr(SHTTY, TCSANOW, &shttyinfo.tio); # else ioctl(SHTTY, TCSETA, &shttyinfo.tio); # endif return (ret <= 0) ? ret : *cptr; # endif #endif } winch_unblock(); ret = read(SHTTY, cptr, 1); winch_block(); return ret; }
int boot_(UNUSED(Module m)) { ztcp_sessions = znewlinklist(); return 0; }