VirtualBox

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

Last change on this file since 92460 was 92460, checked in by vboxsync, 3 years ago

IPRT/thread-r0drv-linux.c: Must test more config options for propertly detection kernel preemption. bugref:10145

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