Bug 218571 - umtx compat6 regression affecting 'jar' command
Summary: umtx compat6 regression affecting 'jar' command
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 11.0-RELEASE
Hardware: Any Any
: --- Affects Some People
Assignee: freebsd-threads mailing list
URL:
Keywords: patch, regression
Depends on:
Blocks:
 
Reported: 2017-04-11 21:26 UTC by Nicholas Hardison
Modified: 2017-09-15 01:15 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Nicholas Hardison 2017-04-11 21:26:34 UTC
Hello,
I'm in the process of upgrading about a hundred 8.2-RELEASE systems to 11.0-RELEASE (maybe 11.1 by the time I'm finished), and hit a snag with one of my regression tests.  It involves running 'jar' from jdk1.5.0 (originally built on 6.3-RELEASE I believe), which goes into a loop and hangs.  Replicating it is very simple - just run 'jar' and instead of displaying the usage message, it starts spinning.  I ran it under truss, and after some normal-looking things (like a bunch of compat6 syscalls) saw a bunch of this at the end:

_umtx_op(0x641c10,UMTX_OP_RESERVED0,0x18947,0x0,0x0) ERR#45 'Operation not supported'

Looking through the svn history, it appears that two umtx syscalls were removed in https://svnweb.freebsd.org/base?view=revision&revision=263318 and https://svnweb.freebsd.org/base?view=revision&revision=304525.  I don't consider myself a kernel developer, but I managed to cobble together a patch that got them working again for my use case.  There is currently a TODO regarding the error handling - I just wanted to prove this would work and fix the jar issue.  Looking through the rest of the code, it feels to me like the correct thing to do is put this stuff back in under #ifdef COMPAT_FREEBSD6.  I have attached a patch that resolves my issue with jar.  If the above approach sounds reasonable, I can work on cleaning it up into an actual, acceptable, form.

Thanks,
-Nicholas

diff -u -r src.fbsd11.stock/lib/libc/sys/Symbol.map src.oldumtx/lib/libc/sys/Symbol.map
--- src.fbsd11.stock/lib/libc/sys/Symbol.map    2016-09-28 19:25:57.000000000 -0400
+++ src.oldumtx/lib/libc/sys/Symbol.map    2017-04-05 13:54:37.026112000 -0400
@@ -34,7 +34,9 @@
     __setugid;
     __syscall;
     __sysctl;
+    _umtx_lock;
     _umtx_op;
+    _umtx_unlock;
     abort2;
     accept;
     access;
@@ -453,8 +455,12 @@
     __sys___syscall;
     ___sysctl;
     __sys___sysctl;
+    __umtx_lock;
+    __sys__umtx_lock;
     __umtx_op;
     __sys__umtx_op;
+    __umtx_unlock;
+        __sys__umtx_unlock;
     _abort2;
     __sys_abort2;
     _accept;
diff -u -r src.fbsd11.stock/sys/compat/freebsd32/freebsd32_proto.h src.oldumtx/sys/compat/freebsd32/freebsd32_proto.h
--- src.fbsd11.stock/sys/compat/freebsd32/freebsd32_proto.h    2016-09-28 19:24:55.000000000 -0400
+++ src.oldumtx/sys/compat/freebsd32/freebsd32_proto.h    2017-04-05 15:48:00.638984000 -0400
@@ -2,8 +2,8 @@
  * System call prototypes.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: releng/11.0/sys/compat/freebsd32/freebsd32_proto.h 303858 2016-08-08 21:19:57Z bdrewery $
- * created from FreeBSD: stable/11/sys/compat/freebsd32/syscalls.master 302094 2016-06-22 21:15:59Z brooks
+ * $FreeBSD$
+ * created from FreeBSD: releng/11.0/sys/compat/freebsd32/syscalls.master 302094 2016-06-22 21:15:59Z brooks
  */
 
 #ifndef _FREEBSD32_SYSPROTO_H_
@@ -359,6 +359,12 @@
     char oucp_l_[PADL_(struct freebsd32_ucontext *)]; struct freebsd32_ucontext * oucp; char oucp_r_[PADR_(struct freebsd32_ucontext *)];
     char ucp_l_[PADL_(const struct freebsd32_ucontext *)]; const struct freebsd32_ucontext * ucp; char ucp_r_[PADR_(const struct freebsd32_ucontext *)];
 };
+struct freebsd32_umtx_lock_args {
+    char umtx_l_[PADL_(struct umtx *)]; struct umtx * umtx; char umtx_r_[PADR_(struct umtx *)];
+};
+struct freebsd32_umtx_unlock_args {
+    char umtx_l_[PADL_(struct umtx *)]; struct umtx * umtx; char umtx_r_[PADR_(struct umtx *)];
+};
 struct freebsd32_ksem_timedwait_args {
     char id_l_[PADL_(semid_t)]; semid_t id; char id_r_[PADR_(semid_t)];
     char abstime_l_[PADL_(const struct timespec32 *)]; const struct timespec32 * abstime; char abstime_r_[PADR_(const struct timespec32 *)];
@@ -757,6 +763,8 @@
 int    freebsd32_getcontext(struct thread *, struct freebsd32_getcontext_args *);
 int    freebsd32_setcontext(struct thread *, struct freebsd32_setcontext_args *);
 int    freebsd32_swapcontext(struct thread *, struct freebsd32_swapcontext_args *);
+int    freebsd32_umtx_lock(struct thread *, struct freebsd32_umtx_lock_args *);
+int    freebsd32_umtx_unlock(struct thread *, struct freebsd32_umtx_unlock_args *);
 int    freebsd32_ksem_timedwait(struct thread *, struct freebsd32_ksem_timedwait_args *);
 int    freebsd32_thr_suspend(struct thread *, struct freebsd32_thr_suspend_args *);
 int    freebsd32_umtx_op(struct thread *, struct freebsd32_umtx_op_args *);
@@ -1223,6 +1231,8 @@
 #define    FREEBSD32_SYS_AUE_freebsd32_getcontext    AUE_NULL
 #define    FREEBSD32_SYS_AUE_freebsd32_setcontext    AUE_NULL
 #define    FREEBSD32_SYS_AUE_freebsd32_swapcontext    AUE_NULL
+#define    FREEBSD32_SYS_AUE_freebsd32_umtx_lock    AUE_NULL
+#define    FREEBSD32_SYS_AUE_freebsd32_umtx_unlock    AUE_NULL
 #define    FREEBSD32_SYS_AUE_freebsd32_ksem_timedwait    AUE_NULL
 #define    FREEBSD32_SYS_AUE_freebsd32_thr_suspend    AUE_NULL
 #define    FREEBSD32_SYS_AUE_freebsd32_umtx_op    AUE_NULL
diff -u -r src.fbsd11.stock/sys/compat/freebsd32/freebsd32_syscall.h src.oldumtx/sys/compat/freebsd32/freebsd32_syscall.h
--- src.fbsd11.stock/sys/compat/freebsd32/freebsd32_syscall.h    2016-09-28 19:24:55.000000000 -0400
+++ src.oldumtx/sys/compat/freebsd32/freebsd32_syscall.h    2017-04-05 15:48:00.635260000 -0400
@@ -2,8 +2,8 @@
  * System call numbers.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: releng/11.0/sys/compat/freebsd32/freebsd32_syscall.h 303858 2016-08-08 21:19:57Z bdrewery $
- * created from FreeBSD: stable/11/sys/compat/freebsd32/syscalls.master 302094 2016-06-22 21:15:59Z brooks
+ * $FreeBSD$
+ * created from FreeBSD: releng/11.0/sys/compat/freebsd32/syscalls.master 302094 2016-06-22 21:15:59Z brooks
  */
 
 #define    FREEBSD32_SYS_syscall    0
@@ -339,6 +339,8 @@
 #define    FREEBSD32_SYS_thr_exit    431
 #define    FREEBSD32_SYS_thr_self    432
 #define    FREEBSD32_SYS_thr_kill    433
+#define    FREEBSD32_SYS_freebsd32_umtx_lock    434
+#define    FREEBSD32_SYS_freebsd32_umtx_unlock    435
 #define    FREEBSD32_SYS_jail_attach    436
 #define    FREEBSD32_SYS_extattr_list_fd    437
 #define    FREEBSD32_SYS_extattr_list_file    438
diff -u -r src.fbsd11.stock/sys/compat/freebsd32/freebsd32_syscalls.c src.oldumtx/sys/compat/freebsd32/freebsd32_syscalls.c
--- src.fbsd11.stock/sys/compat/freebsd32/freebsd32_syscalls.c    2016-09-28 19:24:55.000000000 -0400
+++ src.oldumtx/sys/compat/freebsd32/freebsd32_syscalls.c    2017-04-05 15:48:00.635249000 -0400
@@ -2,8 +2,8 @@
  * System call names.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: releng/11.0/sys/compat/freebsd32/freebsd32_syscalls.c 303858 2016-08-08 21:19:57Z bdrewery $
- * created from FreeBSD: stable/11/sys/compat/freebsd32/syscalls.master 302094 2016-06-22 21:15:59Z brooks
+ * $FreeBSD$
+ * created from FreeBSD: releng/11.0/sys/compat/freebsd32/syscalls.master 302094 2016-06-22 21:15:59Z brooks
  */
 
 const char *freebsd32_syscallnames[] = {
@@ -444,8 +444,8 @@
     "thr_exit",            /* 431 = thr_exit */
     "thr_self",            /* 432 = thr_self */
     "thr_kill",            /* 433 = thr_kill */
-    "#434",            /* 434 = nosys */
-    "#435",            /* 435 = nosys */
+    "freebsd32_umtx_lock",            /* 434 = freebsd32_umtx_lock */
+    "freebsd32_umtx_unlock",            /* 435 = freebsd32_umtx_unlock */
     "jail_attach",            /* 436 = jail_attach */
     "extattr_list_fd",            /* 437 = extattr_list_fd */
     "extattr_list_file",            /* 438 = extattr_list_file */
diff -u -r src.fbsd11.stock/sys/compat/freebsd32/freebsd32_sysent.c src.oldumtx/sys/compat/freebsd32/freebsd32_sysent.c
--- src.fbsd11.stock/sys/compat/freebsd32/freebsd32_sysent.c    2016-09-28 19:24:55.000000000 -0400
+++ src.oldumtx/sys/compat/freebsd32/freebsd32_sysent.c    2017-04-05 15:48:00.637117000 -0400
@@ -2,8 +2,8 @@
  * System call switch table.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: releng/11.0/sys/compat/freebsd32/freebsd32_sysent.c 303858 2016-08-08 21:19:57Z bdrewery $
- * created from FreeBSD: stable/11/sys/compat/freebsd32/syscalls.master 302094 2016-06-22 21:15:59Z brooks
+ * $FreeBSD$
+ * created from FreeBSD: releng/11.0/sys/compat/freebsd32/syscalls.master 302094 2016-06-22 21:15:59Z brooks
  */
 
 #include "opt_compat.h"
@@ -487,8 +487,8 @@
     { AS(thr_exit_args), (sy_call_t *)sys_thr_exit, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC },    /* 431 = thr_exit */
     { AS(thr_self_args), (sy_call_t *)sys_thr_self, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC },    /* 432 = thr_self */
     { AS(thr_kill_args), (sy_call_t *)sys_thr_kill, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC },    /* 433 = thr_kill */
-    { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },            /* 434 = nosys */
-    { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },            /* 435 = nosys */
+    { AS(freebsd32_umtx_lock_args), (sy_call_t *)freebsd32_umtx_lock, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC },    /* 434 = freebsd32_umtx_lock */
+    { AS(freebsd32_umtx_unlock_args), (sy_call_t *)freebsd32_umtx_unlock, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC },    /* 435 = freebsd32_umtx_unlock */
     { AS(jail_attach_args), (sy_call_t *)sys_jail_attach, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC },    /* 436 = jail_attach */
     { AS(extattr_list_fd_args), (sy_call_t *)sys_extattr_list_fd, AUE_EXTATTR_LIST_FD, NULL, 0, 0, 0, SY_THR_STATIC },    /* 437 = extattr_list_fd */
     { AS(extattr_list_file_args), (sy_call_t *)sys_extattr_list_file, AUE_EXTATTR_LIST_FILE, NULL, 0, 0, 0, SY_THR_STATIC },    /* 438 = extattr_list_file */
diff -u -r src.fbsd11.stock/sys/compat/freebsd32/freebsd32_systrace_args.c src.oldumtx/sys/compat/freebsd32/freebsd32_systrace_args.c
--- src.fbsd11.stock/sys/compat/freebsd32/freebsd32_systrace_args.c    2016-09-28 19:24:55.000000000 -0400
+++ src.oldumtx/sys/compat/freebsd32/freebsd32_systrace_args.c    2017-04-05 15:48:00.641174000 -0400
@@ -2,7 +2,7 @@
  * System call argument to DTrace register array converstion.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: releng/11.0/sys/compat/freebsd32/freebsd32_systrace_args.c 302095 2016-06-22 21:18:19Z brooks $
+ * $FreeBSD$
  * This file is part of the DTrace syscall provider.
  */
 
@@ -2200,6 +2200,20 @@
         *n_args = 2;
         break;
     }
+    /* freebsd32_umtx_lock */
+    case 434: {
+        struct freebsd32_umtx_lock_args *p = params;
+        uarg[0] = (intptr_t) p->umtx; /* struct umtx * */
+        *n_args = 1;
+        break;
+    }
+    /* freebsd32_umtx_unlock */
+    case 435: {
+        struct freebsd32_umtx_unlock_args *p = params;
+        uarg[0] = (intptr_t) p->umtx; /* struct umtx * */
+        *n_args = 1;
+        break;
+    }
     /* jail_attach */
     case 436: {
         struct jail_attach_args *p = params;
@@ -6866,6 +6880,26 @@
             break;
         };
         break;
+    /* freebsd32_umtx_lock */
+    case 434:
+        switch(ndx) {
+        case 0:
+            p = "struct umtx *";
+            break;
+        default:
+            break;
+        };
+        break;
+    /* freebsd32_umtx_unlock */
+    case 435:
+        switch(ndx) {
+        case 0:
+            p = "struct umtx *";
+            break;
+        default:
+            break;
+        };
+        break;
     /* jail_attach */
     case 436:
         switch(ndx) {
@@ -10189,6 +10223,16 @@
         if (ndx == 0 || ndx == 1)
             p = "int";
         break;
+    /* freebsd32_umtx_lock */
+    case 434:
+        if (ndx == 0 || ndx == 1)
+            p = "int";
+        break;
+    /* freebsd32_umtx_unlock */
+    case 435:
+        if (ndx == 0 || ndx == 1)
+            p = "int";
+        break;
     /* jail_attach */
     case 436:
         if (ndx == 0 || ndx == 1)
diff -u -r src.fbsd11.stock/sys/compat/freebsd32/syscalls.master src.oldumtx/sys/compat/freebsd32/syscalls.master
--- src.fbsd11.stock/sys/compat/freebsd32/syscalls.master    2016-09-28 19:24:55.000000000 -0400
+++ src.oldumtx/sys/compat/freebsd32/syscalls.master    2017-04-04 14:06:39.408900000 -0400
@@ -777,8 +777,8 @@
 431    AUE_NULL    NOPROTO    { void thr_exit(long *state); }
 432    AUE_NULL    NOPROTO    { int thr_self(long *id); }
 433    AUE_NULL    NOPROTO    { int thr_kill(long id, int sig); }
-434    AUE_NULL    UNIMPL    nosys
-435    AUE_NULL    UNIMPL    nosys
+434    AUE_NULL    STD    { int freebsd32_umtx_lock(struct umtx *umtx); }
+435    AUE_NULL    STD    { int freebsd32_umtx_unlock(struct umtx *umtx); }
 436    AUE_NULL    NOPROTO    { int jail_attach(int jid); }
 437    AUE_EXTATTR_LIST_FD    NOPROTO    { ssize_t extattr_list_fd(int fd, \
                     int attrnamespace, void *data, \
diff -u -r src.fbsd11.stock/sys/kern/capabilities.conf src.oldumtx/sys/kern/capabilities.conf
--- src.fbsd11.stock/sys/kern/capabilities.conf    2016-09-28 19:24:40.000000000 -0400
+++ src.oldumtx/sys/kern/capabilities.conf    2017-04-05 14:17:10.920476000 -0400
@@ -64,7 +64,9 @@
 ##
 ## XXRW: Need to check this very carefully.
 ##
+_umtx_lock
 _umtx_op
+_umtx_unlock
 
 ##
 ## Allow process termination using abort2(2).
diff -u -r src.fbsd11.stock/sys/kern/init_sysent.c src.oldumtx/sys/kern/init_sysent.c
--- src.fbsd11.stock/sys/kern/init_sysent.c    2016-09-28 19:24:40.000000000 -0400
+++ src.oldumtx/sys/kern/init_sysent.c    2017-04-05 15:44:29.739973000 -0400
@@ -2,8 +2,8 @@
  * System call switch table.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: releng/11.0/sys/kern/init_sysent.c 303858 2016-08-08 21:19:57Z bdrewery $
- * created from FreeBSD: stable/11/sys/kern/syscalls.master 303854 2016-08-08 20:23:11Z bdrewery
+ * $FreeBSD$
+ * created from FreeBSD: releng/11.0/sys/kern/syscalls.master 303854 2016-08-08 20:23:11Z bdrewery
  */
 
 #include "opt_compat.h"
@@ -480,8 +480,8 @@
     { AS(thr_exit_args), (sy_call_t *)sys_thr_exit, AUE_NULL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC },    /* 431 = thr_exit */
     { AS(thr_self_args), (sy_call_t *)sys_thr_self, AUE_NULL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC },    /* 432 = thr_self */
     { AS(thr_kill_args), (sy_call_t *)sys_thr_kill, AUE_NULL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC },    /* 433 = thr_kill */
-    { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },            /* 434 = nosys */
-    { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },            /* 435 = nosys */
+    { AS(_umtx_lock_args), (sy_call_t *)sys__umtx_lock, AUE_NULL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC },    /* 434 = _umtx_lock */
+    { AS(_umtx_unlock_args), (sy_call_t *)sys__umtx_unlock, AUE_NULL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC },    /* 435 = _umtx_unlock */
     { AS(jail_attach_args), (sy_call_t *)sys_jail_attach, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC },    /* 436 = jail_attach */
     { AS(extattr_list_fd_args), (sy_call_t *)sys_extattr_list_fd, AUE_EXTATTR_LIST_FD, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC },    /* 437 = extattr_list_fd */
     { AS(extattr_list_file_args), (sy_call_t *)sys_extattr_list_file, AUE_EXTATTR_LIST_FILE, NULL, 0, 0, 0, SY_THR_STATIC },    /* 438 = extattr_list_file */
diff -u -r src.fbsd11.stock/sys/kern/kern_umtx.c src.oldumtx/sys/kern/kern_umtx.c
--- src.fbsd11.stock/sys/kern/kern_umtx.c    2016-09-28 19:24:40.000000000 -0400
+++ src.oldumtx/sys/kern/kern_umtx.c    2017-04-05 15:52:53.900304000 -0400
@@ -909,6 +909,367 @@
 }
 
 /*
+ * Lock a umtx object.
+ */
+static int
+do_lock_umtx(struct thread *td, struct umtx *umtx, u_long id,
+    const struct timespec *timeout)
+{
+    struct abs_timeout timo;
+    struct umtx_q *uq;
+    u_long owner;
+    u_long old;
+    int error = 0;
+
+    uq = td->td_umtxq;
+    if (timeout != NULL)
+        abs_timeout_init(&timo, CLOCK_REALTIME, 0, timeout);
+
+    /*
+     * Care must be exercised when dealing with umtx structure. It
+     * can fault on any access.
+     */
+    for (;;) {
+        /*
+         * Try the uncontested case.  This should be done in userland.
+         */
+        owner = casuword(&umtx->u_owner, UMTX_UNOWNED, id);
+
+        /* The acquire succeeded. */
+        if (owner == UMTX_UNOWNED)
+            return (0);
+
+        /* The address was invalid. */
+        if (owner == -1)
+            return (EFAULT);
+
+        /* If no one owns it but it is contested try to acquire it. */
+        if (owner == UMTX_CONTESTED) {
+            owner = casuword(&umtx->u_owner,
+                UMTX_CONTESTED, id | UMTX_CONTESTED);
+
+            if (owner == UMTX_CONTESTED)
+                return (0);
+
+            /* The address was invalid. */
+            if (owner == -1)
+                return (EFAULT);
+
+            error = umtxq_check_susp(td);
+            if (error != 0)
+                break;
+
+            /* If this failed the lock has changed, restart. */
+            continue;
+        }
+
+        /*
+         * If we caught a signal, we have retried and now
+         * exit immediately.
+         */
+        if (error != 0)
+            break;
+
+        if ((error = umtx_key_get(umtx, TYPE_SIMPLE_LOCK,
+            AUTO_SHARE, &uq->uq_key)) != 0)
+            return (error);
+
+        umtxq_lock(&uq->uq_key);
+        umtxq_busy(&uq->uq_key);
+        umtxq_insert(uq);
+        umtxq_unbusy(&uq->uq_key);
+        umtxq_unlock(&uq->uq_key);
+
+        /*
+         * Set the contested bit so that a release in user space
+         * knows to use the system call for unlock.  If this fails
+         * either some one else has acquired the lock or it has been
+         * released.
+         */
+        old = casuword(&umtx->u_owner, owner, owner | UMTX_CONTESTED);
+
+        /* The address was invalid. */
+        if (old == -1) {
+            umtxq_lock(&uq->uq_key);
+            umtxq_remove(uq);
+            umtxq_unlock(&uq->uq_key);
+            umtx_key_release(&uq->uq_key);
+            return (EFAULT);
+        }
+
+        /*
+         * We set the contested bit, sleep. Otherwise the lock changed
+         * and we need to retry or we lost a race to the thread
+         * unlocking the umtx.
+         */
+        umtxq_lock(&uq->uq_key);
+        if (old == owner)
+            error = umtxq_sleep(uq, "umtx", timeout == NULL ? NULL :
+                &timo);
+        umtxq_remove(uq);
+        umtxq_unlock(&uq->uq_key);
+        umtx_key_release(&uq->uq_key);
+
+        if (error == 0)
+            error = umtxq_check_susp(td);
+    }
+
+    if (timeout == NULL) {
+        /* Mutex locking is restarted if it is interrupted. */
+        if (error == EINTR)
+            error = ERESTART;
+    } else {
+        /* Timed-locking is not restarted. */
+        if (error == ERESTART)
+            error = EINTR;
+    }
+    return (error);
+}
+
+/*
+ * Unlock a umtx object.
+ */
+static int
+do_unlock_umtx(struct thread *td, struct umtx *umtx, u_long id)
+{
+    struct umtx_key key;
+    u_long owner;
+    u_long old;
+    int error;
+    int count;
+
+    /*
+     * Make sure we own this mtx.
+     */
+    owner = fuword(__DEVOLATILE(u_long *, &umtx->u_owner));
+    if (owner == -1)
+        return (EFAULT);
+
+    if ((owner & ~UMTX_CONTESTED) != id)
+        return (EPERM);
+
+    /* This should be done in userland */
+    if ((owner & UMTX_CONTESTED) == 0) {
+        old = casuword(&umtx->u_owner, owner, UMTX_UNOWNED);
+        if (old == -1)
+            return (EFAULT);
+        if (old == owner)
+            return (0);
+        owner = old;
+    }
+
+    /* We should only ever be in here for contested locks */
+    if ((error = umtx_key_get(umtx, TYPE_SIMPLE_LOCK, AUTO_SHARE,
+        &key)) != 0)
+        return (error);
+
+    umtxq_lock(&key);
+    umtxq_busy(&key);
+    count = umtxq_count(&key);
+    umtxq_unlock(&key);
+
+    /*
+     * When unlocking the umtx, it must be marked as unowned if
+     * there is zero or one thread only waiting for it.
+     * Otherwise, it must be marked as contested.
+     */
+    old = casuword(&umtx->u_owner, owner,
+        count <= 1 ? UMTX_UNOWNED : UMTX_CONTESTED);
+    umtxq_lock(&key);
+    umtxq_signal(&key,1);
+    umtxq_unbusy(&key);
+    umtxq_unlock(&key);
+    umtx_key_release(&key);
+    if (old == -1)
+        return (EFAULT);
+    if (old != owner)
+        return (EINVAL);
+    return (0);
+}
+
+#ifdef COMPAT_FREEBSD32
+
+/*
+ * Lock a umtx object.
+ */
+static int
+do_lock_umtx32(struct thread *td, uint32_t *m, uint32_t id,
+    const struct timespec *timeout)
+{
+    struct abs_timeout timo;
+    struct umtx_q *uq;
+    uint32_t owner;
+    uint32_t old;
+    int error = 0;
+
+    uq = td->td_umtxq;
+
+    if (timeout != NULL)
+        abs_timeout_init(&timo, CLOCK_REALTIME, 0, timeout);
+
+    /*
+     * Care must be exercised when dealing with umtx structure. It
+     * can fault on any access.
+     */
+    for (;;) {
+        /*
+         * Try the uncontested case.  This should be done in userland.
+         */
+        owner = casuword32(m, UMUTEX_UNOWNED, id);
+
+        /* The acquire succeeded. */
+        if (owner == UMUTEX_UNOWNED)
+            return (0);
+
+        /* The address was invalid. */
+        if (owner == -1)
+            return (EFAULT);
+
+        /* If no one owns it but it is contested try to acquire it. */
+        if (owner == UMUTEX_CONTESTED) {
+            owner = casuword32(m,
+                UMUTEX_CONTESTED, id | UMUTEX_CONTESTED);
+            if (owner == UMUTEX_CONTESTED)
+                return (0);
+
+            /* The address was invalid. */
+            if (owner == -1)
+                return (EFAULT);
+
+            error = umtxq_check_susp(td);
+            if (error != 0)
+                break;
+
+            /* If this failed the lock has changed, restart. */
+            continue;
+        }
+
+        /*
+         * If we caught a signal, we have retried and now
+         * exit immediately.
+         */
+        if (error != 0)
+            return (error);
+
+        if ((error = umtx_key_get(m, TYPE_SIMPLE_LOCK,
+            AUTO_SHARE, &uq->uq_key)) != 0)
+            return (error);
+
+        umtxq_lock(&uq->uq_key);
+        umtxq_busy(&uq->uq_key);
+        umtxq_insert(uq);
+        umtxq_unbusy(&uq->uq_key);
+        umtxq_unlock(&uq->uq_key);
+
+        /*
+         * Set the contested bit so that a release in user space
+         * knows to use the system call for unlock.  If this fails
+         * either some one else has acquired the lock or it has been
+         * released.
+         */
+        old = casuword32(m, owner, owner | UMUTEX_CONTESTED);
+
+        /* The address was invalid. */
+        if (old == -1) {
+            umtxq_lock(&uq->uq_key);
+            umtxq_remove(uq);
+            umtxq_unlock(&uq->uq_key);
+            umtx_key_release(&uq->uq_key);
+            return (EFAULT);
+        }
+
+        /*
+         * We set the contested bit, sleep. Otherwise the lock changed
+         * and we need to retry or we lost a race to the thread
+         * unlocking the umtx.
+         */
+        umtxq_lock(&uq->uq_key);
+        if (old == owner)
+            error = umtxq_sleep(uq, "umtx", timeout == NULL ?
+                NULL : &timo);
+        umtxq_remove(uq);
+        umtxq_unlock(&uq->uq_key);
+        umtx_key_release(&uq->uq_key);
+
+        if (error == 0)
+            error = umtxq_check_susp(td);
+    }
+
+    if (timeout == NULL) {
+        /* Mutex locking is restarted if it is interrupted. */
+        if (error == EINTR)
+            error = ERESTART;
+    } else {
+        /* Timed-locking is not restarted. */
+        if (error == ERESTART)
+            error = EINTR;
+    }
+    return (error);
+}
+
+/*
+ * Unlock a umtx object.
+ */
+static int
+do_unlock_umtx32(struct thread *td, uint32_t *m, uint32_t id)
+{
+    struct umtx_key key;
+    uint32_t owner;
+    uint32_t old;
+    int error;
+    int count;
+
+    /*
+     * Make sure we own this mtx.
+     */
+    owner = fuword32(m);
+    if (owner == -1)
+        return (EFAULT);
+
+    if ((owner & ~UMUTEX_CONTESTED) != id)
+        return (EPERM);
+
+    /* This should be done in userland */
+    if ((owner & UMUTEX_CONTESTED) == 0) {
+        old = casuword32(m, owner, UMUTEX_UNOWNED);
+        if (old == -1)
+            return (EFAULT);
+        if (old == owner)
+            return (0);
+        owner = old;
+    }
+
+    /* We should only ever be in here for contested locks */
+    if ((error = umtx_key_get(m, TYPE_SIMPLE_LOCK, AUTO_SHARE,
+        &key)) != 0)
+        return (error);
+
+    umtxq_lock(&key);
+    umtxq_busy(&key);
+    count = umtxq_count(&key);
+    umtxq_unlock(&key);
+
+    /*
+     * When unlocking the umtx, it must be marked as unowned if
+     * there is zero or one thread only waiting for it.
+     * Otherwise, it must be marked as contested.
+     */
+    old = casuword32(m, owner,
+        count <= 1 ? UMUTEX_UNOWNED : UMUTEX_CONTESTED);
+    umtxq_lock(&key);
+    umtxq_signal(&key,1);
+    umtxq_unbusy(&key);
+    umtxq_unlock(&key);
+    umtx_key_release(&key);
+    if (old == -1)
+        return (EFAULT);
+    if (old != owner)
+        return (EINVAL);
+    return (0);
+}
+#endif
+
+/*
  * Fetch and compare value, sleep on the address if value is not changed.
  */
 static int
@@ -1078,6 +1439,10 @@
             }
         }
 
+        if ((flags & UMUTEX_ERROR_CHECK) != 0 &&
+            (owner & ~UMUTEX_CONTESTED) == id)
+            return (EDEADLK);
+
         if (mode == _UMUTEX_TRY)
             return (EBUSY);
 
@@ -1880,6 +2245,12 @@
             break;
         }
 
+        if ((flags & UMUTEX_ERROR_CHECK) != 0 &&
+            (owner & ~UMUTEX_CONTESTED) == id) {
+            error = EDEADLK;
+            break;
+        }
+
         if (try != 0) {
             error = EBUSY;
             break;
@@ -2149,6 +2520,12 @@
             break;
         }
 
+        if ((flags & UMUTEX_ERROR_CHECK) != 0 &&
+            (owner & ~UMUTEX_CONTESTED) == id) {
+            error = EDEADLK;
+            break;
+        }
+
         if (try != 0) {
             error = EBUSY;
             break;
@@ -3258,6 +3635,20 @@
     return (error);
 }
 
+int
+sys__umtx_lock(struct thread *td, struct _umtx_lock_args *uap)
+    /* struct umtx *umtx */
+{
+    return do_lock_umtx(td, uap->umtx, td->td_tid, 0);
+}
+
+int
+sys__umtx_unlock(struct thread *td, struct _umtx_unlock_args *uap)
+    /* struct umtx *umtx */
+{
+    return do_unlock_umtx(td, uap->umtx, td->td_tid);
+}
+
 inline int
 umtx_copyin_timeout(const void *addr, struct timespec *tsp)
 {
@@ -3293,10 +3684,27 @@
 }
 
 static int
-__umtx_op_unimpl(struct thread *td, struct _umtx_op_args *uap)
+__umtx_op_lock_umtx(struct thread *td, struct _umtx_op_args *uap)
 {
+    struct timespec *ts, timeout;
+    int error;
+
+    /* Allow a null timespec (wait forever). */
+    if (uap->uaddr2 == NULL)
+        ts = NULL;
+    else {
+        error = umtx_copyin_timeout(uap->uaddr2, &timeout);
+        if (error != 0)
+            return (error);
+        ts = &timeout;
+    }
+    return (do_lock_umtx(td, uap->obj, uap->val, ts));
+}
 
-    return (EOPNOTSUPP);
+static int
+__umtx_op_unlock_umtx(struct thread *td, struct _umtx_op_args *uap)
+{
+    return (do_unlock_umtx(td, uap->obj, uap->val));
 }
 
 static int
@@ -3926,8 +4334,8 @@
 typedef int (*_umtx_op_func)(struct thread *td, struct _umtx_op_args *uap);
 
 static const _umtx_op_func op_table[] = {
-    [UMTX_OP_RESERVED0]    = __umtx_op_unimpl,
-    [UMTX_OP_RESERVED1]    = __umtx_op_unimpl,
+    [UMTX_OP_LOCK]        = __umtx_op_lock_umtx,
+    [UMTX_OP_UNLOCK]    = __umtx_op_unlock_umtx,
     [UMTX_OP_WAIT]        = __umtx_op_wait,
     [UMTX_OP_WAKE]        = __umtx_op_wake,
     [UMTX_OP_MUTEX_TRYLOCK]    = __umtx_op_trylock_umutex,
@@ -3970,6 +4378,19 @@
 }
 
 #ifdef COMPAT_FREEBSD32
+int
+freebsd32_umtx_lock(struct thread *td, struct freebsd32_umtx_lock_args *uap)
+    /* struct umtx *umtx */
+{
+    return (do_lock_umtx32(td, (uint32_t *)uap->umtx, td->td_tid, NULL));
+}
+
+int
+freebsd32_umtx_unlock(struct thread *td, struct freebsd32_umtx_unlock_args *uap)
+    /* struct umtx *umtx */
+{
+    return (do_unlock_umtx32(td, (uint32_t *)uap->umtx, td->td_tid));
+}
 
 struct timespec32 {
     int32_t tv_sec;
@@ -4027,6 +4448,30 @@
 }
 
 static int
+__umtx_op_lock_umtx_compat32(struct thread *td, struct _umtx_op_args *uap)
+{
+    struct timespec *ts, timeout;
+    int error;
+
+    /* Allow a null timespec (wait forever). */
+    if (uap->uaddr2 == NULL)
+        ts = NULL;
+    else {
+        error = umtx_copyin_timeout32(uap->uaddr2, &timeout);
+        if (error != 0)
+            return (error);
+        ts = &timeout;
+    }
+    return (do_lock_umtx32(td, uap->obj, uap->val, ts));
+}
+
+static int
+__umtx_op_unlock_umtx_compat32(struct thread *td, struct _umtx_op_args *uap)
+{
+    return (do_unlock_umtx32(td, uap->obj, (uint32_t)uap->val));
+}
+
+static int
 __umtx_op_wait_compat32(struct thread *td, struct _umtx_op_args *uap)
 {
     struct _umtx_time *tm_p, timeout;
@@ -4245,8 +4690,8 @@
 }
 
 static const _umtx_op_func op_table_compat32[] = {
-    [UMTX_OP_RESERVED0]    = __umtx_op_unimpl,
-    [UMTX_OP_RESERVED1]    = __umtx_op_unimpl,
+    [UMTX_OP_LOCK]        = __umtx_op_lock_umtx_compat32,
+    [UMTX_OP_UNLOCK]    = __umtx_op_unlock_umtx_compat32,
     [UMTX_OP_WAIT]        = __umtx_op_wait_compat32,
     [UMTX_OP_WAKE]        = __umtx_op_wake,
     [UMTX_OP_MUTEX_TRYLOCK]    = __umtx_op_trylock_umutex,
diff -u -r src.fbsd11.stock/sys/kern/syscalls.c src.oldumtx/sys/kern/syscalls.c
--- src.fbsd11.stock/sys/kern/syscalls.c    2016-09-28 19:24:40.000000000 -0400
+++ src.oldumtx/sys/kern/syscalls.c    2017-04-05 15:44:29.738110000 -0400
@@ -2,8 +2,8 @@
  * System call names.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: releng/11.0/sys/kern/syscalls.c 303858 2016-08-08 21:19:57Z bdrewery $
- * created from FreeBSD: stable/11/sys/kern/syscalls.master 303854 2016-08-08 20:23:11Z bdrewery
+ * $FreeBSD$
+ * created from FreeBSD: releng/11.0/sys/kern/syscalls.master 303854 2016-08-08 20:23:11Z bdrewery
  */
 
 const char *syscallnames[] = {
@@ -441,8 +441,8 @@
     "thr_exit",            /* 431 = thr_exit */
     "thr_self",            /* 432 = thr_self */
     "thr_kill",            /* 433 = thr_kill */
-    "#434",            /* 434 = nosys */
-    "#435",            /* 435 = nosys */
+    "_umtx_lock",            /* 434 = _umtx_lock */
+    "_umtx_unlock",            /* 435 = _umtx_unlock */
     "jail_attach",            /* 436 = jail_attach */
     "extattr_list_fd",            /* 437 = extattr_list_fd */
     "extattr_list_file",            /* 438 = extattr_list_file */
diff -u -r src.fbsd11.stock/sys/kern/syscalls.master src.oldumtx/sys/kern/syscalls.master
--- src.fbsd11.stock/sys/kern/syscalls.master    2016-09-28 19:24:40.000000000 -0400
+++ src.oldumtx/sys/kern/syscalls.master    2017-04-04 13:50:05.910545000 -0400
@@ -774,8 +774,8 @@
 431    AUE_NULL    STD    { void thr_exit(long *state); }
 432    AUE_NULL    STD    { int thr_self(long *id); }
 433    AUE_NULL    STD    { int thr_kill(long id, int sig); }
-434    AUE_NULL    UNIMPL    nosys
-435    AUE_NULL    UNIMPL    nosys
+434    AUE_NULL    STD    { int _umtx_lock(struct umtx *umtx); }
+435    AUE_NULL    STD    { int _umtx_unlock(struct umtx *umtx); }
 436    AUE_NULL    STD    { int jail_attach(int jid); }
 437    AUE_EXTATTR_LIST_FD    STD    { ssize_t extattr_list_fd(int fd, \
                     int attrnamespace, void *data, \
diff -u -r src.fbsd11.stock/sys/kern/systrace_args.c src.oldumtx/sys/kern/systrace_args.c
--- src.fbsd11.stock/sys/kern/systrace_args.c    2016-09-28 19:24:40.000000000 -0400
+++ src.oldumtx/sys/kern/systrace_args.c    2017-04-05 15:44:29.743862000 -0400
@@ -2,7 +2,7 @@
  * System call argument to DTrace register array converstion.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: releng/11.0/sys/kern/systrace_args.c 302095 2016-06-22 21:18:19Z brooks $
+ * $FreeBSD$
  * This file is part of the DTrace syscall provider.
  */
 
@@ -2362,6 +2362,20 @@
         *n_args = 2;
         break;
     }
+    /* _umtx_lock */
+    case 434: {
+        struct _umtx_lock_args *p = params;
+        uarg[0] = (intptr_t) p->umtx; /* struct umtx * */
+        *n_args = 1;
+        break;
+    }
+    /* _umtx_unlock */
+    case 435: {
+        struct _umtx_unlock_args *p = params;
+        uarg[0] = (intptr_t) p->umtx; /* struct umtx * */
+        *n_args = 1;
+        break;
+    }
     /* jail_attach */
     case 436: {
         struct jail_attach_args *p = params;
@@ -7148,6 +7162,26 @@
             break;
         };
         break;
+    /* _umtx_lock */
+    case 434:
+        switch(ndx) {
+        case 0:
+            p = "struct umtx *";
+            break;
+        default:
+            break;
+        };
+        break;
+    /* _umtx_unlock */
+    case 435:
+        switch(ndx) {
+        case 0:
+            p = "struct umtx *";
+            break;
+        default:
+            break;
+        };
+        break;
     /* jail_attach */
     case 436:
         switch(ndx) {
@@ -10246,6 +10280,16 @@
         if (ndx == 0 || ndx == 1)
             p = "int";
         break;
+    /* _umtx_lock */
+    case 434:
+        if (ndx == 0 || ndx == 1)
+            p = "int";
+        break;
+    /* _umtx_unlock */
+    case 435:
+        if (ndx == 0 || ndx == 1)
+            p = "int";
+        break;
     /* jail_attach */
     case 436:
         if (ndx == 0 || ndx == 1)
diff -u -r src.fbsd11.stock/sys/sys/_umtx.h src.oldumtx/sys/sys/_umtx.h
--- src.fbsd11.stock/sys/sys/_umtx.h    2016-09-28 19:24:41.000000000 -0400
+++ src.oldumtx/sys/sys/_umtx.h    2017-04-04 13:51:15.942811000 -0400
@@ -33,6 +33,10 @@
 #include <sys/_types.h>
 #include <sys/_timespec.h>
 
+struct umtx {
+    volatile unsigned long u_owner;        /*Owner of the mutex. */
+};
+
 struct umutex {
     volatile __lwpid_t    m_owner;    /* Owner of the mutex */
     __uint32_t        m_flags;    /* Flags of the mutex */
diff -u -r src.fbsd11.stock/sys/sys/syscall.h src.oldumtx/sys/sys/syscall.h
--- src.fbsd11.stock/sys/sys/syscall.h    2016-09-28 19:24:41.000000000 -0400
+++ src.oldumtx/sys/sys/syscall.h    2017-04-05 15:44:29.738119000 -0400
@@ -2,8 +2,8 @@
  * System call numbers.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: releng/11.0/sys/sys/syscall.h 303858 2016-08-08 21:19:57Z bdrewery $
- * created from FreeBSD: stable/11/sys/kern/syscalls.master 303854 2016-08-08 20:23:11Z bdrewery
+ * $FreeBSD$
+ * created from FreeBSD: releng/11.0/sys/kern/syscalls.master 303854 2016-08-08 20:23:11Z bdrewery
  */
 
 #define    SYS_syscall    0
@@ -359,6 +359,8 @@
 #define    SYS_thr_exit    431
 #define    SYS_thr_self    432
 #define    SYS_thr_kill    433
+#define    SYS__umtx_lock    434
+#define    SYS__umtx_unlock    435
 #define    SYS_jail_attach    436
 #define    SYS_extattr_list_fd    437
 #define    SYS_extattr_list_file    438
diff -u -r src.fbsd11.stock/sys/sys/syscall.mk src.oldumtx/sys/sys/syscall.mk
--- src.fbsd11.stock/sys/sys/syscall.mk    2016-09-28 19:24:41.000000000 -0400
+++ src.oldumtx/sys/sys/syscall.mk    2017-04-05 15:44:29.738095000 -0400
@@ -1,7 +1,7 @@
 # FreeBSD system call object files.
 # DO NOT EDIT-- this file is automatically generated.
-# $FreeBSD: releng/11.0/sys/sys/syscall.mk 303858 2016-08-08 21:19:57Z bdrewery $
-# created from FreeBSD: stable/11/sys/kern/syscalls.master 303854 2016-08-08 20:23:11Z bdrewery
+# $FreeBSD$
+# created from FreeBSD: releng/11.0/sys/kern/syscalls.master 303854 2016-08-08 20:23:11Z bdrewery
 MIASM =  \
     syscall.o \
     exit.o \
@@ -289,6 +289,8 @@
     thr_exit.o \
     thr_self.o \
     thr_kill.o \
+    _umtx_lock.o \
+    _umtx_unlock.o \
     jail_attach.o \
     extattr_list_fd.o \
     extattr_list_file.o \
diff -u -r src.fbsd11.stock/sys/sys/sysproto.h src.oldumtx/sys/sys/sysproto.h
--- src.fbsd11.stock/sys/sys/sysproto.h    2016-09-28 19:24:41.000000000 -0400
+++ src.oldumtx/sys/sys/sysproto.h    2017-04-05 15:44:29.741627000 -0400
@@ -2,8 +2,8 @@
  * System call prototypes.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: releng/11.0/sys/sys/sysproto.h 303858 2016-08-08 21:19:57Z bdrewery $
- * created from FreeBSD: stable/11/sys/kern/syscalls.master 303854 2016-08-08 20:23:11Z bdrewery
+ * $FreeBSD$
+ * created from FreeBSD: releng/11.0/sys/kern/syscalls.master 303854 2016-08-08 20:23:11Z bdrewery
  */
 
 #ifndef _SYS_SYSPROTO_H_
@@ -1250,6 +1250,12 @@
     char id_l_[PADL_(long)]; long id; char id_r_[PADR_(long)];
     char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)];
 };
+struct _umtx_lock_args {
+    char umtx_l_[PADL_(struct umtx *)]; struct umtx * umtx; char umtx_r_[PADR_(struct umtx *)];
+};
+struct _umtx_unlock_args {
+    char umtx_l_[PADL_(struct umtx *)]; struct umtx * umtx; char umtx_r_[PADR_(struct umtx *)];
+};
 struct jail_attach_args {
     char jid_l_[PADL_(int)]; int jid; char jid_r_[PADR_(int)];
 };
@@ -2067,6 +2073,8 @@
 int    sys_thr_exit(struct thread *, struct thr_exit_args *);
 int    sys_thr_self(struct thread *, struct thr_self_args *);
 int    sys_thr_kill(struct thread *, struct thr_kill_args *);
+int    sys__umtx_lock(struct thread *, struct _umtx_lock_args *);
+int    sys__umtx_unlock(struct thread *, struct _umtx_unlock_args *);
 int    sys_jail_attach(struct thread *, struct jail_attach_args *);
 int    sys_extattr_list_fd(struct thread *, struct extattr_list_fd_args *);
 int    sys_extattr_list_file(struct thread *, struct extattr_list_file_args *);
@@ -2844,6 +2852,8 @@
 #define    SYS_AUE_thr_exit    AUE_NULL
 #define    SYS_AUE_thr_self    AUE_NULL
 #define    SYS_AUE_thr_kill    AUE_NULL
+#define    SYS_AUE__umtx_lock    AUE_NULL
+#define    SYS_AUE__umtx_unlock    AUE_NULL
 #define    SYS_AUE_jail_attach    AUE_NULL
 #define    SYS_AUE_extattr_list_fd    AUE_EXTATTR_LIST_FD
 #define    SYS_AUE_extattr_list_file    AUE_EXTATTR_LIST_FILE
diff -u -r src.fbsd11.stock/sys/sys/umtx.h src.oldumtx/sys/sys/umtx.h
--- src.fbsd11.stock/sys/sys/umtx.h    2016-09-28 19:24:41.000000000 -0400
+++ src.oldumtx/sys/sys/umtx.h    2017-04-05 17:10:53.884429000 -0400
@@ -31,11 +31,16 @@
 #define    _SYS_UMTX_H_
 
 #include <sys/_umtx.h>
+#include <sys/limits.h>
+
+#define UMTX_UNOWNED        0x0
+#define UMTX_CONTESTED        LONG_MIN
 
 /* Common lock flags */
 #define USYNC_PROCESS_SHARED    0x0001    /* Process shared sync objs */
 
 /* umutex flags */
+#define    UMUTEX_ERROR_CHECK    0x0002    /* Error-checking mutex */
 #define    UMUTEX_PRIO_INHERIT    0x0004    /* Priority inherited mutex */
 #define    UMUTEX_PRIO_PROTECT    0x0008    /* Priority protect mutex */
 #define    UMUTEX_ROBUST        0x0010    /* Robust mutex */
@@ -71,8 +76,8 @@
 #define    USEM_COUNT(c)        ((c) & USEM_MAX_COUNT)
 
 /* op code for _umtx_op */
-#define    UMTX_OP_RESERVED0    0
-#define    UMTX_OP_RESERVED1    1
+#define    UMTX_OP_LOCK        0
+#define    UMTX_OP_UNLOCK        1
 #define    UMTX_OP_WAIT        2
 #define    UMTX_OP_WAKE        3
 #define    UMTX_OP_MUTEX_TRYLOCK    4
@@ -124,6 +129,88 @@
 
 int _umtx_op(void *obj, int op, u_long val, void *uaddr, void *uaddr2);
 
+/*     
+ * Old (deprecated) userland mutex system calls.     
+ */     
+int _umtx_lock(struct umtx *mtx);     
+int _umtx_unlock(struct umtx *mtx);     
+     
+/*     
+ * Standard api.  Try uncontested acquire/release and asks the     
+ * kernel to resolve failures.     
+ */     
+static __inline void     
+umtx_init(struct umtx *umtx)     
+{     
+        umtx->u_owner = UMTX_UNOWNED;     
+}     
+     
+static __inline u_long     
+umtx_owner(struct umtx *umtx)     
+{     
+        return (umtx->u_owner & ~LONG_MIN);     
+}     
+     
+static __inline int     
+umtx_lock(struct umtx *umtx, u_long id)     
+{     
+        if (atomic_cmpset_acq_long(&umtx->u_owner, UMTX_UNOWNED, id) == 0)     
+                if (_umtx_lock(umtx) == -1)     
+                        /* return (errno); */
+            return (88); /*TODO: Fix all these returns once I know what I'm doing*/
+        return (0);     
+}     
+     
+static __inline int     
+umtx_trylock(struct umtx *umtx, u_long id)     
+{     
+        if (atomic_cmpset_acq_long(&umtx->u_owner, UMTX_UNOWNED, id) == 0)     
+                /* return (EBUSY);     */
+        return (16);
+        return (0);     
+}     
+     
+static __inline int     
+umtx_timedlock(struct umtx *umtx, u_long id, const struct timespec *timeout)     
+{     
+        if (atomic_cmpset_acq_long(&umtx->u_owner, UMTX_UNOWNED, id) == 0)     
+                if (_umtx_op(umtx, UMTX_OP_LOCK, id, 0,     
+                    __DECONST(void *, timeout)) == -1)     
+                        /*return (errno);     */
+            return (88);
+        return (0);     
+}     
+     
+static __inline int     
+umtx_unlock(struct umtx *umtx, u_long id)     
+{     
+        if (atomic_cmpset_rel_long(&umtx->u_owner, id, UMTX_UNOWNED) == 0)     
+                if (_umtx_unlock(umtx) == -1)     
+                        /* return (errno);     */
+            return (88);
+        return (0);     
+}     
+     
+static __inline int     
+umtx_wait(u_long *p, long val, const struct timespec *timeout)     
+{     
+        if (_umtx_op(p, UMTX_OP_WAIT, val, 0,     
+            __DECONST(void *, timeout)) == -1)     
+                /* return (errno);     */
+        return (88);
+        return (0);     
+}     
+     
+/* Wake threads waiting on a user address. */     
+static __inline int     
+umtx_wake(u_long *p, int nr_wakeup)     
+{     
+        if (_umtx_op(p, UMTX_OP_WAKE, nr_wakeup, 0, 0) == -1)     
+                /* return (errno);     */
+        return (88);
+        return (0);     
+}
+
 #else
 
 /*
diff -u -r src.fbsd11.stock/usr.bin/truss/syscall.h src.oldumtx/usr.bin/truss/syscall.h
--- src.fbsd11.stock/usr.bin/truss/syscall.h    2016-09-28 19:26:03.000000000 -0400
+++ src.oldumtx/usr.bin/truss/syscall.h    2017-04-04 14:45:02.960814000 -0400
@@ -23,6 +23,7 @@
  * Pollfd -- a pointer to an array of struct pollfd.  Prints .fd and .events.
  * Fd_set -- a pointer to an array of fd_set.  Prints the fds that are set.
  * Sigaction -- a pointer to a struct sigaction.  Prints all elements.
+ * Umtx -- a pointer to a struct umtx.  Prints the value of owner.
  * Sigset -- a pointer to a sigset_t.  Prints the signals that are set.
  * Sigprocmask -- the first argument to sigprocmask().  Prints the name.
  * Kevent -- a pointer to an array of struct kevents.  Prints all elements.
@@ -40,7 +41,7 @@
 enum Argtype { None = 1, Hex, Octal, Int, UInt, LongHex, Name, Ptr, Stat, Ioctl,
     Quad, Signal, Sockaddr, StringArray, Timespec, Timeval, Itimerval,
     Pollfd, Fd_set, Sigaction, Fcntl, Mprot, Mmapflags, Whence, Readlinkres,
-    Sigset, Sigprocmask, StatFs, Kevent, Sockdomain, Socktype, Open,
+    Umtx, Sigset, Sigprocmask, StatFs, Kevent, Sockdomain, Socktype, Open,
     Fcntlflag, Rusage, BinString, Shutdown, Resource, Rlimit, Timeval2,
     Pathconf, Rforkflags, ExitStatus, Waitoptions, Idtype, Procctl,
     LinuxSockArgs, Umtxop, Atfd, Atflags, Timespec2, Accessmode, Long,
diff -u -r src.fbsd11.stock/usr.bin/truss/syscalls.c src.oldumtx/usr.bin/truss/syscalls.c
--- src.fbsd11.stock/usr.bin/truss/syscalls.c    2016-09-28 19:26:03.000000000 -0400
+++ src.oldumtx/usr.bin/truss/syscalls.c    2017-04-04 14:46:19.634451000 -0400
@@ -187,6 +187,10 @@
     { .name = "kevent", .ret_type = 1, .nargs = 6,
       .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 },
             { Int, 4 }, { Timespec, 5 } } },
+    { .name = "_umtx_lock", .ret_type = 0, .nargs = 1,     
+      .args = { { Umtx, 0 } } },     
+    { .name = "_umtx_unlock", .ret_type = 0, .nargs = 1,     
+      .args = { { Umtx, 0 } } },
     { .name = "kill", .ret_type = 1, .nargs = 2,
       .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
     { .name = "kldfind", .ret_type = 1, .nargs = 1,
@@ -668,7 +672,7 @@
 };
 
 static struct xlat umtx_ops[] = {
-    X(UMTX_OP_RESERVED0) X(UMTX_OP_RESERVED1) X(UMTX_OP_WAIT)
+    X(UMTX_OP_LOCK) X(UMTX_OP_UNLOCK) X(UMTX_OP_WAIT)
     X(UMTX_OP_WAKE) X(UMTX_OP_MUTEX_TRYLOCK) X(UMTX_OP_MUTEX_LOCK)
     X(UMTX_OP_MUTEX_UNLOCK) X(UMTX_OP_SET_CEILING) X(UMTX_OP_CV_WAIT)
     X(UMTX_OP_CV_SIGNAL) X(UMTX_OP_CV_BROADCAST) X(UMTX_OP_WAIT_UINT)
@@ -1329,6 +1333,15 @@
         }
         break;
     }
+    case Umtx: {     
+        struct umtx umtx;
+        if (get_struct(pid, (void *)args[sc->offset], &umtx,
+            sizeof(umtx)) != -1)
+            asprintf(&tmp, "{ 0x%lx }", (long)umtx.u_owner);
+        else
+            asprintf(&tmp, "0x%lx", args[sc->offset]);
+        break;
+    }
     case Timespec: {
         struct timespec ts;
Comment 1 Conrad Meyer freebsd_committer 2017-04-11 21:31:01 UTC
Rather than adding backwards compatibility for a 10-year obsolete version of FreeBSD to 11, why not just rebuild jdk1.5.0?
Comment 2 Nicholas Hardison 2017-04-12 22:00:05 UTC
It isn't practical to recompile the jdk in this environment due to its location on a shared filesystem (with a bunch of other stuff) and need to be able to continue running the 8.2 systems as I do the upgrades (a multi-stage process that happens over a period of months, during which work must go on).

I started working in this freebsd environment back when it was running 4.8, and the binary compatibility has been a major selling point of FreeBSD through upgrades since then (though my regression tests don't cover product versions from that long ago - iirc we don't need it _quite_ that far back).  Being able to replace the environment with new systems that can still run the old toolchains keeps me from having to keep and support my current set of 8.2 servers for X more years (they're too old as it is - ironically one of the reasons I could finally justify upgrading is the need to run a _new_ jdk).
Comment 3 Conrad Meyer freebsd_committer 2017-04-12 22:02:08 UTC
You could rebuild jdk1.5.0 on your 8.2 machines, which have the new interface, and share it with the 11 machines.  FreeBSD supports a lot of backwards compatibility but a decade old obsolete interface is expecting a lot.
Comment 4 Jilles Tjoelker freebsd_committer 2017-04-17 16:24:07 UTC
Most of the time, freebsd6 compatibility is left in. It seems inconsistent to remove the old umtx calls if the rest is left in.

It does look unfortunate to have two copies of almost-but-not-completely duplicate code added to kern_umtx.c. However, it may be the least bad way so that development of the current code is hindered as little as possible.

Adding the syscall stubs and exports back to libc seems unnecessary since these calls were not supposed to be used by applications directly, and mixing libc/libthr versions is not supported. Likewise, what was removed from <sys/umtx.h> need not be restored (except as needed for kernel implementation).
UMUTEX_ERROR_CHECK was added after stable/6 and never used, so need not be restored either.

If the old code is dynamically linked, it is worth a try to run it with the new libc and libthr.
Comment 5 Nicholas Hardison 2017-04-20 23:45:16 UTC
Thanks for the pointer - it looks like my binary is dynamically linked, so I'll try making another patch in the next day or so and see if that will work.
Comment 6 Nicholas Hardison 2017-07-13 22:26:38 UTC
I believe I have a new patch, with the syscalls marked as COMPAT6 instead of STD, and without the libc changes, and my test case binary seems to work!

On the UMUTEX_ERROR_CHECK definition - on my 8.2-RELEASE systems, it looks like it is being used in error handling for the functions in kern/kern_umtx.c, so I don't think I should get rid of it.  I could try and remove it, or does that mean it should be marked compat8 instead of compat6?