|
1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32\nkernsmp\x86\ncsched.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 // NThreadBase member data |
|
19 #define __INCLUDE_NTHREADBASE_DEFINES__ |
|
20 |
|
21 #include <x86.h> |
|
22 #include <apic.h> |
|
23 |
|
24 |
|
25 // Called by a thread which has been forced to exit |
|
26 // Kernel locked on entry |
|
27 extern "C" void __fastcall do_forced_exit(NThreadBase* aT) |
|
28 { |
|
29 __NK_ASSERT_ALWAYS(aT->iFastMutexDefer != 1); |
|
30 aT->iFastMutexDefer = 0; |
|
31 aT->Exit(); |
|
32 } |
|
33 |
|
34 extern "C" NThreadBase* __fastcall select_next_thread(TSubScheduler* aS) |
|
35 { |
|
36 return aS->SelectNextThread(); |
|
37 } |
|
38 |
|
39 extern "C" void __fastcall queue_dfcs(TSubScheduler* aS) |
|
40 { |
|
41 aS->QueueDfcs(); |
|
42 } |
|
43 |
|
44 extern "C" void NewThreadTrace(NThread* a) |
|
45 { |
|
46 __ACQUIRE_BTRACE_LOCK(); |
|
47 BTraceData.iHandler(BTRACE_HEADER_C(4,BTrace::ECpuUsage,BTrace::ENewThreadContext),0,(TUint32)a,0,0,0,0,0); |
|
48 __RELEASE_BTRACE_LOCK(); |
|
49 } |
|
50 |
|
51 extern "C" void __fastcall send_ipi(TUint32); |
|
52 extern "C" void __fastcall do_send_resched_ipis(TUint32); |
|
53 |
|
54 extern "C" void send_resched_ipi(TInt aCpu) |
|
55 { |
|
56 TSubScheduler& ss = TheSubSchedulers[aCpu]; |
|
57 __KTRACE_OPT(KSCHED2,DEBUGPRINT("@%d",aCpu)); |
|
58 send_ipi((TUint32)ss.i_APICID); |
|
59 } |
|
60 |
|
61 extern "C" void send_resched_ipis(TUint32 aMask) |
|
62 { |
|
63 __KTRACE_OPT(KSCHED2,DEBUGPRINT("@%02x",aMask)); |
|
64 #ifdef __USE_LOGICAL_DEST_MODE__ |
|
65 do_send_resched_ipis(aMask); |
|
66 #else |
|
67 TInt i=0; |
|
68 while (aMask) |
|
69 { |
|
70 if (aMask&1) |
|
71 send_resched_ipi(i); |
|
72 aMask>>=1; |
|
73 ++i; |
|
74 } |
|
75 #endif |
|
76 } |
|
77 |
|
78 extern "C" void send_resched_ipi_and_wait(TInt aCpu) |
|
79 { |
|
80 TSubScheduler& ss = TheSubSchedulers[aCpu]; |
|
81 __KTRACE_OPT(KSCHED2,DEBUGPRINT("@@%d",aCpu)); |
|
82 volatile TUint32& irqc = (volatile TUint32&)ss.i_IrqCount; |
|
83 volatile TInt& irqn = (volatile TInt&)ss.i_IrqNestCount; |
|
84 TUint32 irqc0 = irqc; |
|
85 mb(); |
|
86 send_ipi((TUint32)ss.i_APICID); |
|
87 mb(); |
|
88 while (!ss.iRescheduleNeededFlag || (irqn<0 && irqc==irqc0)) |
|
89 { |
|
90 __chill(); |
|
91 } |
|
92 mb(); // guaranteed to observe final thread state after this |
|
93 } |
|
94 |
|
95 void TSubScheduler::SaveTimesliceTimer(NThreadBase* aT) |
|
96 { |
|
97 if (aT->iTime>0 && !aT->i_NThread_Initial) |
|
98 { |
|
99 TUint32 remain32 = read_apic_reg(CURRCNT); |
|
100 TUint64 x(remain32); |
|
101 x *= TUint32(i_TimerMultI); |
|
102 x += 0x00800000u; |
|
103 x >>= 24; |
|
104 aT->iTime = (TInt)x; |
|
105 } |
|
106 write_apic_reg(INITCNT, 0); |
|
107 } |
|
108 |
|
109 |
|
110 /* Update aOld's execution time and set up the timer for aNew |
|
111 Update this CPU's timestamp value |
|
112 |
|
113 if (!aOld) aOld=iInitialThread |
|
114 if (!aNew) aNew=iInitialThread |
|
115 if new thread has a timeslice, start the timeslice timer |
|
116 update the last reschedule time |
|
117 update the run time for the old thread |
|
118 update the reschedule count for the new thread and the current CPU |
|
119 */ |
|
120 void TSubScheduler::UpdateThreadTimes(NThreadBase* aOld, NThreadBase* aNew) |
|
121 { |
|
122 if (!aOld) |
|
123 aOld = iInitialThread; |
|
124 if (!aNew) |
|
125 aNew = iInitialThread; |
|
126 if (aNew->iTime>0) |
|
127 { |
|
128 TUint32 remain32 = (TUint32)aNew->iTime; |
|
129 TUint64 x(remain32); |
|
130 x *= TUint32(i_TimerMultF); |
|
131 x += 0x80000000u; |
|
132 x >>= 32; |
|
133 write_apic_reg(LVTTMR, TIMESLICE_VECTOR); |
|
134 write_apic_reg(INITCNT, (TUint32)x); |
|
135 } |
|
136 if (aNew!=aOld) |
|
137 { |
|
138 TUint64 now = NKern::Timestamp(); |
|
139 aOld->iTotalCpuTime64 += (now - iLastTimestamp64); |
|
140 iLastTimestamp64 = now; |
|
141 ++iReschedCount64; |
|
142 ++aNew->iRunCount64; |
|
143 } |
|
144 } |
|
145 |
|
146 |