xref: /freebsd/lib/libthr/thread/thr_kern.c (revision e40db2c46ecb75fdaf399d0a439ae31e501c097c)
1 /*
2  * Copyright (c) 2003 Jeffrey Roberson <jeff@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 
29 #include <sys/cdefs.h>
30 #include <sys/types.h>
31 #include <sys/signalvar.h>
32 #include <sys/time.h>
33 #include <sys/timespec.h>
34 #include <pthread.h>
35 #include <signal.h>
36 #include <errno.h>
37 
38 #include "thr_private.h"
39 
40 /* XXX Why can't I get this from time.h? :-( */
41 #define timespecsub(vvp, uvp)                                           \
42         do {                                                            \
43                 (vvp)->tv_sec -= (uvp)->tv_sec;                         \
44                 (vvp)->tv_nsec -= (uvp)->tv_nsec;                       \
45                 if ((vvp)->tv_nsec < 0) {                               \
46                         (vvp)->tv_sec--;                                \
47                         (vvp)->tv_nsec += 1000000000;                   \
48                 }                                                       \
49         } while (0)
50 
51 static sigset_t restore;
52 
53 void
54 GIANT_LOCK(pthread_t pthread)
55 {
56 	sigset_t set;
57 	sigset_t sav;
58 	int error;
59 
60 	/*
61 	 * Block all signals.
62 	 */
63 	SIGFILLSET(set);
64 
65 	/*
66 	 * We can not use the global 'restore' set until after we have
67 	 * acquired the giant lock.
68 	 */
69 #if 0
70 	error = __sys_sigprocmask(SIG_SETMASK, &set, &sav);
71 	if (error) {
72 		_thread_printf(0, "GIANT_LOCK: sig err %d\n", errno);
73 		abort();
74 	}
75 #endif
76 
77 	error = umtx_lock(&_giant_mutex, pthread->thr_id);
78 	if (error) {
79 		_thread_printf(0, "GIANT_LOCK: %d\n", errno);
80 		abort();
81 	}
82 
83 	restore = sav;
84 }
85 
86 void
87 GIANT_UNLOCK(pthread_t pthread)
88 {
89 	sigset_t set;
90 	int error;
91 
92 	/*
93 	 * restore is protected by giant.  We could restore our signal state
94 	 * incorrectly if someone else set restore between unlocking giant
95 	 * and restoring the signal mask.  To avoid this we cache a copy prior
96 	 * to the unlock.
97 	 */
98 	set = restore;
99 
100 	error = umtx_unlock(&_giant_mutex, pthread->thr_id);
101 	if (error) {
102 		_thread_printf(0, "GIANT_UNLOCK: %d\n", errno);
103 		abort();
104 	}
105 
106 #if 0
107 	/*
108 	 * Restore signals.
109 	 */
110 	error = __sys_sigprocmask(SIG_SETMASK, &set, NULL);
111 	if (error) {
112 		_thread_printf(0, "GIANT_UNLOCK: sig err %d\n", errno);
113 		abort();
114 	}
115 #endif
116 }
117 
118 int
119 _thread_suspend(pthread_t pthread, struct timespec *abstime)
120 {
121 	struct timespec remaining;
122 	struct timespec *ts;
123 	siginfo_t info;
124 	sigset_t set;
125 	int error;
126 
127 	/*
128 	 * Catch SIGTHR.
129 	 */
130 	SIGFILLSET(set);
131 	SIGDELSET(set, SIGTHR);
132 
133 	/*
134 	 * Compute the remainder of the run time.
135 	 */
136 	if (abstime) {
137 		struct timespec now;
138 		struct timeval tv;
139 
140 		GET_CURRENT_TOD(tv);
141 		TIMEVAL_TO_TIMESPEC(&tv, &now);
142 
143 		remaining = *abstime;
144 		timespecsub(&remaining, &now);
145 		ts = &remaining;
146 	} else
147 		ts = NULL;
148 
149 	error = sigtimedwait(&set, &info, ts);
150 	if (error == -1)
151 		error = errno;
152 
153 	return (error);
154 }
155