Author: Armin Rigo <[email protected]>
Branch: reverse-debugger
Changeset: r86137:8ac394503ebe
Date: 2016-08-11 10:45 +0200
http://bitbucket.org/pypy/pypy/changeset/8ac394503ebe/
Log: Careful, we need the gil_acquire byte as well: otherwise effects
like writing to GC objects might occur at the wrong time
diff --git a/rpython/translator/revdb/gencsupp.py
b/rpython/translator/revdb/gencsupp.py
--- a/rpython/translator/revdb/gencsupp.py
+++ b/rpython/translator/revdb/gencsupp.py
@@ -83,18 +83,19 @@
return call_code # a hack for ll_call_destructor() to mean
# that the calls should really be done
#
- # hack: we don't need the flag for at least this common function
- if call_code == 'RPyGilAcquire();':
- return 'RPY_REVDB_CALL_GILCTRL(%s);' % (call_code,)
- if call_code == 'RPyGilRelease();':
+ if call_code in ('RPyGilAcquire();', 'RPyGilRelease();'):
# Could also work with a regular RPY_REVDB_CALL_VOID, but we
- # use a different byte (0xFD instead of 0xFC) to detect more
- # sync misses. In a single-threaded environment this 0xFD
+ # use a different byte (0xFD, 0xFE instead of 0xFC) to detect more
+ # sync misses. In a single-threaded environment this 0xFD or 0xFE
# byte is not needed at all, but in a multi-threaded
# environment it ensures that during replaying, just after
- # reading the 0xFD, we switch to a different thread if needed
+ # reading the 0xFD or 0xFE, we switch to a different thread if needed
# (actually implemented with stacklets).
- return 'RPY_REVDB_CALL_GIL(%s);' % (call_code,)
+ if call_code == 'RPyGilAcquire();':
+ byte = '0xFD'
+ else:
+ byte = '0xFE'
+ return 'RPY_REVDB_CALL_GIL(%s, %s);' % (call_code, byte)
#
tp = funcgen.lltypename(v_result)
if tp == 'void @':
diff --git a/rpython/translator/revdb/src-revdb/revdb.c
b/rpython/translator/revdb/src-revdb/revdb.c
--- a/rpython/translator/revdb/src-revdb/revdb.c
+++ b/rpython/translator/revdb/src-revdb/revdb.c
@@ -57,8 +57,8 @@
static char rpy_rev_buffer[16384]; /* max. 32768 */
int rpy_rev_fileno = -1;
static char flag_io_disabled = FID_REGULAR_MODE;
-__thread bool_t rpy_active_thread;
-static bool_t *rpy_active_thread_ptr;
+__thread int rpy_active_thread;
+static int *rpy_active_thread_ptr;
static void setup_record_mode(int argc, char *argv[]);
@@ -1680,7 +1680,8 @@
RPY_EXTERN
void rpy_reverse_db_bad_acquire_gil(void)
{
- fprintf(stderr, "out of sync: unexpected byte in log (at acquire_gil)\n");
+ fprintf(stderr, "out of sync: unexpected byte in log "
+ " (at acquire_gil or release_gil)\n");
exit(1);
}
diff --git a/rpython/translator/revdb/src-revdb/revdb_include.h
b/rpython/translator/revdb/src-revdb/revdb_include.h
--- a/rpython/translator/revdb/src-revdb/revdb_include.h
+++ b/rpython/translator/revdb/src-revdb/revdb_include.h
@@ -15,7 +15,7 @@
# error "explicit RPY_RDB_REPLAY: not really supported"
#endif
bool_t watch_enabled;
- long lock;
+ int lock;
char *buf_p, *buf_limit, *buf_readend;
uint64_t stop_point_seen, stop_point_break;
uint64_t unique_id_seen, unique_id_break;
@@ -23,7 +23,7 @@
RPY_EXTERN rpy_revdb_t rpy_revdb;
RPY_EXTERN int rpy_rev_fileno;
-RPY_EXTERN __thread bool_t rpy_active_thread;
+RPY_EXTERN __thread int rpy_active_thread;
/* ------------------------------------------------------------ */
@@ -66,11 +66,15 @@
/* Acquire/release the lock around EMIT_RECORD, because it may be
called without holding the GIL. Note that we're always
single-threaded during replaying: the lock is only useful during
- recording. */
+ recording.
+
+ Implementation trick: use 'a >= b' to mean 'a || !b' (the two
+ variables can only take the values 0 or 1).
+*/
#define _RPY_REVDB_LOCK() \
{ \
- bool_t _lock_contention = pypy_lock_test_and_set(&rpy_revdb.lock, 1); \
- if (_lock_contention || !rpy_active_thread) \
+ int _lock_contention = pypy_lock_test_and_set(&rpy_revdb.lock, 1); \
+ if (_lock_contention >= rpy_active_thread) \
rpy_reverse_db_lock_acquire(_lock_contention); \
}
#define _RPY_REVDB_UNLOCK() \
@@ -143,17 +147,17 @@
rpy_reverse_db_invoke_callback(_re); \
}
-#define RPY_REVDB_CALL_GIL(call_code) \
+#define RPY_REVDB_CALL_GIL(call_code, byte) \
if (!RPY_RDB_REPLAY) { \
call_code \
_RPY_REVDB_LOCK(); \
- _RPY_REVDB_EMIT_RECORD_L(unsigned char _e, 0xFD) \
+ _RPY_REVDB_EMIT_RECORD_L(unsigned char _e, byte) \
_RPY_REVDB_UNLOCK(); \
} \
else { \
unsigned char _re; \
_RPY_REVDB_EMIT_REPLAY(unsigned char _e, _re) \
- if (_re != 0xFD) \
+ if (_re != byte) \
rpy_reverse_db_bad_acquire_gil(); \
}
diff --git a/rpython/translator/revdb/test/test_basic.py
b/rpython/translator/revdb/test/test_basic.py
--- a/rpython/translator/revdb/test/test_basic.py
+++ b/rpython/translator/revdb/test/test_basic.py
@@ -95,12 +95,16 @@
x = self.next(); assert x == len(expected_string)
self.same_stack() # errno
x = self.next('i'); assert x == 0 # errno
+ self.gil_acquire()
def same_stack(self):
x = self.next('c'); assert x == '\xFC'
+ def gil_acquire(self):
+ x = self.next('c'); assert x == '\xFD'
+
def gil_release(self):
- x = self.next('c'); assert x == '\xFD'
+ x = self.next('c'); assert x == '\xFE'
def switch_thread(self, expected=None):
th, = self.special_packet(ASYNC_THREAD_SWITCH, 'q')
diff --git a/rpython/translator/revdb/test/test_callback.py
b/rpython/translator/revdb/test/test_callback.py
--- a/rpython/translator/revdb/test/test_callback.py
+++ b/rpython/translator/revdb/test/test_callback.py
@@ -66,16 +66,20 @@
rdb.gil_release()
rdb.same_stack() # callmesimple()
x = rdb.next('i'); assert x == 55555
+ rdb.gil_acquire()
rdb.write_call('55555\n')
rdb.gil_release()
b = rdb.next('!h'); assert 300 <= b < 310 # -> callback
x = rdb.next('i'); assert x == 40 # arg n
+ rdb.gil_acquire()
rdb.gil_release()
x = rdb.next('!h'); assert x == b # -> callback
x = rdb.next('i'); assert x == 3 # arg n
+ rdb.gil_acquire()
rdb.gil_release()
rdb.same_stack() # <- return in main thread
x = rdb.next('i'); assert x == 4000 * 300 # return from callme()
+ rdb.gil_acquire()
rdb.write_call('%s\n' % (4000 * 300,))
x = rdb.next('q'); assert x == 0 # number of stop points
assert rdb.done()
@@ -88,14 +92,17 @@
rdb.gil_release()
b = rdb.next('!h'); assert 300 <= b < 310 # -> callback
x = rdb.next('i'); assert x == 40 # arg n
+ rdb.gil_acquire()
rdb.write_call('40\n')
rdb.gil_release()
x = rdb.next('!h'); assert x == b # -> callback again
x = rdb.next('i'); assert x == 3 # arg n
+ rdb.gil_acquire()
rdb.write_call('3\n')
rdb.gil_release()
rdb.same_stack() # -> return in main thread
x = rdb.next('i'); assert x == 120 # <- return from callme()
+ rdb.gil_acquire()
rdb.write_call('120\n')
x = rdb.next('q'); assert x == 2 # number of stop points
assert rdb.done()
diff --git a/rpython/translator/revdb/test/test_thread.py
b/rpython/translator/revdb/test/test_thread.py
--- a/rpython/translator/revdb/test/test_thread.py
+++ b/rpython/translator/revdb/test/test_thread.py
@@ -41,34 +41,40 @@
th_B = rdb.switch_thread()
assert th_B != th_A
b = rdb.next('!h'); assert 300 <= b < 310 # "callback": start thread
+ rdb.gil_acquire()
rdb.gil_release()
rdb.switch_thread(th_A)
rdb.same_stack() # start_new_thread returns
x = rdb.next(); assert x == th_B # result is the 'th_B' id
+ rdb.gil_acquire()
rdb.gil_release()
rdb.switch_thread(th_B)
- rdb.same_stack() # sleep()
+ rdb.same_stack() # sleep() (finishes here)
rdb.next('i') # sleep()
+ rdb.gil_acquire()
rdb.write_call("BB\n")
rdb.gil_release()
rdb.switch_thread(th_A)
rdb.same_stack() # sleep()
rdb.next('i') # sleep()
+ rdb.gil_acquire()
rdb.write_call("AAAA\n")
rdb.gil_release()
rdb.switch_thread(th_B)
rdb.same_stack() # sleep()
rdb.next('i') # sleep()
+ rdb.gil_acquire()
rdb.write_call("BBB\n")
rdb.gil_release()
rdb.switch_thread(th_A)
rdb.same_stack() # sleep()
rdb.next('i') # sleep()
+ rdb.gil_acquire()
rdb.write_call("AAAA\n")
rdb.done()
diff --git a/rpython/translator/revdb/test/test_weak.py
b/rpython/translator/revdb/test/test_weak.py
--- a/rpython/translator/revdb/test/test_weak.py
+++ b/rpython/translator/revdb/test/test_weak.py
@@ -204,8 +204,9 @@
y = intmask(rdb.next('q')); assert y == -1
triggered = True
rdb.gil_release()
- rdb.same_stack()
- j = rdb.next()
+ rdb.same_stack() #
+ j = rdb.next() # call to foobar()
+ rdb.gil_acquire()
assert j == i + 1000000 * triggered
if triggered:
lst = []
@@ -217,8 +218,9 @@
uid_seen.add(uid)
lst.append(uid)
rdb.gil_release()
- rdb.same_stack()
- totals.append((lst, intmask(rdb.next())))
+ rdb.same_stack() #
+ totals.append((lst, intmask(rdb.next()))) # call to foobar()
+ rdb.gil_acquire()
x = rdb.next('q'); assert x == 3000 # number of stop points
#
assert 1500 <= len(uid_seen) <= 3000
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit