make _lwp_park return the remaining time to sleep in the "ts" argument

if it is a relative timestamp, as discussed in tech-kern.
XXX: pullup-8
This commit is contained in:
christos 2017-12-08 01:19:29 +00:00
parent 3760f161e6
commit 85bf85b701
9 changed files with 192 additions and 26 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.769 2017/12/07 19:48:12 christos Exp $
# $NetBSD: mi,v 1.770 2017/12/08 01:19:29 christos Exp $
#
# Note: don't delete entries from here - mark them as "obsolete" instead.
#
@ -2179,6 +2179,7 @@
./usr/tests/kernel/t_ptrace_waitpid tests-obsolete obsolete
./usr/tests/kernel/t_pty tests-kernel-tests compattestfile,atf
./usr/tests/kernel/t_rnd tests-kernel-tests atf,rump
./usr/tests/kernel/t_timeleft tests-kernel-tests compattestfile,atf
./usr/tests/kernel/t_trapsignal tests-kernel-tests compattestfile,atf
./usr/tests/kernel/t_sigaction tests-obsolete obsolete
./usr/tests/kernel/t_subr_prf tests-kernel-tests compattestfile,atf

View File

@ -1,4 +1,4 @@
/* $NetBSD: lwp.h,v 1.12 2014/01/31 20:44:17 christos Exp $ */
/* $NetBSD: lwp.h,v 1.13 2017/12/08 01:19:29 christos Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -54,7 +54,7 @@ void _lwp_setprivate(void *);
int _lwp_kill(lwpid_t, int);
int _lwp_detach(lwpid_t);
#ifndef __LIBC12_SOURCE__
int _lwp_park(clockid_t, int, const struct timespec *, lwpid_t,
int _lwp_park(clockid_t, int, struct timespec *, lwpid_t,
const void *, const void *) __RENAME(___lwp_park60);
#endif
int _lwp_unpark(lwpid_t, const void *);

View File

@ -1,6 +1,6 @@
.\" $NetBSD: _lwp_park.2,v 1.9 2014/01/31 21:11:05 wiz Exp $
.\" $NetBSD: _lwp_park.2,v 1.10 2017/12/08 01:19:29 christos Exp $
.\"
.\" Copyright (c) 2003, 2007 The NetBSD Foundation, Inc.
.\" Copyright (c) 2003, 2007, 2017 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
@ -27,7 +27,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd March 28, 2013
.Dd December 7, 2017
.Dt _LWP_PARK 2
.Os
.Sh NAME
@ -38,7 +38,7 @@
.Sh SYNOPSIS
.In lwp.h
.Ft int
.Fn _lwp_park "clockid_t clock_id" "int flags" "const struct timespec *ts" "lwpid_t unpark" "const void *hint" "const void *unparkhint"
.Fn _lwp_park "clockid_t clock_id" "int flags" "struct timespec *ts" "lwpid_t unpark" "const void *hint" "const void *unparkhint"
.Sh DESCRIPTION
.Fn _lwp_park
can be used to synchronize access to resources among multiple light-weight
@ -58,14 +58,13 @@ time can be an relative interval to wait if the
.Ar flags
argument does not contain
.Dv TIMER_ABSTIME
or it can be an absolute time compared to
or it can be an absolute time.
The
.Fa clock_id
argument contains the clock to be used; it can be:
.Dv CLOCK_REALTIME
or
.Dv CLOCK_MONOTONIC
depending on the value
of the
.Ar clock_id
argument.
.Dv CLOCK_MONOTONIC .
.It
The LWP receives a directed signal posted using
.Fn _lwp_kill ,
@ -82,6 +81,13 @@ or
.Fn _lwp_unpark_all .
.El
.Pp
If the
.Fa ts
argument contains a relative time interval, it will be modified to contain
the remaining time to sleep when
.Fn _lwp_park
returns.
.Pp
The preferred method to awaken an LWP sleeping as a result of a call
to
.Fn _lwp_park

View File

@ -1,4 +1,4 @@
/* $NetBSD: subr_time.c,v 1.19 2017/01/05 23:29:14 pgoyette Exp $ */
/* $NetBSD: subr_time.c,v 1.20 2017/12/08 01:19:29 christos Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: subr_time.c,v 1.19 2017/01/05 23:29:14 pgoyette Exp $");
__KERNEL_RCSID(0, "$NetBSD: subr_time.c,v 1.20 2017/12/08 01:19:29 christos Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@ -227,6 +227,17 @@ gettimeleft(struct timespec *ts, struct timespec *sleepts)
return tstohz(ts);
}
void
clock_timeleft(clockid_t clockid, struct timespec *ts, struct timespec *sleepts)
{
struct timespec sleptts;
clock_gettime1(clockid, &sleptts);
timespecadd(ts, sleepts, ts);
timespecsub(ts, &sleptts, ts);
*sleepts = sleptts;
}
static void
ticks2ts(uint64_t ticks, struct timespec *ts)
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: sys_lwp.c,v 1.61 2017/06/01 02:45:13 chs Exp $ */
/* $NetBSD: sys_lwp.c,v 1.62 2017/12/08 01:19:29 christos Exp $ */
/*-
* Copyright (c) 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: sys_lwp.c,v 1.61 2017/06/01 02:45:13 chs Exp $");
__KERNEL_RCSID(0, "$NetBSD: sys_lwp.c,v 1.62 2017/12/08 01:19:29 christos Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -542,10 +542,13 @@ lwp_park(clockid_t clock_id, int flags, struct timespec *ts, const void *hint)
kmutex_t *mp;
wchan_t wchan;
int timo, error;
struct timespec start;
lwp_t *l;
bool timeremain = !(flags & TIMER_ABSTIME) && ts;
if (ts != NULL) {
if ((error = ts2timo(clock_id, flags, ts, &timo, NULL)) != 0)
if ((error = ts2timo(clock_id, flags, ts, &timo,
timeremain ? &start : NULL)) != 0)
return error;
KASSERT(timo != 0);
} else {
@ -575,12 +578,15 @@ lwp_park(clockid_t clock_id, int flags, struct timespec *ts, const void *hint)
switch (error) {
case EWOULDBLOCK:
error = ETIMEDOUT;
if (timeremain)
memset(ts, 0, sizeof(*ts));
break;
case ERESTART:
error = EINTR;
break;
/*FALLTHROUGH*/
default:
/* nothing */
if (timeremain)
clock_timeleft(clock_id, ts, &start);
break;
}
return error;
@ -598,7 +604,7 @@ sys____lwp_park60(struct lwp *l, const struct sys____lwp_park60_args *uap,
/* {
syscallarg(clockid_t) clock_id;
syscallarg(int) flags;
syscallarg(const struct timespec *) ts;
syscallarg(struct timespec *) ts;
syscallarg(lwpid_t) unpark;
syscallarg(const void *) hint;
syscallarg(const void *) unparkhint;
@ -621,8 +627,11 @@ sys____lwp_park60(struct lwp *l, const struct sys____lwp_park60_args *uap,
return error;
}
return lwp_park(SCARG(uap, clock_id), SCARG(uap, flags), tsp,
error = lwp_park(SCARG(uap, clock_id), SCARG(uap, flags), tsp,
SCARG(uap, hint));
if (SCARG(uap, ts) != NULL && (SCARG(uap, flags) & TIMER_ABSTIME) == 0)
(void)copyout(tsp, SCARG(uap, ts), sizeof(*tsp));
return error;
}
int

View File

@ -1,4 +1,4 @@
$NetBSD: syscalls.master,v 1.286 2016/11/02 00:11:59 pgoyette Exp $
$NetBSD: syscalls.master,v 1.287 2017/12/08 01:19:29 christos Exp $
; @(#)syscalls.master 8.2 (Berkeley) 1/13/94
@ -975,7 +975,7 @@
int flags, const struct timespec *rqtp, \
struct timespec *rmtp); }
478 STD { int|sys|60|_lwp_park(clockid_t clock_id, int flags, \
const struct timespec *ts, lwpid_t unpark, \
struct timespec *ts, lwpid_t unpark, \
const void *hint, const void *unparkhint); }
479 NOERR RUMP { int|sys||posix_fallocate(int fd, int PAD, off_t pos, \
off_t len); }

View File

@ -1,4 +1,4 @@
/* $NetBSD: timevar.h,v 1.36 2016/03/08 05:02:55 christos Exp $ */
/* $NetBSD: timevar.h,v 1.37 2017/12/08 01:19:29 christos Exp $ */
/*
* Copyright (c) 2005, 2008 The NetBSD Foundation.
@ -151,6 +151,7 @@ void adjtime1(const struct timeval *, struct timeval *, struct proc *);
int clock_getres1(clockid_t, struct timespec *);
int clock_gettime1(clockid_t, struct timespec *);
int clock_settime1(struct proc *, clockid_t, const struct timespec *, bool);
void clock_timeleft(clockid_t, struct timespec *, struct timespec *);
int dogetitimer(struct proc *, int, struct itimerval *);
int dosetitimer(struct proc *, int, struct itimerval *);
int dotimer_gettime(int, struct proc *, struct itimerspec *);

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.48 2017/12/07 19:46:40 christos Exp $
# $NetBSD: Makefile,v 1.49 2017/12/08 01:19:29 christos Exp $
NOMAN= # defined
@ -15,6 +15,7 @@ TESTS_C+= t_sysv
TESTS_C+= t_subr_prf
TESTS_C+= t_kauth_pr_47598
TESTS_C+= t_sysctl
TESTS_C+= t_timeleft
TESTS_SH= t_umount
TESTS_SH+= t_umountstress
@ -41,6 +42,7 @@ LDADD.t_extattrctl+= -lrump -lpthread
LDADD.t_filedesc+= ${LDADD.t_rnd}
LDADD.t_rnd+= -lrumpvfs -lrumpdev_rnd -lrumpdev -lrump -lrumpuser
LDADD.t_rnd+= -lrump -lpthread
LDADD.t_timeleft+= -lpthread
.endif

136
tests/kernel/t_timeleft.c Normal file
View File

@ -0,0 +1,136 @@
/* $NetBSD: t_timeleft.c,v 1.1 2017/12/08 01:19:29 christos Exp $ */
/*-
* Copyright (c) 2017 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__COPYRIGHT("@(#) Copyright (c) 2008\
The NetBSD Foundation, inc. All rights reserved.");
__RCSID("$NetBSD: t_timeleft.c,v 1.1 2017/12/08 01:19:29 christos Exp $");
#include <sys/types.h>
#include <sys/select.h>
#include <atf-c.h>
#include <time.h>
#include <errno.h>
#include <lwp.h>
#include <signal.h>
#include <pthread.h>
#include <stdio.h>
#include <sched.h>
#include <unistd.h>
static void
sighandler(int signo __unused)
{
}
struct info {
void (*fun)(struct timespec *);
struct timespec ts;
};
static void
timeleft__lwp_park(struct timespec *ts)
{
ATF_REQUIRE_ERRNO(EINTR, _lwp_park(CLOCK_MONOTONIC, TIMER_RELTIME,
ts, 0, ts, NULL) == -1);
}
#if 0
static void
timeleft_pselect(struct timespec *ts)
{
ATF_REQUIRE_ERRNO(EINTR, pselect(1, NULL, NULL, NULL, ts, NULL));
}
#endif
static void *
runner(void *arg)
{
struct info *i = arg;
(*i->fun)(&i->ts);
return NULL;
}
static void
tester(void (*fun)(struct timespec *))
{
const struct timespec ts = { 5, 0 };
const struct timespec sts = { 0, 1000000 };
struct info i = { fun, ts };
pthread_t thr;
ATF_REQUIRE(signal(SIGINT, sighandler) == 0);
ATF_REQUIRE(pthread_create(&thr, NULL, runner, &i) == 0);
nanosleep(&sts, NULL);
pthread_kill(thr, SIGINT);
printf("Orig time %ju.%lu\n", (intmax_t)ts.tv_sec, ts.tv_nsec);
printf("Time left %ju.%lu\n", (intmax_t)i.ts.tv_sec, i.ts.tv_nsec);
ATF_REQUIRE(timespeccmp(&i.ts, &ts, <));
}
ATF_TC(timeleft__lwp_park);
ATF_TC_HEAD(timeleft__lwp_park, tc)
{
atf_tc_set_md_var(tc, "descr", "Checks that _lwp_park(2) returns "
"the time left to sleep after interrupted");
}
ATF_TC_BODY(timeleft__lwp_park, tc)
{
tester(timeleft__lwp_park);
}
#if 0
ATF_TC(timeleft_pselect);
ATF_TC_HEAD(timeleft_pselect, tc)
{
atf_tc_set_md_var(tc, "descr", "Checks that pselect(2) returns "
"the time left to sleep after interrupted");
}
ATF_TC_BODY(timeleft_pselect, tc)
{
tester(timeleft_pselect);
}
#endif
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, timeleft__lwp_park);
#if 0
ATF_TP_ADD_TC(tp, timeleft_pselect);
#endif
return atf_no_error();
}