diff --git a/msvc/c/Makefile b/msvc/c/Makefile index f4dd95b07..b4acf7c68 100644 --- a/msvc/c/Makefile +++ b/msvc/c/Makefile @@ -5,7 +5,7 @@ top_srcdir = ..\..\src srcdir = ..\..\src\c !if "$(ECL_THREADS)" != "" -THREADS_OBJ= threads_win32.obj +THREADS_OBJ= threads.obj THREADS_FLAGS= -DECL_THREADS !else THREADS_OBJ= diff --git a/src/c/alloc_2.d b/src/c/alloc_2.d index eaf941641..dcddb5b45 100644 --- a/src/c/alloc_2.d +++ b/src/c/alloc_2.d @@ -522,26 +522,15 @@ ecl_mark_env(struct cl_env_struct *env) GC_set_mark_bit((void *)env->bds_org); } #endif -#if 0 - GC_push_all(&(env->lex_env), &(env->lex_env)+1); - GC_push_all(&(env->string_pool), &(env->print_base)); -#if !defined(ECL_CMU_FORMAT) - GC_push_all(&(env->queue), &(env->qh)); -#endif - GC_push_all(env->big_register, env->big_register + 3); - if (env->nvalues) - GC_push_all(env->values, env->values + env->nvalues + 1); -#else /*memset(env->values[env->nvalues], 0, (64-env->nvalues)*sizeof(cl_object));*/ -#ifdef ECL_THREADS +#if defined(ECL_THREADS) && !defined(ECL_USE_MPROTECT) /* When using threads, "env" is a pointer to memory allocated by ECL. */ GC_push_conditional((void *)env, (void *)(env + 1), 1); GC_set_mark_bit((void *)env); #else - /* When not using threads, "env" is a statically allocated structure. */ + /* When not using threads, "env" is mmaped or statically allocated. */ GC_push_all((void *)env, (void *)(env + 1)); #endif -#endif } static void diff --git a/src/c/big.d b/src/c/big.d index ab2d4116a..31457d0f4 100644 --- a/src/c/big.d +++ b/src/c/big.d @@ -281,18 +281,18 @@ mp_free(void *ptr, size_t size) cl_dealloc(x); } -void init_big_registers(void) +void init_big_registers(cl_env_ptr env) { int i; for (i = 0; i < 3; i++) { - cl_env.big_register[i] = ecl_alloc_object(t_bignum); - big_register_free(cl_env.big_register[i]); + env->big_register[i] = ecl_alloc_object(t_bignum); + big_register_free(env->big_register[i]); } } void -init_big(void) +init_big(cl_env_ptr env) { - init_big_registers(); + init_big_registers(env); mp_set_memory_functions(mp_alloc, mp_realloc, mp_free); } diff --git a/src/c/main.d b/src/c/main.d index 00927701e..ec56b1e21 100644 --- a/src/c/main.d +++ b/src/c/main.d @@ -204,13 +204,14 @@ _ecl_alloc_env() { cl_env_ptr output; #if defined(ECL_USE_MPROTECT) - output = mmap(0, sizeof(*cl_env_p), PROT_READ | PROT_WRITE, + output = mmap(0, sizeof(*output), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 0, 0); if (output < 0) ecl_internal_error("Unable to allocate environment structure."); #else - output = ecl_alloc(sizeof(*cl_env_p)); + output = ecl_alloc(sizeof(*output)); #endif + output->disable_interrupts = 1; return output; } @@ -273,10 +274,6 @@ cl_boot(int argc, char **argv) init_threads(cl_env_p); #endif -#if !defined(MSDOS) && !defined(cygwin) - ecl_self = ecl_expand_pathname(ecl_self); -#endif - /* * 1) Initialize symbols and packages */ diff --git a/src/c/number.d b/src/c/number.d index 1447f1bb6..4458900a9 100644 --- a/src/c/number.d +++ b/src/c/number.d @@ -612,7 +612,7 @@ init_number(void) ECL_SET(@'pi', ecl_make_doublefloat((double)ECL_PI_D)); #endif - init_big(); + init_big(&cl_env); ECL_SET(@'*random-state*', ecl_make_random_state(Ct)); } diff --git a/src/c/symbols_list.h b/src/c/symbols_list.h index 1bf8cbc6c..b139d9442 100644 --- a/src/c/symbols_list.h +++ b/src/c/symbols_list.h @@ -1489,7 +1489,6 @@ cl_symbols[] = { {MP_ "+LOAD-COMPILE-LOCK+", MP_CONSTANT, NULL, -1, OBJNULL}, {MP_ "WITH-LOCK", MP_CONSTANT, NULL, -1, OBJNULL}, {MP_ "WITHOUT-INTERRUPTS", MP_CONSTANT, NULL, -1, OBJNULL}, -{MP_ "CHECK-PENDING-INTERRUPTS", SI_ORDINARY, si_check_pending_interrupts, 0, OBJNULL}, #endif {SYS_ "WHILE", SI_ORDINARY, NULL, -1, OBJNULL}, diff --git a/src/c/symbols_list2.h b/src/c/symbols_list2.h index 4b684e396..adf2dad68 100644 --- a/src/c/symbols_list2.h +++ b/src/c/symbols_list2.h @@ -1489,7 +1489,6 @@ cl_symbols[] = { {MP_ "+LOAD-COMPILE-LOCK+",NULL}, {MP_ "WITH-LOCK",NULL}, {MP_ "WITHOUT-INTERRUPTS",NULL}, -{MP_ "CHECK-PENDING-INTERRUPTS","si_check_pending_interrupts"}, #endif {SYS_ "WHILE",NULL}, diff --git a/src/c/threads.d b/src/c/threads.d index 142f31a92..55fde20f0 100644 --- a/src/c/threads.d +++ b/src/c/threads.d @@ -31,11 +31,29 @@ # include #endif +#if defined(_MSVC) || defined(mingw32) +#define ECL_WINDOWS_THREADS +/* + * We have to put this explicit definition here because Boehm GC + * is designed to produce a DLL and we rather want a static + * reference + */ +#include +#include +extern HANDLE WINAPI GC_CreateThread( + LPSECURITY_ATTRIBUTES lpThreadAttributes, + DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, + LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ); +#ifndef WITH___THREAD +DWORD cl_env_key; +#endif +static DWORD main_thread; +#else #ifndef WITH___THREAD static pthread_key_t cl_env_key; #endif - static pthread_t main_thread; +#endif extern void ecl_init_env(struct cl_env_struct *env); @@ -43,11 +61,15 @@ extern void ecl_init_env(struct cl_env_struct *env); struct cl_env_struct * ecl_process_env(void) { +#ifdef ECL_WINDOWS_THREADS + return TlsGetValue(cl_env_key); +#else struct cl_env_struct *rv = pthread_getspecific(cl_env_key); if (rv) return rv; FElibc_error("pthread_getspecific() failed.", 0); return NULL; +#endif } #endif @@ -90,16 +112,22 @@ thread_cleanup(void *env) static void * thread_entry_point(cl_object process) { + cl_env_ptr env = process->process.env; + /* 1) Setup the environment for the execution of the thread */ - pthread_cleanup_push(thread_cleanup, (void *)process->process.env); + pthread_cleanup_push(thread_cleanup, (void *)env); + ecl_init_env(env); + init_big_registers(env); #ifdef WITH___THREAD - cl_env_p = process->process.env; + cl_env_p = env; #else - if (pthread_setspecific(cl_env_key, process->process.env)) +# ifdef ECL_WINDOWS_THREADS + TlsSetValue(cl_env_key, env); +# else + if (pthread_setspecific(cl_env_key, env)) FElibc_error("pthread_setcspecific() failed.", 0); +# endif #endif - ecl_init_env(process->process.env); - init_big_registers(); /* 2) Execute the code. The CATCH_ALL point is the destination * provides us with an elegant way to exit the thread: we just @@ -116,8 +144,13 @@ thread_entry_point(cl_object process) /* 3) If everything went right, we should be exiting the thread * through this point. thread_cleanup is automatically invoked. */ +#ifdef ECL_WINDOWS_THREADS + thread_cleanup(env); + return 1; +#else pthread_cleanup_pop(1); return NULL; +#endif } static cl_object @@ -155,15 +188,21 @@ void ecl_import_current_thread(cl_object name, cl_object bindings) { cl_object process = alloc_process(name); -#ifdef WITH___THREAD - cl_env_p = process->process.env; -#else - if (pthread_setspecific(cl_env_key, process->process.env)) - FElibc_error("pthread_setcspecific() failed.", 0); -#endif + cl_env_ptr env = process->process.env; initialize_process_bindings(process, bindings); - ecl_init_env(&cl_env); - init_big_registers(); + ecl_init_env(env); + init_big_registers(env); + ecl_enable_interrupts_env(env); +#ifdef WITH___THREAD + cl_env_p = env; +#else +# ifdef ECL_WINDOWS_THREADS + TlsSetValue(cl_env_key, env); +# else + if (pthread_setspecific(cl_env_key, env)) + FElibc_error("pthread_setcspecific() failed.", 0); +# endif +#endif } void @@ -198,17 +237,34 @@ mp_interrupt_process(cl_object process, cl_object function) { if (mp_process_active_p(process) == Cnil) FEerror("Cannot interrupt the inactive process ~A", 1, process); +#ifdef ECL_WINDOWS_THREADS + { + CONTEXT context; + HANDLE thread = process->process.thread; + if (SuspendThread(thread) == (DWORD)-1) + FEwin32_error("Cannot suspend process ~A", 1, process); + context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; + if (!GetThreadContext(thread, &context)) + FEwin32_error("Cannot get context for process ~A", 1, process); + context.Eip = process_interrupt_handler; + if (!SetThreadContext(thread, &context)) + FEwin32_error("Cannot set context for process ~A", 1, process); + process->process.interrupt = function; + if (ResumeThread(thread) == (DWORD)-1) + FEwin32_error("Cannot resume process ~A", 1, process); + } +#else process->process.interrupt = function; if ( pthread_kill(process->process.thread, SIGUSR1) ) FElibc_error("pthread_kill() failed.", 0); +#endif @(return Ct) } cl_object mp_process_kill(cl_object process) { - mp_interrupt_process(process, @'mp::exit-process'); - @(return Ct) + return mp_interrupt_process(process, @'mp::exit-process'); } cl_object @@ -217,7 +273,11 @@ mp_process_yield(void) #ifdef HAVE_SCHED_YIELD sched_yield(); #else +# if defined(_MSVC) || defined(mingw32) + Sleep(0); +# else sleep(0); /* Use sleep(0) to yield to a >= priority thread */ +# endif #endif @(return) } @@ -225,6 +285,25 @@ 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) + FEerror("Cannot enable the running process ~A.", 1, process); + THREAD_OP_LOCK(); + code = (HANDLE)CreateThread(NULL, 0, thread_entry_point, process, 0, &threadId); + if (code) { + /* If everything went ok, add the thread to the list. */ + cl_core.processes = CONS(process, cl_core.processes); + output = process; + } else { + output = Cnil; + } + process->process.thread = code; + THREAD_OP_UNLOCK(); +#else pthread_t *posix_thread; int code; @@ -232,18 +311,27 @@ mp_process_enable(cl_object process) FEerror("Cannot enable the running process ~A.", 1, process); THREAD_OP_LOCK(); code = pthread_create(&process->process.thread, NULL, thread_entry_point, process); - if (!code) { + if (code) { + output = Cnil; + } else { /* If everything went ok, add the thread to the list. */ cl_core.processes = CONS(process, cl_core.processes); + output = process; } /* FIXME: how to do FElibc_error() without leaving a lock? */ THREAD_OP_UNLOCK(); - @(return (code? Cnil : process)) +#endif + @(return output) } cl_object mp_exit_process(void) { - if (pthread_equal(pthread_self(), main_thread)) { +#ifdef ECL_WINDOWS_THREADS + int same = GetCurrentThreadId() == main_thread; +#else + int same = pthread_equal(pthread_self(), main_thread); +#endif + if (same) { /* This is the main thread. Quitting it means exiting the program. */ si_quit(0); @@ -259,7 +347,7 @@ mp_exit_process(void) cl_object mp_all_processes(void) { - /* Isn't it a race condition? */ + /* Isn't it a race condition? */ @(return cl_copy_list(cl_core.processes)) } @@ -310,8 +398,15 @@ mp_process_run_function(cl_narg narg, cl_object name, cl_object function, ...) pthread_mutexattr_t attr; cl_object output; @ - pthread_mutexattr_init(&attr); output = ecl_alloc_object(t_lock); +#ifdef ECL_WINDOWS_THREADS + output->lock.name = name; + output->lock.mutex = CreateMutex(NULL, FALSE, NULL); + output->lock.holder = Cnil; + output->lock.counter = 0; + output->lock.recursive = (recursive != Cnil); +#else + pthread_mutexattr_init(&attr); output->lock.name = name; output->lock.holder = Cnil; output->lock.counter = 0; @@ -324,6 +419,7 @@ mp_process_run_function(cl_narg narg, cl_object name, cl_object function, ...) } pthread_mutex_init(&output->lock.mutex, &attr); pthread_mutexattr_destroy(&attr); +#endif si_set_finalizer(output, Ct); @(return output) @) @@ -365,7 +461,12 @@ mp_giveup_lock(cl_object lock) if (--lock->lock.counter == 0) { lock->lock.holder = Cnil; } +#ifdef ECL_WINDOWS_THREADS + if (ReleaseMutex(lock->lock.mutex) == 0) + FEwin32_error("Unable to release Win32 Mutex", 0); +#else pthread_mutex_unlock(&lock->lock.mutex); +#endif @(return Ct) } @@ -375,10 +476,29 @@ mp_giveup_lock(cl_object lock) @ if (type_of(lock) != t_lock) FEwrong_type_argument(@'mp::lock', lock); + /* In Windows, all locks are recursive. We simulate the other case. */ /* We will complain always if recursive=0 and try to lock recursively. */ if (!lock->lock.recursive && (lock->lock.holder == cl_env.own_process)) { FEerror("A recursive attempt was made to hold lock ~S", 1, lock); } +#ifdef ECL_WINDOWS_THREADS + switch (WaitForSingleObject(lock->lock.mutex, (wait==Ct?INFINITE:0))) { + case WAIT_OBJECT_0: + lock->lock.holder = cl_env.own_process; + lock->lock.counter++; + output = Ct; + break; + case WAIT_TIMEOUT: + output = Cnil; + break; + case WAIT_ABANDONED: + ecl_internal_error(""); + break; + case WAIT_FAILED: + FEwin32_error("Unable to lock Win32 Mutex", 0); + break; + } +#else if (wait == Ct) { rc = pthread_mutex_lock(&lock->lock.mutex); } else { @@ -391,6 +511,7 @@ mp_giveup_lock(cl_object lock) } else { output = Cnil; } +#endif @(return output) @) @@ -401,6 +522,10 @@ mp_giveup_lock(cl_object lock) cl_object mp_make_condition_variable(void) { +#ifdef ECL_WINDOWS_THREADS + FEerror("Condition variables are not supported under Windows.", 0); + @(return Cnil) +#else pthread_condattr_t attr; cl_object output; @@ -410,11 +535,15 @@ mp_make_condition_variable(void) pthread_condattr_destroy(&attr); si_set_finalizer(output, Ct); @(return output) +#endif } cl_object mp_condition_variable_wait(cl_object cv, cl_object lock) { +#ifdef ECL_WINDOWS_THREADS + FEerror("Condition variables are not supported under Windows.", 0); +#else if (type_of(cv) != t_condition_variable) FEwrong_type_argument(@'mp::condition-variable', cv); if (type_of(lock) != t_lock) @@ -422,12 +551,16 @@ mp_condition_variable_wait(cl_object cv, cl_object lock) if (pthread_cond_wait(&cv->condition_variable.cv, &lock->lock.mutex) == 0) lock->lock.holder = cl_env.own_process; +#endif @(return Ct) } cl_object mp_condition_variable_timedwait(cl_object cv, cl_object lock, cl_object seconds) { +#ifdef ECL_WINDOWS_THREADS + FEerror("Condition variables are not supported under Windows.", 0); +#else int rc; double r; struct timespec ts; @@ -443,7 +576,6 @@ mp_condition_variable_timedwait(cl_object cv, cl_object lock, cl_object seconds) make_constant_base_string("Not a non-negative number ~S"), @':format-arguments', cl_list(1, seconds), @':expected-type', @'real', @':datum', seconds); - gettimeofday(&tp, NULL); /* Convert from timeval to timespec */ ts.tv_sec = tp.tv_sec; @@ -464,23 +596,32 @@ mp_condition_variable_timedwait(cl_object cv, cl_object lock, cl_object seconds) } else { @(return Cnil) } +#endif } cl_object mp_condition_variable_signal(cl_object cv) { +#ifdef ECL_WINDOWS_THREADS + FEerror("Condition variables are not supported under Windows.", 0); +#else if (type_of(cv) != t_condition_variable) FEwrong_type_argument(@'mp::condition-variable', cv); pthread_cond_signal(&cv->condition_variable.cv); +#endif @(return Ct) } cl_object mp_condition_variable_broadcast(cl_object cv) { +#ifdef ECL_WINDOWS_THREADS + FEerror("Condition variables are not supported under Windows.", 0); +#else if (type_of(cv) != t_condition_variable) FEwrong_type_argument(@'mp::condition-variable', cv); pthread_cond_broadcast(&cv->condition_variable.cv); +#endif @(return Ct) } @@ -495,10 +636,14 @@ init_threads(cl_env_ptr env) pthread_mutexattr_t attr; cl_core.processes = OBJNULL; +#ifdef ECL_WINDOWS_THREADS + cl_core.global_lock = CreateMutex(NULL, FALSE, NULL); +#else pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP); pthread_mutex_init(&cl_core.global_lock, &attr); pthread_mutexattr_destroy(&attr); +#endif process = ecl_alloc_object(t_process); process->process.active = 1; @@ -511,12 +656,21 @@ init_threads(cl_env_ptr env) #ifdef WITH___THREAD cl_env_p = env; #else +# ifdef ECL_WINDOWS_THREADS + cl_env_key = TlsAlloc(); + TlsSetValue(cl_env_key, env); +# else pthread_key_create(&cl_env_key, NULL); pthread_setspecific(cl_env_key, env); +# endif #endif env->own_process = process; cl_core.processes = ecl_list1(process); +#ifdef ECL_WINDOWS_THREADS + main_thread = GetCurrentThreadId(); +#else main_thread = pthread_self(); +#endif } diff --git a/src/c/threads_win32.d b/src/c/threads_win32.d deleted file mode 100644 index 77337ce55..000000000 --- a/src/c/threads_win32.d +++ /dev/null @@ -1,488 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8 -*- */ -/* - threads.d -- Posix threads with support from GCC. -*/ -/* - Copyright (c) 2003, Juan Jose Garcia Ripoll. - - ECL is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - See file '../Copyright' for full details. -*/ -/* - * IMPORTANT!!!! IF YOU EDIT THIS FILE, CHANGE ALSO threads.d - */ - -#include -#include -#include -#ifdef HAVE_SCHED_YIELD -# include -#endif - -/* - * We have to put this explicit definition here because Boehm GC - * is designed to produce a DLL and we rather want a static - * reference - */ -#include -#include -extern HANDLE WINAPI GC_CreateThread( - LPSECURITY_ATTRIBUTES lpThreadAttributes, - DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, - LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ); -#ifndef WITH___THREAD -DWORD cl_env_key; -#endif - -static DWORD main_thread; - -extern void ecl_init_env(struct cl_env_struct *env); - -#ifndef WITH___THREAD -struct cl_env_struct * -ecl_process_env(void) -{ - return TlsGetValue(cl_env_key); -} -#endif - -cl_object -mp_current_process(void) -{ - return cl_env.own_process; -} - -/*---------------------------------------------------------------------- - * THREAD OBJECT - */ - -static void -assert_type_process(cl_object o) -{ - if (type_of(o) != t_process) - FEwrong_type_argument(@'mp::process', o); -} - -static void -thread_cleanup(void *env) -{ - /* This routine performs some cleanup before a thread is completely - * killed. For instance, it has to remove the associated process - * object from the list, an it has to dealloc some memory. - * - * NOTE: thread_cleanup() does not provide enough "protection". In - * order to ensure that all UNWIND-PROTECT forms are properly - * executed, never use pthread_cancel() to kill a process, but - * rather use the lisp functions mp_interrupt_process() and - * mp_process_kill(). - */ - THREAD_OP_LOCK(); - cl_core.processes = ecl_remove_eq(cl_env.own_process, - cl_core.processes); - THREAD_OP_UNLOCK(); -} - -static DWORD WINAPI -thread_entry_point(cl_object process) -{ - /* 1) Setup the environment for the execution of the thread */ -#ifdef WITH___THREAD - cl_env_p = process->process.env -#else - TlsSetValue(cl_env_key, (void *)process->process.env); -#endif - ecl_init_env(process->process.env); - init_big_registers(); - - /* 2) Execute the code. The CATCH_ALL point is the destination - * provides us with an elegant way to exit the thread: we just - * do an unwind up to frs_top. - */ - process->process.active = 1; - CL_CATCH_ALL_BEGIN { - bds_bind(@'mp::*current-process*', process); - cl_apply(2, process->process.function, process->process.args); - bds_unwind1(); - } CL_CATCH_ALL_END; - process->process.active = 0; - - /* 3) If everything went right, we should be exiting the thread - * through this point. - */ - thread_cleanup(&cl_env); - return 1; -} - -static cl_object -alloc_process(cl_object name) -{ - cl_object process = ecl_alloc_object(t_process); - process->process.active = 0; - process->process.name = name; - process->process.function = Cnil; - process->process.args = Cnil; - process->process.interrupt = Cnil; - process->process.env = ecl_alloc(sizeof(*process->process.env)); - process->process.env->own_process = process; - return process; -} - -static void -initialize_process_bindings(cl_object process, cl_object initial_bindings) -{ - cl_object hash; - /* FIXME! Here we should either use INITIAL-BINDINGS or copy lexical - * bindings */ - if (initial_bindings != OBJNULL) { - hash = cl__make_hash_table(@'eq', MAKE_FIXNUM(1024), - ecl_make_singlefloat(1.5), - ecl_make_singlefloat(0.7), - Cnil); /* no need for locking */ - } else { - hash = si_copy_hash_table(cl_env.bindings_hash); - } - process->process.env->bindings_hash = hash; -} - -void -ecl_import_current_thread(cl_object name, cl_object bindings) -{ - cl_object process = alloc_process(name); -#ifdef WITH___THREAD - cl_env_p = process->process.env; -#else - TlsSetValue(cl_env_key, (void *)process->process.env); -#endif - initialize_process_bindings(process, bindings); - ecl_init_env(&cl_env); - init_big_registers(); -} - -void -ecl_release_current_thread(void) -{ - thread_cleanup(&cl_env); -} - -@(defun mp::make-process (&key name ((:initial-bindings initial_bindings) Ct)) - cl_object process; -@ - process = alloc_process(name); - initialize_process_bindings(process, initial_bindings); - @(return process) -@) - -cl_object -mp_process_preset(cl_narg narg, cl_object process, cl_object function, ...) -{ - cl_va_list args; - cl_va_start(args, function, narg, 2); - if (narg < 2) - FEwrong_num_arguments(@'mp::process-preset'); - assert_type_process(process); - process->process.function = function; - process->process.args = cl_grab_rest_args(args); - @(return process) -} - -static void -process_interrupt_handler(void) -{ - funcall(1, ecl_process_env()->own_process->process.interrupt); -} - -cl_object -mp_interrupt_process(cl_object process, cl_object function) -{ - CONTEXT context; - HANDLE thread = process->process.thread; - - if (mp_process_active_p(process) == Cnil) - FEerror("Cannot interrupt the inactive process ~A", 1, process); - if (SuspendThread(thread) == (DWORD)-1) - FEwin32_error("Cannot suspend process ~A", 1, process); - context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; - if (!GetThreadContext(thread, &context)) - FEwin32_error("Cannot get context for process ~A", 1, process); - context.Eip = process_interrupt_handler; - if (!SetThreadContext(thread, &context)) - FEwin32_error("Cannot set context for process ~A", 1, process); - process->process.interrupt = function; - if (ResumeThread(thread) == (DWORD)-1) - FEwin32_error("Cannot resume process ~A", 1, process); - @(return Ct) -} - -cl_object -mp_process_kill(cl_object process) -{ - return mp_interrupt_process(process, @'mp::exit-process'); -} - -cl_object -mp_process_yield(void) -{ -#ifdef HAVE_SCHED_YIELD - sched_yield(); -#else - Sleep(0); /* Use sleep(0) to yield to a >= priority thread */ -#endif - @(return) -} - -cl_object -mp_process_enable(cl_object process) -{ - HANDLE code; - DWORD threadId; - - if (mp_process_active_p(process) != Cnil) - FEerror("Cannot enable the running process ~A.", 1, process); - THREAD_OP_LOCK(); - code = (HANDLE)CreateThread(NULL, 0, thread_entry_point, process, 0, &threadId); - if (code) { - /* If everything went ok, add the thread to the list. */ - cl_core.processes = CONS(process, cl_core.processes); - } - process->process.thread = code; - THREAD_OP_UNLOCK(); - @(return (code==NULL ? Cnil : process)) -} - -cl_object -mp_exit_process(void) -{ - if (GetCurrentThreadId() == main_thread) { - /* This is the main thread. Quitting it means exiting the - program. */ - si_quit(0); - } else { - /* We simply undo the whole of the frame stack. This brings up - back to the thread entry point, going through all possible - UNWIND-PROTECT. - */ - ecl_unwind(cl_env.frs_org); - } -} - -cl_object -mp_all_processes(void) -{ - @(return cl_copy_list(cl_core.processes)) -} - -cl_object -mp_process_name(cl_object process) -{ - assert_type_process(process); - @(return process->process.name) -} - -cl_object -mp_process_active_p(cl_object process) -{ - assert_type_process(process); - @(return (process->process.active? Ct : Cnil)) -} - -cl_object -mp_process_whostate(cl_object process) -{ - assert_type_process(process); - @(return (cl_core.null_string)) -} - -cl_object -mp_process_run_function(cl_narg narg, cl_object name, cl_object function, ...) -{ - cl_object process; - cl_va_list args; - cl_va_start(args, function, narg, 2); - if (narg < 2) - FEwrong_num_arguments(@'mp::process-run-function'); - if (CONSP(name)) { - process = cl_apply(2, @'mp::make-process', name); - } else { - process = mp_make_process(2, @':name', name); - } - cl_apply(4, @'mp::process-preset', process, function, - cl_grab_rest_args(args)); - return mp_process_enable(process); -} - -/*---------------------------------------------------------------------- - * LOCKS or MUTEX - */ - -@(defun mp::make-lock (&key name ((:recursive recursive) Ct)) - cl_object output; -@ - output = ecl_alloc_object(t_lock); - output->lock.name = name; - output->lock.mutex = CreateMutex(NULL, FALSE, NULL); - output->lock.holder = Cnil; - output->lock.counter = 0; - output->lock.recursive = (recursive != Cnil); - si_set_finalizer(output, Ct); - @(return output) -@) - -cl_object -mp_recursive_lock_p(cl_object lock) -{ - if (type_of(lock) != t_lock) - FEwrong_type_argument(@'mp::lock', lock); - @(return (lock->lock.recursive? Ct : Cnil)) -} - -cl_object -mp_lock_name(cl_object lock) -{ - if (type_of(lock) != t_lock) - FEwrong_type_argument(@'mp::lock', lock); - @(return lock->lock.name) -} - -cl_object -mp_lock_holder(cl_object lock) -{ - if (type_of(lock) != t_lock) - FEwrong_type_argument(@'mp::lock', lock); - @(return lock->lock.holder) -} - -cl_object -mp_giveup_lock(cl_object lock) -{ - if (type_of(lock) != t_lock) - FEwrong_type_argument(@'mp::lock', lock); - if (lock->lock.holder != cl_env.own_process) { - FEerror("Attempt to give up a lock ~S that is not owned by ~S.", 2, - lock, cl_env.own_process); - } - if (--lock->lock.counter == 0) { - lock->lock.holder = Cnil; - } - if (ReleaseMutex(lock->lock.mutex) == 0) - FEwin32_error("Unable to release Win32 Mutex", 0); - @(return Ct) -} - -@(defun mp::get-lock (lock &optional (wait Ct)) - cl_object output; -@ - if (type_of(lock) != t_lock) - FEwrong_type_argument(@'mp::lock', lock); - /* In Windows, all locks are recursive. We simulate the other case. */ - if (!lock->lock.recursive && (lock->lock.holder == cl_env.own_process)) { - FEerror("A recursive attempt was made to hold lock ~S", 1, lock); - } - switch (WaitForSingleObject(lock->lock.mutex, (wait==Ct?INFINITE:0))) { - case WAIT_OBJECT_0: - lock->lock.holder = cl_env.own_process; - lock->lock.counter++; - output = Ct; - break; - case WAIT_TIMEOUT: - output = Cnil; - break; - case WAIT_ABANDONED: - ecl_internal_error(""); - break; - case WAIT_FAILED: - FEwin32_error("Unable to lock Win32 Mutex", 0); - break; - } - @(return output) -@) - -/*---------------------------------------------------------------------- - * CONDITION VARIABLES - */ - -cl_object -mp_make_condition_variable(void) -{ - FEerror("Condition variables are not supported under Windows.", 0); - @(return Cnil) -} - -cl_object -mp_condition_variable_wait(cl_object cv, cl_object lock) -{ - if (type_of(cv) != t_condition_variable) - FEwrong_type_argument(@'mp::condition-variable', cv); - if (type_of(lock) != t_lock) - FEwrong_type_argument(@'mp::lock', lock); - FEerror("Condition variables are not supported under Windows.", 0); - @(return Ct) -} - -cl_object -mp_condition_variable_timedwait(cl_object cv, cl_object lock, cl_object seconds) -{ - if (type_of(cv) != t_condition_variable) - FEwrong_type_argument(@'mp::condition-variable', cv); - if (type_of(lock) != t_lock) - FEwrong_type_argument(@'mp::lock', lock); - FEerror("Condition variables are not supported under Windows.", 0); - @(return Cnil) -} - -cl_object -mp_condition_variable_signal(cl_object cv) -{ - if (type_of(cv) != t_condition_variable) - FEwrong_type_argument(@'mp::condition-variable', cv); - FEerror("Condition variables are not supported under Windows.", 0); - @(return Ct) -} - -cl_object -mp_condition_variable_broadcast(cl_object cv) -{ - if (type_of(cv) != t_condition_variable) - FEwrong_type_argument(@'mp::condition-variable', cv); - FEerror("Condition variables are not supported under Windows.", 0); - @(return Ct) -} - -/*---------------------------------------------------------------------- - * INITIALIZATION - */ - -void -init_threads() -{ - cl_object process; - struct cl_env_struct *env; - - GC_INIT(); - - cl_core.processes = OBJNULL; - cl_core.global_lock = CreateMutex(NULL, FALSE, NULL); - - process = ecl_alloc_object(t_process); - process->process.active = 1; - process->process.name = @'si::top-level'; - process->process.function = Cnil; - process->process.args = Cnil; - process->process.thread = GetCurrentThread(); - process->process.env = env = (struct cl_env_struct*)ecl_alloc(sizeof(*env)); - -#ifdef WITH___THREAD - cl_env_p = env -#else - cl_env_key = TlsAlloc(); - TlsSetValue(cl_env_key, env); -#endif - env->own_process = process; - - cl_core.processes = CONS(process, Cnil); - - main_thread = GetCurrentThreadId(); -} diff --git a/src/c/unixfsys.d b/src/c/unixfsys.d index a1d6efd33..c03d772a1 100644 --- a/src/c/unixfsys.d +++ b/src/c/unixfsys.d @@ -50,6 +50,38 @@ #endif #include +static int +safe_chdir(const char *path) +{ + int output; + ecl_disable_interrupts(); + output = chdir(path); + ecl_enable_interrupts(); + return output; +} + +static int +safe_stat(const char *path, struct stat *sb) +{ + int output; + ecl_disable_interrupts(); + output = stat(path, sb); + ecl_enable_interrupts(); + return output; +} + +#ifdef HAVE_LSTAT +static int +safe_lstat(const char *path, struct stat *sb) +{ + int output; + ecl_disable_interrupts(); + output = lstat(path, sb); + ecl_enable_interrupts(); + return output; +} +#endif + #if defined(_MSC_VER) || defined(mingw32) static void change_drive(cl_object pathname) @@ -57,7 +89,7 @@ change_drive(cl_object pathname) if (pathname->pathname.device != Cnil) { char device[3] = {'\0', ':', '\0'}; device[0] = pathname->pathname.device->base_string.self[0]; - if (chdir(device) < 0) { + if (safe_chdir(device) < 0) { FElibc_error("Can't change the current drive to ~S", 1, pathname->pathname.device); } @@ -91,16 +123,18 @@ current_dir(void) { cl_index size = 128; do { - output = cl_alloc_adjustable_base_string(size); - ok = getcwd(output->base_string.self, size); - size += 256; + output = cl_alloc_adjustable_base_string(size); + ecl_disable_interrupts(); + ok = getcwd(output->base_string.self, size); + ecl_enable_interrupts(); + size += 256; } while(ok == NULL); size = strlen(output->base_string.self); if ((size + 1 /* / */ + 1 /* 0 */) >= output->base_string.dim) { - /* Too large to host the trailing '/' */ - cl_object other = cl_alloc_adjustable_base_string(size+2); - strcpy(other->base_string.self, output->base_string.self); - output = other; + /* Too large to host the trailing '/' */ + cl_object other = cl_alloc_adjustable_base_string(size+2); + strcpy(other->base_string.self, output->base_string.self); + output = other; } #ifdef _MSC_VER for (c=output->base_string.self; *c; c++) @@ -121,32 +155,38 @@ current_dir(void) { static cl_object file_kind(char *filename, bool follow_links) { + cl_object output; #if defined(_MSC_VER) || defined(mingw32) - DWORD dw = GetFileAttributes( filename ); + DWORD dw; + ecl_disable_interrupts(); + dw = GetFileAttributes( filename ); if (dw == -1) - return Cnil; + output = Cnil; else if ( dw & FILE_ATTRIBUTE_DIRECTORY ) - return @':directory'; + output = @':directory'; else - return @':file'; + output = @':file'; + ecl_enable_interrupts(); #else struct stat buf; -#ifdef HAVE_LSTAT - if ((follow_links? stat : lstat)(filename, &buf) < 0) -#else - if (stat(filename, &buf) < 0) -#endif - return Cnil; -#ifdef HAVE_LSTAT - if (S_ISLNK(buf.st_mode)) - return @':link'; -#endif - if (S_ISDIR(buf.st_mode)) - return @':directory'; - if (S_ISREG(buf.st_mode)) - return @':file'; - return @':special'; +# ifdef HAVE_LSTAT + if ((follow_links? safe_stat : safe_lstat)(filename, &buf) < 0) +# else + if (safe_stat(filename, &buf) < 0) +# endif + output = Cnil; +# ifdef HAVE_LSTAT + else if (S_ISLNK(buf.st_mode)) + output = @':link'; +# endif + else if (S_ISDIR(buf.st_mode)) + output = @':directory'; + else if (S_ISREG(buf.st_mode)) + output = @':file'; + else + output = @':special'; #endif + return output; } cl_object @@ -164,7 +204,10 @@ si_readlink(cl_object filename) { cl_object output, kind; do { output = cl_alloc_adjustable_base_string(size); - written = readlink(filename->base_string.self, output->base_string.self, size); + ecl_disable_interrupts(); + written = readlink(filename->base_string.self, + output->base_string.self, size); + ecl_enable_interrupts(); size += 256; } while(written == size); output->base_string.self[written] = '\0'; @@ -227,17 +270,17 @@ cl_truename(cl_object orig_pathname) { cl_object part = CAR(dir); if (type_of(part) == t_base_string) { - if (chdir(part->base_string.self) < 0) { + if (safe_chdir(part->base_string.self) < 0) { ERROR: FElibc_error("Can't change the current directory to ~S", 1, pathname); } } else if (part == @':absolute') { - if (chdir("/") < 0) + if (safe_chdir("/") < 0) goto ERROR; } else if (part == @':relative') { /* Nothing to do */ } else if (part == @':up') { - if (chdir("..") < 0) + if (safe_chdir("..") < 0) goto ERROR; } else { FEerror("~S is not allowed in TRUENAME", 1, part); @@ -253,7 +296,7 @@ ERROR: FElibc_error("Can't change the current directory to ~S", #endif pathname = ecl_merge_pathnames(si_getcwd(0), pathname, @':newest'); } CL_UNWIND_PROTECT_EXIT { - chdir(previous->base_string.self); + safe_chdir(previous->base_string.self); } CL_UNWIND_PROTECT_END; @(return pathname) @@ -268,14 +311,20 @@ ecl_backup_fopen(const char *filename, const char *option) } strcat(strcpy(backupfilename, filename), ".BAK"); + ecl_disable_interrupts(); #ifdef _MSC_VER /* MSVC rename doesn't remove an existing file */ - if (access(backupfilename, F_OK) == 0 && unlink(backupfilename)) + if (access(backupfilename, F_OK) == 0 && unlink(backupfilename)) { + ecl_enable_interrupts(); FElibc_error("Cannot remove the file ~S", 1, make_simple_base_string(backupfilename)); + } #endif - if (rename(filename, backupfilename)) + if (rename(filename, backupfilename)) { + ecl_enable_interrupts(); FElibc_error("Cannot rename the file ~S to ~S.", 2, make_constant_base_string(filename), make_simple_base_string(backupfilename)); + } + ecl_enable_interrupts(); cl_dealloc(backupfilename); return fopen(filename, option); } @@ -284,8 +333,9 @@ cl_object ecl_file_len(void *fp) { struct stat filestatus; - + ecl_disable_interrupts(); fstat(fileno((FILE*)fp), &filestatus); + ecl_enable_interrupts(); return ecl_make_integer(filestatus.st_size); } @@ -305,6 +355,7 @@ ecl_file_len(void *fp) newn = ecl_merge_pathnames(newn, oldn, @':newest'); new_filename = si_coerce_to_filename(newn); + ecl_disable_interrupts(); while (if_exists == @':error' || if_exists == Cnil) { #if defined(_MSC_VER) || defined(mingw32) error = SetErrorMode(0); @@ -331,14 +382,17 @@ ecl_file_len(void *fp) #endif /* if the file already exists */ if (if_exists != Cnil) { + ecl_enable_interrupts(); if_exists = CEerror(@':supersede', "When trying to rename ~S, ~S already exists", 2, oldn, new_filename); + ecl_disable_interrupts(); if (if_exists == Ct) if_exists= @':error'; } if (if_exists == Cnil) { - @(return Cnil) + ecl_enable_interrupts(); + @(return Cnil Cnil Cnil) } } @@ -384,22 +438,30 @@ ecl_file_len(void *fp) #endif } else { /* invalid key */ + ecl_enable_interrupts(); FEerror("~S is an illegal IF-EXISTS option for RENAME-FILE.", 1, if_exists); } FAILURE_CLOBBER: + ecl_enable_interrupts(); FElibc_error("Cannot rename the file ~S to ~S.", 2, oldn, newn); -SUCCESS:new_truename = cl_truename(newn); +SUCCESS: + ecl_enable_interrupts(); + new_truename = cl_truename(newn); @(return newn old_truename new_truename) @) cl_object cl_delete_file(cl_object file) { - cl_object filename; + cl_object filename = si_coerce_to_filename(file); + int ok; - filename = si_coerce_to_filename(file); - if (unlink(filename->base_string.self) < 0) + ecl_disable_interrupts(); + ok = unlink(filename->base_string.self); + ecl_enable_interrupts(); + + if (ok < 0) FElibc_error("Cannot delete the file ~S.", 1, file); @(return Ct) } @@ -414,11 +476,9 @@ cl_probe_file(cl_object file) cl_object cl_file_write_date(cl_object file) { - cl_object filename, time; + cl_object time, filename = si_coerce_to_filename(file); struct stat filestatus; - - filename = si_coerce_to_filename(file); - if (stat(filename->base_string.self, &filestatus) < 0) + if (safe_stat(filename->base_string.self, &filestatus) < 0) time = Cnil; else time = UTC_time_to_universal_time(filestatus.st_mtime); @@ -428,54 +488,22 @@ cl_file_write_date(cl_object file) cl_object cl_file_author(cl_object file) { - cl_object filename = si_coerce_to_filename(file); + cl_object output, filename = si_coerce_to_filename(file); + struct stat filestatus; + if (safe_stat(filename->base_string.self, &filestatus) < 0) + FElibc_error("Cannot get the file status of ~S.", 1, file); #ifdef HAVE_PWD_H - struct stat filestatus; - struct passwd *pwent; - - if (stat(filename->base_string.self, &filestatus) < 0) - FElibc_error("Cannot get the file status of ~S.", 1, file); - pwent = getpwuid(filestatus.st_uid); - @(return make_base_string_copy(pwent->pw_name)) + { + struct passwd *pwent; + ecl_disable_interrupts(); + pwent = getpwuid(filestatus.st_uid); + ecl_enable_interrupts(); + output = make_base_string_copy(pwent->pw_name); + } #else - struct stat filestatus; - if (stat(filename->base_string.self, &filestatus) < 0) - FElibc_error("Cannot get the file status of ~S.", 1, file); - @(return make_constant_base_string("UNKNOWN")) + output = make_constant_base_string("UNKNOWN"); #endif -} - -const char * -ecl_expand_pathname(const char *name) -{ - const char *path, *p; - static char pathname[255], *pn; - - if (IS_DIR_SEPARATOR(name[0])) return(name); - if ((path = getenv("PATH")) == NULL) ecl_internal_error("No PATH in environment"); - p = path; - pn = pathname; - do { - if ((*p == '\0') || (*p == PATH_SEPARATOR)) { - if (pn != pathname) *pn++ = DIR_SEPARATOR; /* on SYSV . is empty */ -LAST: strcpy(pn, name); -#ifdef _MSC_VER - if (GetFileAttributes(pathname) & FILE_ATTRIBUTE_DIRECTORY) - return ( pathname ); -#else - if (access(pathname, X_OK) == 0) - return (pathname); -#endif - pn = pathname; - if (p[0] == PATH_SEPARATOR && p[1] == '\0') { /* last entry is empty */ - p++; - goto LAST; - } - } - else - *pn++ = *p; - } while (*p++ != '\0'); - return(name); /* should never occur */ + @(return output) } cl_object @@ -596,14 +624,16 @@ list_current_directory(const char *mask, bool only_dir) { cl_object out = Cnil; char *text; - #if defined(HAVE_DIRENT_H) DIR *dir; struct dirent *entry; + ecl_disable_interrupts(); dir = opendir("./"); - if (dir == NULL) - return Cnil; + if (dir == NULL) { + out = Cnil; + goto OUTPUT; + } while ((entry = readdir(dir))) { text = entry->d_name; @@ -613,30 +643,32 @@ list_current_directory(const char *mask, bool only_dir) HANDLE hFind = NULL; BOOL found = FALSE; + ecl_disable_interrupts(); for (;;) { - if (hFind == NULL) - { + if (hFind == NULL) { hFind = FindFirstFile(".\\*", &fd); - if (hFind == INVALID_HANDLE_VALUE) - return Cnil; + if (hFind == INVALID_HANDLE_VALUE) { + out = Cnil; + goto OUTPUT; + } found = TRUE; - } - else + } else { found = FindNextFile(hFind, &fd); - + } if (!found) break; text = fd.cFileName; - # else /* sys/dir.h as in SYSV */ FILE *fp; char iobuffer[BUFSIZ]; DIRECTORY dir; + ecl_disable_interrupts(); fp = fopen("./", OPEN_R); - if (fp == NULL) - return Cnil; - + if (fp == NULL) { + out = Cnil; + goto OUTPUT; + } setbuf(fp, iobuffer); for (;;) { if (fread(&dir, sizeof(DIRECTORY), 1, fp) <= 0) @@ -665,6 +697,8 @@ list_current_directory(const char *mask, bool only_dir) fclose(fp); # endif /* !_MSC_VER */ #endif /* !HAVE_DIRENT_H */ + ecl_enable_interrupts(); +OUTPUT: return cl_nreverse(out); } @@ -757,21 +791,21 @@ dir_recursive(cl_object pathname, cl_object directory) loop_for_in(next_dir) { char *text = CAR(next_dir)->base_string.self; /* We are unable to move into this directory! */ - if (chdir(text) < 0) + if (safe_chdir(text) < 0) continue; item = dir_recursive(pathname, CDR(directory)); output = ecl_nconc(item, output); - chdir(prev_dir->base_string.self); + safe_chdir(prev_dir->base_string.self); } end_loop_for_in; } else if (item == @':absolute') { /* * 2.2) If CAR(DIRECTORY) is :ABSOLUTE, we have to scan the * root directory. */ - if (chdir("/") < 0) + if (safe_chdir("/") < 0) return Cnil; output = dir_recursive(pathname, CDR(directory)); - chdir(prev_dir->base_string.self); + safe_chdir(prev_dir->base_string.self); } else if (item == @':relative') { /* * 2.3) If CAR(DIRECTORY) is :RELATIVE, we have to scan the @@ -783,10 +817,10 @@ dir_recursive(cl_object pathname, cl_object directory) * 2.4) If CAR(DIRECTORY) is :UP, we have to scan the directory * which contains this one. */ - if (chdir("..") < 0) + if (safe_chdir("..") < 0) return Cnil; output = dir_recursive(pathname, CDR(directory)); - chdir(prev_dir->base_string.self); + safe_chdir(prev_dir->base_string.self); } else if (item == @':wild-inferiors') { /* * 2.5) If CAR(DIRECTORY) is :WILD-INFERIORS, we have to do @@ -796,11 +830,11 @@ dir_recursive(cl_object pathname, cl_object directory) next_dir = list_current_directory("*", TRUE); loop_for_in(next_dir) { char *text = CAR(next_dir)->base_string.self; - if (chdir(text) < 0) + if (safe_chdir(text) < 0) continue; item = dir_recursive(pathname, directory); output = ecl_nconc(item, output); - chdir(prev_dir->base_string.self); + safe_chdir(prev_dir->base_string.self); } end_loop_for_in; output = ecl_nconc(output, dir_recursive(pathname, CDR(directory))); } @@ -818,7 +852,7 @@ dir_recursive(cl_object pathname, cl_object directory) output = dir_recursive(mask, mask->pathname.directory); } CL_UNWIND_PROTECT_EXIT { if (prev_dir != Cnil) - chdir(prev_dir->base_string.self); + safe_chdir(prev_dir->base_string.self); } CL_UNWIND_PROTECT_END; @(return output) @) @@ -838,10 +872,16 @@ si_get_library_pathname(void) { cl_object s = cl_alloc_adjustable_base_string(cl_core.path_max); char *buffer = (char*)s->base_string.self; - HMODULE hnd = GetModuleHandle( "ecl.dll" ); + HMODULE hnd; cl_index len, ep; - if ((len = GetModuleFileName(hnd, buffer, cl_core.path_max-1)) == 0) - FEerror("GetModuleFileName failed (last error = ~S)", 1, MAKE_FIXNUM(GetLastError())); + ecl_disable_interrupts(); + hnd = GetModuleHandle("ecl.dll"); + len = GetModuleFileName(hnd, buffer, cl_core.path_max-1); + ecl_enable_interrupts(); + if (len == 0) { + FEerror("GetModuleFileName failed (last error = ~S)", + 1, MAKE_FIXNUM(GetLastError())); + } s->base_string.fillp = len; return ecl_parse_namestring(s, 0, len, &ep, Cnil); } @@ -857,7 +897,7 @@ si_get_library_pathname(void) directory->pathname.type != Cnil) FEerror("~A is not a directory pathname.", 1, directory); namestring = cl_namestring(directory); - if (chdir(namestring->base_string.self) <0) + if (safe_chdir(namestring->base_string.self) <0) FElibc_error("Can't change the current directory to ~A", 1, namestring); if (change_d_p_d != Cnil) @@ -868,18 +908,22 @@ si_get_library_pathname(void) cl_object si_mkdir(cl_object directory, cl_object mode) { - cl_object filename; - cl_index modeint; + cl_object filename = si_coerce_to_filename(directory); + cl_index modeint = ecl_fixnum_in_range(@'si::mkdir',"mode",mode,0,0777); + int ok; - filename = si_coerce_to_filename(directory); - modeint = ecl_fixnum_in_range(@'si::mkdir',"mode",mode,0,0777); if (filename->base_string.fillp) filename->base_string.self[--filename->base_string.fillp] = 0; + + ecl_disable_interrupts(); #ifdef mingw32 - if (mkdir(filename->base_string.self) < 0) + ok = mkdir(filename->base_string.self); #else - if (mkdir(filename->base_string.self, modeint) < 0) + ok = mkdir(filename->base_string.self, modeint); #endif + ecl_enable_interrupts(); + + if (ok < 0) FElibc_error("Could not create directory ~S", 1, filename); @(return filename) } @@ -892,67 +936,74 @@ si_mkstemp(cl_object template) int fd; #if defined(mingw32) || defined(_MSC_VER) - cl_object phys, dir, file; char strTempDir[MAX_PATH]; char strTempFileName[MAX_PATH]; - char * s; - + char *s; + int ok; + phys = cl_translate_logical_pathname(1, template); - dir = cl_make_pathname(8, @':type', Cnil, @':name', Cnil, @':version', Cnil, @':defaults', phys); - dir = cl_namestring(dir); file = cl_file_namestring(phys); l = dir->base_string.fillp; - memcpy(strTempDir, dir->base_string.self, l); strTempDir[l] = 0; for (s = strTempDir; *s; s++) if (*s == '/') *s = '\\'; - if (!GetTempFileName(strTempDir, file->base_string.self, 0, strTempFileName)) - { - @(return Cnil) + ecl_disable_interrupts(); + ok = GetTempFileName(strTempDir, file->base_string.self, 0, strTempFileName); + ecl_enable_interrupts(); + if (!ok) { + output = Cnil; + } else { + l = strlen(strTempFileName); + output = cl_alloc_simple_base_string(l); + memcpy(output->base_string.self, strTempFileName, l); } - - l = strlen(strTempFileName); - output = cl_alloc_simple_base_string(l); - memcpy(output->base_string.self, strTempFileName, l); - #else - template = si_coerce_to_filename(template); l = template->base_string.fillp; output = cl_alloc_simple_base_string(l + 6); memcpy(output->base_string.self, template->base_string.self, l); memcpy(output->base_string.self + l, "XXXXXX", 6); -#ifdef HAVE_MKSTEMP + + ecl_disable_interrupts(); +# ifdef HAVE_MKSTEMP fd = mkstemp(output->base_string.self); -#else +# else fd = mktemp(output->base_string.self); fd = open(fd, O_CREAT|O_TRUNC, 0666); -#endif - if (fd < 0) - @(return Cnil) - close(fd); +# endif + ecl_enable_interrupts(); + if (fd < 0) { + output = Cnil; + } else { + close(fd); + } #endif - - @(return cl_truename(output)) + @(return (Null(output)? output : cl_truename(output))) } cl_object si_rmdir(cl_object directory) { + int code; directory = si_coerce_to_filename(directory); - if ( rmdir(directory->base_string.self) != 0 ) + + ecl_disable_interrupts(); + code = rmdir(directory->base_string.self); + ecl_enable_interrupts(); + + if (code != 0) FElibc_error("Can't remove directory ~A.", 1, directory); @(return Cnil) } diff --git a/src/h/external.h b/src/h/external.h index eb2210943..8a5781e2f 100644 --- a/src/h/external.h +++ b/src/h/external.h @@ -1541,7 +1541,6 @@ extern ECL_API cl_object cl_user_homedir_pathname _ARGS((cl_narg narg, ...)); extern ECL_API cl_object si_mkstemp(cl_object templ); extern ECL_API cl_object si_rmdir(cl_object directory); -extern ECL_API const char *ecl_expand_pathname(const char *name); extern ECL_API cl_object ecl_cstring_to_pathname(char *s); extern ECL_API void *ecl_backup_fopen(const char *filename, const char *option); extern ECL_API cl_object ecl_file_len(void *fp); diff --git a/src/h/internal.h b/src/h/internal.h index 588b16553..b30af2c82 100644 --- a/src/h/internal.h +++ b/src/h/internal.h @@ -25,8 +25,8 @@ extern "C" { extern void init_all_symbols(void); extern void init_alloc(void); extern void init_backq(void); -extern void init_big(void); -extern void init_big_registers(void); +extern void init_big(cl_env_ptr); +extern void init_big_registers(cl_env_ptr); #ifdef CLOS extern void init_clos(void); #endif