stdcxx-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From se...@apache.org
Subject svn commit: r432452 - in /incubator/stdcxx/trunk/util: cmdopt.cpp exec.cpp exec.h runall.cpp
Date Fri, 18 Aug 2006 00:51:05 GMT
Author: sebor
Date: Thu Aug 17 17:51:05 2006
New Revision: 432452

URL: http://svn.apache.org/viewvc?rev=432452&view=rev
Log:
2006-08-17  Andrew Black  <ablack@roguewave.com>

	* exec.h [_WIN32 || _WIN64] (exec_attrs): Alter structure definition
	for windows.
	* exec.cpp [_WIN32 || _WIN64]: Use windows.h and process.h in place
	of unistd.h and sys/wait.h on windows.
	[!_WIN32 && !_WIN64] (handle_alrm, wait_for_child, open_input,
	replace_file, exec_file): Reduce scope of (existing) functions
	to non-windows platforms only.
	[_WIN32 || _WIN64] (open_input, merge_argv, warn_last_error, exec_file):
	Define implementation of named functions for windows platforms only.
	* cmdopt.cpp [_WIN32 || _WIN64]: Use windows.h in place of unistd.h
	on windows.
	(escape_code, default_path_sep, suffix_sep, exe_suffix_len): Alter
	values for windows.
	(rw_sleep, rw_signal): Define platform independent wrapper for
	sleep/Sleep and sigaction/signal.
	(eval_options): Use above.
	* runall.cpp [!_WIN32 && !_WIN64]: Don't include sys/wait.h on windows.
	(S_IXUSR, S_IXGRP, S_IXOTH): Define values if undefined (for windows).
	(check_target_ok) [_WIN32 || _WIN64]: Make object file comparison
	operating system specific.
	(process_results) [_WIN32 || _WIN64]: Make error state processing code
	operating system specific.
	(rw_basename) [_WIN32 || _WIN64]: Treat slash as an additional path
	separator on windows.

Modified:
    incubator/stdcxx/trunk/util/cmdopt.cpp
    incubator/stdcxx/trunk/util/exec.cpp
    incubator/stdcxx/trunk/util/exec.h
    incubator/stdcxx/trunk/util/runall.cpp

Modified: incubator/stdcxx/trunk/util/cmdopt.cpp
URL: http://svn.apache.org/viewvc/incubator/stdcxx/trunk/util/cmdopt.cpp?rev=432452&r1=432451&r2=432452&view=diff
==============================================================================
--- incubator/stdcxx/trunk/util/cmdopt.cpp (original)
+++ incubator/stdcxx/trunk/util/cmdopt.cpp Thu Aug 17 17:51:05 2006
@@ -35,7 +35,11 @@
 #include <stdio.h> /* for *printf, fputs */
 #include <stdlib.h> /* for exit */
 #include <string.h> /* for str* */
-#include <unistd.h> /* for sleep */
+#if !defined (_WIN32) && !defined (_WIN64)
+#  include <unistd.h> /* for sleep */
+#else
+#  include <windows.h> /* for Sleep */
+#endif   /* _WIN{32,64} */
 
 #include "exec.h"
 #include "util.h"
@@ -50,10 +54,17 @@
 const char* in_root = ""; /**< Root directory for input/reference files. */
 const char* exe_name; /**< Alias for process argv [0]. */
 const char* target_name;
+#if !defined (_WIN32) && !defined (_WIN64)
 const char escape_code = '\\';
 const char default_path_sep = '/';
 const char suffix_sep = '.';
 const size_t exe_suffix_len = 0;
+#else
+const char escape_code = '^';
+const char default_path_sep = '\\';
+const char suffix_sep = '.';
+const size_t exe_suffix_len = 4; /* strlen(".exe") == 4 */
+#endif
 
 static const char
 usage_text[] = {
@@ -88,6 +99,35 @@
     "  '--option=value' or '--option value'.\n"
 };
 
+#if !defined (_WIN32) && !defined (_WIN64)
+static void
+rw_sleep (int seconds)
+{
+    sleep (seconds);
+}
+
+static int
+rw_signal (int signo, void (*func)(int))
+{
+    struct sigaction act;
+    memset (&act, 0, sizeof act);
+    act.sa_handler = func;
+    return 0 > sigaction (signo, &act, 0);
+}
+#else
+static void
+rw_sleep (int seconds)
+{
+    Sleep (seconds * 1000);
+}
+
+static int
+rw_signal (int signo, void (*func)(int))
+{
+    return SIG_ERR == signal (signo, func);
+}
+#endif
+
 /**
    Display command line switches for program and terminate.
 
@@ -308,7 +348,7 @@
                 if (optarg && *optarg) {
                     const long nsec = strtol (optarg, &end, 10);
                     if ('\0' == *end && 0 <= nsec && !errno) {
-                        sleep (nsec);
+                        rw_sleep (nsec);
                         break;
                     }
                 }
@@ -334,11 +374,8 @@
                 if (optarg && *optarg) {
                     const long signo = get_signo (optarg);
                     if (0 <= signo) {
-                        struct sigaction act;
-                        memset (&act, 0, sizeof act);
-                        act.sa_handler = SIG_IGN;
-                        if (0 > sigaction (signo, &act, 0))
-                            terminate (1, "sigaction(%s, ...) failed: %s\n",
+                        if (rw_signal (signo, SIG_IGN))
+                            terminate (1, "rw_signal(%s, ...) failed: %s\n",
                                        get_signame (signo), strerror (errno));
                         break;
                     }

Modified: incubator/stdcxx/trunk/util/exec.cpp
URL: http://svn.apache.org/viewvc/incubator/stdcxx/trunk/util/exec.cpp?rev=432452&r1=432451&r2=432452&view=diff
==============================================================================
--- incubator/stdcxx/trunk/util/exec.cpp (original)
+++ incubator/stdcxx/trunk/util/exec.cpp Thu Aug 17 17:51:05 2006
@@ -37,10 +37,15 @@
 #include <stdlib.h>
 #include <string.h> /* for str*, mem* */
 
-#include <unistd.h> /* for close, dup, exec, fork */
+#if !defined (_WIN32) && !defined (_WIN64)
+#  include <unistd.h> /* for close, dup, exec, fork */
+#  include <sys/wait.h>
+#else
+#  include <windows.h> /* for PROCESS_INFORMATION, ... */
+#  include <process.h> /* for CreateProcess, ... */
+#endif
 #include <sys/stat.h> /* for S_* */
 #include <sys/types.h>
-#include <sys/wait.h>
 
 #include "cmdopt.h"
 #include "util.h"
@@ -354,6 +359,7 @@
     return def;
 }
 
+#if !defined (_WIN32) && !defined (_WIN64)
 /**
    Callback used to set the alarm_timeout flag in response to recieving
    the signal SIGALRM
@@ -714,3 +720,306 @@
     /* parent */
     return wait_for_child (child_pid);
 }
+#else  /* _WIN{32,64} */
+/**
+   Opens an input file, based on exec_name, using the child_sa security 
+   setting.
+
+   Takes an executable name and security setting, and tries to open an input 
+   file based on these variables and the value of the in_root global variable.
+   If a file is found in neither of two locations derived from these 
+   variables, or if in_root is a null string, it returns null.
+   If a file system error occurs when opening a file, INVALID_HANDLE_VALUE
+   is returned (and should be checked for).
+
+   Source file locations:
+     - [in_root]/manual/in/[exec_name].in
+     - [in_root]/tutorial/in/[exec_name].in
+
+   @param exec_name the name of executable being run
+   @param child_sa pointer to a SECURITY_ATTRIBUTES    structure
+   @returns the file descriptor of the opened file
+   @see in_root
+*/
+static HANDLE
+open_input (const char* exec_name, SECURITY_ATTRIBUTES* child_sa)
+{
+    const size_t root_len = strlen (in_root);
+    HANDLE intermit;
+    DWORD error;
+    char* tmp_name;
+
+    assert (0 != exec_name);
+    assert (0 != in_root);
+    assert (0 != child_sa);
+
+    if (!root_len) 
+        return 0;
+
+    /* Try in_root\manual\in\exec_name.in */
+    tmp_name = reference_name ("manual", "in");
+
+    intermit = CreateFile (tmp_name, GENERIC_READ, FILE_SHARE_READ, child_sa, 
+        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+    error = GetLastError ();
+    /* If we found the file, return the descriptor */
+    if (INVALID_HANDLE_VALUE != intermit || (2 != error && 3 != error)) {
+        free (tmp_name);
+        return intermit;
+    }
+
+    /* Try in_root\tutorial\in\exec_name.in */
+    free (tmp_name);
+    tmp_name = reference_name ("tutorial", "in");
+    intermit = CreateFile (tmp_name, GENERIC_READ, FILE_SHARE_READ, child_sa, 
+        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+    /* If we didn't find the file, null out the handle to return */
+    error = GetLastError ();
+    if (INVALID_HANDLE_VALUE == intermit && (2 == error || 3 == error)) {
+        intermit = 0;
+    }
+
+    free (tmp_name);
+    return intermit;
+}
+
+/**
+   Convert an argv array into a string that can be passed to CreateProcess.
+
+   This method allocates memory which the caller is responsible for free ()ing.
+   The provided argv array is converted into a series of quoted strings.
+
+   @param argv argv array to convert
+   @return allocated array with converted contents
+*/
+static char*
+merge_argv (char** argv)
+{
+    size_t len = 0;
+    char** opts;
+    char* term;
+    char* merge;
+    char* pos;
+
+    assert (0 != argv);
+
+    for (opts = argv; *opts; ++opts) {
+        len += 3; /* for open ", close " and trailing space or null */
+        for (term = *opts; *term; ++term) {
+            if ('"' == *term || escape_code == *term)
+                ++len; /* Escape embedded "s and ^s*/
+            ++len;
+        }
+    }
+
+    pos = merge = (char*)RW_MALLOC (len);
+    for (opts = argv; *opts; ++opts) {
+        *(pos++) = '"';
+        for (term = *opts; *term; ++term) {
+            if ('"' == *term || escape_code == *term)
+                *(pos++) = escape_code;  /* Escape embedded "s and ^s*/
+            *(pos++) = *term;
+        }
+        *(pos++) = '"';
+        *(pos++) = ' ';
+    }
+    *(pos-1) = '\0'; /* convert trailing space to null */
+    return merge;
+}
+
+/**
+   Wrapper function around warn for windows native API calls.
+
+   @param action Human understandable description of failed action.
+   @return Value of GetLastError.
+*/
+static DWORD
+warn_last_error (const char* action)
+{
+    DWORD error = GetLastError (); 
+
+    if (error) {
+        LPTSTR error_text = 0;
+        if (FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | 
+            FORMAT_MESSAGE_FROM_SYSTEM, NULL, error,
+            MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+            error_text, 0, NULL)) {
+            warn ("%s failed with error %d: %s\n", action, error, error_text);
+            LocalFree (error_text);
+        }
+        else {
+            warn ("%s failed with error %d.  Additionally, FormatMessage "
+                  "failed with error %d.\n", action, error, GetLastError ());
+        }
+    }
+    return error;
+}
+
+/**
+   Entry point to the child process (watchdog) subsystem.
+
+   This method creates a process using the windows CreateProcess API call.
+   The startup context for this process is based on the context of the exec
+   utility, but with the standard * file handles redirected.  The execution of
+   the process is monitored with the WaitForSingleObject API call.  If the 
+   process doesn't complete within the allowed timeout, it is then killed.  On 
+   Windows NT systems, a soft kill of the process (via the 
+   GenerateConsoleCtrlEvent API call) are first attempted attempted.  The 
+   process is then hard killed via the TerminateProcess API call.
+
+   @param exec_name name of the child executable
+   @param argv argv array for child process
+   @return structure describing how the child procees exited
+   @see wait_for_child ()
+*/
+struct exec_attrs 
+exec_file (char** argv)
+{
+    char* merged;
+    PROCESS_INFORMATION child;
+    OSVERSIONINFO OSVer;
+    STARTUPINFO context;
+    SECURITY_ATTRIBUTES child_sa = /* SA for inheritable handle. */
+          {sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
+    struct exec_attrs status;
+    const DWORD real_timeout = (timeout > 0) ? timeout * 1000 : INFINITE;
+    DWORD wait_code;
+
+    assert (0 != argv);
+
+    memset (&status, 0, sizeof status);
+
+    OSVer.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+    if (0 == GetVersionEx (&OSVer)) {
+        status.status = -1;
+        status.error = warn_last_error ("Retrieving host version");
+        return status;
+    }
+    /* Borrow our startup info */
+    GetStartupInfo (&context);
+    context.dwFlags = STARTF_USESTDHANDLES;
+
+    /* Create I/O handles */
+    {
+        /* Output redirection */
+        char* const tmp_name = output_name (argv [0]);
+
+        context.hStdOutput = CreateFile (tmp_name, GENERIC_WRITE, 
+                FILE_SHARE_WRITE, &child_sa, CREATE_ALWAYS, 
+                FILE_ATTRIBUTE_NORMAL, NULL);
+        if (INVALID_HANDLE_VALUE == context.hStdOutput) { 
+            status.status = -1;
+            status.error = warn_last_error ("Opening child output stream");
+            return status;
+        }
+
+        context.hStdError = context.hStdOutput;
+        free (tmp_name);
+
+        /* Input redirection */
+        context.hStdInput = open_input (target_name, &child_sa);
+        if (INVALID_HANDLE_VALUE == context.hStdInput) { 
+            CloseHandle (context.hStdOutput);
+            status.status = -1;
+            status.error = warn_last_error ("Opening child input stream");
+            return status;
+        }
+    }    
+
+    merged = merge_argv (argv);
+
+    /* Create the child process */
+    if (0 == CreateProcess (argv [0], merged, 0, 0, 1, 
+        CREATE_NEW_PROCESS_GROUP, 0, 0, &context, &child)) {
+        /* record the status if we failed to create the process */
+        status.status = -1;
+        status.error = warn_last_error ("Creating child process");;
+    }
+
+    /* Clean up handles */
+    if (context.hStdInput)
+        if (0 == CloseHandle (context.hStdInput))
+            warn_last_error ("Closing child input stream");
+    if (0 == CloseHandle (context.hStdOutput))
+        warn_last_error ("Closing child output stream");
+
+    /* Clean up argument string*/
+    free (merged);
+
+    /* Return if we failed to create the child process */
+    if (-1 == status.status)
+        return status;
+
+    /* Wait for the child process to terminate */
+    wait_code = WaitForSingleObject (child.hProcess, real_timeout);
+    if (WAIT_TIMEOUT != wait_code) {
+        if (WAIT_OBJECT_0 == wait_code) {
+            if (0 == GetExitCodeProcess (child.hProcess, &status.status)) {
+                warn_last_error ("Retrieving child process exit code");
+                status.status = -1;
+            }
+            status.error = 0;
+        }
+        else {
+            status.status = -1;
+            status.error = warn_last_error ("Waiting for child process");
+        }
+        return status;
+    }
+
+    /* Try to soft kill child process group if it didn't terminate, but only 
+       on NT */
+    if (VER_PLATFORM_WIN32_NT == OSVer.dwPlatformId) {
+        if (0 == GenerateConsoleCtrlEvent (CTRL_C_EVENT, child.dwProcessId))
+            warn_last_error ("Sending child process Control-C");
+
+        wait_code = WaitForSingleObject (child.hProcess, 1000);
+        if (WAIT_TIMEOUT != wait_code) {
+            if (WAIT_OBJECT_0 == wait_code) {
+                if (0 == GetExitCodeProcess (child.hProcess, 
+                                             &status.status)) {
+                    warn_last_error ("Retrieving child process exit code");
+                    status.status = -1;
+                }
+                status.error = 1;
+            }
+            else {
+                status.status = -1;
+                status.error = warn_last_error ("Waiting for child process");
+            }
+            return status;
+        }
+
+        if (0 == GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, 
+                                           child.dwProcessId))
+            warn_last_error ("Sending child process Control-Break");
+
+        if (WAIT_TIMEOUT != wait_code) {
+            if (WAIT_OBJECT_0 == wait_code) {
+                if (0 == GetExitCodeProcess (child.hProcess, 
+                                             &status.status)) {
+                    warn_last_error ("Retrieving child process exit code");
+                    status.status = -1;
+                }
+                status.error = 2;
+            }
+            else {
+                status.status = -1;
+                status.error = warn_last_error ("Waiting for child process");
+            }
+            return status;
+        }
+    }
+    /* Then hard kill the child process */
+    if (0 == TerminateProcess (child.hProcess, 3))
+        warn_last_error ("Terminating child process");
+    if (0 == GetExitCodeProcess (child.hProcess, &status.status)) {
+        warn_last_error ("Retrieving child process exit code");
+        status.status = -1;
+    }
+    status.error = 3;
+    return status;
+}
+#endif  /* _WIN{32,64} */

Modified: incubator/stdcxx/trunk/util/exec.h
URL: http://svn.apache.org/viewvc/incubator/stdcxx/trunk/util/exec.h?rev=432452&r1=432451&r2=432452&view=diff
==============================================================================
--- incubator/stdcxx/trunk/util/exec.h (original)
+++ incubator/stdcxx/trunk/util/exec.h Thu Aug 17 17:51:05 2006
@@ -28,8 +28,14 @@
 #define RW_EXEC_H
 
 struct exec_attrs {
+#if !defined (_WIN32) && !defined (_WIN64)
     int status;
     int killed;
+#else
+    /* AKA DWORD */
+    unsigned long status;
+    unsigned long error;
+#endif  /* _WIN{32,64} */
 };
 
 int get_signo (const char* signame);

Modified: incubator/stdcxx/trunk/util/runall.cpp
URL: http://svn.apache.org/viewvc/incubator/stdcxx/trunk/util/runall.cpp?rev=432452&r1=432451&r2=432452&view=diff
==============================================================================
--- incubator/stdcxx/trunk/util/runall.cpp (original)
+++ incubator/stdcxx/trunk/util/runall.cpp Thu Aug 17 17:51:05 2006
@@ -33,7 +33,9 @@
 #include <ctype.h>      /* for isspace */
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/wait.h>   /* for WIFEXITED(), ... */
+#if !defined (_WIN32) && !defined (_WIN64)
+#  include <sys/wait.h>   /* for WIFEXITED(), ... */
+#endif
 
 #include "cmdopt.h"
 #include "exec.h"
@@ -44,6 +46,18 @@
 #  define ENOENT 2
 #endif   // ENOENT
 
+#ifndef S_IXUSR
+#  define S_IXUSR 0100
+#endif   // S_IXUSR
+
+#ifndef S_IXGRP
+#  define S_IXGRP 0010
+#endif   // S_IXGRP
+
+#ifndef S_IXOTH
+#  define S_IXOTH 0001
+#endif   // S_IXOTH
+
 /**
    Utility function to rework the argv array
 
@@ -231,10 +245,29 @@
             return 0;
         }
 
-        /* Otherwise, check for the .o file */
+#if !defined (_WIN32) && !defined (_WIN64)
+        /* Otherwise, check for the .o file on non-windows systems */
         tmp_name = (char*)RW_MALLOC (path_len + 3);
         memcpy (tmp_name, target, path_len + 1);
         strcat (tmp_name,".o");
+#else
+        /* Or the target\target.obj file on windows systems*/
+        {
+            size_t target_len = strlen (target_name);
+            size_t tmp_len = path_len + target_len - 2;
+                /* - 2 comes from removing 4 characters (extra .exe) and 
+                   adding 2 characters (\ directory seperator and trailing 
+                   null) */
+            tmp_name = (char*)RW_MALLOC (tmp_len);
+            memcpy (tmp_name, target, path_len - 4);
+            tmp_name [path_len - 4] = default_path_sep;
+            memcpy (tmp_name + path_len - 3, target_name, target_len);
+            tmp_name [tmp_len - 4] = 'o';
+            tmp_name [tmp_len - 3] = 'b';
+            tmp_name [tmp_len - 2] = 'j';
+            tmp_name [tmp_len - 2] = '\0';
+        }
+#endif   /* _WIN{32,64} */
 
         if (0 > stat (tmp_name, &file_info)) {
             if (ENOENT != errno) {
@@ -286,6 +319,7 @@
     if (0 == result->status) {
         parse_output (target);
     } 
+#if !defined (_WIN32) && !defined (_WIN64)
     else if (WIFEXITED (result->status)) {
         const int retcode = WEXITSTATUS (result->status);
         switch (retcode) {
@@ -311,6 +345,14 @@
     else {
         printf ("(%d|%d)\n", result->status, result->killed);
     }
+#else
+    else if (-1 == result->status)
+        puts ("   I/O");
+    else if (result->error)
+        puts ("KILLED");
+    else
+        printf ("%6d\n", result->status);
+#endif   /* _WIN{32,64} */
 }
 
 /**
@@ -335,7 +377,11 @@
     assert (0 != path);
 
     for (mark = pos = path; '\0' != *pos; ++pos)
+#if !defined (_WIN32) && !defined (_WIN64)
         mark = (default_path_sep == *pos) ? pos + 1 : mark;
+#else
+        mark = (default_path_sep == *pos || '/' == *pos) ? pos + 1 : mark;
+#endif   /* _WIN{32,64} */
 
     return mark;
 }



Mime
View raw message