[ruby-oci8-commit] [425] trunk/ruby-oci8/ext/oci8: * ext/oci8/env.c, ext/oci8/oci8.h: Free OCI error handles on the

nobody at rubyforge.org nobody at rubyforge.org
Thu Jun 9 23:59:43 EDT 2011


Revision: 425
Author:   kubo
Date:     2011-06-09 23:59:42 -0400 (Thu, 09 Jun 2011)

Log Message:
-----------
* ext/oci8/env.c, ext/oci8/oci8.h: Free OCI error handles on the
    native thread termination, not on the ruby thread termination.
    (reported by Jordan Curzon and Aaron Qian)
    See: http://rubyforge.org/forum/forum.php?thread_id=49751&forum_id=1078

Modified Paths:
--------------
    branches/ruby-oci8-2.0/ChangeLog
    branches/ruby-oci8-2.0/ext/oci8/env.c
    branches/ruby-oci8-2.0/ext/oci8/oci8.h
    trunk/ruby-oci8/ChangeLog
    trunk/ruby-oci8/ext/oci8/env.c
    trunk/ruby-oci8/ext/oci8/oci8.h

Modified: branches/ruby-oci8-2.0/ChangeLog
===================================================================
--- branches/ruby-oci8-2.0/ChangeLog	2011-02-21 11:10:57 UTC (rev 424)
+++ branches/ruby-oci8-2.0/ChangeLog	2011-06-10 03:59:42 UTC (rev 425)
@@ -1,8 +1,14 @@
+2011-06-10  KUBO Takehiro  <kubo at jiubao.org>
+	* ext/oci8/env.c, ext/oci8/oci8.h: Free OCI error handles on the
+	    native thread termination, not on the ruby thread termination.
+	    (reported by Jordan Curzon and Aaron Qian)
+	    See: http://rubyforge.org/forum/forum.php?thread_id=49751&forum_id=1078
+
 2011-02-21  KUBO Takehiro  <kubo at jiubao.org>
 	* ext/oci8/lob.c, ext/oci8/metadata.c, ext/oci8/oci8.c,
 	  ext/oci8/oci8.h, ext/oci8/oci8lib.c, ext/oci8/stmt.c:
-	    fix segmentation fault when calling closed statement object's
-	    OCI8::Cursor#[]. (reported by Hugo L. Borges)
+	    fix segmentation fault when calling OCI8::Cursor#[] for
+	    closed statement object's (reported by Hugo L. Borges)
 
 2011-02-01  KUBO Takehiro  <kubo at jiubao.org>
 	* ext/oci8/ocidatetime.c, lib/oci8/datetime.rb: rename
@@ -120,7 +126,7 @@
 
 2010-02-28  KUBO Takehiro  <kubo at jiubao.org>
 	* NEWS: add changes between 2.0.3 and 2.0.4.
-	* VERSION: change the version to 2.0.3.
+	* VERSION: change the version to 2.0.4.
 	* ext/oci8/stmt.c: fix segmentation fault when OCI8::Cursor#fetch
 	    is called prior to OCI8::Cursor#exec.
 	* ext/oci8/oci8.c: minor fix in rdoc comment.

Modified: branches/ruby-oci8-2.0/ext/oci8/env.c
===================================================================
--- branches/ruby-oci8-2.0/ext/oci8/env.c	2011-02-21 11:10:57 UTC (rev 424)
+++ branches/ruby-oci8-2.0/ext/oci8/env.c	2011-06-10 03:59:42 UTC (rev 425)
@@ -2,7 +2,7 @@
 /*
  * env.c - part of ruby-oci8
  *
- * Copyright (C) 2002-2009 KUBO Takehiro <kubo at jiubao.org>
+ * Copyright (C) 2002-2011 KUBO Takehiro <kubo at jiubao.org>
  */
 #include "oci8.h"
 
@@ -37,17 +37,47 @@
  */
 
 oci8_tls_key_t oci8_tls_key; /* native thread key */
-static ID id_thread_key;     /* ruby's thread key */
 
-static void oci8_free_errhp(OCIError *errhp)
+/* This function is called on the native thread termination
+ * if the thread local errhp is not null.
+ */
+static void oci8_free_errhp(void *errhp)
 {
     OCIHandleFree(errhp, OCI_HTYPE_ERROR);
 }
 
+#ifdef _WIN32
+static int dllmain_is_called;
+
+__declspec(dllexport)
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+    void *errhp;
+
+    switch (fdwReason) {
+    case DLL_PROCESS_ATTACH:
+        dllmain_is_called = 1;
+        break;
+    case DLL_THREAD_ATTACH:
+        /* do nothing */
+        break;
+    case DLL_THREAD_DETACH:
+        errhp = oci8_tls_get(oci8_tls_key);
+        if (errhp != NULL) {
+            oci8_free_errhp(errhp);
+        }
+        break;
+    case DLL_PROCESS_DETACH:
+        /* do nothing */
+        break;
+    }
+    return TRUE;
+}
+#endif
+
 OCIError *oci8_make_errhp(void)
 {
     OCIError *errhp;
-    VALUE obj;
     sword rv;
 
     /* create a new errhp. */
@@ -55,15 +85,9 @@
     if (rv != OCI_SUCCESS) {
         oci8_env_raise(oci8_envhp, rv);
     }
-    /* create a new ruby object which contains errhp to make
-     * sure that the errhp is freed when it become unnecessary.
+    /* Set the errhp to the thread local storage.
+     * It is freed by oci8_free_errhp().
      */
-    obj = Data_Wrap_Struct(rb_cObject, NULL, oci8_free_errhp, errhp);
-    /* set the ruby object to ruby's thread local storage to prevent
-     * it from being freed while the thread is available.
-     */
-    rb_thread_local_aset(rb_thread_current(), id_thread_key, obj);
-
     oci8_tls_set(oci8_tls_key, (void*)errhp);
     return errhp;
 }
@@ -137,8 +161,21 @@
     }
 
 #ifdef HAVE_TYPE_RB_BLOCKING_FUNCTION_T
-    id_thread_key = rb_intern("__oci8_errhp__");
-    error = oci8_tls_key_init(&oci8_tls_key);
+/* ruby 1.9 */
+#if defined(_WIN32)
+    if (!dllmain_is_called) {
+        /* sanity check */
+        rb_raise(rb_eRuntimeError, "DllMain is not unexpectedly called. This causes resource leaks.");
+    }
+    oci8_tls_key = TlsAlloc();
+    if (oci8_tls_key == 0xFFFFFFFF) {
+        error = GetLastError();
+    } else {
+        error = 0;
+    }
+#else
+    error = pthread_key_create(&oci8_tls_key, oci8_free_errhp);
+#endif
     if (error != 0) {
         rb_raise(rb_eRuntimeError, "Cannot create thread local key (errno = %d)", error);
     }

Modified: branches/ruby-oci8-2.0/ext/oci8/oci8.h
===================================================================
--- branches/ruby-oci8-2.0/ext/oci8/oci8.h	2011-02-21 11:10:57 UTC (rev 424)
+++ branches/ruby-oci8-2.0/ext/oci8/oci8.h	2011-06-10 03:59:42 UTC (rev 425)
@@ -2,7 +2,7 @@
 /*
  * oci8.h - part of ruby-oci8
  *
- * Copyright (C) 2002-2009 KUBO Takehiro <kubo at jiubao.org>
+ * Copyright (C) 2002-2011 KUBO Takehiro <kubo at jiubao.org>
  */
 #ifndef _RUBY_OCI_H_
 #define _RUBY_OCI_H_ 1
@@ -174,10 +174,6 @@
 
 /* macros to access thread-local storage.
  *
- *  int oci8_tls_key_init(oci8_tls_key_t *key);
- *    initialie a key to access thread-local storege
- *    This returns 0 on success or error number.
- *
  *  void *oci8_tls_get(oci8_tls_key_t key);
  *    get a value associated with the key.
  *
@@ -190,15 +186,11 @@
 #if defined(_WIN32)
 #include <windows.h>
 #define oci8_tls_key_t           DWORD
-#define oci8_tls_key_init(key_p) \
-    ((*(key_p) = TlsAlloc()), \
-    (*(key_p) == 0xFFFFFFFF) ? GetLastError() : 0)
 #define oci8_tls_get(key)        TlsGetValue(key)
 #define oci8_tls_set(key, val)   TlsSetValue((key), (val))
 #else
 #include <pthread.h>
 #define oci8_tls_key_t           pthread_key_t
-#define oci8_tls_key_init(key_p) pthread_key_create((key_p), NULL)
 #define oci8_tls_get(key)        pthread_getspecific(key)
 #define oci8_tls_set(key, val)   pthread_setspecific((key), (val))
 #endif

Modified: trunk/ruby-oci8/ChangeLog
===================================================================
--- trunk/ruby-oci8/ChangeLog	2011-02-21 11:10:57 UTC (rev 424)
+++ trunk/ruby-oci8/ChangeLog	2011-06-10 03:59:42 UTC (rev 425)
@@ -1,8 +1,14 @@
+2011-06-10  KUBO Takehiro  <kubo at jiubao.org>
+	* ext/oci8/env.c, ext/oci8/oci8.h: Free OCI error handles on the
+	    native thread termination, not on the ruby thread termination.
+	    (reported by Jordan Curzon and Aaron Qian)
+	    See: http://rubyforge.org/forum/forum.php?thread_id=49751&forum_id=1078
+
 2011-02-21  KUBO Takehiro  <kubo at jiubao.org>
 	* ext/oci8/lob.c, ext/oci8/metadata.c, ext/oci8/oci8.c,
 	  ext/oci8/oci8.h, ext/oci8/oci8lib.c, ext/oci8/stmt.c:
-	    fix segmentation fault when calling closed statement object's
-	    OCI8::Cursor#[]. (reported by Hugo L. Borges)
+	    fix segmentation fault when calling OCI8::Cursor#[] for
+	    closed statement object's (reported by Hugo L. Borges)
 
 2011-02-01  KUBO Takehiro  <kubo at jiubao.org>
 	* ext/oci8/ocidatetime.c, lib/oci8/datetime.rb: rename

Modified: trunk/ruby-oci8/ext/oci8/env.c
===================================================================
--- trunk/ruby-oci8/ext/oci8/env.c	2011-02-21 11:10:57 UTC (rev 424)
+++ trunk/ruby-oci8/ext/oci8/env.c	2011-06-10 03:59:42 UTC (rev 425)
@@ -2,7 +2,7 @@
 /*
  * env.c - part of ruby-oci8
  *
- * Copyright (C) 2002-2009 KUBO Takehiro <kubo at jiubao.org>
+ * Copyright (C) 2002-2011 KUBO Takehiro <kubo at jiubao.org>
  */
 #include "oci8.h"
 
@@ -37,17 +37,47 @@
  */
 
 oci8_tls_key_t oci8_tls_key; /* native thread key */
-static ID id_thread_key;     /* ruby's thread key */
 
-static void oci8_free_errhp(OCIError *errhp)
+/* This function is called on the native thread termination
+ * if the thread local errhp is not null.
+ */
+static void oci8_free_errhp(void *errhp)
 {
     OCIHandleFree(errhp, OCI_HTYPE_ERROR);
 }
 
+#ifdef _WIN32
+static int dllmain_is_called;
+
+__declspec(dllexport)
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+    void *errhp;
+
+    switch (fdwReason) {
+    case DLL_PROCESS_ATTACH:
+        dllmain_is_called = 1;
+        break;
+    case DLL_THREAD_ATTACH:
+        /* do nothing */
+        break;
+    case DLL_THREAD_DETACH:
+        errhp = oci8_tls_get(oci8_tls_key);
+        if (errhp != NULL) {
+            oci8_free_errhp(errhp);
+        }
+        break;
+    case DLL_PROCESS_DETACH:
+        /* do nothing */
+        break;
+    }
+    return TRUE;
+}
+#endif
+
 OCIError *oci8_make_errhp(void)
 {
     OCIError *errhp;
-    VALUE obj;
     sword rv;
 
     /* create a new errhp. */
@@ -55,15 +85,9 @@
     if (rv != OCI_SUCCESS) {
         oci8_env_raise(oci8_envhp, rv);
     }
-    /* create a new ruby object which contains errhp to make
-     * sure that the errhp is freed when it become unnecessary.
+    /* Set the errhp to the thread local storage.
+     * It is freed by oci8_free_errhp().
      */
-    obj = Data_Wrap_Struct(rb_cObject, NULL, oci8_free_errhp, errhp);
-    /* set the ruby object to ruby's thread local storage to prevent
-     * it from being freed while the thread is available.
-     */
-    rb_thread_local_aset(rb_thread_current(), id_thread_key, obj);
-
     oci8_tls_set(oci8_tls_key, (void*)errhp);
     return errhp;
 }
@@ -137,8 +161,21 @@
     }
 
 #ifdef HAVE_TYPE_RB_BLOCKING_FUNCTION_T
-    id_thread_key = rb_intern("__oci8_errhp__");
-    error = oci8_tls_key_init(&oci8_tls_key);
+/* ruby 1.9 */
+#if defined(_WIN32)
+    if (!dllmain_is_called) {
+        /* sanity check */
+        rb_raise(rb_eRuntimeError, "DllMain is not unexpectedly called. This causes resource leaks.");
+    }
+    oci8_tls_key = TlsAlloc();
+    if (oci8_tls_key == 0xFFFFFFFF) {
+        error = GetLastError();
+    } else {
+        error = 0;
+    }
+#else
+    error = pthread_key_create(&oci8_tls_key, oci8_free_errhp);
+#endif
     if (error != 0) {
         rb_raise(rb_eRuntimeError, "Cannot create thread local key (errno = %d)", error);
     }

Modified: trunk/ruby-oci8/ext/oci8/oci8.h
===================================================================
--- trunk/ruby-oci8/ext/oci8/oci8.h	2011-02-21 11:10:57 UTC (rev 424)
+++ trunk/ruby-oci8/ext/oci8/oci8.h	2011-06-10 03:59:42 UTC (rev 425)
@@ -2,7 +2,7 @@
 /*
  * oci8.h - part of ruby-oci8
  *
- * Copyright (C) 2002-2010 KUBO Takehiro <kubo at jiubao.org>
+ * Copyright (C) 2002-2011 KUBO Takehiro <kubo at jiubao.org>
  */
 #ifndef _RUBY_OCI_H_
 #define _RUBY_OCI_H_ 1
@@ -177,10 +177,6 @@
 
 /* macros to access thread-local storage.
  *
- *  int oci8_tls_key_init(oci8_tls_key_t *key);
- *    initialie a key to access thread-local storege
- *    This returns 0 on success or error number.
- *
  *  void *oci8_tls_get(oci8_tls_key_t key);
  *    get a value associated with the key.
  *
@@ -193,15 +189,11 @@
 #if defined(_WIN32)
 #include <windows.h>
 #define oci8_tls_key_t           DWORD
-#define oci8_tls_key_init(key_p) \
-    ((*(key_p) = TlsAlloc()), \
-    (*(key_p) == 0xFFFFFFFF) ? GetLastError() : 0)
 #define oci8_tls_get(key)        TlsGetValue(key)
 #define oci8_tls_set(key, val)   TlsSetValue((key), (val))
 #else
 #include <pthread.h>
 #define oci8_tls_key_t           pthread_key_t
-#define oci8_tls_key_init(key_p) pthread_key_create((key_p), NULL)
 #define oci8_tls_get(key)        pthread_getspecific(key)
 #define oci8_tls_set(key, val)   pthread_setspecific((key), (val))
 #endif




More information about the ruby-oci8-commit mailing list