Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2020-08-01 22:35:58 +0300
committerCorinna Vinschen <corinna@vinschen.de>2020-08-03 13:41:44 +0300
commit3fbfcd11fb09d5f47af3043ee47ec5c7d863d872 (patch)
treef4c67c6b4fdd62945ed90d9fc00f3d3595fc6412 /newlib/libc/posix
parentc222c1b294c7d6e2b0e554aa2fbde79c8b768594 (diff)
Cygwin: posix_spawn: add Cygwin-specific code fixing process synchronisation
Newlib's posix_spawn has been taken from FreeBSD. The code relies on BSD-specific behaviour of vfork, namely the fact that vfork blocks the parent until the child exits or calls execve as well as the fact that the child shares parent memory in non-COW mode. This behaviour can't be emulated by Cygwin. Cygwin's vfork is equivalent to fork. This is POSIX-compliant, but it's lacking BSD's vfork ingrained synchronization of the parent to wait for the child calling execve, or the chance to just write a variable and the parent will see the result. So this requires a Cygwin-specific solution. The core function of posix_spawn, called do_posix_spawn is now implemented twice, once using the BSD method, and once for Cygwin using Windows synchronization under the hood waiting for the child to call execve and signalling errors upstream. The Windows specifics are hidden inside Cygwin, so newlib only calls internal Cygwin functions. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Diffstat (limited to 'newlib/libc/posix')
-rw-r--r--newlib/libc/posix/posix_spawn.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/newlib/libc/posix/posix_spawn.c b/newlib/libc/posix/posix_spawn.c
index 19c5cd0fe..005471fde 100644
--- a/newlib/libc/posix/posix_spawn.c
+++ b/newlib/libc/posix/posix_spawn.c
@@ -254,6 +254,69 @@ process_file_actions(const posix_spawn_file_actions_t fa)
return (0);
}
+#ifdef __CYGWIN__
+/* Cygwin's vfork does not follow BSD vfork semantics. Rather it's equivalent
+ to fork. While that's POSIX compliant, the below FreeBSD implementation
+ relying on BSD vfork semantics doesn't work as expected on Cygwin. The
+ following Cygwin-specific code handles the synchronization FreeBSD gets
+ for free by using vfork. */
+
+extern int __posix_spawn_sem_create (void **semp);
+extern void __posix_spawn_sem_release (void *sem, int error);
+extern int __posix_spawn_sem_wait_and_close (void *sem, void *proc);
+extern int __posix_spawn_fork (void **proc);
+extern int __posix_spawn_execvpe (const char *path, char * const *argv,
+ char *const *envp, void *sem,
+ int use_env_path);
+
+
+static int
+do_posix_spawn(pid_t *pid, const char *path,
+ const posix_spawn_file_actions_t *fa,
+ const posix_spawnattr_t *sa,
+ char * const argv[], char * const envp[], int use_env_path)
+{
+ int error;
+ void *sem, *proc;
+ pid_t p;
+
+ error = __posix_spawn_sem_create(&sem);
+ if (error)
+ return error;
+
+ p = __posix_spawn_fork(&proc);
+ switch (p) {
+ case -1:
+ return (errno);
+ case 0:
+ if (sa != NULL) {
+ error = process_spawnattr(*sa);
+ if (error) {
+ __posix_spawn_sem_release(sem, error);
+ _exit(127);
+ }
+ }
+ if (fa != NULL) {
+ error = process_file_actions(*fa);
+ if (error) {
+ __posix_spawn_sem_release(sem, error);
+ _exit(127);
+ }
+ }
+ __posix_spawn_execvpe(path, argv,
+ envp != NULL ? envp : *p_environ,
+ sem, use_env_path);
+ _exit(127);
+ default:
+ error = __posix_spawn_sem_wait_and_close(sem, proc);
+ if (error != 0)
+ waitpid(p, NULL, WNOHANG);
+ else if (pid != NULL)
+ *pid = p;
+ return (error);
+ }
+}
+#else
static int
do_posix_spawn(pid_t *pid, const char *path,
const posix_spawn_file_actions_t *fa,
@@ -292,6 +355,7 @@ do_posix_spawn(pid_t *pid, const char *path,
return (error);
}
}
+#endif
int
posix_spawn (pid_t *pid,