--- old/usr/src/common/brand/lx/lx_signum.h	Thu Jul 16 00:05:37 2015
+++ new/usr/src/common/brand/lx/lx_signum.h	Thu Jul 16 00:05:37 2015
@@ -71,6 +71,8 @@
 #define	LX_SIGRTMIN	32
 #define	LX_SIGRTMAX	LX_NSIG
 
+#define	LX_SIGTIMER	LX_SIGRTMIN
+
 extern const int ltos_signo[];
 extern const int stol_signo[];
 
--- old/usr/src/lib/brand/lx/lx_brand/common/clock.c	Thu Jul 16 00:05:37 2015
+++ new/usr/src/lib/brand/lx/lx_brand/common/clock.c	Thu Jul 16 00:05:37 2015
@@ -25,9 +25,13 @@
  * Copyright 2015 Joyent, Inc.
  */
 
+#include <sys/syscall.h>
+
 #include <errno.h>
+#include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <unistd.h>
 #include <sys/resource.h>
 #include <sys/lx_misc.h>
 #include <sys/lx_syscall.h>
@@ -113,10 +117,11 @@
 	SIGEV_NONE,
 	SIGEV_THREAD,
 	0,		/* Linux skips event 3 */
-	SIGEV_THREAD	/* the Linux SIGEV_THREAD_ID */
+	SIGEV_THREAD	/* Linux SIGEV_THREAD_ID -- see lx_sigev_thread_id() */
 };
 
-#define	LX_SIGEV_MAX	(sizeof (ltos_sigev) / sizeof (ltos_sigev[0]))
+#define	LX_SIGEV_MAX		(sizeof (ltos_sigev) / sizeof (ltos_sigev[0]))
+#define	LX_SIGEV_THREAD_ID	4
 
 long
 lx_clock_nanosleep(int clock, int flags, struct timespec *rqtp,
@@ -163,6 +168,22 @@
 }
 
 /*
+ * Notification function for use with native SIGEV_THREAD in order to
+ * emulate Linux SIGEV_THREAD_ID. Native SIGEV_THREAD is used as the
+ * timer mechanism and B_SIGEV_THREAD_ID performs the actual event
+ * delivery to the appropriate lx tid.
+ */
+static void
+lx_sigev_thread_id(union sigval sival)
+{
+	lx_sigevent_t *lev = (lx_sigevent_t *)sival.sival_ptr;
+	syscall(SYS_brand, B_SIGEV_THREAD_ID, lev->lx_sigev_un.lx_tid,
+	    lev->lx_sigev_signo, lev->lx_sigev_value);
+	free(lev);
+}
+
+
+/*
  * The Illumos timer_create man page says it accepts the following clocks:
  *   CLOCK_REALTIME (3)	wall clock
  *   CLOCK_VIRTUAL (1)	user CPU usage clock - No Backend
@@ -193,10 +214,56 @@
 	sev.sigev_value = lev.lx_sigev_value;
 
 	/*
-	 * The sigevent sigev_notify_function and sigev_notify_attributes
-	 * members are not used by timer_create, so no conversion is needed.
+	 * Assume all Linux libc implementations map SIGEV_THREAD to
+	 * SIGEV_THREAD_ID and ignore passed-in attributes.
 	 */
+	sev.sigev_notify_attributes = NULL;
 
+	if (lev.lx_sigev_notify == LX_SIGEV_THREAD_ID) {
+		pid_t caller_pid = getpid();
+		pid_t target_pid;
+		int rval;
+
+		if ((rval = lx_lpid_to_spair(lev.lx_sigev_un.lx_tid,
+			    &target_pid, NULL)) != 0) {
+
+			/*
+			 * Attempt to stick to the defined ERRORS in
+			 * timer_create(2).
+			 */
+			if (rval == -ESRCH)
+				return (-EINVAL);
+
+			return (rval);
+		}
+
+		/*
+		 * The caller of SIGEV_THREAD_ID must be in the same
+		 * process as the target thread.
+		 */
+		if (caller_pid != target_pid)
+			return (-EINVAL);
+
+		/*
+		 * Pass the original lx sigevent_t to the native
+		 * notify function so that it may pass it to the lx
+		 * helper thread. It is the responsibility of
+		 * lx_sigev_thread_id() to free lev_copy after the
+		 * information is relayed to lx.
+		 */
+		lx_sigevent_t *lev_copy = malloc(sizeof (lx_sigevent_t));
+		if (lev_copy == NULL)
+			return (-ENOMEM);
+
+		if (uucopy(&lev, lev_copy, sizeof (lx_sigevent_t)) < 0) {
+			free(lev_copy);
+			return (-EFAULT);
+		}
+
+		sev.sigev_notify_function = lx_sigev_thread_id;
+		sev.sigev_value.sival_ptr = lev_copy;
+	}
+
 	return ((timer_create(ltos_timer[clock], &sev, tid) < 0) ? -errno : 0);
 }
 
--- old/usr/src/uts/common/brand/lx/os/lx_brand.c	Thu Jul 16 00:05:38 2015
+++ new/usr/src/uts/common/brand/lx/os/lx_brand.c	Thu Jul 16 00:05:38 2015
@@ -990,6 +990,59 @@
 		return (0);
 	}
 
+	case B_SIGEV_THREAD_ID: {
+		/*
+		 * Emulate Linux's timer_create(2) SIGEV_THREAD_ID
+		 * notification method. This mechanism is only meant
+		 * for userland threading libraries such as glibc and
+		 * is documented as such. Therefore, assume this is
+		 * only ever invoked for the purpose of alerting a
+		 * Linux threading library. Assume that the tid is a
+		 * member of the caller's process and the signal
+		 * number is valid. See lx_sigev_thread_id() for the
+		 * userland side of this emulation.
+		 *
+		 * The return code from this function is not checked
+		 * by the caller since it executes in an asynchronous
+		 * context and there is nothing much to be done. If
+		 * this function does fail then it will manifest as
+		 * Linux threads waiting for a signal they will never
+		 * receive.
+		 *
+		 * arg1 -- Linux tid
+		 * arg2 -- signal number
+		 * arg3 -- union sigval
+		 */
+
+		int native_sig = lx_stol_signo((int)arg2, LX_SIGTIMER);
+		pid_t native_pid;
+		int native_tid;
+		sigqueue_t *sqp;
+
+		lx_lpid_to_spair((pid_t)arg1, &native_pid, &native_tid);
+		sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP);
+		mutex_enter(&curproc->p_lock);
+
+		if ((t = idtot(curproc, native_tid)) == NULL) {
+			mutex_exit(&curproc->p_lock);
+			kmem_free(sqp, sizeof (sigqueue_t));
+			return (ESRCH);
+		}
+
+		sqp->sq_info.si_signo = native_sig;
+		sqp->sq_info.si_code = SI_TIMER;
+		sqp->sq_info.si_pid = curproc->p_pid;
+		sqp->sq_info.si_zoneid = getzoneid();
+		sqp->sq_info.si_uid = crgetruid(CRED());
+		sqp->sq_info.si_value = (union sigval)((void *)arg3);
+		sigaddqa(curproc, t, sqp);
+
+		mutex_exit(&curproc->p_lock);
+		kmem_free(sqp, sizeof (sigqueue_t));
+
+		return (0);
+	}
+
 	case B_SET_AFFINITY_MASK:
 	case B_GET_AFFINITY_MASK:
 		/*
--- old/usr/src/uts/common/brand/lx/sys/lx_brand.h	Thu Jul 16 00:05:38 2015
+++ new/usr/src/uts/common/brand/lx/sys/lx_brand.h	Thu Jul 16 00:05:38 2015
@@ -95,6 +95,7 @@
 #define	B_HELPER_SIGQUEUE	145
 #define	B_HELPER_TGSIGQUEUE	146
 #define	B_SET_NATIVE_STACK	147
+#define	B_SIGEV_THREAD_ID	148
 
 #ifndef _ASM
 /*
