git: f04534f5c84e - main - sysvsem: Add a timeout argument to the semop.

From: Dmitry Chagin <dchagin_at_FreeBSD.org>
Date: Fri, 06 May 2022 17:03:34 UTC
The branch main has been updated by dchagin:

URL: https://cgit.FreeBSD.org/src/commit/?id=f04534f5c84e58009efbb7f378803da3f33585b9

commit f04534f5c84e58009efbb7f378803da3f33585b9
Author:     Dmitry Chagin <dchagin@FreeBSD.org>
AuthorDate: 2022-05-06 16:51:48 +0000
Commit:     Dmitry Chagin <dchagin@FreeBSD.org>
CommitDate: 2022-05-06 16:51:48 +0000

    sysvsem: Add a timeout argument to the semop.
    
    For future use in the Linux emulation layer for the semtimedop syscall
    split the sys_semop syscall into two counterparts and add
    struct timespec *timeout argument to the last one.
    
    Reviewed by:            jhb, kib
    Differential revision:  https://reviews.freebsd.org/D35121
    MFC after:              2 weeks
---
 sys/kern/sysv_sem.c   | 50 ++++++++++++++++++++++++++++++++++++++------------
 sys/sys/syscallsubr.h |  3 +++
 2 files changed, 41 insertions(+), 12 deletions(-)

diff --git a/sys/kern/sysv_sem.c b/sys/kern/sysv_sem.c
index b55ef00c9c70..d489821e983b 100644
--- a/sys/kern/sysv_sem.c
+++ b/sys/kern/sysv_sem.c
@@ -1097,11 +1097,18 @@ struct semop_args {
 #endif
 int
 sys_semop(struct thread *td, struct semop_args *uap)
+{
+
+	return (kern_semop(td, uap->semid, uap->sops, uap->nsops, NULL));
+}
+
+int
+kern_semop(struct thread *td, int usemid, struct sembuf *usops,
+    size_t nsops, struct timespec *timeout)
 {
 #define SMALL_SOPS	8
 	struct sembuf small_sops[SMALL_SOPS];
-	int semid = uap->semid;
-	size_t nsops = uap->nsops;
+	int semid;
 	struct prison *rpr;
 	struct sembuf *sops;
 	struct semid_kernel *semakptr;
@@ -1109,6 +1116,7 @@ sys_semop(struct thread *td, struct semop_args *uap)
 	struct sem *semptr = NULL;
 	struct sem_undo *suptr;
 	struct mtx *sema_mtxp;
+	sbintime_t sbt, precision;
 	size_t i, j, k;
 	int error;
 	int do_wakeup, do_undos;
@@ -1117,18 +1125,35 @@ sys_semop(struct thread *td, struct semop_args *uap)
 #ifdef SEM_DEBUG
 	sops = NULL;
 #endif
-	DPRINTF(("call to semop(%d, %p, %u)\n", semid, sops, nsops));
+	DPRINTF(("call to semop(%d, %p, %u)\n", usemid, usops, nsops));
 
-	AUDIT_ARG_SVIPC_ID(semid);
+	AUDIT_ARG_SVIPC_ID(usemid);
 
 	rpr = sem_find_prison(td->td_ucred);
 	if (sem == NULL)
 		return (ENOSYS);
 
-	semid = IPCID_TO_IX(semid);	/* Convert back to zero origin */
+	semid = IPCID_TO_IX(usemid);	/* Convert back to zero origin */
 
 	if (semid < 0 || semid >= seminfo.semmni)
 		return (EINVAL);
+	if (timeout != NULL) {
+		if (!timespecvalid_interval(timeout))
+			return (EINVAL);
+		precision = 0;
+		if (timespecisset(timeout)) {
+			if (timeout->tv_sec < INT32_MAX / 2) {
+				precision = tstosbt(*timeout);
+				if (TIMESEL(&sbt, precision))
+					sbt += tc_tick_sbt;
+				sbt += precision;
+				precision >>= tc_precexp;
+			} else
+				sbt = 0;
+		} else
+			sbt = -1;
+	} else
+		precision = sbt = 0;
 
 	/* Allocate memory for sem_ops */
 	if (nsops <= SMALL_SOPS)
@@ -1152,9 +1177,9 @@ sys_semop(struct thread *td, struct semop_args *uap)
 
 		sops = malloc(nsops * sizeof(*sops), M_TEMP, M_WAITOK);
 	}
-	if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) {
+	if ((error = copyin(usops, sops, nsops * sizeof(sops[0]))) != 0) {
 		DPRINTF(("error = %d from copyin(%p, %p, %d)\n", error,
-		    uap->sops, sops, nsops * sizeof(sops[0])));
+		    usops, sops, nsops * sizeof(sops[0])));
 		if (sops != small_sops)
 			free(sops, M_TEMP);
 		return (error);
@@ -1168,7 +1193,7 @@ sys_semop(struct thread *td, struct semop_args *uap)
 		goto done2;
 	}
 	seq = semakptr->u.sem_perm.seq;
-	if (seq != IPCID_TO_SEQ(uap->semid)) {
+	if (seq != IPCID_TO_SEQ(usemid)) {
 		error = EINVAL;
 		goto done2;
 	}
@@ -1286,8 +1311,8 @@ sys_semop(struct thread *td, struct semop_args *uap)
 			semptr->semncnt++;
 
 		DPRINTF(("semop:  good night!\n"));
-		error = msleep(semakptr, sema_mtxp, (PZERO - 4) | PCATCH,
-		    "semwait", 0);
+		error = msleep_sbt(semakptr, sema_mtxp, (PZERO - 4) | PCATCH,
+		    "semwait", sbt, precision, C_ABSOLUTE);
 		DPRINTF(("semop:  good morning (error=%d)!\n", error));
 		/* return code is checked below, after sem[nz]cnt-- */
 
@@ -1296,7 +1321,7 @@ sys_semop(struct thread *td, struct semop_args *uap)
 		 */
 		seq = semakptr->u.sem_perm.seq;
 		if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
-		    seq != IPCID_TO_SEQ(uap->semid)) {
+		    seq != IPCID_TO_SEQ(usemid)) {
 			error = EIDRM;
 			goto done2;
 		}
@@ -1323,7 +1348,8 @@ sys_semop(struct thread *td, struct semop_args *uap)
 		 * need to decrement sem[nz]cnt either way.)
 		 */
 		if (error != 0) {
-			error = EINTR;
+			if (error == ERESTART)
+				error = EINTR;
 			goto done2;
 		}
 		DPRINTF(("semop:  good morning!\n"));
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index c66a34536444..1f5f4cd2369d 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -57,6 +57,7 @@ struct ogetdirentries_args;
 struct rlimit;
 struct rusage;
 struct sched_param;
+struct sembuf;
 union semun;
 struct sockaddr;
 struct spacectl_range;
@@ -328,6 +329,8 @@ int	kern_ktimer_settime(struct thread *td, int timer_id, int flags,
 int	kern_ktimer_gettime(struct thread *td, int timer_id,
 	    struct itimerspec *val);
 int	kern_ktimer_getoverrun(struct thread *td, int timer_id);
+int	kern_semop(struct thread *td, int usemid, struct sembuf *usops,
+	    size_t nsops, struct timespec *timeout);
 int	kern_thr_alloc(struct proc *, int pages, struct thread **);
 int	kern_thr_exit(struct thread *td);
 int	kern_thr_new(struct thread *td, struct thr_param *param);