aboutsummaryrefslogtreecommitdiff
path: root/sys/compat/linux/linux_misc.c
diff options
context:
space:
mode:
authorJulian Elischer <julian@FreeBSD.org>1998-12-19 02:55:34 +0000
committerJulian Elischer <julian@FreeBSD.org>1998-12-19 02:55:34 +0000
commit6626c6045c38a22c2dc57621a840ae612da0e2e3 (patch)
treeb5baf90edc2cac8af964657b46d2d820dce40d35 /sys/compat/linux/linux_misc.c
parent02489dd7373f6eb94fc23050f36acaaa2b71167e (diff)
downloadsrc-6626c6045c38a22c2dc57621a840ae612da0e2e3.tar.gz
src-6626c6045c38a22c2dc57621a840ae612da0e2e3.zip
Reviewed by: Luoqi Chen, Jordan Hubbard
Submitted by: "Richard Seaman, Jr." <lists@tar.com> Obtained from: linux :-) Code to allow Linux Threads to run under FreeBSD. By default not enabled This code is dependent on the conditional COMPAT_LINUX_THREADS (suggested by Garret) This is not yet a 'real' option but will be within some number of hours.
Notes
Notes: svn path=/head/; revision=41931
Diffstat (limited to 'sys/compat/linux/linux_misc.c')
-rw-r--r--sys/compat/linux/linux_misc.c174
1 files changed, 173 insertions, 1 deletions
diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
index 68fee0f657d6..4b441fd81370 100644
--- a/sys/compat/linux/linux_misc.c
+++ b/sys/compat/linux/linux_misc.c
@@ -25,7 +25,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: linux_misc.c,v 1.46 1998/12/04 22:54:50 archie Exp $
+ * $Id: linux_misc.c,v 1.47 1998/12/10 13:47:18 jkh Exp $
*/
#include <sys/param.h>
@@ -41,6 +41,9 @@
#include <sys/resourcevar.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
+#ifdef COMPAT_LINUX_THREADS
+#include <sys/unistd.h>
+#endif /* COMPAT_LINUX_THREADS */
#include <sys/vnode.h>
#include <sys/wait.h>
#include <sys/time.h>
@@ -560,6 +563,84 @@ linux_fork(struct proc *p, struct linux_fork_args *args)
return 0;
}
+#ifndef COMPAT_LINUX_THREADS
+int
+linux_clone(struct proc *p, struct linux_clone_args *args)
+{
+ printf("linux_clone(%d): Not enabled\n", p->p_pid);
+ return (EOPNOTSUPP);
+}
+
+#else
+#define CLONE_VM 0x100
+#define CLONE_FS 0x200
+#define CLONE_FILES 0x400
+#define CLONE_SIGHAND 0x800
+#define CLONE_PID 0x1000
+
+int
+linux_clone(struct proc *p, struct linux_clone_args *args)
+{
+ int error, ff = RFPROC;
+ struct proc *p2;
+ int growable;
+ int initstacksize;
+ int maxstacksize;
+ int exit_signal;
+ vm_map_entry_t entry;
+ vm_map_t map;
+ vm_offset_t start;
+ struct rfork_args rf_args;
+
+#ifdef SMP
+ printf("linux_clone(%d): does not work with SMP yet\n", p->p_pid);
+ return (EOPNOTSUPP);
+#endif
+#ifdef DEBUG
+ if (args->flags & CLONE_PID)
+ printf("linux_clone(%d): CLONE_PID not yet supported\n", p->p_pid);
+ printf ("linux_clone(%d): invoked with flags %x and stack %x\n", p->p_pid,
+ (unsigned int)args->flags, (unsigned int)args->stack);
+#endif
+
+ if (!args->stack)
+ return (EINVAL);
+ exit_signal = args->flags & 0x000000ff;
+ if (exit_signal >= LINUX_NSIG)
+ return EINVAL;
+ exit_signal = linux_to_bsd_signal[exit_signal];
+
+ /* RFTHREAD probably not necessary here, but it shouldn't hurt either */
+ ff |= RFTHREAD;
+
+ if (args->flags & CLONE_VM)
+ ff |= RFMEM;
+ if (args->flags & CLONE_SIGHAND)
+ ff |= RFSIGSHARE;
+ if (!(args->flags & CLONE_FILES))
+ ff |= RFFDG;
+
+ error = 0;
+ start = 0;
+
+ rf_args.flags = ff;
+ if (error = rfork(p, &rf_args))
+ return error;
+
+ p2 = pfind(p->p_retval[0]);
+ if (p2 == 0)
+ return ESRCH;
+
+ p2->p_sigparent = exit_signal;
+ p2->p_md.md_regs->tf_esp = (unsigned int)args->stack;
+
+#ifdef DEBUG
+ printf ("linux_clone(%d): successful rfork to %d\n", p->p_pid, p2->p_pid);
+#endif
+ return 0;
+}
+
+#endif /* COMPAT_LINUX_THREADS */
/* XXX move */
struct linux_mmap_argv {
linux_caddr_t addr;
@@ -570,6 +651,11 @@ struct linux_mmap_argv {
int pos;
};
+#ifdef COMPAT_LINUX_THREADS
+#define STACK_SIZE (2 * 1024 * 1024)
+#define GUARD_SIZE (4 * PAGE_SIZE)
+
+#endif /* COMPAT_LINUX_THREADS */
int
linux_mmap(struct proc *p, struct linux_mmap_args *args)
{
@@ -602,8 +688,70 @@ linux_mmap(struct proc *p, struct linux_mmap_args *args)
bsd_args.flags |= MAP_FIXED;
if (linux_args.flags & LINUX_MAP_ANON)
bsd_args.flags |= MAP_ANON;
+#ifndef COMPAT_LINUX_THREADS
bsd_args.addr = linux_args.addr;
bsd_args.len = linux_args.len;
+#else
+
+#if !defined(USE_VM_STACK) && !defined(USE_VM_STACK_FOR_EXEC)
+ /* Linux Threads will map into the proc stack space, unless
+ we prevent it. This causes problems if we're not using
+ our VM_STACK options.
+ */
+ if ((unsigned int)linux_args.addr + linux_args.len > (USRSTACK - MAXSSIZ))
+ return (EINVAL);
+#endif
+
+ if (linux_args.flags & LINUX_MAP_GROWSDOWN) {
+
+#ifdef USE_VM_STACK
+ /* USE_VM_STACK is defined (or not) in vm/vm_map.h */
+ bsd_args.flags |= MAP_STACK;
+#endif
+
+ /* The linux MAP_GROWSDOWN option does not limit auto
+ growth of the region. Linux mmap with this option
+ takes as addr the inital BOS, and as len, the initial
+ region size. It can then grow down from addr without
+ limit. However, linux threads has an implicit internal
+ limit to stack size of STACK_SIZE. Its just not
+ enforced explicitly in linux. But, here we impose
+ a limit of (STACK_SIZE - GUARD_SIZE) on the stack
+ region, since we can do this with our mmap.
+
+ Our mmap with MAP_STACK takes addr as the maximum
+ downsize limit on BOS, and as len the max size of
+ the region. It them maps the top SGROWSIZ bytes,
+ and autgrows the region down, up to the limit
+ in addr.
+
+ If we don't use the MAP_STACK option, the effect
+ of this code is to allocate a stack region of a
+ fixed size of (STACK_SIZE - GUARD_SIZE).
+ */
+
+ /* This gives us TOS */
+ bsd_args.addr = linux_args.addr + linux_args.len;
+
+ /* This gives us our maximum stack size */
+ if (linux_args.len > STACK_SIZE - GUARD_SIZE)
+ bsd_args.len = linux_args.len;
+ else
+ bsd_args.len = STACK_SIZE - GUARD_SIZE;
+
+ /* This gives us a new BOS. If we're using VM_STACK, then
+ mmap will just map the top SGROWSIZ bytes, and let
+ the stack grow down to the limit at BOS. If we're
+ not using VM_STACK we map the full stack, since we
+ don't have a way to autogrow it.
+ */
+ bsd_args.addr -= bsd_args.len;
+
+ } else {
+ bsd_args.addr = linux_args.addr;
+ bsd_args.len = linux_args.len;
+ }
+#endif /* COMPAT_LINUX_THREADS */
bsd_args.prot = linux_args.prot | PROT_READ; /* always required */
bsd_args.fd = linux_args.fd;
bsd_args.pos = linux_args.pos;
@@ -830,11 +978,25 @@ linux_waitpid(struct proc *p, struct linux_waitpid_args *args)
#endif
tmp.pid = args->pid;
tmp.status = args->status;
+#ifndef COMPAT_LINUX_THREADS
tmp.options = args->options;
+#else
+ /* This filters out the linux option _WCLONE. I don't
+ think we need it, but I could be wrong. If we need
+ it, we need to fix wait4, since it will give us an
+ error return of EINVAL if we pass in _WCLONE, and
+ of course, it won't do anything with it.
+ */
+ tmp.options = (args->options & (WNOHANG | WUNTRACED));
+#endif /* COMPAT_LINUX_THREADS */
tmp.rusage = NULL;
if (error = wait4(p, &tmp))
+#ifndef COMPAT_LINUX_THREADS
return error;
+#else
+ return error;
+#endif /* COMPAT_LINUX_THREADS */
if (args->status) {
if (error = copyin(args->status, &tmpstat, sizeof(int)))
return error;
@@ -867,7 +1029,17 @@ linux_wait4(struct proc *p, struct linux_wait4_args *args)
#endif
tmp.pid = args->pid;
tmp.status = args->status;
+#ifndef COMPAT_LINUX_THREADS
tmp.options = args->options;
+#else
+ /* This filters out the linux option _WCLONE. I don't
+ think we need it, but I could be wrong. If we need
+ it, we need to fix wait4, since it will give us an
+ error return of EINVAL if we pass in _WCLONE, and
+ of course, it won't do anything with it.
+ */
+ tmp.options = (args->options & (WNOHANG | WUNTRACED));
+#endif /* COMPAT_LINUX_THREADS */
tmp.rusage = args->rusage;
if (error = wait4(p, &tmp))