1 /* $Id: thread-r0drv-linux.c $ */
3 * IPRT - Threads, Ring-0 Driver, Linux.
7 * Copyright (C) 2006-2016 Oracle Corporation
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.
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.
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.
28 /*********************************************************************************************************************************
30 *********************************************************************************************************************************/
31 #include "the-linux-kernel.h"
32 #include "internal/iprt.h"
33 #include <iprt/thread.h>
36 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 28) || defined(CONFIG_X86_SMAP)
37 # include <iprt/asm-amd64-x86.h>
39 #include <iprt/assert.h>
44 /*********************************************************************************************************************************
46 *********************************************************************************************************************************/
47 #ifndef CONFIG_PREEMPT
48 /** Per-cpu preemption counters. */
49 static int32_t volatile g_acPreemptDisabled
[NR_CPUS
];
53 RTDECL(RTNATIVETHREAD
) RTThreadNativeSelf(void)
55 return (RTNATIVETHREAD
)current
;
57 RT_EXPORT_SYMBOL(RTThreadNativeSelf
);
60 static int rtR0ThreadLnxSleepCommon(RTMSINTERVAL cMillies
)
62 IPRT_LINUX_SAVE_EFL_AC();
63 long cJiffies
= msecs_to_jiffies(cMillies
);
64 set_current_state(TASK_INTERRUPTIBLE
);
65 cJiffies
= schedule_timeout(cJiffies
);
66 IPRT_LINUX_RESTORE_EFL_AC();
69 return VERR_INTERRUPTED
;
73 RTDECL(int) RTThreadSleep(RTMSINTERVAL cMillies
)
75 return rtR0ThreadLnxSleepCommon(cMillies
);
77 RT_EXPORT_SYMBOL(RTThreadSleep
);
80 RTDECL(int) RTThreadSleepNoLog(RTMSINTERVAL cMillies
)
82 return rtR0ThreadLnxSleepCommon(cMillies
);
84 RT_EXPORT_SYMBOL(RTThreadSleepNoLog
);
87 RTDECL(bool) RTThreadYield(void)
89 IPRT_LINUX_SAVE_EFL_AC();
90 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 20)
93 /** @todo r=ramshankar: Can we use cond_resched() instead? */
94 set_current_state(TASK_RUNNING
);
98 IPRT_LINUX_RESTORE_EFL_AC();
101 RT_EXPORT_SYMBOL(RTThreadYield
);
104 RTDECL(bool) RTThreadPreemptIsEnabled(RTTHREAD hThread
)
106 #ifdef CONFIG_PREEMPT
107 Assert(hThread
== NIL_RTTHREAD
); RT_NOREF_PV(hThread
);
109 return preemptible();
111 return preempt_count() == 0 && !in_atomic() && !irqs_disabled();
116 Assert(hThread
== NIL_RTTHREAD
);
117 c
= g_acPreemptDisabled
[smp_processor_id()];
118 AssertMsg(c
>= 0 && c
< 32, ("%d\n", c
));
121 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 32)
125 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 28)
129 if (!ASMIntAreEnabled())
135 RT_EXPORT_SYMBOL(RTThreadPreemptIsEnabled
);
138 RTDECL(bool) RTThreadPreemptIsPending(RTTHREAD hThread
)
140 Assert(hThread
== NIL_RTTHREAD
); RT_NOREF_PV(hThread
);
141 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 4)
142 return !!test_tsk_thread_flag(current
, TIF_NEED_RESCHED
);
144 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 20)
145 return !!need_resched();
147 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 110)
148 return current
->need_resched
!= 0;
151 return need_resched
!= 0;
154 RT_EXPORT_SYMBOL(RTThreadPreemptIsPending
);
157 RTDECL(bool) RTThreadPreemptIsPendingTrusty(void)
159 /* yes, RTThreadPreemptIsPending is reliable. */
162 RT_EXPORT_SYMBOL(RTThreadPreemptIsPendingTrusty
);
165 RTDECL(bool) RTThreadPreemptIsPossible(void)
167 /** @todo r=ramshankar: What about CONFIG_PREEMPT_VOLUNTARY? That can preempt
168 * too but does so in voluntarily in explicit preemption points. */
169 #ifdef CONFIG_PREEMPT
170 return true; /* yes, kernel preemption is possible. */
172 return false; /* no kernel preemption */
175 RT_EXPORT_SYMBOL(RTThreadPreemptIsPossible
);
178 RTDECL(void) RTThreadPreemptDisable(PRTTHREADPREEMPTSTATE pState
)
180 #ifdef CONFIG_PREEMPT
182 Assert(pState
->u32Reserved
== 0);
183 pState
->u32Reserved
= 42;
184 /* This ASSUMES that CONFIG_PREEMPT_COUNT is always defined with CONFIG_PREEMPT. */
186 RT_ASSERT_PREEMPT_CPUID_DISABLE(pState
);
188 #else /* !CONFIG_PREEMPT */
191 Assert(pState
->u32Reserved
== 0);
193 /* Do our own accounting. */
194 c
= ASMAtomicIncS32(&g_acPreemptDisabled
[smp_processor_id()]);
195 AssertMsg(c
> 0 && c
< 32, ("%d\n", c
));
196 pState
->u32Reserved
= c
;
197 RT_ASSERT_PREEMPT_CPUID_DISABLE(pState
);
200 RT_EXPORT_SYMBOL(RTThreadPreemptDisable
);
203 RTDECL(void) RTThreadPreemptRestore(PRTTHREADPREEMPTSTATE pState
)
205 #ifdef CONFIG_PREEMPT
206 IPRT_LINUX_SAVE_EFL_AC(); /* paranoia */
208 Assert(pState
->u32Reserved
== 42);
209 RT_ASSERT_PREEMPT_CPUID_RESTORE(pState
);
211 IPRT_LINUX_RESTORE_EFL_ONLY_AC(); /* paranoia */
214 int32_t volatile *pc
;
216 AssertMsg(pState
->u32Reserved
> 0 && pState
->u32Reserved
< 32, ("%d\n", pState
->u32Reserved
));
217 RT_ASSERT_PREEMPT_CPUID_RESTORE(pState
);
219 /* Do our own accounting. */
220 pc
= &g_acPreemptDisabled
[smp_processor_id()];
221 AssertMsg(pState
->u32Reserved
== (uint32_t)*pc
, ("u32Reserved=%d *pc=%d \n", pState
->u32Reserved
, *pc
));
222 ASMAtomicUoWriteS32(pc
, pState
->u32Reserved
- 1);
224 pState
->u32Reserved
= 0;
226 RT_EXPORT_SYMBOL(RTThreadPreemptRestore
);
229 RTDECL(bool) RTThreadIsInInterrupt(RTTHREAD hThread
)
231 Assert(hThread
== NIL_RTTHREAD
); NOREF(hThread
);
233 return in_interrupt() != 0;
235 RT_EXPORT_SYMBOL(RTThreadIsInInterrupt
);