diff --git a/ACE/ace/OS_NS_errno.cpp b/ACE/ace/OS_NS_errno.cpp index f84975d40af2a..39a8c598a5bca 100644 --- a/ACE/ace/OS_NS_errno.cpp +++ b/ACE/ace/OS_NS_errno.cpp @@ -5,3 +5,75 @@ # include "ace/OS_NS_errno.inl" #endif /* ACE_HAS_INLINED_OSCALLS */ + +// Perform a mapping of Win32 error numbers into POSIX errnos. +// NOTE: Keep this out-of-line as list may grow in future +int +ACE_OS::adapt_last_error(int error) +{ + ACE_OS_TRACE("ACE_OS::adapt_last_error"); + +#if defined(ACE_WIN32) + // Perform a mapping of Win32 error numbers into POSIX errnos. + switch (error) + { + case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM ; break; + case ERROR_FILE_EXISTS: error = EEXIST ; break; + case ERROR_SHARING_VIOLATION: error = EACCES ; break; + case ERROR_PATH_NOT_FOUND: error = ENOENT ; break; + case ERROR_ACCESS_DENIED: error = EPERM ; break; + case ERROR_SEM_TIMEOUT: error = ETIME ; break; + case ERROR_TIMEOUT: error = ETIME ; break; +// +// Reverse WSAGetLastError mappings that are not handled by +// the direct mappings in +// +#if defined(_CRT_NO_POSIX_ERROR_CODES) // see + case WSAEWOULDBLOCK: error = EWOULDBLOCK ; break; + case WSAEINPROGRESS: error = EINPROGRESS ; break; + case WSAEALREADY: error = EALREADY ; break; + case WSAENOTSOCK: error = ENOTSOCK ; break; + case WSAEDESTADDRREQ: error = EDESTADDRREQ ; break; + case WSAEMSGSIZE: error = EMSGSIZE ; break; + case WSAEPROTOTYPE: error = EPROTOTYPE ; break; + case WSAENOPROTOOPT: error = ENOPROTOOPT ; break; + case WSAEPROTONOSUPPORT: error = EPROTONOSUPPORT ; break; + case WSAESOCKTNOSUPPORT: error = ESOCKTNOSUPPORT ; break; + case WSAEOPNOTSUPP: error = EOPNOTSUPP ; break; + case WSAEPFNOSUPPORT: error = EPFNOSUPPORT ; break; + case WSAEAFNOSUPPORT: error = EAFNOSUPPORT ; break; + case WSAEADDRINUSE: error = EADDRINUSE ; break; + case WSAEADDRNOTAVAIL: error = EADDRNOTAVAIL ; break; + case WSAENETDOWN: error = ENETDOWN ; break; + case WSAENETUNREACH: error = ENETUNREACH ; break; + case WSAENETRESET: error = ENETRESET ; break; + case WSAECONNABORTED: error = ECONNABORTED ; break; + case WSAECONNRESET: error = ECONNRESET ; break; + case WSAENOBUFS: error = ENOBUFS ; break; + case WSAEISCONN: error = EISCONN ; break; + case WSAENOTCONN: error = ENOTCONN ; break; + case WSAESHUTDOWN: error = ESHUTDOWN ; break; + case WSAETOOMANYREFS: error = ETOOMANYREFS ; break; + case WSAETIMEDOUT: error = ETIMEDOUT ; break; + case WSAECONNREFUSED: error = ECONNREFUSED ; break; + case WSAELOOP: error = ELOOP ; break; + case WSAEHOSTDOWN: error = EHOSTDOWN ; break; + case WSAEHOSTUNREACH: error = EHOSTUNREACH ; break; + case WSAEPROCLIM: error = EPROCLIM ; break; + case WSAEUSERS: error = EUSERS ; break; + case WSAEDQUOT: error = EDQUOT ; break; + case WSAESTALE: error = ESTALE ; break; + case WSAEREMOTE: error = EREMOTE ; break; +#endif /* defined(_CRT_NO_POSIX_ERROR_CODES) */ +/* ENAMETOOLONG and ENOTEMPTY are defined by the 'standard' library. */ +#if defined(ENAMETOOLONG) + case WSAENAMETOOLONG: error = ENAMETOOLONG ; break; +#endif +#if defined(ENOTEMPTY) + case WSAENOTEMPTY: error = ENOTEMPTY ; break; +#endif + } +#endif /* defined(ACE_WIN32) */ + + return ACE_OS::last_error(error); +} diff --git a/ACE/ace/OS_NS_errno.h b/ACE/ace/OS_NS_errno.h index 75701f9840373..2c5965bcf4cb8 100644 --- a/ACE/ace/OS_NS_errno.h +++ b/ACE/ace/OS_NS_errno.h @@ -39,7 +39,7 @@ namespace ACE_OS { int last_error (void); ACE_NAMESPACE_INLINE_FUNCTION - void last_error (int error); + int last_error (int error); ACE_NAMESPACE_INLINE_FUNCTION int set_errno_to_last_error (void); @@ -47,6 +47,10 @@ namespace ACE_OS { ACE_NAMESPACE_INLINE_FUNCTION int set_errno_to_wsa_last_error (void); + // Perform a mapping of Win32 error numbers into POSIX errnos. + ACE_EXPORT_MACRO + int adapt_last_error (int error); + } /* namespace ACE_OS */ #if defined (ACE_HAS_WINCE_BROKEN_ERRNO) diff --git a/ACE/ace/OS_NS_errno.inl b/ACE/ace/OS_NS_errno.inl index cad5d49789b5c..ef88385ac010b 100644 --- a/ACE/ace/OS_NS_errno.inl +++ b/ACE/ace/OS_NS_errno.inl @@ -22,14 +22,14 @@ ACE_OS::last_error (void) #endif /* ACE_WIN32 */ } -ACE_INLINE void +ACE_INLINE int ACE_OS::last_error (int error) { ACE_OS_TRACE ("ACE_OS::last_error"); #if defined (ACE_WIN32) ::SetLastError (error); #endif /* ACE_WIN32 */ - errno = error; + return int(errno = error); } ACE_INLINE int diff --git a/ACE/ace/OS_NS_macros.h b/ACE/ace/OS_NS_macros.h index 647f3143e8177..7bbe39818c8be 100644 --- a/ACE/ace/OS_NS_macros.h +++ b/ACE/ace/OS_NS_macros.h @@ -26,46 +26,34 @@ #if defined (ACE_WIN32) # define ACE_SOCKCALL_RETURN(OP,TYPE,FAILVALUE) \ do { TYPE ace_result_ = (TYPE) OP; \ - if (ace_result_ == FAILVALUE) { int ___ = ::WSAGetLastError (); errno = ___; return (TYPE) FAILVALUE; } else return ace_result_; \ + if (ace_result_ == FAILVALUE) { ACE_OS::adapt_last_error(ACE_OS::set_errno_to_wsa_last_error()); return (TYPE) FAILVALUE; } else return ace_result_; \ } while (0) # define ACE_SOCKCALL(OP,TYPE,FAILVALUE,RESULT) \ do { RESULT = (TYPE) OP; \ - if (RESULT == FAILVALUE) { int ___ = ::WSAGetLastError (); errno = ___; RESULT = FAILVALUE; } \ + if (RESULT == FAILVALUE) { ACE_OS::adapt_last_error(ACE_OS::set_errno_to_wsa_last_error()); RESULT = FAILVALUE; } \ } while (0) #else # define ACE_SOCKCALL_RETURN(OP,TYPE,FAILVALUE) ACE_OSCALL_RETURN(OP,TYPE,FAILVALUE) # define ACE_SOCKCALL(OP,TYPE,FAILVALUE,RESULT) ACE_OSCALL(OP,TYPE,FAILVALUE,RESULT) #endif /* ACE_WIN32 */ -#if !defined (ACE_WIN32) +#define ACE_FAIL_RETVAL(RESULT) (ACE_OS::adapt_last_error(ACE_OS::set_errno_to_last_error()),(RESULT)) +#define ACE_FAIL_RETURN(RESULT) return ACE_FAIL_RETVAL(RESULT) + +#if defined (ACE_WIN32) +// Adapt the Win32 System Calls (which return BOOLEAN values of TRUE +// and FALSE) into int values expected by the ACE_OSCALL macros. +# define ACE_ADAPT_RETVAL(OP,RESULT) ((RESULT = (OP)) == FALSE ? ACE_FAIL_RETVAL(-1) : 0) // Adapt the weird threading and synchronization routines (which // return errno rather than -1) so that they return -1 and set errno. // This is more consistent with the rest of ACE_OS and enables us to // use the ACE_OSCALL* macros. -# if defined (ACE_VXWORKS) -# define ACE_ADAPT_RETVAL(OP,RESULT) ((RESULT = (OP)) != OK ? (errno = RESULT, -1) : 0) -# else -# define ACE_ADAPT_RETVAL(OP,RESULT) ((RESULT = (OP)) != 0 ? (errno = RESULT, -1) : 0) -# endif /* ACE_VXWORKS */ - -#else /* ACE_WIN32 */ - -// Adapt the Win32 System Calls (which return BOOLEAN values of TRUE -// and FALSE) into int values expected by the ACE_OSCALL macros. -# define ACE_ADAPT_RETVAL(OP,RESULT) ((RESULT = (OP)) == FALSE ? -1 : 0) - -// Perform a mapping of Win32 error numbers into POSIX errnos. -# define ACE_FAIL_RETURN(RESULT) do { \ - switch (ACE_OS::set_errno_to_last_error ()) { \ - case ERROR_NOT_ENOUGH_MEMORY: errno = ENOMEM; break; \ - case ERROR_FILE_EXISTS: errno = EEXIST; break; \ - case ERROR_SHARING_VIOLATION: errno = EACCES; break; \ - case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; \ - } \ - return RESULT; } while (0) - -#endif /* !ACE_WIN32 */ +#elif defined (ACE_VXWORKS) +# define ACE_ADAPT_RETVAL(OP,RESULT) ((RESULT = (OP)) != OK ? (ACE_OS::last_error(RESULT), -1) : 0) +#else +# define ACE_ADAPT_RETVAL(OP,RESULT) ((RESULT = (OP)) != 0 ? (ACE_OS::last_error(RESULT), -1) : 0) +#endif /* ACE_WIN32 */ // Helper functions to split large intergers into smaller high-order // and low-order parts, and reconstitute them again. These are diff --git a/ACE/ace/config-win32-msvc-10.h b/ACE/ace/config-win32-msvc-10.h index 62dcdae8dd336..743d288404784 100644 --- a/ACE/ace/config-win32-msvc-10.h +++ b/ACE/ace/config-win32-msvc-10.h @@ -134,13 +134,12 @@ // explicitly instantiate a template that has ACE_UNIMPLEMENTED_FUNC. # define ACE_NEEDS_FUNC_DEFINITIONS -// Windows Vista and Windows Server 2008 and newer do have native condition -// variables, but this is commented out because the support in ACE hasn't -// been completed -// #if defined (_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) -// # define ACE_HAS_WTHREADS_CONDITION_VARIABLE -// # undef ACE_LACKS_COND_T -// #endif +// Windows Vista and Windows Server 2008 (same value 0x0600) and newer do +// have native condition variables. +#if defined (_WIN32_WINNT) && (_WIN32_WINNT >= _WIN32_WINNT_VISTA) +# define ACE_HAS_WTHREADS_CONDITION_VARIABLE 1 +# undef ACE_LACKS_COND_T +#endif #include /**/ "ace/post.h" #endif /* ACE_CONFIG_WIN32_MSVC_10_H */ diff --git a/ACE/ace/config-win32.h b/ACE/ace/config-win32.h index 3217c2b78945e..7dde7d9b71a28 100644 --- a/ACE/ace/config-win32.h +++ b/ACE/ace/config-win32.h @@ -20,6 +20,11 @@ // NOTE: Please do not add anything besides #include's here. Put other stuff // (definitions, etc.) in the included headers +// To enable proper version checking we should include the Window SDK version header +// This must be included before ace/config-win32-common.h or else we'll default to +// Windows XP +#include + // We need to ensure that for Borland vcl.h can be included before // windows.h. So we will not include config-win32-common.h from here, // but instead let it be included at the appropriate place in diff --git a/ACE/tests/Condition_Variable_Timeout_Test.cpp b/ACE/tests/Condition_Variable_Timeout_Test.cpp new file mode 100644 index 0000000000000..ebace0f55ba67 --- /dev/null +++ b/ACE/tests/Condition_Variable_Timeout_Test.cpp @@ -0,0 +1,46 @@ +//============================================================================= +/** + * @file Condition_Variable_Timeout_Test.cpp + * + * This program tests the return value and setting of errno when a wait on + * a condition variable times out. This was originally noteworthy in the + * case of support for using native condition variables on Microsoft + * Windows. The test checks that errno is correctly mutated to ensure + * return and errno values are consistent across implementations when using + * ACE_Condition. + * + * @author Michael Mathers + */ +//============================================================================= + +#include "test_config.h" +#include "ace/Condition_T.h" +#include "ace/Guard_T.h" + +int +run_main(int, ACE_TCHAR *[]) +{ + ACE_START_TEST(ACE_TEXT("Condition_Variable_Timeout_Test")); + + ACE_SYNCH_MUTEX mutex; + ACE_Condition cond(mutex); + ACE_Time_Value timeout(1, 0); + bool condition = false; // Condition we are waiting on - will never changed (never intentionally signalled) + int result = 0; + + // Place the wait within a loop such that we don't just pass on account of a spurious wakeup + while (!condition && !(result == -1)) + { + ACE_GUARD_REACTION(ACE_SYNCH_MUTEX, guard, mutex, break); // Failure to acquire the mutex will leave result = 0 (will fail the assertion) + result = cond.wait(&timeout); + } + + // We should've timed out waiting for the condition variable to be signalled + // Expected behavior is to return -1 and have errno set to ETIME + // Note that native Windows condition variable will set errno to ERROR_TIMEOUT instead (mutation required) + ACE_TEST_ASSERT(result == -1); + ACE_TEST_ASSERT(ACE_OS::last_error() == ETIME); + + ACE_END_TEST; + return 0; +} diff --git a/ACE/tests/run_test.lst b/ACE/tests/run_test.lst index 0f4f88de61fbc..c4be79fa43dee 100644 --- a/ACE/tests/run_test.lst +++ b/ACE/tests/run_test.lst @@ -109,6 +109,7 @@ Compiler_Features_35_Test Compiler_Features_36_Test Compiler_Features_37_Test Compiler_Features_38_Test +Condition_Variable_Timeout_Test Config_Test: !LynxOS !VxWorks !ACE_FOR_TAO Conn_Test: !ACE_FOR_TAO DLL_Test: !STATIC Linux diff --git a/ACE/tests/tests.mpc b/ACE/tests/tests.mpc index 04e1c9e8949b4..a20c8485d236c 100644 --- a/ACE/tests/tests.mpc +++ b/ACE/tests/tests.mpc @@ -2284,3 +2284,10 @@ project(Missing_Svc_Conf_Test) : acetest { Missing_Svc_Conf_Test.cpp } } + +project(Condition_Variable_Timeout_Test) : acetest { + exename = * + Source_Files { + Condition_Variable_Timeout_Test.cpp + } +}