Permalink
Browse files

Fixed deadlock

  • Loading branch information...
1 parent b7f145c commit 83e516db249f117b9bb81c58fcde89efdefdaa4e @lucasaiu committed Jun 26, 2013
View
Binary file not shown.
View
Binary file not shown.
View
Binary file not shown.
View
Binary file not shown.
View
Binary file not shown.
View
@@ -63,7 +63,9 @@ extern char caml_globals_map[];
#endif
/* The global lock: */
-static pthread_mutex_t caml_global_mutex = (pthread_mutex_t)(long)0xdeaddeaddeaddead;
+static pthread_mutex_t caml_global_mutex;
+static pthread_mutex_t caml_channel_mutex __attribute__((unused));
+static int caml_are_global_mutexes_initialized = 0; // FIXME: will this be needed in the end?
void caml_initialize_mutex(pthread_mutex_t *mutex){
pthread_mutexattr_t attributes;
@@ -161,6 +163,9 @@ section. */
ctx->caml_gc_subphase;
ctx->weak_prev;
*/
+#ifdef DEBUG
+ ctx->major_gc_counter = 0;
+#endif
/* from freelist.c */
ctx->sentinel.filler1 = 0;
@@ -203,6 +208,9 @@ section. */
ctx->caml_weak_ref_table.reserve = 0;
ctx->caml_in_minor_collection = 0;
ctx->oldify_todo_list = 0;
+#ifdef DEBUG
+ ctx->minor_gc_counter = 0;
+#endif
#if 0
/* from memory.h */
@@ -672,7 +680,7 @@ void caml_register_module_r(CAML_R, size_t size_in_bytes, long *offset_pointer){
/* Compute the size in words, which is to say how many globals are there: */
int size_in_words = size_in_bytes / sizeof(void*);
/* We keep the module name right after the offset pointer, as a read-only string: */
- char *module_name = (char*)offset_pointer + sizeof(long);
+ char *module_name __attribute__((unused)) = (char*)offset_pointer + sizeof(long);
DUMP("module_name is %s (%li bytes); offset_pointer is at %p", module_name, (long)size_in_bytes, offset_pointer);
Assert(size_in_words * sizeof(void*) == size_in_bytes); /* there's a whole number of globals */
//fprintf(stderr, "caml_register_module_r [context %p]: registering %s%p [%lu bytes at %p]: BEGIN\n", ctx, module_name, offset_pointer, (unsigned long)size_in_bytes, offset_pointer); fflush(stderr);
@@ -794,50 +802,95 @@ void caml_context_initialize_global_stuff(void){
/* Create the global lock: */
caml_initialize_mutex(&caml_global_mutex);
+ caml_are_global_mutexes_initialized = 1;
}
-void caml_acquire_global_lock(void){
- /* FIXME: is this needed? I wanna play it safe --Luca Saiu REENTRANTRUNTIME */
- //int old_value = caml_global_mutex.__data.__count;
- //int old_owner = caml_global_mutex.__data.__owner;
- int result __attribute__((unused));
+/* This is a thin wrapper over pthread_mutex_lock and pthread_mutex_unlock: */
+static void caml_call_on_global_mutex(int(*function)(pthread_mutex_t *), pthread_mutex_t *mutex){
INIT_CAML_R;
- //DUMP("lock");
- result = pthread_mutex_lock(&caml_global_mutex);
- /////BEGIN
- if(result){
- DUMP("thread_mutex_lock failed");
+ if(! caml_are_global_mutexes_initialized){
+ /* INIT_CAML_R; */ DUMP("global mutexes aren't initialized yet. Bailing out");
exit(EXIT_FAILURE);
}
- //fprintf(stderr, "+[context %p] {%u %p->%u %p | %p}\n", ctx, old_value, (void*)(long)old_owner, caml_global_mutex.__data.__count, (void*)(long)caml_global_mutex.__data.__owner, (void*)(pthread_self())); fflush(stderr);
- /////END
- Assert(result == 0);
-}
-void caml_release_global_lock(void){
- //int old_value = caml_global_mutex.__data.__count;
- //int old_owner = caml_global_mutex.__data.__owner;
- INIT_CAML_R;
- int result __attribute__((unused)) = pthread_mutex_unlock(&caml_global_mutex);
- //DUMP("unlock");
- Assert(result == 0);
- /////BEGIN
+ int result __attribute__((unused));
+ result = function(mutex);
if(result){
- DUMP("pthread_mutex_unlock failed");
- //volatile int a = 1; a /= 0;
+ DUMP("the function %p failed on the mutex %p", function, mutex);
exit(EXIT_FAILURE);
}
- //fprintf(stderr, "-[context %p] {%u %p->%u %p | %p}\n", ctx, old_value, (void*)(long)old_owner, caml_global_mutex.__data.__count, (void*)(long)caml_global_mutex.__data.__owner, (void*)(pthread_self())); fflush(stderr);
- /////END
+ //Assert(result == 0);
+}
+
+/* void caml_acquire_global_lock(void){ */
+/* INIT_CAML_R; */
+/* if(! caml_are_global_mutexes_initialized){ */
+/* /\* INIT_CAML_R; *\/ DUMP("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ caml_global_mutex is not yet initialized"); */
+/* return; */
+/* } */
+
+/* /\* FIXME: is this needed? I wanna play it safe --Luca Saiu REENTRANTRUNTIME *\/ */
+/* //int old_value = caml_global_mutex.__data.__count; */
+/* //int old_owner = caml_global_mutex.__data.__owner; */
+/* int result __attribute__((unused)); */
+/* //DUMP("lock"); */
+/* result = pthread_mutex_lock(&caml_global_mutex); */
+/* /////BEGIN */
+/* if(result){ */
+/* DUMP("thread_mutex_lock failed"); */
+/* exit(EXIT_FAILURE); */
+/* } */
+/* //fprintf(stderr, "+[context %p] {%u %p->%u %p | %p}\n", ctx, old_value, (void*)(long)old_owner, caml_global_mutex.__data.__count, (void*)(long)caml_global_mutex.__data.__owner, (void*)(pthread_self())); fflush(stderr); */
+/* /////END */
+/* Assert(result == 0); */
+/* } */
+
+/* void caml_release_global_lock(void){ */
+/* if(! caml_are_global_mutexes_initialized){ */
+/* INIT_CAML_R; DUMP("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ caml_global_mutex is not yet initialized"); */
+/* return; */
+/* } */
+
+/* //int old_value = caml_global_mutex.__data.__count; */
+/* //int old_owner = caml_global_mutex.__data.__owner; */
+/* INIT_CAML_R; */
+/* int result __attribute__((unused)) = pthread_mutex_unlock(&caml_global_mutex); */
+/* //DUMP("unlock"); */
+/* Assert(result == 0); */
+/* /////BEGIN */
+/* if(result){ */
+/* DUMP("pthread_mutex_unlock failed"); */
+/* //volatile int a = 1; a /= 0; */
+/* exit(EXIT_FAILURE); */
+/* } */
+/* //fprintf(stderr, "-[context %p] {%u %p->%u %p | %p}\n", ctx, old_value, (void*)(long)old_owner, caml_global_mutex.__data.__count, (void*)(long)caml_global_mutex.__data.__owner, (void*)(pthread_self())); fflush(stderr); */
+/* /////END */
+/* } */
+
+
+void caml_acquire_global_lock(void){
+ caml_call_on_global_mutex(pthread_mutex_lock, &caml_global_mutex);
+}
+void caml_release_global_lock(void){
+ caml_call_on_global_mutex(pthread_mutex_unlock, &caml_global_mutex);
+}
+
+void caml_acquire_channel_lock(void){
+ caml_call_on_global_mutex(pthread_mutex_lock, &caml_channel_mutex);
+}
+void caml_release_channel_lock(void){
+ caml_call_on_global_mutex(pthread_mutex_unlock, &caml_channel_mutex);
}
void caml_acquire_contextual_lock(CAML_R){
- int result = pthread_mutex_lock(&ctx->mutex);
- assert(result == 0);
+ caml_call_on_global_mutex(pthread_mutex_lock, &ctx->mutex);
+ //int result = pthread_mutex_lock(&ctx->mutex);
+ //assert(result == 0);
}
void caml_release_contextual_lock(CAML_R){
- int result = pthread_mutex_unlock(&ctx->mutex);
- assert(result == 0);
+ caml_call_on_global_mutex(pthread_mutex_unlock, &ctx->mutex);
+ //int result = pthread_mutex_unlock(&ctx->mutex);
+ //assert(result == 0);
}
View
@@ -295,7 +295,7 @@ struct caml_global_context {
#endif
- /* from majoc_gc.c */
+ /* from major_gc.c */
uintnat caml_percent_free;
uintnat caml_major_heap_increment;
char *caml_heap_start;
@@ -316,6 +316,9 @@ struct caml_global_context {
char *mark_limit; /* instead of limit */
int caml_gc_subphase; /* Subphase_{main,weak1,weak2,final} */
value *weak_prev;
+//#ifdef DEBUG
+ unsigned long major_gc_counter /* = 0 */;
+//#endif
/* from freelist.c */
fl_sentinel sentinel;
@@ -348,6 +351,9 @@ struct caml_global_context {
/* = { NULL, NULL, NULL, NULL, NULL, 0, 0}; */
int caml_in_minor_collection; /* = 0; */
value oldify_todo_list;
+//#ifdef DEBUG
+ unsigned long minor_gc_counter /* = 0 */;
+//#endif
/* from memory.h */
#ifdef ARCH_SIXTYFOUR
@@ -675,8 +681,8 @@ struct caml_global_context_descriptor* caml_global_context_descriptor_of_value(v
value caml_value_of_mailbox(struct caml_mailbox *m);
struct caml_mailbox* caml_mailbox_of_value(value v);
-#define CAML_R caml_global_context * /* volatile */ ctx
-#define INIT_CAML_R CAML_R = caml_get_thread_local_context()
+#define CAML_R caml_global_context * /* volatile */ ctx // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+#define INIT_CAML_R CAML_R __attribute__((unused)) = caml_get_thread_local_context() // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
extern caml_global_context *caml_initialize_first_global_context(void);
extern caml_global_context *caml_make_empty_context(void); /* defined in startup.c */
@@ -735,6 +741,7 @@ extern library_context *caml_get_library_context_r(
#define flp_size ctx->flp_size
#define beyond ctx->beyond
#define caml_allocation_policy ctx->caml_allocation_policy
+#define major_gc_counter ctx->major_gc_counter
#endif
#ifdef CAML_CONTEXT_MINOR_GC
@@ -748,6 +755,7 @@ extern library_context *caml_get_library_context_r(
#define caml_weak_ref_table ctx->caml_weak_ref_table
#define caml_in_minor_collection ctx->caml_in_minor_collection
#define oldify_todo_list ctx->oldify_todo_list
+#define minor_gc_counter ctx->minor_gc_counter
#endif
#ifdef CAML_CONTEXT_MEMORY
@@ -1038,10 +1046,14 @@ void* caml_context_local_c_variable_r(CAML_R, caml_c_global_id id);
from the camlMODULE_entry routine. */
void caml_register_module_r(CAML_R, size_t size_in_bytes, long *offset_pointer);
-/* Acquire or release a global mutex: */
+/* Acquire or release the global mutex: */
void caml_acquire_global_lock(void);
void caml_release_global_lock(void);
+/* Acquire or release the channel mutex: */
+void caml_acquire_channel_lock(void);
+void caml_release_channel_lock(void);
+
/* Acquire or release a per-context mutex: */
void caml_acquire_contextual_lock(CAML_R);
void caml_release_contextual_lock(CAML_R);
@@ -1065,8 +1077,13 @@ void caml_finalize_semaphore(sem_t *semaphore);
#define BLUE NOATTR "\033[34m"
#define LIGHTPURPLE NOATTR "\033[1m\033[35m"
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+#define flockfile(Q) /* nothing */
+#define funlockfile(Q) /* nothing */
+
#define DUMP(FORMAT, ...) \
do{ \
+ flockfile(stderr); \
fprintf(stderr, \
"%s:%i(" RED "%s" NOATTR ") C%p T" CYAN "%p"/* " AP" PURPLE"%p"NOATTR"/"PURPLE"%p" */NOATTR" ", \
__FILE__, __LINE__, __FUNCTION__, ctx, \
@@ -1075,16 +1092,19 @@ void caml_finalize_semaphore(sem_t *semaphore);
fprintf(stderr, " " GREEN FORMAT, ##__VA_ARGS__); \
fprintf(stderr, NOATTR "\n"); \
fflush(stderr); \
+ funlockfile(stderr); \
} while(0)
#define QDUMP(FORMAT, ...) \
do{ \
+ flockfile(stderr); \
fprintf(stderr, \
"%s:%i(" RED "%s" NOATTR ") T%p: ", \
__FILE__, __LINE__, __FUNCTION__, (void*)pthread_self()); \
fprintf(stderr, GREEN FORMAT, ##__VA_ARGS__); \
fprintf(stderr, NOATTR "\n"); \
fflush(stderr); \
+ funlockfile(stderr); \
} while(0)
extern __thread int caml_indentation_level;
@@ -1094,6 +1114,7 @@ extern __thread int caml_indentation_level;
#define QB(FORMAT, ...) \
do{ \
+ flockfile(stderr); \
caml_indentation_level ++; \
INDENT; \
fprintf(stderr, \
@@ -1102,9 +1123,11 @@ extern __thread int caml_indentation_level;
fprintf(stderr, PURPLE "BEGIN " FORMAT, ##__VA_ARGS__); \
fprintf(stderr, NOATTR "\n"); \
fflush(stderr); \
+ funlockfile(stderr); \
} while(0)
#define QR(FORMAT, ...) \
do{ \
+ flockfile(stderr); \
INDENT; \
fprintf(stderr, \
PURPLE "%s:%i(" LIGHTPURPLE "%s" NOATTR ") T%p: ", \
@@ -1113,16 +1136,19 @@ extern __thread int caml_indentation_level;
fprintf(stderr, NOATTR "\n"); \
fflush(stderr); \
caml_indentation_level --; \
+ funlockfile(stderr); \
} while(0)
#define QBR(FORMAT, ...) \
do{ \
+ flockfile(stderr); \
INDENT; \
fprintf(stderr, \
PURPLE "%s:%i(" LIGHTPURPLE "%s" NOATTR ") T%p: ", \
__FILE__, __LINE__, __FUNCTION__, (void*)pthread_self()); \
fprintf(stderr, PURPLE "BEGIN-AND-RETURN " FORMAT, ##__VA_ARGS__); \
fprintf(stderr, NOATTR "\n"); \
fflush(stderr); \
+ funlockfile(stderr); \
} while(0)
/* #undef DUMP */
View
@@ -295,6 +295,7 @@ static void caml_install_globals_and_data_as_c_byte_array_r(CAML_R, char *blob,
/* int reference_count; */
/* }; /\* struct *\/ */
+static char* caml_serialize_context(CAML_R, value function) __attribute__((unused)); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
static char* caml_serialize_context(CAML_R, value function)
{
CAMLparam1(function);
@@ -417,8 +418,8 @@ static int caml_deserialize_and_run_in_this_thread(caml_global_context *parent_c
did_we_fail = caml_run_function_this_thread_r(ctx, function, index);
if(did_we_fail){
fprintf(stderr, "caml_deserialize_and_run_in_this_thread [context %p] [thread %p] (index %i). FAILED.\n", ctx, (void*)(pthread_self()), index); fflush(stderr);
- //volatile int a = 1; a /= 0; /*die horribly*/
DUMP("the Caml code failed"); // !!!!!!!!!!!!!!!!!!!!!!!!!!! What shall we do in this case?
+ volatile int a = 1; a /= 0; /*die horribly*/
}
/* We're done. But we can't destroy the context yet, until it's
joined: the object must remain visibile to the OCaml code, and
@@ -444,6 +445,7 @@ static void* caml_deserialize_and_run_in_this_thread_as_thread_function(void *ar
}
/* Create threads, and wait until all of them have signaled that they're done with the blob: */
+static void caml_split_and_wait_r(CAML_R, char *blob, caml_global_context **split_contexts, size_t how_many, sem_t *semaphore) __attribute__((unused)); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
static void caml_split_and_wait_r(CAML_R, char *blob, caml_global_context **split_contexts, size_t how_many, sem_t *semaphore)
{
//DUMP();
@@ -496,19 +498,8 @@ CAMLprim value caml_context_split_r(CAML_R, value thread_no_as_value, value func
CAMLparam1(function);
CAMLlocal2(result, open_channels);
- /* DUMP("running caml code in the new context (so to speak)"); */
- /* int i; */
- /* for(i = 0; i < Int_val(thread_no_as_value); i ++) */
- /* caml_callback_exn_r(ctx, function, Val_int(i)); */
- /* DUMP("Done running caml code in the new context (so to speak)"); */
- /* CAMLreturn(Val_unit); */
- /* if(0){ */
- /* caml_serialize_context(ctx, function); */
- /* caml_split_and_wait_r(NULL, NULL, NULL, 10, NULL); */
- /* } */
value *exception_closure = caml_named_value_r(ctx, "CannotSplit");
int can_split = caml_can_split_r(ctx);
- //DUMP("************************** can_split is %i", can_split);
if (! can_split)
caml_raise_constant_r(ctx, *exception_closure);
@@ -519,31 +510,25 @@ CAMLprim value caml_context_split_r(CAML_R, value thread_no_as_value, value func
int i;
caml_initialize_semaphore(&semaphore, 0);
+ /* CAMLparam0(); CAMLlocal1(open_channels); */
/* Make sure that the currently-existing channels stay alive until
after deserialization; we can't keep reference counts within the
blob, so we pin all alive channels by keeping this list alive: */
- open_channels = caml_ml_all_channels_list_r(ctx);
+ open_channels = caml_ml_all_channels_list_r(ctx); // !!!!!!!!!!!!!!!!!!!! This can occasionally cause crashes related to channel picounts. I certainly messed up something in io.c. //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/* Serialize the context in the main thread, then create threads,
and in each one of them deserialize it back in parallel: */
blob = caml_serialize_context(ctx, function);
caml_split_and_wait_r(ctx, blob, new_contexts, thread_no, &semaphore);
/* Now we're done with the blob: */
-// DUMP("child threads have finished with the blob: destroying it");
- //memset(blob, 0xcc, 100000); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- //???????
DUMP("destroying the blob");
caml_stat_free(blob); // !!!!!!!!!!!!!!!!!!!!!!!!!!! This is needed !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-// DUMP();
DUMP("GC'ing after destroying the blob");
caml_gc_compaction_r(ctx, Val_unit); //!!!!!@@@@@@@@@@@@@
DUMP("finalizing the semaphore");
- // DUMP();
caml_finalize_semaphore(&semaphore);
-// DUMP();
- /////
/* Copy the contexts we got, and we're done with new_contexts as well: */
DUMP("copying the new context (descriptors) into the Caml data structure result");
@@ -554,6 +539,7 @@ CAMLprim value caml_context_split_r(CAML_R, value thread_no_as_value, value func
caml_stat_free(new_contexts);
DUMP("destroyed the malloced buffer of pointers new_contexts");
CAMLreturn(result);
+ //CAMLreturn(Val_unit);
}
CAMLprim value caml_context_join_r(CAML_R, value context_as_value){
Oops, something went wrong.

0 comments on commit 83e516d

Please sign in to comment.