mike-jumper commented on code in PR #614:
URL: https://github.com/apache/guacamole-server/pull/614#discussion_r2374937195


##########
src/libguac/thread-local.c:
##########
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "config.h"
+#include "guacamole/thread-local.h"
+
+#include <stdlib.h>
+#include <pthread.h>
+#include <errno.h>
+#include <sched.h>
+
+/**
+ * Maximum number of thread-local keys supported.
+ */
+#define MAX_THREAD_KEYS 1024
+
+/**
+ * Structure to hold destructor information for each key.
+ */
+typedef struct guac_key_entry {
+    guac_thread_local_destructor_t destructor;
+    int in_use;
+} guac_key_entry_t;
+
+/**
+ * Thread-local storage entry.
+ */
+typedef struct guac_thread_storage {
+    void* values[MAX_THREAD_KEYS];
+} guac_thread_storage_t;
+
+/**
+ * Global key registry protected by mutex.
+ */
+static guac_key_entry_t key_registry[MAX_THREAD_KEYS];
+static pthread_mutex_t key_registry_mutex = PTHREAD_MUTEX_INITIALIZER;
+static uintptr_t next_key_id = 1;
+
+/**
+ * Thread-local storage using __thread keyword for better performance.
+ */
+static __thread guac_thread_storage_t* thread_storage = NULL;
+
+/**
+ * Global cleanup key created once for all threads.
+ */
+static pthread_key_t global_cleanup_key;
+static pthread_once_t cleanup_key_once = PTHREAD_ONCE_INIT;
+
+/**
+ * Cleanup function called when thread exits.
+ */
+static void cleanup_thread_storage(void* storage) {
+    guac_thread_storage_t* ts = (guac_thread_storage_t*)storage;
+    if (ts == NULL) return;
+
+    pthread_mutex_lock(&key_registry_mutex);
+    
+    for (int i = 0; i < MAX_THREAD_KEYS; i++) {
+        if (key_registry[i].in_use && ts->values[i] != NULL) {
+            if (key_registry[i].destructor) {
+                key_registry[i].destructor(ts->values[i]);
+            }
+        }
+    }
+    
+    pthread_mutex_unlock(&key_registry_mutex);
+    free(ts);
+}
+
+/**
+ * Initialize the global cleanup key once.
+ */
+static void init_cleanup_key(void) {
+    pthread_key_create(&global_cleanup_key, cleanup_thread_storage);
+}
+
+/**
+ * Initialize thread storage if not already done.
+ */
+static guac_thread_storage_t* get_thread_storage(void) {
+    if (thread_storage == NULL) {
+        thread_storage = calloc(1, sizeof(guac_thread_storage_t));
+        if (thread_storage != NULL) {
+            pthread_once(&cleanup_key_once, init_cleanup_key);
+            if (pthread_setspecific(global_cleanup_key, thread_storage) != 0) {
+                /* Critical: if pthread_setspecific fails, we must not leave 
+                 * the thread_storage pointer set, as cleanup won't be called 
*/
+                free(thread_storage);
+                thread_storage = NULL;
+                return NULL;
+            }
+        }
+    }
+    return thread_storage;
+}
+
+int guac_thread_local_key_create(guac_thread_local_key_t* key, 
guac_thread_local_destructor_t destructor) {
+    if (key == NULL) return EINVAL;
+
+    pthread_mutex_lock(&key_registry_mutex);
+    
+    uintptr_t key_id = 0;
+    for (int i = 0; i < MAX_THREAD_KEYS; i++) {
+        if (!key_registry[i].in_use) {
+            key_id = next_key_id++;
+            if (next_key_id == 0) next_key_id = 1; // Avoid key_id of 0
+            
+            key_registry[i].destructor = destructor;
+            key_registry[i].in_use = 1;
+            *key = (key_id << 16) | i; // Combine ID and index for validation

Review Comment:
   Also worth noting: this inherently limits `MAX_THREAD_KEYS` to 65536. Beyond 
that, and indices would start clobbering the shifted bits of `key_id`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to