]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Begin use of a resource manager for CLI.
authorlarrybr <larrybr@noemail.net>
Wed, 10 May 2023 09:51:51 +0000 (09:51 +0000)
committerlarrybr <larrybr@noemail.net>
Wed, 10 May 2023 09:51:51 +0000 (09:51 +0000)
FossilOrigin-Name: 1527d429d66505d4f4bb8635c4d9d7ab926037b136554605d67835ee5d19d2de

manifest
manifest.uuid
src/resmanage.c [new file with mode: 0644]
src/resmanage.h [new file with mode: 0644]

index 7933776880a47c2c200f87aa1cb3fb8968ace297..75d0dd1b33cafcc9333bd0d57317adf55091462f 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Get\sTCL\sextension\sto\sbuild\sand\sextensible\sshell\stests\sto\spass.
-D 2023-05-10T00:45:17.703
+C Begin\suse\sof\sa\sresource\smanager\sfor\sCLI.
+D 2023-05-10T09:51:51.040
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -637,6 +637,8 @@ F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
 F src/prepare.c 6350675966bd0e7ac3a464af9dbfe26db6f0d4237f4e1f1acdb17b12ad371e6e
 F src/printf.c b9320cdbeca0b336c3f139fd36dd121e4167dd62b35fbe9ccaa9bab44c0af38d
 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
+F src/resmanage.c 1af14f7ee7a1ae77f1cd21214661912d6cbd786e33e9c303e2aa272d6fd86de0
+F src/resmanage.h 63778a96198495727b40579291341fbe2a631bf8082e5be906f3a6b1e6b89f2f
 F src/resolve.c 3e53e02ce87c9582bd7e7d22f13f4094a271678d9dc72820fa257a2abb5e4032
 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
 F src/select.c f9333ef8181192c22662f5cb8d257efc4a2880f9ee4853c6c4616f783d27e1b5
@@ -2077,8 +2079,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 76734a4b6c61ab004703df40e2197e4f6e5c0b3d5937aed7ea41193ebe2721a1
-R e17d2c7e426cf79f5b6c9ff2d31408ec
+P 05ecd8a59ec576d4afe7f8785bdcc052c0887b7a5933783a832895b8c40cdeb9
+R 87fb9edd1be1a9bd6d2d5e412cb26bac
 U larrybr
-Z c2f2477a954fb9c881959c41cc321353
+Z 1047f910d7d5ef2b2fd5d09f9bd5a949
 # Remove this line to create a well-formed Fossil manifest.
index 938c02edf934d71767660fd83f45a8a2278d1dd6..fa3275e3f6850428afaa8c2eb5ae96361c90c08c 100644 (file)
@@ -1 +1 @@
-05ecd8a59ec576d4afe7f8785bdcc052c0887b7a5933783a832895b8c40cdeb9
\ No newline at end of file
+1527d429d66505d4f4bb8635c4d9d7ab926037b136554605d67835ee5d19d2de
\ No newline at end of file
diff --git a/src/resmanage.c b/src/resmanage.c
new file mode 100644 (file)
index 0000000..f9aeda3
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+** 2023 May 8
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file implements a simple resource management package, interface
+** and function of which is described in resmanage.h .
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <assert.h>
+#include "resmanage.h"
+
+/* Track how to free various held resources. */
+typedef enum FreeableResourceKind {
+  FRK_Malloc = 0, FRK_DbConn = 1, FRK_DbStmt = 2,
+  FRK_DbMem = 3, FRK_File = 4,
+#if (!defined(_WIN32) && !defined(WIN32)) || !SQLITE_OS_WINRT
+  FRK_Pipe,
+#endif
+  FRK_CustomBase /* series of values for custom freers */
+} FreeableResourceKind;
+
+#if defined(_WIN32) || defined(WIN32)
+# if !SQLITE_OS_WINRT
+#  include <io.h>
+#  include <fcntl.h>
+#  undef pclose
+#  define pclose _pclose
+# endif
+#else
+extern int pclose(FILE*);
+#endif
+
+typedef struct ResourceHeld {
+  union {
+    void *p_any;
+    void *p_malloced;
+    sqlite3 *p_conn;
+    sqlite3_stmt *p_stmt;
+    void *p_s3mem;
+    FILE *p_stream;
+  } held;
+  FreeableResourceKind frk;
+} ResourceHeld;
+
+/* The held-resource stack. This is for single-threaded use only. */
+static ResourceHeld *pResHold = 0;
+static unsigned short numResHold = 0;
+static unsigned short numResAlloc = 0;
+
+/* A small set of custom freers. It is linearly searched, used for
+** layered heap-allocated (and other-allocated) data structures, so
+** tends to have use limited to where slow things are happening.
+*/
+static unsigned short numCustom = 0; /* number of the set */
+static unsigned short numCustomAlloc = 0; /* allocated space */
+typedef void (*FreerFunction)(void *);
+static FreerFunction *aCustomFreers = 0; /* content of set */
+
+/* Info recorded in support of quit_moan(...) and stack-ripping */
+static ResourceMark exit_mark = 0;
+#ifndef SHELL_OMIT_LONGJMP
+static jmp_buf *p_exit_ripper = 0;
+#endif
+
+/* Implementation per header comment */
+ResourceMark holder_mark(){
+  return numResHold;
+}
+
+/* Implementation per header comment */
+void quit_moan(const char *zMoan, int errCode){
+  if( zMoan ){
+    fprintf(stderr, "Quitting due to %s, freeing %d resources.\n",
+            zMoan, numResHold);
+  }
+  holder_free(exit_mark);
+#ifndef SHELL_OMIT_LONGJMP
+  if( p_exit_ripper!=0 ){
+    longjmp(*p_exit_ripper, errCode);
+  } else
+#endif
+    exit(errCode);
+}
+
+/* Free a single resource item. (ignorant of stack) */
+static void free_rk( ResourceHeld *pRH ){
+  if( pRH->held.p_any == 0 ) return;
+  switch( pRH->frk ){
+  case FRK_Malloc:
+    free(pRH->held.p_malloced);
+    break;
+  case FRK_DbConn:
+    sqlite3_close_v2(pRH->held.p_conn);
+    break;
+  case FRK_DbStmt:
+    sqlite3_clear_bindings(pRH->held.p_stmt);
+    sqlite3_finalize(pRH->held.p_stmt);
+    break;
+  case FRK_DbMem:
+    sqlite3_free(pRH->held.p_s3mem);
+    break;
+  case FRK_File:
+    fclose(pRH->held.p_stream);
+    break;
+#if (!defined(_WIN32) && !defined(WIN32)) || !SQLITE_OS_WINRT
+  case FRK_Pipe:
+    pclose(pRH->held.p_stream);
+    break;
+#endif
+  default:
+    {
+      int ck = pRH->frk - FRK_CustomBase;
+      assert(ck>=0);
+      if( ck < numCustom ){
+        aCustomFreers[ck]( pRH->held.p_any );
+      }
+    }
+  }
+  pRH->held.p_any = 0;
+}
+
+void* take_held(ResourceMark mark, unsigned short offset){
+  unsigned short rix = mark + offset;
+  if( rix < numResHold && numResHold > 0 ){
+    void *rv = pResHold[rix].held.p_any;
+    pResHold[rix].held.p_any = 0;
+    return rv;
+  }else return 0;
+}
+
+/* Shared resource-stack pushing code */
+static void res_hold(void *pv, FreeableResourceKind frk){
+  ResourceHeld rh = { pv, frk };
+  if( numResHold == numResAlloc ){
+    size_t nrn = numResAlloc + (numResAlloc>>2) + 5;
+    ResourceHeld *prh;
+    prh = (ResourceHeld*)realloc(pResHold, nrn*sizeof(ResourceHeld));
+    if( prh!=0 ){
+      pResHold = prh;
+      numResAlloc = nrn;
+    }else{
+      quit_moan("Out of memory",1);
+    }
+  }
+  pResHold[numResHold++] = rh;
+}
+
+/* Implementation per header comment */
+void* mmem_holder(void *pm){
+  res_hold(pm, FRK_Malloc);
+  return pm;
+}
+/* Implementation per header comment */
+char* mstr_holder(char *z){
+  if( z!=0 ) res_hold(z, FRK_Malloc);
+  return z;
+}
+/* Implementation per header comment */
+char* sstr_holder(char *z){
+  if( z!=0 ) res_hold(z, FRK_DbMem);
+  return z;
+}
+/* Implementation per header comment */
+void file_holder(FILE *pf){
+  if( pf!=0 ) res_hold(pf, FRK_File);
+}
+#if (!defined(_WIN32) && !defined(WIN32)) || !SQLITE_OS_WINRT
+/* Implementation per header comment */
+void pipe_holder(FILE *pp){
+  if( pp!=0 ) res_hold(pp, FRK_Pipe);
+}
+#endif
+/* Implementation per header comment */
+void* any_holder(void *pm, void (*its_freer)(void*)){
+  int i = 0;
+  while( i < numCustom ){
+    if( its_freer == aCustomFreers[i] ) break;
+    ++i;
+  }
+  if( i == numCustom ){
+    size_t ncf = numCustom + 2;
+    FreerFunction *pcf;
+    pcf = (FreerFunction *)realloc(aCustomFreers, ncf*sizeof(FreerFunction));
+    if( pcf!=0 ){
+      numCustomAlloc = ncf;
+      aCustomFreers = pcf;
+      aCustomFreers[numCustom++] = its_freer;
+    }else{
+      quit_moan("Out of memory",1);
+    }
+  }
+  res_hold(pm, i + FRK_CustomBase);
+  return pm;
+}
+/* Implementation per header comment */
+void* smem_holder(void *pm){
+  res_hold(pm, FRK_DbMem);
+  return pm;
+}
+/* Implementation per header comment */
+void conn_holder(sqlite3 *pdb){
+  res_hold(pdb, FRK_DbConn);
+}
+/* Implementation per header comment */
+void stmt_holder(sqlite3_stmt *pstmt){
+  res_hold(pstmt, FRK_DbStmt);
+}
+
+/* Implementation per header comment */
+void holder_free(ResourceMark mark){
+  while( numResHold > mark ){
+    free_rk(&pResHold[--numResHold]);
+  }
+  if( mark==0 ){
+    if( numResAlloc>0 ){
+      free(pResHold);
+      pResHold = 0;
+      numResAlloc = 0;
+    }
+    if( numCustomAlloc>0 ){
+      free(aCustomFreers);
+      aCustomFreers = 0;
+      numCustom = 0;
+      numCustomAlloc = 0;
+    }
+  }
+}
+
+#ifndef SHELL_OMIT_LONGJMP
+/* Implementation per header comment */
+void register_exit_ripper(jmp_buf *pjb, ResourceMark rip_mark){
+  exit_mark = rip_mark;
+  p_exit_ripper = pjb;
+}
+/* Implementation per header comment */
+void forget_exit_ripper(jmp_buf *pjb){
+  exit_mark = 0;
+  assert(p_exit_ripper == pjb);
+  p_exit_ripper = 0;
+}
+#endif
diff --git a/src/resmanage.h b/src/resmanage.h
new file mode 100644 (file)
index 0000000..a43bee0
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+** 2023 May 8
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file declares the interface of a simple resource management package
+** which supports freeing of resources upon an abrupt, program-initiated
+** termination of a function from somewhere in a call tree. The package is
+** designed to be used with setjmp()/longjmp() to effect a pattern similar
+** to the try/throw/catch available in some programming languages. (But see
+** below regarding usage when the setmp()/longjmp() pair is unavailable.)
+**
+** The general scheme is that routines whose pre-return code might be
+** bypassed, thereby leaking resources, do not rely on pre-return code
+** to release locally held resources. Instead, they give ownership of
+** such resources to this package, via xxxx_holder(...) calls, and use
+** its holder_mark() and holder_free(...) functions to release locally
+** acquired resources.
+**
+** For environments where setmp()/longjmp() are unavailable, (indicated by
+** SHELL_OMIT_LONGJMP defined), the package substitutes a process exit for
+** resumption of execution at a chosen code location. The resources in the
+** package's held resource stack are still released. And the ability to
+** free locally acquired resources as functions return is retained. This
+** can simplify early function exit logic, but a body of code relying on
+** process exit to ease error handling is unsuitable for use as a called
+** routine within a larger application. That use is most of the reason for
+** this package's existence.
+*/
+
+#ifndef RES_MANAGE_H
+# define RES_MANAGE_H
+
+#ifndef SHELL_OMIT_LONGJMP
+# include <setjmp.h>
+# define RIP_STATE(jb) jmp_buf jb
+# define RIP_TO_HERE(jb) setjmp(jb)
+#else
+# define RIP_STATE(jb)
+# define RIP_TO_HERE(jb) 0
+#endif
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "sqlite3.h"
+
+/* Type used for marking positions within a held-resource stack */
+typedef unsigned short ResourceMark;
+
+/* Current position of the held-resource stack */
+extern ResourceMark holder_mark();
+
+/* Routines for holding resources on held-resource stack together
+** with enough information for them to be freed by this package.
+*/
+/* anything together with arbitrary freeing function */
+extern void* any_holder(void *pm, void (*its_freer)(void*));
+/* anything in the malloc() heap */
+extern void* mmem_holder(void *pm);
+/* a C string in the malloc() heap */
+extern char* mstr_holder(char *z);
+/* some SQLite-allocated memory */
+extern void* smem_holder(void *pm);
+/* a C string in the SQLite heap */
+extern char* sstr_holder(char *z);
+/* a SQLite database "connection" */
+extern void conn_holder(sqlite3 *pdb);
+/* a SQLite prepared statement */
+extern void stmt_holder(sqlite3_stmt *pstmt);
+/* an open C runtime FILE */
+extern void file_holder(FILE *);
+#if (!defined(_WIN32) && !defined(WIN32)) || !SQLITE_OS_WINRT
+/* an open C runtime pipe */
+extern void pipe_holder(FILE *);
+#endif
+
+/* Take back a held resource pointer, leaving held as NULL. (no-op) */
+extern void* take_held(ResourceMark mark, unsigned short offset);
+
+/* Free all held resources in excess of given resource stack mark. */
+extern void holder_free(ResourceMark mark);
+
+#ifndef SHELL_OMIT_LONGJMP
+/* Remember a longjmp() destination together with a resource stack
+** mark which determines how far the resource stack may be stripped.
+** This info determines how far the execution and resource stacks
+** will be stripped back should quit_moan(...) be called.
+*/
+extern void register_exit_ripper(jmp_buf *pjb, ResourceMark rip_mark);
+/* Forget whatever register_exit_ripper() has been recorded. */
+extern void forget_exit_ripper(jmp_buf *pjb);
+#else
+#define register_exit_ripper(jb, rm)
+#define forget_exit_ripper()
+#endif
+
+/* Strip resource stack and execute previously registered longjmp() as
+** previously prepared by register_exit_ripper() call. Or, if no such
+** prep done (or possible), strip the whole stack and exit the process.
+*/
+extern void quit_moan(const char *zMoan, int errCode);
+
+#ifdef __cplusplus
+}  /* End of the 'extern "C"' block */
+#endif
+#endif /* RES_MANAGE_H */