in other words code that one cannot reason about, from non-reentrant
code (holding locks), @code{WITHOUT-INTERRUPTS}, @code{WITHOUT-GCING}
is dangerous and best avoided.
+
+@section Debugging
+
+It is not easy to debug signal problems. The best bet probably is to
+enable @code{QSHOW} and @code{QSHOW_SIGNALS} in runtime.h and once
+SBCL runs into problems attach gdb. A simple @code{thread apply all
+ba} is already tremendously useful. Another possibility is to send a
+SIGABORT to SBCL to provoke landing in LDB, if it's compiled with it
+and it has not yet done so on its own.
+
+Note, that fprintf used by QSHOW is not reentrant and at least on x86
+linux it is known to cause deadlocks, so place SHOW and co carefully,
+ideally to places where blockable signals are blocked. Use
+@code{QSHOW_SAFE} if you like.
fprintf(stderr,
"/non-movable pages due to conservative pointers = %d (%d bytes)\n",
num_dont_move_pages,
- npage_bytes(num_dont_move_pages);
+ npage_bytes(num_dont_move_pages));
}
#endif
}
/* initialized in interrupt_init */
-static sigset_t deferrable_sigset;
-static sigset_t blockable_sigset;
+sigset_t deferrable_sigset;
+sigset_t blockable_sigset;
#endif
void
store_signal_data_for_later(data,handler,signal,info,context);
SetSymbolValue(INTERRUPT_PENDING, T,thread);
FSHOW_SIGNAL((stderr,
- "/maybe_defer_handler(%x,%d),thread=%lu: deferred\n",
- (unsigned int)handler,signal,
- (unsigned long)thread->os_thread));
+ "/maybe_defer_handler(%x,%d): deferred\n",
+ (unsigned int)handler,signal));
return 1;
}
/* a slightly confusing test. arch_pseudo_atomic_atomic() doesn't
store_signal_data_for_later(data,handler,signal,info,context);
arch_set_pseudo_atomic_interrupted(context);
FSHOW_SIGNAL((stderr,
- "/maybe_defer_handler(%x,%d),thread=%lu: deferred(PA)\n",
- (unsigned int)handler,signal,
- (unsigned long)thread->os_thread));
+ "/maybe_defer_handler(%x,%d): deferred(PA)\n",
+ (unsigned int)handler,signal));
return 1;
}
FSHOW_SIGNAL((stderr,
- "/maybe_defer_handler(%x,%d),thread=%lu: not deferred\n",
- (unsigned int)handler,signal,
- (unsigned long)thread->os_thread));
+ "/maybe_defer_handler(%x,%d): not deferred\n",
+ (unsigned int)handler,signal));
return 0;
}
if (arch_pseudo_atomic_atomic(context)) {
SetSymbolValue(STOP_FOR_GC_PENDING,T,thread);
arch_set_pseudo_atomic_interrupted(context);
- FSHOW_SIGNAL((stderr,"thread=%lu sig_stop_for_gc deferred (PA)\n",
- thread->os_thread));
+ FSHOW_SIGNAL((stderr, "sig_stop_for_gc deferred (PA)\n"));
return;
}
else if (SymbolValue(GC_INHIBIT,thread) != NIL) {
SetSymbolValue(STOP_FOR_GC_PENDING,T,thread);
- FSHOW_SIGNAL((stderr,
- "thread=%lu sig_stop_for_gc deferred (*GC-INHIBIT*)\n",
- thread->os_thread));
+ FSHOW_SIGNAL((stderr, "sig_stop_for_gc deferred (*GC-INHIBIT*)\n"));
return;
}
}
thread->state=STATE_SUSPENDED;
- FSHOW_SIGNAL((stderr,"thread=%lu suspended\n",thread->os_thread));
+ FSHOW_SIGNAL((stderr,"suspended\n"));
sigemptyset(&ss);
#if defined(SIG_RESUME_FROM_GC)
while (sigwaitinfo(&ss,0) != SIG_STOP_FOR_GC);
#endif
- FSHOW_SIGNAL((stderr,"thread=%lu resumed\n",thread->os_thread));
+ FSHOW_SIGNAL((stderr,"resumed\n"));
if(thread->state!=STATE_RUNNING) {
lose("sig_stop_for_gc_handler: wrong thread state on wakeup: %ld\n",
fixnum_value(thread->state));
*os_context_register_addr(context,reg_CODE) =
(os_context_register_t)(fun + FUN_POINTER_LOWTAG);
#endif
+ FSHOW((stderr, "/arranged return to Lisp function (0x%lx)\n",
+ (long)function));
}
#ifdef LISP_FEATURE_SB_THREAD
{
os_context_t *context = (os_context_t*)arch_os_get_context(&v_context);
+ FSHOW_SIGNAL((stderr,"/interrupt_thread_handler\n"));
+ check_blockables_blocked_or_lose();
+
/* let the handler enable interrupts again when it sees fit */
sigaddset_deferrable(os_context_sigmask_addr(context));
arrange_return_to_lisp_function(context,
/* FIXME: do not rely on NSIG being a multiple of 8 */
#define REAL_SIGSET_SIZE_BYTES ((NSIG/8))
+extern sigset_t deferrable_sigset;
+extern sigset_t blockable_sigset;
+
extern void check_blockables_blocked_or_lose(void);
extern void check_gc_signals_unblocked_or_lose(void);
extern void unblock_gc_signals(void);
#ifndef _SBCL_RUNTIME_H_
#define _SBCL_RUNTIME_H_
-/*#define QSHOW */ /* Enable low-level debugging output? */
+#if defined(LISP_FEATURE_SB_THREAD)
+#define thread_self pthread_self
+#define thread_kill pthread_kill
+#define thread_sigmask pthread_sigmask
+#define thread_mutex_lock(l) pthread_mutex_lock(l)
+#define thread_mutex_unlock(l) pthread_mutex_unlock(l)
+#else
+#define thread_self getpid
+#define thread_kill kill
+#define thread_sigmask sigprocmask
+#define thread_mutex_lock(l) 0
+#define thread_mutex_unlock(l) 0
+#endif
+
+/* #define QSHOW */ /* Enable low-level debugging output? */
+/* #define QSHOW_SAFE */ /* Enable blocking interrupts for each SHOW. */
#ifdef QSHOW
-#define FSHOW(args) fprintf args
+
+#ifdef QSHOW_SAFE
+
+#include <signal.h>
+extern sigset_t blockable_sigset;
+
+#define QSHOW_BLOCK \
+ sigset_t oldset; \
+ thread_sigmask(SIG_BLOCK, &blockable_sigset, &oldset);
+#define QSHOW_UNBLOCK thread_sigmask(SIG_SETMASK,&oldset,0);
+#else
+#define QSHOW_BLOCK
+#define QSHOW_UNBLOCK
+#endif
+
+#ifdef LISP_FEATURE_SB_THREAD
+#define QSHOW_PREFIX fprintf(stderr, "%lu ", pthread_self());
+#else
+#define QSHOW_PREFIX
+#endif
+
+#define FSHOW(args) \
+ do { \
+ QSHOW_BLOCK \
+ QSHOW_PREFIX \
+ fprintf args; \
+ QSHOW_UNBLOCK \
+ } while (0)
#define SHOW(string) FSHOW((stderr, "/%s\n", string))
+
#else
+
#define FSHOW(args)
#define SHOW(string)
+
#endif
/* Enable extra-verbose low-level debugging output for signals? (You
(kid_tid,th->os_attr,(void *(*)(void *))new_thread_trampoline,th))) {
FSHOW_SIGNAL((stderr, "init = %d\n", initcode));
FSHOW_SIGNAL((stderr, printf("pthread_create returned %d, errno %d\n", retcode, errno)));
- FSHOW_SIGNAL((stderr, "wanted stack size %d, min stack size %d\n",
- cstack_size, PTHREAD_STACK_MIN));
if(retcode < 0) {
perror("create_os_thread");
}
int signal_interrupt_thread(os_thread_t os_thread)
{
int status = kill_thread_safely(os_thread, SIG_INTERRUPT_THREAD);
+ FSHOW_SIGNAL((stderr,"/signal_interrupt_thread: %lu\n", os_thread));
if (status == 0) {
return 0;
} else if (status == ESRCH) {
#ifdef LOCK_CREATE_THREAD
/* KLUDGE: Stopping the thread during pthread_create() causes deadlock
* on FreeBSD. */
- FSHOW_SIGNAL((stderr,"/gc_stop_the_world:waiting on create_thread_lock, thread=%lu\n",
- th->os_thread));
+ FSHOW_SIGNAL((stderr,"/gc_stop_the_world:waiting on create_thread_lock\n"));
lock_ret = pthread_mutex_lock(&create_thread_lock);
gc_assert(lock_ret == 0);
- FSHOW_SIGNAL((stderr,"/gc_stop_the_world:got create_thread_lock, thread=%lu\n",
- th->os_thread));
+ FSHOW_SIGNAL((stderr,"/gc_stop_the_world:got create_thread_lock\n"));
#endif
- FSHOW_SIGNAL((stderr,"/gc_stop_the_world:waiting on lock, thread=%lu\n",
- th->os_thread));
+ FSHOW_SIGNAL((stderr,"/gc_stop_the_world:waiting on lock\n"));
/* keep threads from starting while the world is stopped. */
lock_ret = pthread_mutex_lock(&all_threads_lock); \
gc_assert(lock_ret == 0);
- FSHOW_SIGNAL((stderr,"/gc_stop_the_world:got lock, thread=%lu\n",
- th->os_thread));
+ FSHOW_SIGNAL((stderr,"/gc_stop_the_world:got lock\n"));
/* stop all other threads by sending them SIG_STOP_FOR_GC */
for(p=all_threads; p; p=p->next) {
gc_assert(p->os_thread != 0);
- FSHOW_SIGNAL((stderr,"/gc_stop_the_world: p->state: %x\n", p->state));
+ FSHOW_SIGNAL((stderr,"/gc_stop_the_world: thread=%lu, state=%x\n",
+ p->os_thread, p->state));
if((p!=th) && ((p->state==STATE_RUNNING))) {
- FSHOW_SIGNAL((stderr,"/gc_stop_the_world: suspending %x, os_thread %x\n",
- p, p->os_thread));
+ FSHOW_SIGNAL((stderr,"/gc_stop_the_world: suspending thread %lu\n",
+ p->os_thread));
status=kill_thread_safely(p->os_thread,SIG_STOP_FOR_GC);
if (status==ESRCH) {
/* This thread has exited. */
}
FSHOW_SIGNAL((stderr,"/gc_stop_the_world:signals sent\n"));
/* wait for the running threads to stop or finish */
- for(p=all_threads;p;) {
- FSHOW_SIGNAL((stderr,"/gc_stop_the_world: th: %p, p: %p\n", th, p));
- if((p!=th) && (p->state==STATE_RUNNING)) {
- sched_yield();
- } else {
- p=p->next;
+ {
+#if QSHOW_SIGNALS
+ struct thread *prev = 0;
+#endif
+ for(p=all_threads;p;) {
+#if QSHOW_SIGNALS
+ if ((p!=th)&&(p!=prev)&&(p->state==STATE_RUNNING)) {
+ FSHOW_SIGNAL
+ ((stderr,
+ "/gc_stop_the_world: waiting for thread=%lu: state=%x\n",
+ p->os_thread, p->state));
+ prev=p;
+ }
+#endif
+ if((p!=th) && (p->state==STATE_RUNNING)) {
+ sched_yield();
+ } else {
+ p=p->next;
+ }
}
}
FSHOW_SIGNAL((stderr,"/gc_stop_the_world:end\n"));
#define EXCEPTION_PORT_TO_THREAD_STRUCT(th) ((struct thread *) th)
#endif
-#if defined(LISP_FEATURE_SB_THREAD)
-#define thread_self pthread_self
-#define thread_kill pthread_kill
-#define thread_sigmask pthread_sigmask
-#define thread_mutex_lock(l) pthread_mutex_lock(l)
-#define thread_mutex_unlock(l) pthread_mutex_unlock(l)
-#else
-#define thread_self getpid
-#define thread_kill kill
-#define thread_sigmask sigprocmask
-#define thread_mutex_lock(l) 0
-#define thread_mutex_unlock(l) 0
-#endif
-
extern void create_initial_thread(lispobj);
extern int kill_thread_safely(os_thread_t os_thread, int signo);
;;; checkins which aren't released. (And occasionally for internal
;;; versions, especially for internal versions off the main CVS
;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"1.0.25.17"
+"1.0.25.18"