⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tclio.c

📁 linux系统下的音频通信
💻 C
📖 第 1 页 / 共 5 页
字号:
                (chanPtr->flags & BG_FLUSH_SCHEDULED)) {            return 0;        }        /*         * If the output queue is still empty, break out of the while loop.         */        if (bufPtr == (ChannelBuffer *) NULL) {            break;	/* Out of the "while (1)". */        }        /*         * Produce the output on the channel.         */                toWrite = bufPtr->nextAdded - bufPtr->nextRemoved;        written = (chanPtr->typePtr->outputProc) (chanPtr->instanceData,                bufPtr->buf + bufPtr->nextRemoved, toWrite, &errorCode);            	/*         * If the write failed completely attempt to start the asynchronous         * flush mechanism and break out of this loop - do not attempt to         * write any more output at this time.         */        if (written < 0) {                        /*             * If the last attempt to write was interrupted, simply retry.             */                        if (errorCode == EINTR) {                errorCode = 0;                continue;            }            /*             * If the channel is non-blocking and we would have blocked,             * start a background flushing handler and break out of the loop.             */            if ((errorCode == EWOULDBLOCK) || (errorCode == EAGAIN)) {		if (chanPtr->flags & CHANNEL_NONBLOCKING) {		    if (!(chanPtr->flags & BG_FLUSH_SCHEDULED)) {			chanPtr->flags |= BG_FLUSH_SCHEDULED;			UpdateInterest(chanPtr);                    }                    errorCode = 0;                    break;		} else {		    panic("Blocking channel driver did not block on output");                }            }            /*             * Decide whether to report the error upwards or defer it.             */            if (calledFromAsyncFlush) {                if (chanPtr->unreportedError == 0) {                    chanPtr->unreportedError = errorCode;                }            } else {                Tcl_SetErrno(errorCode);		if (interp != NULL) {		    Tcl_SetResult(interp,			    Tcl_PosixError(interp), TCL_VOLATILE);		}            }            /*             * When we get an error we throw away all the output             * currently queued.             */            DiscardOutputQueued(chanPtr);            continue;        }        bufPtr->nextRemoved += written;        /*         * If this buffer is now empty, recycle it.         */        if (bufPtr->nextRemoved == bufPtr->nextAdded) {            chanPtr->outQueueHead = bufPtr->nextPtr;            if (chanPtr->outQueueHead == (ChannelBuffer *) NULL) {                chanPtr->outQueueTail = (ChannelBuffer *) NULL;            }            RecycleBuffer(chanPtr, bufPtr, 0);        }    }	/* Closes "while (1)". */        /*     * If the queue became empty and we have the asynchronous flushing     * mechanism active, cancel the asynchronous flushing.     */    if ((chanPtr->outQueueHead == (ChannelBuffer *) NULL) &&            (chanPtr->flags & BG_FLUSH_SCHEDULED)) {        chanPtr->flags &= (~(BG_FLUSH_SCHEDULED));	(chanPtr->typePtr->watchProc)(chanPtr->instanceData,		chanPtr->interestMask);    }    /*     * If the channel is flagged as closed, delete it when the refCount     * drops to zero, the output queue is empty and there is no output     * in the current output buffer.     */    if ((chanPtr->flags & CHANNEL_CLOSED) && (chanPtr->refCount <= 0) &&            (chanPtr->outQueueHead == (ChannelBuffer *) NULL) &&            ((chanPtr->curOutPtr == (ChannelBuffer *) NULL) ||                    (chanPtr->curOutPtr->nextAdded ==                            chanPtr->curOutPtr->nextRemoved))) {        return CloseChannel(interp, chanPtr, errorCode);    }    return errorCode;}/* *---------------------------------------------------------------------- * * CloseChannel -- * *	Utility procedure to close a channel and free its associated *	resources. * * Results: *	0 on success or a POSIX error code if the operation failed. * * Side effects: *	May close the actual channel; may free memory. * *---------------------------------------------------------------------- */static intCloseChannel(interp, chanPtr, errorCode)    Tcl_Interp *interp;			/* For error reporting. */    Channel *chanPtr;			/* The channel to close. */    int errorCode;			/* Status of operation so far. */{    int result = 0;			/* Of calling driver close                                         * operation. */    Channel *prevChanPtr;		/* Preceding channel in list of                                         * all channels - used to splice a                                         * channel out of the list on close. */            if (chanPtr == NULL) {        return result;    }        /*     * No more input can be consumed so discard any leftover input.     */    DiscardInputQueued(chanPtr, 1);    /*     * Discard a leftover buffer in the current output buffer field.     */    if (chanPtr->curOutPtr != (ChannelBuffer *) NULL) {        ckfree((char *) chanPtr->curOutPtr);        chanPtr->curOutPtr = (ChannelBuffer *) NULL;    }        /*     * The caller guarantees that there are no more buffers     * queued for output.     */    if (chanPtr->outQueueHead != (ChannelBuffer *) NULL) {        panic("TclFlush, closed channel: queued output left");    }    /*     * If the EOF character is set in the channel, append that to the     * output device.     */    if ((chanPtr->outEofChar != 0) && (chanPtr->flags & TCL_WRITABLE)) {        int dummy;        char c;        c = (char) chanPtr->outEofChar;        (chanPtr->typePtr->outputProc) (chanPtr->instanceData, &c, 1, &dummy);    }    /*     * Remove TCL_READABLE and TCL_WRITABLE from chanPtr->flags, so     * that close callbacks can not do input or output (assuming they     * squirreled the channel away in their clientData). This also     * prevents infinite loops if the callback calls any C API that     * could call FlushChannel.     */    chanPtr->flags &= (~(TCL_READABLE|TCL_WRITABLE));            /*     * Splice this channel out of the list of all channels.     */    if (chanPtr == firstChanPtr) {        firstChanPtr = chanPtr->nextChanPtr;    } else {        for (prevChanPtr = firstChanPtr;                 (prevChanPtr != (Channel *) NULL) &&                     (prevChanPtr->nextChanPtr != chanPtr);                 prevChanPtr = prevChanPtr->nextChanPtr) {            /* Empty loop body. */        }        if (prevChanPtr == (Channel *) NULL) {            panic("FlushChannel: damaged channel list");        }        prevChanPtr->nextChanPtr = chanPtr->nextChanPtr;    }    /*     * OK, close the channel itself.     */            result = (chanPtr->typePtr->closeProc) (chanPtr->instanceData, interp);        if (chanPtr->channelName != (char *) NULL) {        ckfree(chanPtr->channelName);    }        /*     * If we are being called synchronously, report either     * any latent error on the channel or the current error.     */            if (chanPtr->unreportedError != 0) {        errorCode = chanPtr->unreportedError;    }    if (errorCode == 0) {        errorCode = result;        if (errorCode != 0) {            Tcl_SetErrno(errorCode);        }    }    /*     * Cancel any outstanding timer.     */    Tcl_DeleteTimerHandler(chanPtr->timer);    /*     * Mark the channel as deleted by clearing the type structure.     */    chanPtr->typePtr = NULL;    Tcl_EventuallyFree((ClientData) chanPtr, TCL_DYNAMIC);    return errorCode;}/* *---------------------------------------------------------------------- * * Tcl_Close -- * *	Closes a channel. * * Results: *	A standard Tcl result. * * Side effects: *	Closes the channel if this is the last reference. * * NOTE: *	Tcl_Close removes the channel as far as the user is concerned. *	However, it may continue to exist for a while longer if it has *	a background flush scheduled. The device itself is eventually *	closed and the channel record removed, in CloseChannel, above. * *---------------------------------------------------------------------- */	/* ARGSUSED */intTcl_Close(interp, chan)    Tcl_Interp *interp;			/* Interpreter for errors. */    Tcl_Channel chan;			/* The channel being closed. Must                                         * not be referenced in any                                         * interpreter. */{    ChannelHandler *chPtr, *chNext;	/* Iterate over channel handlers. */    CloseCallback *cbPtr;		/* Iterate over close callbacks                                         * for this channel. */    EventScriptRecord *ePtr, *eNextPtr;	/* Iterate over eventscript records. */    Channel *chanPtr;			/* The real IO channel. */    int result;				/* Of calling FlushChannel. */    NextChannelHandler *nhPtr;    if (chan == (Tcl_Channel) NULL) {        return TCL_OK;    }        /*     * Perform special handling for standard channels being closed. If the     * refCount is now 1 it means that the last reference to the standard     * channel is being explicitly closed, so bump the refCount down     * artificially to 0. This will ensure that the channel is actually     * closed, below. Also set the static pointer to NULL for the channel.     */    CheckForStdChannelsBeingClosed(chan);    chanPtr = (Channel *) chan;    if (chanPtr->refCount > 0) {        panic("called Tcl_Close on channel with refCount > 0");    }    /*     * Remove any references to channel handlers for this channel that     * may be about to be invoked.     */    for (nhPtr = nestedHandlerPtr;             nhPtr != (NextChannelHandler *) NULL;             nhPtr = nhPtr->nestedHandlerPtr) {        if (nhPtr->nextHandlerPtr &&		(nhPtr->nextHandlerPtr->chanPtr == chanPtr)) {	    nhPtr->nextHandlerPtr = NULL;        }    }    /*     * Remove all the channel handler records attached to the channel     * itself.     */            for (chPtr = chanPtr->chPtr;             chPtr != (ChannelHandler *) NULL;             chPtr = chNext) {        chNext = chPtr->nextPtr;        ckfree((char *) chPtr);    }    chanPtr->chPtr = (ChannelHandler *) NULL;            /*     * Cancel any pending copy operation.     */    StopCopy(chanPtr->csPtr);    /*     * Must set the interest mask now to 0, otherwise infinite loops     * will occur if Tcl_DoOneEvent is called before the channel is     * finally deleted in FlushChannel. This can happen if the channel     * has a background flush active.     */            chanPtr->interestMask = 0;        /*     * Remove any EventScript records for this channel.     */    for (ePtr = chanPtr->scriptRecordPtr;             ePtr != (EventScriptRecord *) NULL;             ePtr = eNextPtr) {        eNextPtr = ePtr->nextPtr;	ckfree(ePtr->script);        ckfree((char *) ePtr);    }    chanPtr->scriptRecordPtr = (EventScriptRecord *) NULL;            /*     * Invoke the registered close callbacks and delete their records.     */    while (chanPtr->closeCbPtr != (CloseCallback *) NULL) {        cbPtr = chanPtr->closeCbPtr;        chanPtr->closeCbPtr = cbPtr->nextPtr;        (cbPtr->proc) (cbPtr->clientData);        ckfree((char *) cbPtr);    }    /*     * Ensure that the last output buffer will be flushed.     */        if ((chanPtr->curOutPtr != (ChannelBuffer *) NULL) &&           (chanPtr->curOutPtr->nextAdded > chanPtr->curOutPtr->nextRemoved)) {        chanPtr->flags |= BUFFER_READY;    }    /*     * The call to FlushChannel will flush any queued output and invoke     * the close function of the channel driver, or it will set up the     * channel to be flushed and closed asynchronously.     */        chanPtr->flags |= CHANNEL_CLOSED;    result = Flu

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -