Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 31 Jul 2006 15:22:34 GMT
From:      Roman Divacky <rdivacky@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 102853 for review
Message-ID:  <200607311522.k6VFMYxY034413@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=102853

Change 102853 by rdivacky@rdivacky_witten on 2006/07/31 15:22:00

	Implement FUTEX_WAKE_OP. This should be correct but doesnt seem to let realplay work.

Affected files ...

.. //depot/projects/soc2006/rdivacky_linuxolator/compat/linux/linux_futex.c#11 edit
.. //depot/projects/soc2006/rdivacky_linuxolator/compat/linux/linux_futex.h#5 edit
.. //depot/projects/soc2006/rdivacky_linuxolator/i386/i386/support.s#2 edit

Differences ...

==== //depot/projects/soc2006/rdivacky_linuxolator/compat/linux/linux_futex.c#11 (text+ko) ====

@@ -77,6 +77,14 @@
 static void futex_put(struct futex *);
 static int futex_sleep(struct futex *, struct thread *, unsigned long);
 static int futex_wake(struct futex *, int, struct futex *);
+static int futex_atomic_op(struct thread *td, int encoded_op, caddr_t uaddr);
+
+/* support.s */
+int futex_xchgl(int oparg, caddr_t uaddr, int *oldval);
+int futex_addl(int oparg, caddr_t uaddr, int *oldval);
+int futex_orl(int oparg, caddr_t uaddr, int *oldval);
+int futex_andnl(int oparg, caddr_t uaddr, int *oldval);
+int futex_xorl(int oparg, caddr_t uaddr, int *oldval);
 
 int
 linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
@@ -85,10 +93,11 @@
 	int ret;
 	struct timespec timeout = { 0, 0 };
 	int error = 0;
-	struct futex *f;
+	struct futex *f, *f2;
 	struct futex *newf;
 	int timeout_hz;
 	struct timeval tv = {0, 0};
+	int op_ret;
 
 #ifdef	DEBUG
 	if (ldebug(sys_futex))
@@ -209,11 +218,46 @@
 		printf("linux_sys_futex: unimplemented op %d\n", 
 		    args->op);
 		break;
+
 	case LINUX_FUTEX_WAKE_OP:
-		/* XXX: it seems necessary for realplay */
-		printf("linux_sys_futex: unimplemented op %d\n",
-		    args->op);
+#ifdef DEBUG
+		if (ldebug(sys_futex))
+   		   	printf("FUTEX_WAKE_OP: %d: uaddr = %p, op = %d, val = %d, uaddr2 = %p, val3 = %d\n",
+		      		td->td_proc->p_pid, args->uaddr, args->op, args->val, args->uaddr2, args->val3);
+#endif
+		f = futex_get(args->uaddr);
+		f2 = futex_get(args->uaddr2);
+
+		op_ret = futex_atomic_op(td, args->val3, args->uaddr2);
+		if (op_ret < 0) {
+
+		   	/* XXX: ? */
+		   	if (op_ret != -EFAULT) {
+			   	futex_put(f);
+			   	futex_put(f2);
+			   	return (-op_ret);
+			}
+
+			futex_put(f);
+			futex_put(f2);
+
+			return (EFAULT);
+
+		}
+
+		ret = futex_wake(f, args->val, NULL);
+		futex_put(f);
+		if (op_ret > 0) {
+		   	printf("second wakeup\n");
+		   	op_ret = 0;
+		   	/* Linux always puts there 0 retries */
+   		   	op_ret += futex_wake(f2, 0, NULL);
+			futex_put(f2);
+			ret += op_ret;
+		}
+		td->td_retval[0] = ret;
 	   	break;
+
 	default:
 		printf("linux_sys_futex: unknown op %d\n", 
 		    args->op);
@@ -321,3 +365,71 @@
 
 	return count;
 }
+
+static int
+futex_atomic_op(struct thread *td, int encoded_op, caddr_t uaddr)
+{
+   	int op = (encoded_op >> 28) & 7;
+        int cmp = (encoded_op >> 24) & 15;
+        int oparg = (encoded_op << 8) >> 20;
+        int cmparg = (encoded_op << 20) >> 20;
+        int oldval = 0, ret;
+
+	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+	   	oparg = 1 << oparg;
+
+#ifdef DEBUG	
+	printf("futex_atomic_op: op = %d, cmp = %d, oparg = %d, cmparg = %d\n",
+	      op, cmp, oparg, cmparg);
+#endif
+	/* XXX: linux verifies access here and returns EFAULT */
+
+	critical_enter();
+
+	switch (op) {
+	   	case FUTEX_OP_SET:
+		   	ret = futex_xchgl(oparg, uaddr, &oldval);
+			break;
+		case FUTEX_OP_ADD:
+			ret = futex_addl(oparg, uaddr, &oldval);
+			break;
+		case FUTEX_OP_OR:
+			ret = futex_orl(oparg, uaddr, &oldval);
+			break;
+		case FUTEX_OP_ANDN:
+			ret = futex_andnl(oparg, uaddr, &oldval);
+			break;
+		case FUTEX_OP_XOR:
+			ret = futex_xorl(oparg, uaddr, &oldval);
+			break;
+		default:
+			ret = -ENOSYS;
+	}
+
+	critical_exit();
+
+	if (!ret)
+	   	switch (cmp) {
+		      case FUTEX_OP_CMP_EQ: 
+			 	ret = (oldval == cmparg); 
+				break;
+		      case FUTEX_OP_CMP_NE: 
+				ret = (oldval != cmparg); 
+				break;
+		      case FUTEX_OP_CMP_LT: 
+				ret = (oldval < cmparg); 
+				break;
+		      case FUTEX_OP_CMP_GE: 
+				ret = (oldval >= cmparg); 
+				break;
+		      case FUTEX_OP_CMP_LE: 
+				ret = (oldval <= cmparg); 
+				break;
+		      case FUTEX_OP_CMP_GT: 
+				ret = (oldval > cmparg); 
+				break;
+		      default: ret = -ENOSYS;
+		}
+
+	return (ret);
+}

==== //depot/projects/soc2006/rdivacky_linuxolator/compat/linux/linux_futex.h#5 (text+ko) ====

@@ -47,4 +47,13 @@
 #define FUTEX_OP_ANDN           3       /* *(int *)UADDR2 &= ~OPARG; */
 #define FUTEX_OP_XOR            4       /* *(int *)UADDR2 ^= OPARG; */
 
+#define FUTEX_OP_OPARG_SHIFT    8       /* Use (1 << OPARG) instead of OPARG.  */
+
+#define FUTEX_OP_CMP_EQ         0       /* if (oldval == CMPARG) wake */
+#define FUTEX_OP_CMP_NE         1       /* if (oldval != CMPARG) wake */
+#define FUTEX_OP_CMP_LT         2       /* if (oldval < CMPARG) wake */
+#define FUTEX_OP_CMP_LE         3       /* if (oldval <= CMPARG) wake */
+#define FUTEX_OP_CMP_GT         4       /* if (oldval > CMPARG) wake */
+#define FUTEX_OP_CMP_GE         5       /* if (oldval >= CMPARG) wake */
+
 #endif /* !_LINUX_FUTEX_H */

==== //depot/projects/soc2006/rdivacky_linuxolator/i386/i386/support.s#2 (text+ko) ====

@@ -1522,6 +1522,12 @@
 bbhead:
 	.long 0
 
+#if defined(SMP) || !defined(_KERNEL)
+#define MPLOCKED        lock ;
+#else
+#define MPLOCKED
+#endif
+
 	.text
 NON_GPROF_ENTRY(__bb_init_func)
 	movl	4(%esp),%eax
@@ -1530,3 +1536,98 @@
 	movl	%edx,16(%eax)
 	movl	%eax,bbhead
 	NON_GPROF_RET
+
+/* necessary for linux_futex support */
+	.text
+
+futex_fault:
+	movl	PCPU(CURPCB), %edx
+	movl	$0, PCB_ONFAULT(%edx)
+	movl	$-EFAULT, %eax
+	ret
+
+/* int futex_xchgl(int oparg, caddr_t uaddr, int *oldval); */
+	.globl	futex_xchgl
+futex_xchgl:
+	movl	PCPU(CURPCB), %eax
+	movl	$futex_fault, PCB_ONFAULT(%eax)
+	movl	4(%esp), %eax
+	movl	8(%esp), %edx
+
+	xchgl	%eax, (%edx)
+	movl	0xc(%esp), %edx
+	movl	%eax, (%edx)
+	xorl	%eax, %eax
+
+	movl	PCPU(CURPCB), %edx	
+	movl	$0, PCB_ONFAULT(%edx)
+	ret
+
+/* int futex_addl(int oparg, caddr_t uaddr, int *oldval); */
+	.globl	futex_addl
+futex_addl:
+	movl	PCPU(CURPCB), %eax
+	movl	$futex_fault, PCB_ONFAULT(%eax)
+	movl	4(%esp), %eax
+	movl	8(%esp), %edx
+
+	MPLOCKED xaddl	%eax, (%edx)
+	movl	0xc(%esp), %edx
+	movl	%eax, (%edx)
+	xorl	%eax, %eax
+
+	movl	PCPU(CURPCB), %edx
+	movl	$0, PCB_ONFAULT(%edx)
+	ret
+
+/* int futex_orl(int oparg, caddr_t uaddr, int *oldval); */
+	.globl	futex_orl
+futex_orl:
+	movl	PCPU(CURPCB), %eax
+	movl	$futex_fault, PCB_ONFAULT(%eax)
+	movl	4(%esp), %eax
+	movl	8(%esp), %edx
+
+	orl 	%eax, (%edx)
+	movl	0xc(%esp), %edx
+	movl	%eax, (%edx)
+	xorl	%eax, %eax
+
+	movl	PCPU(CURPCB), %edx
+	movl	$0, PCB_ONFAULT(%edx)
+	ret
+
+/* int futex_andnl(int oparg, caddr_t uaddr, int *oldval); */
+	.globl	futex_andnl
+futex_andnl:
+	movl	PCPU(CURPCB), %eax
+	movl	$futex_fault, PCB_ONFAULT(%eax)
+	movl	4(%esp), %eax
+	movl	8(%esp), %edx
+
+	notl	(%edx)
+	andl 	%eax, (%edx)
+	movl	0xc(%esp), %edx
+	movl	%eax, (%edx)
+	xorl	%eax, %eax
+
+	movl	PCPU(CURPCB), %edx
+	movl	$0, PCB_ONFAULT(%edx)
+	ret
+
+/* int futex_xorl(int oparg, caddr_t uaddr, int *oldval); */
+	.globl	futex_xorl
+futex_xorl:
+	movl	PCPU(CURPCB), %eax
+	movl	$futex_fault, PCB_ONFAULT(%eax)
+	movl	4(%esp), %eax
+	movl	8(%esp), %edx
+
+	xorl 	%eax, (%edx)
+	movl	0xc(%esp), %edx
+	movl	%eax, (%edx)
+	xorl	%eax, %eax
+
+	movl	PCPU(CURPCB), %edx
+	movl	$0, PCB_ONFAULT(%edx)
+	ret



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200607311522.k6VFMYxY034413>