|
1 // Copyright (c) 2002-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 // e32test\debug\d_traceredirect.cpp |
|
15 // Trace redirection LDD |
|
16 // This device driver captures RDebug::Prints from user side code using the |
|
17 // debug event handler. |
|
18 // The text can be retrieved with the RTraceRedirect::NextTrace() function |
|
19 // TODO: Modify this LDD to use asynchronous retrieval. |
|
20 // |
|
21 // |
|
22 |
|
23 #include <kernel/kernel.h> |
|
24 #include <kernel/kern_priv.h> |
|
25 #include "d_traceredirect.h" |
|
26 |
|
27 _LIT(KLddName,"D_TRACEREDIRECT"); |
|
28 |
|
29 const TInt KMajorVersionNumber = 0; |
|
30 const TInt KMinorVersionNumber = 1; |
|
31 const TInt KBuildVersionNumber = 1; |
|
32 |
|
33 const TInt KMaxTraceEventLength=100; |
|
34 const TInt KTraceBufferSize=256; |
|
35 const TInt KTraceBufferSizeMask=0xff; |
|
36 |
|
37 |
|
38 class TTraceEvent |
|
39 { |
|
40 public: |
|
41 TInt iLength; |
|
42 TUint16 iText[KMaxTraceEventLength]; |
|
43 }; |
|
44 |
|
45 class DTraceRedirect; |
|
46 |
|
47 class DTraceEventHandler : public DKernelEventHandler |
|
48 { |
|
49 public: |
|
50 DTraceEventHandler() |
|
51 : DKernelEventHandler(HandleEvent, this) {} |
|
52 TInt Create(DLogicalDevice* aDevice); |
|
53 ~DTraceEventHandler(); |
|
54 TInt GetNextEvent(TAny *outdes); |
|
55 private: |
|
56 static TUint HandleEvent(TKernelEvent aEvent, TAny* a1, TAny* a2, TAny* aThis); |
|
57 void HandleUserTrace(TText* aStr, TInt aLen); |
|
58 public: |
|
59 DTraceRedirect *iChannel; |
|
60 TTraceEvent *iTraceBuffer; |
|
61 TInt iFront; |
|
62 TInt iBack; |
|
63 DMutex* iLock; // serialise calls to handler |
|
64 DLogicalDevice* iDevice; // open reference to LDD for avoiding lifetime issues |
|
65 }; |
|
66 |
|
67 class DTraceRedirectFactory : public DLogicalDevice |
|
68 { |
|
69 public: |
|
70 DTraceRedirectFactory(); |
|
71 virtual TInt Install(); |
|
72 virtual void GetCaps(TDes8& aDes) const; |
|
73 virtual TInt Create(DLogicalChannelBase*& aChannel); |
|
74 }; |
|
75 |
|
76 class DTraceRedirect : public DLogicalChannelBase |
|
77 { |
|
78 public: |
|
79 virtual ~DTraceRedirect(); |
|
80 protected: |
|
81 virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); |
|
82 virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2); |
|
83 TInt NextTrace(TAny *outdes); |
|
84 public: |
|
85 DTraceEventHandler *iEventHandler; |
|
86 }; |
|
87 |
|
88 |
|
89 |
|
90 DECLARE_STANDARD_LDD() |
|
91 { |
|
92 return new DTraceRedirectFactory; |
|
93 } |
|
94 |
|
95 // |
|
96 // DTraceRedirectFactory |
|
97 // |
|
98 |
|
99 DTraceRedirectFactory::DTraceRedirectFactory() |
|
100 { |
|
101 iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber); |
|
102 } |
|
103 |
|
104 TInt DTraceRedirectFactory::Create(DLogicalChannelBase*& aChannel) |
|
105 /** |
|
106 Create a new DSchedhookTest on this logical device |
|
107 */ |
|
108 { |
|
109 aChannel=new DTraceRedirect; |
|
110 return aChannel ? KErrNone : KErrNoMemory; |
|
111 } |
|
112 |
|
113 TInt DTraceRedirectFactory::Install() |
|
114 /** |
|
115 Install the LDD - overriding pure virtual |
|
116 */ |
|
117 { |
|
118 return SetName(&KLddName); |
|
119 } |
|
120 |
|
121 void DTraceRedirectFactory::GetCaps(TDes8& aDes) const |
|
122 /** |
|
123 Get capabilities - overriding pure virtual |
|
124 */ |
|
125 { |
|
126 TCapsTestV01 b; |
|
127 b.iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber); |
|
128 Kern::InfoCopy(aDes,(TUint8*)&b,sizeof(b)); |
|
129 } |
|
130 |
|
131 |
|
132 // |
|
133 // DSchedhookTest |
|
134 // |
|
135 |
|
136 TInt DTraceRedirect::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer) |
|
137 /** |
|
138 Create channel |
|
139 */ |
|
140 { |
|
141 if (!Kern::QueryVersionSupported(TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber),aVer)) |
|
142 return KErrNotSupported; |
|
143 |
|
144 iEventHandler=new DTraceEventHandler; |
|
145 if (iEventHandler == NULL) |
|
146 return KErrNoMemory; |
|
147 return iEventHandler->Create(iDevice); |
|
148 } |
|
149 |
|
150 DTraceRedirect::~DTraceRedirect() |
|
151 { |
|
152 iEventHandler->Close(); |
|
153 } |
|
154 |
|
155 TInt DTraceEventHandler::Create(DLogicalDevice* aDevice) |
|
156 { |
|
157 TInt r; |
|
158 r = aDevice->Open(); |
|
159 if (r != KErrNone) |
|
160 return r; |
|
161 iDevice = aDevice; |
|
162 iFront=0; |
|
163 iBack=0; |
|
164 iTraceBuffer=new TTraceEvent[KTraceBufferSize]; |
|
165 if (iTraceBuffer == NULL) |
|
166 return KErrNoMemory; |
|
167 _LIT(KDataMutexName, "EventHandlerMutex"); |
|
168 r = Kern::MutexCreate(iLock, KDataMutexName, KMutexOrdDebug); |
|
169 if (r != KErrNone) |
|
170 return r; |
|
171 return Add(); |
|
172 } |
|
173 |
|
174 DTraceEventHandler::~DTraceEventHandler() |
|
175 { |
|
176 if (iLock) |
|
177 iLock->Close(NULL); |
|
178 delete [] iTraceBuffer; |
|
179 if (iDevice) |
|
180 iDevice->Close(NULL); |
|
181 } |
|
182 |
|
183 TUint DTraceEventHandler::HandleEvent(TKernelEvent aEvent, TAny* a1, TAny* a2, TAny* aThis) |
|
184 { |
|
185 if (aEvent==EEventUserTrace) |
|
186 { |
|
187 ((DTraceEventHandler*)aThis)->HandleUserTrace((TText*)a1, (TInt)a2); |
|
188 return ETraceHandled; |
|
189 } |
|
190 return ERunNext; |
|
191 } |
|
192 |
|
193 // called in CS |
|
194 void DTraceEventHandler::HandleUserTrace(TText* aStr, TInt aLen) |
|
195 { |
|
196 Kern::MutexWait(*iLock); |
|
197 TInt frontplus1=(iFront+1)&KTraceBufferSizeMask; |
|
198 if (frontplus1!=iBack) // check overflow |
|
199 { |
|
200 TTraceEvent *e=&iTraceBuffer[iFront]; |
|
201 XTRAPD(r, XT_DEFAULT, kumemget(e->iText, aStr, aLen*2)); |
|
202 if (r == KErrNone) |
|
203 e->iLength=aLen; |
|
204 else |
|
205 e->iLength = -1; // an error will be reported in GetNextEvent() |
|
206 iFront=frontplus1; |
|
207 } |
|
208 Kern::MutexSignal(*iLock); |
|
209 } |
|
210 |
|
211 TInt DTraceEventHandler::GetNextEvent(TAny *outdes) |
|
212 { |
|
213 |
|
214 if (iBack==iFront) |
|
215 { // buffer empty |
|
216 return KErrNone; |
|
217 } |
|
218 TTraceEvent *e=&iTraceBuffer[iBack]; |
|
219 if (e->iLength == -1) |
|
220 return KErrCorrupt; // earlier error when copying trace data from userland |
|
221 TPtr ptr((TUint8*)e->iText, e->iLength, e->iLength); |
|
222 TInt r=KErrNone; |
|
223 Kern::KUDesPut(*(TDes *)outdes, ptr); |
|
224 iBack=(iBack+1)&KTraceBufferSizeMask; |
|
225 return r; |
|
226 } |
|
227 |
|
228 TInt DTraceRedirect::NextTrace(TAny *outdes) |
|
229 { |
|
230 |
|
231 TInt r=iEventHandler->GetNextEvent(outdes); |
|
232 return r; |
|
233 } |
|
234 |
|
235 TInt DTraceRedirect::Request(TInt aFunction, TAny* a1, TAny* /*a2*/) |
|
236 /** |
|
237 Handle requests from the test program |
|
238 */ |
|
239 { |
|
240 TInt r=KErrNone; |
|
241 switch (aFunction) |
|
242 { |
|
243 case RTraceRedirect::ENextTrace: |
|
244 r=NextTrace(a1); |
|
245 break; |
|
246 default: |
|
247 r=KErrNotSupported; |
|
248 break; |
|
249 } |
|
250 return r; |
|
251 } |
|
252 |