Files
oldlinux-files/gnu/glibc/glibc-1.03/sysdeps/mach/hurd/__vfork.c
2024-02-19 00:24:47 -05:00

166 lines
5.2 KiB
C

/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
#include <ansidecl.h>
#include <errno.h>
#include <unistd.h>
#include <hurd.h>
extern const struct
{
int set;
struct _hurd_dtable *dtable;
} _hurd_dtable_set;
/* Clone the calling process, but without copying the whole address space.
The the calling process is suspended until the the new process exits or is
replaced by a call to `execve'. Return -1 for errors, 0 to the new process,
and the process ID of the new process to the old process. */
int
DEFUN_VOID(__vfork)
{
error_t err;
process_t newproc;
struct _hurd_sigstate *ss = _hurd_thread_sigstate (__mach_thread_self ());
__mutex_lock (&_hurd_lock);
__proc_dostop (_hurd_proc, __mach_thread_self ());
if (err = __proc_register (_hurd_proc, __mach_task_self (),
_hurd_sigport, &newproc))
goto lose;
if (_hurd_dtable_set.set)
{
struct _hurd_dtable *const dt = _hurd_dtable_set.dtable;
__mutex_lock (&dt->lock);
ss->vfork_saved.dtable = *dt;
dt->d = malloc (dt->size * sizeof (dt->d[0]));
if (dt->d == NULL)
{
dt->d = ss->vfork_saved.dtable.d;
__mutex_unlock (&dt->lock);
goto lose;
}
for (i = 0; i < dt->size; ++i)
{
dt->d[i] = ss->vfork_saved.dtable.d[i];
if (dt->d[i].server != MACH_PORT_NULL)
__mach_port_mod_refs (__mach_task_self (),
dt->d[i].server,
MACH_PORT_RIGHT_SEND, 1);
}
__mutex_unlock (&dt->lock);
}
ss->vforked = 1;
ss->vfork_saved.proc = _hurd_proc;
_hurd_proc = newproc;
ss->vfork_saved.auth = _hurd_auth;
__mach_port_mod_refs (__mach_task_self (), ss->vfork_saved.auth,
MACH_PORT_RIGHT_SEND, 1);
ss->vfork_saved.ccdir = _hurd_ccdir;
__mach_port_mod_refs (__mach_task_self (), ss->vfork_saved.ccdir,
MACH_PORT_RIGHT_SEND, 1);
ss->vfork_saved.cwdir = _hurd_cwdir;
__mach_port_mod_refs (__mach_task_self (), ss->vfork_saved.cwdir,
MACH_PORT_RIGHT_SEND, 1);
ss->vfork_saved.crdir = _hurd_crdir;
__mach_port_mod_refs (__mach_task_self (), ss->vfork_saved.crdir,
MACH_PORT_RIGHT_SEND, 1);
ss->vfork_saved.umask = _hurd_umask;
ss->vfork_saved.ctty_fstype = _hurd_ctty_fstype;
ss->vfork_saved.ctty_fsid = _hurd_ctty_fsid;
ss->vfork_saved.ctty_fileid = _hurd_ctty_fileid;
__proc_getpids (_hurd_proc, &_hurd_pid, &_hurd_ppid, &_hurd_orphaned);
if (setjmp (ss->vfork_saved.continuation))
{
/* The vfork child has exec'd or exitted.
SS->lock is held. */
pid_t child = _hurd_pid;
/* Restore the saved state of the parent fork. */
mach_port_t osigport, otask;
__mutex_lock (&_hurd_lock);
ss->vforked = 0;
_hurd_proc = ss->vfork_saved.proc;
_hurd_auth = ss->vfork_saved.auth;
_hurd_id_valid = 0;
if (_hurd_rid_auth != MACH_PORT_NULL)
{
__mach_port_deallocate (__mach_task_self (), _hurd_rid_auth);
_hurd_rid_auth = MACH_PORT_NULL;
}
_hurd_ccdir = ss->vfork_saved.ccdir;
_hurd_cwdir = ss->vfork_saved.cwdir;
_hurd_crdir = ss->vfork_saved.crdir;
_hurd_umask = ss->vfork_saved.umask;
__mutex_lock (&_hurd_dtable.lock);
_hurd_ctty_fstype = ss->vfork_saved.ctty_fstype;
_hurd_ctty_fsid = ss->vfork_saved.ctty_fsid;
_hurd_ctty_fileid = ss->vfork_saved.ctty_fileid;
if (_hurd_dtable_set.set)
{
__mutex_lock (&_hurd_dtable_set.dtable->lock);
*_hurd_dtable_set.dtable = *ss->vfork_saved.dtable;
__mutex_unlock (&_hurd_dtable_set.dtable->lock);
}
__proc_setports (_hurd_proc, __mach_task_self (), sigport,
&osigport, &otask);
if (osigport != MACH_PORT_NULL)
__mach_port_deallocate (__mach_task_self (), osigport);
if (otask != MACH_PORT_NULL)
__mach_port_deallocate (__mach_task_self (), otask);
__proc_getpids (_hurd_proc, &_hurd_pid, &_hurd_ppid, &_hurd_orphaned);
err = 0;
lose:
__mutex_unlock (&_hurd_lock);
__mutex_unlock (&ss->lock);
/* Resume all threads. */
{
const thread_t me = __mach_thread_self ();
thread_t *threads;
size_t nthreads;
for (__task_threads (__mach_task_self (), &threads, &nthreads);
nthreads-- > 0;
__mach_port_deallocate (__mach_task_self (), *threads++))
if (*threads != me && *threads != _hurd_sigport_thread)
__thread_resume (*threads);
}
if (err)
return __hurd_fail (err);
return child;
}
/* Return to the vfork child. */
__mutex_unlock (&ss->lock);
__thread_resume (_hurd_sigport_thread);
return 0;
}