|
1 | 1 | /* |
2 | | - * Copyright (c) 1995-2018, NVIDIA CORPORATION. All rights reserved. |
| 2 | + * Copyright (c) 1995-2019, NVIDIA CORPORATION. All rights reserved. |
3 | 3 | * |
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | 5 | * you may not use this file except in compliance with the License. |
|
24 | 24 | #include "stdioInterf.h" |
25 | 25 | #include "fioMacros.h" |
26 | 26 |
|
| 27 | +extern char *__fstr2cstr(); |
| 28 | + |
27 | 29 | void |
28 | 30 | ENTFTN(TEMPLATE, template)(F90_Desc *dd, __INT_T *p_rank, |
29 | 31 | __INT_T *p_flags, ...); |
30 | 32 |
|
| 33 | +#include <string.h> |
31 | 34 | #include "fort_vars.h" |
32 | | - |
| 35 | +#if defined(TARGET_LINUX_X8664) || defined (TARGET_LINUX_POWER) || defined(TARGET_OSX_X8664) |
| 36 | +#include <unistd.h> |
| 37 | +#include <sys/wait.h> |
| 38 | +#endif |
| 39 | +static void store_int_kind(void *, __INT_T *, int); |
| 40 | +static void ftn_msgcpy(char*, const char*, int); |
33 | 41 | static char *intents[] = {"INOUT", "IN", "OUT", "??"}; |
34 | 42 |
|
35 | 43 | /** \brief Compare alignments and local storage sequences. Return true if all |
@@ -2808,4 +2816,163 @@ ENTF90(CONTIGCHK, contigchk)(void *ptr, F90_Desc *pd, __INT_T lineno, |
2808 | 2816 | ENTF90(CONTIGERROR, contigerror)(ptr, pd, lineno, ptrnam, srcfil, flags); |
2809 | 2817 | } |
2810 | 2818 | } |
| 2819 | + |
| 2820 | +/** \brief Execute a command line. |
| 2821 | + * |
| 2822 | + * \param command is the command to be executed. |
| 2823 | + * \param wait controls to execute command synchronously or asynchronously. |
| 2824 | + * \param exitstatus is the value of exit status. |
| 2825 | + * \param cmdstat shows the status of command execution. |
| 2826 | + * \param cmdmsg is the assigned explanatory message. |
| 2827 | + * \param exitstat_int_kind is the integer kind for the exitstat. |
| 2828 | + * \param cmdstat_int_kind is the integer kind for the cmdstat. |
| 2829 | + * \param DCLEN64(command) is generated by compiler which contains the length |
| 2830 | + * of the command string. |
| 2831 | + * \param DCLEN64(cmdmsg) is generated by compiler which contains the length |
| 2832 | + of the cmdmsg string. |
| 2833 | + */ |
| 2834 | +void |
| 2835 | +ENTF90(EXECCMDLINE, execcmdline)(DCHAR(command), __LOG_T *wait, |
| 2836 | + __INT_T *exitstatus, |
| 2837 | + __INT_T *cmdstat, DCHAR (cmdmsg), |
| 2838 | + __INT_T *exitstat_int_kind, |
| 2839 | + __INT_T *cmdstat_int_kind |
| 2840 | + DCLEN64(command) DCLEN64(cmdmsg)) { |
| 2841 | + char *cmd, *cmdmes; |
| 2842 | + int cmdmes_len, stat; |
| 2843 | + int cmdflag = 0; |
| 2844 | + enum CMD_ERR{NO_SUPPORT_ERR=-1, FORK_ERR=1, EXECL_ERR=2, SIGNAL_ERR=3}; |
2811 | 2845 |
|
| 2846 | + cmd = __fstr2cstr(CADR(command), CLEN(command)); |
| 2847 | + cmdmes = (char*) CADR(cmdmsg); |
| 2848 | + cmdmes_len = CLEN(cmdmsg); |
| 2849 | + |
| 2850 | + if (cmdstat) |
| 2851 | + store_int_kind(cmdstat, cmdstat_int_kind, 0); |
| 2852 | +#if defined(TARGET_LINUX_X8664) || defined(TARGET_OSX_X8664) || defined (TARGET_LINUX_POWER) |
| 2853 | + pid_t pid, w; |
| 2854 | + int wstatus, ret; |
| 2855 | + |
| 2856 | + /* If WAIT is present with the value false, and the processor supports |
| 2857 | + * asynchronous execution of the command, the command is executed |
| 2858 | + * asynchronously; otherwise it is executed synchronously. |
| 2859 | + */ |
| 2860 | + pid = fork(); |
| 2861 | + if (pid < 0) { |
| 2862 | + if (cmdmes) |
| 2863 | + ftn_msgcpy(cmdmes, "Fork failed", cmdmsg_len); |
| 2864 | + if (cmdstat) |
| 2865 | + store_int_kind(cmdstat, cmdstat_int_kind, FORK_ERR); |
| 2866 | + } else if (pid == 0) { |
| 2867 | + ret = execl("/bin/sh", "sh", "-c", cmd, (char *) NULL); |
| 2868 | + exit(ret); |
| 2869 | + } else { |
| 2870 | + // either wait is not specified or wait is true, then synchronous mode |
| 2871 | + if ( !wait || *wait == -1) { |
| 2872 | +#if DEBUG |
| 2873 | + printf("either wait is not specified or Wait = .true.\n"); |
| 2874 | + printf("Synchronous execution mode!\n"); |
| 2875 | +#endif |
| 2876 | + /* code executed by parent, wait for children */ |
| 2877 | + w = waitpid(pid, &wstatus, WUNTRACED | WCONTINUED); |
| 2878 | + if (w == -1) |
| 2879 | + cmdflag = EXECL_ERR; |
| 2880 | + |
| 2881 | + if (WIFEXITED(wstatus)) { |
| 2882 | + stat = WEXITSTATUS(wstatus); |
| 2883 | + |
| 2884 | + if (exitstatus) |
| 2885 | + store_int_kind(exitstatus, exitstat_int_kind, stat); |
| 2886 | + } |
| 2887 | + |
| 2888 | + if (WIFSIGNALED(wstatus)) |
| 2889 | + cmdflag = SIGNAL_ERR; |
| 2890 | + |
| 2891 | + if (cmdstat && cmdflag > 0) |
| 2892 | + store_int_kind(cmdstat, cmdstat_int_kind, cmdflag); |
| 2893 | + |
| 2894 | + if (cmdmes) { |
| 2895 | + switch (cmdflag) { |
| 2896 | + case EXECL_ERR: |
| 2897 | + ftn_msgcpy(cmdmes, "Excel failed", cmdmsg_len); |
| 2898 | + break; |
| 2899 | + case SIGNAL_ERR: |
| 2900 | + ftn_msgcpy(cmdmes, "Signal error", cmdmsg_len); |
| 2901 | + break; |
| 2902 | + } |
| 2903 | + } |
| 2904 | + |
| 2905 | + /* If a condition occurs that would assign a nonzero value to CMDSTAT |
| 2906 | + but the CMDSTAT variable is not present, error termination is |
| 2907 | + initiated. |
| 2908 | + */ |
| 2909 | + if (!cmdstat && cmdflag > 0) { |
| 2910 | + fprintf(__io_stderr(), "ERROR STOP "); |
| 2911 | + exit(cmdflag); |
| 2912 | + } |
| 2913 | + |
| 2914 | +#if DEBUG |
| 2915 | + if (WIFEXITED(wstatus)) { |
| 2916 | + printf("exited, status=%d\n", WEXITSTATUS(wstatus)); |
| 2917 | + } else if (WIFSIGNALED(wstatus)) { |
| 2918 | + printf("killed by signal %d\n", WTERMSIG(wstatus)); |
| 2919 | + } else if (WIFSTOPPED(wstatus)) { |
| 2920 | + printf("stopped by signal %d\n", WSTOPSIG(wstatus)); |
| 2921 | + } else if (WIFCONTINUED(wstatus)) { |
| 2922 | + printf("continued\n"); |
| 2923 | + } |
| 2924 | +#endif |
| 2925 | + } // end else |
| 2926 | + } |
| 2927 | +#else // defined(TARGET_WIN) |
| 2928 | + // Windows runtime work to be continued. |
| 2929 | + cmdflag = NO_SUPPORT_ERR; |
| 2930 | + if (cmdmes) |
| 2931 | + ftn_msgcpy(cmdmes, "No Windows support", cmdmsg_len); |
| 2932 | + if (cmdstat) |
| 2933 | + store_int_kind(cmdstat, cmdstat_int_kind, cmdflag); |
| 2934 | + else |
| 2935 | + __fort_abort("execute_command_line: not yet supported on Windows\n"); |
| 2936 | +#endif |
| 2937 | + __cstr_free(cmd); |
| 2938 | +} |
| 2939 | + |
| 2940 | +// TODO: Code restructure needed to reduce redundant codes. |
| 2941 | +/* |
| 2942 | + * helper function to store an int/logical value into a varying int/logical |
| 2943 | + */ |
| 2944 | +static void |
| 2945 | +store_int_kind(void *b, __INT_T *int_kind, int v) |
| 2946 | +{ |
| 2947 | + switch (*int_kind) { |
| 2948 | + case 1: |
| 2949 | + *(__INT1_T *)b = (__INT1_T)v; |
| 2950 | + break; |
| 2951 | + case 2: |
| 2952 | + *(__INT2_T *)b = (__INT2_T)v; |
| 2953 | + break; |
| 2954 | + case 4: |
| 2955 | + *(__INT4_T *)b = (__INT4_T)v; |
| 2956 | + break; |
| 2957 | + case 8: |
| 2958 | + *(__INT8_T *)b = (__INT8_T)v; |
| 2959 | + break; |
| 2960 | + default: |
| 2961 | + __fort_abort("store_int_kind: unexpected int kind"); |
| 2962 | + } |
| 2963 | +} |
| 2964 | + |
| 2965 | +// TODO: Code restructure needed to reduce redundant codes. |
| 2966 | +/** \brief Copy msg string to statmsg and padding with blank space at the end. |
| 2967 | + * |
| 2968 | + * \param statmsg is the Fortran string we want to assign values. |
| 2969 | + * \param msg is the string contains error message. |
| 2970 | + * \param len is the length of statmsg. |
| 2971 | + */ |
| 2972 | +static void |
| 2973 | +ftn_msgcpy(char *statmsg, const char *msg, int len) { |
| 2974 | + int i; |
| 2975 | + for (i=0; i<len; ++i) { |
| 2976 | + statmsg[i] = *msg ? *msg++ : ' '; |
| 2977 | + } |
| 2978 | +} |
0 commit comments