summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--internal.h1
-rw-r--r--io.c1
-rw-r--r--test/ruby/test_signal.rb13
-rw-r--r--thread.c23
5 files changed, 41 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index 8b4a3f6..b26e2c4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+Wed Nov 28 16:21:46 2012 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * thread.c (struct rb_mutex_struct): add allow_trap field.
+ * internal.h (rb_mutex_allow_trap): added.
+ * thread.c (rb_mutex_lock, rb_mutex_unlock): check mutex->allow_trap.
+ * thread.c (mutex_sleep): remove trap check because it uses
+ rb_mutex_lock and rb_mutex_unlock internally.
+ * thread.c (rb_mutex_allow_trap): new helper function for the above.
+
+ * io.c (io_binwrite): mark fptr->write_lock as writable in trap.
+
+ * test/ruby/test_signal.rb (test_trap_puts): test for the above.
+
Wed Nov 28 16:59:12 2012 Koichi Sasada <ko1@atdot.net>
* proc.c: remove Proc#== and Proc#eql?.
diff --git a/internal.h b/internal.h
index 0dd93d9..86181f9 100644
--- a/internal.h
+++ b/internal.h
@@ -278,6 +278,7 @@ VALUE rb_thread_shield_new(void);
VALUE rb_thread_shield_wait(VALUE self);
VALUE rb_thread_shield_release(VALUE self);
VALUE rb_thread_shield_destroy(VALUE self);
+void rb_mutex_allow_trap(VALUE self, int val);
/* thread_pthread.c, thread_win32.c */
void Init_native_thread(void);
diff --git a/io.c b/io.c
index cab47d0..63bb8a0 100644
--- a/io.c
+++ b/io.c
@@ -1126,6 +1126,7 @@ io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync)
fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
fptr->write_lock = rb_mutex_new();
+ rb_mutex_allow_trap(fptr->write_lock, 1);
}
if ((!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY))) ||
(fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)) {
diff --git a/test/ruby/test_signal.rb b/test/ruby/test_signal.rb
index 63d6d9d..3a89240 100644
--- a/test/ruby/test_signal.rb
+++ b/test/ruby/test_signal.rb
@@ -260,4 +260,17 @@ EOS
end
end
end
+
+ def test_trap_puts
+ assert_in_out_err([], <<-INPUT, ["a"*10000], [])
+ Signal.trap(:INT) {
+ # for enable internal io mutex
+ sync = false
+ # larger than internal io buffer
+ print "a"*10000
+ }
+ Process.kill :INT, $$
+ sleep 0.1
+ INPUT
+ end
end
diff --git a/thread.c b/thread.c
index 97ab79f..f32da2c 100644
--- a/thread.c
+++ b/thread.c
@@ -342,6 +342,7 @@ typedef struct rb_mutex_struct
struct rb_thread_struct volatile *th;
int cond_waiting;
struct rb_mutex_struct *next_mutex;
+ int allow_trap;
} rb_mutex_t;
static void rb_mutex_abandon_all(rb_mutex_t *mutexes);
@@ -4140,16 +4141,15 @@ VALUE
rb_mutex_lock(VALUE self)
{
rb_thread_t *th = GET_THREAD();
+ rb_mutex_t *mutex;
+ GetMutexPtr(self, mutex);
/* When running trap handler */
- if (th->interrupt_mask & TRAP_INTERRUPT_MASK) {
+ if (!mutex->allow_trap && th->interrupt_mask & TRAP_INTERRUPT_MASK) {
rb_raise(rb_eThreadError, "can't be called from trap context");
}
if (rb_mutex_trylock(self) == Qfalse) {
- rb_mutex_t *mutex;
- GetMutexPtr(self, mutex);
-
if (mutex->th == GET_THREAD()) {
rb_raise(rb_eThreadError, "deadlock; recursive locking");
}
@@ -4254,7 +4254,7 @@ rb_mutex_unlock(VALUE self)
GetMutexPtr(self, mutex);
/* When running trap handler */
- if (GET_THREAD()->interrupt_mask & TRAP_INTERRUPT_MASK) {
+ if (!mutex->allow_trap && GET_THREAD()->interrupt_mask & TRAP_INTERRUPT_MASK) {
rb_raise(rb_eThreadError, "can't be called from trap context");
}
@@ -4326,11 +4326,6 @@ mutex_sleep(int argc, VALUE *argv, VALUE self)
{
VALUE timeout;
- /* When running trap handler */
- if (GET_THREAD()->interrupt_mask & TRAP_INTERRUPT_MASK) {
- rb_raise(rb_eThreadError, "can't be called from trap context");
- }
-
rb_scan_args(argc, argv, "01", &timeout);
return rb_mutex_sleep(self, timeout);
}
@@ -4367,6 +4362,14 @@ rb_mutex_synchronize_m(VALUE self, VALUE args)
return rb_mutex_synchronize(self, rb_yield, Qnil);
}
+void rb_mutex_allow_trap(VALUE self, int val)
+{
+ rb_mutex_t *m;
+ GetMutexPtr(self, m);
+
+ m->allow_trap = val;
+}
+
/*
* Document-class: ThreadShield
*/