Skip to content

Commit 979ba84

Browse files
committed
add c source
1 parent 35e7146 commit 979ba84

File tree

4 files changed

+256
-3
lines changed

4 files changed

+256
-3
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.14.0)
44
set(CMAKE_USER_MAKE_RULES_OVERRIDE ${CMAKE_CURRENT_SOURCE_DIR}/config/DefaultFlags.cmake)
55

66
project(fortran_stdlib
7-
LANGUAGES Fortran
7+
LANGUAGES Fortran C
88
DESCRIPTION "Community driven and agreed upon de facto standard library for Fortran"
99
)
1010

config/fypp_deployment.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ def recursive_copy(folder):
9797
for root, _, files in os.walk(folder):
9898
for file in files:
9999
if file not in prune:
100-
if file.endswith(".f90") or file.endswith(".F90") or file.endswith(".dat") or file.endswith(".npy"):
100+
if file.endswith((".f90", ".F90", ".dat", ".npy", ".c")):
101101
shutil.copy2(os.path.join(root, file), 'stdlib-fpm'+os.sep+folder+os.sep+file)
102102
recursive_copy('src')
103103
recursive_copy('test')
@@ -162,4 +162,4 @@ def fpm_build(args,unknown):
162162
#==========================================
163163
# build using fpm
164164
if args.build:
165-
fpm_build(args,unknown)
165+
fpm_build(args,unknown)

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ set(SRC
117117
stdlib_hashmap_open.f90
118118
stdlib_logger.f90
119119
stdlib_sorting_radix_sort.f90
120+
stdlib_system_subprocess.c
120121
stdlib_system.F90
121122
stdlib_sparse.f90
122123
stdlib_specialfunctions.f90

src/stdlib_system_subprocess.c

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
#include <sys/types.h>
2+
#include <stdio.h>
3+
#include <stdbool.h>
4+
#include <stdint.h>
5+
6+
#ifdef _WIN32
7+
#include <windows.h>
8+
#else
9+
#include <sys/wait.h>
10+
#include <unistd.h>
11+
#endif // _WIN32
12+
13+
// Typedefs
14+
typedef void* stdlib_handle;
15+
typedef int64_t stdlib_pid;
16+
17+
18+
/////////////////////////////////////////////////////////////////////////////////////
19+
// Windows-specific code
20+
/////////////////////////////////////////////////////////////////////////////////////
21+
#ifdef _WIN32
22+
23+
// On Windows systems: create a new process
24+
void process_create_windows(const char* cmd, const char* stdin_stream,
25+
const char* stdin_file, const char* stdout_file, const char* stderr_file,
26+
stdlib_handle* handle, stdlib_pid* pid) {
27+
28+
STARTUPINFO si;
29+
PROCESS_INFORMATION pi;
30+
HANDLE hStdout = NULL, hStderr = NULL;
31+
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
32+
FILE* stdin_fp = NULL;
33+
34+
// Initialize null handle
35+
(*handle) = NULL;
36+
(*pid) = 0;
37+
38+
ZeroMemory(&si, sizeof(si));
39+
si.cb = sizeof(STARTUPINFO);
40+
41+
// If possible, we redirect stdout/stderr to file handles directly.
42+
// This will override any cmd redirection settings (<>). For stdin
43+
44+
// Write stdin_stream to stdin_file if provided
45+
if (stdin_stream && stdin_file) {
46+
stdin_fp = fopen(stdin_file, "w");
47+
if (!stdin_fp) {
48+
fprintf(stderr, "Failed to open stdin file for writing\n");
49+
return;
50+
}
51+
fputs(stdin_stream, stdin_fp);
52+
fclose(stdin_fp);
53+
}
54+
55+
// Open stdout file if provided
56+
if (stdout_file) {
57+
hStdout = CreateFile(stdout_file, GENERIC_WRITE, 0, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
58+
if (hStdout == INVALID_HANDLE_VALUE) {
59+
fprintf(stderr, "Failed to open stdout file\n");
60+
return;
61+
}
62+
si.hStdOutput = hStdout;
63+
si.dwFlags |= STARTF_USESTDHANDLES;
64+
}
65+
66+
// Open stderr file if provided
67+
if (stderr_file) {
68+
hStderr = CreateFile(stderr_file, GENERIC_WRITE, 0, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
69+
if (hStderr == INVALID_HANDLE_VALUE) {
70+
fprintf(stderr, "Failed to open stderr file\n");
71+
return;
72+
}
73+
si.hStdError = hStderr;
74+
si.dwFlags |= STARTF_USESTDHANDLES;
75+
}
76+
77+
// Prepare the command line with redirected stdin
78+
char full_cmd[4096];
79+
if (stdin_file) {
80+
snprintf(full_cmd, sizeof(full_cmd), "%s < %s", cmd, stdin_file);
81+
} else {
82+
snprintf(full_cmd, sizeof(full_cmd), "%s", cmd);
83+
}
84+
85+
// Create the process
86+
BOOL success = CreateProcess(
87+
NULL, // Application name
88+
full_cmd, // Command line
89+
NULL, // Process security attributes
90+
NULL, // Thread security attributes
91+
TRUE, // Inherit handles
92+
0, // Creation flags
93+
NULL, // Environment variables
94+
NULL, // Current directory
95+
&si, // STARTUPINFO
96+
&pi // PROCESS_INFORMATION
97+
);
98+
99+
if (!success) {
100+
fprintf(stderr, "CreateProcess failed (%lud).\n", GetLastError());
101+
return;
102+
}
103+
104+
// Close unneeded handles
105+
if (hStdout) CloseHandle(hStdout);
106+
if (hStderr) CloseHandle(hStderr);
107+
108+
// Return the process handle for status queries
109+
CloseHandle(pi.hThread); // Close the thread handle
110+
(*handle) = (stdlib_handle) pi.hProcess; // Return the process handle
111+
(*pid) = (stdlib_pid) pi.dwProcessId;
112+
113+
}
114+
115+
// Query process state on a Windows system
116+
void process_query_status_windows(int pid, bool wait, bool* is_running, int* exit_code)
117+
{
118+
int wait_code;
119+
HANDLE hProcess;
120+
DWORD dwExitCode;
121+
122+
// Open the process with the appropriate access rights
123+
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, pid);
124+
125+
// Error opening the process, likely pid does not exist
126+
if (hProcess == NULL) {
127+
*is_running = false;
128+
*exit_code = -1;
129+
return;
130+
}
131+
132+
133+
if (wait) {
134+
// Wait for the process to terminate
135+
wait_code = WaitForSingleObject(hProcess, INFINITE);
136+
} else {
137+
// Check if the process has terminated
138+
wait_code = WaitForSingleObject(hProcess, 0);
139+
}
140+
141+
if (wait_code == WAIT_OBJECT_0) {
142+
// Process has exited, get the exit code
143+
*is_running = false;
144+
if (GetExitCodeProcess(hProcess, &dwExitCode)) {
145+
*exit_code = dwExitCode;
146+
} else {
147+
*exit_code = -1; // Error retrieving the exit code
148+
}
149+
} else if (wait_code == WAIT_TIMEOUT) {
150+
// Process is still running
151+
*is_running = true;
152+
*exit_code = 0;
153+
} else { // WAIT_FAILED
154+
// Error occurred
155+
*is_running = false;
156+
*exit_code = -1; // Error occurred in WaitForSingleObject
157+
}
158+
159+
// Close the process handle
160+
CloseHandle(hProcess);
161+
}
162+
163+
#else // _WIN32
164+
165+
/////////////////////////////////////////////////////////////////////////////////////
166+
// Unix-specific code
167+
/////////////////////////////////////////////////////////////////////////////////////
168+
void process_query_status_unix(int pid, bool wait, bool* is_running, int* exit_code)
169+
{
170+
int status;
171+
int wait_code;
172+
173+
// Wait or return immediately if no status change
174+
int options = wait ? 0 : WNOHANG;
175+
176+
// Call waitpid to check the process state
177+
wait_code = waitpid(pid, &status, options);
178+
179+
if (wait_code > 0) {
180+
// Process state was updated
181+
if (WIFEXITED(status)) {
182+
*is_running = false;
183+
184+
// Get exit code
185+
*exit_code = WEXITSTATUS(status);
186+
} else if (WIFSIGNALED(status)) {
187+
*is_running = false;
188+
189+
// Use negative value to indicate termination by signal
190+
*exit_code = -WTERMSIG(status);
191+
} else {
192+
// Process is still running: no valid exit code yet
193+
*is_running = true;
194+
*exit_code = 0;
195+
}
196+
} else if (wait_code == 0) {
197+
// No status change; process is still running
198+
*is_running = true;
199+
*exit_code = 0;
200+
} else {
201+
// Error occurred
202+
*is_running = false;
203+
*exit_code = -1; // Indicate an error
204+
}
205+
}
206+
207+
// On UNIX systems: just fork a new process. The command line will be executed from Fortran.
208+
void process_create_posix(stdlib_handle* handle, stdlib_pid* pid)
209+
{
210+
211+
(*handle) = NULL;
212+
(*pid) = (stdlib_pid) fork();
213+
}
214+
215+
#endif // _WIN32
216+
217+
/////////////////////////////////////////////////////////////////////////////////////
218+
// Cross-platform interface
219+
/////////////////////////////////////////////////////////////////////////////////////
220+
221+
// Create or fork process
222+
void process_create(const char* cmd, const char* stdin_stream, const char* stdin_file,
223+
const char* stdout_file, const char* stderr_file,
224+
stdlib_handle* handle, stdlib_pid* pid) {
225+
#ifdef _WIN32
226+
process_create_windows(cmd, stdin_stream, stdin_file, stdout_file, stderr_file, handle, pid);
227+
#else
228+
process_create_posix(handle, pid);
229+
#endif // _WIN32
230+
}
231+
232+
// Cross-platform interface: query process state
233+
void process_query_status(int pid, bool wait, bool* is_running, int* exit_code)
234+
{
235+
#ifdef _WIN32
236+
process_query_status_windows(pid, wait, is_running, exit_code);
237+
#else
238+
process_query_status_unix (pid, wait, is_running, exit_code);
239+
#endif // _WIN32
240+
}
241+
242+
// Cross-platform interface: sleep(seconds)
243+
void process_wait(float seconds)
244+
{
245+
#ifdef _WIN32
246+
DWORD dwMilliseconds = 1000*seconds;
247+
Sleep(dwMilliseconds);
248+
#else
249+
int uSeconds = (int) 1.0e6*seconds;
250+
usleep(uSeconds);
251+
#endif // _WIN32
252+
}

0 commit comments

Comments
 (0)