[ruby-oci8-commit] [249] trunk/ruby-oci8: * ext/oci8/env.c, ext/oci8/oci8.h: use native API to get a thread

nobody at rubyforge.org nobody at rubyforge.org
Wed Mar 5 09:29:35 EST 2008


Revision: 249
Author:   kubo
Date:     2008-03-05 09:29:35 -0500 (Wed, 05 Mar 2008)

Log Message:
-----------
* ext/oci8/env.c, ext/oci8/oci8.h: use native API to get a thread
    local errhp (ruby 1.9 only)
      pthread: pthread_getspecific()
      win32:   TlsGetValue()

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

Modified: trunk/ruby-oci8/ChangeLog
===================================================================
--- trunk/ruby-oci8/ChangeLog	2008-03-04 08:13:21 UTC (rev 248)
+++ trunk/ruby-oci8/ChangeLog	2008-03-05 14:29:35 UTC (rev 249)
@@ -1,3 +1,9 @@
+2008-03-05  KUBO Takehiro  <kubo at jiubao.org>
+	* ext/oci8/env.c, ext/oci8/oci8.h: use native API to get a thread
+	    local errhp (ruby 1.9 only)
+	      pthread: pthread_getspecific()
+	      win32:   TlsGetValue()
+
 2008-03-04  KUBO Takehiro  <kubo at jiubao.org>
 	* ext/oci8/extconf.rb: output a message to say 'install
 	    a ruby development package' when 'mkmf.rb' is not

Modified: trunk/ruby-oci8/ext/oci8/env.c
===================================================================
--- trunk/ruby-oci8/ext/oci8/env.c	2008-03-04 08:13:21 UTC (rev 248)
+++ trunk/ruby-oci8/ext/oci8/env.c	2008-03-05 14:29:35 UTC (rev 249)
@@ -2,7 +2,7 @@
 /*
   env.c - part of ruby-oci8
 
-  Copyright (C) 2002-2006 KUBO Takehiro <kubo at jiubao.org>
+  Copyright (C) 2002-2008 KUBO Takehiro <kubo at jiubao.org>
 
 */
 #include "oci8.h"
@@ -17,52 +17,59 @@
 
 OCIEnv *oci8_envhp;
 #ifdef RUBY_VM
-static ID id_thread_key;
+/*
+ * oci8_errhp is a thread local object in ruby 1.9.
+ */
+
+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)
 {
     OCIHandleFree(errhp, OCI_HTYPE_ERROR);
 }
 
-OCIError *oci8_get_errhp(void)
+OCIError *oci8_make_errhp(void)
 {
-    static OCIError *errhp = NULL;
-    static VALUE my_thread = Qnil;
+    OCIError *errhp;
     VALUE obj;
+    sword rv;
 
-    if (rb_thread_current() == my_thread) {
-        /* tricky!
-         * This code works only when ruby thread model is 1 or 2.
-         *   model 1: ruby 1.8 or earlier.
-         *   model 2: ruby 1.9
-         */
-        return errhp;
+    /* create a new errhp. */
+    rv = OCIHandleAlloc(oci8_envhp, (dvoid *)&errhp, OCI_HTYPE_ERROR, 0, NULL);
+    if (rv != OCI_SUCCESS) {
+        oci8_env_raise(oci8_envhp, rv);
     }
-    my_thread = rb_thread_current();
-    obj = rb_thread_local_aref(my_thread, id_thread_key);
-    if (!NIL_P(obj)) {
-        Data_Get_Struct(obj, OCIError, errhp);
-        if (errhp == NULL) {
-            rb_bug("oci8_get_errhp");
-        }
-    } else {
-        sword rv = OCIHandleAlloc(oci8_envhp, (dvoid *)&errhp, OCI_HTYPE_ERROR, 0, NULL);
-        if (rv != OCI_SUCCESS) {
-            oci8_env_raise(oci8_envhp, rv);
-        }
-        obj = Data_Wrap_Struct(rb_cObject, NULL, oci8_free_errhp, errhp);
-        rb_thread_local_aset(my_thread, id_thread_key, obj);
-    }
+    /* create a new ruby object which contains errhp to make
+     * sure that the errhp is freed when it become unnecessary.
+     */
+    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;
 }
 #else
+/*
+ * oci8_errhp is global in ruby 1.8.
+ */
 OCIError *oci8_errhp;
 #endif
 
 void Init_oci8_env(void)
 {
     sword rv;
+#ifdef RUBY_VM
+    ub4 mode = OCI_OBJECT | OCI_THREADED;
+    int error;
+#else
+    ub4 mode = OCI_OBJECT;
+#endif
 
-#ifndef WIN32
+#if !defined(RUBY_VM) && !defined(_WIN32)
     /* workaround code.
      *
      * Some instant clients set the environment variables
@@ -81,7 +88,7 @@
         }
     }
 #endif /* WIN32 */
-    rv = OCIInitialize(OCI_OBJECT, NULL, NULL, NULL, NULL);
+    rv = OCIInitialize(mode, NULL, NULL, NULL, NULL);
     if (rv != OCI_SUCCESS) {
         oci8_raise_init_error();
     }
@@ -91,7 +98,11 @@
     }
 #ifdef RUBY_VM
     id_thread_key = rb_intern("__oci8_errhp__");
-#else
+    error = oci8_tls_key_init(&oci8_tls_key);
+    if (error != 0) {
+        rb_raise(rb_eRuntimeError, "Cannot create thread local key (errno = %d)", error);
+    }
+#else /* RUBY_VM */
     rv = OCIHandleAlloc(oci8_envhp, (dvoid *)&oci8_errhp, OCI_HTYPE_ERROR, 0, NULL);
     if (rv != OCI_SUCCESS)
         oci8_env_raise(oci8_envhp, rv);

Modified: trunk/ruby-oci8/ext/oci8/oci8.h
===================================================================
--- trunk/ruby-oci8/ext/oci8/oci8.h	2008-03-04 08:13:21 UTC (rev 248)
+++ trunk/ruby-oci8/ext/oci8/oci8.h	2008-03-05 14:29:35 UTC (rev 249)
@@ -2,7 +2,7 @@
 /*
   oci8.h - part of ruby-oci8
 
-  Copyright (C) 2002-2007 KUBO Takehiro <kubo at jiubao.org>
+  Copyright (C) 2002-2008 KUBO Takehiro <kubo at jiubao.org>
 */
 #ifndef _RUBY_OCI_H_
 #define _RUBY_OCI_H_ 1
@@ -223,9 +223,38 @@
 /* env.c */
 extern OCIEnv *oci8_envhp;
 #ifdef RUBY_VM
-OCIError *oci8_get_errhp(void);
+/* oci8_errhp is a thread local object in ruby 1.9. */
 #define oci8_errhp oci8_get_errhp()
+
+#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))
+#elif defined(HAVE_PTHREAD_H)
+#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))
 #else
+#error unsupported thread API
+#endif
+
+extern oci8_tls_key_t oci8_tls_key; /* native thread key */
+OCIError *oci8_make_errhp(void);
+
+static inline OCIError *oci8_get_errhp()
+{
+    OCIError *errhp = (OCIError *)oci8_tls_get(oci8_tls_key);
+    return (errhp != NULL) ? errhp : oci8_make_errhp();
+}
+
+#else
+/* oci8_errhp is global in ruby 1.8. */
 extern OCIError *oci8_errhp;
 #endif
 void Init_oci8_env(void);




More information about the ruby-oci8-commit mailing list