Exemplo n.º 1
0
/*++

FreeState

    Deletes hash tables and frees state structure.

Arguments:
    state      - Pointer to a "ExtState" structure.

    removeCmds - Remove registered commands.

    removeProc - Remove the interp deletion callback.

Return Value:
    None.

--*/
static void
FreeState(
    ExtState *state,
    int removeCmds,
    int removeProc
    )
{
    assert(state != NULL);
    DebugPrint("FreeState: state=%p state->interp=%p removeCmds=%d removeProc=%d\n",
        state, state->interp, removeCmds, removeProc);

    if (removeCmds) {
        int i;
        for (i = 0; i < ARRAYSIZE(state->cmds); i++) {
            if (state->cmds[i] == NULL) {
                continue;
            }
            Tcl_DeleteCommandFromToken(state->interp, state->cmds[i]);
        }
    }

    if (removeProc) {
        Tcl_DontCallWhenDeleted(state->interp, InterpDeleted, (ClientData)state);
    }

    // Free hash tables.
    CryptCloseHandles(state->cryptTable);
    Tcl_DeleteHashTable(state->cryptTable);
    ckfree((char *)state->cryptTable);

#ifndef _WINDOWS
    GlCloseHandles(state->glftpdTable);
    Tcl_DeleteHashTable(state->glftpdTable);
    ckfree((char *)state->glftpdTable);
#endif

    ckfree((char *)state);
}
Exemplo n.º 2
0
/*
 * Remove a connection Id from the hash table and
 * close all portals the user forgot.
 */
int
PgDelConnectionId(DRIVER_DEL_PROTO)
{
	Tcl_HashEntry *entry;
	Tcl_HashSearch hsearch;
	Pg_ConnectionId *connid;
	Pg_TclNotifies *notifies;
	int			i;

	connid = (Pg_ConnectionId *) cData;

	for (i = 0; i < connid->res_max; i++)
	{
		if (connid->results[i])
			PQclear(connid->results[i]);
	}
	ckfree((void *) connid->results);

	/* Release associated notify info */
	while ((notifies = connid->notify_list) != NULL)
	{
		connid->notify_list = notifies->next;
		for (entry = Tcl_FirstHashEntry(&notifies->notify_hash, &hsearch);
			 entry != NULL;
			 entry = Tcl_NextHashEntry(&hsearch))
			ckfree((char *) Tcl_GetHashValue(entry));
		Tcl_DeleteHashTable(&notifies->notify_hash);
		if (notifies->conn_loss_cmd)
			ckfree((void *) notifies->conn_loss_cmd);
		if (notifies->interp)
			Tcl_DontCallWhenDeleted(notifies->interp, PgNotifyInterpDelete,
									(ClientData) notifies);
		ckfree((void *) notifies);
	}

	/*
	 * Turn off the Tcl event source for this connection, and delete any
	 * pending notify and connection-loss events.
	 */
	PgStopNotifyEventSource(connid, true);

	/* Close the libpq connection too */
	PQfinish(connid->conn);
	connid->conn = NULL;

	/*
	 * Kill the notifier channel, too.	We must not do this until after
	 * we've closed the libpq connection, because Tcl will try to close
	 * the socket itself!
	 *
	 * XXX Unfortunately, while this works fine if we are closing due to
	 * explicit pg_disconnect, all Tcl versions through 8.4.1 dump core if
	 * we try to do it during interpreter shutdown.  Not clear why. For
	 * now, we kill the channel during pg_disconnect, but during interp
	 * shutdown we just accept leakage of the (fairly small) amount of
	 * memory taken for the channel state representation. (Note we are not
	 * leaking a socket, since libpq closed that already.) We tell the
	 * difference between pg_disconnect and interpreter shutdown by
	 * testing for interp != NULL, which is an undocumented but apparently
	 * safe way to tell.
	 */
#if TCL_MAJOR_VERSION >= 8
	if (connid->notifier_channel != NULL && interp != NULL)
		Tcl_UnregisterChannel(NULL, connid->notifier_channel);
#endif

	/*
	 * We must use Tcl_EventuallyFree because we don't want the connid
	 * struct to vanish instantly if Pg_Notify_EventProc is active for it.
	 * (Otherwise, closing the connection from inside a pg_listen callback
	 * could lead to coredump.)  Pg_Notify_EventProc can detect that the
	 * connection has been deleted from under it by checking connid->conn.
	 */
	Tcl_EventuallyFree((ClientData) connid, TCL_DYNAMIC);

	return 0;
}