summaryrefslogtreecommitdiff
path: root/eval_intern.h
diff options
context:
space:
mode:
Diffstat (limited to 'eval_intern.h')
-rw-r--r--eval_intern.h27
1 files changed, 23 insertions, 4 deletions
diff --git a/eval_intern.h b/eval_intern.h
index 190ef9195c..b945848a7a 100644
--- a/eval_intern.h
+++ b/eval_intern.h
@@ -108,14 +108,33 @@ extern int select_large_fdset(int, fd_set *, fd_set *, fd_set *, struct timeval
#define PUSH_TAG() TH_PUSH_TAG(GET_THREAD())
#define POP_TAG() TH_POP_TAG()
-#define TH_EXEC_TAG() ruby_setjmp(_th->tag->buf)
+/* clear th->state, and return the value */
+static inline int
+ruby_threadptr_tag_state(rb_thread_t *th)
+{
+ int state = th->state;
+ th->state = 0;
+ return state;
+}
+
+NORETURN(static inline void ruby_threadptr_tag_jump(rb_thread_t *, int));
+static inline void
+ruby_threadptr_tag_jump(rb_thread_t *th, int st)
+{
+ ruby_longjmp(th->tag->buf, (th->state = st));
+}
+
+/*
+ setjmp() in assignment expression rhs is undefined behavior
+ [ISO/IEC 9899:1999] 7.13.1.1
+*/
+#define TH_EXEC_TAG() \
+ (ruby_setjmp(_th->tag->buf) ? ruby_threadptr_tag_state(_th) : 0)
#define EXEC_TAG() \
TH_EXEC_TAG()
-#define TH_JUMP_TAG(th, st) do { \
- ruby_longjmp((th)->tag->buf,(st)); \
-} while (0)
+#define TH_JUMP_TAG(th, st) ruby_threadptr_tag_jump(th, st)
#define JUMP_TAG(st) TH_JUMP_TAG(GET_THREAD(), (st))