The environment of a thread is now allocated and managed by the parent thread. This...
authorJuan Jose Garcia Ripoll <jjgarcia@juanjo-imac.local>
Thu, 21 Jan 2010 14:39:41 +0000 (15:39 +0100)
committerJuan Jose Garcia Ripoll <jjgarcia@juanjo-imac.local>
Thu, 21 Jan 2010 14:39:41 +0000 (15:39 +0100)
src/c/main.d
src/c/threads.d

index 36cdd50..9ae3b2f 100644 (file)
@@ -261,12 +261,12 @@ void
 _ecl_dealloc_env(cl_env_ptr env)
 {
         /*
-         * Environment cleanup
+         * Environment cleanup. This is only required when the environment is
+        * allocated using mmap or some other method. We could do more, cleaning
+        * up stacks, etc, but we actually do not do it because that would need
+        * a lisp environment set up -- the allocator assumes one -- and we
+        * may have already cleaned up the value of ecl_process_env()
          */
-        int i;
-        for (i = 0; i < 3; i++) {
-                _ecl_big_clear(env->big_register[i]);
-        }
 #if defined(ECL_USE_MPROTECT)
        if (munmap(env, sizeof(*env)))
                ecl_internal_error("Unable to deallocate environment structure.");
@@ -274,8 +274,6 @@ _ecl_dealloc_env(cl_env_ptr env)
 # if defined(ECL_USE_GUARD_PAGE)
         if (VirtualFree(env, sizeof(*env), MEM_RELEASE))
                 ecl_internal_error("Unable to deallocate environment structure.");
-# else
-       ecl_dealloc(env);
 # endif
 #endif
 }
index 3f33dcc..a19040f 100644 (file)
@@ -121,14 +121,16 @@ thread_cleanup(void *aux)
         * mp_process_kill().
         */
        cl_object process = (cl_object)aux;
-       mp_giveup_lock(process->process.exit_lock);
+       cl_env_ptr env = process->process.env;
        process->process.active = 0;
+       process->process.env = NULL;
+        ecl_disable_interrupts_env(env);
+       mp_giveup_lock(process->process.exit_lock);
        THREAD_OP_LOCK();
        cl_core.processes = ecl_remove_eq(process, cl_core.processes);
        THREAD_OP_UNLOCK();
-       if (process->process.env)
-               _ecl_dealloc_env(process->process.env);
-       process->process.env = NULL;
+       ecl_set_process_env(NULL);
+       if (env) _ecl_dealloc_env(env);
 }
 
 #ifdef ECL_WINDOWS_THREADS
@@ -139,26 +141,19 @@ thread_entry_point(void *arg)
 #endif
 {
         cl_object process = (cl_object)arg;
-       cl_env_ptr env;
+       cl_env_ptr env = process->process.env;
 
-        ecl_set_process_env(NULL);
-        process->process.active = 2;
+       /* 1) Setup the environment for the execution of the thread */
+       ecl_set_process_env(env = process->process.env);
 #ifndef ECL_WINDOWS_THREADS
        pthread_cleanup_push(thread_cleanup, (void *)process);
 #endif
-       /* 1) Setup the environment for the execution of the thread */
-       process->process.env = env = _ecl_alloc_env();
-       env->own_process = process;
-       ecl_set_process_env(env);
        THREAD_OP_LOCK();
        cl_core.processes = CONS(process, cl_core.processes);
        THREAD_OP_UNLOCK();
-       ecl_init_env(env);
        ecl_cs_set_org(env);
-       env->bindings_hash = process->process.initial_bindings;
-       ecl_enable_interrupts_env(env);
-        env->trap_fpe_bits = process->process.trap_fpe_bits;
         si_trap_fpe(@'last', Ct);
+       ecl_enable_interrupts_env(env);
 
        /* 2) Execute the code. The CATCH_ALL point is the destination
        *     provides us with an elegant way to exit the thread: we just
@@ -360,27 +355,51 @@ mp_process_yield(void)
 cl_object
 mp_process_enable(cl_object process)
 {
-       cl_object output;
-#ifdef ECL_WINDOWS_THREADS
-       HANDLE code;
-       DWORD threadId;
-
-       if (mp_process_active_p(process) != Cnil)
+       /*
+        * We try to grab the process exit lock. If we achieve it that
+        * means the 1) process is not running or in the finalization
+        * or 2) it is in the initialization phase. The second case we
+        * can distinguish because process.active != 0. The first one
+        * is ok.
+        */
+       cl_env_ptr process_env;
+       int ok;
+       if (Null(mp_get_lock_nowait(process->process.exit_lock))) {
                FEerror("Cannot enable the running process ~A.", 1, process);
+               return;
+       }
+       if (process->process.active) {
+               mp_giveup_lock(process->process.exit_lock);
+               FEerror("Cannot enable the running process ~A.", 1, process);
+               return;
+       }
+       process_env = _ecl_alloc_env();
+       ecl_init_env(process_env);
+       process_env->trap_fpe_bits = process->process.trap_fpe_bits;
+       process_env->bindings_hash = process->process.initial_bindings;
+       process_env->own_process = process;
+
+       process->process.env = process_env;
         process->process.parent = mp_current_process();
        process->process.trap_fpe_bits =
                process->process.parent->process.env->trap_fpe_bits;
+       process->process.active = 2;
+
+#ifdef ECL_WINDOWS_THREADS
+       {
+       HANDLE code;
+       DWORD threadId;
+
        code = (HANDLE)CreateThread(NULL, 0, thread_entry_point, process, 0, &threadId);
-       output = (process->process.thread = code)? process : Cnil;
+       ok = (process->process.thread = code);
+       }
 #else
+       {
        int code;
         pthread_attr_t pthreadattr;
 
        pthread_attr_init(&pthreadattr);
        pthread_attr_setdetachstate(&pthreadattr, PTHREAD_CREATE_DETACHED);
-       if (mp_process_active_p(process) != Cnil)
-               FEerror("Cannot enable the running process ~A.", 1, process);
-        process->process.parent = mp_current_process();
        /*
         * We launch the thread with the signal mask specified in cl_core.
         * The reason is that we might need to block certain signals
@@ -395,11 +414,20 @@ mp_process_enable(cl_object process)
                pthread_sigmask(SIG_SETMASK, &previous, NULL);
        }
 #else
-       code = pthread_create(&process->process.thread, &pthreadattr, thread_entry_point, process);
+       code = pthread_create(&process->process.thread, &pthreadattr,
+                             thread_entry_point, process);
 #endif
-       output = code? Cnil : process;
+       ok = (code == 0);
+       }
 #endif
-       @(return output)
+       if (!ok) {
+               process->process.active = 0;
+               process->process.env = NULL;
+               _ecl_dealloc_env(process_env);
+       }
+       mp_giveup_lock(process->process.exit_lock);
+
+       @(return (ok? Ct : Cnil))
 }
 
 cl_object