diff options
| author | Konstantin Belousov <kib@FreeBSD.org> | 2016-02-28 17:52:33 +0000 |
|---|---|---|
| committer | Konstantin Belousov <kib@FreeBSD.org> | 2016-02-28 17:52:33 +0000 |
| commit | 1bdbd705993eab79189dff87b69a9cff5c69b17e (patch) | |
| tree | 93354adb0a612a635964c8498072087760a0f93b /sys | |
| parent | 3f3af790f95027d0c3b859a53eb82ef5d00dc4f8 (diff) | |
Implement process-shared locks support for libthr.so.3, without
breaking the ABI. Special value is stored in the lock pointer to
indicate shared lock, and offline page in the shared memory is
allocated to store the actual lock.
Reviewed by: vangyzen (previous version)
Discussed with: deischen, emaste, jhb, rwatson,
Martin Simmons <martin@lispworks.com>
Tested by: pho
Sponsored by: The FreeBSD Foundation
Notes
svn path=/head/; revision=296162
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/kern/kern_resource.c | 7 | ||||
| -rw-r--r-- | sys/kern/kern_umtx.c | 322 | ||||
| -rw-r--r-- | sys/kern/uipc_shm.c | 17 | ||||
| -rw-r--r-- | sys/sys/mman.h | 7 | ||||
| -rw-r--r-- | sys/sys/resource.h | 4 | ||||
| -rw-r--r-- | sys/sys/resourcevar.h | 2 | ||||
| -rw-r--r-- | sys/sys/umtx.h | 10 | ||||
| -rw-r--r-- | sys/vm/vm_object.c | 5 | ||||
| -rw-r--r-- | sys/vm/vm_object.h | 5 |
9 files changed, 366 insertions, 13 deletions
diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index cbcd680be243..dfe68a52b921 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -1432,3 +1432,10 @@ chgkqcnt(struct uidinfo *uip, int diff, rlim_t max) return (chglimit(uip, &uip->ui_kqcnt, diff, max, "kqcnt")); } + +int +chgumtxcnt(struct uidinfo *uip, int diff, rlim_t max) +{ + + return (chglimit(uip, &uip->ui_umtxcnt, diff, max, "umtxcnt")); +} diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c index 681120fd45ba..9474b0bf8b43 100644 --- a/sys/kern/kern_umtx.c +++ b/sys/kern/kern_umtx.c @@ -1,8 +1,12 @@ /*- + * Copyright (c) 2015 The FreeBSD Foundation * Copyright (c) 2004, David Xu <davidxu@freebsd.org> * Copyright (c) 2002, Jeffrey Roberson <jeff@freebsd.org> * All rights reserved. * + * Portions of this software were developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -33,12 +37,19 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/kernel.h> +#include <sys/fcntl.h> +#include <sys/file.h> +#include <sys/filedesc.h> #include <sys/limits.h> #include <sys/lock.h> #include <sys/malloc.h> +#include <sys/mman.h> #include <sys/mutex.h> #include <sys/priv.h> #include <sys/proc.h> +#include <sys/resource.h> +#include <sys/resourcevar.h> +#include <sys/rwlock.h> #include <sys/sbuf.h> #include <sys/sched.h> #include <sys/smp.h> @@ -47,9 +58,12 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/sysproto.h> #include <sys/syscallsubr.h> +#include <sys/taskqueue.h> #include <sys/eventhandler.h> #include <sys/umtx.h> +#include <security/mac/mac_framework.h> + #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/pmap.h> @@ -213,6 +227,7 @@ SYSCTL_LONG(_debug_umtx, OID_AUTO, max_length, CTLFLAG_RD, &max_length, 0, "max_ static SYSCTL_NODE(_debug_umtx, OID_AUTO, chains, CTLFLAG_RD, 0, "umtx chain stats"); #endif +static void umtx_shm_init(void); static void umtxq_sysinit(void *); static void umtxq_hash(struct umtx_key *key); static struct umtxq_chain *umtxq_getchain(struct umtx_key *key); @@ -399,6 +414,7 @@ umtxq_sysinit(void *arg __unused) mtx_init(&umtx_lock, "umtx lock", NULL, MTX_DEF); EVENTHANDLER_REGISTER(process_exec, umtx_exec_hook, NULL, EVENTHANDLER_PRI_ANY); + umtx_shm_init(); } struct umtx_q * @@ -3440,6 +3456,310 @@ __umtx_op_sem2_wake(struct thread *td, struct _umtx_op_args *uap) return (do_sem2_wake(td, uap->obj)); } +#define USHM_OBJ_UMTX(o) \ + ((struct umtx_shm_obj_list *)(&(o)->umtx_data)) + +#define USHMF_REG_LINKED 0x0001 +#define USHMF_OBJ_LINKED 0x0002 +struct umtx_shm_reg { + TAILQ_ENTRY(umtx_shm_reg) ushm_reg_link; + LIST_ENTRY(umtx_shm_reg) ushm_obj_link; + struct umtx_key ushm_key; + struct ucred *ushm_cred; + struct shmfd *ushm_obj; + u_int ushm_refcnt; + u_int ushm_flags; +}; + +LIST_HEAD(umtx_shm_obj_list, umtx_shm_reg); +TAILQ_HEAD(umtx_shm_reg_head, umtx_shm_reg); + +static uma_zone_t umtx_shm_reg_zone; +static struct umtx_shm_reg_head umtx_shm_registry[UMTX_CHAINS]; +static struct mtx umtx_shm_lock; +static struct umtx_shm_reg_head umtx_shm_reg_delfree = + TAILQ_HEAD_INITIALIZER(umtx_shm_reg_delfree); + +static void umtx_shm_free_reg(struct umtx_shm_reg *reg); + +static void +umtx_shm_reg_delfree_tq(void *context __unused, int pending __unused) +{ + struct umtx_shm_reg_head d; + struct umtx_shm_reg *reg, *reg1; + + TAILQ_INIT(&d); + mtx_lock(&umtx_shm_lock); + TAILQ_CONCAT(&d, &umtx_shm_reg_delfree, ushm_reg_link); + mtx_unlock(&umtx_shm_lock); + TAILQ_FOREACH_SAFE(reg, &d, ushm_reg_link, reg1) { + TAILQ_REMOVE(&d, reg, ushm_reg_link); + umtx_shm_free_reg(reg); + } +} + +static struct task umtx_shm_reg_delfree_task = + TASK_INITIALIZER(0, umtx_shm_reg_delfree_tq, NULL); + +static struct umtx_shm_reg * +umtx_shm_find_reg_locked(const struct umtx_key *key) +{ + struct umtx_shm_reg *reg; + struct umtx_shm_reg_head *reg_head; + + KASSERT(key->shared, ("umtx_p_find_rg: private key")); + mtx_assert(&umtx_shm_lock, MA_OWNED); + reg_head = &umtx_shm_registry[key->hash]; + TAILQ_FOREACH(reg, reg_head, ushm_reg_link) { + KASSERT(reg->ushm_key.shared, + ("non-shared key on reg %p %d", reg, reg->ushm_key.shared)); + if (reg->ushm_key.info.shared.object == + key->info.shared.object && + reg->ushm_key.info.shared.offset == + key->info.shared.offset) { + KASSERT(reg->ushm_key.type == TYPE_SHM, ("TYPE_USHM")); + KASSERT(reg->ushm_refcnt > 0, + ("reg %p refcnt 0 onlist", reg)); + KASSERT((reg->ushm_flags & USHMF_REG_LINKED) != 0, + ("reg %p not linked", reg)); + reg->ushm_refcnt++; + return (reg); + } + } + return (NULL); +} + +static struct umtx_shm_reg * +umtx_shm_find_reg(const struct umtx_key *key) +{ + struct umtx_shm_reg *reg; + + mtx_lock(&umtx_shm_lock); + reg = umtx_shm_find_reg_locked(key); + mtx_unlock(&umtx_shm_lock); + return (reg); +} + +static void +umtx_shm_free_reg(struct umtx_shm_reg *reg) +{ + + chgumtxcnt(reg->ushm_cred->cr_ruidinfo, -1, 0); + crfree(reg->ushm_cred); + shm_drop(reg->ushm_obj); + uma_zfree(umtx_shm_reg_zone, reg); +} + +static bool +umtx_shm_unref_reg_locked(struct umtx_shm_reg *reg, bool force) +{ + bool res; + + mtx_assert(&umtx_shm_lock, MA_OWNED); + KASSERT(reg->ushm_refcnt > 0, ("ushm_reg %p refcnt 0", reg)); + reg->ushm_refcnt--; + res = reg->ushm_refcnt == 0; + if (res || force) { + if ((reg->ushm_flags & USHMF_REG_LINKED) != 0) { + TAILQ_REMOVE(&umtx_shm_registry[reg->ushm_key.hash], + reg, ushm_reg_link); + reg->ushm_flags &= ~USHMF_REG_LINKED; + } + if ((reg->ushm_flags & USHMF_OBJ_LINKED) != 0) { + LIST_REMOVE(reg, ushm_obj_link); + reg->ushm_flags &= ~USHMF_OBJ_LINKED; + } + } + return (res); +} + +static void +umtx_shm_unref_reg(struct umtx_shm_reg *reg, bool force) +{ + vm_object_t object; + bool dofree; + + if (force) { + object = reg->ushm_obj->shm_object; + VM_OBJECT_WLOCK(object); + object->flags |= OBJ_UMTXDEAD; + VM_OBJECT_WUNLOCK(object); + } + mtx_lock(&umtx_shm_lock); + dofree = umtx_shm_unref_reg_locked(reg, force); + mtx_unlock(&umtx_shm_lock); + if (dofree) + umtx_shm_free_reg(reg); +} + +void +umtx_shm_object_init(vm_object_t object) +{ + + LIST_INIT(USHM_OBJ_UMTX(object)); +} + +void +umtx_shm_object_terminated(vm_object_t object) +{ + struct umtx_shm_reg *reg, *reg1; + bool dofree; + + dofree = false; + mtx_lock(&umtx_shm_lock); + LIST_FOREACH_SAFE(reg, USHM_OBJ_UMTX(object), ushm_obj_link, reg1) { + if (umtx_shm_unref_reg_locked(reg, true)) { + TAILQ_INSERT_TAIL(&umtx_shm_reg_delfree, reg, + ushm_reg_link); + dofree = true; + } + } + mtx_unlock(&umtx_shm_lock); + if (dofree) + taskqueue_enqueue(taskqueue_thread, &umtx_shm_reg_delfree_task); +} + +static int +umtx_shm_create_reg(struct thread *td, const struct umtx_key *key, + struct umtx_shm_reg **res) +{ + struct umtx_shm_reg *reg, *reg1; + struct ucred *cred; + int error; + + reg = umtx_shm_find_reg(key); + if (reg != NULL) { + *res = reg; + return (0); + } + cred = td->td_ucred; + if (!chgumtxcnt(cred->cr_ruidinfo, 1, lim_cur(td, RLIMIT_UMTXP))) + return (ENOMEM); + reg = uma_zalloc(umtx_shm_reg_zone, M_WAITOK | M_ZERO); + reg->ushm_refcnt = 1; + bcopy(key, ®->ushm_key, sizeof(*key)); + reg->ushm_obj = shm_alloc(td->td_ucred, O_RDWR); + reg->ushm_cred = crhold(cred); + error = shm_dotruncate(reg->ushm_obj, PAGE_SIZE); + if (error != 0) { + umtx_shm_free_reg(reg); + return (error); + } + mtx_lock(&umtx_shm_lock); + reg1 = umtx_shm_find_reg_locked(key); + if (reg1 != NULL) { + mtx_unlock(&umtx_shm_lock); + umtx_shm_free_reg(reg); + *res = reg1; + return (0); + } + reg->ushm_refcnt++; + TAILQ_INSERT_TAIL(&umtx_shm_registry[key->hash], reg, ushm_reg_link); + LIST_INSERT_HEAD(USHM_OBJ_UMTX(key->info.shared.object), reg, + ushm_obj_link); + reg->ushm_flags = USHMF_REG_LINKED | USHMF_OBJ_LINKED; + mtx_unlock(&umtx_shm_lock); + *res = reg; + return (0); +} + +static int +umtx_shm_alive(struct thread *td, void *addr) +{ + vm_map_t map; + vm_map_entry_t entry; + vm_object_t object; + vm_pindex_t pindex; + vm_prot_t prot; + int res, ret; + boolean_t wired; + + map = &td->td_proc->p_vmspace->vm_map; + res = vm_map_lookup(&map, (uintptr_t)addr, VM_PROT_READ, &entry, + &object, &pindex, &prot, &wired); + if (res != KERN_SUCCESS) + return (EFAULT); + if (object == NULL) + ret = EINVAL; + else + ret = (object->flags & OBJ_UMTXDEAD) != 0 ? ENOTTY : 0; + vm_map_lookup_done(map, entry); + return (ret); +} + +static void +umtx_shm_init(void) +{ + int i; + + umtx_shm_reg_zone = uma_zcreate("umtx_shm", sizeof(struct umtx_shm_reg), + NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); + mtx_init(&umtx_shm_lock, "umtxshm", NULL, MTX_DEF); + for (i = 0; i < nitems(umtx_shm_registry); i++) + TAILQ_INIT(&umtx_shm_registry[i]); +} + +static int +umtx_shm(struct thread *td, void *addr, u_int flags) +{ + struct umtx_key key; + struct umtx_shm_reg *reg; + struct file *fp; + int error, fd; + + if (__bitcount(flags & (UMTX_SHM_CREAT | UMTX_SHM_LOOKUP | + UMTX_SHM_DESTROY| UMTX_SHM_ALIVE)) != 1) + return (EINVAL); + if ((flags & UMTX_SHM_ALIVE) != 0) + return (umtx_shm_alive(td, addr)); + error = umtx_key_get(addr, TYPE_SHM, PROCESS_SHARE, &key); + if (error != 0) + return (error); + KASSERT(key.shared == 1, ("non-shared key")); + if ((flags & UMTX_SHM_CREAT) != 0) { + error = umtx_shm_create_reg(td, &key, ®); + } else { + reg = umtx_shm_find_reg(&key); + if (reg == NULL) + error = ESRCH; + } + umtx_key_release(&key); + if (error != 0) + return (error); + KASSERT(reg != NULL, ("no reg")); + if ((flags & UMTX_SHM_DESTROY) != 0) { + umtx_shm_unref_reg(reg, true); + } else { +#if 0 +#ifdef MAC + error = mac_posixshm_check_open(td->td_ucred, + reg->ushm_obj, FFLAGS(O_RDWR)); + if (error == 0) +#endif + error = shm_access(reg->ushm_obj, td->td_ucred, + FFLAGS(O_RDWR)); + if (error == 0) +#endif + error = falloc_caps(td, &fp, &fd, O_CLOEXEC, NULL); + if (error == 0) { + shm_hold(reg->ushm_obj); + finit(fp, FFLAGS(O_RDWR), DTYPE_SHM, reg->ushm_obj, + &shm_ops); + td->td_retval[0] = fd; + fdrop(fp, td); + } + } + umtx_shm_unref_reg(reg, false); + return (error); +} + +static int +__umtx_op_shm(struct thread *td, struct _umtx_op_args *uap) +{ + + return (umtx_shm(td, uap->uaddr1, uap->val)); +} + typedef int (*_umtx_op_func)(struct thread *td, struct _umtx_op_args *uap); static const _umtx_op_func op_table[] = { @@ -3473,6 +3793,7 @@ static const _umtx_op_func op_table[] = { [UMTX_OP_MUTEX_WAKE2] = __umtx_op_wake2_umutex, [UMTX_OP_SEM2_WAIT] = __umtx_op_sem2_wait, [UMTX_OP_SEM2_WAKE] = __umtx_op_sem2_wake, + [UMTX_OP_SHM] = __umtx_op_shm, }; int @@ -3768,6 +4089,7 @@ static const _umtx_op_func op_table_compat32[] = { [UMTX_OP_MUTEX_WAKE2] = __umtx_op_wake2_umutex, [UMTX_OP_SEM2_WAIT] = __umtx_op_sem2_wait_compat32, [UMTX_OP_SEM2_WAKE] = __umtx_op_sem2_wake, + [UMTX_OP_SHM] = __umtx_op_shm, }; int diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c index 8df6e43db0c9..a2146b99cc3e 100644 --- a/sys/kern/uipc_shm.c +++ b/sys/kern/uipc_shm.c @@ -109,15 +109,10 @@ static dev_t shm_dev_ino; #define SHM_HASH(fnv) (&shm_dictionary[(fnv) & shm_hash]) -static int shm_access(struct shmfd *shmfd, struct ucred *ucred, int flags); -static struct shmfd *shm_alloc(struct ucred *ucred, mode_t mode); static void shm_init(void *arg); -static void shm_drop(struct shmfd *shmfd); -static struct shmfd *shm_hold(struct shmfd *shmfd); static void shm_insert(char *path, Fnv32_t fnv, struct shmfd *shmfd); static struct shmfd *shm_lookup(char *path, Fnv32_t fnv); static int shm_remove(char *path, Fnv32_t fnv, struct ucred *ucred); -static int shm_dotruncate(struct shmfd *shmfd, off_t length); static fo_rdwr_t shm_read; static fo_rdwr_t shm_write; @@ -131,7 +126,7 @@ static fo_fill_kinfo_t shm_fill_kinfo; static fo_mmap_t shm_mmap; /* File descriptor operations. */ -static struct fileops shm_ops = { +struct fileops shm_ops = { .fo_read = shm_read, .fo_write = shm_write, .fo_truncate = shm_truncate, @@ -412,7 +407,7 @@ shm_close(struct file *fp, struct thread *td) return (0); } -static int +int shm_dotruncate(struct shmfd *shmfd, off_t length) { vm_object_t object; @@ -521,7 +516,7 @@ retry: * shmfd object management including creation and reference counting * routines. */ -static struct shmfd * +struct shmfd * shm_alloc(struct ucred *ucred, mode_t mode) { struct shmfd *shmfd; @@ -559,7 +554,7 @@ shm_alloc(struct ucred *ucred, mode_t mode) return (shmfd); } -static struct shmfd * +struct shmfd * shm_hold(struct shmfd *shmfd) { @@ -567,7 +562,7 @@ shm_hold(struct shmfd *shmfd) return (shmfd); } -static void +void shm_drop(struct shmfd *shmfd) { @@ -588,7 +583,7 @@ shm_drop(struct shmfd *shmfd) * Determine if the credentials have sufficient permissions for a * specified combination of FREAD and FWRITE. */ -static int +int shm_access(struct shmfd *shmfd, struct ucred *ucred, int flags) { accmode_t accmode; diff --git a/sys/sys/mman.h b/sys/sys/mman.h index 19d992e83361..1fce960746e8 100644 --- a/sys/sys/mman.h +++ b/sys/sys/mman.h @@ -233,6 +233,13 @@ struct shmfd { int shm_map(struct file *fp, size_t size, off_t offset, void **memp); int shm_unmap(struct file *fp, void *mem, size_t size); +int shm_access(struct shmfd *shmfd, struct ucred *ucred, int flags); +struct shmfd *shm_alloc(struct ucred *ucred, mode_t mode); +struct shmfd *shm_hold(struct shmfd *shmfd); +void shm_drop(struct shmfd *shmfd); +int shm_dotruncate(struct shmfd *shmfd, off_t length); + +extern struct fileops shm_ops; #else /* !_KERNEL */ __BEGIN_DECLS diff --git a/sys/sys/resource.h b/sys/sys/resource.h index fb9e05b24866..9d45e5c6b9ce 100644 --- a/sys/sys/resource.h +++ b/sys/sys/resource.h @@ -104,8 +104,9 @@ struct __wrusage { #define RLIMIT_NPTS 11 /* pseudo-terminals */ #define RLIMIT_SWAP 12 /* swap used */ #define RLIMIT_KQUEUES 13 /* kqueues allocated */ +#define RLIMIT_UMTXP 14 /* process-shared umtx */ -#define RLIM_NLIMITS 14 /* number of resource limits */ +#define RLIM_NLIMITS 15 /* number of resource limits */ #define RLIM_INFINITY ((rlim_t)(((uint64_t)1 << 63) - 1)) /* XXX Missing: RLIM_SAVED_MAX, RLIM_SAVED_CUR */ @@ -131,6 +132,7 @@ static const char *rlimit_ident[RLIM_NLIMITS] = { "npts", "swap", "kqueues", + "umtx", }; #endif diff --git a/sys/sys/resourcevar.h b/sys/sys/resourcevar.h index e5483c4175e8..a81cafd03e0a 100644 --- a/sys/sys/resourcevar.h +++ b/sys/sys/resourcevar.h @@ -101,6 +101,7 @@ struct uidinfo { long ui_proccnt; /* (b) number of processes */ long ui_ptscnt; /* (b) number of pseudo-terminals */ long ui_kqcnt; /* (b) number of kqueues */ + long ui_umtxcnt; /* (b) number of shared umtxs */ uid_t ui_uid; /* (a) uid */ u_int ui_ref; /* (b) reference count */ #ifdef RACCT @@ -124,6 +125,7 @@ int chgproccnt(struct uidinfo *uip, int diff, rlim_t maxval); int chgsbsize(struct uidinfo *uip, u_int *hiwat, u_int to, rlim_t maxval); int chgptscnt(struct uidinfo *uip, int diff, rlim_t maxval); +int chgumtxcnt(struct uidinfo *uip, int diff, rlim_t maxval); int fuswintr(void *base); int kern_proc_setrlimit(struct thread *td, struct proc *p, u_int which, struct rlimit *limp); diff --git a/sys/sys/umtx.h b/sys/sys/umtx.h index 5187ad774902..325148c61449 100644 --- a/sys/sys/umtx.h +++ b/sys/sys/umtx.h @@ -83,6 +83,7 @@ #define UMTX_OP_MUTEX_WAKE2 22 #define UMTX_OP_SEM2_WAIT 23 #define UMTX_OP_SEM2_WAKE 24 +#define UMTX_OP_SHM 25 /* Flags for UMTX_OP_CV_WAIT */ #define CVWAIT_CHECK_UNPARKING 0x01 @@ -93,6 +94,12 @@ #define UMTX_CHECK_UNPARKING CVWAIT_CHECK_UNPARKING +/* Flags for UMTX_OP_SHM */ +#define UMTX_SHM_CREAT 0x0001 +#define UMTX_SHM_LOOKUP 0x0002 +#define UMTX_SHM_DESTROY 0x0004 +#define UMTX_SHM_ALIVE 0x0008 + #ifndef _KERNEL int _umtx_op(void *obj, int op, u_long val, void *uaddr, void *uaddr2); @@ -113,7 +120,8 @@ enum { TYPE_PI_UMUTEX, TYPE_PP_UMUTEX, TYPE_RWLOCK, - TYPE_FUTEX + TYPE_FUTEX, + TYPE_SHM, }; /* Key to represent a unique userland synchronous object */ diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index bc0e4c05f126..1b1d532ba1cf 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -264,6 +264,7 @@ _vm_object_allocate(objtype_t type, vm_pindex_t size, vm_object_t object) #if VM_NRESERVLEVEL > 0 LIST_INIT(&object->rvq); #endif + umtx_shm_object_init(object); } /* @@ -475,6 +476,9 @@ vm_object_vndeallocate(vm_object_t object) } #endif + if (object->ref_count == 1) + umtx_shm_object_terminated(object); + /* * The test for text of vp vnode does not need a bypass to * reach right VV_TEXT there, since it is obtained from @@ -647,6 +651,7 @@ retry: return; } doterm: + umtx_shm_object_terminated(object); temp = object->backing_object; if (temp != NULL) { KASSERT((object->flags & OBJ_TMPFS_NODE) == 0, diff --git a/sys/vm/vm_object.h b/sys/vm/vm_object.h index ca2d73a75a42..c68fdce09158 100644 --- a/sys/vm/vm_object.h +++ b/sys/vm/vm_object.h @@ -174,6 +174,7 @@ struct vm_object { } un_pager; struct ucred *cred; vm_ooffset_t charge; + void *umtx_data; }; /* @@ -184,6 +185,7 @@ struct vm_object { #define OBJ_ACTIVE 0x0004 /* active objects */ #define OBJ_DEAD 0x0008 /* dead objects (during rundown) */ #define OBJ_NOSPLIT 0x0010 /* dont split this object */ +#define OBJ_UMTXDEAD 0x0020 /* umtx pshared was terminated */ #define OBJ_PIPWNT 0x0040 /* paging in progress wanted */ #define OBJ_MIGHTBEDIRTY 0x0100 /* object might be dirty, only for vnode */ #define OBJ_TMPFS_NODE 0x0200 /* object belongs to tmpfs VREG node */ @@ -296,6 +298,9 @@ vm_object_cache_is_empty(vm_object_t object) return (vm_radix_is_empty(&object->cache)); } +void umtx_shm_object_init(vm_object_t object); +void umtx_shm_object_terminated(vm_object_t object); + vm_object_t vm_object_allocate (objtype_t, vm_pindex_t); boolean_t vm_object_coalesce(vm_object_t, vm_ooffset_t, vm_size_t, vm_size_t, boolean_t); |
