VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/linux/thread-r0drv-linux.c@ 96763

Last change on this file since 96763 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 8.5 KB
Line 
1/* $Id: thread-r0drv-linux.c 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * IPRT - Threads, Ring-0 Driver, Linux.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include "the-linux-kernel.h"
42#include "internal/iprt.h"
43#include <iprt/thread.h>
44
45#include <iprt/asm.h>
46#if RTLNX_VER_MAX(2,5,28) || defined(CONFIG_X86_SMAP)
47# include <iprt/asm-amd64-x86.h>
48#endif
49#include <iprt/assert.h>
50#include <iprt/errcore.h>
51#include <iprt/mp.h>
52
53
54/*********************************************************************************************************************************
55* Defined Constants And Macros *
56*********************************************************************************************************************************/
57#if defined(CONFIG_PREEMPT_COUNT) /* since 3.1 */ \
58 || defined(CONFIG_PREEMPTION) /* since 5.3 */ \
59 || defined(CONFIG_PREEMPT) /* since 2.6.13 - preemption model choice; before that arch specific choice back to 2.5.45. */
60# define IPRT_LNX_HAVE_PREEMPTION
61#endif
62
63
64/*********************************************************************************************************************************
65* Global Variables *
66*********************************************************************************************************************************/
67#ifndef IPRT_LNX_HAVE_PREEMPTION
68/** Per-cpu preemption counters. */
69static int32_t volatile g_acPreemptDisabled[NR_CPUS];
70#endif
71
72
73RTDECL(RTNATIVETHREAD) RTThreadNativeSelf(void)
74{
75 return (RTNATIVETHREAD)current;
76}
77RT_EXPORT_SYMBOL(RTThreadNativeSelf);
78
79
80static int rtR0ThreadLnxSleepCommon(RTMSINTERVAL cMillies)
81{
82 IPRT_LINUX_SAVE_EFL_AC();
83 long cJiffies = msecs_to_jiffies(cMillies);
84 set_current_state(TASK_INTERRUPTIBLE);
85 cJiffies = schedule_timeout(cJiffies);
86 IPRT_LINUX_RESTORE_EFL_AC();
87 if (!cJiffies)
88 return VINF_SUCCESS;
89 return VERR_INTERRUPTED;
90}
91
92
93RTDECL(int) RTThreadSleep(RTMSINTERVAL cMillies)
94{
95 return rtR0ThreadLnxSleepCommon(cMillies);
96}
97RT_EXPORT_SYMBOL(RTThreadSleep);
98
99
100RTDECL(int) RTThreadSleepNoLog(RTMSINTERVAL cMillies)
101{
102 return rtR0ThreadLnxSleepCommon(cMillies);
103}
104RT_EXPORT_SYMBOL(RTThreadSleepNoLog);
105
106
107RTDECL(bool) RTThreadYield(void)
108{
109 IPRT_LINUX_SAVE_EFL_AC();
110#if RTLNX_VER_MIN(2,4,20)
111 yield();
112#else
113 /** @todo r=ramshankar: Can we use cond_resched() instead? */
114 set_current_state(TASK_RUNNING);
115 sys_sched_yield();
116 schedule();
117#endif
118 IPRT_LINUX_RESTORE_EFL_AC();
119 return true;
120}
121RT_EXPORT_SYMBOL(RTThreadYield);
122
123
124RTDECL(bool) RTThreadPreemptIsEnabled(RTTHREAD hThread)
125{
126#ifdef IPRT_LNX_HAVE_PREEMPTION
127 Assert(hThread == NIL_RTTHREAD); RT_NOREF_PV(hThread);
128# ifdef preemptible
129 return preemptible();
130# else
131 return preempt_count() == 0 && !in_atomic() && !irqs_disabled();
132# endif
133#else
134 int32_t c;
135
136 Assert(hThread == NIL_RTTHREAD);
137 c = g_acPreemptDisabled[smp_processor_id()];
138 AssertMsg(c >= 0 && c < 32, ("%d\n", c));
139 if (c != 0)
140 return false;
141# if RTLNX_VER_MIN(2,5,32)
142 if (in_atomic())
143 return false;
144# endif
145# if RTLNX_VER_MIN(2,5,28)
146 if (irqs_disabled())
147 return false;
148# else
149 if (!ASMIntAreEnabled())
150 return false;
151# endif
152 return true;
153#endif
154}
155RT_EXPORT_SYMBOL(RTThreadPreemptIsEnabled);
156
157
158RTDECL(bool) RTThreadPreemptIsPending(RTTHREAD hThread)
159{
160 Assert(hThread == NIL_RTTHREAD); RT_NOREF_PV(hThread);
161#if RTLNX_VER_MIN(2,5,4)
162 return !!test_tsk_thread_flag(current, TIF_NEED_RESCHED);
163
164#elif RTLNX_VER_MIN(2,4,20)
165 return !!need_resched();
166
167#elif RTLNX_VER_MIN(2,1,110)
168 return current->need_resched != 0;
169
170#else
171 return need_resched != 0;
172#endif
173}
174RT_EXPORT_SYMBOL(RTThreadPreemptIsPending);
175
176
177RTDECL(bool) RTThreadPreemptIsPendingTrusty(void)
178{
179 /* yes, RTThreadPreemptIsPending is reliable. */
180 return true;
181}
182RT_EXPORT_SYMBOL(RTThreadPreemptIsPendingTrusty);
183
184
185RTDECL(bool) RTThreadPreemptIsPossible(void)
186{
187#ifdef IPRT_LNX_HAVE_PREEMPTION
188 return true; /* Yes, kernel preemption is possible. */
189#else
190 return false; /* No kernel preemption (or just CONFIG_PREEMPT_VOLUNTARY). */
191#endif
192}
193RT_EXPORT_SYMBOL(RTThreadPreemptIsPossible);
194
195
196RTDECL(void) RTThreadPreemptDisable(PRTTHREADPREEMPTSTATE pState)
197{
198#ifdef IPRT_LNX_HAVE_PREEMPTION
199 AssertPtr(pState);
200 Assert(pState->u32Reserved == 0);
201 pState->u32Reserved = 42;
202 preempt_disable();
203 RT_ASSERT_PREEMPT_CPUID_DISABLE(pState);
204
205#else /* !IPRT_LNX_HAVE_PREEMPTION */
206 int32_t c;
207 AssertPtr(pState);
208 Assert(pState->u32Reserved == 0);
209
210 /* Do our own accounting. */
211 c = ASMAtomicIncS32(&g_acPreemptDisabled[smp_processor_id()]);
212 AssertMsg(c > 0 && c < 32, ("%d\n", c));
213 pState->u32Reserved = c;
214 RT_ASSERT_PREEMPT_CPUID_DISABLE(pState);
215#endif
216}
217RT_EXPORT_SYMBOL(RTThreadPreemptDisable);
218
219
220RTDECL(void) RTThreadPreemptRestore(PRTTHREADPREEMPTSTATE pState)
221{
222#ifdef IPRT_LNX_HAVE_PREEMPTION
223 IPRT_LINUX_SAVE_EFL_AC(); /* paranoia */
224 AssertPtr(pState);
225 Assert(pState->u32Reserved == 42);
226 RT_ASSERT_PREEMPT_CPUID_RESTORE(pState);
227 preempt_enable();
228 IPRT_LINUX_RESTORE_EFL_ONLY_AC(); /* paranoia */
229
230#else
231 int32_t volatile *pc;
232 AssertPtr(pState);
233 AssertMsg(pState->u32Reserved > 0 && pState->u32Reserved < 32, ("%d\n", pState->u32Reserved));
234 RT_ASSERT_PREEMPT_CPUID_RESTORE(pState);
235
236 /* Do our own accounting. */
237 pc = &g_acPreemptDisabled[smp_processor_id()];
238 AssertMsg(pState->u32Reserved == (uint32_t)*pc, ("u32Reserved=%d *pc=%d \n", pState->u32Reserved, *pc));
239 ASMAtomicUoWriteS32(pc, pState->u32Reserved - 1);
240#endif
241 pState->u32Reserved = 0;
242}
243RT_EXPORT_SYMBOL(RTThreadPreemptRestore);
244
245
246RTDECL(bool) RTThreadIsInInterrupt(RTTHREAD hThread)
247{
248 Assert(hThread == NIL_RTTHREAD); NOREF(hThread);
249
250 return in_interrupt() != 0;
251}
252RT_EXPORT_SYMBOL(RTThreadIsInInterrupt);
253
254
255RTDECL(int) RTThreadQueryTerminationStatus(RTTHREAD hThread)
256{
257 struct task_struct *pTask = current;
258 AssertReturn(hThread == NIL_RTTHREAD, VERR_NOT_SUPPORTED);
259
260 /* Check out pending signals. ASSUMES we can get away w/o locking
261 anything because we're only reading the data. */
262 if (sigismember(&pTask->pending.signal, SIGKILL))
263 return VINF_THREAD_IS_TERMINATING;
264
265#if RTLNX_VER_MIN(2,5,34)
266 /* Check the pending signals shared with other threads in
267 the same process/group. ASSUME since we're alive that
268 the signal_struct won't be freed while we're looking
269 at it here... */
270 {
271# if RTLNX_VER_MIN(2,5,60)
272 struct signal_struct *pSignal = current->signal;
273# else
274 struct signal_struct *pSignal = current->sig;
275# endif
276 if ( pSignal
277 && sigismember(&pSignal->shared_pending.signal, SIGKILL))
278 return VINF_THREAD_IS_TERMINATING;
279 }
280#endif
281
282 return VINF_SUCCESS;
283}
284RT_EXPORT_SYMBOL(RTThreadQueryTerminationStatus);
285
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette