diff options
Diffstat (limited to 'erts/emulator/sys')
-rw-r--r-- | erts/emulator/sys/common/erl_poll.c | 59 | ||||
-rw-r--r-- | erts/emulator/sys/unix/erl9_start.c | 130 | ||||
-rw-r--r-- | erts/emulator/sys/win32/erl_poll.c | 65 | ||||
-rw-r--r-- | erts/emulator/sys/win32/sys.c | 124 |
4 files changed, 188 insertions, 190 deletions
diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c index 5cca33d7eb..09fb6337f7 100644 --- a/erts/emulator/sys/common/erl_poll.c +++ b/erts/emulator/sys/common/erl_poll.c @@ -130,13 +130,18 @@ #define ERTS_POLLSET_IS_POLLED(PS) \ ((int) erts_smp_atomic_read(&(PS)->polled)) -#define ERTS_POLLSET_SET_POLLER_WOKEN_CHK(PS) \ - ((int) erts_smp_atomic_xchg(&(PS)->woken, (long) 1)) -#define ERTS_POLLSET_SET_POLLER_WOKEN(PS) \ - erts_smp_atomic_set(&(PS)->woken, (long) 1) -#define ERTS_POLLSET_UNSET_POLLER_WOKEN(PS) \ - erts_smp_atomic_set(&(PS)->woken, (long) 0) -#define ERTS_POLLSET_IS_POLLER_WOKEN(PS) \ +#define ERTS_POLLSET_SET_POLLER_WOKEN_CHK(PS) set_poller_woken_chk((PS)) +#define ERTS_POLLSET_SET_POLLER_WOKEN(PS) \ +do { \ + ERTS_THR_MEMORY_BARRIER; \ + erts_smp_atomic_set(&(PS)->woken, (long) 1); \ +} while (0) +#define ERTS_POLLSET_UNSET_POLLER_WOKEN(PS) \ +do { \ + erts_smp_atomic_set(&(PS)->woken, (long) 0); \ + ERTS_THR_MEMORY_BARRIER; \ +} while (0) +#define ERTS_POLLSET_IS_POLLER_WOKEN(PS) \ ((int) erts_smp_atomic_read(&(PS)->woken)) #else @@ -194,13 +199,18 @@ #else -#define ERTS_POLLSET_UNSET_INTERRUPTED_CHK(PS) \ - ((int) erts_smp_atomic_xchg(&(PS)->interrupt, (long) 0)) -#define ERTS_POLLSET_UNSET_INTERRUPTED(PS) \ - erts_smp_atomic_set(&(PS)->interrupt, (long) 0) -#define ERTS_POLLSET_SET_INTERRUPTED(PS) \ - erts_smp_atomic_set(&(PS)->interrupt, (long) 1) -#define ERTS_POLLSET_IS_INTERRUPTED(PS) \ +#define ERTS_POLLSET_UNSET_INTERRUPTED_CHK(PS) unset_interrupted_chk((PS)) +#define ERTS_POLLSET_UNSET_INTERRUPTED(PS) \ +do { \ + erts_smp_atomic_set(&(PS)->interrupt, (long) 0); \ + ERTS_THR_MEMORY_BARRIER; \ +} while (0) +#define ERTS_POLLSET_SET_INTERRUPTED(PS) \ +do { \ + ERTS_THR_MEMORY_BARRIER; \ + erts_smp_atomic_set(&(PS)->interrupt, (long) 1); \ +} while (0) +#define ERTS_POLLSET_IS_INTERRUPTED(PS) \ ((int) erts_smp_atomic_read(&(PS)->interrupt)) #endif @@ -336,16 +346,30 @@ struct ErtsPollSet_ { #endif }; -#if ERTS_POLL_ASYNC_INTERRUPT_SUPPORT && !defined(ERTS_SMP) - static ERTS_INLINE int unset_interrupted_chk(ErtsPollSet ps) { + int res; +#if ERTS_POLL_ASYNC_INTERRUPT_SUPPORT && !defined(ERTS_SMP) /* This operation isn't atomic, but we have no need at all for an atomic operation here... */ - int res = ps->interrupt; + res = ps->interrupt; ps->interrupt = 0; +#else + res = (int) erts_smp_atomic_xchg(&ps->interrupt, (long) 0); + ERTS_THR_MEMORY_BARRIER; +#endif return res; + +} + +#ifdef ERTS_SMP + +static ERTS_INLINE int +set_poller_woken_chk(ErtsPollSet ps) +{ + ERTS_THR_MEMORY_BARRIER; + return (int) erts_smp_atomic_xchg(&ps->woken, (long) 1); } #endif @@ -2405,6 +2429,7 @@ ERTS_POLL_EXPORT(erts_poll_info)(ErtsPollSet ps, ErtsPollInfo *pip) while (urqbp) { size += sizeof(ErtsPollSetUpdateRequestsBlock); pending_updates += urqbp->len; + urqbp = urqbp->next; } } #endif diff --git a/erts/emulator/sys/unix/erl9_start.c b/erts/emulator/sys/unix/erl9_start.c deleted file mode 100644 index 578062d7e2..0000000000 --- a/erts/emulator/sys/unix/erl9_start.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2002-2009. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include "sys.h" -#include "erl_vm.h" -#include "global.h" -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -/* - * XXX This is a temporary dummy to make sys.c happy until we'll rewrite it. - */ -unsigned preloaded_size_ring0 = 1; -unsigned char preloaded_ring0[1] = {0}; - -Preload pre_loaded[] = { - {"ring0", 1, preloaded_ring0}, - {0, 0, 0} -}; - -int -main(int argc, char** argv) -{ - char sbuf[1024]; - struct { - void* p; - int sz; - } bins[2]; - int bin_num = 0; - FILE* fp; - char* progname = argv[0]; - char* eq; - - argv++, argc--; - - if (argc > 0 && argv[0][0] == '-') { - argv++, argc--; - } - if (argc < 1) { - abort(); - } - if ((fp = fopen(argv[0], "r")) == NULL) { - abort(); - } - - /* Needs to be called before any memory allocation */ - erts_short_init(); - - while (fgets(sbuf, sizeof sbuf, fp)) { - if (sbuf[0] == '#') { - continue; /* Comment */ - } else if (sbuf[0] == 'e' && strncmp("exec", sbuf, 4) == 0) { - continue; /* Comment ;-) */ - } else if ((eq = strchr(sbuf, '=')) != NULL) { - char* val; - char* p = strchr(sbuf, '\n'); - if (p) { - *p = '\0'; - } - *eq = '\0'; - val = erts_read_env(sbuf); - if (val == NULL) { - *eq = '='; - erts_sys_putenv(sbuf, eq - &sbuf[0]); - } - erts_free_read_env(val); - } else if (sbuf[0] == ':' && '0' <= sbuf[1] && sbuf[1] <= '9') { - int load_size = atoi(sbuf+1); - void* bin; - - bin = malloc(load_size); - if (fread(bin, 1, load_size, fp) != load_size) { - abort(); - } - bins[bin_num].p = bin; - bins[bin_num].sz = load_size; - bin_num++; - } else if (strcmp(sbuf, "--end--\n") == 0) { - int rval; - Eterm mod = NIL; - char *val; - - fclose(fp); - - if (bin_num != 2) { - abort(); - } - - val = erts_read_env("ERLBREAKHANDLER"); - if (val) { - init_break_handler(); - } - erts_free_read_env(val); - - if ((rval = erts_load_module(NULL, 0, NIL, &mod, bins[0].p, bins[0].sz)) < 0) { - fprintf(stderr, "%s: Load of initial module failed: %d\n", - progname, rval); - abort(); - } - erts_first_process(mod, bins[1].p, bins[1].sz, argc, argv); - free(bins[0].p); - free(bins[1].p); - process_main(); - abort(); - } else { - fprintf(stderr, "%s: bad line: %s\n", progname, sbuf); - abort(); - } - } - abort(); -} diff --git a/erts/emulator/sys/win32/erl_poll.c b/erts/emulator/sys/win32/erl_poll.c index d816cc2c07..a766fe9575 100644 --- a/erts/emulator/sys/win32/erl_poll.c +++ b/erts/emulator/sys/win32/erl_poll.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2007-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2007-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ #ifdef HAVE_CONFIG_H @@ -304,24 +304,51 @@ struct ErtsPollSet_ { erts_smp_atomic_set(&(PS)->polled, (long) 0) #define ERTS_POLLSET_IS_POLLED(PS) \ ((int) erts_smp_atomic_read(&(PS)->polled)) -#define ERTS_POLLSET_SET_POLLER_WOKEN_CHK(PS) \ - ((int) erts_smp_atomic_xchg(&(PS)->woken, (long) 1)) -#define ERTS_POLLSET_SET_POLLER_WOKEN(PS) \ - erts_smp_atomic_set(&(PS)->woken, (long) 1) -#define ERTS_POLLSET_UNSET_POLLER_WOKEN(PS) \ - erts_smp_atomic_set(&(PS)->woken, (long) 0) -#define ERTS_POLLSET_IS_POLLER_WOKEN(PS) \ + +#define ERTS_POLLSET_SET_POLLER_WOKEN_CHK(PS) set_poller_woken_chk((PS)) +#define ERTS_POLLSET_SET_POLLER_WOKEN(PS) \ +do { \ + ERTS_THR_MEMORY_BARRIER; \ + erts_smp_atomic_set(&(PS)->woken, (long) 1); \ +} while (0) +#define ERTS_POLLSET_UNSET_POLLER_WOKEN(PS) \ +do { \ + erts_smp_atomic_set(&(PS)->woken, (long) 0); \ + ERTS_THR_MEMORY_BARRIER; \ +} while (0) +#define ERTS_POLLSET_IS_POLLER_WOKEN(PS) \ ((int) erts_smp_atomic_read(&(PS)->woken)) -#define ERTS_POLLSET_UNSET_INTERRUPTED_CHK(PS) \ - ((int) erts_smp_atomic_xchg(&(PS)->interrupt, (long) 0)) -#define ERTS_POLLSET_UNSET_INTERRUPTED(PS) \ - erts_smp_atomic_set(&(PS)->interrupt, (long) 0) -#define ERTS_POLLSET_SET_INTERRUPTED(PS) \ - erts_smp_atomic_set(&(PS)->interrupt, (long) 1) -#define ERTS_POLLSET_IS_INTERRUPTED(PS) \ +#define ERTS_POLLSET_UNSET_INTERRUPTED_CHK(PS) unset_interrupted_chk((PS)) +#define ERTS_POLLSET_UNSET_INTERRUPTED(PS) \ +do { \ + erts_smp_atomic_set(&(PS)->interrupt, (long) 0); \ + ERTS_THR_MEMORY_BARRIER; \ +} while (0) +#define ERTS_POLLSET_SET_INTERRUPTED(PS) \ +do { \ + ERTS_THR_MEMORY_BARRIER; \ + erts_smp_atomic_set(&(PS)->interrupt, (long) 1); \ +} while (0) +#define ERTS_POLLSET_IS_INTERRUPTED(PS) \ ((int) erts_smp_atomic_read(&(PS)->interrupt)) +static ERTS_INLINE int +unset_interrupted_chk(ErtsPollSet ps) +{ + int res = (int) erts_smp_atomic_xchg(&ps->interrupt, (long) 0); + ERTS_THR_MEMORY_BARRIER; + return res; + +} + +static ERTS_INLINE int +set_poller_woken_chk(ErtsPollSet ps) +{ + ERTS_THR_MEMORY_BARRIER; + return (int) erts_smp_atomic_xchg(&ps->woken, (long) 1); +} + #else #define ERTS_POLLSET_LOCK(PS) diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c index 46dee826f0..d3921a14f8 100644 --- a/erts/emulator/sys/win32/sys.c +++ b/erts/emulator/sys/win32/sys.c @@ -33,6 +33,7 @@ #include "../../drivers/win32/win_con.h" + void erts_sys_init_float(void); void erl_start(int, char**); @@ -95,6 +96,10 @@ static erts_smp_mtx_t sys_driver_data_lock; static FUNCTION(int, driver_write, (long, HANDLE, byte*, int)); static void common_stop(int); static int create_file_thread(struct async_io* aio, int mode); +#ifdef ERTS_SMP +static void close_active_handles(ErlDrvPort, const HANDLE* handles, int cnt); +static DWORD WINAPI threaded_handle_closer(LPVOID param); +#endif static DWORD WINAPI threaded_reader(LPVOID param); static DWORD WINAPI threaded_writer(LPVOID param); static DWORD WINAPI threaded_exiter(LPVOID param); @@ -132,6 +137,9 @@ static BOOL win_console = FALSE; static OSVERSIONINFO int_os_version; /* Version information for Win32. */ +#ifdef ERTS_SMP +static BOOL (WINAPI *fpCancelIoEx)(HANDLE,LPOVERLAPPED); +#endif /* This is the system's main function (which may or may not be called "main") - do general system-dependent initialization @@ -676,25 +684,50 @@ release_driver_data(DriverData* dp) erts_smp_mtx_lock(&sys_driver_data_lock); #ifdef ERTS_SMP - /* This is a workaround for the fact that CancelIo cant cancel - requests issued by another thread and that we still cant use - CancelIoEx as that's only availabele in Vista etc. */ - if(dp->in.async_io_active && dp->in.fd != INVALID_HANDLE_VALUE) { - CloseHandle(dp->in.fd); - dp->in.fd = INVALID_HANDLE_VALUE; - DEBUGF(("Waiting for the in event thingie")); - WaitForSingleObject(dp->in.ov.hEvent,INFINITE); - DEBUGF(("...done\n")); - } - if(dp->out.async_io_active && dp->out.fd != INVALID_HANDLE_VALUE) { - CloseHandle(dp->out.fd); - dp->out.fd = INVALID_HANDLE_VALUE; - DEBUGF(("Waiting for the out event thingie")); - WaitForSingleObject(dp->out.ov.hEvent,INFINITE); - DEBUGF(("...done\n")); + if (fpCancelIoEx != NULL) { + if (dp->in.thread == (HANDLE) -1 && dp->in.fd != INVALID_HANDLE_VALUE) { + (*fpCancelIoEx)(dp->in.fd, NULL); + } + if (dp->out.thread == (HANDLE) -1 && dp->out.fd != INVALID_HANDLE_VALUE) { + (*fpCancelIoEx)(dp->out.fd, NULL); + } + } + else { + /* This is a workaround for the fact that CancelIo cant cancel + requests issued by another thread and that we cant use + CancelIoEx as that's only availabele in Vista etc. + R14: Avoid scheduler deadlock by only wait for 10ms, and then spawn + a thread that will keep waiting in in order to close handles. */ + HANDLE handles[2]; + int i = 0; + int timeout = 10; + if(dp->in.async_io_active && dp->in.fd != INVALID_HANDLE_VALUE) { + CloseHandle(dp->in.fd); + dp->in.fd = INVALID_HANDLE_VALUE; + DEBUGF(("Waiting for the in event thingie")); + if (WaitForSingleObject(dp->in.ov.hEvent,timeout) == WAIT_TIMEOUT) { + handles[i++] = dp->in.ov.hEvent; + dp->in.ov.hEvent = NULL; + timeout = 0; + } + DEBUGF(("...done\n")); + } + if(dp->out.async_io_active && dp->out.fd != INVALID_HANDLE_VALUE) { + CloseHandle(dp->out.fd); + dp->out.fd = INVALID_HANDLE_VALUE; + DEBUGF(("Waiting for the out event thingie")); + if (WaitForSingleObject(dp->out.ov.hEvent,timeout) == WAIT_TIMEOUT) { + handles[i++] = dp->out.ov.hEvent; + dp->out.ov.hEvent = NULL; + } + DEBUGF(("...done\n")); + } + if (i > 0) { + close_active_handles(dp->port_num, handles, i); + } } #else - if (dp->out.thread == (HANDLE) -1 && dp->in.fd != INVALID_HANDLE_VALUE) { + if (dp->in.thread == (HANDLE) -1 && dp->in.fd != INVALID_HANDLE_VALUE) { CancelIo(dp->in.fd); } if (dp->out.thread == (HANDLE) -1 && dp->out.fd != INVALID_HANDLE_VALUE) { @@ -737,6 +770,48 @@ release_driver_data(DriverData* dp) erts_smp_mtx_unlock(&sys_driver_data_lock); } +#ifdef ERTS_SMP + +struct handles_to_be_closed +{ + int cnt; + HANDLE handles[2]; +}; + +static void close_active_handles(ErlDrvPort port_num, const HANDLE* handles, int cnt) +{ + DWORD tid; + HANDLE thread; + int i; + struct handles_to_be_closed* htbc = erts_alloc(ERTS_ALC_T_DRV_TAB, + sizeof(struct handles_to_be_closed)); + htbc->cnt = cnt; + for (i=0; i < cnt; ++i) { + htbc->handles[i] = handles[i]; + (void) driver_select(port_num, (ErlDrvEvent)handles[i], + ERL_DRV_USE_NO_CALLBACK, 0); + } + thread = (HANDLE *) _beginthreadex(NULL, 0, threaded_handle_closer, htbc, 0, &tid); + CloseHandle(thread); +} + + +static DWORD WINAPI +threaded_handle_closer(LPVOID param) +{ + struct handles_to_be_closed* htbc = (struct handles_to_be_closed*) param; + int i; + DEBUGF(("threaded_handle_closer waiting for %d handles\r\n",htbc->cnt)); + WaitForMultipleObjects(htbc->cnt, htbc->handles, TRUE, INFINITE); + for (i=0; i < htbc->cnt; ++i) { + CloseHandle(htbc->handles[i]); + } + erts_free(ERTS_ALC_T_DRV_TAB, htbc); + DEBUGF(("threaded_handle_closer terminating\r\n")); + return 0; +} +#endif /* ERTS_SMP */ + /* * Stores input and output file descriptors in the DriverData structure, * and calls driver_select(). @@ -1026,12 +1101,19 @@ static int spawn_init() { int i; - +#ifdef ERTS_SMP + HMODULE module = GetModuleHandle("kernel32"); + fpCancelIoEx = (module != NULL) ? + (BOOL (WINAPI *)(HANDLE,LPOVERLAPPED)) + GetProcAddress(module,"CancelIoEx") : NULL; + DEBUGF(("fpCancelIoEx = %p\r\n", fpCancelIoEx)); +#endif driver_data = (struct driver_data *) erts_alloc(ERTS_ALC_T_DRV_TAB, max_files * sizeof(struct driver_data)); erts_smp_atomic_add(&sys_misc_mem_sz, max_files*sizeof(struct driver_data)); for (i = 0; i < max_files; i++) driver_data[i].port_num = PORT_FREE; + return 0; } @@ -2928,12 +3010,6 @@ erts_sys_pre_init(void) erts_sys_env_init(); } -/* - * the last two only used for standalone erlang - * they should are used by sae_main in beam dll to - * enable standalone execution via erl_api-routines - */ - void noinherit_std_handle(DWORD type) { HANDLE h = GetStdHandle(type); |