/*++ 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); }
/* * 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(¬ifies->notify_hash, &hsearch); entry != NULL; entry = Tcl_NextHashEntry(&hsearch)) ckfree((char *) Tcl_GetHashValue(entry)); Tcl_DeleteHashTable(¬ifies->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; }