The branch main has been updated by dchagin:

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

commit f04534f5c84e58009efbb7f378803da3f33585b9
Author:     Dmitry Chagin <[email protected]>
AuthorDate: 2022-05-06 16:51:48 +0000
Commit:     Dmitry Chagin <[email protected]>
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);

Reply via email to