implement reference counting for DavContext and DavSession dav-2 tip

Sat, 20 Jun 2026 19:00:56 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sat, 20 Jun 2026 19:00:56 +0200
branch
dav-2
changeset 914
42c6b071b231
parent 913
8e2727fc4e07

implement reference counting for DavContext and DavSession

libidav/atomic.h file | annotate | diff | comparison | revisions
libidav/session.c file | annotate | diff | comparison | revisions
libidav/webdav.c file | annotate | diff | comparison | revisions
libidav/webdav.h file | annotate | diff | comparison | revisions
test/Makefile file | annotate | diff | comparison | revisions
test/context.c file | annotate | diff | comparison | revisions
test/context.h file | annotate | diff | comparison | revisions
test/main.c file | annotate | diff | comparison | revisions
test/session.c file | annotate | diff | comparison | revisions
test/session.h file | annotate | diff | comparison | revisions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libidav/atomic.h	Sat Jun 20 19:00:56 2026 +0200
@@ -0,0 +1,57 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV_ATOMIC_H
+#define	DAV_ATOMIC_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#if defined(__gnu_linux__) || defined(OSX) || defined(BSD)
+
+#define dav_atomic_inc32(intptr) __sync_fetch_and_add(intptr, 1)
+#define dav_atomic_dec32(intptr) (__sync_fetch_and_sub(intptr, 1) - 1)
+
+#else
+// use atomic.h
+#include <atomic.h>
+
+#define dav_atomic_inc32(intptr) atomic_inc_32_nv(intptr)
+#define dav_atomic_dec32(intptr) atomic_dec_32_nv(intptr)
+// TODO
+
+#endif
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* DAV_ATOMIC_H */
+
--- a/libidav/session.c	Sat Feb 14 18:11:29 2026 +0100
+++ b/libidav/session.c	Sat Jun 20 19:00:56 2026 +0200
@@ -38,6 +38,7 @@
 #include "session.h"
 #include "resource.h"
 #include "methods.h"
+#include "atomic.h"
 
 DavSession* dav_session_new(DavContext *context, char *base_url) {
     if(!base_url) {
@@ -95,6 +96,9 @@
     // add to context
     dav_context_add_session(context, sn);
     sn->context = context;
+    dav_context_ref(context);
+    
+    sn->ref = 1;
     
     return sn;
 }
@@ -138,10 +142,23 @@
     // add to context
     dav_context_add_session(sn->context, newsn);
     newsn->context = sn->context;
+    dav_context_ref(sn->context);
+    
+    newsn->ref = 1;
 
     return newsn;
 }
 
+void dav_session_ref(DavSession *sn) {
+    dav_atomic_inc32(&sn->ref);
+}
+
+void dav_session_unref(DavSession *sn) {
+    if(dav_atomic_dec32(&sn->ref) == 0) {
+        dav_session_destroy(sn);
+    }
+}
+
 void dav_session_set_auth(DavSession *sn, const char *user, const char *password) {
     if(user && password) {
         dav_session_set_auth_s(sn, cx_str(user), cx_str(password));
@@ -344,15 +361,19 @@
 
 void dav_session_destroy(DavSession *sn) { 
     // remove session from context
-    if (dav_context_remove_session(sn->context, sn)) {
+    DavContext *ctx = sn->context;
+    dav_context_ref(ctx);
+    if (dav_context_remove_session(ctx, sn)) {
         fprintf(stderr, "Error: session not found in ctx->sessions\n");
         dav_session_destructor(sn);
     }
+    dav_context_unref(ctx);
 }
 
 void dav_session_destructor(DavSession *sn) {
     cxMempoolFree(sn->mp);
     curl_easy_cleanup(sn->handle);
+    dav_context_unref(sn->context);
     free(sn);
 }
 
--- a/libidav/webdav.c	Sat Feb 14 18:11:29 2026 +0100
+++ b/libidav/webdav.c	Sat Jun 20 19:00:56 2026 +0200
@@ -41,6 +41,7 @@
 #include <cx/compare.h>
 #include "davqlparser.h"
 #include "davqlexec.h"
+#include "atomic.h"
 
 
 DavContext* dav_context_new(void) {
@@ -94,10 +95,22 @@
         dav_context_destroy(context);
         return NULL;
     }   
+    
+    context->ref = 1;
 
     return context;
 }
 
+void dav_context_ref(DavContext *ctx) {
+    dav_atomic_inc32(&ctx->ref);
+}
+
+void dav_context_unref(DavContext *ctx) {
+    if(dav_atomic_dec32(&ctx->ref) == 0) {
+        dav_context_destroy(ctx);
+    }
+}
+
 void dav_context_destroy(DavContext *ctx) {
     // destroy all sessions assoziated with this context
     // ctx->sessions destructor must be dav_session_destructor
--- a/libidav/webdav.h	Sat Feb 14 18:11:29 2026 +0100
+++ b/libidav/webdav.h	Sat Jun 20 19:00:56 2026 +0200
@@ -189,17 +189,20 @@
     void(*get_progress)(DavResource *res, int64_t total, int64_t now, void *userdata);
     void(*put_progress)(DavResource *res, int64_t total, int64_t now, void *userdata);
     void *progress_userdata;
+    
+    unsigned int ref;
 };
 
 struct DavContext {
-    CxMap     *namespaces;
-    CxMap     *namespaceinfo;
-    CxMap     *keys;
-    CxList    *sessions;
-    DavProxy  *http_proxy;
-    DavProxy  *https_proxy;
-    DAV_MUTEX mutex;
-    DavBool   mtsafe;
+    CxMap        *namespaces;
+    CxMap        *namespaceinfo;
+    CxMap        *keys;
+    CxList       *sessions;
+    DavProxy     *http_proxy;
+    DavProxy     *https_proxy;
+    DAV_MUTEX    mutex;
+    DavBool      mtsafe;
+    unsigned int ref;
 };
 
 struct DavProxy {
@@ -264,6 +267,8 @@
 };
 
 DavContext* dav_context_new(void);
+void dav_context_ref(DavContext *ctx);
+void dav_context_unref(DavContext *ctx);
 void dav_context_destroy(DavContext *ctx);
 void dav_context_set_mtsafe(DavContext *ctx, DavBool enable);
 
@@ -290,6 +295,8 @@
         char *user,
         char *password);
 DavSession* dav_session_clone(DavSession *sn);
+void dav_session_ref(DavSession *sn);
+void dav_session_unref(DavSession *sn);
 void dav_session_set_auth(DavSession *sn, const char *user, const char *password);
 void dav_session_set_auth_s(DavSession *sn, cxstring user, cxstring password);
 void dav_session_set_baseurl(DavSession *sn, char *base_url);
--- a/test/Makefile	Sat Feb 14 18:11:29 2026 +0100
+++ b/test/Makefile	Sat Jun 20 19:00:56 2026 +0200
@@ -33,6 +33,8 @@
 TEST_SRC += base64.c
 TEST_SRC += crypto.c
 TEST_SRC += utils.c
+TEST_SRC += context.c
+TEST_SRC += session.c
 TEST_SRC += webdav.c
 TEST_SRC += webdav_resource.c
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/context.c	Sat Jun 20 19:00:56 2026 +0200
@@ -0,0 +1,42 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2026 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "context.h"
+
+CX_TEST(test_context_ref_counting) {
+    CX_TEST_DO {
+        DavContext *ctx = dav_context_new();
+        CX_TEST_ASSERT(ctx->ref == 1);
+        dav_context_ref(ctx);
+        CX_TEST_ASSERT(ctx->ref == 2);
+        dav_context_unref(ctx);
+        CX_TEST_ASSERT(ctx->ref == 1);
+        dav_context_unref(ctx);
+        // context destroyed
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/context.h	Sat Jun 20 19:00:56 2026 +0200
@@ -0,0 +1,47 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2026 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TEST_DAV_CONTEXT_H
+#define TEST_DAV_CONTEXT_H
+
+#include <cx/test.h>
+#include <libidav/webdav.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+CX_TEST(test_context_ref_counting);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TEST_DAV_CONTEXT_H */
+
--- a/test/main.c	Sat Feb 14 18:11:29 2026 +0100
+++ b/test/main.c	Sat Jun 20 19:00:56 2026 +0200
@@ -35,6 +35,8 @@
 #include "crypto.h"
 #include "utils.h"
 
+#include "context.h"
+#include "session.h"
 #include "webdav.h"
 #include "webdav_resource.h"
 
@@ -81,6 +83,8 @@
     cx_test_register(suite, test_util_path_isabsolut);
     cx_test_register(suite, test_util_path_normalize);
     cx_test_register(suite, test_util_parent_path);
+    cx_test_register(suite, test_context_ref_counting);
+    cx_test_register(suite, test_session_ref_counting);
     
     CxTestSuite* suite_webdav = cx_test_suite_new("libidav webdav");
     test_webdav_init();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/session.c	Sat Jun 20 19:00:56 2026 +0200
@@ -0,0 +1,48 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2026 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "session.h"
+
+CX_TEST(test_session_ref_counting) {
+    CX_TEST_DO {
+        DavContext *ctx = dav_context_new();
+        DavSession *sn = dav_session_new(ctx, "http://example.com/webdav/");
+        
+        CX_TEST_ASSERT(sn->ref == 1);
+        CX_TEST_ASSERT(ctx->ref == 2);
+        
+        dav_session_ref(sn);
+        CX_TEST_ASSERT(sn->ref == 2);
+        
+        dav_context_unref(ctx);
+        CX_TEST_ASSERT(ctx->ref == 1);
+        dav_session_unref(sn);
+        CX_TEST_ASSERT(sn->ref == 1);
+        dav_session_unref(sn);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/session.h	Sat Jun 20 19:00:56 2026 +0200
@@ -0,0 +1,46 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2026 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TEST_DAV_SESSION_H
+#define TEST_DAV_SESSION_H
+
+#include <cx/test.h>
+#include <libidav/webdav.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+CX_TEST(test_session_ref_counting);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TEST_DAV_SESSION_H */
+

mercurial