Beispiel #1
0
int
TkWinSend_QueueCommand(
    Tcl_Interp *interp,
    Tcl_Obj *cmdPtr)
{
    SendEvent *evPtr;

    TRACE("SendQueueCommand()\n");

    evPtr = ckalloc(sizeof(SendEvent));
    evPtr->header.proc = SendEventProc;
    evPtr->header.nextPtr = NULL;
    evPtr->interp = interp;
    Tcl_Preserve(evPtr->interp);

    if (Tcl_IsShared(cmdPtr)) {
	evPtr->cmdPtr = Tcl_DuplicateObj(cmdPtr);
    } else {
	evPtr->cmdPtr = cmdPtr;
	Tcl_IncrRefCount(evPtr->cmdPtr);
    }

    Tcl_QueueEvent((Tcl_Event *)evPtr, TCL_QUEUE_TAIL);

    return 0;
}
Beispiel #2
0
void
PgNotifyTransferEvents(Pg_ConnectionId * connid)
{
	PGnotify   *notify;

	while ((notify = PQnotifies(connid->conn)) != NULL)
	{
		NotifyEvent *event = (NotifyEvent *) ckalloc(sizeof(NotifyEvent));

		event->header.proc = Pg_Notify_EventProc;
		event->notify = notify;
		event->connid = connid;
		Tcl_QueueEvent((Tcl_Event *) event, TCL_QUEUE_TAIL);
	}

	/*
	 * This is also a good place to check for unexpected closure of the
	 * connection (ie, backend crash), in which case we must shut down the
	 * notify event source to keep Tcl from trying to select() on the now-
	 * closed socket descriptor.  But don't kill on-connection-loss
	 * events; in fact, register one.
	 */
	if (PQsocket(connid->conn) < 0)
		PgConnLossTransferEvents(connid);
}
Beispiel #3
0
static OSErr
QuitHandler(
    const AppleEvent *event,
    AppleEvent *reply,
    long handlerRefcon)
{
    Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon;
    KillEvent *eventPtr;

    if (interp) {
	/*
	 * Call the exit command from the event loop, since you are not
	 * supposed to call ExitToShell in an Apple Event Handler. We put this
	 * at the head of Tcl's event queue because this message usually comes
	 * when the Mac is shutting down, and we want to kill the shell as
	 * quickly as possible.
	 */

	eventPtr = (KillEvent *) ckalloc(sizeof(KillEvent));
	eventPtr->header.proc = ReallyKillMe;
	eventPtr->interp = interp;

	Tcl_QueueEvent((Tcl_Event *) eventPtr, TCL_QUEUE_HEAD);
    }
    return noErr;
}
Beispiel #4
0
static gboolean tcl_file_callback(GIOChannel *source, GIOCondition condition, gpointer data)
{
	struct tcl_file_handler *tfh = data;
	struct tcl_file_event *fev;
	int mask = 0;

	if (condition & G_IO_IN)
		mask |= TCL_READABLE;
	if (condition & G_IO_OUT)
		mask |= TCL_WRITABLE;
	if (condition & (G_IO_ERR|G_IO_HUP|G_IO_NVAL))
		mask |= TCL_EXCEPTION;

	if (!(tfh->mask & (mask & ~tfh->pending)))
		return TRUE;

	tfh->pending |= mask;
	fev = (struct tcl_file_event *)ckalloc(sizeof(struct tcl_file_event));
	memset(fev, 0, sizeof(struct tcl_file_event));
	fev->header.proc = tcl_file_event_callback;
	fev->fd = tfh->fd;
	Tcl_QueueEvent((Tcl_Event *)fev, TCL_QUEUE_TAIL);

	Tcl_ServiceAll();

	return TRUE;
}
Beispiel #5
0
static void
ConsoleCheckProc(
    ClientData data,		/* Not used. */
    int flags)			/* Event flags as passed to Tcl_DoOneEvent. */
{
    ConsoleInfo *infoPtr;
    int needEvent;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    if (!(flags & TCL_FILE_EVENTS)) {
	return;
    }

    /*
     * Queue events for any ready consoles that don't already have events
     * queued.
     */

    for (infoPtr = tsdPtr->firstConsolePtr; infoPtr != NULL;
	    infoPtr = infoPtr->nextPtr) {
	if (infoPtr->flags & CONSOLE_PENDING) {
	    continue;
	}

	/*
	 * Queue an event if the console is signaled for reading or writing.
	 */

	needEvent = 0;
	if (infoPtr->watchMask & TCL_WRITABLE) {
	    if (WaitForSingleObject(infoPtr->writer.readyEvent,
		    0) != WAIT_TIMEOUT) {
		needEvent = 1;
	    }
	}

	if (infoPtr->watchMask & TCL_READABLE) {
	    if (WaitForRead(infoPtr, 0) >= 0) {
		needEvent = 1;
	    }
	}

	if (needEvent) {
	    ConsoleEvent *evPtr = ckalloc(sizeof(ConsoleEvent));

	    infoPtr->flags |= CONSOLE_PENDING;
	    evPtr->header.proc = ConsoleEventProc;
	    evPtr->infoPtr = infoPtr;
	    Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
	}
    }
}
Beispiel #6
0
static void
FileProc(
    ClientData clientData,
    int *fd,
    XtInputId *id)
{
    FileHandler *filePtr = (FileHandler *)clientData;
    FileHandlerEvent *fileEvPtr;
    int mask = 0;

    /*
     * Determine which event happened.
     */

    if (*id == filePtr->read) {
	mask = TCL_READABLE;
    } else if (*id == filePtr->write) {
	mask = TCL_WRITABLE;
    } else if (*id == filePtr->except) {
	mask = TCL_EXCEPTION;
    }

    /*
     * Ignore unwanted or duplicate events.
     */

    if (!(filePtr->mask & mask) || (filePtr->readyMask & mask)) {
	return;
    }

    /*
     * This is an interesting event, so put it onto the event queue.
     */

    filePtr->readyMask |= mask;
    fileEvPtr = ckalloc(sizeof(FileHandlerEvent));
    fileEvPtr->header.proc = FileHandlerEventProc;
    fileEvPtr->fd = filePtr->fd;
    Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);

    /*
     * Process events on the Tcl event queue before returning to Xt.
     */

    Tcl_ServiceAll();
}
Beispiel #7
0
static void
QueueGrabWindowChange(
    TkDisplay *dispPtr,		/* Display on which to change the grab
				 * window. */
    TkWindow *grabWinPtr)	/* Window that is to become the new grab
				 * window (may be NULL). */
{
    NewGrabWinEvent *grabEvPtr;

    grabEvPtr = (NewGrabWinEvent *) ckalloc(sizeof(NewGrabWinEvent));
    grabEvPtr->header.proc = GrabWinEventProc;
    grabEvPtr->dispPtr = dispPtr;
    if (grabWinPtr == NULL) {
	grabEvPtr->grabWindow = None;
    } else {
	grabEvPtr->grabWindow = grabWinPtr->window;
    }
    Tcl_QueueEvent(&grabEvPtr->header, TCL_QUEUE_MARK);
    dispPtr->eventualGrabWinPtr = grabWinPtr;
}
Beispiel #8
0
static void
TimerCheckProc(
    ClientData data,		/* Not used. */
    int flags)			/* Event flags as passed to Tcl_DoOneEvent. */
{
    Tcl_Event *timerEvPtr;
    Tcl_Time blockTime;
    ThreadSpecificData *tsdPtr = InitTimer();

    if ((flags & TCL_TIMER_EVENTS) && tsdPtr->firstTimerHandlerPtr) {
	/*
	 * Compute the timeout for the next timer on the list.
	 */

	Tcl_GetTime(&blockTime);
	blockTime.sec = tsdPtr->firstTimerHandlerPtr->time.sec - blockTime.sec;
	blockTime.usec = tsdPtr->firstTimerHandlerPtr->time.usec -
		blockTime.usec;
	if (blockTime.usec < 0) {
	    blockTime.sec -= 1;
	    blockTime.usec += 1000000;
	}
	if (blockTime.sec < 0) {
	    blockTime.sec = 0;
	    blockTime.usec = 0;
	}

	/*
	 * If the first timer has expired, stick an event on the queue.
	 */

	if (blockTime.sec == 0 && blockTime.usec == 0 &&
		!tsdPtr->timerPending) {
	    tsdPtr->timerPending = 1;
	    timerEvPtr = ckalloc(sizeof(Tcl_Event));
	    timerEvPtr->proc = TimerHandlerEventProc;
	    Tcl_QueueEvent(timerEvPtr, TCL_QUEUE_TAIL);
	}
    }
}
Beispiel #9
0
/*
 * Handle a connection-loss event
 */
void
PgConnLossTransferEvents(Pg_ConnectionId * connid)
{
	if (connid->notifier_running)
	{
		/* Put the on-connection-loss event in the Tcl queue */
		NotifyEvent *event = (NotifyEvent *) ckalloc(sizeof(NotifyEvent));

		event->header.proc = Pg_Notify_EventProc;
		event->notify = NULL;
		event->connid = connid;
		Tcl_QueueEvent((Tcl_Event *) event, TCL_QUEUE_TAIL);
	}

	/*
	 * Shut down the notify event source to keep Tcl from trying to
	 * select() on the now-closed socket descriptor.  And zap any
	 * unprocessed notify events ... but not, of course, the
	 * connection-loss event.
	 */
	PgStopNotifyEventSource(connid, false);
}
Beispiel #10
0
void DBus_CallResult(DBusPendingCall *pending, void *data)
{
   DBusMessage *msg;
   Tcl_CallData *dataPtr = data;
   Tcl_DBusEvent *evPtr;
   
   msg = dbus_pending_call_steal_reply(pending);
   /* free the pending message handle */
   dbus_pending_call_unref(pending);
   /* Allocate a DBus event structure and copy in some basic data */
   evPtr = (Tcl_DBusEvent *) ckalloc(sizeof(Tcl_DBusEvent));
   evPtr->interp = dataPtr->interp;
   evPtr->script = dataPtr->script;
   evPtr->conn = dataPtr->conn;
   /* Fill in the rest of the DBus event structure */
   evPtr->event.proc = DBus_EventHandler;
   evPtr->msg = msg;
   /* Don't send a reply on the reply */
   evPtr->flags = dataPtr->flags | DBUSFLAG_NOREPLY;
   Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
   /* Free the DBus handler data structure */
   ckfree(data);
}
Beispiel #11
0
DBusHandlerResult DBus_Monitor(DBusConnection *conn, 
	DBusMessage *msg, void *data)
{
   Tcl_DBusEvent *evPtr;
   Tcl_DBusMonitorData* dataPtr = data;

   if (dataPtr->script != NULL) {
      evPtr = (Tcl_DBusEvent *) ckalloc(sizeof(Tcl_DBusEvent));
      /* Storage at *evPtr will be freed by Tcl_ServiceEvent */
      evPtr->event.proc = DBus_EventHandler;
      evPtr->interp = dataPtr->interp;
      evPtr->script = dataPtr->script;
      Tcl_IncrRefCount(evPtr->script);
      evPtr->conn = conn;
      evPtr->msg = msg;
      /* Never report the result of a snoop handler */
      evPtr->flags = dataPtr->flags | DBUSFLAG_NOREPLY;
      dbus_message_ref(msg);
      Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
   }
   /* Allow messages to proceed to invoke methods and signal events */
   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
Beispiel #12
0
int
Tcl_WaitForEvent(
    Tcl_Time *timePtr)		/* Maximum block time, or NULL. */
{
    FileHandler *filePtr;
    FileHandlerEvent *fileEvPtr;
    int mask;
    int waitForFiles;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) {
	return tclStubs.tcl_WaitForEvent(timePtr);
    }

    /*
     * Start notifier thread if necessary.
     */

    LOCK_NOTIFIER_INIT;
    if (!notifierCount) {
        Tcl_Panic("Tcl_WaitForEvent: notifier not initialized");
    }
    if (!notifierThread) {
	int result;
	pthread_attr_t attr;

	pthread_attr_init(&attr);
	pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
	pthread_attr_setstacksize(&attr, 60 * 1024);
	result = pthread_create(&notifierThread, &attr,
		(void * (*)(void *))NotifierThreadProc, NULL);
	pthread_attr_destroy(&attr);
	if (result || !notifierThread) {
	    Tcl_Panic("Tcl_WaitForEvent: unable to start notifier thread");
	}
    }
    UNLOCK_NOTIFIER_INIT;

    /*
     * Place this thread on the list of interested threads, signal the
     * notifier thread, and wait for a response or a timeout.
     */

    LOCK_NOTIFIER;
    if (!tsdPtr->runLoop) {
        Tcl_Panic("Tcl_WaitForEvent: CFRunLoop not initialized");
    }
    waitForFiles = (tsdPtr->numFdBits > 0);
    if (timePtr != NULL && timePtr->sec == 0 && timePtr->usec == 0) {
	/*
	 * Cannot emulate a polling select with a polling condition variable.
	 * Instead, pretend to wait for files and tell the notifier thread
	 * what we are doing. The notifier thread makes sure it goes through
	 * select with its select mask in the same state as ours currently is.
	 * We block until that happens.
	 */

	waitForFiles = 1;
	tsdPtr->pollState = POLL_WANT;
	timePtr = NULL;
    } else {
	tsdPtr->pollState = 0;
    }

    if (waitForFiles) {
	/*
	 * Add the ThreadSpecificData structure of this thread to the list of
	 * ThreadSpecificData structures of all threads that are waiting on
	 * file events.
	 */

	tsdPtr->nextPtr = waitingListPtr;
	if (waitingListPtr) {
	    waitingListPtr->prevPtr = tsdPtr;
	}
	tsdPtr->prevPtr = 0;
	waitingListPtr = tsdPtr;
	tsdPtr->onList = 1;

	write(triggerPipe, "", 1);
    }

    FD_ZERO(&(tsdPtr->readyMasks.readable));
    FD_ZERO(&(tsdPtr->readyMasks.writable));
    FD_ZERO(&(tsdPtr->readyMasks.exceptional));

    if (!tsdPtr->eventReady) {
	CFTimeInterval waitTime;
	CFStringRef runLoopMode;

	if (timePtr == NULL) {
	    waitTime = 1.0e10; /* Wait forever, as per CFRunLoop.c */
	} else {
	    waitTime = timePtr->sec + 1.0e-6 * timePtr->usec;
	}
	/*
	 * If the run loop is already running (e.g. if Tcl_WaitForEvent was
	 * called recursively), re-run it in a custom run loop mode containing
	 * only the source for the notifier thread, otherwise wakeups from other
	 * sources added to the common run loop modes might get lost.
	 */
	if ((runLoopMode = CFRunLoopCopyCurrentMode(tsdPtr->runLoop))) {
	    CFRelease(runLoopMode);
	    runLoopMode = tclEventsOnlyRunLoopMode;
	} else {
	    runLoopMode = kCFRunLoopDefaultMode;
	}
	UNLOCK_NOTIFIER;
	CFRunLoopRunInMode(runLoopMode, waitTime, TRUE);
	LOCK_NOTIFIER;
    }
    tsdPtr->eventReady = 0;

    if (waitForFiles && tsdPtr->onList) {
	/*
	 * Remove the ThreadSpecificData structure of this thread from the
	 * waiting list. Alert the notifier thread to recompute its select
	 * masks - skipping this caused a hang when trying to close a pipe
	 * which the notifier thread was still doing a select on.
	 */

	if (tsdPtr->prevPtr) {
	    tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
	} else {
	    waitingListPtr = tsdPtr->nextPtr;
	}
	if (tsdPtr->nextPtr) {
	    tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
	}
	tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;
	tsdPtr->onList = 0;
	write(triggerPipe, "", 1);
    }

    /*
     * Queue all detected file events before returning.
     */

    for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL);
	    filePtr = filePtr->nextPtr) {

	mask = 0;
	if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.readable))) {
	    mask |= TCL_READABLE;
	}
	if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.writable))) {
	    mask |= TCL_WRITABLE;
	}
	if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.exceptional))) {
	    mask |= TCL_EXCEPTION;
	}

	if (!mask) {
	    continue;
	}

	/*
	 * Don't bother to queue an event if the mask was previously non-zero
	 * since an event must still be on the queue.
	 */

	if (filePtr->readyMask == 0) {
	    fileEvPtr = (FileHandlerEvent *) ckalloc(sizeof(FileHandlerEvent));
	    fileEvPtr->header.proc = FileHandlerEventProc;
	    fileEvPtr->fd = filePtr->fd;
	    Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
	}
	filePtr->readyMask = mask;
    }
    UNLOCK_NOTIFIER;
    return 0;
}
Beispiel #13
0
DBusHandlerResult DBus_Message(DBusConnection *conn, 
	DBusMessage *msg, void *data)
{
   Tcl_HashTable *members;
   Tcl_HashEntry *memberPtr;
   Tcl_HashSearch search;
   Tcl_DBusEvent *evPtr;
   Tcl_DBusMethodData *mPtr = NULL;
   Tcl_DBusSignalData *sPtr;
   DBusMessage *err;
   int i, len;
   char buffer[DBUS_MAXIMUM_NAME_LENGTH + 1], *errbuf;
   const char *path, *name, *intf, *str[2];
   Tcl_DBusHandlerData* dataPtr = data;

   path = dbus_message_get_path(msg);
   intf = dbus_message_get_interface(msg);
   name = dbus_message_get_member(msg);
   if (intf != NULL) {
      intf = strncpy(buffer, intf, DBUS_MAXIMUM_NAME_LENGTH);
      buffer[DBUS_MAXIMUM_NAME_LENGTH] = '\0';
      len = strlen(intf);
      buffer[len++] = '.';
      name = strncpy(buffer + len, name, DBUS_MAXIMUM_NAME_LENGTH - len);
   }
   switch (dbus_message_get_type(msg)) {
    case DBUS_MESSAGE_TYPE_METHOD_CALL:
      if (intf != NULL) {
	 mPtr = DBus_FindListeners(dataPtr->dbus, path, intf, TRUE);
	 if (mPtr == NULL) {
	    /* Check if a method was defined without a path */
	    mPtr = DBus_FindListeners(dataPtr->dbus, "", intf, TRUE);
	 }
      }
      if (intf == NULL || mPtr == NULL) {
	 /* TODO: Method calls are not required to specify an interface */
	 /* So should really also check for *.name if intf == NULL */

	 /* Check if a method was defined without an interface */
	 mPtr = DBus_FindListeners(dataPtr->dbus, path, name, TRUE);
	 if (mPtr == NULL) {
	    /* Check if a method was defined with no path and no interface */
	    mPtr = DBus_FindListeners(dataPtr->dbus, "", name, TRUE);
	 }
      }
      if (mPtr == NULL) {
	  /* Check if an unknown handler was defined for the path */
	  mPtr = DBus_FindListeners(dataPtr->dbus, path, "", TRUE);
	  if (mPtr == NULL) {
	      /* Check if a global unknown handler was defined */
	      mPtr = DBus_FindListeners(dataPtr->dbus, "", "", TRUE);
	  }
      }
      if (mPtr == NULL) {
	  /* There is no script-level handler for this method call */
	  if (dbus_message_get_no_reply(msg))
	    /* The caller is not interested in succes or failure */
	    break;
	  /* Allocate space and construct the error message */
	  /* Each of name, interface, and signature can only be 255 chars */
	  /* long, but path is unlimited. So base the amount of space */
	  /* to request on the length of the path string */
	  if ((errbuf = attemptckalloc(strlen(path) + 1024)) != NULL) {
	      sprintf(errbuf, "No such method '%s' in interface '%s' "
		      "at object path '%s' (signature '%s')",
		      name, dbus_message_get_interface(msg),
		      path, dbus_message_get_signature(msg));
	  }
	  /* Send the error back to the caller */
	  err = dbus_message_new_error(msg, DBUS_ERROR_UNKNOWN_METHOD, errbuf);
	  if (dbus_connection_send(conn, err, NULL)) {
	      dbus_connection_flush(conn);
	  }
	  /* Free up the used resources */
	  dbus_message_unref(err);
	  if (errbuf != NULL) ckfree(errbuf);
	  break;
      }
      evPtr = (Tcl_DBusEvent *) ckalloc(sizeof(Tcl_DBusEvent));
      evPtr->event.proc = DBus_EventHandler;
      evPtr->interp = mPtr->interp;
      evPtr->script = mPtr->script;
      Tcl_IncrRefCount(evPtr->script);
      evPtr->conn = mPtr->conn;
      evPtr->msg = msg;
      evPtr->flags = mPtr->flags;
      dbus_message_ref(msg);
      if (dbus_message_get_no_reply(msg))
	/* Don't report the result of the event handler */
	evPtr->flags |= DBUSFLAG_NOREPLY;
      Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
      break;
    case DBUS_MESSAGE_TYPE_METHOD_RETURN:
      break;
    case DBUS_MESSAGE_TYPE_ERROR:
      break;
    case DBUS_MESSAGE_TYPE_SIGNAL:
      str[0] = intf; str[1] = name;
      for (i = 0; i < 2; i++) {
	 if (str[i] == NULL) continue;
	 members = DBus_FindListeners(dataPtr->dbus, path, str[i], FALSE);
	 if (members == NULL) {
	    members = DBus_FindListeners(dataPtr->dbus, "", str[i], FALSE);
	    if (members == NULL) continue;
	 }
	 /* Queue execution of listeners for this signal in all interpreters */
	 for (memberPtr = Tcl_FirstHashEntry(members, &search);
	      memberPtr != NULL; memberPtr = Tcl_NextHashEntry(&search)) {
	    evPtr = (Tcl_DBusEvent *) ckalloc(sizeof(Tcl_DBusEvent));
	    sPtr = (Tcl_DBusSignalData *) Tcl_GetHashValue(memberPtr);
	    evPtr->event.proc = DBus_EventHandler;
	    evPtr->interp = (Tcl_Interp *) Tcl_GetHashKey(members, memberPtr);
	    evPtr->script = sPtr->script;
	    Tcl_IncrRefCount(evPtr->script);
	    evPtr->conn = conn;
	    evPtr->msg = msg;
	    /* Never report the result of a signal handler */
	    evPtr->flags = sPtr->flags | DBUSFLAG_NOREPLY;
	    dbus_message_ref(msg);
	    Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
	 }
      }
      break;
   }
   return DBUS_HANDLER_RESULT_HANDLED;
}