Skip to content

Instantly share code, notes, and snippets.

@kubo
Created October 26, 2012 02:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kubo/3956611 to your computer and use it in GitHub Desktop.
Save kubo/3956611 to your computer and use it in GitHub Desktop.
diff --git a/ChangeLog b/ChangeLog
index 73e1c10..5ca1e38 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2012-10-26 KUBO Takehiro <kubo@jiubao.org>
+ * ext/oci8/lob.c, ext/oci8/oci8.c, ext/oci8/oci8.h, ext/oci8/oci8lib.c:
+ Fix github issue #20
+
2012-04-28 KUBO Takehiro <kubo@jiubao.org>
* NEWS: add changes between 2.1.2 and 2.1.1
* VERSION: change the version to 2.1.2.
diff --git a/ext/oci8/lob.c b/ext/oci8/lob.c
index 4289a3a..b9d2400 100644
--- a/ext/oci8/lob.c
+++ b/ext/oci8/lob.c
@@ -98,6 +98,18 @@ static void oci8_lob_mark(oci8_base_t *base)
rb_gc_mark(lob->svc);
}
+#ifdef HAVE_RB_THREAD_BLOCKING_REGION
+static void oci8_lob_free_func(oci8_svcctx_t *svchp, void *arg1, void *arg2)
+{
+ OCIError *errhp = (OCIError*)arg1;
+ OCILobLocator *lob = (OCILobLocator*)arg1;
+
+ /* FIXME: This may stops all ruby threads. */
+ OCILobFreeTemporary(svchp->base.hp.svc, errhp, lob);
+ OCIHandleFree(errhp, OCI_HTYPE_ERROR);
+}
+#endif
+
static void oci8_lob_free(oci8_base_t *base)
{
oci8_lob_t *lob = (oci8_lob_t *)base;
@@ -106,9 +118,23 @@ static void oci8_lob_free(oci8_base_t *base)
if (lob->svchp != NULL
&& OCILobIsTemporary(oci8_envhp, oci8_errhp, lob->base.hp.lob, &is_temporary) == OCI_SUCCESS
&& is_temporary) {
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc);
- /* FIXME: This may stall the GC. */
- OCILobFreeTemporary(lob->svchp, oci8_errhp, lob->base.hp.lob);
+#ifdef HAVE_RB_THREAD_BLOCKING_REGION
+ if (NIL_P(svcctx->executing_thread)) {
+#endif
+ /* FIXME: This may stall the GC. */
+ OCILobFreeTemporary(lob->svchp, oci8_errhp, lob->base.hp.lob);
+#ifdef HAVE_RB_THREAD_BLOCKING_REGION
+ } else {
+ OCIError *errhp;
+ sword rv = OCIHandleAlloc(oci8_envhp, (void*)&errhp, OCI_HTYPE_ERROR, 0, 0);
+
+ if (rv != OCI_SUCCESS)
+ oci8_env_raise(oci8_envhp, rv);
+ oci8_add_pending_command(svcctx, oci8_lob_free_func, errhp, lob->base.hp.lob);
+ }
+#endif
}
lob->svc = Qnil;
lob->svchp = NULL;
diff --git a/ext/oci8/oci8.c b/ext/oci8/oci8.c
index f951cda..7abc62f 100644
--- a/ext/oci8/oci8.c
+++ b/ext/oci8/oci8.c
@@ -41,6 +41,13 @@ static VALUE cServer;
static ID id_at_session_handle;
static ID id_at_server_handle;
+struct oci8_command {
+ struct oci8_command *next;
+ void (*func)(oci8_svcctx_t *svcctx, void *arg1, void *arg2);
+ void *arg1;
+ void *arg2;
+};
+
typedef struct oci8_svcctx_associate {
oci8_base_t base;
oci8_svcctx_t *svcctx;
@@ -1156,3 +1163,30 @@ void oci8_check_pid_consistency(oci8_svcctx_t *svcctx)
}
}
+void oci8_add_pending_command(oci8_svcctx_t *svcctx, void (*func)(oci8_svcctx_t *, void *, void *), void *arg1, void *arg2)
+{
+ oci8_command_t *cmd = ALLOC(oci8_command_t);
+#if 0
+ fprintf(stderr, "add pending_command %p\n", cmd);
+#endif
+ cmd->next = svcctx->pending_commands;
+ cmd->func = func;
+ cmd->arg1 = arg1;
+ cmd->arg2 = arg2;
+ svcctx->pending_commands = cmd;
+}
+
+void oci8_execute_pending_commands(oci8_svcctx_t *svcctx)
+{
+ oci8_command_t *cmd, *cmd_next;
+
+ for (cmd = svcctx->pending_commands; cmd != NULL; cmd = cmd_next) {
+#if 0
+ fprintf(stderr, "call pending_command %p\n", cmd);
+#endif
+ cmd_next = cmd->next;
+ cmd->func(svcctx, cmd->arg1, cmd->arg2);
+ xfree(cmd);
+ }
+ svcctx->pending_commands = NULL;
+}
diff --git a/ext/oci8/oci8.h b/ext/oci8/oci8.h
index 96190f2..0243264 100644
--- a/ext/oci8/oci8.h
+++ b/ext/oci8/oci8.h
@@ -332,6 +332,7 @@ struct oci8_bind {
};
typedef struct oci8_logoff_strategy oci8_logoff_strategy_t;
+typedef struct oci8_command oci8_command_t;
typedef struct oci8_svcctx {
oci8_base_t base;
@@ -346,6 +347,7 @@ typedef struct oci8_svcctx {
char non_blocking;
#endif
VALUE long_read_len;
+ oci8_command_t *pending_commands;
} oci8_svcctx_t;
struct oci8_logoff_strategy {
@@ -477,6 +479,8 @@ oci8_svcctx_t *oci8_get_svcctx(VALUE obj);
OCISvcCtx *oci8_get_oci_svcctx(VALUE obj);
OCISession *oci8_get_oci_session(VALUE obj);
void oci8_check_pid_consistency(oci8_svcctx_t *svcctx);
+void oci8_add_pending_command(oci8_svcctx_t *svcctx, void (*)(oci8_svcctx_t *, void *, void *), void *, void *);
+void oci8_execute_pending_commands(oci8_svcctx_t *svcctx);
#define TO_SVCCTX oci8_get_oci_svcctx
#define TO_SESSION oci8_get_oci_session
diff --git a/ext/oci8/oci8lib.c b/ext/oci8/oci8lib.c
index 9cc39bc..9d0330d 100644
--- a/ext/oci8/oci8lib.c
+++ b/ext/oci8/oci8lib.c
@@ -246,6 +246,7 @@ sword oci8_blocking_region(oci8_svcctx_t *svcctx, rb_blocking_function_t func, v
svcctx->executing_thread = rb_thread_current();
/* Note: executing_thread is cleard at the end of the blocking function. */
rv = (sword)rb_thread_blocking_region(func, data, oci8_unblock_func, svcctx);
+ oci8_execute_pending_commands(svcctx);
if (rv == OCI_ERROR) {
if (oci8_get_error_code(oci8_errhp) == 1013) {
rb_raise(eOCIBreak, "Canceled by user request.");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment