|
1 // Copyright (c) 2008-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 "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 // The Symbian OS porting layer - multi-threaded implementation. |
|
15 // Platform dependend implementation of the static mutexes and the file session API. |
|
16 // |
|
17 // |
|
18 |
|
19 /** |
|
20 @file |
|
21 */ |
|
22 #include "os_symbian.h" |
|
23 #include <pls.h> |
|
24 #include <e32std.h> |
|
25 |
|
26 #ifdef SQLITE_OS_SYMBIAN |
|
27 |
|
28 const TUid KSqliteUid = {0x10285A79};//See UID3 in SQLite3.mmp file - it should be the same |
|
29 |
|
30 /** |
|
31 This class describes an object that serves as a container for SQLite global variables |
|
32 that are stored in an allocated WSD buffer. |
|
33 The global variables are organised in a map, where the pointer to the initial global variable value |
|
34 is used as a key. |
|
35 A hash table is used to speed-up the key search. |
|
36 A single TWsdMap object is created and stored in the process local storage - TPls. |
|
37 |
|
38 @see TPls |
|
39 |
|
40 @internalComponent |
|
41 */ |
|
42 NONSHARABLE_CLASS(TWsdMap) |
|
43 { |
|
44 /** |
|
45 Hash table entry. |
|
46 */ |
|
47 struct TPair |
|
48 { |
|
49 const TUint8* iKey; //Global variable - key (a pointer the initial variable value) |
|
50 TUint8* iData; //Global variable - data |
|
51 }; |
|
52 |
|
53 public: |
|
54 enum {KBufferSize = 4096}; //WSD buffer size in bytes |
|
55 enum {KMaxEntries = 37}; //Max No. of entries in the hash table - prime number |
|
56 |
|
57 TWsdMap() : |
|
58 iNext(iBuffer), |
|
59 iSize(0) |
|
60 { |
|
61 Mem::FillZ(iTable, sizeof(iTable)); |
|
62 } |
|
63 /** |
|
64 Performs a search in the map for a global variable with aKey key. |
|
65 If there is no such variable in the map, the variable will be added and the new variable will be initialized |
|
66 with the data of aLength length, pointed by aKey. |
|
67 @param aKey Global variable key |
|
68 @param aLength Global variable data length in bytes |
|
69 @return Pointer to the global variable (located in the WSD buffer) |
|
70 @panic SqliteMt 9 The global variables map is full |
|
71 @panic SqliteMt 10 There is no space in the WSD buffer for the new variable |
|
72 */ |
|
73 TUint8* Find(const TUint8* aKey, TInt aLength) |
|
74 { |
|
75 TInt idx = Hash((TUint)aKey); |
|
76 TInt cnt = 0; |
|
77 while(iTable[idx].iKey != aKey && iTable[idx].iKey != NULL && ++cnt < KMaxEntries) |
|
78 { |
|
79 idx = ++idx % KMaxEntries; |
|
80 } |
|
81 __ASSERT_ALWAYS(cnt < KMaxEntries, User::Panic(KPanicCategory, EPanicMaxKeysExceeded)); |
|
82 if(!iTable[idx].iKey) |
|
83 { |
|
84 Add(idx, aKey, aLength); |
|
85 } |
|
86 return iTable[idx].iData; |
|
87 } |
|
88 |
|
89 private: |
|
90 /** |
|
91 Hash function. Calculates the index of the global variable key in the hash table. |
|
92 @param aKey Global variable key (casted "const TUint8*" to "TUint") |
|
93 @return Hash table index |
|
94 */ |
|
95 TUint Hash(TUint aKey) const |
|
96 { |
|
97 return (aKey * (aKey + 3)) % KMaxEntries; |
|
98 } |
|
99 /** |
|
100 Adds a new global variable to the WSD buffer and initializes a new entry in the hash table for the key. |
|
101 @param aIdx The entry index in the hash table |
|
102 @param aKey Global variable key |
|
103 @param aLength Global variable data length in bytes |
|
104 @panic SqliteMt 10 There is no space in the WSD buffer for the new variable |
|
105 */ |
|
106 void Add(TInt aIdx, const TUint8* aKey, TInt aLength) |
|
107 { |
|
108 __ASSERT_ALWAYS((iSize + aLength) <= KBufferSize, User::Panic(KPanicCategory, EPanicBufferSizeExceeded)); |
|
109 //Add new entry to the hash table and the intial value to the WSD buffer |
|
110 iTable[aIdx].iKey = aKey; |
|
111 iTable[aIdx].iData = iNext; |
|
112 iNext = Mem::Copy(iNext, aKey, aLength); |
|
113 iSize += aLength; |
|
114 //////////////// DEBUG prints ///////////////// |
|
115 //for(TInt i=0;i<KMaxEntries;++i) |
|
116 // { |
|
117 // RDebug::Print(_L("%d %X %X %d\r\n"), i, (TUint)iTable[i].iKey, (TUint)iTable[i].iData, Hash((TUint)iTable[i].iKey)); |
|
118 // } |
|
119 } |
|
120 |
|
121 private: |
|
122 TUint8 iBuffer[KBufferSize]; //WSD buffer |
|
123 TUint8* iNext; //Points to the next entry in the buffer |
|
124 TInt iSize; //Amount of buffer currently allocated in bytes |
|
125 TPair iTable[KMaxEntries]; //Hash table matching the address of global varaibles to the address of the values in the WSD buffer |
|
126 |
|
127 }; |
|
128 |
|
129 /** |
|
130 "Process local storage" structure, used for managing SQLite global variables. |
|
131 |
|
132 @see TStaticFs |
|
133 @see TStaticMutex |
|
134 @see TWsdMap |
|
135 @see PlsInitialize |
|
136 |
|
137 @internalComponent |
|
138 */ |
|
139 NONSHARABLE_STRUCT(TPls) |
|
140 { |
|
141 TStaticFs iStaticFs; |
|
142 TStaticMutex iStaticMutex[KStaticMutexCount]; |
|
143 TWsdMap iWsdMap; |
|
144 sqlite3_vfs iVfsApi; |
|
145 }; |
|
146 |
|
147 /** |
|
148 This is a callback function used by the Pls() call to get the process local storage initialized. |
|
149 The function initializes the TPls data members. |
|
150 |
|
151 @param aPls A pointer to the process local storage. |
|
152 @return KErrNone The process local storage has been successfully initialized. |
|
153 |
|
154 @panic SqliteMt 1 Failed to connect the RFs |
|
155 @panic SqliteMt 2 Failed to create the static mutexes |
|
156 @panic SqliteMt 4 Null aPls parameter value |
|
157 |
|
158 @internalComponent |
|
159 */ |
|
160 static TInt PlsInitialize(TPls* aPls) |
|
161 { |
|
162 __ASSERT_ALWAYS(aPls != NULL, User::Panic(KPanicCategory, EPanicNullPls1)); |
|
163 //Global RFs object |
|
164 TInt err = aPls->iStaticFs.Connect(); |
|
165 __ASSERT_ALWAYS(err == KErrNone , User::Panic(KPanicCategory, EPanicFsCreationError)); |
|
166 //Static mutexes |
|
167 for(TInt i=0;i<(sizeof(aPls->iStaticMutex)/sizeof(aPls->iStaticMutex[0])) && err==KErrNone;++i) |
|
168 { |
|
169 err = aPls->iStaticMutex[i].Create(); |
|
170 } |
|
171 __ASSERT_ALWAYS(err == KErrNone , User::Panic(KPanicCategory, EPanicMutexCreationError)); |
|
172 //WSD map |
|
173 //...already initialized by its constructor |
|
174 //sqlite3_vfs object |
|
175 aPls->iVfsApi.iVersion = 1; |
|
176 aPls->iVfsApi.szOsFile = sizeof(TDbFile); |
|
177 aPls->iVfsApi.mxPathname = KMaxFileName; |
|
178 aPls->iVfsApi.pNext = NULL; |
|
179 aPls->iVfsApi.zName = "SymbianSqliteMt"; |
|
180 aPls->iVfsApi.pAppData = NULL; |
|
181 aPls->iVfsApi.xOpen = &TVfs::Open; |
|
182 aPls->iVfsApi.xDelete = &TVfs::Delete; |
|
183 aPls->iVfsApi.xAccess = &TVfs::Access; |
|
184 aPls->iVfsApi.xFullPathname = &TVfs::FullPathName; |
|
185 aPls->iVfsApi.xDlOpen = NULL; |
|
186 aPls->iVfsApi.xDlError = NULL; |
|
187 aPls->iVfsApi.xDlSym = NULL; |
|
188 aPls->iVfsApi.xDlClose = NULL; |
|
189 aPls->iVfsApi.xRandomness = &TVfs::Randomness; |
|
190 aPls->iVfsApi.xSleep = &TVfs::Sleep; |
|
191 aPls->iVfsApi.xCurrentTime = &TVfs::CurrentTime; |
|
192 aPls->iVfsApi.xGetLastError = &TVfs::GetLastError; |
|
193 |
|
194 return KErrNone; |
|
195 } |
|
196 |
|
197 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
198 ////////////////////////// TStaticFs ///////////////////////////////////////////////////////////////////////////////////////// |
|
199 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
200 |
|
201 TStaticFs::TStaticFs() |
|
202 { |
|
203 } |
|
204 |
|
205 /** |
|
206 Returns a reference to the already created RFs object that is located in the process local storage. |
|
207 |
|
208 @return RFs reference |
|
209 |
|
210 @panic SqliteMt 3 Invalid RFs handle |
|
211 @panic SqliteMt 5 Process local storage initialization failure |
|
212 */ |
|
213 RFs& TStaticFs::Fs() |
|
214 { |
|
215 TPls* pls = ::Pls(KSqliteUid, &PlsInitialize); |
|
216 __ASSERT_ALWAYS(pls != 0, User::Panic(KPanicCategory, EPanicNullPls2)); |
|
217 __ASSERT_DEBUG(pls->iStaticFs.iFs.Handle() != KNullHandle, User::Panic(KPanicCategory, EPanicInvalidFs)); |
|
218 return pls->iStaticFs.iFs; |
|
219 } |
|
220 |
|
221 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
222 ////////////////////////// TStaticMutex ////////////////////////////////////////////////////////////////////////////////////// |
|
223 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
224 |
|
225 TStaticMutex::TStaticMutex() |
|
226 { |
|
227 } |
|
228 |
|
229 sqlite3_mutex* StaticMutex(TInt aType) |
|
230 { |
|
231 TPls* pls = ::Pls(KSqliteUid, &PlsInitialize); |
|
232 __ASSERT_ALWAYS(pls != 0, User::Panic(KPanicCategory, EPanicNullPls3)); |
|
233 __ASSERT_ALWAYS((TUint)aType < (sizeof(pls->iStaticMutex)/sizeof(pls->iStaticMutex[0])), User::Panic(KPanicCategory, EPanicInvalidMutexType)); |
|
234 return &pls->iStaticMutex[aType]; |
|
235 } |
|
236 |
|
237 |
|
238 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
239 //////////////////////// sqlite3_wsd ///////////////////////////////////////////////////////////////////////////////////// |
|
240 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
241 |
|
242 /** |
|
243 The implementation of this function does not do anything special apart from checking that the requested WSD buffer size and |
|
244 global variables count (WSD entries) are not bigger than the max TWsdMap buffer size and max TWsdMap entry count. |
|
245 |
|
246 @param aWsdBufSize SQLite expects the size of the WSD buffer to be "aWsdBufSize" bytes |
|
247 @param aWsdEntryCount SQLite can place in the WSD buffer up to "aWsdEntryCount" global variables. |
|
248 |
|
249 @panic SqliteMt 12 The requested WSD buffer is too big. Bigger than TWsdMap::KBufferSize. |
|
250 @panic SqliteMt 13 The requested global variables count is too big. Bigger than TWsdMap::KMaxEntries. |
|
251 |
|
252 @see TWsdMap |
|
253 */ |
|
254 int sqlite3_wsd_init(int aWsdBufSize, int aWsdEntryCount) |
|
255 { |
|
256 __ASSERT_ALWAYS(aWsdBufSize <= TWsdMap::KBufferSize, User::Panic(KPanicCategory, EPanicWsdBufSize)); |
|
257 __ASSERT_ALWAYS(aWsdEntryCount <= TWsdMap::KMaxEntries, User::Panic(KPanicCategory, EPanicWsdEntryCount)); |
|
258 return SQLITE_OK; |
|
259 } |
|
260 |
|
261 /** |
|
262 Performs a search in the WSD map (in the process local storage) for a global variable identified by the aKey parameter. |
|
263 |
|
264 @param aKey Global variable key |
|
265 @param aLength Global variable data length in bytes |
|
266 @return Pointer to the global variable data |
|
267 |
|
268 @panic SqliteMt 11 Process local storage initialization failure |
|
269 |
|
270 @see TWsdMap |
|
271 @see TPls |
|
272 */ |
|
273 void* sqlite3_wsd_find(void* aKey, int aLength) |
|
274 { |
|
275 __ASSERT_ALWAYS(aKey != NULL, User::Panic(KPanicCategory, EPanicNullKey)); |
|
276 return ::Pls(KSqliteUid, &PlsInitialize)->iWsdMap.Find(static_cast <const TUint8*> (aKey), aLength); |
|
277 } |
|
278 |
|
279 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
280 ////////////////////////// sqlite3_vfs /////////////////////////////////////////////////////////////////////////////////// |
|
281 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
282 |
|
283 sqlite3_vfs* VfsApi() |
|
284 { |
|
285 TPls* pls = ::Pls(KSqliteUid, &PlsInitialize); |
|
286 __ASSERT_ALWAYS(pls != 0, User::Panic(KPanicCategory, EPanicNullPls4)); |
|
287 return &pls->iVfsApi; |
|
288 } |
|
289 |
|
290 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
291 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
292 |
|
293 #endif SQLITE_OS_SYMBIAN |