📄 tclwinchan.c
字号:
/* * tclWinChan.c * * Channel drivers for Windows channels based on files, command * pipes and TCP sockets. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: tclWinChan.c,v 1.24 2002/07/08 10:08:58 vincentdarley Exp $ */#include "tclWinInt.h"/* * State flags used in the info structures below. */#define FILE_PENDING (1<<0) /* Message is pending in the queue. */#define FILE_ASYNC (1<<1) /* Channel is non-blocking. */#define FILE_APPEND (1<<2) /* File is in append mode. */#define FILE_TYPE_SERIAL (FILE_TYPE_PIPE+1)#define FILE_TYPE_CONSOLE (FILE_TYPE_PIPE+2)/* * The following structure contains per-instance data for a file based channel. */typedef struct FileInfo { Tcl_Channel channel; /* Pointer to channel structure. */ int validMask; /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, or TCL_EXCEPTION: indicates * which operations are valid on the file. */ int watchMask; /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, or TCL_EXCEPTION: indicates * which events should be reported. */ int flags; /* State flags, see above for a list. */ HANDLE handle; /* Input/output file. */ struct FileInfo *nextPtr; /* Pointer to next registered file. */ int dirty; /* Boolean flag. Set if the OS may have data * pending on the channel */} FileInfo;typedef struct ThreadSpecificData { /* * List of all file channels currently open. */ FileInfo *firstFilePtr;} ThreadSpecificData;static Tcl_ThreadDataKey dataKey;/* * The following structure is what is added to the Tcl event queue when * file events are generated. */typedef struct FileEvent { Tcl_Event header; /* Information that is standard for * all events. */ FileInfo *infoPtr; /* Pointer to file info structure. Note * that we still have to verify that the * file exists before dereferencing this * pointer. */} FileEvent;/* * Static routines for this file: */static int FileBlockProc _ANSI_ARGS_((ClientData instanceData, int mode));static void FileChannelExitHandler _ANSI_ARGS_(( ClientData clientData));static void FileCheckProc _ANSI_ARGS_((ClientData clientData, int flags));static int FileCloseProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp));static int FileEventProc _ANSI_ARGS_((Tcl_Event *evPtr, int flags));static int FileGetHandleProc _ANSI_ARGS_((ClientData instanceData, int direction, ClientData *handlePtr));static ThreadSpecificData *FileInit _ANSI_ARGS_((void));static int FileInputProc _ANSI_ARGS_((ClientData instanceData, char *buf, int toRead, int *errorCode));static int FileOutputProc _ANSI_ARGS_((ClientData instanceData, CONST char *buf, int toWrite, int *errorCode));static int FileSeekProc _ANSI_ARGS_((ClientData instanceData, long offset, int mode, int *errorCode));static Tcl_WideInt FileWideSeekProc _ANSI_ARGS_((ClientData instanceData, Tcl_WideInt offset, int mode, int *errorCode));static void FileSetupProc _ANSI_ARGS_((ClientData clientData, int flags));static void FileWatchProc _ANSI_ARGS_((ClientData instanceData, int mask)); /* * This structure describes the channel type structure for file based IO. */static Tcl_ChannelType fileChannelType = { "file", /* Type name. */ TCL_CHANNEL_VERSION_3, /* v3 channel */ FileCloseProc, /* Close proc. */ FileInputProc, /* Input proc. */ FileOutputProc, /* Output proc. */ FileSeekProc, /* Seek proc. */ NULL, /* Set option proc. */ NULL, /* Get option proc. */ FileWatchProc, /* Set up the notifier to watch the channel. */ FileGetHandleProc, /* Get an OS handle from channel. */ NULL, /* close2proc. */ FileBlockProc, /* Set blocking or non-blocking mode.*/ NULL, /* flush proc. */ NULL, /* handler proc. */ FileWideSeekProc, /* Wide seek proc. */};#ifdef HAVE_NO_SEHstatic void *ESP __attribute__ ((used));static void *EBP __attribute__ ((used));#endif /* HAVE_NO_SEH *//* *---------------------------------------------------------------------- * * FileInit -- * * This function creates the window used to simulate file events. * * Results: * None. * * Side effects: * Creates a new window and creates an exit handler. * *---------------------------------------------------------------------- */static ThreadSpecificData *FileInit(){ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (tsdPtr == NULL) { tsdPtr = TCL_TSD_INIT(&dataKey); tsdPtr->firstFilePtr = NULL; Tcl_CreateEventSource(FileSetupProc, FileCheckProc, NULL); Tcl_CreateThreadExitHandler(FileChannelExitHandler, NULL); } return tsdPtr;}/* *---------------------------------------------------------------------- * * FileChannelExitHandler -- * * This function is called to cleanup the channel driver before * Tcl is unloaded. * * Results: * None. * * Side effects: * Destroys the communication window. * *---------------------------------------------------------------------- */static voidFileChannelExitHandler(clientData) ClientData clientData; /* Old window proc */{ Tcl_DeleteEventSource(FileSetupProc, FileCheckProc, NULL);}/* *---------------------------------------------------------------------- * * FileSetupProc -- * * This procedure is invoked before Tcl_DoOneEvent blocks waiting * for an event. * * Results: * None. * * Side effects: * Adjusts the block time if needed. * *---------------------------------------------------------------------- */voidFileSetupProc(data, flags) ClientData data; /* Not used. */ int flags; /* Event flags as passed to Tcl_DoOneEvent. */{ FileInfo *infoPtr; Tcl_Time blockTime = { 0, 0 }; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return; } /* * Check to see if there is a ready file. If so, poll. */ for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->watchMask) { Tcl_SetMaxBlockTime(&blockTime); break; } }}/* *---------------------------------------------------------------------- * * FileCheckProc -- * * This procedure is called by Tcl_DoOneEvent to check the file * event source for events. * * Results: * None. * * Side effects: * May queue an event. * *---------------------------------------------------------------------- */static voidFileCheckProc(data, flags) ClientData data; /* Not used. */ int flags; /* Event flags as passed to Tcl_DoOneEvent. */{ FileEvent *evPtr; FileInfo *infoPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return; } /* * Queue events for any ready files that don't already have events * queued (caused by persistent states that won't generate WinSock * events). */ for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->watchMask && !(infoPtr->flags & FILE_PENDING)) { infoPtr->flags |= FILE_PENDING; evPtr = (FileEvent *) ckalloc(sizeof(FileEvent)); evPtr->header.proc = FileEventProc; evPtr->infoPtr = infoPtr; Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL); } }}/*---------------------------------------------------------------------- * * FileEventProc -- * * This function is invoked by Tcl_ServiceEvent when a file event * reaches the front of the event queue. This procedure invokes * Tcl_NotifyChannel on the file. * * Results: * Returns 1 if the event was handled, meaning it should be removed * from the queue. Returns 0 if the event was not handled, meaning * it should stay on the queue. The only time the event isn't * handled is if the TCL_FILE_EVENTS flag bit isn't set. * * Side effects: * Whatever the notifier callback does. * *---------------------------------------------------------------------- */static intFileEventProc(evPtr, flags) Tcl_Event *evPtr; /* Event to service. */ int flags; /* Flags that indicate what events to * handle, such as TCL_FILE_EVENTS. */{ FileEvent *fileEvPtr = (FileEvent *)evPtr; FileInfo *infoPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return 0; } /* * Search through the list of watched files for the one whose handle * matches the event. We do this rather than simply dereferencing * the handle in the event so that files can be deleted while the * event is in the queue. */ for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (fileEvPtr->infoPtr == infoPtr) { infoPtr->flags &= ~(FILE_PENDING); Tcl_NotifyChannel(infoPtr->channel, infoPtr->watchMask); break; } } return 1;}/* *---------------------------------------------------------------------- * * FileBlockProc -- * * Set blocking or non-blocking mode on channel. * * Results: * 0 if successful, errno when failed. * * Side effects: * Sets the device into blocking or non-blocking mode. * *---------------------------------------------------------------------- */static intFileBlockProc(instanceData, mode) ClientData instanceData; /* Instance data for channel. */ int mode; /* TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */{ FileInfo *infoPtr = (FileInfo *) instanceData; /* * Files on Windows can not be switched between blocking and nonblocking, * hence we have to emulate the behavior. This is done in the input * function by checking against a bit in the state. We set or unset the * bit here to cause the input function to emulate the correct behavior. */ if (mode == TCL_MODE_NONBLOCKING) { infoPtr->flags |= FILE_ASYNC; } else { infoPtr->flags &= ~(FILE_ASYNC); } return 0;}/* *---------------------------------------------------------------------- * * FileCloseProc -- * * Closes the IO channel. * * Results: * 0 if successful, the value of errno if failed. * * Side effects: * Closes the physical channel * *---------------------------------------------------------------------- */static intFileCloseProc(instanceData, interp) ClientData instanceData; /* Pointer to FileInfo structure. */ Tcl_Interp *interp; /* Not used. */{ FileInfo *fileInfoPtr = (FileInfo *) instanceData; FileInfo **nextPtrPtr; int errorCode = 0; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * Remove the file from the watch list. */ FileWatchProc(instanceData, 0); /* * Don't close the Win32 handle if the handle is a standard channel * during the exit process. Otherwise, one thread may kill the stdio * of another. */ if (!TclInExit() || ((GetStdHandle(STD_INPUT_HANDLE) != fileInfoPtr->handle) && (GetStdHandle(STD_OUTPUT_HANDLE) != fileInfoPtr->handle) && (GetStdHandle(STD_ERROR_HANDLE) != fileInfoPtr->handle))) { if (CloseHandle(fileInfoPtr->handle) == FALSE) { TclWinConvertError(GetLastError()); errorCode = errno; } } for (nextPtrPtr = &(tsdPtr->firstFilePtr); (*nextPtrPtr) != NULL; nextPtrPtr = &((*nextPtrPtr)->nextPtr)) { if ((*nextPtrPtr) == fileInfoPtr) { (*nextPtrPtr) = fileInfoPtr->nextPtr; break; } } ckfree((char *)fileInfoPtr); return errorCode;}/* *---------------------------------------------------------------------- * * FileSeekProc -- * * Seeks on a file-based channel. Returns the new position. * * Results: * -1 if failed, the new position if successful. If failed, it * also sets *errorCodePtr to the error code. * * Side effects: * Moves the location at which the channel will be accessed in * future operations. * *----------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -