diff options
Diffstat (limited to 'erts')
-rw-r--r-- | erts/configure.in | 5 | ||||
-rwxr-xr-x | erts/emulator/sys/win32/sys.c | 77 | ||||
-rw-r--r-- | erts/include/internal/ethread.h | 2 | ||||
-rw-r--r-- | erts/test/otp_SUITE.erl | 21 |
4 files changed, 95 insertions, 10 deletions
diff --git a/erts/configure.in b/erts/configure.in index 8d70a1b74a..6ad1951a4e 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -3575,6 +3575,11 @@ case $host_os in DED_LDFLAGS="-m32 $DED_LDFLAGS" fi ;; + openbsd*) + DED_LD="$CC" + DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH" + DED_LDFLAGS="-shared" + ;; osf*) # NOTE! Whitespace after -rpath is important. DED_LD_FLAG_RUNTIME_LIBRARY_PATH="-rpath " diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c index 1c9f8ebf43..6c69fecbf3 100755 --- a/erts/emulator/sys/win32/sys.c +++ b/erts/emulator/sys/win32/sys.c @@ -420,6 +420,8 @@ typedef struct async_io { HANDLE ioAllowed; /* The thread will wait for this event * before starting a new read or write. */ + HANDLE flushEvent; /* Used to signal that a flush should be done. */ + HANDLE flushReplyEvent; /* Used to signal that a flush has been done. */ DWORD pendingError; /* Used to delay presentating an error to Erlang * until the check_io function is entered. */ @@ -878,6 +880,8 @@ init_async_io(AsyncIo* aio, int use_threads) aio->ov.Offset = 0L; aio->ov.OffsetHigh = 0L; aio->ioAllowed = NULL; + aio->flushEvent = NULL; + aio->flushReplyEvent = NULL; aio->pendingError = 0; aio->bytesTransferred = 0; #ifdef ERTS_SMP @@ -890,6 +894,12 @@ init_async_io(AsyncIo* aio, int use_threads) aio->ioAllowed = CreateAutoEvent(FALSE); if (aio->ioAllowed == NULL) return -1; + aio->flushEvent = CreateAutoEvent(FALSE); + if (aio->flushEvent == NULL) + return -1; + aio->flushReplyEvent = CreateAutoEvent(FALSE); + if (aio->flushReplyEvent == NULL) + return -1; } return 0; } @@ -923,6 +933,14 @@ release_async_io(AsyncIo* aio, ErlDrvPort port_num) if (aio->ioAllowed != NULL) CloseHandle(aio->ioAllowed); aio->ioAllowed = NULL; + + if (aio->flushEvent != NULL) + CloseHandle(aio->flushEvent); + aio->flushEvent = NULL; + + if (aio->flushReplyEvent != NULL) + CloseHandle(aio->flushReplyEvent); + aio->flushReplyEvent = NULL; } /* ---------------------------------------------------------------------- @@ -2083,16 +2101,26 @@ threaded_writer(LPVOID param) AsyncIo* aio = (AsyncIo *) param; HANDLE thread = GetCurrentThread(); char* buf; - DWORD numToWrite; + DWORD numToWrite, handle; int ok; + HANDLE handles[2]; + handles[0] = aio->ioAllowed; + handles[1] = aio->flushEvent; for (;;) { - WaitForSingleObject(aio->ioAllowed, INFINITE); + handle = WaitForMultipleObjects(2, handles, FALSE, INFINITE); if (aio->flags & DF_EXIT_THREAD) break; + buf = OV_BUFFER_PTR(aio); numToWrite = OV_NUM_TO_READ(aio); aio->pendingError = 0; + + if (handle == (WAIT_OBJECT_0 + 1) && numToWrite == 0) { + SetEvent(aio->flushReplyEvent); + continue; + } + ok = WriteFile(aio->fd, buf, numToWrite, &aio->bytesTransferred, NULL); if (!ok) { aio->pendingError = GetLastError(); @@ -2127,7 +2155,11 @@ threaded_writer(LPVOID param) } } } - SetEvent(aio->ov.hEvent); + OV_NUM_TO_READ(aio) = 0; + if (handle == (WAIT_OBJECT_0 + 1)) + SetEvent(aio->flushReplyEvent); + else + SetEvent(aio->ov.hEvent); if (aio->pendingError != NO_ERROR || aio->bytesTransferred == 0) break; if (aio->flags & DF_EXIT_THREAD) @@ -2193,6 +2225,43 @@ fd_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts) if ((dp = new_driver_data(port_num, opts->packet_bytes, 2, TRUE)) == NULL) return ERL_DRV_ERROR_GENERAL; + /** + * Here is a brief description about how the fd driver works on windows. + * + * fd_init: + * For each in/out fd pair a threaded_reader and threaded_writer thread is + * created. Within the DriverData struct each of the threads have an AsyncIO + * sctruct associated with it. Within AsyncIO there are two important HANDLEs, + * ioAllowed and ov.hEvent. ioAllowed is used to signal the threaded_* threads + * should read/write some data, and ov.hEvent is driver_select'ed to be used to + * signal that the thread is done reading/writing. + * + * The reason for the driver being threaded like this is because once the FD is open + * on windows, it is not possible to set the it in overlapped mode. So we have to + * simulate this using threads. + * + * output: + * When an output occurs the data to be outputted is copied to AsyncIO.ov. Then + * the ioAllowed HANDLE is set, ov.hEvent is cleared and the port is marked as busy. + * The threaded_writer thread is lying in WaitForMultipleObjects on ioAllowed, and + * when signalled it writes all data in AsyncIO.ov and then sets ov.hEvent so that + * ready_output gets triggered and (potentially) sends the reply to the port and + * marks the port an non-busy. + * + * input: + * The threaded_reader is lying waiting in ReadFile on the in fd and when a new + * line is written it sets ov.hEvent that new data is available and then goes + * and waits for ioAllowed to be set. ready_input is run when ov.hEvent is set and + * delivers the data to the port. Then ioAllowed is signalled again and threaded_reader + * goes back to ReadFile. + * + * shutdown: + * In order to guarantee that all io is outputted before the driver is stopped, + * fd_stop uses flushEvent and flushReplyEvent to make sure that there is no data + * in ov which needs writing before returning from fd_stop. + * + **/ + if (!create_file_thread(&dp->in, DO_READ)) { dp->port_num = PORT_FREE; return ERL_DRV_ERROR_GENERAL; @@ -2241,6 +2310,8 @@ static void fd_stop(ErlDrvData d) (void) driver_select(dp->port_num, (ErlDrvEvent)dp->out.ov.hEvent, ERL_DRV_WRITE, 0); + SetEvent(dp->out.flushEvent); + WaitForSingleObject(dp->out.flushReplyEvent, INFINITE); } } diff --git a/erts/include/internal/ethread.h b/erts/include/internal/ethread.h index 142c26c0ca..e1885c627a 100644 --- a/erts/include/internal/ethread.h +++ b/erts/include/internal/ethread.h @@ -355,10 +355,8 @@ extern ethr_runtime_t ethr_runtime__; # include "sparc64/ethread.h" # endif # endif -#if 0 # include "gcc/ethread.h" # include "libatomic_ops/ethread.h" -#endif # endif # elif defined(ETHR_HAVE_LIBATOMIC_OPS) # include "libatomic_ops/ethread.h" diff --git a/erts/test/otp_SUITE.erl b/erts/test/otp_SUITE.erl index 5f28f22606..b7ceb0a3fd 100644 --- a/erts/test/otp_SUITE.erl +++ b/erts/test/otp_SUITE.erl @@ -84,13 +84,14 @@ undefined_functions(Config) when is_list(Config) -> "ExcludedFrom = ~p:_/_," "Undef - Undef | ExcludedFrom", [UndefS,ExcludeFrom]), - ?line {ok,Undef0} = xref:q(Server, lists:flatten(Q)), - ?line Undef1 = hipe_filter(Undef0), - ?line Undef2 = ssl_crypto_filter(Undef1), - ?line Undef3 = edoc_filter(Undef2), + {ok,Undef0} = xref:q(Server, lists:flatten(Q)), + Undef1 = hipe_filter(Undef0), + Undef2 = ssl_crypto_filter(Undef1), + Undef3 = edoc_filter(Undef2), Undef4 = eunit_filter(Undef3), Undef5 = dialyzer_filter(Undef4), - Undef = wx_filter(Undef5), + Undef6 = wx_filter(Undef5), + Undef = gs_filter(Undef6), case Undef of [] -> ok; @@ -202,6 +203,16 @@ wx_filter(Undef) -> _ -> Undef end. +gs_filter(Undef) -> + case code:lib_dir(gs) of + {error,bad_name} -> + filter(fun({_,{gs,_,_}}) -> false; + ({_,{gse,_,_}}) -> false; + ({_,{tool_utils,_,_}}) -> false; + (_) -> true + end, Undef); + _ -> Undef + end. deprecated_not_in_obsolete(Config) when is_list(Config) -> ?line Server = ?config(xref_server, Config), |