// $Id$ #include "ace/OS.h" #include "ace/Sched_Params.h" #include "ace/OS_Thread_Adapter.h" #if !defined (ACE_HAS_WINCE) #include "ace/OS_QoS.h" #endif // ACE_HAS_WINCE // Perhaps we should *always* include ace/OS.i in order to make sure // we can always link against the OS symbols? #if !defined (ACE_HAS_INLINED_OSCALLS) # include "ace/OS.i" #endif /* ACE_HAS_INLINED_OS_CALLS */ ACE_RCSID(ace, OS, "$Id$") #if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) # if defined (ACE_HAS_WINCE) const wchar_t *ACE_OS::day_of_week_name[] = {ACE_LIB_TEXT ("Sun"), ACE_LIB_TEXT ("Mon"), ACE_LIB_TEXT ("Tue"), ACE_LIB_TEXT ("Wed"), ACE_LIB_TEXT ("Thu"), ACE_LIB_TEXT ("Fri"), ACE_LIB_TEXT ("Sat")}; const wchar_t *ACE_OS::month_name[] = {ACE_LIB_TEXT ("Jan"), ACE_LIB_TEXT ("Feb"), ACE_LIB_TEXT ("Mar"), ACE_LIB_TEXT ("Apr"), ACE_LIB_TEXT ("May"), ACE_LIB_TEXT ("Jun"), ACE_LIB_TEXT ("Jul"), ACE_LIB_TEXT ("Aug"), ACE_LIB_TEXT ("Sep"), ACE_LIB_TEXT ("Oct"), ACE_LIB_TEXT ("Nov"), ACE_LIB_TEXT ("Dec") }; static const ACE_TCHAR *ACE_OS_CTIME_R_FMTSTR = ACE_LIB_TEXT ("%3s %3s %02d %02d:%02d:%02d %04d\n"); # endif /* ACE_HAS_WINCE */ # if defined (ACE_WIN32) OSVERSIONINFO ACE_OS::win32_versioninfo_; // Cached win32 version information. HINSTANCE ACE_OS::win32_resource_module_; # if defined (ACE_OS_HAS_DLL) && (ACE_OS_HAS_DLL == 1) && !defined (ACE_HAS_WINCE) // This function is called by the OS when the ACE DLL is loaded. We // use it to determine the default module containing ACE's resources. BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID) { if (reason == DLL_PROCESS_ATTACH) { #if defined (ACE_DISABLES_THREAD_LIBRARY_CALLS) && (ACE_DISABLES_THREAD_LIBRARY_CALLS == 1) ::DisableThreadLibraryCalls (instance); #endif /* ACE_DISABLES_THREAD_LIBRARY_CALLS */ ACE_OS::set_win32_resource_module(instance); } return TRUE; } # endif /* ACE_OS_HAS_DLL && ACE_OS_HAS_DLL == 1 */ # endif /* ACE_WIN32 */ /** * @class ACE_OS_Thread_Mutex_Guard * * This data structure is meant to be used within an ACE_OS * function. It performs automatic aquisition and release of * an ACE_thread_mutex_t. * * For internal use only by ACE_OS. */ class ACE_OS_Thread_Mutex_Guard { public: /// Implicitly and automatically acquire the lock. ACE_OS_Thread_Mutex_Guard (ACE_thread_mutex_t &m); /// Implicitly release the lock. ~ACE_OS_Thread_Mutex_Guard (void); /// Explicitly acquire the lock. int acquire (void); /// Explicitly release the lock. int release (void); protected: /// Reference to the mutex. ACE_thread_mutex_t &lock_; /// Keeps track of whether we acquired the lock or failed. int owner_; // = Prevent assignment and initialization. ACE_OS_Thread_Mutex_Guard &operator= (const ACE_OS_Thread_Mutex_Guard &); ACE_OS_Thread_Mutex_Guard (const ACE_OS_Thread_Mutex_Guard &); }; #if defined (ACE_IS_SPLITTING) # define ACE_SPECIAL_INLINE #else # define ACE_SPECIAL_INLINE inline #endif ACE_SPECIAL_INLINE int ACE_OS_Thread_Mutex_Guard::acquire (void) { return owner_ = ACE_OS::thread_mutex_lock (&lock_); } ACE_SPECIAL_INLINE int ACE_OS_Thread_Mutex_Guard::release (void) { if (owner_ == -1) return 0; else { owner_ = -1; return ACE_OS::thread_mutex_unlock (&lock_); } } ACE_SPECIAL_INLINE ACE_OS_Thread_Mutex_Guard::ACE_OS_Thread_Mutex_Guard (ACE_thread_mutex_t &m) : lock_ (m) { acquire (); } ACE_OS_Thread_Mutex_Guard::~ACE_OS_Thread_Mutex_Guard () { release (); } /** * @class ACE_OS_Recursive_Thread_Mutex_Guard * * @brief For internal use only by ACE_OS. * * This data structure is meant to be used within an ACE_OS * function. It performs automatic aquisition and release of * an ACE_recursive_thread_mutex_t. */ class ACE_OS_Recursive_Thread_Mutex_Guard { public: /// Implicitly and automatically acquire the lock. ACE_OS_Recursive_Thread_Mutex_Guard (ACE_recursive_thread_mutex_t &m); /// Implicitly release the lock. ~ACE_OS_Recursive_Thread_Mutex_Guard (void); /// Explicitly acquire the lock. int acquire (void); /// Explicitly release the lock. int release (void); protected: /// Reference to the mutex. ACE_recursive_thread_mutex_t &lock_; /// Keeps track of whether we acquired the lock or failed. int owner_; // = Prevent assignment and initialization. ACE_OS_Recursive_Thread_Mutex_Guard &operator= ( const ACE_OS_Recursive_Thread_Mutex_Guard &); ACE_OS_Recursive_Thread_Mutex_Guard ( const ACE_OS_Recursive_Thread_Mutex_Guard &); }; ACE_SPECIAL_INLINE int ACE_OS_Recursive_Thread_Mutex_Guard::acquire (void) { return owner_ = ACE_OS::recursive_mutex_lock (&lock_); } ACE_SPECIAL_INLINE int ACE_OS_Recursive_Thread_Mutex_Guard::release (void) { if (owner_ == -1) return 0; else { owner_ = -1; return ACE_OS::recursive_mutex_unlock (&lock_); } } ACE_SPECIAL_INLINE ACE_OS_Recursive_Thread_Mutex_Guard::ACE_OS_Recursive_Thread_Mutex_Guard ( ACE_recursive_thread_mutex_t &m) : lock_ (m), owner_ (-1) { acquire (); } ACE_OS_Recursive_Thread_Mutex_Guard::~ACE_OS_Recursive_Thread_Mutex_Guard () { release (); } #define ACE_OS_GUARD \ ACE_OS_Thread_Mutex_Guard ace_os_guard__ (*(ACE_thread_mutex_t *) \ ACE_OS_Object_Manager::preallocated_object[ \ ACE_OS_Object_Manager::ACE_OS_MONITOR_LOCK]); #define ACE_TSS_CLEANUP_GUARD \ ACE_OS_Recursive_Thread_Mutex_Guard ace_tss_cleanup_guard__ (*(ACE_recursive_thread_mutex_t *) \ ACE_OS_Object_Manager::preallocated_object[ \ ACE_OS_Object_Manager::ACE_TSS_CLEANUP_LOCK]); #define ACE_TSS_BASE_GUARD \ ACE_OS_Recursive_Thread_Mutex_Guard ace_tss_base_guard__ (*(ACE_recursive_thread_mutex_t *) \ ACE_OS_Object_Manager::preallocated_object[ \ ACE_OS_Object_Manager::ACE_TSS_BASE_LOCK]); # if defined (ACE_LACKS_NETDB_REENTRANT_FUNCTIONS) int ACE_OS::netdb_acquire (void) { return ACE_OS::thread_mutex_lock ((ACE_thread_mutex_t *) ACE_OS_Object_Manager::preallocated_object[ ACE_OS_Object_Manager::ACE_OS_MONITOR_LOCK]); } int ACE_OS::netdb_release (void) { return ACE_OS::thread_mutex_unlock ((ACE_thread_mutex_t *) ACE_OS_Object_Manager::preallocated_object[ ACE_OS_Object_Manager::ACE_OS_MONITOR_LOCK]); } # endif /* defined (ACE_LACKS_NETDB_REENTRANT_FUNCTIONS) */ #else /* ! ACE_MT_SAFE */ # define ACE_OS_GUARD # define ACE_TSS_CLEANUP_GUARD # define ACE_TSS_BASE_GUARD #endif /* ! ACE_MT_SAFE */ ACE_EXIT_HOOK ACE_OS::exit_hook_ = 0; ACE_Cleanup_Info::ACE_Cleanup_Info (void) : object_ (0), cleanup_hook_ (0), param_ (0) { } int ACE_Cleanup_Info::operator== (const ACE_Cleanup_Info &o) const { return o.object_ == this->object_ && o.cleanup_hook_ == this->cleanup_hook_ && o.param_ == this->param_; } int ACE_Cleanup_Info::operator!= (const ACE_Cleanup_Info &o) const { return !(*this == o); } /** * @class ACE_Cleanup_Info_Node * * @brief For maintaining a list of ACE_Cleanup_Info items. * * For internal use by ACE_Object_Manager. */ class ACE_Cleanup_Info_Node { public: ACE_Cleanup_Info_Node (void); ACE_Cleanup_Info_Node (const ACE_Cleanup_Info &new_info, ACE_Cleanup_Info_Node *next); ~ACE_Cleanup_Info_Node (void); ACE_Cleanup_Info_Node *insert (const ACE_Cleanup_Info &); private: ACE_Cleanup_Info cleanup_info_; ACE_Cleanup_Info_Node *next_; friend class ACE_OS_Exit_Info; }; ACE_Cleanup_Info_Node::ACE_Cleanup_Info_Node (void) : cleanup_info_ (), next_ (0) { } ACE_Cleanup_Info_Node::ACE_Cleanup_Info_Node (const ACE_Cleanup_Info &new_info, ACE_Cleanup_Info_Node *next) : cleanup_info_ (new_info), next_ (next) { } ACE_Cleanup_Info_Node::~ACE_Cleanup_Info_Node (void) { delete next_; } ACE_Cleanup_Info_Node * ACE_Cleanup_Info_Node::insert (const ACE_Cleanup_Info &new_info) { ACE_Cleanup_Info_Node *new_node; ACE_NEW_RETURN (new_node, ACE_Cleanup_Info_Node (new_info, this), 0); return new_node; } ACE_OS_Exit_Info::ACE_OS_Exit_Info (void) { ACE_NEW (registered_objects_, ACE_Cleanup_Info_Node); } ACE_OS_Exit_Info::~ACE_OS_Exit_Info (void) { delete registered_objects_; registered_objects_ = 0; } int ACE_OS_Exit_Info::at_exit_i (void *object, ACE_CLEANUP_FUNC cleanup_hook, void *param) { ACE_Cleanup_Info new_info; new_info.object_ = object; new_info.cleanup_hook_ = cleanup_hook; new_info.param_ = param; // Return -1 and sets errno if unable to allocate storage. Enqueue // at the head and dequeue from the head to get LIFO ordering. ACE_Cleanup_Info_Node *new_node; if ((new_node = registered_objects_->insert (new_info)) == 0) return -1; else { registered_objects_ = new_node; return 0; } } int ACE_OS_Exit_Info::find (void *object) { // Check for already in queue, and return 1 if so. for (ACE_Cleanup_Info_Node *iter = registered_objects_; iter && iter->next_ != 0; iter = iter->next_) { if (iter->cleanup_info_.object_ == object) { // The object has already been registered. return 1; } } return 0; } void ACE_OS_Exit_Info::call_hooks () { // Call all registered cleanup hooks, in reverse order of // registration. for (ACE_Cleanup_Info_Node *iter = registered_objects_; iter && iter->next_ != 0; iter = iter->next_) { ACE_Cleanup_Info &info = iter->cleanup_info_; if (info.cleanup_hook_ == ACE_reinterpret_cast (ACE_CLEANUP_FUNC, ace_cleanup_destroyer)) // The object is an ACE_Cleanup. ace_cleanup_destroyer (ACE_reinterpret_cast (ACE_Cleanup *, info.object_), info.param_); else if (info.object_ == &ace_exit_hook_marker) // The hook is an ACE_EXIT_HOOK. (* ACE_reinterpret_cast (ACE_EXIT_HOOK, info.cleanup_hook_)) (); else (*info.cleanup_hook_) (info.object_, info.param_); } } ACE_Countdown_Time::ACE_Countdown_Time (ACE_Time_Value *max_wait_time) : max_wait_time_ (max_wait_time), stopped_ (0) { this->start (); } ACE_Countdown_Time::~ACE_Countdown_Time (void) { this->stop (); } #if defined (ACE_HAS_POWERPC_TIMER) && defined (ghs) void ACE_OS::readPPCTimeBase (u_long &most, u_long &least) { ACE_OS_TRACE ("ACE_OS::readPPCTimeBase"); // This function can't be inline because it depends on the arguments // being in particular registers (r3 and r4), in conformance with the // EABI standard. It would be nice if we knew how to put the variable // names directly into the assembler instructions . . . asm("aclock:"); asm("mftb r5,TBU"); asm("mftb r6,TBL"); asm("mftb r7,TBU"); asm("cmpw r5,r7"); asm("bne aclock"); asm("stw r5, 0(r3)"); asm("stw r6, 0(r4)"); } #elif defined (ACE_HAS_POWERPC_TIMER) && defined (__GNUG__) void ACE_OS::readPPCTimeBase (u_long &most, u_long &least) { ACE_OS_TRACE ("ACE_OS::readPPCTimeBase"); // This function can't be inline because it defines a symbol, // aclock. If there are multiple calls to the function in a // compilation unit, then that symbol would be multiply defined if // the function was inline. asm volatile ("aclock:\n" "mftbu 5\n" /* upper time base register */ "mftb 6\n" /* lower time base register */ "mftbu 7\n" /* upper time base register */ "cmpw 5,7\n" /* check for rollover of upper */ "bne aclock\n" "stw 5,%0\n" /* most */ "stw 6,%1" /* least */ : "=m" (most), "=m" (least) /* outputs */ : /* no inputs */ : "5", "6", "7", "memory" /* constraints */); } #endif /* ACE_HAS_POWERPC_TIMER && (ghs or __GNUG__) */ #if defined (ACE_WIN32) || defined (VXWORKS) || defined (CHORUS) || defined (ACE_PSOS) // Don't inline on those platforms because this function contains // string literals, and some compilers, e.g., g++, don't handle those // efficiently in unused inline functions. int ACE_OS::uname (ACE_utsname *name) { ACE_OS_TRACE ("ACE_OS::uname"); # if defined (ACE_WIN32) size_t maxnamelen = sizeof name->nodename; ACE_OS::strcpy (name->sysname, ACE_LIB_TEXT ("Win32")); OSVERSIONINFO vinfo; vinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); ::GetVersionEx (&vinfo); SYSTEM_INFO sinfo; # if defined (ACE_HAS_PHARLAP) // PharLap doesn't do GetSystemInfo. What's really wanted is the // CPU architecture, so we can get that with EtsGetSystemInfo. Fill // in what's wanted in the SYSTEM_INFO structure, and carry on. Note // that the CPU type values in EK_KERNELINFO have the same values // are the ones defined for SYSTEM_INFO. EK_KERNELINFO ets_kern; EK_SYSTEMINFO ets_sys; EtsGetSystemInfo (&ets_kern, &ets_sys); sinfo.wProcessorLevel = ACE_static_cast (WORD, ets_kern.CpuType); sinfo.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL; sinfo.dwProcessorType = ets_kern.CpuType * 100 + 86; # else ::GetSystemInfo(&sinfo); ACE_OS::strcpy (name->sysname, ACE_LIB_TEXT ("Win32")); # endif /* ACE_HAS_PHARLAP */ const ACE_TCHAR* unknown = ACE_LIB_TEXT ("???"); if (vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { // Get information from the two structures ACE_OS::sprintf (name->release, # if defined (ACE_HAS_WINCE) ACE_LIB_TEXT ("Windows CE %d.%d"), # else ACE_LIB_TEXT ("Windows NT %d.%d"), # endif /* ACE_HAS_WINCE */ (int) vinfo.dwMajorVersion, (int) vinfo.dwMinorVersion); ACE_OS::sprintf (name->version, ACE_LIB_TEXT ("Build %d %s"), (int) vinfo.dwBuildNumber, vinfo.szCSDVersion); // We have to make sure that the size of (processor + subtype) // is not greater than the size of name->machine. So we give // half the space to the processor and half the space to // subtype. The -1 is necessary for because of the space // between processor and subtype in the machine name. const int bufsize = ((sizeof (name->machine) / sizeof (ACE_TCHAR)) / 2) - 1; ACE_TCHAR processor[bufsize] = ACE_LIB_TEXT ("Unknown"); ACE_TCHAR subtype[bufsize] = ACE_LIB_TEXT ("Unknown"); # if defined (ghs) WORD arch = sinfo.u.s.wProcessorArchitecture; # else WORD arch = sinfo.wProcessorArchitecture; # endif switch (arch) { case PROCESSOR_ARCHITECTURE_INTEL: ACE_OS::strcpy (processor, ACE_LIB_TEXT ("Intel")); if (sinfo.wProcessorLevel == 3) ACE_OS::strcpy (subtype, ACE_LIB_TEXT ("80386")); else if (sinfo.wProcessorLevel == 4) ACE_OS::strcpy (subtype, ACE_LIB_TEXT ("80486")); else if (sinfo.wProcessorLevel == 5) ACE_OS::strcpy (subtype, ACE_LIB_TEXT ("Pentium")); else if (sinfo.wProcessorLevel == 6) ACE_OS::strcpy (subtype, ACE_LIB_TEXT ("Pentium Pro")); else if (sinfo.wProcessorLevel == 7) // I'm guessing here ACE_OS::strcpy (subtype, ACE_LIB_TEXT ("Pentium II")); break; case PROCESSOR_ARCHITECTURE_MIPS: ACE_OS::strcpy (processor, ACE_LIB_TEXT ("MIPS")); ACE_OS::strcpy (subtype, ACE_LIB_TEXT ("R4000")); break; case PROCESSOR_ARCHITECTURE_ALPHA: ACE_OS::strcpy (processor, ACE_LIB_TEXT ("Alpha")); ACE_OS::sprintf (subtype, ACE_LIB_TEXT ("%d"), sinfo.wProcessorLevel); break; case PROCESSOR_ARCHITECTURE_PPC: ACE_OS::strcpy (processor, ACE_LIB_TEXT ("PPC")); if (sinfo.wProcessorLevel == 1) ACE_OS::strcpy (subtype, ACE_LIB_TEXT ("601")); else if (sinfo.wProcessorLevel == 3) ACE_OS::strcpy (subtype, ACE_LIB_TEXT ("603")); else if (sinfo.wProcessorLevel == 4) ACE_OS::strcpy (subtype, ACE_LIB_TEXT ("604")); else if (sinfo.wProcessorLevel == 6) ACE_OS::strcpy (subtype, ACE_LIB_TEXT ("603+")); else if (sinfo.wProcessorLevel == 9) ACE_OS::strcpy (subtype, ACE_LIB_TEXT ("804+")); else if (sinfo.wProcessorLevel == 20) ACE_OS::strcpy (subtype, ACE_LIB_TEXT ("620")); break; # if defined PROCESSOR_ARCHITECTURE_IA64 case PROCESSOR_ARCHITECTURE_IA64: ACE_OS_String::strcpy (processor, ACE_LIB_TEXT ("Itanium")); ACE_OS::sprintf (subtype, ACE_LIB_TEXT ("%d"), sinfo.wProcessorLevel); break; # endif case PROCESSOR_ARCHITECTURE_UNKNOWN: default: // @@ We could provide WinCE specific info here. But let's // defer that to some later point. ACE_OS::strcpy (processor, ACE_LIB_TEXT ("Unknown")); break; } ACE_OS::sprintf (name->machine, ACE_LIB_TEXT ("%s %s"), processor, subtype); } else if (vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { if (vinfo.dwMajorVersion == 4 && vinfo.dwMinorVersion == 0) { ACE_OS::strcpy (name->release, ACE_LIB_TEXT ("Windows 95")); if (vinfo.szCSDVersion[1] == 'C') ACE_OS::strcat (name->release, ACE_LIB_TEXT (" OSR2")); } else if (vinfo.dwMajorVersion == 4 && vinfo.dwMinorVersion == 10) { ACE_OS::strcpy (name->release, ACE_LIB_TEXT ("Windows 98")); if (vinfo.szCSDVersion[1] == 'A') ACE_OS::strcat (name->release, ACE_LIB_TEXT (" SE")); } else if (vinfo.dwMajorVersion == 4 && vinfo.dwMinorVersion == 90) { ACE_OS::strcpy (name->release, ACE_LIB_TEXT ("Windows Me")); } else { ACE_OS::strcpy (name->release, unknown); } ACE_OS::sprintf (name->version, ACE_LIB_TEXT ("%d"), LOWORD (vinfo.dwBuildNumber)); if (sinfo.dwProcessorType == PROCESSOR_INTEL_386) ACE_OS::strcpy (name->machine, ACE_LIB_TEXT ("Intel 80386")); else if (sinfo.dwProcessorType == PROCESSOR_INTEL_486) ACE_OS::strcpy (name->machine, ACE_LIB_TEXT ("Intel 80486")); else if (sinfo.dwProcessorType == PROCESSOR_INTEL_PENTIUM) ACE_OS::strcpy (name->machine, ACE_LIB_TEXT ("Intel Pentium")); else ACE_OS::strcpy (name->machine, unknown); } else { // We don't know what this is! ACE_OS::strcpy (name->release, unknown); ACE_OS::strcpy (name->version, unknown); ACE_OS::strcpy (name->machine, unknown); } # if defined (ACE_LACKS_HOSTNAME) return 0; # else /* ACE_LACKS_HOSTNAME */ return ACE_OS::hostname (name->nodename, maxnamelen); # endif /* ACE_LACKS_HOSTNAME */ # elif defined (VXWORKS) size_t maxnamelen = sizeof name->nodename; ACE_OS::strcpy (name->sysname, "VxWorks"); ACE_OS::strcpy (name->release, "???"); ACE_OS::strcpy (name->version, sysBspRev ()); ACE_OS::strcpy (name->machine, sysModel ()); return ACE_OS::hostname (name->nodename, maxnamelen); # elif defined (CHORUS) size_t maxnamelen = sizeof name->nodename; ACE_OS::strcpy (name->sysname, "CHORUS/ClassiX"); ACE_OS::strcpy (name->release, "???"); ACE_OS::strcpy (name->version, "???"); ACE_OS::strcpy (name->machine, "???"); return ACE_OS::hostname (name->nodename, maxnamelen); #elif defined (ACE_PSOS) const unsigned long buflen(64); char buf[buflen]; unsigned long len; sys_info(PSOS_VERSION,(void *)buf,buflen,&len); ACE_OS::strcpy (name->sysname, "pSOS"); ACE_OS::strcpy (name->release, "???"); ACE_OS::strcpy (name->version, buf); ACE_OS::strcpy (name->machine, "PPC 405"); // a bit of a hack #endif /* ACE_WIN32 */ } #endif /* ACE_WIN32 || VXWORKS */ #if defined (VXWORKS) struct hostent * ACE_OS::gethostbyname (const char *name) { ACE_OS_TRACE ("ACE_OS::gethostbyname"); // not thread safe! static hostent ret; static int first_addr; static char *hostaddr[2]; static char *aliases[1]; ACE_OSCALL (::hostGetByName ((char *) name), int, -1, first_addr); if (first_addr == -1) return 0; hostaddr[0] = (char *) &first_addr; hostaddr[1] = 0; aliases[0] = 0; // Might not be official: just echo input arg. ret.h_name = (char *) name; ret.h_addrtype = AF_INET; ret.h_length = 4; // VxWorks 5.2/3 doesn't define IP_ADDR_LEN; ret.h_addr_list = hostaddr; ret.h_aliases = aliases; return &ret; } struct hostent * ACE_OS::gethostbyaddr (const char *addr, int length, int type) { ACE_OS_TRACE ("ACE_OS::gethostbyaddr"); if (length != 4 || type != AF_INET) { errno = EINVAL; return 0; } // not thread safe! static hostent ret; static char name [MAXNAMELEN + 1]; static char *hostaddr[2]; static char *aliases[1]; if (::hostGetByAddr (*(int *) addr, name) != 0) { // errno will have been set to S_hostLib_UNKNOWN_HOST. return 0; } // Might not be official: just echo input arg. hostaddr[0] = (char *) addr; hostaddr[1] = 0; aliases[0] = 0; ret.h_name = name; ret.h_addrtype = AF_INET; ret.h_length = 4; // VxWorks 5.2/3 doesn't define IP_ADDR_LEN; ret.h_addr_list = hostaddr; ret.h_aliases = aliases; return &ret; } struct hostent * ACE_OS::gethostbyaddr_r (const char *addr, int length, int type, hostent *result, ACE_HOSTENT_DATA buffer, int *h_errnop) { ACE_OS_TRACE ("ACE_OS::gethostbyaddr_r"); if (length != 4 || type != AF_INET) { errno = EINVAL; return 0; } if (ACE_OS::netdb_acquire ()) return 0; else { // buffer layout: // buffer[0-3]: h_addr_list[0], the first (and only) addr. // buffer[4-7]: h_addr_list[1], the null terminator for the h_addr_list. // buffer[8]: the name of the host, null terminated. // Call ::hostGetByAddr (), which puts the (one) hostname into // buffer. if (::hostGetByAddr (*(int *) addr, &buffer[8]) == 0) { // Store the return values in result. result->h_name = &buffer[8]; // null-terminated host name result->h_addrtype = AF_INET; result->h_length = 4; // VxWorks 5.2/3 doesn't define IP_ADDR_LEN. result->h_addr_list = (char **) buffer; // Might not be official: just echo input arg. result->h_addr_list[0] = (char *) addr; // Null-terminate the list of addresses. result->h_addr_list[1] = 0; // And no aliases, so null-terminate h_aliases. result->h_aliases = &result->h_addr_list[1]; } else { // errno will have been set to S_hostLib_UNKNOWN_HOST. result = 0; } } ACE_OS::netdb_release (); *h_errnop = errno; return result; } struct hostent * ACE_OS::gethostbyname_r (const char *name, hostent *result, ACE_HOSTENT_DATA buffer, int *h_errnop) { ACE_OS_TRACE ("ACE_OS::gethostbyname_r"); if (ACE_OS::netdb_acquire ()) return 0; else { int addr; ACE_OSCALL (::hostGetByName ((char *) name), int, -1, addr); if (addr == -1) { // errno will have been set to S_hostLib_UNKNOWN_HOST result = 0; } else { // Might not be official: just echo input arg. result->h_name = (char *) name; result->h_addrtype = AF_INET; result->h_length = 4; // VxWorks 5.2/3 doesn't define IP_ADDR_LEN; // buffer layout: // buffer[0-3]: h_addr_list[0], pointer to the addr. // buffer[4-7]: h_addr_list[1], null terminator for the h_addr_list. // buffer[8-11]: the first (and only) addr. // Store the address list in buffer. result->h_addr_list = (char **) buffer; // Store the actual address _after_ the address list. result->h_addr_list[0] = (char *) &result->h_addr_list[2]; result->h_addr_list[2] = (char *) addr; // Null-terminate the list of addresses. result->h_addr_list[1] = 0; // And no aliases, so null-terminate h_aliases. result->h_aliases = &result->h_addr_list[1]; } } ACE_OS::netdb_release (); *h_errnop = errno; return result; } #endif /* VXWORKS */ void ACE_OS::ace_flock_t::dump (void) const { ACE_OS_TRACE ("ACE_OS::ace_flock_t::dump"); #if 0 ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("handle_ = %u"), this->handle_)); #if defined (ACE_WIN32) ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nInternal = %d"), this->overlapped_.Internal)); ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nInternalHigh = %d"), this->overlapped_.InternalHigh)); ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nOffsetHigh = %d"), this->overlapped_.OffsetHigh)); ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nhEvent = %d"), this->overlapped_.hEvent)); #elif !defined (CHORUS) ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nl_whence = %d"), this->lock_.l_whence)); ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nl_start = %d"), this->lock_.l_start)); ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nl_len = %d"), this->lock_.l_len)); ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nl_type = %d"), this->lock_.l_type)); #endif /* ACE_WIN32 */ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); #endif /* 0 */ } void ACE_OS::mutex_lock_cleanup (void *mutex) { ACE_OS_TRACE ("ACE_OS::mutex_lock_cleanup"); #if defined (ACE_HAS_THREADS) # if defined (ACE_HAS_PTHREADS) ACE_mutex_t *p_lock = (ACE_mutex_t *) mutex; ACE_OS::mutex_unlock (p_lock); # else ACE_UNUSED_ARG (mutex); # endif /* ACE_HAS_PTHREADS */ # else ACE_UNUSED_ARG (mutex); # endif /* ACE_HAS_THREADS */ } #if defined (ACE_USES_WCHAR) void ACE_OS::checkUnicodeFormat (FILE* fp) { if (fp != 0) { // Due to the ACE_TCHAR definition, all default input files, such as // svc.conf, have to be in Unicode format (small endian) on WinCE // because ACE has all 'char' converted into ACE_TCHAR. // However, for TAO, ASCII files, such as IOR file, can still be read and // be written without any error since given buffers are all in 'char' type // instead of ACE_TCHAR. Therefore, it is user's reponsibility to select // correct buffer type. // At this point, check if the file is Unicode or not. WORD first_two_bytes; int numRead = ACE_OS::fread(&first_two_bytes, sizeof(WORD), 1, fp); if (numRead == 1) { if ((first_two_bytes != 0xFFFE) && // not a small endian Unicode file (first_two_bytes != 0xFEFF)) // not a big endian Unicode file { ACE_OS::fseek(fp, 0, FILE_BEGIN); // set file pointer back to the beginning } } // if it is a Unicode file, file pointer will be right next to the first two-bytes } } #endif // ACE_USES_WCHAR #if defined (ACE_WIN32) FILE * ACE_OS::fopen (const ACE_TCHAR *filename, const ACE_TCHAR *mode) { ACE_OS_TRACE ("ACE_OS::fopen"); int hmode = _O_TEXT; for (const ACE_TCHAR *mode_ptr = mode; *mode_ptr != 0; mode_ptr++) ACE_OS::fopen_mode_to_open_mode_converter (*mode_ptr, hmode); ACE_HANDLE handle = ACE_OS::open (filename, hmode); if (handle != ACE_INVALID_HANDLE) { # if defined (ACE_HAS_WINCE) FILE *fp = ::_wfdopen (handle, mode); if (fp != 0) { checkUnicodeFormat(fp); return fp; } # else hmode &= _O_TEXT | _O_RDONLY | _O_APPEND; # if defined (ACE_WIN64) int fd = _open_osfhandle (intptr_t (handle), hmode); # else int fd = _open_osfhandle (long (handle), hmode); # endif /* ACE_WIN64 */ if (fd != -1) { # if defined (__BORLANDC__) && !defined (ACE_USES_WCHAR) FILE *fp = ::_fdopen (fd, ACE_const_cast (char *, mode)); # elif defined (__BORLANDC__) && defined (ACE_USES_WCHAR) FILE *fp = ::_wfdopen (fd, ACE_const_cast (wchar_t *, mode)); # elif defined (ACE_USES_WCHAR) FILE *fp = ::_wfdopen (fd, mode); # else FILE *fp = ::fdopen (fd, mode); # endif /* defined(__BORLANDC__) && !defined (ACE_USES_WCHAR)) */ if (fp != 0) { # if defined (ACE_USES_WCHAR) checkUnicodeFormat(fp); # endif // ACE_USES_WCHAR return fp; } _close (fd); } # endif // ACE_HAS_WINCE ACE_OS::close (handle); } return 0; } #endif /* ACE_WIN32 */ // The following *printf functions aren't inline because // they use varargs. int ACE_OS::fprintf (FILE *fp, const char *format, ...) { ACE_OS_TRACE ("ACE_OS::fprintf"); int result = 0; va_list ap; va_start (ap, format); ACE_OSCALL (::vfprintf (fp, format, ap), int, -1, result); va_end (ap); return result; } #if defined (ACE_HAS_WCHAR) int ACE_OS::fprintf (FILE *fp, const wchar_t *format, ...) { ACE_OS_TRACE ("ACE_OS::fprintf"); # if !defined (ACE_HAS_VFWPRINTF) ACE_UNUSED_ARG (fp); ACE_UNUSED_ARG (format); ACE_NOTSUP_RETURN (-1); # else int result = 0; va_list ap; va_start (ap, format); ACE_OSCALL (::vfwprintf (fp, format, ap), int, -1, result); va_end (ap); return result; # endif /* ACE_HAS_VFWPRINTF */ } #endif /* ACE_HAS_WCHAR */ int ACE_OS::printf (const char *format, ...) { ACE_OS_TRACE ("ACE_OS::printf"); int result; va_list ap; va_start (ap, format); ACE_OSCALL (::vprintf (format, ap), int, -1, result); va_end (ap); return result; } int ACE_OS::sprintf (char *buf, const char *format, ...) { // ACE_OS_TRACE ("ACE_OS::sprintf"); int result; va_list ap; va_start (ap, format); ACE_OSCALL (ACE_SPRINTF_ADAPTER (::vsprintf (buf, format, ap)), int, -1, result); va_end (ap); return result; } #if defined (ACE_HAS_WCHAR) int ACE_OS::sprintf (wchar_t *buf, const wchar_t *format, ...) { ACE_OS_TRACE ("ACE_OS::sprintf"); # if defined (_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500) // The XPG4/UNIX98/C99 signature of the wide-char sprintf has a // maxlen argument. Since this method doesn't supply one, pass in // the max possible length. If this isn't ok, use ACE_OS::snprintf(). int result; va_list ap; va_start (ap, format); ACE_OSCALL (::vswprintf (buf, ULONG_MAX, format, ap), int, -1, result); va_end (ap); return result; # elif defined (ACE_WIN32) // Windows has vswprintf, but the signature is from the older ISO C // standard. Also see ACE_OS::snprintf() for more info on this. int result; va_list ap; va_start (ap, format); ACE_OSCALL (::vswprintf (buf, format, ap), int, -1, result); va_end (ap); return result; # else ACE_UNUSED_ARG (buf); ACE_UNUSED_ARG (format); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_VSWPRINTF */ } #endif /* ACE_HAS_WCHAR */ int ACE_OS::snprintf (char *buf, size_t maxlen, const char *format, ...) { // ACE_OS_TRACE ("ACE_OS::snprintf"); #if defined (ACE_HAS_SNPRINTF) int result; va_list ap; va_start (ap, format); # if defined (ACE_WIN32) ACE_OSCALL (ACE_SPRINTF_ADAPTER (::_vsnprintf (buf, maxlen, format, ap)), int, -1, result); // Win32 doesn't 0-terminate the string if it overruns maxlen. if (result == -1) buf[maxlen-1] = '\0'; # else ACE_OSCALL (ACE_SPRINTF_ADAPTER (::vsnprintf (buf, maxlen, format, ap)), int, -1, result); # endif /* ACE_WIN32 */ va_end (ap); // In out-of-range conditions, C99 defines vsnprintf to return the number // of characters that would have been written if enough space was available. // Earlier variants of the vsnprintf() (e.g. UNIX98) defined it to return // -1. This method follows the C99 standard, but needs to guess at the // value; uses maxlen + 1. if (result == -1) result = ACE_static_cast (int, (maxlen + 1)); return result; #else ACE_UNUSED_ARG (buf); ACE_UNUSED_ARG (maxlen); ACE_UNUSED_ARG (format); ACE_NOTSUP_RETURN (-1); #endif /* ACE_HAS_SNPRINTF */ } #if defined (ACE_HAS_WCHAR) int ACE_OS::snprintf (wchar_t *buf, size_t maxlen, const wchar_t *format, ...) { // ACE_OS_TRACE ("ACE_OS::snprintf"); #if (defined (_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) || defined (ACE_WIN32) int result; va_list ap; va_start (ap, format); # if defined (ACE_WIN32) // Microsoft's vswprintf() doesn't have the maxlen argument that // XPG4/UNIX98 define. They do, however, recommend use of _vsnwprintf() // as a substitute, which does have the same signature as the UNIX98 one. ACE_OSCALL (ACE_SPRINTF_ADAPTER (::_vsnwprintf (buf, maxlen, format, ap)), int, -1, result); // Win32 doesn't 0-terminate the string if it overruns maxlen. if (result == -1) buf[maxlen-1] = '\0'; # else ACE_OSCALL (ACE_SPRINTF_ADAPTER (::vswprintf (buf, maxlen, format, ap)), int, -1, result); # endif /* ACE_WIN32 */ va_end (ap); // In out-of-range conditions, C99 defines vsnprintf to return the number // of characters that would have been written if enough space was available. // Earlier variants of the vsnprintf() (e.g. UNIX98) defined it to return // -1. This method follows the C99 standard, but needs to guess at the // value; uses maxlen + 1. if (result == -1) result = ACE_static_cast (int, (maxlen + 1)); return result; #else ACE_UNUSED_ARG (buf); ACE_UNUSED_ARG (maxlen); ACE_UNUSED_ARG (format); ACE_NOTSUP_RETURN (-1); #endif /* ACE_HAS_SNPRINTF */ } #endif /* ACE_HAS_WCHAR */ char * ACE_OS::gets (char *str, int n) { ACE_OS_TRACE ("ACE_OS::gets"); int c; char *s = str; if (str == 0 || n < 0) n = 0; if (n == 0) str = 0; else n--; while ((c = getchar ()) != '\n') { if (c == EOF && errno == EINTR) { # if defined (ACE_HAS_SIGNAL_SAFE_OS_CALLS) continue; # else break; # endif /* ACE_HAS_SIGNAL_SAFE_OS_CALLS */ } if (c == EOF) break; if (n > 0) n--, *s++ = c; } if (s) *s = '\0'; return (c == EOF) ? 0 : str; } int ACE_OS::execl (const char * /* path */, const char * /* arg0 */, ...) { ACE_OS_TRACE ("ACE_OS::execl"); #if defined (ACE_WIN32) || defined (VXWORKS) ACE_NOTSUP_RETURN (-1); #else ACE_NOTSUP_RETURN (-1); // Need to write this code. // ACE_OSCALL_RETURN (::execv (path, argv), int, -1); #endif /* ACE_WIN32 */ } int ACE_OS::execle (const char * /* path */, const char * /* arg0 */, ...) { ACE_OS_TRACE ("ACE_OS::execle"); #if defined (ACE_WIN32) || defined (VXWORKS) ACE_NOTSUP_RETURN (-1); #else ACE_NOTSUP_RETURN (-1); // Need to write this code. // ACE_OSCALL_RETURN (::execve (path, argv, envp), int, -1); #endif /* ACE_WIN32 */ } int ACE_OS::execlp (const char * /* file */, const char * /* arg0 */, ...) { ACE_OS_TRACE ("ACE_OS::execlp"); #if defined (ACE_WIN32) || defined (VXWORKS) ACE_NOTSUP_RETURN (-1); #else ACE_NOTSUP_RETURN (-1); // Need to write this code. // ACE_OSCALL_RETURN (::execvp (file, argv), int, -1); #endif /* ACE_WIN32 */ } int ACE_OS::scheduling_class (const char *class_name, ACE_id_t &id) { #if defined (ACE_HAS_PRIOCNTL) // Get the priority class ID. pcinfo_t pcinfo; // The following is just to avoid Purify warnings about unitialized // memory reads. ACE_OS::memset (&pcinfo, 0, sizeof pcinfo); ACE_OS::strcpy (pcinfo.pc_clname, class_name); if (ACE_OS::priority_control (P_ALL /* ignored */, P_MYID /* ignored */, PC_GETCID, (char *) &pcinfo) == -1) { return -1; } else { id = pcinfo.pc_cid; return 0; } #else /* ! ACE_HAS_PRIOCNTL */ ACE_UNUSED_ARG (class_name); ACE_UNUSED_ARG (id); ACE_NOTSUP_RETURN (-1); #endif /* ! ACE_HAS_PRIOCNTL */ } int ACE_OS::set_scheduling_params (const ACE_Sched_Params &sched_params, ACE_id_t id) { #if defined (ACE_HAS_PRIOCNTL) // Set priority class, priority, and quantum of this LWP or process as // specified in sched_params. // Get the priority class ID. ACE_id_t class_id; if (ACE_OS::scheduling_class (sched_params.policy() == ACE_SCHED_OTHER ? "TS" : "RT", class_id) == -1) { return -1; } pcparms_t pcparms; // The following is just to avoid Purify warnings about unitialized // memory reads. ACE_OS::memset (&pcparms, 0, sizeof pcparms); pcparms.pc_cid = class_id; if (sched_params.policy () == ACE_SCHED_OTHER && sched_params.quantum () == ACE_Time_Value::zero) // SunOS doesn't support non-zero quantums in time-sharing class: use // real-time class instead. { tsparms_t tsparms; // The following is just to avoid Purify warnings about unitialized // memory reads. ACE_OS::memset (&tsparms, 0, sizeof tsparms); // Don't change ts_uprilim (user priority limit) tsparms.ts_uprilim = TS_NOCHANGE; tsparms.ts_upri = sched_params.priority (); // Package up the TS class ID and parameters for the // priority_control () call. ACE_OS::memcpy (pcparms.pc_clparms, &tsparms, sizeof tsparms); } else if (sched_params.policy () == ACE_SCHED_FIFO || (sched_params.policy () == ACE_SCHED_RR && sched_params.quantum () != ACE_Time_Value::zero)) // must have non-zero quantum for RR, to make it meaningful // A zero quantum with FIFO has special significance: it actually // means infinite time quantum, i.e., run-to-completion. { rtparms_t rtparms; // The following is just to avoid Purify warnings about unitialized // memory reads. ACE_OS::memset (&rtparms, 0, sizeof rtparms); rtparms.rt_pri = sched_params.priority (); if (sched_params.quantum () == ACE_Time_Value::zero) { // rtparms.rt_tqsecs is ignored with RT_TQINF rtparms.rt_tqnsecs = RT_TQINF; } else { rtparms.rt_tqsecs = (ulong) sched_params.quantum ().sec (); rtparms.rt_tqnsecs = sched_params.quantum ().usec () * 1000; } // Package up the RT class ID and parameters for the // priority_control () call. ACE_OS::memcpy (pcparms.pc_clparms, &rtparms, sizeof rtparms); } else { errno = EINVAL; return -1; } if (ACE_OS::priority_control ((idtype_t) (sched_params.scope () == ACE_SCOPE_THREAD ? ACE_SCOPE_PROCESS : sched_params.scope ()), id, PC_SETPARMS, (char *) &pcparms) < 0) { return ACE_OS::last_error (); } return 0; #else /* ! ACE_HAS_PRIOCNTL */ ACE_UNUSED_ARG (sched_params); ACE_UNUSED_ARG (id); ACE_NOTSUP_RETURN (-1); #endif /* ! ACE_HAS_PRIOCNTL */ } int ACE_OS::thr_setprio (const ACE_Sched_Priority prio) { // Set the thread priority on the current thread. ACE_hthread_t my_thread_id; ACE_OS::thr_self (my_thread_id); int status = ACE_OS::thr_setprio (my_thread_id, prio); # if defined (ACE_NEEDS_LWP_PRIO_SET) // If the thread is in the RT class, then set the priority on its // LWP. (Instead of doing this if the thread is in the RT class, it // should be done for all bound threads. But, there doesn't appear // to be an easy way to determine if the thread is bound.) if (status == 0) { // Find what scheduling class the thread's LWP is in. ACE_Sched_Params sched_params (ACE_SCHED_OTHER, 0); if (ACE_OS::lwp_getparams (sched_params) == -1) { return -1; } else if (sched_params.policy () == ACE_SCHED_FIFO || sched_params.policy () == ACE_SCHED_RR) { // This thread's LWP is in the RT class, so we need to set // its priority. sched_params.priority (prio); return ACE_OS::lwp_setparams (sched_params); } // else this is not an RT thread. Nothing more needs to be // done. } # endif /* ACE_NEEDS_LWP_PRIO_SET */ return status; } int ACE_OS::sched_params (const ACE_Sched_Params &sched_params, ACE_id_t id) { ACE_OS_TRACE ("ACE_OS::sched_params"); # if defined (CHORUS) ACE_UNUSED_ARG (id); int result; struct sched_param param; ACE_thread_t thr_id = ACE_OS::thr_self (); param.sched_priority = sched_params.priority (); ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::pthread_setschedparam (thr_id, sched_params.policy (), ¶m), result), int, -1); # elif defined (ACE_HAS_STHREADS) return ACE_OS::set_scheduling_params (sched_params, id); # elif defined (ACE_HAS_PTHREADS) && !defined (ACE_LACKS_SETSCHED) ACE_UNUSED_ARG (id); if (sched_params.quantum () != ACE_Time_Value::zero) { // quantums not supported errno = EINVAL; return -1; } // Thanks to Thilo Kielmann for // providing this code for 1003.1c PThreads. Please note that this // has only been tested for POSIX 1003.1c threads, and may cause // problems with other PThreads flavors! struct sched_param param; param.sched_priority = sched_params.priority (); if (sched_params.scope () == ACE_SCOPE_PROCESS) { int result = ::sched_setscheduler (0, // this process sched_params.policy (), ¶m) == -1 ? -1 : 0; # if defined (DIGITAL_UNIX) return result == 0 ? // Use priocntl (2) to set the process in the RT class, // if using an RT policy. ACE_OS::set_scheduling_params (sched_params) : result; # else /* ! DIGITAL_UNIX */ return result; # endif /* ! DIGITAL_UNIX */ } else if (sched_params.scope () == ACE_SCOPE_THREAD) { ACE_thread_t thr_id = ACE_OS::thr_self (); # if defined (ACE_HAS_PTHREADS_DRAFT4) return (::pthread_setscheduler (thr_id, sched_params.policy (), sched_params.priority()) == -1 ? -1 : 0); # else int result; ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::pthread_setschedparam (thr_id, sched_params.policy (), ¶m), result), int, -1); # endif /* ACE_HAS_PTHREADS_DRAFT4 */ } # if defined (sun) // We need to be able to set LWP priorities on Suns, even without // ACE_HAS_STHREADS, to obtain preemption. else if (sched_params.scope () == ACE_SCOPE_LWP) return ACE_OS::set_scheduling_params (sched_params, id); # endif /* sun */ else // sched_params.scope () == ACE_SCOPE_LWP, which isn't POSIX { errno = EINVAL; return -1; } # elif defined (ACE_WIN32) && !defined (ACE_HAS_WINCE) // PharLap ETS can act on the current thread - it can set the // quantum also, unlike Win32. All this only works on the RT // version. # if defined (ACE_HAS_PHARLAP_RT) if (id != ACE_SELF) ACE_NOTSUP_RETURN (-1); if (sched_params.quantum() != ACE_Time_Value::zero) EtsSetTimeSlice (sched_params.quantum().msec()); # else ACE_UNUSED_ARG (id); if (sched_params.scope () != ACE_SCOPE_PROCESS || sched_params.quantum () != ACE_Time_Value::zero) { // Win32 only allows setting priority class (therefore, policy) // at the process level. I don't know of a way to set the // quantum. errno = EINVAL; return -1; } // Set the priority class of this process to the REALTIME process class // _if_ the policy is ACE_SCHED_FIFO. Otherwise, set to NORMAL. if (!::SetPriorityClass (::GetCurrentProcess (), sched_params.policy () == ACE_SCHED_FIFO ? REALTIME_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS)) { ACE_OS::set_errno_to_last_error (); return -1; } # endif /* ACE_HAS_PHARLAP_RT */ // Set the thread priority on the current thread. return ACE_OS::thr_setprio (sched_params.priority ()); # elif defined (VXWORKS) || defined (ACE_PSOS) ACE_UNUSED_ARG (id); // There is only one class of priorities on VxWorks, and no time // quanta. So, just set the current thread's priority. if (sched_params.policy () != ACE_SCHED_FIFO || sched_params.scope () != ACE_SCOPE_PROCESS || sched_params.quantum () != ACE_Time_Value::zero) { errno = EINVAL; return -1; } // Set the thread priority on the current thread. return ACE_OS::thr_setprio (sched_params.priority ()); # else ACE_UNUSED_ARG (sched_params); ACE_UNUSED_ARG (id); ACE_NOTSUP_RETURN (-1); # endif /* CHORUS */ } // = Static initialization. // This is necessary to deal with POSIX pthreads insanity. This // guarantees that we've got a "zero'd" thread id even when // ACE_thread_t, ACE_hthread_t, and ACE_thread_key_t are implemented // as structures... Under no circumstances should these be given // initial values. // Note: these three objects require static construction. ACE_thread_t ACE_OS::NULL_thread; ACE_hthread_t ACE_OS::NULL_hthread; #if defined (ACE_HAS_TSS_EMULATION) || (defined (ACE_PSOS) && defined (ACE_PSOS_HAS_TSS)) ACE_thread_key_t ACE_OS::NULL_key = ACE_static_cast (ACE_thread_key_t, -1); #else /* ! ACE_HAS_TSS_EMULATION */ ACE_thread_key_t ACE_OS::NULL_key; #endif /* ! ACE_HAS_TSS_EMULATION */ #if defined (CHORUS) KnCap ACE_OS::actorcaps_[ACE_CHORUS_MAX_ACTORS]; // This is used to map an actor's id into a KnCap for killing and // waiting actors. #endif /* CHORUS */ #if defined (ACE_WIN32) // = Static initialization. // Keeps track of whether we've initialized the WinSock DLL. int ACE_OS::socket_initialized_; #endif /* WIN32 */ #if defined (ACE_WIN32) || defined (ACE_HAS_TSS_EMULATION) || (defined (ACE_PSOS) && defined (ACE_PSOS_HAS_TSS)) // Moved class ACE_TSS_Ref declaration to OS.h so it can be visible to // the single file of template instantiations. ACE_TSS_Ref::ACE_TSS_Ref (ACE_thread_t id) : tid_(id) { ACE_OS_TRACE ("ACE_TSS_Ref::ACE_TSS_Ref"); } ACE_TSS_Ref::ACE_TSS_Ref (void) { ACE_OS_TRACE ("ACE_TSS_Ref::ACE_TSS_Ref"); } // Check for equality. int ACE_TSS_Ref::operator== (const ACE_TSS_Ref &info) const { ACE_OS_TRACE ("ACE_TSS_Ref::operator=="); return this->tid_ == info.tid_; } // Check for inequality. ACE_SPECIAL_INLINE int ACE_TSS_Ref::operator != (const ACE_TSS_Ref &tss_ref) const { ACE_OS_TRACE ("ACE_TSS_Ref::operator !="); return !(*this == tss_ref); } // moved class ACE_TSS_Info declaration // to OS.h so it can be visible to the // single file of template instantiations ACE_TSS_Info::ACE_TSS_Info (ACE_thread_key_t key, void (*dest)(void *), void *tss_inst) : key_ (key), destructor_ (dest), tss_obj_ (tss_inst), thread_count_ (-1) { ACE_OS_TRACE ("ACE_TSS_Info::ACE_TSS_Info"); } ACE_TSS_Info::ACE_TSS_Info (void) : key_ (ACE_OS::NULL_key), destructor_ (0), tss_obj_ (0), thread_count_ (-1) { ACE_OS_TRACE ("ACE_TSS_Info::ACE_TSS_Info"); } # if defined (ACE_HAS_NONSCALAR_THREAD_KEY_T) static inline int operator== (const ACE_thread_key_t &lhs, const ACE_thread_key_t &rhs) { return ! ACE_OS::memcmp (&lhs, &rhs, sizeof (ACE_thread_key_t)); } static inline int operator!= (const ACE_thread_key_t &lhs, const ACE_thread_key_t &rhs) { return ! (lhs == rhs); } # endif /* ACE_HAS_NONSCALAR_THREAD_KEY_T */ // Check for equality. int ACE_TSS_Info::operator== (const ACE_TSS_Info &info) const { ACE_OS_TRACE ("ACE_TSS_Info::operator=="); return this->key_ == info.key_; } // Check for inequality. int ACE_TSS_Info::operator != (const ACE_TSS_Info &info) const { ACE_OS_TRACE ("ACE_TSS_Info::operator !="); return !(*this == info); } void ACE_TSS_Info::dump (void) { // ACE_OS_TRACE ("ACE_TSS_Info::dump"); #if 0 ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("key_ = %u\n"), this->key_)); ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("destructor_ = %u\n"), this->destructor_)); ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("tss_obj_ = %u\n"), this->tss_obj_)); ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); #endif /* 0 */ } // Moved class ACE_TSS_Keys declaration to OS.h so it can be visible // to the single file of template instantiations. ACE_TSS_Keys::ACE_TSS_Keys (void) { for (u_int i = 0; i < ACE_WORDS; ++i) { key_bit_words_[i] = 0; } } ACE_SPECIAL_INLINE void ACE_TSS_Keys::find (const u_int key, u_int &word, u_int &bit) { word = key / ACE_BITS_PER_WORD; bit = key % ACE_BITS_PER_WORD; } int ACE_TSS_Keys::test_and_set (const ACE_thread_key_t key) { ACE_KEY_INDEX (key_index, key); u_int word, bit; find (key_index, word, bit); if (ACE_BIT_ENABLED (key_bit_words_[word], 1 << bit)) { return 1; } else { ACE_SET_BITS (key_bit_words_[word], 1 << bit); return 0; } } int ACE_TSS_Keys::test_and_clear (const ACE_thread_key_t key) { ACE_KEY_INDEX (key_index, key); u_int word, bit; find (key_index, word, bit); if (ACE_BIT_ENABLED (key_bit_words_[word], 1 << bit)) { ACE_CLR_BITS (key_bit_words_[word], 1 << bit); return 0; } else { return 1; } } int ACE_TSS_Keys::is_set (const ACE_thread_key_t key) const { ACE_KEY_INDEX (key_index, key); u_int word, bit; find (key_index, word, bit); return ACE_BIT_ENABLED (key_bit_words_[word], 1 << bit); } /** * @class ACE_TSS_Cleanup * * @brief Singleton that knows how to clean up all the thread-specific * resources for Win32. * * All this nonsense is required since Win32 doesn't * automatically cleanup thread-specific storage on thread exit, * unlike real operating systems... ;-) */ class ACE_TSS_Cleanup { public: static ACE_TSS_Cleanup *instance (void); ~ACE_TSS_Cleanup (void); /// Cleanup the thread-specific objects. Does _NOT_ exit the thread. void exit (void *status); /// Insert a tuple into the table. int insert (ACE_thread_key_t key, void (*destructor)(void *), void *inst); /// Remove a tuple from the table. int remove (ACE_thread_key_t key); /// Detaches a tss_instance from its key. int detach (void *inst); /// Mark a key as being used by this thread. void key_used (ACE_thread_key_t key); /// Free all keys left in the table before destruction. int free_all_keys_left (void); /// Indication of whether the ACE_TSS_CLEANUP_LOCK is usable, and /// therefore whether we are in static constructor/destructor phase /// or not. static int lockable () { return instance_ != 0; } protected: void dump (void); /// Ensure singleton. ACE_TSS_Cleanup (void); private: // Array of objects. typedef ACE_TSS_Info ACE_TSS_TABLE[ACE_DEFAULT_THREAD_KEYS]; typedef ACE_TSS_Info *ACE_TSS_TABLE_ITERATOR; /// Table of 's. ACE_TSS_TABLE table_; /// Key for the thread-specific array of whether each TSS key is in use. ACE_thread_key_t in_use_; /// Accessor for this threads ACE_TSS_Keys instance. ACE_TSS_Keys *tss_keys (); #if defined (ACE_HAS_TSS_EMULATION) /// Key that is used by in_use_. We save this key so that we know /// not to call its destructor in free_all_keys_left (). ACE_thread_key_t in_use_key_; #endif /* ACE_HAS_TSS_EMULATION */ // = Static data. /// Pointer to the singleton instance. static ACE_TSS_Cleanup *instance_; }; // = Static object initialization. // Pointer to the singleton instance. ACE_TSS_Cleanup *ACE_TSS_Cleanup::instance_ = 0; ACE_TSS_Cleanup::~ACE_TSS_Cleanup (void) { // Zero out the instance pointer to support lockable () accessor. ACE_TSS_Cleanup::instance_ = 0; } void ACE_TSS_Cleanup::exit (void * /* status */) { ACE_OS_TRACE ("ACE_TSS_Cleanup::exit"); ACE_TSS_TABLE_ITERATOR key_info = table_; ACE_TSS_Info info_arr[ACE_DEFAULT_THREAD_KEYS]; int info_ix = 0; // While holding the lock, we only collect the ACE_TSS_Info objects // in an array without invoking the according destructors. { ACE_TSS_CLEANUP_GUARD // Iterate through all the thread-specific items and free them all // up. for (unsigned int i = 0; i < ACE_DEFAULT_THREAD_KEYS; ++key_info, ++i) { if (key_info->key_ == ACE_OS::NULL_key || ! key_info->key_in_use ()) continue; // If the key's ACE_TSS_Info in-use bit for this thread was set, // unset it and decrement the key's thread_count_. if (! tss_keys ()->test_and_clear (key_info->key_)) { --key_info->thread_count_; } void *tss_info = 0; if (key_info->destructor_ && ACE_OS::thr_getspecific (key_info->key_, &tss_info) == 0 && tss_info) { info_arr[info_ix].key_ = key_info->key_; info_arr[info_ix].destructor_ = key_info->destructor_; info_arr[info_ix++].tss_obj_ = key_info->tss_obj_; } } } // Now we have given up the ACE_TSS_Cleanup::lock_ and we start // invoking destructors, in the reverse order of creation. for (int i = info_ix - 1; i >= 0; --i) { void *tss_info = 0; ACE_OS::thr_getspecific (info_arr[i].key_, &tss_info); if (tss_info != 0) { // Only call the destructor if the value is non-zero for this // thread. (*info_arr[i].destructor_)(tss_info); } } // Acquire the ACE_TSS_CLEANUP_LOCK, then free TLS keys and remove // entries from ACE_TSS_Info table. { ACE_TSS_CLEANUP_GUARD # if 0 // We shouldn't free the key and remove it from the table here // because if we do and some thread ends before other threads // even get started (or their TSS object haven't been created yet,) // it's entry will be removed from the table and we are in big chaos. // For TSS object, these have been done in ACE_TSS_Cleanup::detach. // Two other use cases will be user managed TSS'es and system wide // TSS, ones are users responsibilities and the others should be // persistant system wide. for (int i = 0; i < index; i++) { # if defined (ACE_WIN32) || (defined (ACE_PSOS) && defined (ACE_PSOS_HAS_TSS)) // Calling thr_keyfree here ensure the key // gets removed appropriately. Notice that // a key should be removed before freeing it. ACE_OS::thr_keyfree (key_info->key_); # else // don't bother to free the key this->remove (key_info->key_); # endif /* ACE_WIN32 */ } # endif /* 0 */ } } int ACE_TSS_Cleanup::free_all_keys_left (void) // This is called from ACE_OS::cleanup_tss (). When this gets // called, all threads should have exited except the main thread. // No key should be freed from this routine. It there's any, // something might be wrong. { ACE_thread_key_t key_arr[ACE_DEFAULT_THREAD_KEYS]; ACE_TSS_TABLE_ITERATOR key_info = table_; unsigned int idx = 0; unsigned int i; for (i = 0; i < ACE_DEFAULT_THREAD_KEYS; ++key_info, ++i) #if defined (ACE_HAS_TSS_EMULATION) if (key_info->key_ != in_use_key_) #endif /* ACE_HAS_TSS_EMULATION */ // Don't call ACE_OS::thr_keyfree () on ACE_TSS_Cleanup's own // key. See the comments in ACE_OS::thr_key_detach (): the key // doesn't get detached, so it will be in the table here. // However, there's no resource associated with it, so we don't // need to keyfree it. The dynamic memory associated with it // was already deleted by ACE_TSS_Cleanup::exit (), so we don't // want to access it again. key_arr [idx++] = key_info->key_; for (i = 0; i < idx; i++) if (key_arr[i] != ACE_OS::NULL_key) #if defined (ACE_HAS_TSS_EMULATION) ACE_OS::thr_keyfree (key_arr[i]); #elif defined (ACE_PSOS) && defined (ACE_PSOS_HAS_TSS) // Don't call ACE_OS::thr_keyfree here. It will try to use // which has already been cleaned up here. ::tsd_delete (key_arr[i]); #else /* ACE_WIN32 */ // Don't call ACE_OS::thr_keyfree here. It will try to use // which has already been cleaned up here. TlsFree (key_arr[i]); #endif /* ACE_HAS_TSS_EMULATION */ return 0; } extern "C" void ACE_TSS_Cleanup_keys_destroyer (void *tss_keys) { delete ACE_reinterpret_cast (ACE_TSS_Keys *, tss_keys); } ACE_TSS_Cleanup::ACE_TSS_Cleanup (void) : in_use_ (ACE_OS::NULL_key) #if defined (ACE_HAS_TSS_EMULATION) // ACE_TSS_Emulation::total_keys () provides the value of the next // key to be created. , in_use_key_ (ACE_TSS_Emulation::total_keys ()) #endif /* ACE_HAS_TSS_EMULATION */ { ACE_OS_TRACE ("ACE_TSS_Cleanup::ACE_TSS_Cleanup"); } ACE_TSS_Cleanup * ACE_TSS_Cleanup::instance (void) { ACE_OS_TRACE ("ACE_TSS_Cleanup::instance"); // Create and initialize thread-specific key. if (ACE_TSS_Cleanup::instance_ == 0) { // Insure that we are serialized! ACE_TSS_CLEANUP_GUARD // Now, use the Double-Checked Locking pattern to make sure we // only create the ACE_TSS_Cleanup instance once. if (ACE_TSS_Cleanup::instance_ == 0) ACE_NEW_RETURN (ACE_TSS_Cleanup::instance_, ACE_TSS_Cleanup, 0); } return ACE_TSS_Cleanup::instance_; } int ACE_TSS_Cleanup::insert (ACE_thread_key_t key, void (*destructor)(void *), void *inst) { ACE_OS_TRACE ("ACE_TSS_Cleanup::insert"); ACE_TSS_CLEANUP_GUARD ACE_KEY_INDEX (key_index, key); if (key_index < ACE_DEFAULT_THREAD_KEYS) { table_[key_index] = ACE_TSS_Info (key, destructor, inst); return 0; } else { return -1; } } int ACE_TSS_Cleanup::remove (ACE_thread_key_t key) { ACE_OS_TRACE ("ACE_TSS_Cleanup::remove"); ACE_TSS_CLEANUP_GUARD ACE_KEY_INDEX (key_index, key); if (key_index < ACE_DEFAULT_THREAD_KEYS) { // "Remove" the TSS_Info table entry by zeroing out its key_ and // destructor_ fields. Also, keep track of the number threads // using the key. ACE_TSS_Info &info = this->table_ [key_index]; // Don't bother to test/clear the in "use bit" if the program is // shutting down. Doing so will cause a new ACE_TSS object to be // created again. if (!ACE_OS_Object_Manager::shutting_down ()) tss_keys ()->test_and_clear (info.key_); info.key_in_use (0); info.key_ = ACE_OS::NULL_key; info.destructor_ = 0; return 0; } else return -1; } int ACE_TSS_Cleanup::detach (void *inst) { ACE_TSS_CLEANUP_GUARD ACE_TSS_TABLE_ITERATOR key_info = table_; int success = 0; int ref_cnt = 0; // Mark the key as detached in the TSS_Info table. // It only works for the first key that "inst" owns. // I don't know why. for (unsigned int i = 0; i < ACE_DEFAULT_THREAD_KEYS; ++key_info, ++i) { if (key_info->tss_obj_ == inst) { key_info->tss_obj_ = 0; ref_cnt = --key_info->thread_count_; success = 1; break; } } if (success == 0) return -1; else if (ref_cnt == 0) { // Mark the key as no longer being used. key_info->key_in_use (0); # if defined (ACE_WIN32) || (defined (ACE_PSOS) && defined (ACE_PSOS_HAS_TSS)) ACE_thread_key_t temp_key = key_info->key_; # endif /* ACE_WIN32 */ int retv = this->remove (key_info->key_); # if defined (ACE_WIN32) ::TlsFree (temp_key); # elif defined (ACE_PSOS) && defined (ACE_PSOS_HAS_TSS) ::tsd_delete (temp_key); # endif /* ACE_WIN32 */ return retv; } return 0; } void ACE_TSS_Cleanup::key_used (ACE_thread_key_t key) { // If the key's ACE_TSS_Info in-use bit for this thread is not set, // set it and increment the key's thread_count_. if (! tss_keys ()->test_and_set (key)) { ACE_TSS_CLEANUP_GUARD // Retrieve the key's ACE_TSS_Info and increment its thread_count_. ACE_KEY_INDEX (key_index, key); ACE_TSS_Info &key_info = this->table_ [key_index]; if (!key_info.key_in_use ()) key_info.key_in_use (1); else ++key_info.thread_count_; } } void ACE_TSS_Cleanup::dump (void) { // Iterate through all the thread-specific items and dump them all. ACE_TSS_TABLE_ITERATOR key_info = table_; for (unsigned int i = 0; i < ACE_DEFAULT_THREAD_KEYS; ++key_info, ++i) key_info->dump (); } ACE_TSS_Keys * ACE_TSS_Cleanup::tss_keys () { if (in_use_ == ACE_OS::NULL_key) { ACE_TSS_CLEANUP_GUARD // Double-check; if (in_use_ == ACE_OS::NULL_key) { // Initialize in_use_ with a new key. if (ACE_OS::thr_keycreate (&in_use_, &ACE_TSS_Cleanup_keys_destroyer)) return 0; // Major problems, this should *never* happen! } } ACE_TSS_Keys *ts_keys = 0; if (ACE_OS::thr_getspecific (in_use_, ACE_reinterpret_cast (void **, &ts_keys)) == -1) return 0; // This should not happen! if (ts_keys == 0) { ACE_NEW_RETURN (ts_keys, ACE_TSS_Keys, 0); // Store the dynamically allocated pointer in thread-specific // storage. if (ACE_OS::thr_setspecific (in_use_, ACE_reinterpret_cast (void *, ts_keys)) == -1) { delete ts_keys; return 0; // Major problems, this should *never* happen! } } return ts_keys; } # if defined (ACE_HAS_TSS_EMULATION) u_int ACE_TSS_Emulation::total_keys_ = 0; ACE_TSS_Keys ACE_TSS_Emulation::tss_keys_used_; ACE_TSS_Emulation::ACE_TSS_DESTRUCTOR ACE_TSS_Emulation::tss_destructor_[ACE_TSS_Emulation::ACE_TSS_THREAD_KEYS_MAX] = { 0 }; # if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) int ACE_TSS_Emulation::key_created_ = 0; ACE_OS_thread_key_t ACE_TSS_Emulation::native_tss_key_; /* static */ # if defined (ACE_HAS_THR_C_FUNC) extern "C" void ACE_TSS_Emulation_cleanup (void *ptr) { ACE_UNUSED_ARG (ptr); // Really this must be used for ACE_TSS_Emulation code to make the TSS // cleanup } #else void ACE_TSS_Emulation_cleanup (void *ptr) { ACE_UNUSED_ARG (ptr); // Really this must be used for ACE_TSS_Emulation code to make the TSS // cleanup } # endif /* ACE_HAS_THR_C_FUNC */ void ** ACE_TSS_Emulation::tss_base (void* ts_storage[], u_int *ts_created) { // TSS Singleton implementation. // Create the one native TSS key, if necessary. if (key_created_ == 0) { // Double-checked lock . . . ACE_TSS_BASE_GUARD if (key_created_ == 0) { ACE_NO_HEAP_CHECK; if (ACE_OS::thr_keycreate (&native_tss_key_, &ACE_TSS_Emulation_cleanup) != 0) { return 0; // Major problems, this should *never* happen! } key_created_ = 1; } } void **old_ts_storage = 0; // Get the tss_storage from thread-OS specific storage. if (ACE_OS::thr_getspecific (native_tss_key_, (void **) &old_ts_storage) == -1) return 0; // This should not happen! // Check to see if this is the first time in for this thread. // This block can also be entered after a fork () in the child process, // at least on Pthreads Draft 4 platforms. if (old_ts_storage == 0) { if (ts_created) *ts_created = 1u; // Use the ts_storage passed as argument, if non-zero. It is // possible that this has been implemented in the stack. At the // moment, this is unknown. The cleanup must not do nothing. // If ts_storage is zero, allocate (and eventually leak) the // storage array. if (ts_storage == 0) { ACE_NO_HEAP_CHECK; ACE_NEW_RETURN (ts_storage, void*[ACE_TSS_THREAD_KEYS_MAX], 0); // Zero the entire TSS array. Do it manually instead of // using memset, for optimum speed. Though, memset may be // faster :-) void **tss_base_p = ts_storage; for (u_int i = 0; i < ACE_TSS_THREAD_KEYS_MAX; ++i) *tss_base_p++ = 0; } // Store the pointer in thread-specific storage. It gets // deleted via the ACE_TSS_Emulation_cleanup function when the // thread terminates. if (ACE_OS::thr_setspecific (native_tss_key_, (void *) ts_storage) != 0) return 0; // Major problems, this should *never* happen! } else if (ts_created) ts_created = 0; return ts_storage ? ts_storage : old_ts_storage; } # endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE */ u_int ACE_TSS_Emulation::total_keys () { ACE_OS_Recursive_Thread_Mutex_Guard ( *ACE_static_cast (ACE_recursive_thread_mutex_t *, ACE_OS_Object_Manager::preallocated_object[ ACE_OS_Object_Manager::ACE_TSS_KEY_LOCK])); return total_keys_; } int ACE_TSS_Emulation::next_key (ACE_thread_key_t &key) { ACE_OS_Recursive_Thread_Mutex_Guard ( *ACE_static_cast (ACE_recursive_thread_mutex_t *, ACE_OS_Object_Manager::preallocated_object[ ACE_OS_Object_Manager::ACE_TSS_KEY_LOCK])); if (total_keys_ < ACE_TSS_THREAD_KEYS_MAX) { u_int counter = 0; // Loop through all possible keys and check whether a key is free for ( ;counter < ACE_TSS_THREAD_KEYS_MAX; counter++) { ACE_thread_key_t localkey; # if defined (ACE_HAS_NONSCALAR_THREAD_KEY_T) ACE_OS::memset (&localkey, 0, sizeof (ACE_thread_key_t)); ACE_OS::memcpy (&localkey, &counter_, sizeof (u_int)); # else localkey = counter; # endif /* ACE_HAS_NONSCALAR_THREAD_KEY_T */ // If the key is not set as used, we can give out this key, if not // we have to search further if (tss_keys_used_.is_set(localkey) == 0) { tss_keys_used_.test_and_set(localkey); key = localkey; break; } } ++total_keys_; return 0; } else { key = ACE_OS::NULL_key; return -1; } } int ACE_TSS_Emulation::release_key (ACE_thread_key_t key) { ACE_OS_Recursive_Thread_Mutex_Guard ( *ACE_static_cast (ACE_recursive_thread_mutex_t *, ACE_OS_Object_Manager::preallocated_object[ ACE_OS_Object_Manager::ACE_TSS_KEY_LOCK])); if (tss_keys_used_.test_and_clear (key) == 0) { --total_keys_; return 0; } return 1; } void * ACE_TSS_Emulation::tss_open (void *ts_storage[ACE_TSS_THREAD_KEYS_MAX]) { # if defined (ACE_PSOS) u_long tss_base; // Use the supplied array for this thread's TSS. tss_base = (u_long) ts_storage; t_setreg (0, PSOS_TASK_REG_TSS, tss_base); // Zero the entire TSS array. void **tss_base_p = ts_storage; for (u_int i = 0; i < ACE_TSS_THREAD_KEYS_MAX; ++i, ++tss_base_p) { *tss_base_p = 0; } return (void *) tss_base; # else /* ! ACE_PSOS */ # if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) // On VxWorks, in particular, don't check to see if the field // is 0. It isn't always, specifically, when a program is run // directly by the shell (without spawning a new task) after // another program has been run. u_int ts_created = 0; tss_base (ts_storage, &ts_created); if (ts_created) { # else /* ! ACE_HAS_THREAD_SPECIFIC_STORAGE */ tss_base () = ts_storage; # endif // Zero the entire TSS array. Do it manually instead of using // memset, for optimum speed. Though, memset may be faster :-) void **tss_base_p = tss_base (); for (u_int i = 0; i < ACE_TSS_THREAD_KEYS_MAX; ++i, ++tss_base_p) { *tss_base_p = 0; } return tss_base (); # if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) } else { return 0; } # endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE */ # endif /* ! ACE_PSOS */ } void ACE_TSS_Emulation::tss_close () { #if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) // Free native_tss_key_ here. #endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE */ } # endif /* ACE_HAS_TSS_EMULATION */ #endif /* WIN32 || ACE_HAS_TSS_EMULATION */ void ACE_OS::cleanup_tss (const u_int main_thread) { #if defined (ACE_HAS_TSS_EMULATION) || defined (ACE_WIN32) || (defined (ACE_PSOS) && defined (ACE_PSOS_HAS_TSS)) // Call TSS destructors for current thread. ACE_TSS_Cleanup::instance ()->exit (0); #endif /* ACE_HAS_TSS_EMULATION || ACE_WIN32 || ACE_PSOS_HAS_TSS */ if (main_thread) { #if !defined (ACE_HAS_TSS_EMULATION) && !defined (ACE_HAS_MINIMAL_ACE_OS) // Just close the ACE_Log_Msg for the current (which should be // main) thread. We don't have TSS emulation; if there's native // TSS, it should call its destructors when the main thread // exits. ACE_Base_Thread_Adapter::close_log_msg (); #endif /* ! ACE_HAS_TSS_EMULATION && ! ACE_HAS_MINIMAL_ACE_OS */ #if defined (ACE_WIN32) || defined (ACE_HAS_TSS_EMULATION) || (defined (ACE_PSOS) && defined (ACE_PSOS_HAS_TSS)) #if ! defined (ACE_HAS_TSS_EMULATION) // Don't do this with TSS_Emulation, because the the // ACE_TSS_Cleanup::instance () has already exited (). We can't // safely access the TSS values that were created by the main // thread. // Remove all TSS_Info table entries. ACE_TSS_Cleanup::instance ()->free_all_keys_left (); #endif /* ! ACE_HAS_TSS_EMULATION */ // Finally, free up the ACE_TSS_Cleanup instance. This method gets // called by the ACE_Object_Manager. delete ACE_TSS_Cleanup::instance (); #endif /* WIN32 || ACE_HAS_TSS_EMULATION || ACE_PSOS_HAS_TSS */ #if defined (ACE_HAS_TSS_EMULATION) ACE_TSS_Emulation::tss_close (); #endif /* ACE_HAS_TSS_EMULATION */ } } #if !defined(ACE_WIN32) && defined (__IBMCPP__) && (__IBMCPP__ >= 400) #define ACE_BEGINTHREADEX(STACK, STACKSIZE, ENTRY_POINT, ARGS, FLAGS, THR_ID) \ (*THR_ID = ::_beginthreadex ((void(_Optlink*)(void*))ENTRY_POINT, STACK, STACKSIZE, ARGS), *THR_ID) #elif defined(ACE_WIN32) && defined (__IBMCPP__) && (__IBMCPP__ >= 400) struct __IBMCPP__thread_params { __IBMCPP__thread_params(ACE_THR_C_FUNC e, LPVOID a) :entry_point(e),args(a) {} ACE_THR_C_FUNC entry_point; LPVOID args; }; #pragma handler(initThread) extern "C" DWORD __stdcall __IBMCPP__initThread(void *arg) { // Must reset 387 since using CreateThread _fpreset(); // Dispatch user function... auto_ptr<__IBMCPP__thread_params> parms((__IBMCPP__thread_params *)arg); (*parms->entry_point)(parms->args); _endthread(); return 0; } HANDLE WINAPI __IBMCPP__beginthreadex(void *stack, DWORD stacksize, ACE_THR_C_FUNC entry_point, LPVOID args, DWORD flags, LPDWORD thr_id) { return CreateThread(0, stacksize, (LPTHREAD_START_ROUTINE)__IBMCPP__initThread, new __IBMCPP__thread_params(entry_point, args), flags, thr_id); } #define ACE_BEGINTHREADEX(STACK, STACKSIZE, ENTRY_POINT, ARGS, FLAGS, THR_ID) \ __IBMCPP__beginthreadex(STACK, STACKSIZE, ENTRY_POINT, ARGS, FLAGS, THR_ID) #elif defined (ACE_HAS_WINCE) && defined (UNDER_CE) && (UNDER_CE >= 211) #define ACE_BEGINTHREADEX(STACK, STACKSIZE, ENTRY_POINT, ARGS, FLAGS, THR_ID) \ CreateThread (0, STACKSIZE, (unsigned long (__stdcall *) (void *)) ENTRY_POINT, ARGS, (FLAGS) & CREATE_SUSPENDED, (unsigned long *) THR_ID) #elif defined(ACE_HAS_WTHREADS) // Green Hills compiler gets confused when __stdcall is imbedded in // parameter list, so we define the type ACE_WIN32THRFUNC_T and use it // instead. typedef unsigned (__stdcall *ACE_WIN32THRFUNC_T)(void*); #define ACE_BEGINTHREADEX(STACK, STACKSIZE, ENTRY_POINT, ARGS, FLAGS, THR_ID) \ ::_beginthreadex (STACK, STACKSIZE, (ACE_WIN32THRFUNC_T) ENTRY_POINT, ARGS, FLAGS, (unsigned int *) THR_ID) #endif /* defined (__IBMCPP__) && (__IBMCPP__ >= 400) */ #if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS) int ACE_SEH_Default_Exception_Selector (void *) { #if 0 ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("(%t) Win32 structured exception exiting thread\n"))); #endif /* 0 */ return (DWORD) ACE_SEH_DEFAULT_EXCEPTION_HANDLING_ACTION; } int ACE_SEH_Default_Exception_Handler (void *) { return 0; } #endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */ extern "C" void ace_cleanup_destroyer (ACE_Cleanup *object, void *param) { object->cleanup (param); } int ACE_OS::thr_create (ACE_THR_FUNC func, void *args, long flags, ACE_thread_t *thr_id, ACE_hthread_t *thr_handle, long priority, void *stack, size_t stacksize, ACE_Base_Thread_Adapter *thread_adapter) { ACE_OS_TRACE ("ACE_OS::thr_create"); if (ACE_BIT_DISABLED (flags, THR_DETACHED) && ACE_BIT_DISABLED (flags, THR_JOINABLE)) ACE_SET_BITS (flags, THR_JOINABLE); # if defined (ACE_NO_THREAD_ADAPTER) # define ACE_THREAD_FUNCTION func # define ACE_THREAD_ARGUMENT args # else /* ! defined (ACE_NO_THREAD_ADAPTER) */ # if defined (ACE_PSOS) # define ACE_THREAD_FUNCTION (PSOS_TASK_ENTRY_POINT) thread_args->entry_point () # else # define ACE_THREAD_FUNCTION thread_args->entry_point () # endif /* defined (ACE_PSOS) */ # define ACE_THREAD_ARGUMENT thread_args # endif /* ! defined (ACE_NO_THREAD_ADAPTER) */ ACE_Base_Thread_Adapter *thread_args; if (thread_adapter == 0) # if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS) ACE_NEW_RETURN (thread_args, ACE_OS_Thread_Adapter (func, args, (ACE_THR_C_FUNC) ace_thread_adapter, ACE_OS_Object_Manager::seh_except_selector(), ACE_OS_Object_Manager::seh_except_handler()), -1); # else ACE_NEW_RETURN (thread_args, ACE_OS_Thread_Adapter (func, args, (ACE_THR_C_FUNC) ace_thread_adapter), -1); # endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */ else thread_args = thread_adapter; # if defined (ACE_HAS_THREADS) // *** Set Stack Size # if defined (ACE_NEEDS_HUGE_THREAD_STACKSIZE) if (stacksize < ACE_NEEDS_HUGE_THREAD_STACKSIZE) stacksize = ACE_NEEDS_HUGE_THREAD_STACKSIZE; # endif /* ACE_NEEDS_HUGE_THREAD_STACKSIZE */ # if !defined (VXWORKS) // On VxWorks, the OS will provide a task name if the user doesn't. // So, we don't need to create a tmp_thr. If the caller of this // member function is the Thread_Manager, than thr_id will be non-zero // anyways. ACE_thread_t tmp_thr; if (thr_id == 0) thr_id = &tmp_thr; # endif /* ! VXWORKS */ ACE_hthread_t tmp_handle; if (thr_handle == 0) thr_handle = &tmp_handle; # if defined (ACE_HAS_PTHREADS) int result; pthread_attr_t attr; # if defined (ACE_HAS_PTHREADS_DRAFT4) if (::pthread_attr_create (&attr) != 0) # else /* ACE_HAS_PTHREADS_DRAFT4 */ if (::pthread_attr_init (&attr) != 0) # endif /* ACE_HAS_PTHREADS_DRAFT4 */ return -1; # if defined (CHORUS) // If it is a super actor, we can't set stacksize. But for the time // being we are all non-super actors. Should be fixed to take care // of super actors!!! if (stacksize == 0) stacksize = ACE_CHORUS_DEFAULT_MIN_STACK_SIZE; else if (stacksize < ACE_CHORUS_DEFAULT_MIN_STACK_SIZE) stacksize = ACE_CHORUS_DEFAULT_MIN_STACK_SIZE; # endif /*CHORUS */ # if defined (ACE_HAS_PTHREAD_SETSTACK) if ((stacksize != 0) && (stack != 0)) # else if (stacksize != 0) # endif /* ACE_HAS_PTHREAD_SETSTACK */ { size_t size = stacksize; # if defined (PTHREAD_STACK_MIN) if (size < ACE_static_cast (size_t, PTHREAD_STACK_MIN)) size = PTHREAD_STACK_MIN; # endif /* PTHREAD_STACK_MIN */ # if !defined (ACE_LACKS_THREAD_STACK_SIZE) // JCEJ 12/17/96 # if defined (ACE_HAS_PTHREADS_DRAFT4) || defined (ACE_HAS_PTHREADS_DRAFT6) if (::pthread_attr_setstacksize (&attr, size) != 0) # else # if defined (ACE_HAS_PTHREAD_SETSTACK) if (ACE_ADAPT_RETVAL(pthread_attr_setstack (&attr, stack, size), result) == -1) # else if (ACE_ADAPT_RETVAL(pthread_attr_setstacksize (&attr, size), result) == -1) # endif /* ACE_HAS_PTHREAD_SETSTACK */ # endif /* ACE_HAS_PTHREADS_DRAFT4, 6 */ { # if defined (ACE_HAS_PTHREADS_DRAFT4) ::pthread_attr_delete (&attr); # else /* ACE_HAS_PTHREADS_DRAFT4 */ ::pthread_attr_destroy (&attr); # endif /* ACE_HAS_PTHREADS_DRAFT4 */ return -1; } # else ACE_UNUSED_ARG (size); # endif /* !ACE_LACKS_THREAD_STACK_SIZE */ } // *** Set Stack Address # if !defined (ACE_HAS_PTHREAD_SETSTACK) # if !defined (ACE_LACKS_THREAD_STACK_ADDR) if (stack != 0) { if (::pthread_attr_setstackaddr (&attr, stack) != 0) { # if defined (ACE_HAS_PTHREADS_DRAFT4) ::pthread_attr_delete (&attr); # else /* ACE_HAS_PTHREADS_DRAFT4 */ ::pthread_attr_destroy (&attr); # endif /* ACE_HAS_PTHREADS_DRAFT4 */ return -1; } } # else ACE_UNUSED_ARG (stack); # endif /* !ACE_LACKS_THREAD_STACK_ADDR */ # endif /* ACE_HAS_PTHREAD_SETSTACK */ // *** Deal with various attributes if (flags != 0) { // *** Set Detach state # if !defined (ACE_LACKS_SETDETACH) if (ACE_BIT_ENABLED (flags, THR_DETACHED) || ACE_BIT_ENABLED (flags, THR_JOINABLE)) { int dstate = PTHREAD_CREATE_JOINABLE; if (ACE_BIT_ENABLED (flags, THR_DETACHED)) dstate = PTHREAD_CREATE_DETACHED; # if defined (ACE_HAS_PTHREADS_DRAFT4) if (::pthread_attr_setdetach_np (&attr, dstate) != 0) # else /* ACE_HAS_PTHREADS_DRAFT4 */ # if defined (ACE_HAS_PTHREADS_DRAFT6) if (::pthread_attr_setdetachstate (&attr, &dstate) != 0) # else if (ACE_ADAPT_RETVAL(::pthread_attr_setdetachstate (&attr, dstate), result) != 0) # endif /* ACE_HAS_PTHREADS_DRAFT6 */ # endif /* ACE_HAS_PTHREADS_DRAFT4 */ { # if defined (ACE_HAS_PTHREADS_DRAFT4) ::pthread_attr_delete (&attr); # else /* ACE_HAS_PTHREADS_DRAFT4 */ ::pthread_attr_destroy (&attr); # endif /* ACE_HAS_PTHREADS_DRAFT4 */ return -1; } } // Note: if ACE_LACKS_SETDETACH and THR_DETACHED is enabled, we // call ::pthread_detach () below. If THR_DETACHED is not // enabled, we call ::pthread_detach () in the Thread_Manager, // after joining with the thread. # endif /* ACE_LACKS_SETDETACH */ // *** Set Policy # if !defined (ACE_LACKS_SETSCHED) // If we wish to set the priority explicitly, we have to enable // explicit scheduling, and a policy, too. if (priority != ACE_DEFAULT_THREAD_PRIORITY) { ACE_SET_BITS (flags, THR_EXPLICIT_SCHED); if (ACE_BIT_DISABLED (flags, THR_SCHED_FIFO) && ACE_BIT_DISABLED (flags, THR_SCHED_RR) && ACE_BIT_DISABLED (flags, THR_SCHED_DEFAULT)) ACE_SET_BITS (flags, THR_SCHED_DEFAULT); } if (ACE_BIT_ENABLED (flags, THR_SCHED_FIFO) || ACE_BIT_ENABLED (flags, THR_SCHED_RR) || ACE_BIT_ENABLED (flags, THR_SCHED_DEFAULT)) { int spolicy; # if defined (ACE_HAS_ONLY_SCHED_OTHER) // SunOS, thru version 5.6, only supports SCHED_OTHER. spolicy = SCHED_OTHER; # else // Make sure to enable explicit scheduling, in case we didn't // enable it above (for non-default priority). ACE_SET_BITS (flags, THR_EXPLICIT_SCHED); if (ACE_BIT_ENABLED (flags, THR_SCHED_DEFAULT)) spolicy = SCHED_OTHER; else if (ACE_BIT_ENABLED (flags, THR_SCHED_FIFO)) spolicy = SCHED_FIFO; # if defined (SCHED_IO) else if (ACE_BIT_ENABLED (flags, THR_SCHED_IO)) spolicy = SCHED_IO; # else else if (ACE_BIT_ENABLED (flags, THR_SCHED_IO)) { errno = ENOSYS; return -1; } # endif /* SCHED_IO */ else spolicy = SCHED_RR; # if defined (ACE_HAS_FSU_PTHREADS) int ret; switch (spolicy) { case SCHED_FIFO: case SCHED_RR: ret = 0; break; default: ret = 22; break; } if (ret != 0) { ::pthread_attr_destroy (&attr); return -1; } # endif /* ACE_HAS_FSU_PTHREADS */ # endif /* ACE_HAS_ONLY_SCHED_OTHER */ # if defined (ACE_HAS_PTHREADS_DRAFT4) result = ::pthread_attr_setsched (&attr, spolicy); # elif defined (ACE_HAS_PTHREADS_DRAFT6) result = ::pthread_attr_setschedpolicy (&attr, spolicy); # else /* draft 7 or std */ ACE_ADAPT_RETVAL(::pthread_attr_setschedpolicy (&attr, spolicy), result); # endif /* ACE_HAS_PTHREADS_DRAFT4 */ if (result != 0) { # if defined (ACE_HAS_PTHREADS_DRAFT4) ::pthread_attr_delete (&attr); # else /* ACE_HAS_PTHREADS_DRAFT4 */ ::pthread_attr_destroy (&attr); # endif /* ACE_HAS_PTHREADS_DRAFT4 */ return -1; } } // *** Set Priority (use reasonable default priorities) # if defined(ACE_HAS_PTHREADS_STD) // If we wish to explicitly set a scheduling policy, we also // have to specify a priority. We choose a "middle" priority as // default. Maybe this is also necessary on other POSIX'ish // implementations? if ((ACE_BIT_ENABLED (flags, THR_SCHED_FIFO) || ACE_BIT_ENABLED (flags, THR_SCHED_RR) || ACE_BIT_ENABLED (flags, THR_SCHED_DEFAULT)) && priority == ACE_DEFAULT_THREAD_PRIORITY) { if (ACE_BIT_ENABLED (flags, THR_SCHED_FIFO)) priority = ACE_THR_PRI_FIFO_DEF; else if (ACE_BIT_ENABLED (flags, THR_SCHED_RR)) priority = ACE_THR_PRI_RR_DEF; else // THR_SCHED_DEFAULT priority = ACE_THR_PRI_OTHER_DEF; } # endif /* ACE_HAS_PTHREADS_STD */ if (priority != ACE_DEFAULT_THREAD_PRIORITY) { struct sched_param sparam; ACE_OS::memset ((void *) &sparam, 0, sizeof sparam); # if defined (ACE_HAS_IRIX62_THREADS) sparam.sched_priority = ACE_MIN (priority, (long) PTHREAD_MAX_PRIORITY); # elif defined (PTHREAD_MAX_PRIORITY) && !defined(ACE_HAS_PTHREADS_STD) /* For MIT pthreads... */ sparam.prio = ACE_MIN (priority, PTHREAD_MAX_PRIORITY); # elif defined(ACE_HAS_PTHREADS_STD) && !defined (ACE_HAS_STHREADS) // The following code forces priority into range. if (ACE_BIT_ENABLED (flags, THR_SCHED_FIFO)) sparam.sched_priority = ACE_MIN (ACE_THR_PRI_FIFO_MAX, ACE_MAX (ACE_THR_PRI_FIFO_MIN, priority)); else if (ACE_BIT_ENABLED(flags, THR_SCHED_RR)) sparam.sched_priority = ACE_MIN (ACE_THR_PRI_RR_MAX, ACE_MAX (ACE_THR_PRI_RR_MIN, priority)); else // Default policy, whether set or not sparam.sched_priority = ACE_MIN (ACE_THR_PRI_OTHER_MAX, ACE_MAX (ACE_THR_PRI_OTHER_MIN, priority)); # elif defined (PRIORITY_MAX) sparam.sched_priority = ACE_MIN (priority, (long) PRIORITY_MAX); # else sparam.sched_priority = priority; # endif /* ACE_HAS_IRIX62_THREADS */ # if defined (ACE_HAS_FSU_PTHREADS) if (sparam.sched_priority >= PTHREAD_MIN_PRIORITY && sparam.sched_priority <= PTHREAD_MAX_PRIORITY) attr.prio = sparam.sched_priority; else { pthread_attr_destroy (&attr); errno = EINVAL; return -1; } # else { # if defined (sun) && defined (ACE_HAS_ONLY_SCHED_OTHER) // SunOS, through 5.6, POSIX only allows priorities > 0 to // ::pthread_attr_setschedparam. If a priority of 0 was // requested, set the thread priority after creating it, below. if (priority > 0) # endif /* sun && ACE_HAS_ONLY_SCHED_OTHER */ { # if defined (ACE_HAS_PTHREADS_DRAFT4) || defined (ACE_HAS_PTHREADS_DRAFT6) result = ::pthread_attr_setprio (&attr, sparam.sched_priority); # else /* this is draft 7 or std */ ACE_ADAPT_RETVAL(::pthread_attr_setschedparam (&attr, &sparam), result); # endif /* ACE_HAS_PTHREADS_DRAFT4, 6 */ if (result != 0) { # if defined (ACE_HAS_PTHREADS_DRAFT4) ::pthread_attr_delete (&attr); # else /* ACE_HAS_PTHREADS_DRAFT4 */ ::pthread_attr_destroy (&attr); # endif /* ACE_HAS_PTHREADS_DRAFT4 */ return -1; } } } # endif /* ACE_HAS_FSU_PTHREADS */ } // *** Set scheduling explicit or inherited if (ACE_BIT_ENABLED (flags, THR_INHERIT_SCHED) || ACE_BIT_ENABLED (flags, THR_EXPLICIT_SCHED)) { # if defined (ACE_HAS_PTHREADS_DRAFT4) int sched = PTHREAD_DEFAULT_SCHED; # else /* ACE_HAS_PTHREADS_DRAFT4 */ int sched = PTHREAD_EXPLICIT_SCHED; # endif /* ACE_HAS_PTHREADS_DRAFT4 */ if (ACE_BIT_ENABLED (flags, THR_INHERIT_SCHED)) sched = PTHREAD_INHERIT_SCHED; if (::pthread_attr_setinheritsched (&attr, sched) != 0) { # if defined (ACE_HAS_PTHREADS_DRAFT4) ::pthread_attr_delete (&attr); # else /* ACE_HAS_PTHREADS_DRAFT4 */ ::pthread_attr_destroy (&attr); # endif /* ACE_HAS_PTHREADS_DRAFT4 */ return -1; } } # else /* ACE_LACKS_SETSCHED */ ACE_UNUSED_ARG (priority); # endif /* ACE_LACKS_SETSCHED */ // *** Set Scope # if !defined (ACE_LACKS_THREAD_PROCESS_SCOPING) if (ACE_BIT_ENABLED (flags, THR_SCOPE_SYSTEM) || ACE_BIT_ENABLED (flags, THR_SCOPE_PROCESS)) { # if defined (ACE_CONFIG_LINUX_H) || defined (HPUX) // LinuxThreads do not have support for PTHREAD_SCOPE_PROCESS. // Neither does HPUX (up to HP-UX 11.00, as far as I know). int scope = PTHREAD_SCOPE_SYSTEM; # else /* ACE_CONFIG_LINUX_H */ int scope = PTHREAD_SCOPE_PROCESS; # endif /* ACE_CONFIG_LINUX_H */ if (ACE_BIT_ENABLED (flags, THR_SCOPE_SYSTEM)) scope = PTHREAD_SCOPE_SYSTEM; if (::pthread_attr_setscope (&attr, scope) != 0) { # if defined (ACE_HAS_PTHREADS_DRAFT4) ::pthread_attr_delete (&attr); # else /* ACE_HAS_PTHREADS_DRAFT4 */ ::pthread_attr_destroy (&attr); # endif /* ACE_HAS_PTHREADS_DRAFT4 */ return -1; } } # endif /* !ACE_LACKS_THREAD_PROCESS_SCOPING */ if (ACE_BIT_ENABLED (flags, THR_NEW_LWP)) { // Increment the number of LWPs by one to emulate the // SunOS semantics. int lwps = ACE_OS::thr_getconcurrency (); if (lwps == -1) { if (errno == ENOTSUP) // Suppress the ENOTSUP because it's harmless. errno = 0; else // This should never happen on SunOS: // ::thr_getconcurrency () should always succeed. return -1; } else if (ACE_OS::thr_setconcurrency (lwps + 1) == -1) { if (errno == ENOTSUP) { // Unlikely: ::thr_getconcurrency () is supported but // ::thr_setconcurrency () is not? } else return -1; } } } # if defined (ACE_HAS_PTHREADS_DRAFT4) ACE_OSCALL (::pthread_create (thr_id, attr, thread_args->entry_point (), thread_args), int, -1, result); # if defined (ACE_LACKS_SETDETACH) if (ACE_BIT_ENABLED (flags, THR_DETACHED)) { # if defined (HPUX_10) // HP-UX DCE threads' pthread_detach will smash thr_id if it's // just given as an argument. This will cause // ACE_Thread_Manager (if it's doing this create) to lose track // of the new thread since the ID will be passed back equal to // 0. So give pthread_detach a junker to scribble on. ACE_thread_t junker; cma_handle_assign(thr_id, &junker); ::pthread_detach (&junker); # else ::pthread_detach (thr_id); # endif /* HPUX_10 */ } # endif /* ACE_LACKS_SETDETACH */ ::pthread_attr_delete (&attr); # elif defined (ACE_HAS_PTHREADS_DRAFT6) ACE_OSCALL (::pthread_create (thr_id, &attr, thread_args->entry_point (), thread_args), int, -1, result); ::pthread_attr_destroy (&attr); # else /* this is draft 7 or std */ ACE_OSCALL (ACE_ADAPT_RETVAL (::pthread_create (thr_id, &attr, thread_args->entry_point (), thread_args), result), int, -1, result); ::pthread_attr_destroy (&attr); # endif /* ACE_HAS_PTHREADS_DRAFT4 */ // This is a SunOS or POSIX implementation of pthreads, where we // assume that ACE_thread_t and ACE_hthread_t are the same. If this // *isn't* correct on some platform, please let us know. if (result != -1) *thr_handle = *thr_id; # if defined (sun) && defined (ACE_HAS_ONLY_SCHED_OTHER) // SunOS prior to 5.7: // If the priority is 0, then we might have to set it now because we // couldn't set it with ::pthread_attr_setschedparam, as noted // above. This doesn't provide strictly correct behavior, because // the thread was created (above) with the priority of its parent. // (That applies regardless of the inherit_sched attribute: if it // was PTHREAD_INHERIT_SCHED, then it certainly inherited its // parent's priority. If it was PTHREAD_EXPLICIT_SCHED, then "attr" // was initialized by the SunOS ::pthread_attr_init () to contain // NULL for the priority, which indicated to SunOS ::pthread_create // () to inherit the parent priority.) if (priority == 0) { // Check the priority of this thread, which is the parent // of the newly created thread. If it is 0, then the // newly created thread will have inherited the priority // of 0, so there's no need to explicitly set it. struct sched_param sparam; int policy = 0; ACE_OSCALL (ACE_ADAPT_RETVAL (::pthread_getschedparam (thr_self (), &policy, &sparam), result), int, -1, result); // The only policy supported by by SunOS, thru version 5.6, // is SCHED_OTHER, so that's hard-coded here. policy = ACE_SCHED_OTHER; if (sparam.sched_priority != 0) { ACE_OS::memset ((void *) &sparam, 0, sizeof sparam); // The memset to 0 sets the priority to 0, so we don't need // to explicitly set sparam.sched_priority. ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::pthread_setschedparam (*thr_id, policy, &sparam), result), int, -1); } } # if defined (ACE_NEEDS_LWP_PRIO_SET) # if 0 // It would be useful if we could make this work. But, it requires // a mechanism for determining the ID of an LWP to which another // thread is bound. Is there a way to do that? Instead, just rely // on the code in ACE_Thread_Adapter::invoke () to set the LWP // priority. // If the thread is bound, then set the priority on its LWP. if (ACE_BIT_ENABLED (flags, THR_BOUND)) { ACE_Sched_Params sched_params (ACE_BIT_ENABLED (flags, THR_SCHED_FIFO) || ACE_BIT_ENABLED (flags, THR_SCHED_RR) ? ACE_SCHED_FIFO : ACE_SCHED_OTHER, priority); result = ACE_OS::lwp_setparams (sched_params, /* ? How do we find the ID of the LWP to which *thr_id is bound? */); } # endif /* 0 */ # endif /* ACE_NEEDS_LWP_PRIO_SET */ # endif /* sun && ACE_HAS_ONLY_SCHED_OTHER */ return result; # elif defined (ACE_HAS_STHREADS) int result; int start_suspended = ACE_BIT_ENABLED (flags, THR_SUSPENDED); if (priority != ACE_DEFAULT_THREAD_PRIORITY) // If we need to set the priority, then we need to start the // thread in a suspended mode. ACE_SET_BITS (flags, THR_SUSPENDED); ACE_OSCALL (ACE_ADAPT_RETVAL (::thr_create (stack, stacksize, thread_args->entry_point (), thread_args, flags, thr_id), result), int, -1, result); if (result != -1) { // With SunOS threads, ACE_thread_t and ACE_hthread_t are the same. *thr_handle = *thr_id; if (priority != ACE_DEFAULT_THREAD_PRIORITY) { // Set the priority of the new thread and then let it // continue, but only if the user didn't start it suspended // in the first place! if ((result = ACE_OS::thr_setprio (*thr_id, priority)) != 0) { errno = result; return -1; } if (start_suspended == 0) { if ((result = ACE_OS::thr_continue (*thr_id)) != 0) { errno = result; return -1; } } } } return result; # elif defined (ACE_HAS_WTHREADS) ACE_UNUSED_ARG (stack); # if defined (ACE_HAS_MFC) && (ACE_HAS_MFC != 0) if (ACE_BIT_ENABLED (flags, THR_USE_AFX)) { CWinThread *cwin_thread = ::AfxBeginThread ((AFX_THREADPROC) thread_args->entry_point (), thread_args, priority, 0, flags | THR_SUSPENDED); // Have to duplicate the handle because // CWinThread::~CWinThread() closes the original handle. # if !defined (ACE_HAS_WINCE) (void) ::DuplicateHandle (::GetCurrentProcess (), cwin_thread->m_hThread, ::GetCurrentProcess (), thr_handle, 0, TRUE, DUPLICATE_SAME_ACCESS); # endif /* ! ACE_HAS_WINCE */ *thr_id = cwin_thread->m_nThreadID; if (ACE_BIT_ENABLED (flags, THR_SUSPENDED) == 0) cwin_thread->ResumeThread (); // cwin_thread will be deleted in AfxThreadExit() // Warning: If AfxThreadExit() is called from within the // thread, ACE_TSS_Cleanup->exit() never gets called ! } else # endif /* ACE_HAS_MFC */ { int start_suspended = ACE_BIT_ENABLED (flags, THR_SUSPENDED); if (priority != ACE_DEFAULT_THREAD_PRIORITY) // If we need to set the priority, then we need to start the // thread in a suspended mode. ACE_SET_BITS (flags, THR_SUSPENDED); *thr_handle = (void *) ACE_BEGINTHREADEX (0, ACE_static_cast (u_int, stacksize), thread_args->entry_point (), thread_args, flags, thr_id); if (priority != ACE_DEFAULT_THREAD_PRIORITY && *thr_handle != 0) { // Set the priority of the new thread and then let it // continue, but only if the user didn't start it suspended // in the first place! ACE_OS::thr_setprio (*thr_handle, priority); if (start_suspended == 0) ACE_OS::thr_continue (*thr_handle); } } # if 0 *thr_handle = ::CreateThread (0, stacksize, LPTHREAD_START_ROUTINE (thread_args->entry_point ()), thread_args, flags, thr_id); # endif /* 0 */ // Close down the handle if no one wants to use it. if (thr_handle == &tmp_handle) ::CloseHandle (tmp_handle); if (*thr_handle != 0) return 0; else ACE_FAIL_RETURN (-1); /* NOTREACHED */ # elif defined (ACE_PSOS) // stack is created in the task's memory region 0 ACE_UNUSED_ARG (stack); // task creation and start flags are fixed ACE_UNUSED_ARG (flags); // lowest priority is reserved for the IDLE pSOS+ system daemon, // highest are reserved for high priority pSOS+ system daemons if (priority < PSOS_TASK_MIN_PRIORITY) { priority = PSOS_TASK_MIN_PRIORITY; } else if (priority > PSOS_TASK_MAX_PRIORITY) { priority = PSOS_TASK_MAX_PRIORITY; } // set the stacksize to a default value if no size is specified if (stacksize == 0) stacksize = ACE_PSOS_DEFAULT_STACK_SIZE; ACE_hthread_t tid; *thr_handle = 0; // create the thread if (t_create ((char *) thr_id, // task name priority, // (possibly adjusted) task priority stacksize, // passed stack size is used for supervisor stack 0, // no user stack: tasks run strictly in supervisor mode T_LOCAL, // local to the pSOS+ node (does not support pSOS+m) &tid) // receives task id != 0) { return -1; } // pSOS tasks are passed an array of 4 u_longs u_long targs[4]; targs[0] = (u_long) ACE_THREAD_ARGUMENT; targs[1] = 0; targs[2] = 0; targs[3] = 0; // start the thread if (t_start (tid, T_PREEMPT | // Task can be preempted // T_NOTSLICE | // Task is not timesliced with other tasks at same priority T_TSLICE | // Task is timesliced with other tasks at same priority T_NOASR | // Task level signals disabled T_SUPV | // Task runs strictly in supervisor mode T_ISR, // Hardware interrupts are enabled ACE_THREAD_FUNCTION, // Task entry point targs) // Task argument(s) != 0) { return -1; } // store the task id in the handle and return success *thr_handle = tid; return 0; # elif defined (VXWORKS) // The hard-coded values below are what ::sp () would use. (::sp () // hardcodes priority to 100, flags to VX_FP_TASK, and stacksize to // 20,000.) stacksize should be an even integer. If a stack is not // specified, ::taskSpawn () is used so that we can set the // priority, flags, and stacksize. If a stack is specified, // ::taskInit ()/::taskActivate() are used. // If called with thr_create() defaults, use same default values as ::sp (): if (priority == ACE_DEFAULT_THREAD_PRIORITY) priority = 100; // Assumes that there is a floating point coprocessor. As noted // above, ::sp () hardcodes this, so we should be safe with it. if (flags == 0) flags = VX_FP_TASK; if (stacksize == 0) stacksize = 20000; const u_int thr_id_provided = thr_id && *thr_id && (*thr_id)[0] != ACE_THR_ID_ALLOCATED; ACE_hthread_t tid; # if 0 /* Don't support setting of stack, because it doesn't seem to work. */ if (stack == 0) { # else ACE_UNUSED_ARG (stack); # endif /* 0 */ // The call below to ::taskSpawn () causes VxWorks to assign a // unique task name of the form: "t" + an integer, because the // first argument is 0. tid = ::taskSpawn (thr_id_provided ? *thr_id : 0, priority, (int) flags, (int) stacksize, thread_args->entry_point (), (int) thread_args, 0, 0, 0, 0, 0, 0, 0, 0, 0); # if 0 /* Don't support setting of stack, because it doesn't seem to work. */ } else { // If a task name (thr_id) was not supplied, then the task will // not have a unique name. That's VxWorks' behavior. // Carve out a TCB at the beginning of the stack space. The TCB // occupies 400 bytes with VxWorks 5.3.1/I386. WIND_TCB *tcb = (WIND_TCB *) stack; // The TID is defined to be the address of the TCB. int status = ::taskInit (tcb, thr_id_provided ? *thr_id : 0, priority, (int) flags, (char *) stack + sizeof (WIND_TCB), (int) (stacksize - sizeof (WIND_TCB)), thread_args->entry_point (), (int) thread_args, 0, 0, 0, 0, 0, 0, 0, 0, 0); if (status == OK) { // The task was successfully initialized, now activate it. status = ::taskActivate ((ACE_hthread_t) tcb); } tid = status == OK ? (ACE_hthread_t) tcb : ERROR; } # endif /* 0 */ if (tid == ERROR) return -1; else { if (! thr_id_provided && thr_id) { if (*thr_id && (*thr_id)[0] == ACE_THR_ID_ALLOCATED) // *thr_id was allocated by the Thread_Manager. ::taskTcb // (int tid) returns the address of the WIND_TCB (task // control block). According to the ::taskSpawn() // documentation, the name of the new task is stored at // pStackBase, but is that of the current task? If so, it // might be a bit quicker than this extraction of the tcb // . . . ACE_OS::strsncpy (*thr_id + 1, ::taskTcb (tid)->name, 10); else // *thr_id was not allocated by the Thread_Manager. // Pass back the task name in the location pointed to // by thr_id. *thr_id = ::taskTcb (tid)->name; } // else if the thr_id was provided, there's no need to overwrite // it with the same value (string). If thr_id is 0, then we can't // pass the task name back. if (thr_handle) *thr_handle = tid; return 0; } # endif /* ACE_HAS_STHREADS */ # else ACE_UNUSED_ARG (func); ACE_UNUSED_ARG (args); ACE_UNUSED_ARG (flags); ACE_UNUSED_ARG (thr_id); ACE_UNUSED_ARG (thr_handle); ACE_UNUSED_ARG (priority); ACE_UNUSED_ARG (stack); ACE_UNUSED_ARG (stacksize); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_THREADS */ } void ACE_OS::thr_exit (ACE_THR_FUNC_RETURN status) { ACE_OS_TRACE ("ACE_OS::thr_exit"); #if defined (ACE_HAS_THREADS) # if defined (ACE_HAS_PTHREADS) ::pthread_exit (status); # elif defined (ACE_HAS_STHREADS) ::thr_exit (status); # elif defined (ACE_HAS_WTHREADS) // Can't call it here because on NT, the thread is exited // directly by ACE_Thread_Adapter::invoke (). // ACE_TSS_Cleanup::instance ()->exit (status); # if defined (ACE_HAS_MFC) && (ACE_HAS_MFC != 0) int using_afx = -1; // An ACE_Thread_Descriptor really is an ACE_OS_Thread_Descriptor. // But without #including ace/Thread_Manager.h, we don't know that. ACE_OS_Thread_Descriptor *td = ACE_Base_Thread_Adapter::thr_desc_log_msg (); if (td) using_afx = ACE_BIT_ENABLED (td->flags (), THR_USE_AFX); # endif /* ACE_HAS_MFC && (ACE_HAS_MFC != 0) */ // Call TSS destructors. ACE_OS::cleanup_tss (0 /* not main thread */); // Exit the thread. // Allow CWinThread-destructor to be invoked from AfxEndThread. // _endthreadex will be called from AfxEndThread so don't exit the // thread now if we are running an MFC thread. # if defined (ACE_HAS_MFC) && (ACE_HAS_MFC != 0) if (using_afx != -1) { if (using_afx) ::AfxEndThread (status); else ACE_ENDTHREADEX (status); } else { // Not spawned by ACE_Thread_Manager, use the old buggy // version. You should seriously consider using // ACE_Thread_Manager to spawn threads. The following code is // know to cause some problem. CWinThread *pThread = ::AfxGetThread (); if (!pThread || pThread->m_nThreadID != ACE_OS::thr_self ()) ACE_ENDTHREADEX (status); else ::AfxEndThread (status); } # else ACE_ENDTHREADEX (status); # endif /* ACE_HAS_MFC && ACE_HAS_MFS != 0*/ # elif defined (VXWORKS) ACE_hthread_t tid; ACE_OS::thr_self (tid); *((int *) status) = ::taskDelete (tid); # elif defined (ACE_PSOS) ACE_hthread_t tid; ACE_OS::thr_self (tid); # if defined (ACE_PSOS) && defined (ACE_PSOS_HAS_TSS) // Call TSS destructors. ACE_OS::cleanup_tss (0 /* not main thread */); # endif /* ACE_PSOS && ACE_PSOS_HAS_TSS */ *((u_long *) status) = ::t_delete (tid); # endif /* ACE_HAS_PTHREADS */ # else ACE_UNUSED_ARG (status); # endif /* ACE_HAS_THREADS */ } int ACE_OS::lwp_getparams (ACE_Sched_Params &sched_params) { # if defined (ACE_HAS_STHREADS) || defined (sun) // Get the class TS and RT class IDs. ACE_id_t rt_id; ACE_id_t ts_id; if (ACE_OS::scheduling_class ("RT", rt_id) == -1 || ACE_OS::scheduling_class ("TS", ts_id) == -1) return -1; // Get this LWP's scheduling parameters. pcparms_t pcparms; // The following is just to avoid Purify warnings about unitialized // memory reads. ACE_OS::memset (&pcparms, 0, sizeof pcparms); pcparms.pc_cid = PC_CLNULL; if (ACE_OS::priority_control (P_LWPID, P_MYID, PC_GETPARMS, (char *) &pcparms) == -1) return -1; else if (pcparms.pc_cid == rt_id) { // RT class. rtparms_t rtparms; ACE_OS::memcpy (&rtparms, pcparms.pc_clparms, sizeof rtparms); sched_params.policy (ACE_SCHED_FIFO); sched_params.priority (rtparms.rt_pri); sched_params.scope (ACE_SCOPE_THREAD); ACE_Time_Value quantum (rtparms.rt_tqsecs, rtparms.rt_tqnsecs == RT_TQINF ? 0 : rtparms.rt_tqnsecs * 1000); sched_params.quantum (quantum); return 0; } else if (pcparms.pc_cid == ts_id) { /* TS class */ tsparms_t tsparms; ACE_OS::memcpy (&tsparms, pcparms.pc_clparms, sizeof tsparms); sched_params.policy (ACE_SCHED_OTHER); sched_params.priority (tsparms.ts_upri); sched_params.scope (ACE_SCOPE_THREAD); return 0; } else return -1; # else /* ! ACE_HAS_STHREADS && ! sun */ ACE_UNUSED_ARG (sched_params); ACE_NOTSUP_RETURN (-1); # endif /* ! ACE_HAS_STHREADS && ! sun */ } int ACE_OS::lwp_setparams (const ACE_Sched_Params &sched_params) { # if defined (ACE_HAS_STHREADS) || defined (sun) ACE_Sched_Params lwp_params (sched_params); lwp_params.scope (ACE_SCOPE_LWP); return ACE_OS::sched_params (lwp_params); # else /* ! ACE_HAS_STHREADS && ! sun */ ACE_UNUSED_ARG (sched_params); ACE_NOTSUP_RETURN (-1); # endif /* ! ACE_HAS_STHREADS && ! sun */ } # if defined (ACE_HAS_TSS_EMULATION) && defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) int ACE_OS::thr_setspecific (ACE_OS_thread_key_t key, void *data) { // ACE_OS_TRACE ("ACE_OS::thr_setspecific"); # if defined (ACE_HAS_THREADS) # if defined (ACE_HAS_PTHREADS) # if defined (ACE_HAS_FSU_PTHREADS) // Call pthread_init() here to initialize threads package. FSU // threads need an initialization before the first thread constructor. // This seems to be the one; however, a segmentation fault may // indicate that another pthread_init() is necessary, perhaps in // Synch.cpp or Synch_T.cpp. FSU threads will not reinit if called // more than once, so another call to pthread_init will not adversely // affect existing threads. pthread_init (); # endif /* ACE_HAS_FSU_PTHREADS */ ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::pthread_setspecific (key, data), ace_result_), int, -1); # elif defined (ACE_HAS_STHREADS) ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::thr_setspecific (key, data), ace_result_), int, -1); # elif defined (ACE_HAS_WTHREADS) ::TlsSetValue (key, data); return 0; # endif /* ACE_HAS_STHREADS */ # else ACE_UNUSED_ARG (key); ACE_UNUSED_ARG (data); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_THREADS */ } # endif /* ACE_HAS_TSS_EMULATION && ACE_HAS_THREAD_SPECIFIC_STORAGE */ int ACE_OS::thr_setspecific (ACE_thread_key_t key, void *data) { // ACE_OS_TRACE ("ACE_OS::thr_setspecific"); #if defined (ACE_HAS_THREADS) # if defined (ACE_HAS_TSS_EMULATION) ACE_KEY_INDEX (key_index, key); if (key_index >= ACE_TSS_Emulation::total_keys ()) { errno = EINVAL; data = 0; return -1; } else { ACE_TSS_Emulation::ts_object (key) = data; ACE_TSS_Cleanup::instance ()->key_used (key); return 0; } # elif defined (ACE_HAS_PTHREADS) # if defined (ACE_HAS_FSU_PTHREADS) // Call pthread_init() here to initialize threads package. FSU // threads need an initialization before the first thread constructor. // This seems to be the one; however, a segmentation fault may // indicate that another pthread_init() is necessary, perhaps in // Synch.cpp or Synch_T.cpp. FSU threads will not reinit if called // more than once, so another call to pthread_init will not adversely // affect existing threads. pthread_init (); # endif /* ACE_HAS_FSU_PTHREADS */ # if defined (ACE_HAS_PTHREADS_DRAFT4) || defined (ACE_HAS_PTHREADS_DRAFT6) ACE_OSCALL_RETURN (::pthread_setspecific (key, data), int, -1); # else ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::pthread_setspecific (key, data), ace_result_), int, -1); # endif /* ACE_HAS_PTHREADS_DRAFT4, 6 */ # elif defined (ACE_HAS_STHREADS) ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::thr_setspecific (key, data), ace_result_), int, -1); # elif defined (ACE_PSOS) && defined (ACE_PSOS_HAS_TSS) ACE_hthread_t tid; ACE_OS::thr_self (tid); if (::tsd_setval (key, tid, data) != 0) return -1; ACE_TSS_Cleanup::instance ()->key_used (key); return 0; # elif defined (ACE_HAS_WTHREADS) ::TlsSetValue (key, data); ACE_TSS_Cleanup::instance ()->key_used (key); return 0; # else ACE_UNUSED_ARG (key); ACE_UNUSED_ARG (data); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_STHREADS */ # else ACE_UNUSED_ARG (key); ACE_UNUSED_ARG (data); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_THREADS */ } int ACE_OS::thr_keyfree (ACE_thread_key_t key) { ACE_OS_TRACE ("ACE_OS::thr_keyfree"); # if defined (ACE_HAS_THREADS) # if defined (ACE_HAS_TSS_EMULATION) // Release the key in the TSS_Emulation administration ACE_TSS_Emulation::release_key (key); return ACE_TSS_Cleanup::instance ()->remove (key); # elif defined (ACE_HAS_PTHREADS_DRAFT4) || defined (ACE_HAS_PTHREADS_DRAFT6) ACE_UNUSED_ARG (key); ACE_NOTSUP_RETURN (-1); # elif defined (ACE_HAS_PTHREADS) return ::pthread_key_delete (key); # elif defined (ACE_HAS_THR_KEYDELETE) return ::thr_keydelete (key); # elif defined (ACE_HAS_STHREADS) ACE_UNUSED_ARG (key); ACE_NOTSUP_RETURN (-1); # elif defined (ACE_HAS_WTHREADS) // Extract out the thread-specific table instance and free up // the key and destructor. ACE_TSS_Cleanup::instance ()->remove (key); ACE_WIN32CALL_RETURN (ACE_ADAPT_RETVAL (::TlsFree (key), ace_result_), int, -1); # elif defined (ACE_PSOS) && defined (ACE_PSOS_HAS_TSS) // Extract out the thread-specific table instance and free up // the key and destructor. ACE_TSS_Cleanup::instance ()->remove (key); return (::tsd_delete (key) == 0) ? 0 : -1; # else ACE_UNUSED_ARG (key); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_TSS_EMULATION */ # else ACE_UNUSED_ARG (key); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_THREADS */ } # if defined (ACE_HAS_TSS_EMULATION) && defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) int ACE_OS::thr_keycreate (ACE_OS_thread_key_t *key, # if defined (ACE_HAS_THR_C_DEST) ACE_THR_C_DEST dest, # else ACE_THR_DEST dest, # endif /* ACE_HAS_THR_C_DEST */ void *inst) { // ACE_OS_TRACE ("ACE_OS::thr_keycreate"); # if defined (ACE_HAS_THREADS) # if defined (ACE_HAS_PTHREADS) ACE_UNUSED_ARG (inst); # if defined (ACE_HAS_PTHREADS_DRAFT4) # if defined (ACE_HAS_STDARG_THR_DEST) ACE_OSCALL_RETURN (::pthread_keycreate (key, (void (*)(...)) dest), int, -1); # else /* ! ACE_HAS_STDARG_THR_DEST */ ACE_OSCALL_RETURN (::pthread_keycreate (key, dest), int, -1); # endif /* ! ACE_HAS_STDARG_THR_DEST */ # elif defined (ACE_HAS_PTHREADS_DRAFT6) ACE_OSCALL_RETURN (::pthread_key_create (key, dest), int, -1); # else ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::pthread_key_create (key, dest), ace_result_), int, -1); # endif /* ACE_HAS_PTHREADS_DRAFT4 */ # elif defined (ACE_HAS_STHREADS) ACE_UNUSED_ARG (inst); ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::thr_keycreate (key, dest), ace_result_), int, -1); # elif defined (ACE_HAS_WTHREADS) *key = ::TlsAlloc (); if (*key != ACE_SYSCALL_FAILED) { // Extract out the thread-specific table instance and stash away // the key and destructor so that we can free it up later on... return ACE_TSS_Cleanup::instance ()->insert (*key, dest, inst); } else ACE_FAIL_RETURN (-1); /* NOTREACHED */ # endif /* ACE_HAS_STHREADS */ # else ACE_UNUSED_ARG (key); ACE_UNUSED_ARG (dest); ACE_UNUSED_ARG (inst); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_THREADS */ } # endif /* ACE_HAS_TSS_EMULATION && ACE_HAS_THREAD_SPECIFIC_STORAGE */ int ACE_OS::thr_keycreate (ACE_thread_key_t *key, # if defined (ACE_HAS_THR_C_DEST) ACE_THR_C_DEST dest, # else ACE_THR_DEST dest, # endif /* ACE_HAS_THR_C_DEST */ void *inst) { // ACE_OS_TRACE ("ACE_OS::thr_keycreate"); #if defined (ACE_HAS_THREADS) # if defined (ACE_HAS_TSS_EMULATION) if (ACE_TSS_Emulation::next_key (*key) == 0) { ACE_TSS_Emulation::tss_destructor (*key, dest); // Extract out the thread-specific table instance and stash away // the key and destructor so that we can free it up later on... return ACE_TSS_Cleanup::instance ()->insert (*key, dest, inst); } else { errno = EAGAIN; return -1; } # elif defined (ACE_HAS_PTHREADS) ACE_UNUSED_ARG (inst); # if defined (ACE_HAS_PTHREADS_DRAFT4) # if defined (ACE_HAS_STDARG_THR_DEST) ACE_OSCALL_RETURN (::pthread_keycreate (key, (void (*)(...)) dest), int, -1); # else /* ! ACE_HAS_STDARG_THR_DEST */ ACE_OSCALL_RETURN (::pthread_keycreate (key, dest), int, -1); # endif /* ! ACE_HAS_STDARG_THR_DEST */ # elif defined (ACE_HAS_PTHREADS_DRAFT6) ACE_OSCALL_RETURN (::pthread_key_create (key, dest), int, -1); # else ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::pthread_key_create (key, dest), ace_result_), int, -1); # endif /* ACE_HAS_PTHREADS_DRAFT4 */ # elif defined (ACE_HAS_STHREADS) ACE_UNUSED_ARG (inst); ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::thr_keycreate (key, dest), ace_result_), int, -1); # elif defined (ACE_PSOS) && defined (ACE_PSOS_HAS_TSS) static u_long unique_name = 0; void *tsdanchor; ++unique_name; if (::tsd_create (ACE_reinterpret_cast (char *, &unique_name), 0, TSD_NOALLOC, (void ****) &tsdanchor, key) != 0) { return -1; } return ACE_TSS_Cleanup::instance ()->insert (*key, dest, inst); # elif defined (ACE_HAS_WTHREADS) *key = ::TlsAlloc (); if (*key != ACE_SYSCALL_FAILED) { // Extract out the thread-specific table instance and stash away // the key and destructor so that we can free it up later on... return ACE_TSS_Cleanup::instance ()->insert (*key, dest, inst); } else ACE_FAIL_RETURN (-1); /* NOTREACHED */ # else ACE_UNUSED_ARG (key); ACE_UNUSED_ARG (dest); ACE_UNUSED_ARG (inst); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_TSS_EMULATION */ # else ACE_UNUSED_ARG (key); ACE_UNUSED_ARG (dest); ACE_UNUSED_ARG (inst); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_THREADS */ } int ACE_OS::thr_key_used (ACE_thread_key_t key) { # if defined (ACE_WIN32) || defined (ACE_HAS_TSS_EMULATION) || (defined (ACE_PSOS) && defined (ACE_PSOS_HAS_TSS)) ACE_TSS_Cleanup::instance ()->key_used (key); return 0; # else ACE_UNUSED_ARG (key); ACE_NOTSUP_RETURN (-1); # endif /* ACE_WIN32 || ACE_HAS_TSS_EMULATION || ACE_PSOS_HAS_TSS */ } int ACE_OS::thr_key_detach (void *inst) { # if defined (ACE_WIN32) || defined (ACE_HAS_TSS_EMULATION) || (defined (ACE_PSOS) && defined (ACE_PSOS_HAS_TSS)) if (ACE_TSS_Cleanup::lockable ()) return ACE_TSS_Cleanup::instance()->detach (inst); else // We're in static constructor/destructor phase. Don't // try to use the ACE_TSS_Cleanup instance because its lock // might not have been constructed yet, or might have been // destroyed already. Just leak the key . . . return -1; # else ACE_UNUSED_ARG (inst); ACE_NOTSUP_RETURN (-1); # endif /* ACE_WIN32 || ACE_HAS_TSS_EMULATION */ } void ACE_OS::unique_name (const void *object, ACE_TCHAR *name, size_t length) { // The process ID will provide uniqueness between processes on the // same machine. The "this" pointer of the will provide // uniqueness between other "live" objects in the same process. The // uniqueness of this name is therefore only valid for the life of // . ACE_TCHAR temp_name[ACE_UNIQUE_NAME_LEN]; ACE_OS::sprintf (temp_name, ACE_LIB_TEXT ("%p%d"), object, ACE_static_cast (int, ACE_OS::getpid ())); ACE_OS::strsncpy (name, temp_name, length); } int ACE_OS::argv_to_string (ACE_TCHAR **argv, ACE_TCHAR *&buf, int substitute_env_args) { if (argv == 0 || argv[0] == 0) return 0; size_t buf_len = 0; // Determine the length of the buffer. for (int i = 0; argv[i] != 0; i++) { ACE_TCHAR *temp = 0; #if !defined (ACE_LACKS_ENV) // Account for environment variables. if (substitute_env_args && (argv[i][0] == '$' && (temp = ACE_OS::getenv (&argv[i][1])) != 0)) buf_len += ACE_OS_String::strlen (temp); else #endif /* ACE_LACKS_ENV */ buf_len += ACE_OS_String::strlen (argv[i]); // Add one for the extra space between each string. buf_len++; } // Step through all argv params and copy each one into buf; separate // each param with white space. ACE_NEW_RETURN (buf, ACE_TCHAR[buf_len + 1], 0); // Initial null charater to make it a null string. buf[0] = '\0'; ACE_TCHAR *end = buf; int j; for (j = 0; argv[j] != 0; j++) { ACE_TCHAR *temp = 0; # if !defined (ACE_LACKS_ENV) // Account for environment variables. if (substitute_env_args && (argv[j][0] == '$' && (temp = ACE_OS::getenv (&argv[j][1])) != 0)) end = ACE_OS::strecpy (end, temp); else #endif /* ACE_LACKS_ENV */ end = ACE_OS::strecpy (end, argv[j]); // Replace the null char that strecpy put there with white // space. end[-1] = ' '; } // Null terminate the string. *end = '\0'; // The number of arguments. return j; } int ACE_OS::string_to_argv (ACE_TCHAR *buf, int &argc, ACE_TCHAR **&argv, int substitute_env_args) { // Reset the number of arguments argc = 0; if (buf == 0) return -1; ACE_TCHAR *cp = buf; // First pass: count arguments. // '#' is the start-comment token.. while (*cp != '\0' && *cp != '#') { // Skip whitespace.. while (ACE_OS::ace_isspace (*cp)) cp++; // Increment count and move to next whitespace.. if (*cp != '\0') argc++; while (*cp != '\0' && !ACE_OS::ace_isspace (*cp)) { // Grok quotes.... if (*cp == '\'' || *cp == '"') { ACE_TCHAR quote = *cp; // Scan past the string.. for (cp++; *cp != '\0' && *cp != quote; cp++) continue; // '\0' implies unmatched quote.. if (*cp == '\0') { argc--; break; } else cp++; } else cp++; } } // Second pass: copy arguments. ACE_TCHAR arg[ACE_DEFAULT_ARGV_BUFSIZ]; ACE_TCHAR *argp = arg; // Make sure that the buffer we're copying into is always large // enough. if (cp - buf >= ACE_DEFAULT_ARGV_BUFSIZ) ACE_NEW_RETURN (argp, ACE_TCHAR[cp - buf + 1], -1); // Make a new argv vector of argc + 1 elements. ACE_NEW_RETURN (argv, ACE_TCHAR *[argc + 1], -1); ACE_TCHAR *ptr = buf; for (int i = 0; i < argc; i++) { // Skip whitespace.. while (ACE_OS::ace_isspace (*ptr)) ptr++; // Copy next argument and move to next whitespace.. cp = argp; while (*ptr != '\0' && !ACE_OS::ace_isspace (*ptr)) if (*ptr == '\'' || *ptr == '"') { ACE_TCHAR quote = *ptr++; while (*ptr != '\0' && *ptr != quote) *cp++ = *ptr++; if (*ptr == quote) ptr++; } else *cp++ = *ptr++; *cp = '\0'; #if !defined (ACE_LACKS_ENV) // Check for environment variable substitution here. if (substitute_env_args) { argv[i] = ACE_OS::strenvdup(argp); if (argv[i] == 0) { if (argp != arg) delete [] argp; errno = ENOMEM; return -1; } } else #endif /* ACE_LACKS_ENV */ { argv[i] = ACE_OS::strdup(argp); if (argv[i] == 0) { if (argp != arg) delete [] argp; errno = ENOMEM; return -1; } } } if (argp != arg) delete [] argp; argv[argc] = 0; return 0; } // Create a contiguous command-line argument buffer with each arg // separated by spaces. pid_t ACE_OS::fork_exec (ACE_TCHAR *argv[]) { # if defined (ACE_WIN32) ACE_TCHAR *buf; if (ACE_OS::argv_to_string (argv, buf) != -1) { PROCESS_INFORMATION process_info; # if !defined (ACE_HAS_WINCE) ACE_TEXT_STARTUPINFO startup_info; ACE_OS::memset ((void *) &startup_info, 0, sizeof startup_info); startup_info.cb = sizeof startup_info; if (ACE_TEXT_CreateProcess (0, buf, 0, // No process attributes. 0, // No thread attributes. TRUE, // Allow handle inheritance. 0, // Don't create a new console window. 0, // No environment. 0, // No current directory. &startup_info, &process_info)) # else if (ACE_TEXT_CreateProcess (0, buf, 0, // No process attributes. 0, // No thread attributes. FALSE, // Can's inherit handles on CE 0, // Don't create a new console window. 0, // No environment. 0, // No current directory. 0, // Can't use startup info on CE &process_info)) # endif /* ! ACE_HAS_WINCE */ { // Free resources allocated in kernel. ACE_OS::close (process_info.hThread); ACE_OS::close (process_info.hProcess); // Return new process id. delete [] buf; return process_info.dwProcessId; } } // CreateProcess failed. return -1; # elif defined (CHORUS) return ACE_OS::execv (argv[0], argv); # else pid_t result = ACE_OS::fork (); switch (result) { case -1: // Error. return -1; case 0: // Child process. if (ACE_OS::execv (argv[0], argv) == -1) { // The OS layer should not print stuff out // ACE_ERROR ((LM_ERROR, // "%p Exec failed\n")); // If the execv fails, this child needs to exit. ACE_OS::exit (errno); } default: // Server process. The fork succeeded. return result; } # endif /* ACE_WIN32 */ } ssize_t ACE_OS::read_n (ACE_HANDLE handle, void *buf, size_t len, size_t *bt) { size_t temp; size_t &bytes_transferred = bt == 0 ? temp : *bt; ssize_t n; for (bytes_transferred = 0; bytes_transferred < len; bytes_transferred += n) { n = ACE_OS::read (handle, (char *) buf + bytes_transferred, len - bytes_transferred); if (n == -1 || n == 0) return n; } return bytes_transferred; } // Write bytes from to (uses the // system call on UNIX and the call on Win32). ssize_t ACE_OS::write_n (ACE_HANDLE handle, const void *buf, size_t len, size_t *bt) { size_t temp; size_t &bytes_transferred = bt == 0 ? temp : *bt; ssize_t n; for (bytes_transferred = 0; bytes_transferred < len; bytes_transferred += n) { n = ACE_OS::write (handle, (char *) buf + bytes_transferred, len - bytes_transferred); if (n == -1 || n == 0) return n; } return bytes_transferred; } # if defined (ACE_LACKS_WRITEV) // "Fake" writev for operating systems without it. Note that this is // thread-safe. int ACE_OS::writev_emulation (ACE_HANDLE handle, ACE_WRITEV_TYPE iov[], int n) { ACE_OS_TRACE ("ACE_OS::writev_emulation"); size_t length = 0; int i; // Determine the total length of all the buffers in . for (i = 0; i < n; i++) if (ACE_static_cast (int, iov[i].iov_len) < 0) return -1; else length += iov[i].iov_len; char *buf; # if defined (ACE_HAS_ALLOCA) buf = (char *) alloca (length); # else ACE_NEW_RETURN (buf, char[length], -1); # endif /* !defined (ACE_HAS_ALLOCA) */ char *ptr = buf; for (i = 0; i < n; i++) { ACE_OS::memcpy (ptr, iov[i].iov_base, iov[i].iov_len); ptr += iov[i].iov_len; } ssize_t result = ACE_OS::write (handle, buf, length); # if !defined (ACE_HAS_ALLOCA) delete [] buf; # endif /* !defined (ACE_HAS_ALLOCA) */ return result; } # endif /* ACE_LACKS_WRITEV */ # if defined (ACE_LACKS_READV) // "Fake" readv for operating systems without it. Note that this is // thread-safe. ssize_t ACE_OS::readv_emulation (ACE_HANDLE handle, ACE_READV_TYPE *iov, int n) { ACE_OS_TRACE ("ACE_OS::readv_emulation"); ssize_t length = 0; int i; for (i = 0; i < n; i++) if (ACE_static_cast (int, iov[i].iov_len) < 0) return -1; else length += iov[i].iov_len; char *buf; # if defined (ACE_HAS_ALLOCA) buf = (char *) alloca (length); # else ACE_NEW_RETURN (buf, char[length], -1); # endif /* !defined (ACE_HAS_ALLOCA) */ length = ACE_OS::read (handle, buf, length); if (length != -1) { char *ptr = buf; ssize_t copyn = length; for (i = 0; i < n && copyn > 0; i++) { ACE_OS::memcpy (iov[i].iov_base, ptr, // iov_len is int on some platforms, size_t on others copyn > (int) iov[i].iov_len ? (size_t) iov[i].iov_len : (size_t) copyn); ptr += iov[i].iov_len; copyn -= iov[i].iov_len; } } # if !defined (ACE_HAS_ALLOCA) delete [] buf; # endif /* !defined (ACE_HAS_ALLOCA) */ return length; } # endif /* ACE_LACKS_READV */ # if defined (ACE_NEEDS_FTRUNCATE) extern "C" int ftruncate (ACE_HANDLE handle, long len) { struct flock fl; fl.l_whence = 0; fl.l_len = 0; fl.l_start = len; fl.l_type = F_WRLCK; return ACE_OS::fcntl (handle, F_FREESP, ACE_reinterpret_cast (long, &fl)); } # endif /* ACE_NEEDS_FTRUNCATE */ # if defined (ACE_LACKS_MKTEMP) ACE_TCHAR * ACE_OS::mktemp (ACE_TCHAR *s) { ACE_OS_TRACE ("ACE_OS::mktemp"); if (s == 0) // check for null template string failed! return 0; else { ACE_TCHAR *xxxxxx = ACE_OS::strstr (s, ACE_LIB_TEXT ("XXXXXX")); if (xxxxxx == 0) // the template string doesn't contain "XXXXXX"! return s; else { ACE_TCHAR unique_letter = ACE_LIB_TEXT ('a'); ACE_stat sb; // Find an unused filename for this process. It is assumed // that the user will open the file immediately after // getting this filename back (so, yes, there is a race // condition if multiple threads in a process use the same // template). This appears to match the behavior of the // SunOS 5.5 mktemp(). ACE_OS::sprintf (xxxxxx, ACE_LIB_TEXT ("%05d%c"), ACE_OS::getpid (), unique_letter); while (ACE_OS::stat (s, &sb) >= 0) { if (++unique_letter <= ACE_LIB_TEXT ('z')) ACE_OS::sprintf (xxxxxx, ACE_LIB_TEXT ("%05d%c"), ACE_OS::getpid (), unique_letter); else { // maximum of 26 unique files per template, per process ACE_OS::sprintf (xxxxxx, ACE_LIB_TEXT ("%s"), ACE_LIB_TEXT ("")); return s; } } } return s; } } # endif /* ACE_LACKS_MKTEMP */ int ACE_OS::socket_init (int version_high, int version_low) { # if defined (ACE_WIN32) if (ACE_OS::socket_initialized_ == 0) { WORD version_requested = MAKEWORD (version_high, version_low); WSADATA wsa_data; int error = WSAStartup (version_requested, &wsa_data); if (error != 0) # if defined (ACE_HAS_WINCE) { wchar_t fmt[] = ACE_LIB_TEXT ("%s failed, WSAGetLastError returned %d"); wchar_t buf[80]; // @@ Eliminate magic number. ACE_OS::sprintf (buf, fmt, ACE_LIB_TEXT ("WSAStartup"), error); ::MessageBox (0, buf, ACE_LIB_TEXT ("WSAStartup failed!"), MB_OK); } # else ACE_OS::fprintf (stderr, "ACE_OS::socket_init; WSAStartup failed, " "WSAGetLastError returned %d\n", error); # endif /* ACE_HAS_WINCE */ ACE_OS::socket_initialized_ = 1; } # else ACE_UNUSED_ARG (version_high); ACE_UNUSED_ARG (version_low); # endif /* ACE_WIN32 */ return 0; } int ACE_OS::socket_fini (void) { # if defined (ACE_WIN32) if (ACE_OS::socket_initialized_ != 0) { if (WSACleanup () != 0) { int error = ::WSAGetLastError (); # if defined (ACE_HAS_WINCE) wchar_t fmt[] = ACE_LIB_TEXT ("%s failed, WSAGetLastError returned %d"); wchar_t buf[80]; // @@ Eliminate magic number. ACE_OS::sprintf (buf, fmt, ACE_LIB_TEXT ("WSACleanup"), error); ::MessageBox (0, buf , ACE_LIB_TEXT ("WSACleanup failed!"), MB_OK); # else ACE_OS::fprintf (stderr, "ACE_OS::socket_fini; WSACleanup failed, " "WSAGetLastError returned %d\n", error); # endif /* ACE_HAS_WINCE */ } ACE_OS::socket_initialized_ = 0; } # endif /* ACE_WIN32 */ return 0; } # if defined (ACE_LACKS_SYS_NERR) # if defined (__rtems__) int sys_nerr = EWOULDBLOCK + 1; // definitely a hack. # else int sys_nerr = ERRMAX + 1; # endif /* __rtems__ */ # endif /* ACE_LACKS_SYS_NERR */ # if defined (VXWORKS) # include /**/ /* for ::sp() */ // This global function can be used from the VxWorks shell to pass // arguments to a C main () function. // // usage: -> spa main, "arg1", "arg2" // // All arguments must be quoted, even numbers. int spa (FUNCPTR entry, ...) { static const unsigned int MAX_ARGS = 10; static char *argv[MAX_ARGS]; va_list pvar; unsigned int argc; // Hardcode a program name because the real one isn't available // through the VxWorks shell. argv[0] = "ace_main"; // Peel off arguments to spa () and put into argv. va_arg () isn't // necessarily supposed to return 0 when done, though since the // VxWorks shell uses a fixed number (10) of arguments, it might 0 // the unused ones. This function could be used to increase that // limit, but then it couldn't depend on the trailing 0. So, the // number of arguments would have to be passed. va_start (pvar, entry); for (argc = 1; argc <= MAX_ARGS; ++argc) { argv[argc] = va_arg (pvar, char *); if (argv[argc] == 0) break; } if (argc > MAX_ARGS && argv[argc-1] != 0) { // try to read another arg, and warn user if the limit was exceeded if (va_arg (pvar, char *) != 0) ACE_OS::fprintf (stderr, "spa(): number of arguments limited to %d\n", MAX_ARGS); } else { // fill unused argv slots with 0 to get rid of leftovers // from previous invocations for (unsigned int i = argc; i <= MAX_ARGS; ++i) argv[i] = 0; } // The hard-coded options are what ::sp () uses, except for the // larger stack size (instead of ::sp ()'s 20000). const int ret = ::taskSpawn (argv[0], // task name 100, // task priority VX_FP_TASK, // task options ACE_NEEDS_HUGE_THREAD_STACKSIZE, // stack size entry, // entry point argc, // first argument to main () (int) argv, // second argument to main () 0, 0, 0, 0, 0, 0, 0, 0); va_end (pvar); // ::taskSpawn () returns the taskID on success: return 0 instead if // successful return ret > 0 ? 0 : ret; } // A helper function for the extended spa functions static void add_to_argv (int& argc, char** argv, int max_args, char* string) { char indouble = 0; size_t previous = 0; size_t length = ACE_OS_String::strlen (string); // We use <= to make sure that we get the last argument for (size_t i = 0; i <= length; i++) { // Is it a double quote that hasn't been escaped? if (string[i] == '\"' && (i == 0 || string[i - 1] != '\\')) { indouble ^= 1; if (indouble) { // We have just entered a double quoted string, so // save the starting position of the contents. previous = i + 1; } else { // We have just left a double quoted string, so // zero out the ending double quote. string[i] = '\0'; } } else if (string[i] == '\\') // Escape the next character { // The next character is automatically // skipped because of the strcpy ACE_OS_String::strcpy (string + i, string + i + 1); length--; } else if (!indouble && (ACE_OS::ace_isspace (string[i]) || string[i] == '\0')) { string[i] = '\0'; if (argc < max_args) { argv[argc] = string + previous; argc++; } else { ACE_OS::fprintf (stderr, "spae(): number of arguments " "limited to %d\n", max_args); } // Skip over whitespace in between arguments for(++i; i < length && ACE_OS::ace_isspace (string[i]); ++i) { } // Save the starting point for the next time around previous = i; // Make sure we don't skip over a character due // to the above loop to skip over whitespace i--; } } } // This global function can be used from the VxWorks shell to pass // arguments to a C main () function. // // usage: -> spae main, "arg1 arg2 \"arg3 with spaces\"" // // All arguments must be within double quotes, even numbers. int spae (FUNCPTR entry, ...) { static const int WINDSH_ARGS = 10; static const int MAX_ARGS = 128; static char* argv[MAX_ARGS] = { "ace_main", 0 }; va_list pvar; int argc = 1; // Peel off arguments to spa () and put into argv. va_arg () isn't // necessarily supposed to return 0 when done, though since the // VxWorks shell uses a fixed number (10) of arguments, it might 0 // the unused ones. va_start (pvar, entry); int i = 0; for (char* str = va_arg (pvar, char*); str != 0 && i < WINDSH_ARGS; str = va_arg (pvar, char*), ++i) { add_to_argv(argc, argv, MAX_ARGS, str); } // fill unused argv slots with 0 to get rid of leftovers // from previous invocations for (i = argc; i < MAX_ARGS; ++i) argv[i] = 0; // The hard-coded options are what ::sp () uses, except for the // larger stack size (instead of ::sp ()'s 20000). const int ret = ::taskSpawn (argv[0], // task name 100, // task priority VX_FP_TASK, // task options ACE_NEEDS_HUGE_THREAD_STACKSIZE, // stack size entry, // entry point argc, // first argument to main () (int) argv, // second argument to main () 0, 0, 0, 0, 0, 0, 0, 0); va_end (pvar); // ::taskSpawn () returns the taskID on success: return 0 instead if // successful return ret > 0 ? 0 : ret; } // This global function can be used from the VxWorks shell to pass // arguments to a C main () function. The function will be run // within the shells task. // // usage: -> spaef main, "arg1 arg2 \"arg3 with spaces\"" // // All arguments must be within double quotes, even numbers. // Unlike the spae function, this fuction executes the supplied // routine in the foreground, rather than spawning it in a separate // task. int spaef (FUNCPTR entry, ...) { static const int WINDSH_ARGS = 10; static const int MAX_ARGS = 128; static char* argv[MAX_ARGS] = { "ace_main", 0 }; va_list pvar; int argc = 1; // Peel off arguments to spa () and put into argv. va_arg () isn't // necessarily supposed to return 0 when done, though since the // VxWorks shell uses a fixed number (10) of arguments, it might 0 // the unused ones. va_start (pvar, entry); int i = 0; for (char* str = va_arg (pvar, char*); str != 0 && i < WINDSH_ARGS; str = va_arg (pvar, char*), ++i) { add_to_argv(argc, argv, MAX_ARGS, str); } // fill unused argv slots with 0 to get rid of leftovers // from previous invocations for (i = argc; i < MAX_ARGS; ++i) argv[i] = 0; int ret = entry (argc, argv); va_end (pvar); // Return the return value of the invoked ace_main routine. return ret; } # endif /* VXWORKS */ # if !defined (ACE_HAS_SIGINFO_T) siginfo_t::siginfo_t (ACE_HANDLE handle) : si_handle_ (handle), si_handles_ (&handle) { } siginfo_t::siginfo_t (ACE_HANDLE *handles) : si_handle_ (handles[0]), si_handles_ (handles) { } # endif /* ACE_HAS_SIGINFO_T */ pid_t ACE_OS::fork (const ACE_TCHAR *program_name) { ACE_OS_TRACE ("ACE_OS::fork"); # if defined (ACE_LACKS_FORK) ACE_UNUSED_ARG (program_name); ACE_NOTSUP_RETURN (pid_t (-1)); # else pid_t pid = # if defined (ACE_HAS_STHREADS) ::fork1 (); #else ::fork (); #endif /* ACE_HAS_STHREADS */ #if !defined (ACE_HAS_MINIMAL_ACE_OS) if (pid == 0) ACE_Base_Thread_Adapter::sync_log_msg (program_name); #endif /* ! ACE_HAS_MINIMAL_ACE_OS */ return pid; # endif /* ACE_WIN32 */ } void ACE_Cleanup::cleanup (void *) { delete this; } ACE_Cleanup::~ACE_Cleanup (void) { } // This is necessary to work around nasty problems with MVS C++. extern "C" void ace_mutex_lock_cleanup_adapter (void *args) { ACE_OS::mutex_lock_cleanup (args); } ACE_Thread_ID::ACE_Thread_ID (ACE_thread_t thread_id, ACE_hthread_t thread_handle) : thread_id_ (thread_id), thread_handle_ (thread_handle) { } ACE_Thread_ID::ACE_Thread_ID (const ACE_Thread_ID &id) : thread_id_ (id.thread_id_), thread_handle_ (id.thread_handle_) { } ACE_thread_t ACE_Thread_ID::id (void) { return this->thread_id_; } void ACE_Thread_ID::id (ACE_thread_t thread_id) { this->thread_id_ = thread_id; } ACE_hthread_t ACE_Thread_ID::handle (void) { return this->thread_handle_; } void ACE_Thread_ID::handle (ACE_hthread_t thread_handle) { this->thread_handle_ = thread_handle; } int ACE_Thread_ID::operator== (const ACE_Thread_ID &rhs) const { return ACE_OS::thr_cmp (this->thread_handle_, rhs.thread_handle_) == 0 && ACE_OS::thr_equal (this->thread_id_, rhs.thread_id_) == 0; } int ACE_Thread_ID::operator!= (const ACE_Thread_ID &rhs) const { return !(*this == rhs); } // All other platforms have this inlined in OS.i #if defined (ACE_PSOS) char * ACE_OS::inet_ntoa (const struct in_addr addr) { ACE_OS_TRACE ("ACE_OS::inet_ntoa"); static char addrstr[INET_ADDRSTRLEN + 1] = { 0 }; ACE_UINT32 ipaddr = ntohl (addr.s_addr); //printf("Socket address %X, IP address %X.\n",addr.s_addr,ipaddr); sprintf(addrstr, "%d.%d.%d.%d", ((ipaddr & 0xff000000) >> 24) & 0x000000ff, (ipaddr & 0x00ff0000) >> 16, (ipaddr & 0x0000ff00) >> 8, (ipaddr & 0x000000ff)); return addrstr; } #endif /* defined (ACE_PSOS) */ int ACE_OS::inet_aton (const char *host_name, struct in_addr *addr) { #if defined (ACE_LACKS_INET_ATON) ACE_UINT32 ip_addr = ACE_OS::inet_addr (host_name); if (ip_addr == INADDR_NONE // Broadcast addresses are weird... && ACE_OS::strcmp (host_name, "255.255.255.255") != 0) return 0; else if (addr == 0) return 0; else { addr->s_addr = ip_addr; // Network byte ordered return 1; } #elif defined (VXWORKS) // inet_aton() returns 0 upon failure, not -1 since -1 is a valid // address (255.255.255.255). ACE_OSCALL_RETURN (::inet_aton ((char*)host_name, addr), int, 0); #else // inet_aton() returns 0 upon failure, not -1 since -1 is a valid // address (255.255.255.255). ACE_OSCALL_RETURN (::inet_aton (host_name, addr), int, 0); #endif /* ACE_LACKS_INET_ATON */ } struct tm * ACE_OS::localtime_r (const time_t *t, struct tm *res) { ACE_OS_TRACE ("ACE_OS::localtime_r"); #if defined (ACE_HAS_REENTRANT_FUNCTIONS) # if defined (DIGITAL_UNIX) ACE_OSCALL_RETURN (::_Plocaltime_r (t, res), struct tm *, 0); # elif defined (HPUX_10) return (::localtime_r (t, res) == 0 ? res : (struct tm *)0); # else ACE_OSCALL_RETURN (::localtime_r (t, res), struct tm *, 0); # endif /* DIGITAL_UNIX */ #elif !defined (ACE_HAS_WINCE) && !defined(ACE_PSOS) || defined (ACE_PSOS_HAS_TIME) ACE_OS_GUARD ACE_UNUSED_ARG (res); struct tm * res_ptr; ACE_OSCALL (::localtime (t), struct tm *, 0, res_ptr); if (res_ptr == 0) return 0; else { *res = *res_ptr; return res; } #elif defined (ACE_HAS_WINCE) // This is really stupid, converting FILETIME to timeval back and // forth. It assumes FILETIME and DWORDLONG are the same structure // internally. TIME_ZONE_INFORMATION pTz; const unsigned short int __mon_yday[2][13] = { /* Normal years. */ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, /* Leap years. */ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } }; ULARGE_INTEGER _100ns; ::GetTimeZoneInformation (&pTz); _100ns.QuadPart = (DWORDLONG) *t * 10000 * 1000 + ACE_Time_Value::FILETIME_to_timval_skew; FILETIME file_time; file_time.dwLowDateTime = _100ns.LowPart; file_time.dwHighDateTime = _100ns.HighPart; FILETIME localtime; SYSTEMTIME systime; FileTimeToLocalFileTime (&file_time, &localtime); FileTimeToSystemTime (&localtime, &systime); res->tm_hour = systime.wHour; if(pTz.DaylightBias!=0) res->tm_isdst = 1; else res->tm_isdst = 1; int iLeap; iLeap = (res->tm_year % 4 == 0 && (res->tm_year% 100 != 0 || res->tm_year % 400 == 0)); // based on leap select which group to use res->tm_mday = systime.wDay; res->tm_min = systime.wMinute; res->tm_mon = systime.wMonth; res->tm_sec = systime.wSecond; res->tm_wday = systime.wDayOfWeek; res->tm_yday = __mon_yday[iLeap][systime.wMonth] + systime.wDay; res->tm_year = systime.wYear;// this the correct year but bias the value to start at the 1900 res->tm_year = res->tm_year - 1900; return res; #else // @@ Same as ACE_OS::localtime (), you need to implement it // yourself. ACE_UNUSED_ARG (t); ACE_UNUSED_ARG (res); ACE_NOTSUP_RETURN (0); #endif /* ACE_HAS_REENTRANT_FUNCTIONS */ } ssize_t ACE_OS::pread (ACE_HANDLE handle, void *buf, size_t nbytes, off_t offset) { # if defined (ACE_HAS_P_READ_WRITE) # if defined (ACE_WIN32) ACE_OS_GUARD // Remember the original file pointer position DWORD original_position = ::SetFilePointer (handle, 0, 0, FILE_CURRENT); if (original_position == 0xFFFFFFFF) return -1; // Go to the correct position DWORD altered_position = ::SetFilePointer (handle, offset, 0, FILE_BEGIN); if (altered_position == 0xFFFFFFFF) return -1; DWORD bytes_read; # if defined (ACE_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0) OVERLAPPED overlapped; overlapped.Internal = 0; overlapped.InternalHigh = 0; overlapped.Offset = offset; overlapped.OffsetHigh = 0; overlapped.hEvent = 0; BOOL result = ::ReadFile (handle, buf, ACE_static_cast (DWORD, nbytes), &bytes_read, &overlapped); if (result == FALSE) { if (::GetLastError () != ERROR_IO_PENDING) return -1; else { result = ::GetOverlappedResult (handle, &overlapped, &bytes_read, TRUE); if (result == FALSE) return -1; } } # else /* ACE_HAS_WINNT4 && (ACE_HAS_WINNT4 != 0) */ BOOL result = ::ReadFile (handle, buf, nbytes, &bytes_read, 0); if (result == FALSE) return -1; # endif /* ACE_HAS_WINNT4 && (ACE_HAS_WINNT4 != 0) */ // Reset the original file pointer position if (::SetFilePointer (handle, original_position, 0, FILE_BEGIN) == 0xFFFFFFFF) return -1; return (ssize_t) bytes_read; # else /* ACE_WIN32 */ return ::pread (handle, buf, nbytes, offset); # endif /* ACE_WIN32 */ # else /* ACE_HAS_P_READ_WRITE */ ACE_OS_GUARD // Remember the original file pointer position off_t original_position = ACE_OS::lseek (handle, 0, SEEK_CUR); if (original_position == -1) return -1; // Go to the correct position off_t altered_position = ACE_OS::lseek (handle, offset, SEEK_SET); if (altered_position == -1) return -1; ssize_t bytes_read = ACE_OS::read (handle, buf, nbytes); if (bytes_read == -1) return -1; if (ACE_OS::lseek (handle, original_position, SEEK_SET) == -1) return -1; return bytes_read; # endif /* ACE_HAD_P_READ_WRITE */ } ssize_t ACE_OS::pwrite (ACE_HANDLE handle, const void *buf, size_t nbytes, off_t offset) { # if defined (ACE_HAS_P_READ_WRITE) # if defined (ACE_WIN32) ACE_OS_GUARD // Remember the original file pointer position DWORD original_position = ::SetFilePointer (handle, 0, 0, FILE_CURRENT); if (original_position == 0xFFFFFFFF) return -1; // Go to the correct position DWORD altered_position = ::SetFilePointer (handle, offset, 0, FILE_BEGIN); if (altered_position == 0xFFFFFFFF) return -1; DWORD bytes_written; # if defined (ACE_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0) OVERLAPPED overlapped; overlapped.Internal = 0; overlapped.InternalHigh = 0; overlapped.Offset = offset; overlapped.OffsetHigh = 0; overlapped.hEvent = 0; BOOL result = ::WriteFile (handle, buf, ACE_static_cast (DWORD, nbytes), &bytes_written, &overlapped); if (result == FALSE) { if (::GetLastError () != ERROR_IO_PENDING) return -1; else { result = ::GetOverlappedResult (handle, &overlapped, &bytes_written, TRUE); if (result == FALSE) return -1; } } # else /* ACE_HAS_WINNT4 && (ACE_HAS_WINNT4 != 0) */ BOOL result = ::WriteFile (handle, buf, nbytes, &bytes_written, 0); if (result == FALSE) return -1; # endif /* ACE_HAS_WINNT4 && (ACE_HAS_WINNT4 != 0) */ // Reset the original file pointer position if (::SetFilePointer (handle, original_position, 0, FILE_BEGIN) == 0xFFFFFFFF) return -1; return (ssize_t) bytes_written; # else /* ACE_WIN32 */ return ::pwrite (handle, buf, nbytes, offset); # endif /* ACE_WIN32 */ # else /* ACE_HAS_P_READ_WRITE */ ACE_OS_GUARD // Remember the original file pointer position off_t original_position = ACE_OS::lseek (handle, 0, SEEK_CUR); if (original_position == -1) return -1; // Go to the correct position off_t altered_position = ACE_OS::lseek (handle, offset, SEEK_SET); if (altered_position == -1) return -1; ssize_t bytes_written = ACE_OS::write (handle, buf, nbytes); if (bytes_written == -1) return -1; if (ACE_OS::lseek (handle, original_position, SEEK_SET) == -1) return -1; return bytes_written; # endif /* ACE_HAD_P_READ_WRITE */ } ACE_HANDLE ACE_OS::open (const char *filename, int mode, int perms, LPSECURITY_ATTRIBUTES sa) { ACE_OS_TRACE ("ACE_OS::open"); #if defined (ACE_WIN32) DWORD access = GENERIC_READ; if (ACE_BIT_ENABLED (mode, O_WRONLY)) access = GENERIC_WRITE; else if (ACE_BIT_ENABLED (mode, O_RDWR)) access = GENERIC_READ | GENERIC_WRITE; DWORD creation = OPEN_EXISTING; if ((mode & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL)) creation = CREATE_NEW; else if ((mode & (_O_CREAT | _O_TRUNC)) == (_O_CREAT | _O_TRUNC)) creation = CREATE_ALWAYS; else if (ACE_BIT_ENABLED (mode, _O_CREAT)) creation = OPEN_ALWAYS; else if (ACE_BIT_ENABLED (mode, _O_TRUNC)) creation = TRUNCATE_EXISTING; DWORD flags = 0; if (ACE_BIT_ENABLED (mode, _O_TEMPORARY)) flags |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY; if (ACE_BIT_ENABLED (mode, FILE_FLAG_WRITE_THROUGH)) flags |= FILE_FLAG_WRITE_THROUGH; if (ACE_BIT_ENABLED (mode, FILE_FLAG_OVERLAPPED)) flags |= FILE_FLAG_OVERLAPPED; if (ACE_BIT_ENABLED (mode, FILE_FLAG_NO_BUFFERING)) flags |= FILE_FLAG_NO_BUFFERING; if (ACE_BIT_ENABLED (mode, FILE_FLAG_RANDOM_ACCESS)) flags |= FILE_FLAG_RANDOM_ACCESS; if (ACE_BIT_ENABLED (mode, FILE_FLAG_SEQUENTIAL_SCAN)) flags |= FILE_FLAG_SEQUENTIAL_SCAN; if (ACE_BIT_ENABLED (mode, FILE_FLAG_DELETE_ON_CLOSE)) flags |= FILE_FLAG_DELETE_ON_CLOSE; if (ACE_BIT_ENABLED (mode, FILE_FLAG_BACKUP_SEMANTICS)) flags |= FILE_FLAG_BACKUP_SEMANTICS; if (ACE_BIT_ENABLED (mode, FILE_FLAG_POSIX_SEMANTICS)) flags |= FILE_FLAG_POSIX_SEMANTICS; ACE_MT (ACE_thread_mutex_t *ace_os_monitor_lock = 0;) if (ACE_BIT_ENABLED (mode, _O_APPEND)) { ACE_MT ( ace_os_monitor_lock = (ACE_thread_mutex_t *) ACE_OS_Object_Manager::preallocated_object[ ACE_OS_Object_Manager::ACE_OS_MONITOR_LOCK]; ACE_OS::thread_mutex_lock (ace_os_monitor_lock); ) } DWORD shared_mode = perms; #if defined (ACE_HAS_WINCE) ACE_HANDLE h = ::CreateFileW (ACE_Ascii_To_Wide (filename).wchar_rep (), access, shared_mode, ACE_OS::default_win32_security_attributes (sa), creation, flags, 0); #else /* ACE_HAS_WINCE */ ACE_HANDLE h = ::CreateFileA (filename, access, shared_mode, ACE_OS::default_win32_security_attributes (sa), creation, flags, 0); #endif /* ACE_HAS_WINCE */ if (ACE_BIT_ENABLED (mode, _O_APPEND)) { if (h != ACE_INVALID_HANDLE) { ::SetFilePointer (h, 0, 0, FILE_END); } ACE_MT (ACE_OS::thread_mutex_unlock (ace_os_monitor_lock);) } if (h == ACE_INVALID_HANDLE) ACE_FAIL_RETURN (h); else return h; #elif defined (ACE_PSOS) ACE_UNUSED_ARG (perms); ACE_UNUSED_ARG (sa); # if defined (ACE_PSOS_LACKS_PHILE) ACE_UNUSED_ARG (filename); return 0; # else unsigned long result, handle; result = ::open_f (&handle, ACE_const_cast(char *, filename), 0); if (result != 0) { // We need to clean this up...not 100% correct! // To correct we should handle all the cases of TRUNC and CREAT if ((result == 0x200B) && (ACE_BIT_ENABLED (mode, O_CREAT))) { result = ::create_f(ACE_const_cast(char *, filename),1,0); if (result != 0) { errno = result; return ACE_static_cast (ACE_HANDLE, -1); } else //File created...try to open it again { result = ::open_f (&handle, ACE_const_cast(char *, filename), 0); if (result != 0) { errno = result; return ACE_static_cast (ACE_HANDLE, -1); } } } else { errno = result; return ACE_static_cast (ACE_HANDLE, -1); } } return ACE_static_cast (ACE_HANDLE, handle); # endif /* defined (ACE_PSOS_LACKS_PHILE) */ #else ACE_UNUSED_ARG (sa); ACE_OSCALL_RETURN (::open (filename, mode, perms), ACE_HANDLE, -1); #endif /* ACE_WIN32 */ } #if defined (ACE_HAS_WCHAR) ACE_HANDLE ACE_OS::open (const wchar_t *filename, int mode, int perms, LPSECURITY_ATTRIBUTES sa) { #if defined (ACE_WIN32) // @@ (brunsch) Yuck, maybe there is a way to combine the code // here with the char version DWORD access = GENERIC_READ; if (ACE_BIT_ENABLED (mode, O_WRONLY)) access = GENERIC_WRITE; else if (ACE_BIT_ENABLED (mode, O_RDWR)) access = GENERIC_READ | GENERIC_WRITE; DWORD creation = OPEN_EXISTING; if ((mode & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL)) creation = CREATE_NEW; else if ((mode & (_O_CREAT | _O_TRUNC)) == (_O_CREAT | _O_TRUNC)) creation = CREATE_ALWAYS; else if (ACE_BIT_ENABLED (mode, _O_CREAT)) creation = OPEN_ALWAYS; else if (ACE_BIT_ENABLED (mode, _O_TRUNC)) creation = TRUNCATE_EXISTING; DWORD flags = 0; if (ACE_BIT_ENABLED (mode, _O_TEMPORARY)) flags |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY; if (ACE_BIT_ENABLED (mode, FILE_FLAG_WRITE_THROUGH)) flags |= FILE_FLAG_WRITE_THROUGH; if (ACE_BIT_ENABLED (mode, FILE_FLAG_OVERLAPPED)) flags |= FILE_FLAG_OVERLAPPED; if (ACE_BIT_ENABLED (mode, FILE_FLAG_NO_BUFFERING)) flags |= FILE_FLAG_NO_BUFFERING; if (ACE_BIT_ENABLED (mode, FILE_FLAG_RANDOM_ACCESS)) flags |= FILE_FLAG_RANDOM_ACCESS; if (ACE_BIT_ENABLED (mode, FILE_FLAG_SEQUENTIAL_SCAN)) flags |= FILE_FLAG_SEQUENTIAL_SCAN; if (ACE_BIT_ENABLED (mode, FILE_FLAG_DELETE_ON_CLOSE)) flags |= FILE_FLAG_DELETE_ON_CLOSE; if (ACE_BIT_ENABLED (mode, FILE_FLAG_BACKUP_SEMANTICS)) flags |= FILE_FLAG_BACKUP_SEMANTICS; if (ACE_BIT_ENABLED (mode, FILE_FLAG_POSIX_SEMANTICS)) flags |= FILE_FLAG_POSIX_SEMANTICS; ACE_MT (ACE_thread_mutex_t *ace_os_monitor_lock = 0;) if (ACE_BIT_ENABLED (mode, _O_APPEND)) { ACE_MT ( ace_os_monitor_lock = (ACE_thread_mutex_t *) ACE_OS_Object_Manager::preallocated_object[ ACE_OS_Object_Manager::ACE_OS_MONITOR_LOCK]; ACE_OS::thread_mutex_lock (ace_os_monitor_lock); ) } DWORD shared_mode = perms; ACE_HANDLE h = ::CreateFileW (filename, access, shared_mode, ACE_OS::default_win32_security_attributes (sa), creation, flags, 0); if (ACE_BIT_ENABLED (mode, _O_APPEND)) { if (h != ACE_INVALID_HANDLE) { ::SetFilePointer (h, 0, 0, FILE_END); } ACE_MT (ACE_OS::thread_mutex_unlock (ace_os_monitor_lock);) } if (h == ACE_INVALID_HANDLE) ACE_FAIL_RETURN (h); else return h; #else /* ACE_WIN32 */ // Just emulate with ascii version return ACE_OS::open (ACE_Wide_To_Ascii (filename).char_rep (), mode, perms, sa); #endif /* ACE_WIN32 */ } #endif /* ACE_HAS_WCHAR */ # if defined (ACE_LACKS_DIFFTIME) double ACE_OS::difftime (time_t t1, time_t t0) { /* return t1 - t0 in seconds */ struct tm tms[2], *ptms[2], temp; double seconds; double days; int swap = 0; /* extract the tm structure from time_t */ ptms[1] = gmtime_r (&t1, &tms[1]); if (ptms[1] == 0) return 0.0; ptms[0] = gmtime_r (&t0, &tms[0]); if (ptms[0] == 0) return 0.0; /* make sure t1 is > t0 */ if (tms[1].tm_year < tms[0].tm_year) swap = 1; else if (tms[1].tm_year == tms[0].tm_year) { if (tms[1].tm_yday < tms[0].tm_yday) swap = 1; else if (tms[1].tm_yday == tms[0].tm_yday) { if (tms[1].tm_hour < tms[0].tm_hour) swap = 1; else if (tms[1].tm_hour == tms[0].tm_hour) { if (tms[1].tm_min < tms[0].tm_min) swap = 1; else if (tms[1].tm_min == tms[0].tm_min) { if (tms[1].tm_sec < tms[0].tm_sec) swap = 1; } } } } if (swap) temp = tms[0], tms[0] = tms[1], tms[1] = temp; seconds = 0.0; if (tms[1].tm_year > tms[0].tm_year) { // Accumulate the time until t[0] catches up to t[1]'s year. seconds = 60 - tms[0].tm_sec; tms[0].tm_sec = 0; tms[0].tm_min += 1; seconds += 60 * (60 - tms[0].tm_min); tms[0].tm_min = 0; tms[0].tm_hour += 1; seconds += 60*60 * (24 - tms[0].tm_hour); tms[0].tm_hour = 0; tms[0].tm_yday += 1; # define ISLEAPYEAR(y) ((y)&3u?0:(y)%25u?1:(y)/25u&12?0:1) if (ISLEAPYEAR(tms[0].tm_year)) seconds += 60*60*24 * (366 - tms[0].tm_yday); else seconds += 60*60*24 * (365 - tms[0].tm_yday); tms[0].tm_yday = 0; tms[0].tm_year += 1; while (tms[1].tm_year > tms[0].tm_year) { if (ISLEAPYEAR(tms[0].tm_year)) seconds += 60*60*24 * 366; else seconds += 60*60*24 * 365; tms[0].tm_year += 1; } # undef ISLEAPYEAR } else { // Normalize if (tms[1].tm_sec < tms[0].tm_sec) { if (tms[1].tm_min == 0) { if (tms[1].tm_hour == 0) { tms[1].tm_yday -= 1; tms[1].tm_hour += 24; } tms[1].tm_hour -= 1; tms[1].tm_min += 60; } tms[1].tm_min -= 1; tms[1].tm_sec += 60; } tms[1].tm_sec -= tms[0].tm_sec; if (tms[1].tm_min < tms[0].tm_min) { if (tms[1].tm_hour == 0) { tms[1].tm_yday -= 1; tms[1].tm_hour += 24; } tms[1].tm_hour -= 1; tms[1].tm_min += 60; } tms[1].tm_min -= tms[0].tm_min; if (tms[1].tm_hour < tms[0].tm_hour) { tms[1].tm_yday -= 1; tms[1].tm_hour += 24; } tms[1].tm_hour -= tms[0].tm_hour; tms[1].tm_yday -= tms[0].tm_yday; } // accumulate the seconds seconds += tms[1].tm_sec; seconds += 60 * tms[1].tm_min; seconds += 60*60 * tms[1].tm_hour; seconds += 60*60*24 * tms[1].tm_yday; return seconds; } # endif /* ACE_LACKS_DIFFTIME */ # if defined (ACE_HAS_WINCE) ACE_TCHAR * ACE_OS::ctime_r (const time_t *clock, ACE_TCHAR *buf, int buflen) { // buflen must be at least 26 wchar_t long. if (buflen < 26) // Again, 26 is a magic number. { errno = ERANGE; return 0; } // This is really stupid, converting FILETIME to timeval back and // forth. It assumes FILETIME and DWORDLONG are the same structure // internally. ULARGE_INTEGER _100ns; _100ns.QuadPart = (DWORDLONG) *clock * 10000 * 1000 + ACE_Time_Value::FILETIME_to_timval_skew; FILETIME file_time; file_time.dwLowDateTime = _100ns.LowPart; file_time.dwHighDateTime = _100ns.HighPart; FILETIME localtime; SYSTEMTIME systime; FileTimeToLocalFileTime (&file_time, &localtime); FileTimeToSystemTime (&localtime, &systime); ACE_OS::sprintf (buf, ACE_OS_CTIME_R_FMTSTR, ACE_OS::day_of_week_name[systime.wDayOfWeek], ACE_OS::month_name[systime.wMonth - 1], systime.wDay, systime.wHour, systime.wMinute, systime.wSecond, systime.wYear); return buf; } # endif /* ACE_HAS_WINCE */ time_t ACE_OS::mktime (struct tm *t) { ACE_OS_TRACE ("ACE_OS::mktime"); # if defined (ACE_PSOS) && ! defined (ACE_PSOS_HAS_TIME) ACE_UNUSED_ARG (t); ACE_NOTSUP_RETURN (-1); # elif defined (ACE_HAS_WINCE) SYSTEMTIME t_sys; FILETIME t_file; t_sys.wSecond = t->tm_sec; t_sys.wMinute = t->tm_min; t_sys.wHour = t->tm_hour; t_sys.wDay = t->tm_mday; t_sys.wMonth = t->tm_mon + 1; // SYSTEMTIME is 1-indexed, tm is 0-indexed t_sys.wYear = t->tm_year + 1900; // SYSTEMTIME is real; tm is since 1900 t_sys.wDayOfWeek = t->tm_wday; // Ignored in below function call. if (SystemTimeToFileTime (&t_sys, &t_file) == 0) return -1; ACE_Time_Value tv (t_file); return tv.sec (); # else # if defined (ACE_HAS_THREADS) && !defined (ACE_HAS_MT_SAFE_MKTIME) ACE_OS_GUARD # endif /* ACE_HAS_THREADS && ! ACE_HAS_MT_SAFE_MKTIME */ ACE_OSCALL_RETURN (::mktime (t), time_t, (time_t) -1); # endif /* ACE_PSOS && ! ACE_PSOS_HAS_TIME */ } # if !defined (ACE_HAS_THREADS) || defined (ACE_LACKS_RWLOCK_T) int ACE_OS::rwlock_init (ACE_rwlock_t *rw, int type, const ACE_TCHAR *name, void *arg) { // ACE_OS_TRACE ("ACE_OS::rwlock_init"); # if defined (ACE_HAS_THREADS) && defined (ACE_LACKS_RWLOCK_T) // NT, POSIX, and VxWorks don't support this natively. ACE_UNUSED_ARG (name); int result = -1; // Since we cannot use the user specified name for all three // objects, we will create three completely new names. ACE_TCHAR name1[ACE_UNIQUE_NAME_LEN]; ACE_TCHAR name2[ACE_UNIQUE_NAME_LEN]; ACE_TCHAR name3[ACE_UNIQUE_NAME_LEN]; ACE_TCHAR name4[ACE_UNIQUE_NAME_LEN]; ACE_OS::unique_name ((const void *) &rw->lock_, name1, ACE_UNIQUE_NAME_LEN); ACE_OS::unique_name ((const void *) &rw->waiting_readers_, name2, ACE_UNIQUE_NAME_LEN); ACE_OS::unique_name ((const void *) &rw->waiting_writers_, name3, ACE_UNIQUE_NAME_LEN); ACE_OS::unique_name ((const void *) &rw->waiting_important_writer_, name4, ACE_UNIQUE_NAME_LEN); ACE_condattr_t attributes; if (ACE_OS::condattr_init (attributes, type) == 0) { if (ACE_OS::mutex_init (&rw->lock_, type, name1, (ACE_mutexattr_t *) arg) == 0 && ACE_OS::cond_init (&rw->waiting_readers_, attributes, name2, arg) == 0 && ACE_OS::cond_init (&rw->waiting_writers_, attributes, name3, arg) == 0 && ACE_OS::cond_init (&rw->waiting_important_writer_, attributes, name4, arg) == 0) { // Success! rw->ref_count_ = 0; rw->num_waiting_writers_ = 0; rw->num_waiting_readers_ = 0; rw->important_writer_ = 0; result = 0; } ACE_OS::condattr_destroy (attributes); } if (result == -1) { // Save/restore errno. ACE_Errno_Guard error (errno); ACE_OS::mutex_destroy (&rw->lock_); ACE_OS::cond_destroy (&rw->waiting_readers_); ACE_OS::cond_destroy (&rw->waiting_writers_); ACE_OS::cond_destroy (&rw->waiting_important_writer_); } return result; # else ACE_UNUSED_ARG (rw); ACE_UNUSED_ARG (type); ACE_UNUSED_ARG (name); ACE_UNUSED_ARG (arg); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_THREADS */ } # endif /* ! ACE_HAS_THREADS || ACE_LACKS_RWLOCK_T */ #if defined (ACE_LACKS_COND_T) && ! defined (ACE_PSOS_DIAB_MIPS) // NOTE: The ACE_OS::cond_* functions for some non-Unix platforms are // defined here either because they're too big to be inlined, or // to avoid use before definition if they were inline. int ACE_OS::cond_destroy (ACE_cond_t *cv) { ACE_OS_TRACE ("ACE_OS::cond_destroy"); # if defined (ACE_HAS_THREADS) # if defined (ACE_HAS_WTHREADS) ACE_OS::event_destroy (&cv->waiters_done_); # elif defined (VXWORKS) || defined (ACE_PSOS) ACE_OS::sema_destroy (&cv->waiters_done_); # endif /* VXWORKS */ ACE_OS::thread_mutex_destroy (&cv->waiters_lock_); return ACE_OS::sema_destroy (&cv->sema_); # else ACE_UNUSED_ARG (cv); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_THREADS */ } // @@ The following functions could be inlined if i could figure where // to put it among the #ifdefs! int ACE_OS::condattr_init (ACE_condattr_t &attributes, int type) { attributes.type = type; return 0; } int ACE_OS::condattr_destroy (ACE_condattr_t &) { return 0; } int ACE_OS::cond_init (ACE_cond_t *cv, ACE_condattr_t &attributes, const char *name, void *arg) { return ACE_OS::cond_init (cv, attributes.type, name, arg); } #if defined (ACE_HAS_WCHAR) int ACE_OS::cond_init (ACE_cond_t *cv, ACE_condattr_t &attributes, const wchar_t *name, void *arg) { return ACE_OS::cond_init (cv, attributes.type, name, arg); } #endif /* ACE_HAS_WCHAR */ int ACE_OS::cond_init (ACE_cond_t *cv, short type, const char *name, void *arg) { ACE_OS_TRACE ("ACE_OS::cond_init"); # if defined (ACE_HAS_THREADS) cv->waiters_ = 0; cv->was_broadcast_ = 0; int result = 0; if (ACE_OS::sema_init (&cv->sema_, 0, type, name, arg) == -1) result = -1; else if (ACE_OS::thread_mutex_init (&cv->waiters_lock_) == -1) result = -1; # if defined (VXWORKS) || defined (ACE_PSOS) else if (ACE_OS::sema_init (&cv->waiters_done_, 0, type) == -1) # else else if (ACE_OS::event_init (&cv->waiters_done_) == -1) # endif /* VXWORKS */ result = -1; return result; # else ACE_UNUSED_ARG (cv); ACE_UNUSED_ARG (type); ACE_UNUSED_ARG (name); ACE_UNUSED_ARG (arg); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_THREADS */ } #if defined (ACE_HAS_WCHAR) int ACE_OS::cond_init (ACE_cond_t *cv, short type, const wchar_t *name, void *arg) { ACE_OS_TRACE ("ACE_OS::cond_init"); # if defined (ACE_HAS_THREADS) cv->waiters_ = 0; cv->was_broadcast_ = 0; int result = 0; if (ACE_OS::sema_init (&cv->sema_, 0, type, name, arg) == -1) result = -1; else if (ACE_OS::thread_mutex_init (&cv->waiters_lock_) == -1) result = -1; # if defined (VXWORKS) || defined (ACE_PSOS) else if (ACE_OS::sema_init (&cv->waiters_done_, 0, type) == -1) # else else if (ACE_OS::event_init (&cv->waiters_done_) == -1) # endif /* VXWORKS */ result = -1; return result; # else ACE_UNUSED_ARG (cv); ACE_UNUSED_ARG (type); ACE_UNUSED_ARG (name); ACE_UNUSED_ARG (arg); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_THREADS */ } #endif /* ACE_HAS_WCHAR */ int ACE_OS::cond_signal (ACE_cond_t *cv) { ACE_OS_TRACE ("ACE_OS::cond_signal"); # if defined (ACE_HAS_THREADS) // If there aren't any waiters, then this is a no-op. Note that // this function *must* be called with the held // since other wise there is a race condition that can lead to the // lost wakeup bug... This is needed to ensure that the // value is not in an inconsistent internal state while being // updated by another thread. ACE_OS::thread_mutex_lock (&cv->waiters_lock_); int have_waiters = cv->waiters_ > 0; ACE_OS::thread_mutex_unlock (&cv->waiters_lock_); if (have_waiters != 0) return ACE_OS::sema_post (&cv->sema_); else return 0; // No-op # else ACE_UNUSED_ARG (cv); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_THREADS */ } int ACE_OS::cond_broadcast (ACE_cond_t *cv) { ACE_OS_TRACE ("ACE_OS::cond_broadcast"); # if defined (ACE_HAS_THREADS) // The must be locked before this call is made. // This is needed to ensure that and are // consistent relative to each other. ACE_OS::thread_mutex_lock (&cv->waiters_lock_); int have_waiters = 0; if (cv->waiters_ > 0) { // We are broadcasting, even if there is just one waiter... // Record the fact that we are broadcasting. This helps the // cond_wait() method know how to optimize itself. Be sure to // set this with the held. cv->was_broadcast_ = 1; have_waiters = 1; } ACE_OS::thread_mutex_unlock (&cv->waiters_lock_); int result = 0; if (have_waiters) { // Wake up all the waiters. if (ACE_OS::sema_post (&cv->sema_, cv->waiters_) == -1) result = -1; // Wait for all the awakened threads to acquire their part of // the counting semaphore. # if defined (VXWORKS) || defined (ACE_PSOS) else if (ACE_OS::sema_wait (&cv->waiters_done_) == -1) # else else if (ACE_OS::event_wait (&cv->waiters_done_) == -1) # endif /* VXWORKS */ result = -1; // This is okay, even without the held because // no other waiter threads can wake up to access it. cv->was_broadcast_ = 0; } return result; # else ACE_UNUSED_ARG (cv); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_THREADS */ } int ACE_OS::cond_wait (ACE_cond_t *cv, ACE_mutex_t *external_mutex) { ACE_OS_TRACE ("ACE_OS::cond_wait"); # if defined (ACE_HAS_THREADS) // Prevent race conditions on the count. ACE_OS::thread_mutex_lock (&cv->waiters_lock_); cv->waiters_++; ACE_OS::thread_mutex_unlock (&cv->waiters_lock_); int result = 0; # if defined (ACE_HAS_SIGNAL_OBJECT_AND_WAIT) if (external_mutex->type_ == USYNC_PROCESS) // This call will automatically release the mutex and wait on the semaphore. ACE_WIN32CALL (ACE_ADAPT_RETVAL (::SignalObjectAndWait (external_mutex->proc_mutex_, cv->sema_, INFINITE, FALSE), result), int, -1, result); else # endif /* ACE_HAS_SIGNAL_OBJECT_AND_WAIT */ { // We keep the lock held just long enough to increment the count of // waiters by one. Note that we can't keep it held across the call // to ACE_OS::sema_wait() since that will deadlock other calls to // ACE_OS::cond_signal(). if (ACE_OS::mutex_unlock (external_mutex) != 0) return -1; // Wait to be awakened by a ACE_OS::cond_signal() or // ACE_OS::cond_broadcast(). result = ACE_OS::sema_wait (&cv->sema_); } // Reacquire lock to avoid race conditions on the count. ACE_OS::thread_mutex_lock (&cv->waiters_lock_); // We're ready to return, so there's one less waiter. cv->waiters_--; int last_waiter = cv->was_broadcast_ && cv->waiters_ == 0; // Release the lock so that other collaborating threads can make // progress. ACE_OS::thread_mutex_unlock (&cv->waiters_lock_); if (result == -1) // Bad things happened, so let's just return below. /* NOOP */; # if defined (ACE_HAS_SIGNAL_OBJECT_AND_WAIT) else if (external_mutex->type_ == USYNC_PROCESS) { if (last_waiter) // This call atomically signals the event and // waits until it can acquire the mutex. This is important to // prevent unfairness. ACE_WIN32CALL (ACE_ADAPT_RETVAL (::SignalObjectAndWait (cv->waiters_done_, external_mutex->proc_mutex_, INFINITE, FALSE), result), int, -1, result); else // We must always regain the , even when // errors occur because that's the guarantee that we give to // our callers. ACE_OS::mutex_lock (external_mutex); return result; /* NOTREACHED */ } # endif /* ACE_HAS_SIGNAL_OBJECT_AND_WAIT */ // If we're the last waiter thread during this particular broadcast // then let all the other threads proceed. else if (last_waiter) # if defined (VXWORKS) || defined (ACE_PSOS) ACE_OS::sema_post (&cv->waiters_done_); # else ACE_OS::event_signal (&cv->waiters_done_); # endif /* VXWORKS */ // We must always regain the , even when errors // occur because that's the guarantee that we give to our callers. ACE_OS::mutex_lock (external_mutex); return result; # else ACE_UNUSED_ARG (cv); ACE_UNUSED_ARG (external_mutex); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_THREADS */ } int ACE_OS::cond_timedwait (ACE_cond_t *cv, ACE_mutex_t *external_mutex, ACE_Time_Value *timeout) { ACE_OS_TRACE ("ACE_OS::cond_timedwait"); # if defined (ACE_HAS_THREADS) // Handle the easy case first. if (timeout == 0) return ACE_OS::cond_wait (cv, external_mutex); # if defined (ACE_HAS_WTHREADS) || defined (VXWORKS) || defined (ACE_PSOS) // Prevent race conditions on the count. ACE_OS::thread_mutex_lock (&cv->waiters_lock_); cv->waiters_++; ACE_OS::thread_mutex_unlock (&cv->waiters_lock_); int result = 0; ACE_Errno_Guard error (errno, 0); int msec_timeout; if (timeout->sec () == 0 && timeout->usec () == 0) msec_timeout = 0; // Do a "poll." else { // Note that we must convert between absolute time (which is // passed as a parameter) and relative time (which is what // WaitForSingleObjects() expects). ACE_Time_Value relative_time (*timeout - ACE_OS::gettimeofday ()); // Watchout for situations where a context switch has caused the // current time to be > the timeout. if (relative_time < ACE_Time_Value::zero) msec_timeout = 0; else msec_timeout = relative_time.msec (); } # if defined (ACE_HAS_SIGNAL_OBJECT_AND_WAIT) if (external_mutex->type_ == USYNC_PROCESS) // This call will automatically release the mutex and wait on the // semaphore. result = ::SignalObjectAndWait (external_mutex->proc_mutex_, cv->sema_, msec_timeout, FALSE); else # endif /* ACE_HAS_SIGNAL_OBJECT_AND_WAIT */ { // We keep the lock held just long enough to increment the count // of waiters by one. Note that we can't keep it held across // the call to WaitForSingleObject since that will deadlock // other calls to ACE_OS::cond_signal(). if (ACE_OS::mutex_unlock (external_mutex) != 0) return -1; // Wait to be awakened by a ACE_OS::signal() or // ACE_OS::broadcast(). # if defined (ACE_WIN32) # if !defined (ACE_USES_WINCE_SEMA_SIMULATION) result = ::WaitForSingleObject (cv->sema_, msec_timeout); # else /* ACE_USES_WINCE_SEMA_SIMULATION */ // Can't use Win32 API on our simulated semaphores. result = ACE_OS::sema_wait (&cv->sema_, timeout); # endif /* ACE_USES_WINCE_SEMA_SIMULATION */ # elif defined (ACE_PSOS) // Inline the call to ACE_OS::sema_wait () because it takes an // ACE_Time_Value argument. Avoid the cost of that conversion . . . u_long ticks = (KC_TICKS2SEC * msec_timeout) / ACE_ONE_SECOND_IN_MSECS; //Tick set to 0 tells pSOS to wait forever is SM_WAIT is set. if(ticks == 0) result = ::sm_p (cv->sema_.sema_, SM_NOWAIT, ticks); //no timeout else result = ::sm_p (cv->sema_.sema_, SM_WAIT, ticks); # elif defined (VXWORKS) // Inline the call to ACE_OS::sema_wait () because it takes an // ACE_Time_Value argument. Avoid the cost of that conversion . . . int ticks_per_sec = ::sysClkRateGet (); int ticks = msec_timeout * ticks_per_sec / ACE_ONE_SECOND_IN_MSECS; result = ::semTake (cv->sema_.sema_, ticks); # endif /* ACE_WIN32 || VXWORKS */ } // Reacquire lock to avoid race conditions. ACE_OS::thread_mutex_lock (&cv->waiters_lock_); cv->waiters_--; int last_waiter = cv->was_broadcast_ && cv->waiters_ == 0; ACE_OS::thread_mutex_unlock (&cv->waiters_lock_); # if defined (ACE_WIN32) if (result != WAIT_OBJECT_0) { switch (result) { case WAIT_TIMEOUT: error = ETIME; break; default: error = ::GetLastError (); break; } result = -1; } # elif defined (ACE_PSOS) if (result != 0) { switch (result) { case ERR_TIMEOUT: // Timeout occured with SM_WAIT case ERR_NOMSG: // Didn't acquire semaphore w/ SM_NOWAIT (ticks=0) error = ETIME; break; default: error = errno; break; } result = -1; } # elif defined (VXWORKS) if (result == ERROR) { switch (errno) { case S_objLib_OBJ_TIMEOUT: error = ETIME; break; case S_objLib_OBJ_UNAVAILABLE: if (msec_timeout == 0) error = ETIME; break; default: error = errno; break; } result = -1; } # endif /* ACE_WIN32 || VXWORKS */ # if defined (ACE_HAS_SIGNAL_OBJECT_AND_WAIT) if (external_mutex->type_ == USYNC_PROCESS) { if (last_waiter) // This call atomically signals the event and // waits until it can acquire the mutex. This is important to // prevent unfairness. ACE_WIN32CALL (ACE_ADAPT_RETVAL (::SignalObjectAndWait (cv->waiters_done_, external_mutex->proc_mutex_, INFINITE, FALSE), result), int, -1, result); else // We must always regain the , even when // errors occur because that's the guarantee that we give to // our callers. ACE_OS::mutex_lock (external_mutex); return result; /* NOTREACHED */ } # endif /* ACE_HAS_SIGNAL_OBJECT_AND_WAIT */ // Note that this *must* be an "if" statement rather than an "else // if" statement since the caller may have timed out and hence the // result would have been -1 above. if (last_waiter) // Release the signaler/broadcaster if we're the last waiter. # if defined (ACE_WIN32) ACE_OS::event_signal (&cv->waiters_done_); # else ACE_OS::sema_post (&cv->waiters_done_); # endif /* ACE_WIN32 */ // We must always regain the , even when errors // occur because that's the guarantee that we give to our callers. ACE_OS::mutex_lock (external_mutex); return result; # endif /* ACE_HAS_WTHREADS || ACE_HAS_VXWORKS || ACE_PSOS */ # else ACE_UNUSED_ARG (cv); ACE_UNUSED_ARG (external_mutex); ACE_UNUSED_ARG (timeout); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_THREADS */ } # if defined (ACE_HAS_WTHREADS) int ACE_OS::cond_timedwait (ACE_cond_t *cv, ACE_thread_mutex_t *external_mutex, ACE_Time_Value *timeout) { ACE_OS_TRACE ("ACE_OS::cond_timedwait"); # if defined (ACE_HAS_THREADS) // Handle the easy case first. if (timeout == 0) return ACE_OS::cond_wait (cv, external_mutex); // Prevent race conditions on the count. ACE_OS::thread_mutex_lock (&cv->waiters_lock_); cv->waiters_++; ACE_OS::thread_mutex_unlock (&cv->waiters_lock_); int result = 0; int error = 0; int msec_timeout; if (timeout->sec () == 0 && timeout->usec () == 0) msec_timeout = 0; // Do a "poll." else { // Note that we must convert between absolute time (which is // passed as a parameter) and relative time (which is what // WaitForSingleObjects() expects). ACE_Time_Value relative_time (*timeout - ACE_OS::gettimeofday ()); // Watchout for situations where a context switch has caused the // current time to be > the timeout. if (relative_time < ACE_Time_Value::zero) msec_timeout = 0; else msec_timeout = relative_time.msec (); } // We keep the lock held just long enough to increment the count of // waiters by one. Note that we can't keep it held across the call // to WaitForSingleObject since that will deadlock other calls to // ACE_OS::cond_signal(). if (ACE_OS::thread_mutex_unlock (external_mutex) != 0) return -1; // Wait to be awakened by a ACE_OS::signal() or ACE_OS::broadcast(). # if defined (ACE_USES_WINCE_SEMA_SIMULATION) // Can't use Win32 API on simulated semaphores. result = ACE_OS::sema_wait (&cv->sema_, timeout); if (result == -1 && errno == ETIME) result = WAIT_TIMEOUT; # else result = ::WaitForSingleObject (cv->sema_, msec_timeout); # endif /* ACE_USES_WINCE_SEMA_SIMULATION */ // Reacquire lock to avoid race conditions. ACE_OS::thread_mutex_lock (&cv->waiters_lock_); cv->waiters_--; int last_waiter = cv->was_broadcast_ && cv->waiters_ == 0; ACE_OS::thread_mutex_unlock (&cv->waiters_lock_); if (result != WAIT_OBJECT_0) { switch (result) { case WAIT_TIMEOUT: error = ETIME; break; default: error = ::GetLastError (); break; } result = -1; } if (last_waiter) // Release the signaler/broadcaster if we're the last waiter. ACE_OS::event_signal (&cv->waiters_done_); // We must always regain the , even when errors // occur because that's the guarantee that we give to our callers. ACE_OS::thread_mutex_lock (external_mutex); errno = error; return result; # else ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_THREADS */ } int ACE_OS::cond_wait (ACE_cond_t *cv, ACE_thread_mutex_t *external_mutex) { ACE_OS_TRACE ("ACE_OS::cond_wait"); # if defined (ACE_HAS_THREADS) ACE_OS::thread_mutex_lock (&cv->waiters_lock_); cv->waiters_++; ACE_OS::thread_mutex_unlock (&cv->waiters_lock_); int result = 0; int error = 0; // We keep the lock held just long enough to increment the count of // waiters by one. Note that we can't keep it held across the call // to ACE_OS::sema_wait() since that will deadlock other calls to // ACE_OS::cond_signal(). if (ACE_OS::thread_mutex_unlock (external_mutex) != 0) return -1; // Wait to be awakened by a ACE_OS::cond_signal() or // ACE_OS::cond_broadcast(). # if !defined (ACE_USES_WINCE_SEMA_SIMULATION) result = ::WaitForSingleObject (cv->sema_, INFINITE); # else // Can't use Win32 API on simulated semaphores. result = ACE_OS::sema_wait (&cv->sema_); if (result != WAIT_OBJECT_0 && errno == ETIME) result = WAIT_TIMEOUT; # endif /* ACE_USES_WINCE_SEMA_SIMULATION */ // Reacquire lock to avoid race conditions. ACE_OS::thread_mutex_lock (&cv->waiters_lock_); cv->waiters_--; int last_waiter = cv->was_broadcast_ && cv->waiters_ == 0; ACE_OS::thread_mutex_unlock (&cv->waiters_lock_); if (result != WAIT_OBJECT_0) { switch (result) { case WAIT_TIMEOUT: error = ETIME; break; default: error = ::GetLastError (); break; } } else if (last_waiter) // Release the signaler/broadcaster if we're the last waiter. ACE_OS::event_signal (&cv->waiters_done_); // We must always regain the , even when errors // occur because that's the guarantee that we give to our callers. ACE_OS::thread_mutex_lock (external_mutex); // Reset errno in case mutex_lock() also fails... errno = error; return result; # else ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_THREADS */ } # endif /* ACE_HAS_WTHREADS */ #endif /* ACE_LACKS_COND_T */ void ACE_OS::exit (int status) { ACE_OS_TRACE ("ACE_OS::exit"); #if defined (ACE_HAS_NONSTATIC_OBJECT_MANAGER) && !defined (ACE_HAS_WINCE) && !defined (ACE_DOESNT_INSTANTIATE_NONSTATIC_OBJECT_MANAGER) // Shut down the ACE_Object_Manager, if it had registered its exit_hook. // With ACE_HAS_NONSTATIC_OBJECT_MANAGER, the ACE_Object_Manager is // instantiated on the main's stack. ::exit () doesn't destroy it. if (exit_hook_) (*exit_hook_) (); #endif /* ACE_HAS_NONSTATIC_OBJECT_MANAGER && !ACE_HAS_WINCE && !ACE_DOESNT_INSTANTIATE_NONSTATIC_OBJECT_MANAGER */ #if !defined (ACE_HAS_WINCE) # if defined (ACE_WIN32) ::ExitProcess ((UINT) status); # elif defined (ACE_PSOSIM) ::u_exit (status); # else ::exit (status); # endif /* ACE_WIN32 */ #else // @@ This is not exactly the same as ExitProcess. But this is the // closest one I can get. ::TerminateProcess (::GetCurrentProcess (), status); #endif /* ACE_HAS_WINCE */ } # if defined (ACE_PSOS) // bit masks and shifts for prying info out of the pSOS time encoding const u_long ACE_PSOS_Time_t::year_mask = 0x0000FFFFul; const u_long ACE_PSOS_Time_t::month_mask = 0x000000FFul; const u_long ACE_PSOS_Time_t::day_mask = 0x000000FFul; const u_long ACE_PSOS_Time_t::hour_mask = 0x0000FFFFul; const u_long ACE_PSOS_Time_t::minute_mask = 0x000000FFul; const u_long ACE_PSOS_Time_t::second_mask = 0x000000FFul; const int ACE_PSOS_Time_t::year_shift = 16; const int ACE_PSOS_Time_t::month_shift = 8; const int ACE_PSOS_Time_t::hour_shift = 16; const int ACE_PSOS_Time_t::minute_shift = 8; const int ACE_PSOS_Time_t::year_origin = 1900; const int ACE_PSOS_Time_t::month_origin = 1; // maximum number of clock ticks supported const u_long ACE_PSOS_Time_t::max_ticks = ~0UL; ACE_PSOS_Time_t::ACE_PSOS_Time_t (void) : date_ (0), time_ (0), ticks_ (0) { } // default ctor: date, time, and ticks all zeroed ACE_PSOS_Time_t::ACE_PSOS_Time_t (const timespec_t& t) { struct tm* tm_struct = ACE_OS::gmtime (&(t.tv_sec)); // Encode date values from tm struct into pSOS date bit array. date_ = (ACE_PSOS_Time_t::year_mask & ACE_static_cast (u_long, tm_struct->tm_year + ACE_PSOS_Time_t::year_origin)) << ACE_PSOS_Time_t::year_shift; date_ |= (ACE_PSOS_Time_t::month_mask & ACE_static_cast (u_long, tm_struct->tm_mon + ACE_PSOS_Time_t::month_origin)) << ACE_PSOS_Time_t::month_shift; date_ |= ACE_PSOS_Time_t::day_mask & ACE_static_cast (u_long, tm_struct->tm_mday); // Encode time values from tm struct into pSOS time bit array. time_ = (ACE_PSOS_Time_t::hour_mask & ACE_static_cast (u_long, tm_struct->tm_hour)) << ACE_PSOS_Time_t::hour_shift; time_ |= (ACE_PSOS_Time_t::minute_mask & ACE_static_cast (u_long, tm_struct->tm_min)) << ACE_PSOS_Time_t::minute_shift; time_ |= ACE_PSOS_Time_t::second_mask & ACE_static_cast (u_int, tm_struct->tm_sec); // encode nanoseconds as system clock ticks ticks_ = ACE_static_cast (u_long, ((ACE_static_cast (double, t.tv_nsec) * ACE_static_cast (double, KC_TICKS2SEC)) / ACE_static_cast (double, 1000000000))); } // ctor from a timespec_t ACE_PSOS_Time_t::operator timespec_t (void) { struct tm tm_struct; // Decode date and time bit arrays and fill in fields of tm_struct. tm_struct.tm_year = ACE_static_cast (int, (ACE_PSOS_Time_t::year_mask & (date_ >> ACE_PSOS_Time_t::year_shift))) - ACE_PSOS_Time_t::year_origin; tm_struct.tm_mon = ACE_static_cast (int, (ACE_PSOS_Time_t::month_mask & (date_ >> ACE_PSOS_Time_t::month_shift))) - ACE_PSOS_Time_t::month_origin; tm_struct.tm_mday = ACE_static_cast (int, (ACE_PSOS_Time_t::day_mask & date_)); tm_struct.tm_hour = ACE_static_cast (int, (ACE_PSOS_Time_t::hour_mask & (time_ >> ACE_PSOS_Time_t::hour_shift))); tm_struct.tm_min = ACE_static_cast (int, (ACE_PSOS_Time_t::minute_mask & (time_ >> ACE_PSOS_Time_t::minute_shift))); tm_struct.tm_sec = ACE_static_cast (int, (ACE_PSOS_Time_t::second_mask & time_)); // Indicate values we don't know as negative numbers. tm_struct.tm_wday = -1; tm_struct.tm_yday = -1; tm_struct.tm_isdst = -1; timespec_t t; // Convert calendar time to time struct. t.tv_sec = ACE_OS::mktime (&tm_struct); // Encode nanoseconds as system clock ticks. t.tv_nsec = ACE_static_cast (long, ((ACE_static_cast (double, ticks_) * ACE_static_cast (double, 1000000000)) / ACE_static_cast (double, KC_TICKS2SEC))); return t; } // type cast operator (to a timespec_t) u_long ACE_PSOS_Time_t::get_system_time (ACE_PSOS_Time_t& t) { u_long ret_val = 0; # if defined (ACE_PSOSIM) // system time is broken in simulator. timeval tv; int result = 0; ACE_OSCALL (::gettimeofday (&tv, 0), int, -1, result); if (result == -1) return 1; ACE_Time_Value atv (tv); timespec ts = atv; ACE_PSOS_Time_t pt (ts); t.date_ = pt.date_; t.time_ = pt.time_; t.ticks_ = pt.ticks_; # else ret_val = tm_get (&(t.date_), &(t.time_), &(t.ticks_)); # endif /* ACE_PSOSIM */ return ret_val; } // Static member function to get current system time. u_long ACE_PSOS_Time_t::set_system_time (const ACE_PSOS_Time_t& t) { return tm_set (t.date_, t.time_, t.ticks_); } // Static member function to set current system time. # if defined (ACE_PSOSIM) u_long ACE_PSOS_Time_t::init_simulator_time (void) { // This is a hack using a direct UNIX system call, because the // appropriate ACE_OS method ultimately uses the pSOS tm_get // function, which would fail because the simulator's system time is // uninitialized (chicken and egg). timeval t; int result = 0; ACE_OSCALL (::gettimeofday (&t, 0), int, -1, result); if (result == -1) return 1; else { ACE_Time_Value tv (t); timespec ts = tv; ACE_PSOS_Time_t pt (ts); u_long ret_val = ACE_PSOS_Time_t::set_system_time (pt); return ret_val; } } // Static member function to initialize system time, using UNIX calls. # endif /* ACE_PSOSIM */ # endif /* ACE_PSOS && ! ACE_PSOS_DIAB_MIPS */ # if defined (__DGUX) && defined (ACE_HAS_THREADS) && defined (_POSIX4A_DRAFT10_SOURCE) extern "C" int __d6_sigwait (sigset_t *set); extern "C" int __d10_sigwait (const sigset_t *set, int *sig) { sigset_t unconst_set = *set; int caught_sig = __d6_sigwait (&unconst_set); if (caught == -1) return -1; *sig = caught_sig; return 0; } # endif /* __DGUX && PTHREADS && _POSIX4A_DRAFT10_SOURCE */ # define ACE_OS_PREALLOCATE_OBJECT(TYPE, ID)\ {\ TYPE *obj_p = 0;\ ACE_NEW_RETURN (obj_p, TYPE, -1);\ preallocated_object[ID] = (void *) obj_p;\ } # define ACE_OS_DELETE_PREALLOCATED_OBJECT(TYPE, ID)\ delete (TYPE *) preallocated_object[ID];\ preallocated_object[ID] = 0; ACE_Object_Manager_Base::ACE_Object_Manager_Base (void) : object_manager_state_ (OBJ_MAN_UNINITIALIZED) , dynamically_allocated_ (0) , next_ (0) { } ACE_Object_Manager_Base::~ACE_Object_Manager_Base (void) { #if defined (ACE_HAS_NONSTATIC_OBJECT_MANAGER) // Clear the flag so that fini () doesn't delete again. dynamically_allocated_ = 0; #endif /* ACE_HAS_NONSTATIC_OBJECT_MANAGER */ } int ACE_Object_Manager_Base::starting_up_i () { return object_manager_state_ < OBJ_MAN_INITIALIZED; } int ACE_Object_Manager_Base::shutting_down_i () { return object_manager_state_ > OBJ_MAN_INITIALIZED; } extern "C" void ACE_OS_Object_Manager_Internal_Exit_Hook (void) { if (ACE_OS_Object_Manager::instance_) ACE_OS_Object_Manager::instance ()->fini (); } ACE_OS_Object_Manager *ACE_OS_Object_Manager::instance_ = 0; void *ACE_OS_Object_Manager::preallocated_object[ ACE_OS_Object_Manager::ACE_OS_PREALLOCATED_OBJECTS] = { 0 }; ACE_OS_Object_Manager::ACE_OS_Object_Manager (void) // default_mask_ isn't initialized, because it's defined by . : thread_hook_ (0) , exit_info_ () #if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS) , seh_except_selector_ (ACE_SEH_Default_Exception_Selector) , seh_except_handler_ (ACE_SEH_Default_Exception_Handler) #endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */ { // If instance_ was not 0, then another ACE_OS_Object_Manager has // already been instantiated (it is likely to be one initialized by // way of library/DLL loading). Let this one go through // construction in case there really is a good reason for it (like, // ACE is a static/archive library, and this one is the non-static // instance (with ACE_HAS_NONSTATIC_OBJECT_MANAGER, or the user has // a good reason for creating a separate one) but the original one // will be the one retrieved from calls to // ACE_Object_Manager::instance(). // Be sure that no further instances are created via instance (). if (instance_ == 0) instance_ = this; init (); } ACE_OS_Object_Manager::~ACE_OS_Object_Manager (void) { dynamically_allocated_ = 0; // Don't delete this again in fini() fini (); } sigset_t * ACE_OS_Object_Manager::default_mask (void) { return ACE_OS_Object_Manager::instance ()->default_mask_; } ACE_Thread_Hook * ACE_OS_Object_Manager::thread_hook (void) { return ACE_OS_Object_Manager::instance ()->thread_hook_; } #if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS) ACE_SEH_EXCEPT_HANDLER ACE_OS_Object_Manager::seh_except_selector (void) { return ACE_OS_Object_Manager::instance ()->seh_except_selector_; } ACE_SEH_EXCEPT_HANDLER ACE_OS_Object_Manager::seh_except_selector (ACE_SEH_EXCEPT_HANDLER n) { ACE_OS_Object_Manager *instance = ACE_OS_Object_Manager::instance (); ACE_SEH_EXCEPT_HANDLER retv = instance->seh_except_selector_; instance->seh_except_selector_ = n; return retv; } ACE_SEH_EXCEPT_HANDLER ACE_OS_Object_Manager::seh_except_handler (void) { return ACE_OS_Object_Manager::instance ()->seh_except_handler_; } ACE_SEH_EXCEPT_HANDLER ACE_OS_Object_Manager::seh_except_handler (ACE_SEH_EXCEPT_HANDLER n) { ACE_OS_Object_Manager *instance = ACE_OS_Object_Manager::instance (); ACE_SEH_EXCEPT_HANDLER retv = instance->seh_except_handler_; instance->seh_except_handler_ = n; return retv; } #endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */ ACE_Thread_Hook * ACE_OS_Object_Manager::thread_hook (ACE_Thread_Hook *new_thread_hook) { ACE_OS_Object_Manager *os_om = ACE_OS_Object_Manager::instance (); ACE_Thread_Hook *old_hook = os_om->thread_hook_; os_om->thread_hook_ = new_thread_hook; return old_hook; } ACE_OS_Object_Manager * ACE_OS_Object_Manager::instance (void) { // This function should be called during construction of static // instances, or before any other threads have been created in the // process. So, it's not thread safe. if (instance_ == 0) { ACE_OS_Object_Manager *instance_pointer; ACE_NEW_RETURN (instance_pointer, ACE_OS_Object_Manager, 0); // I (coryan) removed it, using asserts in the OS layer // brings down the Log msg stuff // ACE_ASSERT (instance_pointer == instance_); instance_pointer->dynamically_allocated_ = 1; } return instance_; } int ACE_OS_Object_Manager::init (void) { if (starting_up_i ()) { // First, indicate that this ACE_OS_Object_Manager instance is being // initialized. object_manager_state_ = OBJ_MAN_INITIALIZING; if (this == instance_) { # if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) # if defined (ACE_HAS_WINCE_BROKEN_ERRNO) ACE_CE_Errno::init (); # endif /* ACE_HAS_WINCE_BROKEN_ERRNO */ ACE_OS_PREALLOCATE_OBJECT (ACE_thread_mutex_t, ACE_OS_MONITOR_LOCK) if (ACE_OS::thread_mutex_init // This line must not be broken to avoid tickling a bug with SunC++'s preprocessor. (ACE_reinterpret_cast (ACE_thread_mutex_t *, ACE_OS_Object_Manager::preallocated_object[ACE_OS_MONITOR_LOCK])) != 0) ACE_OS_Object_Manager::print_error_message ( __LINE__, ACE_LIB_TEXT ("ACE_OS_MONITOR_LOCK")); ACE_OS_PREALLOCATE_OBJECT (ACE_recursive_thread_mutex_t, ACE_TSS_CLEANUP_LOCK) if (ACE_OS::recursive_mutex_init // This line must not be broken to avoid tickling a bug with SunC++'s preprocessor. (ACE_reinterpret_cast (ACE_recursive_thread_mutex_t *, ACE_OS_Object_Manager::preallocated_object[ACE_TSS_CLEANUP_LOCK])) != 0) ACE_OS_Object_Manager::print_error_message ( __LINE__, ACE_LIB_TEXT ("ACE_TSS_CLEANUP_LOCK")); ACE_OS_PREALLOCATE_OBJECT (ACE_thread_mutex_t, ACE_LOG_MSG_INSTANCE_LOCK) if (ACE_OS::thread_mutex_init // This line must not be broken to avoid tickling a bug with SunC++'s preprocessor. (ACE_reinterpret_cast (ACE_thread_mutex_t *, ACE_OS_Object_Manager::preallocated_object[ACE_LOG_MSG_INSTANCE_LOCK])) != 0) ACE_OS_Object_Manager::print_error_message ( __LINE__, ACE_LIB_TEXT ("ACE_LOG_MSG_INSTANCE_LOCK")); # if defined (ACE_HAS_TSS_EMULATION) ACE_OS_PREALLOCATE_OBJECT (ACE_recursive_thread_mutex_t, ACE_TSS_KEY_LOCK) if (ACE_OS::recursive_mutex_init // This line must not be broken to avoid tickling a bug with SunC++'s preprocessor. (ACE_reinterpret_cast (ACE_recursive_thread_mutex_t *, ACE_OS_Object_Manager::preallocated_object[ACE_TSS_KEY_LOCK])) != 0) ACE_OS_Object_Manager::print_error_message ( __LINE__, ACE_LIB_TEXT ("ACE_TSS_KEY_LOCK")); # if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) ACE_OS_PREALLOCATE_OBJECT (ACE_recursive_thread_mutex_t, ACE_TSS_BASE_LOCK) if (ACE_OS::recursive_mutex_init // This line must not be broken to avoid tickling a bug with SunC++'s preprocessor. (ACE_reinterpret_cast (ACE_recursive_thread_mutex_t *, ACE_OS_Object_Manager::preallocated_object[ACE_TSS_BASE_LOCK])) != 0) ACE_OS_Object_Manager::print_error_message ( __LINE__, ACE_LIB_TEXT ("ACE_TSS_BASE_LOCK")); # endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE */ # endif /* ACE_HAS_TSS_EMULATION */ # endif /* ACE_MT_SAFE */ // Open Winsock (no-op on other platforms). ACE_OS::socket_init (ACE_WSOCK_VERSION); // Register the exit hook, for use by ACE_OS::exit (). ACE_OS::set_exit_hook (&ACE_OS_Object_Manager_Internal_Exit_Hook); } ACE_NEW_RETURN (default_mask_, sigset_t, -1); ACE_OS::sigfillset (default_mask_); // Finally, indicate that the ACE_OS_Object_Manager instance has // been initialized. object_manager_state_ = OBJ_MAN_INITIALIZED; # if defined (ACE_WIN32) ACE_OS::win32_versioninfo_.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); ::GetVersionEx (&ACE_OS::win32_versioninfo_); # endif /* ACE_WIN32 */ return 0; } else { // Had already initialized. return 1; } } // Clean up an ACE_OS_Object_Manager. There can be instances of this object // other than The Instance. This can happen if a user creates one for some // reason. All objects clean up their per-object information and managed // objects, but only The Instance cleans up the static preallocated objects. int ACE_OS_Object_Manager::fini (void) { if (instance_ == 0 || shutting_down_i ()) // Too late. Or, maybe too early. Either fini () has already // been called, or init () was never called. return object_manager_state_ == OBJ_MAN_SHUT_DOWN ? 1 : -1; // No mutex here. Only the main thread should destroy the singleton // ACE_OS_Object_Manager instance. // Indicate that the ACE_OS_Object_Manager instance is being shut // down. This object manager should be the last one to be shut // down. object_manager_state_ = OBJ_MAN_SHUTTING_DOWN; // If another Object_Manager has registered for termination, do it. if (next_) { next_->fini (); next_ = 0; // Protect against recursive calls. } // Call all registered cleanup hooks, in reverse order of // registration. exit_info_.call_hooks (); // Only clean up preallocated objects when the singleton Instance is being // destroyed. if (this == instance_) { // Close down Winsock (no-op on other platforms). ACE_OS::socket_fini (); #if ! defined (ACE_HAS_STATIC_PREALLOCATION) // Cleanup the dynamically preallocated objects. # if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) # if !defined(ACE_HAS_BROKEN_PREALLOCATED_OBJECTS_AFTER_FORK) if (ACE_OS::thread_mutex_destroy // This line must not be broken to avoid tickling a bug with SunC++'s preprocessor. (ACE_reinterpret_cast (ACE_thread_mutex_t *, ACE_OS_Object_Manager::preallocated_object[ACE_OS_MONITOR_LOCK])) != 0) ACE_OS_Object_Manager::print_error_message ( __LINE__, ACE_LIB_TEXT ("ACE_OS_MONITOR_LOCK")); # endif /* ! ACE_HAS_BROKEN_PREALLOCATED_OBJECTS_AFTER_FORK */ ACE_OS_DELETE_PREALLOCATED_OBJECT (ACE_thread_mutex_t, ACE_OS_MONITOR_LOCK) # if !defined(ACE_HAS_BROKEN_PREALLOCATED_OBJECTS_AFTER_FORK) if (ACE_OS::recursive_mutex_destroy // This line must not be broken to avoid tickling a bug with SunC++'s preprocessor. (ACE_reinterpret_cast (ACE_recursive_thread_mutex_t *, ACE_OS_Object_Manager::preallocated_object[ACE_TSS_CLEANUP_LOCK])) != 0) ACE_OS_Object_Manager::print_error_message ( __LINE__, ACE_LIB_TEXT ("ACE_TSS_CLEANUP_LOCK")); # endif /* ! ACE_HAS_BROKEN_PREALLOCATED_OBJECTS_AFTER_FORK */ ACE_OS_DELETE_PREALLOCATED_OBJECT (ACE_recursive_thread_mutex_t, ACE_TSS_CLEANUP_LOCK) # if !defined(ACE_HAS_BROKEN_PREALLOCATED_OBJECTS_AFTER_FORK) if (ACE_OS::thread_mutex_destroy // This line must not be broken to avoid tickling a bug with SunC++'s preprocessor. (ACE_reinterpret_cast (ACE_thread_mutex_t *, ACE_OS_Object_Manager::preallocated_object [ACE_LOG_MSG_INSTANCE_LOCK])) != 0) ACE_OS_Object_Manager::print_error_message ( __LINE__, ACE_LIB_TEXT ("ACE_LOG_MSG_INSTANCE_LOCK ")); # endif /* ! ACE_HAS_BROKEN_PREALLOCATED_OBJECTS_AFTER_FORK */ ACE_OS_DELETE_PREALLOCATED_OBJECT (ACE_thread_mutex_t, ACE_LOG_MSG_INSTANCE_LOCK) # if defined (ACE_HAS_TSS_EMULATION) # if !defined(ACE_HAS_BROKEN_PREALLOCATED_OBJECTS_AFTER_FORK) if (ACE_OS::recursive_mutex_destroy // This line must not be broken to avoid tickling a bug with SunC++'s preprocessor. (ACE_reinterpret_cast (ACE_recursive_thread_mutex_t *, ACE_OS_Object_Manager::preallocated_object[ACE_TSS_KEY_LOCK])) != 0) ACE_OS_Object_Manager::print_error_message ( __LINE__, ACE_LIB_TEXT ("ACE_TSS_KEY_LOCK")); # endif /* ! ACE_HAS_BROKEN_PREALLOCATED_OBJECTS_AFTER_FORK */ ACE_OS_DELETE_PREALLOCATED_OBJECT (ACE_recursive_thread_mutex_t, ACE_TSS_KEY_LOCK) # if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) # if !defined(ACE_HAS_BROKEN_PREALLOCATED_OBJECTS_AFTER_FORK) if (ACE_OS::recursive_mutex_destroy // This line must not be broken to avoid tickling a bug with SunC++'s preprocessor. (ACE_reinterpret_cast (ACE_recursive_thread_mutex_t *, ACE_OS_Object_Manager::preallocated_object[ACE_TSS_BASE_LOCK])) != 0) ACE_OS_Object_Manager::print_error_message ( __LINE__, ACE_LIB_TEXT ("ACE_TSS_BASE_LOCK")); # endif /* ! ACE_HAS_BROKEN_PREALLOCATED_OBJECTS_AFTER_FORK */ ACE_OS_DELETE_PREALLOCATED_OBJECT (ACE_recursive_thread_mutex_t, ACE_TSS_BASE_LOCK) # endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE */ # endif /* ACE_HAS_TSS_EMULATION */ # if defined (ACE_HAS_WINCE_BROKEN_ERRNO) ACE_CE_Errno::fini (); # endif /* ACE_HAS_WINCE_BROKEN_ERRNO */ # endif /* ACE_MT_SAFE */ #endif /* ! ACE_HAS_STATIC_PREALLOCATION */ } delete default_mask_; default_mask_ = 0; // Indicate that this ACE_OS_Object_Manager instance has been shut down. object_manager_state_ = OBJ_MAN_SHUT_DOWN; if (dynamically_allocated_) { delete this; } if (this == instance_) instance_ = 0; return 0; } int ace_exit_hook_marker = 0; int ACE_OS_Object_Manager::at_exit (ACE_EXIT_HOOK func) { return exit_info_.at_exit_i (&ace_exit_hook_marker, ACE_reinterpret_cast (ACE_CLEANUP_FUNC, func), 0); } void ACE_OS_Object_Manager::print_error_message (u_int line_number, const ACE_TCHAR *message) { // To avoid duplication of these const strings in OS.o. #if !defined (ACE_HAS_WINCE) fprintf (stderr, "ace/OS.cpp, line %u: %s ", line_number, message); perror ("failed"); #else // @@ Need to use the following information. ACE_UNUSED_ARG (line_number); ACE_UNUSED_ARG (message); ACE_TCHAR *lpMsgBuf = 0; ::FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, ::GetLastError (), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (ACE_TCHAR *) &lpMsgBuf, 0, 0); ::MessageBox (NULL, lpMsgBuf, ACE_LIB_TEXT ("ACE_OS error"), MB_OK); #endif } int ACE_OS_Object_Manager::starting_up (void) { return ACE_OS_Object_Manager::instance_ ? instance_->starting_up_i () : 1; } int ACE_OS_Object_Manager::shutting_down (void) { return ACE_OS_Object_Manager::instance_ ? instance_->shutting_down_i () : 1; } #if !defined (ACE_HAS_NONSTATIC_OBJECT_MANAGER) /** * @class ACE_OS_Object_Manager_Manager * * @brief Ensure that the gets initialized at * program startup, and destroyed at program termination. * * Without ACE_HAS_NONSTATIC_OBJECT_MANAGER, a static instance of this * class is created. Therefore, it gets created before main () * is called. And it gets destroyed after main () returns. */ class ACE_OS_Object_Manager_Manager { public: /// Constructor. ACE_OS_Object_Manager_Manager (void); /// Destructor. ~ACE_OS_Object_Manager_Manager (void); private: /// Save the main thread ID, so that destruction can be suppressed. ACE_thread_t saved_main_thread_id_; }; ACE_OS_Object_Manager_Manager::ACE_OS_Object_Manager_Manager (void) : saved_main_thread_id_ (ACE_OS::thr_self ()) { // Ensure that the Object_Manager gets initialized before any // application threads have been spawned. Because this will be called // during construction of static objects, that should always be the // case. (void) ACE_OS_Object_Manager::instance (); } ACE_OS_Object_Manager_Manager::~ACE_OS_Object_Manager_Manager (void) { if (ACE_OS::thr_equal (ACE_OS::thr_self (), saved_main_thread_id_)) { delete ACE_OS_Object_Manager::instance_; ACE_OS_Object_Manager::instance_ = 0; } // else if this destructor is not called by the main thread, then do // not delete the ACE_OS_Object_Manager. That causes problems, on // WIN32 at least. } static ACE_OS_Object_Manager_Manager ACE_OS_Object_Manager_Manager_instance; #endif /* ! ACE_HAS_NONSTATIC_OBJECT_MANAGER */ # if defined (ACE_HAS_WINCE) ACE_CE_ARGV::ACE_CE_ARGV(ACE_TCHAR* cmdLine) : ce_argv_(0) , ce_argc_(0) { // Note: ACE has argv parser and processor; however, they cannot be // used because of dependency. ACE_OS is now separate from ACE, and // ACE depends on ACE_OS. Still, using all this array and complicated // pointer manipulation should be considered to be replaced and use STL // (or something) for better readability and code management. Also, // string_to_argv() does not work well for CE argv because of incorrect // '"' identification. const ACE_TCHAR* dummyArgv = ACE_TEXT("root"); // dummy for the first argv const ACE_TCHAR* separator = ACE_TEXT(" "); // blank space is a separator int formattedCmdLineLength = ACE_OS::strlen(dummyArgv) + ACE_OS::strlen(separator) + 1; // for 0 term. if (ACE_OS::strlen(cmdLine) > 0) { formattedCmdLineLength += ACE_OS::strlen(cmdLine); formattedCmdLineLength += ACE_OS::strlen(separator); } // formattedCmdLine will have dummyArgv and a separator at the beginning // of cmdLine and a separator at the end to generalize format and reduce // the amount of code. ACE_TCHAR* formattedCmdLine = 0; ACE_NEW(formattedCmdLine, ACE_TCHAR[formattedCmdLineLength]); ACE_OS::strcpy(formattedCmdLine, dummyArgv); ACE_OS::strcat(formattedCmdLine, separator); // start with 1 because of the dummyArgv at the beginning int max_possible_argc = 1; if (ACE_OS::strlen(cmdLine) > 0) { int formattedPos = ACE_OS::strlen(formattedCmdLine); int cmdLineLength = ACE_OS::strlen(cmdLine); // Inside of this for loop, it does same thing as strcat except it // checks and puts only one single white space between two argv entries. for (int i = 0; i < cmdLineLength; ++i) { if (iswspace(cmdLine[i]) != 0) ++max_possible_argc; // counting the number of white spaces formattedCmdLine[formattedPos++] = cmdLine[i]; if (iswspace(cmdLine[i]) != 0) { // make sure there is only one white space between two // argv entries. while ((i < cmdLineLength) && (iswspace(cmdLine[i + 1]) != 0)) ++i; } } formattedCmdLine[formattedPos] = 0; // make sure formattedCmdLine ends with a blank ACE_OS::strcat (formattedCmdLine, separator); } int formattedCmdLength = ACE_OS::strlen(formattedCmdLine); int insideQuotation = 0; int* argv_strlen = 0; int entry_size = 0; ACE_NEW (argv_strlen, int[max_possible_argc]); // determine argc for (int i = 0; i < formattedCmdLength; ++i) { if (formattedCmdLine[i] == '\\') { ++i; // ignore the following character ++entry_size; } else if (formattedCmdLine[i] == '"') { insideQuotation = (insideQuotation ? 0 : 1); } else if ((!insideQuotation) && (iswspace(formattedCmdLine[i]) != 0)) { // new argv entry end found argv_strlen[ce_argc_++] = entry_size; // cache this entry size entry_size = 0; } else { ++entry_size; } } ACE_NEW (ce_argv_, ACE_TCHAR*[ce_argc_ + 1]); ce_argv_[ce_argc_] = 0; // Last command line entry is a NULL. for (int j = 0, cmdLinePos = 0; j < ce_argc_; ++j, ++cmdLinePos) { int length = argv_strlen[j]; ACE_NEW (ce_argv_[j], ACE_TCHAR[length + 1]); ce_argv_[j][length] = 0; // string termination null if (iswspace (formattedCmdLine[cmdLinePos]) != 0) { // This is where prior argv has trailing '"' at the end. ++cmdLinePos; } for (int n = 0; n < length; ++n, ++cmdLinePos) { if ((formattedCmdLine[cmdLinePos] == '\\') || (formattedCmdLine[cmdLinePos] == '"') ) { ++cmdLinePos; } ce_argv_[j][n] = formattedCmdLine[cmdLinePos]; } } delete argv_strlen; delete formattedCmdLine; } ACE_CE_ARGV::~ACE_CE_ARGV(void) { for (int i = 0; i < ce_argc_; ++i) delete [] ce_argv_[i]; delete [] ce_argv_; } # endif // ACE_HAS_WINCE // You may be asking yourself, why are we doing this? Well, in winbase.h, // MS didn't follow their normal Api_FunctionA and Api_FunctionW style, // so we have to #undef their define to get access to the unicode version. // And because we don't want to #undef this for the users code, we keep // this method in the .cpp file. #if defined (ACE_WIN32) && defined (UNICODE) && !defined (ACE_USES_TCHAR) #undef GetEnvironmentStrings #endif /* ACE_WIN32 && UNICODE !ACE_USES_TCHAR */ ACE_TCHAR * ACE_OS::getenvstrings (void) { #if defined (ACE_LACKS_ENV) ACE_NOTSUP_RETURN (0); #elif defined (ACE_WIN32) # if defined (ACE_USES_WCHAR) return ::GetEnvironmentStringsW (); # else /* ACE_USES_WCHAR */ return ::GetEnvironmentStrings (); # endif /* ACE_USES_WCHAR */ #else /* ACE_WIN32 */ ACE_NOTSUP_RETURN (0); #endif /* ACE_WIN32 */ } #if defined (ACE_HAS_STRPTIME) char * ACE_OS::strptime (char *buf, const char *format, struct tm *tm) { #if !defined (ACE_HAS_WINCE) #if defined (ACE_LACKS_NATIVE_STRPTIME) int bi = 0; int fi = 0; int percent = 0; if (!buf || !format) return 0; while (format[fi] != '\0') { if (percent) { percent = 0; switch (format[fi]) { case '%': // an escaped % if (buf[bi] == '%') { fi++; bi++; } else return buf + bi; break; /* not supported yet: weekday via locale long/short names case 'a': / * weekday via locale * / / * FALL THROUGH * / case 'A': / * long/short names * / break; */ /* not supported yet: case 'b': / * month via locale * / / * FALL THROUGH * / case 'B': / * long/short names * / / * FALL THROUGH * / case 'h': break; */ /* not supported yet: case 'c': / * %x %X * / break; */ /* not supported yet: case 'C': / * date & time - * / / * locale long format * / break; */ case 'd': /* day of month (1-31) */ /* FALL THROUGH */ case 'e': if (!ACE_OS::strptime_getnum (buf + bi, &tm->tm_mday, &bi, &fi, 1, 31)) return buf + bi; break; case 'D': /* %m/%d/%y */ if (!ACE_OS::strptime_getnum (buf + bi, &tm->tm_mon, &bi, &fi, 1, 12)) return buf + bi; fi--; tm->tm_mon--; if (buf[bi] != '/') return buf + bi; bi++; if (!ACE_OS::strptime_getnum (buf + bi, &tm->tm_mday, &bi, &fi, 1, 31)) return buf + bi; fi--; if (buf[bi] != '/') return buf + bi; bi++; if (!ACE_OS::strptime_getnum (buf + bi, &tm->tm_year, &bi, &fi, 0, 99)) return buf + bi; if (tm->tm_year < 69) tm->tm_year += 100; break; case 'H': /* hour (0-23) */ /* FALL THROUGH */ case 'k': if (!ACE_OS::strptime_getnum (buf + bi, &tm->tm_hour, &bi, &fi, 0, 23)) return buf + bi; break; /* not supported yet: case 'I': / * hour (0-12) * / / * FALL THROUGH * / case 'l': break; */ case 'j': /* day of year (0-366) */ if (!ACE_OS::strptime_getnum (buf + bi, &tm->tm_yday, &bi, &fi, 1, 366)) return buf + bi; tm->tm_yday--; break; case 'm': /* an escaped % */ if (!ACE_OS::strptime_getnum (buf + bi, &tm->tm_mon, &bi, &fi, 1, 12)) return buf + bi; tm->tm_mon--; break; case 'M': /* minute (0-59) */ if (!ACE_OS::strptime_getnum (buf + bi, &tm->tm_min, &bi, &fi, 0, 59)) return buf + bi; break; /* not supported yet: case 'p': / * am or pm for locale * / break; */ /* not supported yet: case 'r': / * %I:%M:%S %p * / break; */ case 'R': /* %H:%M */ if (!ACE_OS::strptime_getnum (buf + bi, &tm->tm_hour, &bi, &fi, 0, 23)) return buf + bi; fi--; if (buf[bi] != ':') return buf + bi; bi++; if (!ACE_OS::strptime_getnum (buf + bi, &tm->tm_min, &bi, &fi, 0, 59)) return buf + bi; break; case 'S': /* seconds (0-61) */ if (!ACE_OS::strptime_getnum (buf + bi, &tm->tm_sec, &bi, &fi, 0, 61)) return buf + bi; break; case 'T': /* %H:%M:%S */ if (!ACE_OS::strptime_getnum (buf + bi, &tm->tm_hour, &bi, &fi, 0, 23)) return buf + bi; fi--; if (buf[bi] != ':') return buf + bi; bi++; if (!ACE_OS::strptime_getnum (buf + bi, &tm->tm_min, &bi, &fi, 0, 59)) return buf + bi; fi--; if (buf[bi] != ':') return buf + bi; bi++; if (!ACE_OS::strptime_getnum (buf + bi, &tm->tm_sec, &bi, &fi, 0, 61)) return buf + bi; break; case 'w': /* day of week (0=Sun-6) */ if (!ACE_OS::strptime_getnum (buf + bi, &tm->tm_wday, &bi, &fi, 0, 6)) return buf + bi; break; /* not supported yet: date, based on locale case 'x': / * date, based on locale * / break; */ /* not supported yet: case 'X': / * time, based on locale * / break; */ case 'y': /* the year - 1900 (0-99) */ if (!ACE_OS::strptime_getnum (buf + bi, &tm->tm_year, &bi, &fi, 0, 99)) return buf + bi; if (tm->tm_year < 69) tm->tm_year += 100; break; case 'Y': /* the full year (1999) */ if (!ACE_OS::strptime_getnum (buf + bi, &tm->tm_year, &bi, &fi, 0, 0)) return buf + bi; tm->tm_year -= 1900; break; default: /* unrecognised */ return buf + bi; } /* switch (format[fi]) */ } else { /* if (percent) */ if (format[fi] == '%') { percent = 1; fi++; } else { if (format[fi] == buf[bi]) { fi++; bi++; } else return buf + bi; } } /* if (percent) */ } /* while (format[fi] */ return buf + bi; #else /* ! ACE_LACKS_NATIVE_STRPTIME */ return ::strptime (buf, format, tm); #endif /* ! ACE_LACKS_NATIVE_STRPTIME */ #else /* ! ACE_HAS_WINCE */ ACE_UNUSED_ARG (buf); ACE_UNUSED_ARG (format); ACE_UNUSED_ARG (tm); ACE_NOTSUP_RETURN (0); #endif /* ! ACE_HAS_WINCE */ } # if defined (ACE_LACKS_NATIVE_STRPTIME) int ACE_OS::strptime_getnum (char *buf, int *num, int *bi, int *fi, int min, int max) { int i = 0, tmp = 0; while (isdigit (buf[i])) { tmp = (tmp * 10) + (buf[i] - '0'); if (max && (tmp > max)) return 0; i++; } if (tmp < min) return 0; else if (i) { *num = tmp; (*fi)++; *bi += i; return 1; } else return 0; } # endif /* ACE_LACKS_NATIVE_STRPTIME */ #endif /* ACE_HAS_STRPTIME */ #if !defined (ACE_HAS_WINCE) ACE_HANDLE ACE_OS::accept (ACE_HANDLE handle, struct sockaddr *addr, int *addrlen, const ACE_Accept_QoS_Params &qos_params) { # if defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0) ACE_SOCKCALL_RETURN (::WSAAccept ((ACE_SOCKET) handle, addr, (ACE_SOCKET_LEN *) addrlen, (LPCONDITIONPROC) qos_params.qos_condition_callback (), qos_params.callback_data ()), ACE_HANDLE, ACE_INVALID_HANDLE); # else ACE_UNUSED_ARG (qos_params); return ACE_OS::accept (handle, addr, addrlen); # endif /* ACE_HAS_WINSOCK2 */ } ACE_HANDLE ACE_OS::join_leaf (ACE_HANDLE socket, const sockaddr *name, int namelen, const ACE_QoS_Params &qos_params) { # if defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0) QOS qos; // Construct the WinSock2 QOS structure. qos.SendingFlowspec = *(qos_params.socket_qos ()->sending_flowspec ()); qos.ReceivingFlowspec = *(qos_params.socket_qos ()->receiving_flowspec ()); qos.ProviderSpecific = (WSABUF) qos_params.socket_qos ()->provider_specific (); ACE_SOCKCALL_RETURN (::WSAJoinLeaf ((ACE_SOCKET) socket, name, namelen, (WSABUF *) qos_params.caller_data (), (WSABUF *) qos_params.callee_data (), &qos, (QOS *) qos_params.group_socket_qos (), qos_params.flags ()), ACE_HANDLE, ACE_INVALID_HANDLE); # else ACE_UNUSED_ARG (socket); ACE_UNUSED_ARG (name); ACE_UNUSED_ARG (namelen); ACE_UNUSED_ARG (qos_params); ACE_NOTSUP_RETURN (ACE_INVALID_HANDLE); # endif /* ACE_HAS_WINSOCK2 */ } int ACE_OS::ioctl (ACE_HANDLE socket, u_long io_control_code, void *in_buffer_p, u_long in_buffer, void *out_buffer_p, u_long out_buffer, u_long *bytes_returned, ACE_OVERLAPPED *overlapped, ACE_OVERLAPPED_COMPLETION_FUNC func) { # if defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0) ACE_SOCKCALL_RETURN (::WSAIoctl ((ACE_SOCKET) socket, io_control_code, in_buffer_p, in_buffer, out_buffer_p, out_buffer, bytes_returned, (WSAOVERLAPPED *) overlapped, func), int, SOCKET_ERROR); # else ACE_UNUSED_ARG (socket); ACE_UNUSED_ARG (io_control_code); ACE_UNUSED_ARG (in_buffer_p); ACE_UNUSED_ARG (in_buffer); ACE_UNUSED_ARG (out_buffer_p); ACE_UNUSED_ARG (out_buffer); ACE_UNUSED_ARG (bytes_returned); ACE_UNUSED_ARG (overlapped); ACE_UNUSED_ARG (func); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_WINSOCK2 */ } int ACE_OS::ioctl (ACE_HANDLE socket, u_long io_control_code, ACE_QoS &ace_qos, u_long *bytes_returned, void *buffer_p, u_long buffer, ACE_OVERLAPPED *overlapped, ACE_OVERLAPPED_COMPLETION_FUNC func) { # if defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0) QOS qos; u_long qos_len = sizeof (QOS); if (io_control_code == SIO_SET_QOS) { qos.SendingFlowspec = *(ace_qos.sending_flowspec ()); qos.ReceivingFlowspec = *(ace_qos.receiving_flowspec ()); qos.ProviderSpecific = (WSABUF) ace_qos.provider_specific (); qos_len += ace_qos.provider_specific ().iov_len; ACE_SOCKCALL_RETURN (::WSAIoctl ((ACE_SOCKET) socket, io_control_code, &qos, qos_len, buffer_p, buffer, bytes_returned, (WSAOVERLAPPED *) overlapped, func), int, SOCKET_ERROR); } else { u_long dwBufferLen = 0; // Query for the buffer size. int result = ::WSAIoctl ((ACE_SOCKET) socket, io_control_code, NULL, 0, &dwBufferLen, sizeof (dwBufferLen), bytes_returned, NULL, NULL); if (result == SOCKET_ERROR) { u_long dwErr = ::WSAGetLastError (); if (dwErr == WSAEWOULDBLOCK) { errno = dwErr; return -1; } else if (dwErr != WSAENOBUFS) { errno = dwErr; return -1; } } char *qos_buf; ACE_NEW_RETURN (qos_buf, char [dwBufferLen], -1); QOS *qos = ACE_reinterpret_cast (QOS*, qos_buf); result = ::WSAIoctl ((ACE_SOCKET) socket, io_control_code, NULL, 0, qos, dwBufferLen, bytes_returned, NULL, NULL); if (result == SOCKET_ERROR) return result; ACE_Flow_Spec sending_flowspec (qos->SendingFlowspec.TokenRate, qos->SendingFlowspec.TokenBucketSize, qos->SendingFlowspec.PeakBandwidth, qos->SendingFlowspec.Latency, qos->SendingFlowspec.DelayVariation, # if defined(ACE_HAS_WINSOCK2_GQOS) qos->SendingFlowspec.ServiceType, qos->SendingFlowspec.MaxSduSize, qos->SendingFlowspec.MinimumPolicedSize, # else /* ACE_HAS_WINSOCK2_GQOS */ 0, 0, 0, # endif /* ACE_HAS_WINSOCK2_GQOS */ 0, 0); ACE_Flow_Spec receiving_flowspec (qos->ReceivingFlowspec.TokenRate, qos->ReceivingFlowspec.TokenBucketSize, qos->ReceivingFlowspec.PeakBandwidth, qos->ReceivingFlowspec.Latency, qos->ReceivingFlowspec.DelayVariation, # if defined(ACE_HAS_WINSOCK2_GQOS) qos->ReceivingFlowspec.ServiceType, qos->ReceivingFlowspec.MaxSduSize, qos->ReceivingFlowspec.MinimumPolicedSize, # else /* ACE_HAS_WINSOCK2_GQOS */ 0, 0, 0, # endif /* ACE_HAS_WINSOCK2_GQOS */ 0, 0); ace_qos.sending_flowspec (&sending_flowspec); ace_qos.receiving_flowspec (&receiving_flowspec); ace_qos.provider_specific (*((struct iovec *) (&qos->ProviderSpecific))); return result; } # else ACE_UNUSED_ARG (socket); ACE_UNUSED_ARG (io_control_code); ACE_UNUSED_ARG (ace_qos); ACE_UNUSED_ARG (bytes_returned); ACE_UNUSED_ARG (buffer_p); ACE_UNUSED_ARG (buffer); ACE_UNUSED_ARG (overlapped); ACE_UNUSED_ARG (func); ACE_NOTSUP_RETURN (-1); # endif /* ACE_HAS_WINSOCK2 */ } int ACE_OS::connect (ACE_HANDLE handle, const sockaddr *addr, int addrlen, const ACE_QoS_Params &qos_params) { ACE_OS_TRACE ("ACE_OS::connect"); # if defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0) ACE_SOCKCALL_RETURN (::WSAConnect ((ACE_SOCKET) handle, (const sockaddr *) addr, (ACE_SOCKET_LEN) addrlen, (WSABUF *) qos_params.caller_data (), (WSABUF *) qos_params.callee_data (), (QOS *) qos_params.socket_qos (), (QOS *) qos_params.group_socket_qos ()), int, -1); # else ACE_UNUSED_ARG (qos_params); return ACE_OS::connect (handle, (sockaddr *) addr, addrlen); # endif /* ACE_HAS_WINSOCK2 */ } #endif // ACE_HAS_WINCE long ACE_OS::num_processors (void) { ACE_OS_TRACE ("ACE_OS::num_processors"); #if defined (ACE_WIN32) || defined (ACE_WIN64) SYSTEM_INFO sys_info; ::GetSystemInfo (&sys_info); return sys_info.dwNumberOfProcessors; #elif defined (linux) || defined (sun) return ::sysconf (_SC_NPROCESSORS_CONF); #else ACE_NOTSUP_RETURN (-1); #endif } long ACE_OS::num_processors_online (void) { ACE_OS_TRACE ("ACE_OS::num_processors_online"); #if defined (ACE_WIN32) || defined (ACE_WIN64) SYSTEM_INFO sys_info; ::GetSystemInfo (&sys_info); return sys_info.dwNumberOfProcessors; #elif defined (linux) || defined (sun) return ::sysconf (_SC_NPROCESSORS_ONLN); #elif defined (__hpux) struct pst_dynamic psd; if (::pstat_getdynamic (&psd, sizeof (psd), (size_t) 1, 0) != -1) return psd.psd_proc_cnt; else return -1; #else ACE_NOTSUP_RETURN (-1); #endif }