diff options
Diffstat (limited to 'ACE/ace/OS_NS_unistd.cpp')
-rw-r--r-- | ACE/ace/OS_NS_unistd.cpp | 776 |
1 files changed, 776 insertions, 0 deletions
diff --git a/ACE/ace/OS_NS_unistd.cpp b/ACE/ace/OS_NS_unistd.cpp new file mode 100644 index 00000000000..c3080ffcfae --- /dev/null +++ b/ACE/ace/OS_NS_unistd.cpp @@ -0,0 +1,776 @@ +// $Id$ + +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(ace, OS_NS_unistd, "$Id$") + +#if !defined (ACE_HAS_INLINED_OSCALLS) +# include "ace/OS_NS_unistd.inl" +#endif /* ACE_HAS_INLINED_OSCALLS */ + +#include "ace/Base_Thread_Adapter.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_ctype.h" +#include "ace/Default_Constants.h" +#include "ace/OS_Memory.h" +#include "ace/OS_NS_Thread.h" +#include "ace/Object_Manager_Base.h" +#include "ace/os_include/sys/os_pstat.h" +#include "ace/os_include/sys/os_sysctl.h" + +#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, reinterpret_cast <long> (&fl)); +} +#endif /* ACE_NEEDS_FTRUNCATE */ + +/*****************************************************************************/ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +int +ACE_OS::argv_to_string (ACE_TCHAR **argv, + ACE_TCHAR *&buf, + bool 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++) + { +#if !defined (ACE_LACKS_ENV) + // Account for environment variables. + if (substitute_env_args && argv[i][0] == ACE_LIB_TEXT ('$')) + { +# if defined (ACE_WIN32) || !defined (ACE_HAS_WCHAR) + ACE_TCHAR *temp = 0; + // Win32 is the only platform with a wide-char ACE_OS::getenv(). + if ((temp = ACE_OS::getenv (&argv[i][1])) != 0) + buf_len += ACE_OS::strlen (temp); + else + buf_len += ACE_OS::strlen (argv[i]); +# else + // This is an ACE_HAS_WCHAR platform and not ACE_WIN32. + // Convert the env variable name for getenv(), then add + // the length of the returned char *string. Later, when we + // actually use the returned env variable value, convert it + // as well. + char *ctemp = ACE_OS::getenv (ACE_TEXT_ALWAYS_CHAR (&argv[i][1])); + if (ctemp == 0) + buf_len += ACE_OS::strlen (argv[i]); + else + buf_len += ACE_OS::strlen (ctemp); +# endif /* ACE_WIN32 || !ACE_HAS_WCHAR */ + } + else +#endif /* ACE_LACKS_ENV */ + buf_len += ACE_OS::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++) + { + +#if !defined (ACE_LACKS_ENV) + // Account for environment variables. + if (substitute_env_args && argv[j][0] == ACE_LIB_TEXT ('$')) + { +# if defined (ACE_WIN32) || !defined (ACE_HAS_WCHAR) + // Win32 is the only platform with a wide-char ACE_OS::getenv(). + ACE_TCHAR *temp = ACE_OS::getenv (&argv[j][1]); + if (temp != 0) + end = ACE_OS::strecpy (end, temp); + else + end = ACE_OS::strecpy (end, argv[j]); +# else + // This is an ACE_HAS_WCHAR platform and not ACE_WIN32. + // Convert the env variable name for getenv(), then convert + // the returned char *string back to wchar_t. + char *ctemp = ACE_OS::getenv (ACE_TEXT_ALWAYS_CHAR (&argv[j][1])); + if (ctemp == 0) + end = ACE_OS::strecpy (end, argv[j]); + else + end = ACE_OS::strecpy (end, ACE_TEXT_CHAR_TO_TCHAR (ctemp)); +# endif /* ACE_WIN32 || !ACE_HAS_WCHAR */ + } + 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::execl (const char * /* path */, const char * /* arg0 */, ...) +{ + ACE_OS_TRACE ("ACE_OS::execl"); + ACE_NOTSUP_RETURN (-1); + // Need to write this code. + // ACE_OSCALL_RETURN (::execv (path, argv), int, -1); +} + +int +ACE_OS::execle (const char * /* path */, const char * /* arg0 */, ...) +{ + ACE_OS_TRACE ("ACE_OS::execle"); + ACE_NOTSUP_RETURN (-1); + // Need to write this code. + // ACE_OSCALL_RETURN (::execve (path, argv, envp), int, -1); +} + +int +ACE_OS::execlp (const char * /* file */, const char * /* arg0 */, ...) +{ + ACE_OS_TRACE ("ACE_OS::execlp"); + ACE_NOTSUP_RETURN (-1); + // Need to write this code. + // ACE_OSCALL_RETURN (::execvp (file, argv), int, -1); +} + +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 const 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 */ +} + +// 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 = 0; + + 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; +# else + pid_t const result = ACE_OS::fork (); + +# if defined (ACE_USES_WCHAR) + // Wide-char builds need to convert the command-line args to + // narrow char strings for execv(). + char **cargv = 0; + int arg_count; +# endif /* ACE_HAS_WCHAR */ + + switch (result) + { + case -1: + // Error. + return -1; + case 0: + // Child process. +# if defined (ACE_USES_WCHAR) + for (arg_count = 0; argv[arg_count] != 0; ++arg_count) + ; + ++arg_count; // Need a 0-pointer end-of-array marker + ACE_NEW_NORETURN (cargv, char*[arg_count]); + if (cargv == 0) + ACE_OS::exit (errno); + --arg_count; // Back to 0-indexed + cargv[arg_count] = 0; + while (--arg_count >= 0) + cargv[arg_count] = ACE_Wide_To_Ascii::convert (argv[arg_count]); + // Don't worry about freeing the cargv or the strings it points to. + // Either the process will be replaced, or we'll exit. + if (ACE_OS::execv (cargv[0], cargv) == -1) + ACE_OS::exit (errno); +# else + 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); + } +# endif /* ACE_HAS_WCHAR */ + + default: + // Server process. The fork succeeded. + return result; + } +# endif /* ACE_WIN32 */ +} + +long +ACE_OS::num_processors (void) +{ + ACE_OS_TRACE ("ACE_OS::num_processors"); + +#if defined (ACE_HAS_PHARLAP) + return 1; +#elif defined (ACE_WIN32) + SYSTEM_INFO sys_info; + ::GetSystemInfo (&sys_info); + return sys_info.dwNumberOfProcessors; +#elif defined (_SC_NPROCESSORS_CONF) + return ::sysconf (_SC_NPROCESSORS_CONF); +#elif defined (ACE_HAS_SYSCTL) + int num_processors; + int mib[2] = { CTL_HW, HW_NCPU }; + size_t len = sizeof (num_processors); + + sysctl(mib, 2, &num_processors, &len, NULL, 0); + return num_processors; +#else + ACE_NOTSUP_RETURN (-1); +#endif +} + +long +ACE_OS::num_processors_online (void) +{ + ACE_OS_TRACE ("ACE_OS::num_processors_online"); + +#if defined (ACE_HAS_PHARLAP) + return 1; +#elif defined (ACE_WIN32) + SYSTEM_INFO sys_info; + ::GetSystemInfo (&sys_info); + return sys_info.dwNumberOfProcessors; +#elif defined (_SC_NPROCESSORS_ONLN) + return ::sysconf (_SC_NPROCESSORS_ONLN); +#elif defined (ACE_HAS_SYSCTL) + int num_processors; + int mib[2] = { CTL_HW, HW_NCPU }; + size_t len = sizeof (num_processors); + + sysctl(mib, 2, &num_processors, &len, NULL, 0); + return num_processors; +#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 +} + +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; +} + +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, + 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, + ACE_LOFF_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 + LARGE_INTEGER loffset; + loffset.QuadPart = offset; + DWORD altered_position = ::SetFilePointerEx (handle, + loffset, + 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, + 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 */ +} + +int +ACE_OS::string_to_argv (ACE_TCHAR *buf, + int &argc, + ACE_TCHAR **&argv, + bool 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 != ACE_LIB_TEXT ('\0') && *cp != ACE_LIB_TEXT ('#')) + { + // Skip whitespace.. + while (ACE_OS::ace_isspace (*cp)) + cp++; + + // Increment count and move to next whitespace.. + if (*cp != ACE_LIB_TEXT ('\0')) + argc++; + + while (*cp != ACE_LIB_TEXT ('\0') && !ACE_OS::ace_isspace (*cp)) + { + // Grok quotes.... + if (*cp == ACE_LIB_TEXT ('\'') || *cp == ACE_LIB_TEXT ('"')) + { + ACE_TCHAR quote = *cp; + + // Scan past the string.. + for (cp++; *cp != ACE_LIB_TEXT ('\0') && *cp != quote; cp++) + continue; + + // '\0' implies unmatched quote.. + if (*cp == ACE_LIB_TEXT ('\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 != ACE_LIB_TEXT ('\0') && !ACE_OS::ace_isspace (*ptr)) + if (*ptr == ACE_LIB_TEXT ('\'') || *ptr == ACE_LIB_TEXT ('"')) + { + ACE_TCHAR quote = *ptr++; + + while (*ptr != ACE_LIB_TEXT ('\0') && *ptr != quote) + *cp++ = *ptr++; + + if (*ptr == quote) + ptr++; + } + else + *cp++ = *ptr++; + + *cp = ACE_LIB_TEXT ('\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; +} + +// Write <len> bytes from <buf> to <handle> (uses the <write> +// system call on UNIX and the <WriteFile> 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; +} + +ACE_END_VERSIONED_NAMESPACE_DECL |