1 #include "ace/OS_NS_unistd.h"
3 #if !defined (ACE_HAS_INLINED_OSCALLS)
4 # include "ace/OS_NS_unistd.inl"
5 #endif /* ACE_HAS_INLINED_OSCALLS */
7 #include "ace/Base_Thread_Adapter.h"
8 #include "ace/OS_NS_stdlib.h"
9 #include "ace/OS_NS_ctype.h"
10 #include "ace/Default_Constants.h"
11 #include "ace/OS_Memory.h"
12 #include "ace/OS_NS_Thread.h"
13 #include "ace/Object_Manager_Base.h"
14 #if defined (ACE_HAS_SYSCTL)
15 # include "ace/os_include/sys/os_sysctl.h"
16 #endif /* ACE_HAS_SYSCTL */
18 #if defined ACE_HAS_VXCPULIB
19 # include "vxCpuLib.h"
21 #endif /* ACE_HAS_VXCPULIB */
25 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
28 ACE_OS::argv_to_string (ACE_TCHAR
**argv
,
30 bool substitute_env_args
,
33 if (argv
== 0 || argv
[0] == 0)
37 for (argc
= 0; argv
[argc
] != 0; ++argc
)
40 return argv_to_string (argc
,
48 ACE_OS::argv_to_string (int argc
,
51 bool substitute_env_args
,
54 if (argc
<= 0 || argv
== 0 || argv
[0] == 0)
59 // Determine the length of the buffer.
61 ACE_TCHAR
**argv_p
= argv
;
63 for (int i
= 0; i
< argc
; ++i
)
65 // Account for environment variables.
66 if (substitute_env_args
67 && ACE_OS::strchr (argv
[i
], ACE_TEXT ('$')) != 0)
71 #if defined (ACE_HAS_ALLOC_HOOKS)
72 argv_p
= (ACE_TCHAR
**) ACE_Allocator::instance()->malloc (argc
* sizeof (ACE_TCHAR
*));
74 argv_p
= (ACE_TCHAR
**) ACE_OS::malloc (argc
* sizeof (ACE_TCHAR
*));
75 #endif /* ACE_HAS_ALLOC_HOOKS */
81 ACE_OS::memcpy (argv_p
, argv
, argc
* sizeof (ACE_TCHAR
*));
83 argv_p
[i
] = ACE_OS::strenvdup (argv
[i
]);
86 #if defined (ACE_HAS_ALLOC_HOOKS)
87 ACE_Allocator::instance()->free (argv_p
);
89 ACE_OS::free (argv_p
);
90 #endif /* ACE_HAS_ALLOC_HOOKS */
95 // If must quote, we only do it if the arg contains spaces, or
96 // is empty. Perhaps a check for other c | ord(c) <= 32 is in
99 && (ACE_OS::strchr (argv_p
[i
], ACE_TEXT (' ')) != 0
100 || ACE_OS::strchr (argv_p
[i
], ACE_TEXT ('\t')) != 0
101 || ACE_OS::strchr (argv_p
[i
], ACE_TEXT ('\n')) != 0
106 #if defined (ACE_HAS_ALLOC_HOOKS)
107 argv_p
= (ACE_TCHAR
**) ACE_Allocator::instance()->malloc (argc
* sizeof (ACE_TCHAR
*));
109 argv_p
= (ACE_TCHAR
**) ACE_OS::malloc (argc
* sizeof (ACE_TCHAR
*));
110 #endif /* ACE_HAS_ALLOC_HOOKS */
116 ACE_OS::memcpy (argv_p
, argv
, argc
* sizeof (ACE_TCHAR
*));
119 ACE_TCHAR
*temp
= argv_p
[i
];
120 if (ACE_OS::strchr (temp
, ACE_TEXT ('"')) != 0)
122 for (int j
= 0; temp
[j
] != 0; ++j
)
123 if (temp
[j
] == ACE_TEXT ('"'))
127 #if defined (ACE_HAS_ALLOC_HOOKS)
128 (ACE_TCHAR
*) ACE_Allocator::instance()->malloc ((ACE_OS::strlen (temp
) + quotes
+ 3)
129 * sizeof (ACE_TCHAR
));
131 (ACE_TCHAR
*) ACE_OS::malloc ((ACE_OS::strlen (temp
) + quotes
+ 3)
132 * sizeof (ACE_TCHAR
));
133 #endif /* ACE_HAS_ALLOC_HOOKS */
136 #if defined (ACE_HAS_ALLOC_HOOKS)
137 ACE_Allocator::instance()->free (argv_p
);
139 ACE_OS::free (argv_p
);
140 #endif /* ACE_HAS_ALLOC_HOOKS */
144 ACE_TCHAR
*end
= argv_p
[i
];
146 *end
++ = ACE_TEXT ('"');
150 for (ACE_TCHAR
*p
= temp
;
153 if (*p
== ACE_TEXT ('"'))
154 *end
++ = ACE_TEXT ('\\');
156 *end
++ = ACE_TEXT ('\0');
159 end
= ACE_OS::strecpy (end
, temp
);
161 end
[-1] = ACE_TEXT ('"');
163 *end
= ACE_TEXT ('\0');
165 #if defined (ACE_HAS_ALLOC_HOOKS)
166 ACE_Allocator::instance()->free (temp
);
169 #endif /* ACE_HAS_ALLOC_HOOKS */
171 buf_len
+= ACE_OS::strlen (argv_p
[i
]);
173 // Add one for the extra space between each string.
177 // Step through all argv params and copy each one into buf; separate
178 // each param with white space.
180 #if defined (ACE_HAS_ALLOC_HOOKS)
181 ACE_ALLOCATOR_RETURN (buf
,
182 static_cast<ACE_TCHAR
*>(ACE_Allocator::instance()->malloc(sizeof(ACE_TCHAR
) * (buf_len
+ 1))),
186 ACE_TCHAR
[buf_len
+ 1],
188 #endif /* ACE_HAS_ALLOC_HOOKS */
190 // Initial null charater to make it a null string.
191 buf
[0] = ACE_TEXT ('\0');
192 ACE_TCHAR
*end
= buf
;
194 for (int i
= 0; i
< argc
; ++i
)
196 end
= ACE_OS::strecpy (end
, argv_p
[i
]);
197 if (argv_p
[i
] != argv
[i
])
198 #if defined (ACE_HAS_ALLOC_HOOKS)
199 ACE_Allocator::instance()->free (argv_p
[i
]);
201 ACE_OS::free (argv_p
[i
]);
202 #endif /* ACE_HAS_ALLOC_HOOKS */
204 // Replace the null char that strecpy put there with white
206 end
[-1] = ACE_TEXT (' ');
208 // Null terminate the string.
209 *end
= ACE_TEXT ('\0');
212 #if defined (ACE_HAS_ALLOC_HOOKS)
213 ACE_Allocator::instance()->free (argv_p
);
215 ACE_OS::free (argv_p
);
216 #endif /* ACE_HAS_ALLOC_HOOKS */
218 // The number of arguments.
223 ACE_OS::execl (const char * /* path */, const char * /* arg0 */, ...)
225 ACE_OS_TRACE ("ACE_OS::execl");
226 ACE_NOTSUP_RETURN (-1);
227 // Need to write this code.
228 // return ::execv (path, argv);
232 ACE_OS::execle (const char * /* path */, const char * /* arg0 */, ...)
234 ACE_OS_TRACE ("ACE_OS::execle");
235 ACE_NOTSUP_RETURN (-1);
236 // Need to write this code.
237 // return ::execve (path, argv, envp);
241 ACE_OS::execlp (const char * /* file */, const char * /* arg0 */, ...)
243 ACE_OS_TRACE ("ACE_OS::execlp");
244 ACE_NOTSUP_RETURN (-1);
245 // Need to write this code.
246 // return ::execvp (file, argv);
250 ACE_OS::fork (const ACE_TCHAR
*program_name
)
252 ACE_OS_TRACE ("ACE_OS::fork");
253 # if defined (ACE_LACKS_FORK)
254 ACE_UNUSED_ARG (program_name
);
255 ACE_NOTSUP_RETURN (pid_t (-1));
257 pid_t
const pid
= ::fork ();
259 #if !defined (ACE_HAS_MINIMAL_ACE_OS) && !defined (ACE_HAS_THREADS)
261 // ACE_Base_Thread_Adapter::sync_log_msg() is used to update the
262 // program name and process id in ACE's log framework. However, we
263 // can't invoke it from (the child process of) threaded programs
264 // because it calls async signal unsafe functions, which will result
265 // in undefined behavior (only async signal safe functions can be
266 // called after fork() until an exec()).
268 // This is no great loss. Using the ACE log framework in the child
269 // process will undoubtedly call async signal unsafe functions too.
270 // So it doesn't really matter that the program name and process id
271 // will not be updated.
274 ACE_Base_Thread_Adapter::sync_log_msg (program_name
);
278 ACE_UNUSED_ARG (program_name
);
280 #endif /* ! ACE_HAS_MINIMAL_ACE_OS && !ACE_HAS_THREADS */
283 # endif /* ACE_WIN32 */
286 // Create a contiguous command-line argument buffer with each arg
287 // separated by spaces.
290 ACE_OS::fork_exec (ACE_TCHAR
*argv
[])
292 # if defined (ACE_WIN32)
295 std::unique_ptr
<ACE_TCHAR
[]> safe_ptr (buf
);
296 if (ACE_OS::argv_to_string (argv
, buf
) != -1)
298 PROCESS_INFORMATION process_info
;
299 ACE_TEXT_STARTUPINFO startup_info
;
300 ACE_OS::memset ((void *) &startup_info
,
302 sizeof startup_info
);
303 startup_info
.cb
= sizeof startup_info
;
305 if (ACE_TEXT_CreateProcess (0,
307 0, // No process attributes.
308 0, // No thread attributes.
309 TRUE
, // Allow handle inheritance.
310 0, // Don't create a new console window.
311 0, // No environment.
312 0, // No current directory.
316 // Free resources allocated in kernel.
317 ACE_OS::close (process_info
.hThread
);
318 ACE_OS::close (process_info
.hProcess
);
319 // Return new process id.
320 return process_info
.dwProcessId
;
324 // CreateProcess failed.
327 pid_t
const result
= ACE_OS::fork ();
329 # if defined (ACE_USES_WCHAR)
330 // Wide-char builds need to convert the command-line args to
331 // narrow char strings for execv ().
334 # endif /* ACE_HAS_WCHAR */
338 case static_cast<pid_t
>(-1):
343 # if defined (ACE_USES_WCHAR)
344 for (arg_count
= 0; argv
[arg_count
] != 0; ++arg_count
)
346 ++arg_count
; // Need a 0-pointer end-of-array marker
347 ACE_NEW_NORETURN (cargv
, char*[arg_count
]);
349 ACE_OS::exit (errno
);
350 --arg_count
; // Back to 0-indexed
351 cargv
[arg_count
] = 0;
352 while (--arg_count
>= 0)
353 cargv
[arg_count
] = ACE_Wide_To_Ascii::convert (argv
[arg_count
]);
354 // Don't worry about freeing the cargv or the strings it points to.
355 // Either the process will be replaced, or we'll exit.
356 if (ACE_OS::execv (cargv
[0], cargv
) == -1)
357 ACE_OS::exit (errno
);
359 if (ACE_OS::execv (argv
[0], argv
) == -1)
361 // The OS layer should not print stuff out
362 // ACELIB_ERROR ((LM_ERROR,
363 // "%p Exec failed\n"));
365 // If the execv fails, this child needs to exit.
366 ACE_OS::exit (errno
);
368 # endif /* ACE_HAS_WCHAR */
371 // Server process. The fork succeeded.
374 # endif /* ACE_WIN32 */
378 ACE_OS::num_processors ()
380 ACE_OS_TRACE ("ACE_OS::num_processors");
382 #if defined (ACE_WIN32)
383 SYSTEM_INFO sys_info
;
384 ::GetSystemInfo (&sys_info
);
385 return sys_info
.dwNumberOfProcessors
;
386 #elif defined (ACE_HAS_VXCPULIB)
387 return vxCpuConfiguredGet();
388 #elif defined (_SC_NPROCESSORS_CONF)
389 return ::sysconf (_SC_NPROCESSORS_CONF
);
390 #elif defined (ACE_HAS_SYSCTL)
391 int num_processors
= 0;
392 int mib
[2] = { CTL_HW
, HW_NCPU
};
393 size_t len
= sizeof (num_processors
);
394 if (::sysctl (mib
, 2, &num_processors
, &len
, 0, 0) != -1)
395 return num_processors
;
399 ACE_NOTSUP_RETURN (-1);
404 ACE_OS::num_processors_online ()
406 ACE_OS_TRACE ("ACE_OS::num_processors_online");
408 #if defined (ACE_WIN32)
409 SYSTEM_INFO sys_info
;
410 ::GetSystemInfo (&sys_info
);
411 long active_processors
= 0;
412 DWORD_PTR mask
= sys_info
.dwActiveProcessorMask
;
419 return active_processors
;
420 #elif defined (ACE_HAS_VXCPULIB)
423 CPUSET_ZERO (cpuset
);
424 cpuset
= vxCpuEnabledGet();
425 unsigned int const maxcpu
= vxCpuConfiguredGet();
426 for (unsigned int i
=0; i
< maxcpu
; i
++)
428 if (CPUSET_ISSET (cpuset
, i
))
434 #elif defined (_SC_NPROCESSORS_ONLN)
435 return ::sysconf (_SC_NPROCESSORS_ONLN
);
436 #elif defined (ACE_HAS_SYSCTL)
438 int mib
[2] = { CTL_HW
, HW_NCPU
};
439 size_t len
= sizeof (num_processors
);
440 if (::sysctl (mib
, 2, &num_processors
, &len
, 0, 0) != -1)
441 return num_processors
;
445 ACE_NOTSUP_RETURN (-1);
450 ACE_OS::read_n (ACE_HANDLE handle
,
456 size_t &bytes_transferred
= bt
== 0 ? temp
: *bt
;
459 for (bytes_transferred
= 0;
460 bytes_transferred
< len
;
461 bytes_transferred
+= n
)
463 n
= ACE_OS::read (handle
,
464 (char *) buf
+ bytes_transferred
,
465 len
- bytes_transferred
);
467 if (n
== -1 || n
== 0)
473 return ACE_Utils::truncate_cast
<ssize_t
> (bytes_transferred
);
477 ACE_OS::pread (ACE_HANDLE handle
,
482 # if defined (ACE_HAS_P_READ_WRITE)
483 # if defined (ACE_WIN32)
487 // Remember the original file pointer position
488 LONG original_high_position
= 0;
489 DWORD original_low_position
= ::SetFilePointer (handle
,
491 &original_high_position
,
494 if (original_low_position
== INVALID_SET_FILE_POINTER
495 && GetLastError () != NO_ERROR
)
497 ACE_OS::set_errno_to_last_error ();
501 // Go to the correct position
502 LONG low_offset
= ACE_LOW_PART (offset
);
503 LONG high_offset
= ACE_HIGH_PART (offset
);
504 DWORD altered_position
= ::SetFilePointer (handle
,
508 if (altered_position
== INVALID_SET_FILE_POINTER
509 && GetLastError () != NO_ERROR
)
511 ACE_OS::set_errno_to_last_error ();
517 # if defined (ACE_HAS_WIN32_OVERLAPPED_IO)
519 OVERLAPPED overlapped
;
520 overlapped
.Internal
= 0;
521 overlapped
.InternalHigh
= 0;
522 overlapped
.Offset
= low_offset
;
523 overlapped
.OffsetHigh
= high_offset
;
524 overlapped
.hEvent
= 0;
526 BOOL result
= ::ReadFile (handle
,
528 static_cast <DWORD
> (nbytes
),
534 if (::GetLastError () != ERROR_IO_PENDING
)
539 result
= ::GetOverlappedResult (handle
,
548 # else /* ACE_HAS_WIN32_OVERLAPPED_IO */
550 BOOL result
= ::ReadFile (handle
,
558 # endif /* ACE_HAS_WIN32_OVERLAPPED_IO */
560 // Reset the original file pointer position
561 if (::SetFilePointer (handle
,
562 original_low_position
,
563 &original_high_position
,
564 FILE_BEGIN
) == INVALID_SET_FILE_POINTER
565 && GetLastError () != NO_ERROR
)
567 ACE_OS::set_errno_to_last_error ();
571 return (ssize_t
) bytes_read
;
573 # else /* ACE_WIN32 */
575 return ::pread (handle
, buf
, nbytes
, offset
);
577 # endif /* ACE_WIN32 */
579 # else /* ACE_HAS_P_READ_WRITE */
583 // Remember the original file pointer position
584 ACE_OFF_T original_position
= ACE_OS::lseek (handle
,
588 if (original_position
== -1)
591 // Go to the correct position
592 ACE_OFF_T altered_position
= ACE_OS::lseek (handle
, offset
, SEEK_SET
);
594 if (altered_position
== -1)
597 ssize_t
const bytes_read
= ACE_OS::read (handle
, buf
, nbytes
);
599 if (bytes_read
== -1)
602 if (ACE_OS::lseek (handle
,
609 # endif /* ACE_HAS_P_READ_WRITE */
613 ACE_OS::pwrite (ACE_HANDLE handle
,
618 # if defined (ACE_HAS_P_READ_WRITE)
619 # if defined (ACE_WIN32)
623 // Remember the original file pointer position
624 LONG original_high_position
= 0;
625 DWORD original_low_position
= ::SetFilePointer (handle
,
627 &original_high_position
,
630 if (original_low_position
== INVALID_SET_FILE_POINTER
631 && GetLastError () != NO_ERROR
)
633 ACE_OS::set_errno_to_last_error ();
638 LONG low_offset
= ACE_LOW_PART (offset
);
639 LONG high_offset
= ACE_HIGH_PART (offset
);
641 # if defined (ACE_HAS_WIN32_OVERLAPPED_IO)
643 OVERLAPPED overlapped
;
644 overlapped
.Internal
= 0;
645 overlapped
.InternalHigh
= 0;
646 overlapped
.Offset
= low_offset
;
647 overlapped
.OffsetHigh
= high_offset
;
648 overlapped
.hEvent
= 0;
650 BOOL result
= ::WriteFile (handle
,
652 static_cast <DWORD
> (nbytes
),
658 if (::GetLastError () != ERROR_IO_PENDING
)
664 result
= ::GetOverlappedResult (handle
,
673 # else /* ACE_HAS_WIN32_OVERLAPPED_IO */
675 if (::SetFilePointer (handle
,
678 FILE_BEGIN
) == INVALID_SET_FILE_POINTER
679 && ::GetLastError () != NO_ERROR
)
681 ACE_OS::set_errno_to_last_error ();
685 BOOL result
= ::WriteFile (handle
,
693 # endif /* ACE_HAS_WIN32_OVERLAPPED_IO */
695 // Reset the original file pointer position
696 if (::SetFilePointer (handle
,
697 original_low_position
,
698 &original_high_position
,
699 FILE_BEGIN
) == INVALID_SET_FILE_POINTER
700 && GetLastError () != NO_ERROR
)
702 ACE_OS::set_errno_to_last_error ();
706 return (ssize_t
) bytes_written
;
708 # else /* ACE_WIN32 */
709 # if defined (ACE_HAS_NON_CONST_PWRITE)
710 return ::pwrite (handle
, const_cast<void*> (buf
), nbytes
, offset
);
712 return ::pwrite (handle
, buf
, nbytes
, offset
);
714 # endif /* ACE_WIN32 */
715 # else /* ACE_HAS_P_READ_WRITE */
719 // Remember the original file pointer position
720 ACE_OFF_T original_position
= ACE_OS::lseek (handle
,
723 if (original_position
== -1)
726 // Go to the correct position
727 ACE_OFF_T altered_position
= ACE_OS::lseek (handle
,
730 if (altered_position
== -1)
733 ssize_t
const bytes_written
= ACE_OS::write (handle
,
736 if (bytes_written
== -1)
739 if (ACE_OS::lseek (handle
,
744 return bytes_written
;
745 # endif /* ACE_HAS_P_READ_WRITE */
749 ACE_OS::string_to_argv (ACE_TCHAR
*buf
,
752 bool substitute_env_args
)
754 // Reset the number of arguments
762 // First pass: count arguments.
764 // '#' is the start-comment token..
765 while (*cp
!= ACE_TEXT ('\0') && *cp
!= ACE_TEXT ('#'))
768 while (ACE_OS::ace_isspace (*cp
))
771 // Increment count and move to next whitespace..
772 if (*cp
!= ACE_TEXT ('\0'))
775 while (*cp
!= ACE_TEXT ('\0') && !ACE_OS::ace_isspace (*cp
))
778 if (*cp
== ACE_TEXT ('\'') || *cp
== ACE_TEXT ('"'))
780 ACE_TCHAR quote
= *cp
;
782 // Scan past the string..
783 for (++cp
; *cp
!= ACE_TEXT ('\0')
784 && (*cp
!= quote
|| cp
[-1] == ACE_TEXT ('\\')); ++cp
)
787 // '\0' implies unmatched quote..
788 if (*cp
== ACE_TEXT ('\0'))
801 // Second pass: copy arguments.
802 ACE_TCHAR arg
[ACE_DEFAULT_ARGV_BUFSIZ
];
803 ACE_TCHAR
*argp
= arg
;
805 // Make sure that the buffer we're copying into is always large
807 if (cp
- buf
>= ACE_DEFAULT_ARGV_BUFSIZ
)
808 #if defined (ACE_HAS_ALLOC_HOOKS)
809 ACE_ALLOCATOR_RETURN(argp
,
810 static_cast<ACE_TCHAR
*>(ACE_Allocator::instance()->malloc(sizeof (ACE_TCHAR
) * (cp
- buf
+ 1))),
813 ACE_NEW_RETURN (argp
,
814 ACE_TCHAR
[cp
- buf
+ 1],
816 #endif /* ACE_HAS_ALLOC_HOOKS */
818 // Make a new argv vector of argc + 1 elements.
819 #if defined (ACE_HAS_ALLOC_HOOKS)
820 ACE_ALLOCATOR_RETURN(argv
,
821 static_cast<ACE_TCHAR
**>(ACE_Allocator::instance()->malloc(sizeof (ACE_TCHAR
*) * (argc
+ 1))),
824 ACE_NEW_RETURN (argv
,
825 ACE_TCHAR
*[argc
+ 1],
827 #endif /* ACE_HAS_ALLOC_HOOKS */
829 ACE_TCHAR
*ptr
= buf
;
831 for (int i
= 0; i
< argc
; ++i
)
834 while (ACE_OS::ace_isspace (*ptr
))
837 // Copy next argument and move to next whitespace..
839 while (*ptr
!= ACE_TEXT ('\0') && !ACE_OS::ace_isspace (*ptr
))
840 if (*ptr
== ACE_TEXT ('\'') || *ptr
== ACE_TEXT ('"'))
842 ACE_TCHAR quote
= *ptr
++;
844 while (*ptr
!= ACE_TEXT ('\0')
845 && (*ptr
!= quote
|| ptr
[-1] == ACE_TEXT ('\\')))
847 if (*ptr
== quote
&& ptr
[-1] == ACE_TEXT ('\\')) --cp
;
857 *cp
= ACE_TEXT ('\0');
859 // Check for environment variable substitution here.
860 if (substitute_env_args
) {
861 argv
[i
] = ACE_OS::strenvdup (argp
);
866 #if defined (ACE_HAS_ALLOC_HOOKS)
867 ACE_Allocator::instance()->free(argp
);
870 #endif /* ACE_HAS_ALLOC_HOOKS */
877 argv
[i
] = ACE_OS::strdup (argp
);
883 #if defined (ACE_HAS_ALLOC_HOOKS)
884 ACE_Allocator::instance()->free(argp
);
887 #endif /* ACE_HAS_ALLOC_HOOKS */
898 #if defined (ACE_HAS_ALLOC_HOOKS)
899 ACE_Allocator::instance()->free(argp
);
902 #endif /* ACE_HAS_ALLOC_HOOKS */
909 // Write <len> bytes from <buf> to <handle> (uses the <write>
910 // system call on UNIX and the <WriteFile> call on Win32).
913 ACE_OS::write_n (ACE_HANDLE handle
,
919 size_t &bytes_transferred
= bt
== 0 ? temp
: *bt
;
922 for (bytes_transferred
= 0;
923 bytes_transferred
< len
;
924 bytes_transferred
+= n
)
926 n
= ACE_OS::write (handle
,
927 (char *) buf
+ bytes_transferred
,
928 len
- bytes_transferred
);
930 if (n
== -1 || n
== 0)
936 return ACE_Utils::truncate_cast
<ssize_t
> (bytes_transferred
);
939 ACE_END_VERSIONED_NAMESPACE_DECL