Update of /cvsroot/sbcl/sbcl/src/runtime
In directory sc8-pr-cvs8.sourceforge.net:/tmp/cvs-serv2242/src/runtime
Modified Files:
Tag: lutex-branch
thread.c pthread-lutex.c gencgc.c
Log Message:
0.9.12.26.lutex-branch.40
* When scavenging an interrupt_context on Darwin, use the
os_context_register_addr (and .._pc_addr) macros for getting the
address of the registers as these are not members of a struct
member of the context itself, but rather are members of a struct
pointed to by a pointer in the context. This fixes various
GC-related memory corruption problems.
* added lutex_assert and various thread_mutex_[un]lock assertions
* define FREEABLE_STACK_QUEUE_SIZE and set it to 4 instead of
hardcoding 8.
* update x86-darwin-threads internals-note
Index: thread.c
===================================================================
RCS file: /cvsroot/sbcl/sbcl/src/runtime/thread.c,v
retrieving revision 1.62.2.11
retrieving revision 1.62.2.12
diff -u -d -r1.62.2.11 -r1.62.2.12
--- thread.c 18 May 2006 22:35:00 -0000 1.62.2.11
+++ thread.c 21 May 2006 01:04:41 -0000 1.62.2.12
@@ -172,9 +172,11 @@
}
}
+#define FREEABLE_STACK_QUEUE_SIZE 4
+
static void
free_freeable_stacks() {
- if (freeable_stack_queue && (freeable_stack_count > 8)) {
+ if (freeable_stack_queue && (freeable_stack_count > FREEABLE_STACK_QUEUE_SIZE)) {
struct freeable_stack* old;
pthread_mutex_lock(&freeable_stack_lock);
old = freeable_stack_queue;
@@ -227,7 +229,7 @@
new_thread_trampoline(struct thread *th)
{
lispobj function;
- int result;
+ int result, lock_ret;
FSHOW((stderr,"/creating thread %lu\n", thread_self()));
function = th->no_tls_value_marker;
th->no_tls_value_marker = NO_TLS_VALUE_MARKER_WIDETAG;
@@ -242,19 +244,24 @@
* list and we're just adding this thread to it there is no danger
* of deadlocking even with SIG_STOP_FOR_GC blocked (which it is
* not). */
- pthread_mutex_lock(&all_threads_lock);
+ lock_ret = pthread_mutex_lock(&all_threads_lock);
+ gc_assert(lock_ret == 0);
link_thread(th);
- pthread_mutex_unlock(&all_threads_lock);
+ lock_ret = pthread_mutex_unlock(&all_threads_lock);
+ gc_assert(lock_ret == 0);
result = funcall0(function);
th->state=STATE_DEAD;
/* SIG_STOP_FOR_GC is blocked and GC might be waiting for this
* thread, but since we are already dead it won't wait long. */
- pthread_mutex_lock(&all_threads_lock);
+ lock_ret = pthread_mutex_lock(&all_threads_lock);
+ gc_assert(lock_ret == 0);
+
gc_alloc_update_page_tables(0, &th->alloc_region);
unlink_thread(th);
pthread_mutex_unlock(&all_threads_lock);
+ gc_assert(lock_ret == 0);
if(th->tls_cookie>=0) arch_os_thread_cleanup(th);
os_invalidate((os_vm_address_t)th->interrupt_data,
@@ -534,11 +541,13 @@
void gc_stop_the_world()
{
struct thread *p,*th=arch_os_get_current_thread();
- int status;
+ int status, lock_ret;
FSHOW_SIGNAL((stderr,"/gc_stop_the_world:waiting on lock, thread=%lu\n",
th->os_thread));
/* keep threads from starting while the world is stopped. */
- pthread_mutex_lock(&all_threads_lock); \
+ 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));
/* stop all other threads by sending them SIG_STOP_FOR_GC */
@@ -574,7 +583,7 @@
void gc_start_the_world()
{
struct thread *p,*th=arch_os_get_current_thread();
- int status;
+ int status, lock_ret;
/* if a resumed thread creates a new thread before we're done with
* this loop, the new thread will get consed on the front of
* all_threads, but it won't have been stopped so won't need
@@ -620,7 +629,9 @@
}
#endif
- pthread_mutex_unlock(&all_threads_lock);
+ lock_ret = pthread_mutex_unlock(&all_threads_lock);
+ gc_assert(lock_ret == 0);
+
FSHOW_SIGNAL((stderr,"/gc_start_the_world:end\n"));
}
#endif
Index: pthread-lutex.c
===================================================================
RCS file: /cvsroot/sbcl/sbcl/src/runtime/Attic/pthread-lutex.c,v
retrieving revision 1.1.2.4
retrieving revision 1.1.2.5
diff -u -d -r1.1.2.4 -r1.1.2.5
--- pthread-lutex.c 18 May 2006 22:39:58 -0000 1.1.2.4
+++ pthread-lutex.c 21 May 2006 01:04:41 -0000 1.1.2.5
@@ -26,6 +26,27 @@
typedef unsigned long tagged_lutex_t;
+#if 1
+# define lutex_assert(ex) \
+do { \
+ if (!(ex)) lutex_abort(); \
+} while (0)
+# define lutex_assert_verbose(ex, fmt, ...) \
+do { \
+ if (!(ex)) { \
+ fprintf(stderr, fmt, ## __VA_ARGS__); \
+ lutex_abort(); \
+ } \
+} while (0)
+#else
+# define lutex_assert(ex)
+# define lutex_assert_verbose(ex, fmt, ...)
+#endif
+
+#define lutex_abort() \
+ lose("Lutex assertion failure, file \"%s\", line %d\n", __FILE__, __LINE__)
+
+
/* FIXME: Add some real error checking. */
pthread_mutex_t lutex_register_lock = PTHREAD_MUTEX_INITIALIZER;
@@ -37,17 +58,25 @@
struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
lutex->mutex = malloc(sizeof(pthread_mutex_t));
+ lutex_assert(lutex->mutex != 0);
+
ret = pthread_mutex_init(lutex->mutex, NULL);
+ lutex_assert(ret == 0);
- thread_mutex_lock(&lutex_register_lock);
- gencgc_register_lutex(lutex);
- thread_mutex_unlock(&lutex_register_lock);
+ ret = thread_mutex_lock(&lutex_register_lock);
+ lutex_assert(ret == 0);
- if (ret)
- return ret;
+ gencgc_register_lutex(lutex);
+ lutex_assert(ret == 0);
+
+ ret = thread_mutex_unlock(&lutex_register_lock);
+ lutex_assert(ret == 0);
lutex->condition_variable = malloc(sizeof(pthread_cond_t));
+ lutex_assert(ret == 0);
+
ret = pthread_cond_init(lutex->condition_variable, NULL);
+ lutex_assert(ret == 0);
return ret;
}
@@ -60,6 +89,7 @@
struct lutex *mutex_lutex = (struct lutex*) native_pointer(tagged_mutex_lutex);
ret = pthread_cond_wait(queue_lutex->condition_variable, mutex_lutex->mutex);
+ lutex_assert(ret == 0);
return ret;
}
@@ -74,6 +104,7 @@
if (n >= ((1 << 29) - 1)) {
/* CONDITION-BROADCAST */
ret = pthread_cond_broadcast(lutex->condition_variable);
+ lutex_assert(ret == 0);
} else{
/* We're holding the lutex mutex, so a thread we're waking can't
* re-enter the wait between to calls to pthread_cond_signal. Thus
@@ -82,8 +113,7 @@
*/
while (n--) {
ret = pthread_cond_signal(lutex->condition_variable);
- if (ret)
- return ret;
+ lutex_assert(ret == 0);
}
}
@@ -93,17 +123,25 @@
int
lutex_lock (tagged_lutex_t tagged_lutex)
{
+ int ret = 0;
struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
+
+ ret = thread_mutex_lock(lutex->mutex);
+ lutex_assert(ret == 0);
- return pthread_mutex_lock(lutex->mutex);
+ return ret;
}
int
lutex_unlock (tagged_lutex_t tagged_lutex)
{
+ int ret = 0;
struct lutex *lutex = (struct lutex*) native_pointer(tagged_lutex);
- return pthread_mutex_unlock(lutex->mutex);
+ ret = thread_mutex_unlock(lutex->mutex);
+ lutex_assert(ret == 0);
+
+ return ret;
}
int
Index: gencgc.c
===================================================================
RCS file: /cvsroot/sbcl/sbcl/src/runtime/gencgc.c,v
retrieving revision 1.99.2.1
retrieving revision 1.99.2.2
diff -u -d -r1.99.2.1 -r1.99.2.2
--- gencgc.c 13 May 2006 16:32:13 -0000 1.99.2.1
+++ gencgc.c 21 May 2006 01:04:41 -0000 1.99.2.2
@@ -588,6 +588,7 @@
page_index_t last_page;
long bytes_found;
page_index_t i;
+ int ret;
/*
FSHOW((stderr,
@@ -599,7 +600,8 @@
gc_assert((alloc_region->first_page == 0)
&& (alloc_region->last_page == -1)
&& (alloc_region->free_pointer == alloc_region->end_addr));
- thread_mutex_lock(&free_pages_lock);
+ ret = thread_mutex_lock(&free_pages_lock);
+ gc_assert(ret == 0);
if (unboxed) {
first_page =
generations[gc_alloc_generation].alloc_unboxed_start_page;
@@ -660,7 +662,8 @@
/* do we only want to call this on special occasions? like for boxed_region? */
set_alloc_pointer((lispobj)(((char *)heap_base) + last_free_page*PAGE_BYTES));
}
- thread_mutex_unlock(&free_pages_lock);
+ ret = thread_mutex_unlock(&free_pages_lock);
+ gc_assert(ret == 0);
/* we can do this after releasing free_pages_lock */
if (gencgc_zero_check) {
@@ -802,6 +805,7 @@
long orig_first_page_bytes_used;
long region_size;
long byte_cnt;
+ int ret;
first_page = alloc_region->first_page;
@@ -812,7 +816,8 @@
next_page = first_page+1;
- thread_mutex_lock(&free_pages_lock);
+ ret = thread_mutex_lock(&free_pages_lock);
+ gc_assert(ret == 0);
if (alloc_region->free_pointer != alloc_region->start_addr) {
/* some bytes were allocated in the region */
orig_first_page_bytes_used = page_table[first_page].bytes_used;
@@ -916,7 +921,9 @@
page_table[next_page].allocated = FREE_PAGE_FLAG;
next_page++;
}
- thread_mutex_unlock(&free_pages_lock);
+ ret = thread_mutex_unlock(&free_pages_lock);
+ gc_assert(ret == 0);
+
/* alloc_region is per-thread, we're ok to do this unlocked */
gc_set_region_empty(alloc_region);
}
@@ -934,8 +941,10 @@
int more;
long bytes_used;
page_index_t next_page;
+ int ret;
- thread_mutex_lock(&free_pages_lock);
+ ret = thread_mutex_lock(&free_pages_lock);
+ gc_assert(ret == 0);
if (unboxed) {
first_page =
@@ -1035,7 +1044,8 @@
last_free_page = last_page+1;
set_alloc_pointer((lispobj)(((char *)heap_base) + last_free_page*PAGE_BYTES));
}
- thread_mutex_unlock(&free_pages_lock);
+ ret = thread_mutex_unlock(&free_pages_lock);
+ gc_assert(ret == 0);
#ifdef READ_PROTECT_FREE_PAGES
os_protect(page_address(first_page),
@@ -4093,9 +4103,24 @@
if (esp1>=(void **)th->control_stack_start &&
esp1<(void **)th->control_stack_end) {
if(esp1<esp) esp=esp1;
+ /* Ok, so the problem here is that on linux
+ the registers are on the stack. My hunch is
+ that on Darwin, while the context is on the
+ stack, the registers are actually elsewhere
+ in the ss struct. */
+#if defined(LISP_FEATURE_DARWIN)
+ preserve_pointer((void*)*os_context_register_addr(c,reg_EAX));
+ preserve_pointer((void*)*os_context_register_addr(c,reg_ECX));
+ preserve_pointer((void*)*os_context_register_addr(c,reg_EDX));
+ preserve_pointer((void*)*os_context_register_addr(c,reg_EBX));
+ preserve_pointer((void*)*os_context_register_addr(c,reg_ESI));
+ preserve_pointer((void*)*os_context_register_addr(c,reg_EDI));
+ preserve_pointer((void*)*os_context_pc_addr(c));
+#else
for(ptr = (void **)(c+1); ptr>=(void **)c; ptr--) {
preserve_pointer(*ptr);
}
+#endif
}
}
}
|