From 5050658ae4d134f2fc808d9a47433f85aef0900a Mon Sep 17 00:00:00 2001
From: "Stephen R. van den Berg" <srb@cuci.nl>
Date: Sun, 16 Dec 2018 11:14:34 +0100
Subject: [PATCH] pgsql: Autoterminate dangling database connections at program
 exit.

---
 lib/modules/Sql.pmod/pgsql_util.pmod | 26 +++++++++++++++-----------
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/lib/modules/Sql.pmod/pgsql_util.pmod b/lib/modules/Sql.pmod/pgsql_util.pmod
index 6799aa42c2..645b494dae 100644
--- a/lib/modules/Sql.pmod/pgsql_util.pmod
+++ b/lib/modules/Sql.pmod/pgsql_util.pmod
@@ -84,7 +84,7 @@ final Pike.Backend local_backend;
 private Pike.Backend cb_backend;
 private sql_result qalreadyprinted;
 private Thread.Mutex backendmux = Thread.Mutex();
-private Thread.ResourceCount clientsregistered = Thread.ResourceCount();
+final multiset(proxy) clients = set_weak_flag((<>), Pike.WEAK);
 
 constant emptyarray = ({});
 constant describenodata
@@ -147,11 +147,17 @@ private void default_backend_runs() {		// Runs as soon as the
 }
 
 private void create() {
+  atexit(destroy);
   // Run callbacks from our local_backend until DefaultBackend has started
   cb_backend = local_backend = Pike.SmallBackend();
   call_out(default_backend_runs, 0);
 }
 
+private void destroy() {
+  foreach (clients; proxy client; )
+    destruct(client);
+}
+
 private Regexp iregexp(string expr) {
   Stdio.Buffer ret = Stdio.Buffer();
   foreach (expr; ; int c)
@@ -178,7 +184,7 @@ private void run_local_backend() {
     looponce = 0;
     if (lock = backendmux->trylock()) {
       PD("Starting local backend\n");
-      while (!clientsregistered->drained()	// Autoterminate when not needed
+      while (sizeof(clients)    		// Autoterminate when not needed
        || sizeof(local_backend->call_out_info())) {
         mixed err;
         if (err = catch(local_backend(4096.0)))
@@ -186,19 +192,18 @@ private void run_local_backend() {
       }
       PD("Terminating local backend\n");
       lock = 0;
-      looponce = !clientsregistered->drained();
+      looponce = sizeof(clients);
     }
   } while (looponce);
 }
 
 //! Registers yourself as a user of this backend.  If the backend
 //! has not been started yet, it will be spawned automatically.
-final Thread.ResourceCountKey register_backend() {
-  int startbackend = clientsregistered->drained();
-  Thread.ResourceCountKey key = clientsregistered->acquire();
+final void register_backend(proxy client) {
+  int startbackend = !sizeof(clients);
+  clients[client] = 1;
   if (startbackend)
     Thread.Thread(run_local_backend);
-  return key;
 }
 
 final void throwdelayederror(sql_result|proxy parent) {
@@ -1718,7 +1723,6 @@ class proxy {
   final MUTEX unnamedportalmux;
   final MUTEX unnamedstatement;
   private Thread.MutexKey termlock;
-  private Thread.ResourceCountKey backendreg;
   final Thread.ResourceCount portalsinflight, statementsinflight;
   final int(0..1) wasparallelisable;
   final int(0..1) intransaction;
@@ -1783,7 +1787,7 @@ class proxy {
 
     if (!port)
       port = PGSQL_DEFAULT_PORT;
-    backendreg = register_backend();
+    register_backend(this);
     shortmux = MUTEX();
     PD("Connect\n");
     waitforauthready = Thread.Condition();
@@ -2544,7 +2548,7 @@ class proxy {
       if (err == MAGICTERMINATE) { // Announce connection termination to server
         catch {
           void|bufcon|conxsess cs = ci->start();
-          CHAIN(cs)->add("X\0\0\0\4");
+          CHAIN(cs)->add(PGSYNC)->add("X\0\0\0\4");
           cs->sendcmd(SENDOUT);
         };
         terminating = 1;
@@ -2612,7 +2616,7 @@ class proxy {
   private void destroy() {
     string errstring;
     mixed err = catch(close());
-    backendreg = 0;
+    clients[this] = 0;
     if (untolderror) {
       /*
        * Flush out any asynchronously reported errors to stderr; because we are
-- 
GitLab