Index: generic/tclIO.c ================================================================== --- generic/tclIO.c +++ generic/tclIO.c @@ -8923,12 +8923,12 @@ ChannelState *statePtr; /* State info for channel */ Tcl_Channel chan; /* The opaque type for the channel. */ const char *chanName; int modeIndex; /* Index of mode argument. */ int mask; - static const char *const modeOptions[] = {"readable", "writable", NULL}; - static const int maskArray[] = {TCL_READABLE, TCL_WRITABLE}; + static const char *const modeOptions[] = {"readable", "writable", "exception", NULL}; + static const int maskArray[] = {TCL_READABLE, TCL_WRITABLE, TCL_EXCEPTION }; if ((objc != 3) && (objc != 4)) { Tcl_WrongNumArgs(interp, 1, objv, "channelId event ?script?"); return TCL_ERROR; } @@ -8943,11 +8943,11 @@ if (chan == NULL) { return TCL_ERROR; } chanPtr = (Channel *) chan; statePtr = chanPtr->state; - if ((statePtr->flags & mask) == 0) { + if ( ((statePtr->flags | TCL_EXCEPTION) & mask) == 0) { Tcl_SetObjResult(interp, Tcl_ObjPrintf("channel is not %s", (mask == TCL_READABLE) ? "readable" : "writable")); return TCL_ERROR; } Index: tests/chanio.test ================================================================== --- tests/chanio.test +++ tests/chanio.test @@ -5496,11 +5496,11 @@ test chan-io-41.4 {Tcl_FileeventCmd: errors} -constraints fileevent -body { chan event gorp writable } -returnCodes error -result {can not find channel named "gorp"} test chan-io-41.5 {Tcl_FileeventCmd: errors} -constraints fileevent -body { chan event gorp who-knows -} -returnCodes error -result {bad event name "who-knows": must be readable or writable} +} -returnCodes error -result {bad event name "who-knows": must be readable, writable, or exception} # # Test chan event on a file # Index: tests/io.test ================================================================== --- tests/io.test +++ tests/io.test @@ -5795,11 +5795,11 @@ test io-41.4 {Tcl_FileeventCmd: errors} {fileevent} { list [catch {fileevent gorp writable} msg] $msg } {1 {can not find channel named "gorp"}} test io-41.5 {Tcl_FileeventCmd: errors} {fileevent} { list [catch {fileevent gorp who-knows} msg] $msg -} {1 {bad event name "who-knows": must be readable or writable}} +} {1 {bad event name "who-knows": must be readable, writable, or exception}} # # Test fileevent on a file # Index: tests/zlib.test ================================================================== --- tests/zlib.test +++ tests/zlib.test @@ -838,11 +838,11 @@ set ::total } -cleanup { close $srv rename bgerror {} } -returnCodes error \ - -result {bad event name "xyzzy": must be readable or writable} + -result {bad event name "xyzzy": must be readable, writable, or exception} test zlib-10.1 "bug #2818131 (mismatch read)" -constraints { zlib } -setup { proc bgerror {s} {set ::total [list error $s]} proc zlibRead {c} { Index: unix/tclEpollNotfy.c ================================================================== --- unix/tclEpollNotfy.c +++ unix/tclEpollNotfy.c @@ -219,11 +219,14 @@ struct epoll_event newEvent; struct PlatformEventData *newPedPtr; struct stat fdStat; newEvent.events = 0; - if (filePtr->mask & (TCL_READABLE | TCL_EXCEPTION)) { + if (filePtr->mask & TCL_EXCEPTION) { + newEvent.events |= EPOLLERR | EPOLLPRI; + } + if (filePtr->mask & TCL_READABLE) { newEvent.events |= EPOLLIN; } if (filePtr->mask & TCL_WRITABLE) { newEvent.events |= EPOLLOUT; } @@ -240,11 +243,13 @@ * port regular files (S_IFREG.) Therefore, filePtr is in these * cases simply added or deleted from the list of FileHandlers * associated with regular files belonging to tsdPtr. */ - if (fstat(filePtr->fd, &fdStat) == -1) { + if (newEvent.events & EPOLLERR) { + /* if exceptions are requested, ignore file type */ + } else if (fstat(filePtr->fd, &fdStat) == -1) { Tcl_Panic("fstat: %s", strerror(errno)); } else if ((fdStat.st_mode & S_IFMT) == S_IFREG) { switch (op) { case EPOLL_CTL_ADD: if (isNew) { @@ -254,11 +259,12 @@ case EPOLL_CTL_DEL: LIST_REMOVE(filePtr, readyNode); break; } return; - } else if (epoll_ctl(tsdPtr->eventsFd, op, filePtr->fd, &newEvent) == -1) { + } + if (epoll_ctl(tsdPtr->eventsFd, op, filePtr->fd, &newEvent) == -1) { Tcl_Panic("epoll_ctl: %s", strerror(errno)); } } /*