summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1996-02-23 18:49:25 +0000
committerpeter <peter@FreeBSD.org>1996-02-23 18:49:25 +0000
commit5239b23b5dd3a758a93e0c2186e188e829e7ba19 (patch)
tree8062bc6b4973f0a1762ce55c879b8c3019d7662e /sys
parent834adf89dc86160b3de01b8991acc8ec96028a47 (diff)
downloadFreeBSD-src-5239b23b5dd3a758a93e0c2186e188e829e7ba19.zip
FreeBSD-src-5239b23b5dd3a758a93e0c2186e188e829e7ba19.tar.gz
kern_descrip.c: add fdshare()/fdcopy()
kern_fork.c: add the tiny bit of code for rfork operation. kern/sysv_*: shmfork() takes one less arg, it was never used. sys/shm.h: drop "isvfork" arg from shmfork() prototype sys/param.h: declare rfork args.. (this is where OpenBSD put it..) sys/filedesc.h: protos for fdshare/fdcopy. vm/vm_mmap.c: add minherit code, add rounding to mmap() type args where it makes sense. vm/*: drop unused isvfork arg. Note: this rfork() implementation copies the address space mappings, it does not connect the mappings together. ie: once the two processes have split, the pages may be shared, but the address space is not. If one does a mmap() etc, it does not appear in the other. This makes it not useful for pthreads, but it is useful in it's own right for having light-weight threads in a static shared address space. Obtained from: Original by Ron Minnich, extended by OpenBSD
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/kern_descrip.c46
-rw-r--r--sys/kern/kern_fork.c73
-rw-r--r--sys/kern/sysv_ipc.c5
-rw-r--r--sys/kern/sysv_shm.c5
-rw-r--r--sys/sys/filedesc.h4
-rw-r--r--sys/sys/param.h18
-rw-r--r--sys/sys/shm.h4
-rw-r--r--sys/vm/vm_extern.h4
-rw-r--r--sys/vm/vm_glue.c10
-rw-r--r--sys/vm/vm_mmap.c127
10 files changed, 247 insertions, 49 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index d214f0d..8dc24d7 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)kern_descrip.c 8.6 (Berkeley) 4/19/94
- * $Id: kern_descrip.c,v 1.24 1996/01/28 23:41:39 dyson Exp $
+ * $Id: kern_descrip.c,v 1.25 1996/02/04 19:56:34 dyson Exp $
*/
#include <sys/param.h>
@@ -82,6 +82,7 @@ static int finishdup(struct filedesc *fdp, int old, int new, int *retval);
*/
struct file *filehead; /* head of list of open files */
int nfiles; /* actual number of open files */
+extern int cmask;
/*
* System calls on descriptors.
@@ -701,6 +702,49 @@ ffree(fp)
}
/*
+ * Build a new filedesc structure.
+ */
+struct filedesc *
+fdinit(p)
+ struct proc *p;
+{
+ register struct filedesc0 *newfdp;
+ register struct filedesc *fdp = p->p_fd;
+
+ MALLOC(newfdp, struct filedesc0 *, sizeof(struct filedesc0),
+ M_FILEDESC, M_WAITOK);
+ bzero(newfdp, sizeof(struct filedesc0));
+ newfdp->fd_fd.fd_cdir = fdp->fd_cdir;
+ VREF(newfdp->fd_fd.fd_cdir);
+ newfdp->fd_fd.fd_rdir = fdp->fd_rdir;
+ if (newfdp->fd_fd.fd_rdir)
+ VREF(newfdp->fd_fd.fd_rdir);
+
+ /* Create the file descriptor table. */
+ newfdp->fd_fd.fd_refcnt = 1;
+ newfdp->fd_fd.fd_cmask = cmask;
+ newfdp->fd_fd.fd_ofiles = newfdp->fd_dfiles;
+ newfdp->fd_fd.fd_ofileflags = newfdp->fd_dfileflags;
+ newfdp->fd_fd.fd_nfiles = NDFILE;
+
+ newfdp->fd_fd.fd_freefile = 0;
+ newfdp->fd_fd.fd_lastfile = 0;
+
+ return (&newfdp->fd_fd);
+}
+
+/*
+ * Share a filedesc structure.
+ */
+struct filedesc *
+fdshare(p)
+ struct proc *p;
+{
+ p->p_fd->fd_refcnt++;
+ return (p->p_fd);
+}
+
+/*
* Copy a filedesc structure.
*/
struct filedesc *
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index d73ff1a..dbb56c4 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)kern_fork.c 8.6 (Berkeley) 4/8/94
- * $Id: kern_fork.c,v 1.15 1995/12/07 12:46:42 davidg Exp $
+ * $Id: kern_fork.c,v 1.16 1996/01/03 21:42:02 wollman Exp $
*/
#include "opt_ktrace.h"
@@ -56,9 +56,17 @@
#include <vm/vm.h>
#include <vm/vm_param.h>
+#include <vm/lock.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
#include <vm/vm_extern.h>
+#include <vm/vm_inherit.h>
-static int fork1(struct proc *, int, int *);
+static int fork1(struct proc *p, int forktype, int rforkflags, int *retval);
+
+#define ISFORK 0
+#define ISVFORK 1
+#define ISRFORK 2
#ifndef _SYS_SYSPROTO_H_
struct fork_args {
@@ -73,27 +81,38 @@ fork(p, uap, retval)
struct fork_args *uap;
int retval[];
{
-
- return (fork1(p, 0, retval));
+ return (fork1(p, ISFORK, 0, retval));
}
/* ARGSUSED */
int
vfork(p, uap, retval)
struct proc *p;
- struct fork_args *uap;
+ struct vfork_args *uap;
int retval[];
{
+ return (fork1(p, ISVFORK, 0, retval));
+}
- return (fork1(p, 1, retval));
+/* ARGSUSED */
+int
+rfork(p, uap, retval)
+ struct proc *p;
+ struct rfork_args *uap;
+ int retval[];
+{
+ return (fork1(p, ISRFORK, uap->flags, retval));
}
+
int nprocs = 1; /* process 0 */
static int
-fork1(p1, isvfork, retval)
+fork1(p1, forktype, rforkflags, retval)
register struct proc *p1;
- int isvfork, retval[];
+ int forktype;
+ int rforkflags;
+ int retval[];
{
register struct proc *p2;
register uid_t uid;
@@ -101,6 +120,21 @@ fork1(p1, isvfork, retval)
struct proc **hash;
int count;
static int nextpid, pidchecked = 0;
+ int dupfd = 1, cleanfd = 0;
+
+ if (forktype == ISRFORK) {
+ dupfd = 0;
+ if ((rforkflags & RFPROC) == 0)
+ return (EINVAL);
+ if ((rforkflags & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG))
+ return (EINVAL);
+ if (rforkflags & RFFDG)
+ dupfd = 1;
+ if (rforkflags & RFNOWAIT)
+ return (EINVAL); /* XXX unimplimented */
+ if (rforkflags & RFCFDG)
+ cleanfd = 1;
+ }
/*
* Although process entries are dynamically created, we still keep
@@ -235,7 +269,13 @@ again:
if (p2->p_textvp)
VREF(p2->p_textvp);
- p2->p_fd = fdcopy(p1);
+ if (cleanfd)
+ p2->p_fd = fdinit(p1);
+ else if (dupfd)
+ p2->p_fd = fdcopy(p1);
+ else
+ p2->p_fd = fdshare(p1);
+
/*
* If p_limit is still copy-on-write, bump refcnt,
* otherwise get a copy that won't be modified.
@@ -251,7 +291,7 @@ again:
if (p1->p_session->s_ttyvp != NULL && p1->p_flag & P_CONTROLT)
p2->p_flag |= P_CONTROLT;
- if (isvfork)
+ if (forktype == ISVFORK)
p2->p_flag |= P_PPWAIT;
p2->p_pgrpnxt = p1->p_pgrpnxt;
p1->p_pgrpnxt = p2;
@@ -284,6 +324,15 @@ again:
p1->p_flag |= P_NOSWAP;
/*
+ * share as much address space as possible
+ */
+ if (forktype == ISRFORK && (rforkflags & RFMEM)) {
+ (void) vm_map_inherit(&p1->p_vmspace->vm_map,
+ VM_MIN_ADDRESS, VM_MAXUSER_ADDRESS - MAXSSIZ,
+ VM_INHERIT_SHARE);
+ }
+
+ /*
* Set return values for child before vm_fork,
* so they can be copied to child stack.
* We return parent pid, and mark as child in retval[1].
@@ -293,7 +342,7 @@ again:
*/
retval[0] = p1->p_pid;
retval[1] = 1;
- if (vm_fork(p1, p2, isvfork)) {
+ if (vm_fork(p1, p2)) {
/*
* Child process. Set start time and get to work.
*/
@@ -321,7 +370,7 @@ again:
* child to exec or exit, set P_PPWAIT on child, and sleep on our
* proc (in case of exit).
*/
- if (isvfork)
+ if (forktype == ISVFORK)
while (p2->p_flag & P_PPWAIT)
tsleep(p1, PWAIT, "ppwait", 0);
diff --git a/sys/kern/sysv_ipc.c b/sys/kern/sysv_ipc.c
index bd7c0c8..e62068e 100644
--- a/sys/kern/sysv_ipc.c
+++ b/sys/kern/sysv_ipc.c
@@ -1,4 +1,4 @@
-/* $Id: sysv_ipc.c,v 1.2 1996/01/05 16:37:52 wollman Exp $ */
+/* $Id: sysv_ipc.c,v 1.3 1996/01/08 04:30:48 peter Exp $ */
/* $NetBSD: sysv_ipc.c,v 1.7 1994/06/29 06:33:11 cgd Exp $ */
/*
@@ -278,9 +278,8 @@ shmsys(p, uap, retval)
/* called from kern_fork.c */
void
-shmfork(p1, p2, isvfork)
+shmfork(p1, p2)
struct proc *p1, *p2;
- int isvfork;
{
return;
}
diff --git a/sys/kern/sysv_shm.c b/sys/kern/sysv_shm.c
index 72c8a22..a68f8a6 100644
--- a/sys/kern/sysv_shm.c
+++ b/sys/kern/sysv_shm.c
@@ -1,4 +1,4 @@
-/* $Id: sysv_shm.c,v 1.16 1995/12/26 16:03:32 joerg Exp $ */
+/* $Id: sysv_shm.c,v 1.17 1996/01/05 16:38:03 wollman Exp $ */
/* $NetBSD: sysv_shm.c,v 1.23 1994/07/04 23:25:12 glass Exp $ */
/*
@@ -565,9 +565,8 @@ shmsys(p, uap, retval)
}
void
-shmfork(p1, p2, isvfork)
+shmfork(p1, p2)
struct proc *p1, *p2;
- int isvfork;
{
struct shmmap_state *shmmap_s;
size_t size;
diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h
index 7f71cd8..7bd4578 100644
--- a/sys/sys/filedesc.h
+++ b/sys/sys/filedesc.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)filedesc.h 8.1 (Berkeley) 6/2/93
- * $Id: filedesc.h,v 1.6 1995/05/30 08:14:20 rgrimes Exp $
+ * $Id: filedesc.h,v 1.7 1995/11/04 10:35:17 bde Exp $
*/
#ifndef _SYS_FILEDESC_H_
@@ -100,6 +100,8 @@ int fdalloc __P((struct proc *p, int want, int *result));
int fdavail __P((struct proc *p, int n));
int falloc __P((struct proc *p, struct file **resultfp, int *resultfd));
void ffree __P((struct file *));
+struct filedesc *fdinit __P((struct proc *p));
+struct filedesc *fdshare __P((struct proc *p));
struct filedesc *fdcopy __P((struct proc *p));
void fdfree __P((struct proc *p));
int closef __P((struct file *fp,struct proc *p));
diff --git a/sys/sys/param.h b/sys/sys/param.h
index 88e0e16..6766c2f 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)param.h 8.2 (Berkeley) 1/21/94
- * $Id: param.h,v 1.10 1995/12/05 21:03:13 bde Exp $
+ * $Id: param.h,v 1.11 1996/01/30 23:01:04 mpp Exp $
*/
#ifndef _SYS_PARAM_H_
@@ -226,4 +226,20 @@
#define FSHIFT 11 /* bits to right of fixed binary point */
#define FSCALE (1<<FSHIFT)
+/*
+ * rfork() options.
+ *
+ * XXX currently, operations without RFPROC set are not supported.
+ */
+#define RFNAMEG (1<<0) /* UNIMPL new plan9 `name space' */
+#define RFENVG (1<<1) /* UNIMPL copy plan9 `env space' */
+#define RFFDG (1<<2) /* copy fd table */
+#define RFNOTEG (1<<3) /* UNIMPL create new plan9 `note group' */
+#define RFPROC (1<<4) /* change child (else changes curproc) */
+#define RFMEM (1<<5) /* share `address space' */
+#define RFNOWAIT (1<<6) /* UNIMPL parent need not wait() on child */
+#define RFCNAMEG (1<<10) /* UNIMPL zero plan9 `name space' */
+#define RFCENVG (1<<11) /* UNIMPL zero plan9 `env space' */
+#define RFCFDG (1<<12) /* zero fd table */
+
#endif
diff --git a/sys/sys/shm.h b/sys/sys/shm.h
index 7cc6e5a..8dcf9de 100644
--- a/sys/sys/shm.h
+++ b/sys/sys/shm.h
@@ -1,4 +1,4 @@
-/* $Id: shm.h,v 1.6 1995/08/30 00:33:35 bde Exp $ */
+/* $Id: shm.h,v 1.7 1996/01/30 23:01:19 mpp Exp $ */
/* $NetBSD: shm.h,v 1.15 1994/06/29 06:45:17 cgd Exp $ */
/*
@@ -80,7 +80,7 @@ extern struct shminfo shminfo;
extern struct shmid_ds *shmsegs;
void shmexit __P((struct proc *));
-void shmfork __P((struct proc *, struct proc *, int));
+void shmfork __P((struct proc *, struct proc *));
#else /* !KERNEL */
#include <sys/cdefs.h>
diff --git a/sys/vm/vm_extern.h b/sys/vm/vm_extern.h
index c6b3067..b0d7480 100644
--- a/sys/vm/vm_extern.h
+++ b/sys/vm/vm_extern.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)vm_extern.h 8.2 (Berkeley) 1/12/94
- * $Id: vm_extern.h,v 1.22 1995/12/14 09:54:55 phk Exp $
+ * $Id: vm_extern.h,v 1.23 1996/02/04 22:08:57 dyson Exp $
*/
#ifndef _VM_EXTERN_H_
@@ -88,7 +88,7 @@ int vm_fault __P((vm_map_t, vm_offset_t, vm_prot_t, boolean_t));
void vm_fault_copy_entry __P((vm_map_t, vm_map_t, vm_map_entry_t, vm_map_entry_t));
void vm_fault_unwire __P((vm_map_t, vm_offset_t, vm_offset_t));
int vm_fault_wire __P((vm_map_t, vm_offset_t, vm_offset_t));
-int vm_fork __P((struct proc *, struct proc *, int));
+int vm_fork __P((struct proc *, struct proc *));
void vm_map_print __P((/* db_expr_t */ int, boolean_t, /* db_expr_t */ int, char *));
int vm_mmap __P((vm_map_t, vm_offset_t *, vm_size_t, vm_prot_t, vm_prot_t, int, caddr_t, vm_ooffset_t));
vm_offset_t vm_page_alloc_contig __P((vm_offset_t, vm_offset_t, vm_offset_t, vm_offset_t));
diff --git a/sys/vm/vm_glue.c b/sys/vm/vm_glue.c
index 1d45e37..3dfa281 100644
--- a/sys/vm/vm_glue.c
+++ b/sys/vm/vm_glue.c
@@ -59,10 +59,9 @@
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
- * $Id: vm_glue.c,v 1.38 1996/01/29 12:10:30 davidg Exp $
+ * $Id: vm_glue.c,v 1.39 1996/02/22 10:57:36 davidg Exp $
*/
-#include "opt_sysvipc.h"
#include "opt_ddb.h"
#include <sys/param.h>
@@ -210,9 +209,8 @@ vsunlock(addr, len, dirtied)
* after cpu_fork returns.
*/
int
-vm_fork(p1, p2, isvfork)
+vm_fork(p1, p2)
register struct proc *p1, *p2;
- int isvfork;
{
register struct user *up;
vm_offset_t addr, ptaddr, ptpa;
@@ -234,10 +232,8 @@ vm_fork(p1, p2, isvfork)
UPT_MIN_ADDRESS - UPAGES * PAGE_SIZE, VM_MAX_ADDRESS, VM_INHERIT_NONE);
p2->p_vmspace = vmspace_fork(p1->p_vmspace);
-#ifdef SYSVSHM
if (p1->p_vmspace->vm_shm)
- shmfork(p1, p2, isvfork);
-#endif
+ shmfork(p1, p2);
/*
* Allocate a wired-down (for now) pcb and kernel stack for the
diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c
index c68f5f4..d7d597d 100644
--- a/sys/vm/vm_mmap.c
+++ b/sys/vm/vm_mmap.c
@@ -38,7 +38,7 @@
* from: Utah $Hdr: vm_mmap.c 1.6 91/10/21$
*
* @(#)vm_mmap.c 8.4 (Berkeley) 1/12/94
- * $Id: vm_mmap.c,v 1.34 1995/12/17 07:19:57 bde Exp $
+ * $Id: vm_mmap.c,v 1.35 1996/01/19 03:59:59 dyson Exp $
*/
/*
@@ -319,7 +319,7 @@ msync(p, uap, retval)
int *retval;
{
vm_offset_t addr;
- vm_size_t size;
+ vm_size_t size, pageoff;
int flags;
vm_map_t map;
int rv;
@@ -329,8 +329,18 @@ msync(p, uap, retval)
size = round_page((vm_size_t) uap->len);
flags = uap->flags;
- if (((int) addr & PAGE_MASK) || addr + size < addr ||
- (flags & (MS_ASYNC|MS_INVALIDATE)) == (MS_ASYNC|MS_INVALIDATE))
+ /*
+ * Align the address to a page boundary,
+ * and adjust the size accordingly.
+ */
+ pageoff = (addr & PAGE_MASK);
+ addr -= pageoff;
+ size += pageoff;
+ size = (vm_size_t) round_page(size);
+ if ((int)size < 0)
+ return(EINVAL);
+
+ if ((flags & (MS_ASYNC|MS_INVALIDATE)) == (MS_ASYNC|MS_INVALIDATE))
return (EINVAL);
/*
@@ -385,15 +395,25 @@ munmap(p, uap, retval)
int *retval;
{
vm_offset_t addr;
- vm_size_t size;
+ vm_size_t size, pageoff;
vm_map_t map;
addr = (vm_offset_t) uap->addr;
- if ((addr & PAGE_MASK) || uap->len < 0)
- return (EINVAL);
- size = (vm_size_t) round_page(uap->len);
+ size = (vm_size_t) uap->len;
+
+ /*
+ * Align the address to a page boundary,
+ * and adjust the size accordingly.
+ */
+ pageoff = (addr & PAGE_MASK);
+ addr -= pageoff;
+ size += pageoff;
+ size = (vm_size_t) round_page(size);
+ if ((int)size < 0)
+ return(EINVAL);
if (size == 0)
return (0);
+
/*
* Check for illegal addresses. Watch out for address wrap... Note
* that VM_*_ADDRESS are not constants due to casts (argh).
@@ -442,15 +462,24 @@ mprotect(p, uap, retval)
int *retval;
{
vm_offset_t addr;
- vm_size_t size;
+ vm_size_t size, pageoff;
register vm_prot_t prot;
addr = (vm_offset_t) uap->addr;
- if ((addr & PAGE_MASK) || uap->len < 0)
- return (EINVAL);
size = (vm_size_t) uap->len;
prot = uap->prot & VM_PROT_ALL;
+ /*
+ * Align the address to a page boundary,
+ * and adjust the size accordingly.
+ */
+ pageoff = (addr & PAGE_MASK);
+ addr -= pageoff;
+ size += pageoff;
+ size = (vm_size_t) round_page(size);
+ if ((int)size < 0)
+ return(EINVAL);
+
switch (vm_map_protect(&p->p_vmspace->vm_map, addr, addr + size, prot,
FALSE)) {
case KERN_SUCCESS:
@@ -462,6 +491,48 @@ mprotect(p, uap, retval)
}
#ifndef _SYS_SYSPROTO_H_
+struct minherit_args {
+ caddr_t addr;
+ int len;
+ int inherit;
+};
+#endif
+int
+minherit(p, uap, retval)
+ struct proc *p;
+ struct minherit_args *uap;
+ int *retval;
+{
+ vm_offset_t addr;
+ vm_size_t size, pageoff;
+ register vm_inherit_t inherit;
+
+ addr = (vm_offset_t)uap->addr;
+ size = (vm_size_t)uap->len;
+ inherit = uap->inherit;
+
+ /*
+ * Align the address to a page boundary,
+ * and adjust the size accordingly.
+ */
+ pageoff = (addr & PAGE_MASK);
+ addr -= pageoff;
+ size += pageoff;
+ size = (vm_size_t) round_page(size);
+ if ((int)size < 0)
+ return(EINVAL);
+
+ switch (vm_map_inherit(&p->p_vmspace->vm_map, addr, addr+size,
+ inherit)) {
+ case KERN_SUCCESS:
+ return (0);
+ case KERN_PROTECTION_FAILURE:
+ return (EACCES);
+ }
+ return (EINVAL);
+}
+
+#ifndef _SYS_SYSPROTO_H_
struct madvise_args {
caddr_t addr;
int len;
@@ -536,13 +607,24 @@ mlock(p, uap, retval)
int *retval;
{
vm_offset_t addr;
- vm_size_t size;
+ vm_size_t size, pageoff;
int error;
addr = (vm_offset_t) uap->addr;
- if ((addr & PAGE_MASK) || uap->addr + uap->len < uap->addr)
+ size = (vm_size_t) uap->len;
+ /*
+ * Align the address to a page boundary,
+ * and adjust the size accordingly.
+ */
+ pageoff = (addr & PAGE_MASK);
+ addr -= pageoff;
+ size += pageoff;
+ size = (vm_size_t) round_page(size);
+
+ /* disable wrap around */
+ if (addr + (int)size < addr)
return (EINVAL);
- size = round_page((vm_size_t) uap->len);
+
if (atop(size) + cnt.v_wire_count > vm_page_max_wired)
return (EAGAIN);
#ifdef pmap_wired_count
@@ -572,18 +654,29 @@ munlock(p, uap, retval)
int *retval;
{
vm_offset_t addr;
- vm_size_t size;
+ vm_size_t size, pageoff;
int error;
addr = (vm_offset_t) uap->addr;
- if ((addr & PAGE_MASK) || uap->addr + uap->len < uap->addr)
+ size = (vm_size_t) uap->len;
+ /*
+ * Align the address to a page boundary,
+ * and adjust the size accordingly.
+ */
+ pageoff = (addr & PAGE_MASK);
+ addr -= pageoff;
+ size += pageoff;
+ size = (vm_size_t) round_page(size);
+
+ /* disable wrap around */
+ if (addr + (int)size < addr)
return (EINVAL);
+
#ifndef pmap_wired_count
error = suser(p->p_ucred, &p->p_acflag);
if (error)
return (error);
#endif
- size = round_page((vm_size_t) uap->len);
error = vm_map_pageable(&p->p_vmspace->vm_map, addr, addr + size, TRUE);
return (error == KERN_SUCCESS ? 0 : ENOMEM);
OpenPOWER on IntegriCloud