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
This commit is contained in:
Dmitry Chagin 2022-05-06 19:51:48 +03:00
parent 0b6bacc787
commit f04534f5c8
2 changed files with 41 additions and 12 deletions

View file

@ -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"));

View file

@ -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);