|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the Qt Mobility Components. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qvaluespace_p.h" |
|
43 #include "qmallocpool_p.h" |
|
44 #include "qvaluespacepublisher.h" |
|
45 #include "qsystemreadwritelock_p.h" |
|
46 #include "qpacketprotocol_p.h" |
|
47 |
|
48 #include <QSet> |
|
49 #include <QCoreApplication> |
|
50 #include <QLocalSocket> |
|
51 #include <QLocalServer> |
|
52 #include <QDir> |
|
53 #include <QVariant> |
|
54 |
|
55 #include <QMutex> |
|
56 #include <QSharedMemory> |
|
57 #include <QTime> |
|
58 #include <QThread> |
|
59 |
|
60 QTM_BEGIN_NAMESPACE |
|
61 |
|
62 #define VERSION_TABLE_ENTRIES 8191 |
|
63 #define ROOT_VERSION_ENTRY 0 |
|
64 |
|
65 #define MAX_PATH_SIZE 16384 |
|
66 #define MAX_DATA_SIZE 16384 |
|
67 #define INVALID_HANDLE 0xFFFF |
|
68 |
|
69 #define ALIGN4b(n) ((n) + (((n) % 4)?(4 - ((n) % 4)):0)) |
|
70 |
|
71 // #define QVALUESPACE_UPDATE_STATS |
|
72 |
|
73 static inline QDataStream& operator<<(QDataStream& stream, unsigned long v) |
|
74 { |
|
75 if (sizeof(unsigned long) == sizeof(uint)) { |
|
76 stream << (uint)v; |
|
77 return stream; |
|
78 } else { |
|
79 stream << (quint64)v; |
|
80 return stream; |
|
81 } |
|
82 } |
|
83 |
|
84 static inline QDataStream& operator>>(QDataStream& stream, unsigned long& v) |
|
85 { |
|
86 if (sizeof(unsigned long) == sizeof(uint)) { |
|
87 uint v32; |
|
88 stream >> v32; |
|
89 v = (unsigned long)v32; |
|
90 } else { |
|
91 quint64 v64; |
|
92 stream >> v64; |
|
93 v = (unsigned long)v64; |
|
94 } |
|
95 return stream; |
|
96 } |
|
97 |
|
98 static int vsmemcmp(const char * s1, int l1, const char * s2, int l2) |
|
99 { |
|
100 if (l1 < l2) |
|
101 return -1; |
|
102 if (l1 > l2) |
|
103 return 1; |
|
104 return ::memcmp(s1, s2, l1); |
|
105 } |
|
106 |
|
107 /////////////////////////////////////////////////////////////////////////////// |
|
108 // declare VersionTable |
|
109 /////////////////////////////////////////////////////////////////////////////// |
|
110 struct VersionTable { |
|
111 |
|
112 struct Entry { |
|
113 Entry(unsigned int v, unsigned int n) : version(v), nodePtr(n) {} |
|
114 |
|
115 unsigned int version; |
|
116 union { |
|
117 unsigned int nodePtr; |
|
118 unsigned int nxtFreeBlk; // 0 means no next free block |
|
119 // (as root is always 0) |
|
120 }; |
|
121 }; |
|
122 |
|
123 unsigned int nxtFreeBlk; |
|
124 unsigned int nextCreationId; |
|
125 |
|
126 Entry entries[VERSION_TABLE_ENTRIES]; |
|
127 }; |
|
128 |
|
129 |
|
130 // declare NodeOwner |
|
131 /* |
|
132 Owner of data in a node. |
|
133 |
|
134 Overhead: 8 |
|
135 */ |
|
136 struct NodeOwner { |
|
137 unsigned long data1; |
|
138 unsigned long data2; |
|
139 }; |
|
140 |
|
141 |
|
142 // declare NodeDatum |
|
143 /* |
|
144 Encapsulates the data and data owner associated with a Node. |
|
145 |
|
146 Overhead: 12 + data size |
|
147 */ |
|
148 struct NodeDatum { |
|
149 NodeOwner owner; |
|
150 enum Type { Boolean = QVariant::Bool, |
|
151 Int = QVariant::Int, |
|
152 UInt = QVariant::UInt, |
|
153 LongLong = QVariant::LongLong, |
|
154 ULongLong = QVariant::ULongLong, |
|
155 Double = QVariant::Double, |
|
156 Char = QVariant::Char, |
|
157 String = QVariant::String, |
|
158 ByteArray = QVariant::ByteArray, |
|
159 SerializedType /* Catch all for everything else */ }; |
|
160 //Type type; |
|
161 unsigned short type; |
|
162 unsigned short len; |
|
163 char data[0]; |
|
164 }; |
|
165 |
|
166 // declare NodeWatch |
|
167 /* |
|
168 Node write watcher. |
|
169 |
|
170 Overhead: 8 |
|
171 */ |
|
172 struct NodeWatch { |
|
173 unsigned long data1; |
|
174 unsigned long data2; |
|
175 }; |
|
176 |
|
177 /////////////////////////////////////////////////////////////////////////////// |
|
178 // declare Node |
|
179 /////////////////////////////////////////////////////////////////////////////// |
|
180 /* |
|
181 In memory representation of a node. |
|
182 |
|
183 In memory, nodes are structured in one of the following three ways. |
|
184 Virtual (No Data) Node: |
|
185 <Node (dataCount == 0)><const char [] name> |
|
186 Single data node: |
|
187 <Node (dataCount == 1)><char [] name><NodeDatum><char [] data> |
|
188 Multiple data node: |
|
189 <Node (dataCount >= 2)><char [] name><unsigned int dataListPtr> |
|
190 With single watch: |
|
191 <Node (watchCount == 1)><char [] name><Rest of node...><NodeWatch> |
|
192 With multiple watch: |
|
193 <Node (watchCount >= 2)><char [] name><Rest of node...><unsigned int nodeWatchPtr> |
|
194 |
|
195 Overhead: 16 bytes + name size |
|
196 */ |
|
197 struct Node { |
|
198 unsigned short parent; /* Id for my parent */ |
|
199 unsigned int creationId; /* Unique id set when I was constructed */ |
|
200 |
|
201 unsigned short subNodes; /* Sub node count */ |
|
202 unsigned int subNodePtr; /* Ptr to malloc'd array of sub node ptrs */ |
|
203 |
|
204 unsigned short watchCount; |
|
205 unsigned short dataCount; /* Amount of data associated with this node */ |
|
206 unsigned short nameLen; /* Length of name in bytes */ |
|
207 unsigned short dummy; /* dummy for 4 byte alignment */ |
|
208 |
|
209 char name[0]; /* My name - NO trailing null */ |
|
210 |
|
211 bool valid() { |
|
212 return 0 != watchCount || 0 != dataCount || 0 != subNodes; |
|
213 } |
|
214 unsigned int dataBlockSize() |
|
215 { |
|
216 if(0 == dataCount) { |
|
217 return 0; |
|
218 } else if(1 == dataCount) { |
|
219 NodeDatum * datum = (NodeDatum *)dataBegin(); |
|
220 return sizeof(NodeDatum) + datum->len; |
|
221 } else if(2 >= dataCount) { |
|
222 return sizeof(unsigned int); |
|
223 } |
|
224 } |
|
225 |
|
226 unsigned int watchBlockSize() |
|
227 { |
|
228 if(0 == watchCount) |
|
229 return 0; |
|
230 else if(1 == watchCount) |
|
231 return sizeof(NodeWatch); |
|
232 else if(2 >= watchCount) |
|
233 return sizeof(unsigned int); |
|
234 return 0; |
|
235 } |
|
236 |
|
237 unsigned int size() |
|
238 { |
|
239 unsigned int rv = sizeof(Node); |
|
240 rv += ALIGN4b(nameLen); |
|
241 if(watchCount == 1) { |
|
242 rv += sizeof(NodeWatch); |
|
243 } else if(watchCount >= 2) { |
|
244 rv += sizeof(unsigned int); |
|
245 } |
|
246 |
|
247 if(dataCount == 1) { |
|
248 NodeDatum * datum = (NodeDatum *)dataBegin(); |
|
249 rv += sizeof(NodeDatum) + ALIGN4b(datum->len); |
|
250 } else if(dataCount >= 2) { |
|
251 rv += sizeof(unsigned int); |
|
252 } |
|
253 |
|
254 return rv; |
|
255 } |
|
256 |
|
257 void * dataBegin() |
|
258 { |
|
259 return (void *)(name + ALIGN4b(nameLen)); |
|
260 } |
|
261 |
|
262 void * watchBegin() |
|
263 { |
|
264 if(0 == dataCount) { |
|
265 return dataBegin(); |
|
266 } else if(1 == dataCount) { |
|
267 NodeDatum * datum = (NodeDatum *)dataBegin(); |
|
268 return datum->data + ALIGN4b(datum->len); |
|
269 } else { |
|
270 return name + ALIGN4b(nameLen) + sizeof(unsigned int); |
|
271 } |
|
272 } |
|
273 }; |
|
274 |
|
275 bool operator==(const NodeOwner &lhs, const NodeOwner &rhs) |
|
276 { |
|
277 return 0 == ::memcmp(&lhs, &rhs, sizeof(NodeOwner)); |
|
278 } |
|
279 bool operator!=(const NodeOwner &lhs, const NodeOwner &rhs) |
|
280 { |
|
281 return 0 != ::memcmp(&lhs, &rhs, sizeof(NodeOwner)); |
|
282 } |
|
283 bool operator==(const NodeWatch &lhs, const NodeWatch &rhs) |
|
284 { |
|
285 return 0 == ::memcmp(&lhs, &rhs, sizeof(NodeWatch)); |
|
286 } |
|
287 bool operator!=(const NodeWatch &lhs, const NodeWatch &rhs) |
|
288 { |
|
289 return 0 != ::memcmp(&lhs, &rhs, sizeof(NodeWatch)); |
|
290 } |
|
291 static const NodeWatch INVALID_WATCH = {0,0}; |
|
292 static const NodeOwner INVALID_OWNER = {0,0}; |
|
293 |
|
294 /////////////////////////////////////////////////////////////////////////////// |
|
295 // declare FixedMemoryTree |
|
296 /////////////////////////////////////////////////////////////////////////////// |
|
297 class FixedMemoryTree : public QObject |
|
298 { |
|
299 Q_OBJECT |
|
300 public: |
|
301 FixedMemoryTree(void * mem, unsigned int size, bool initMem); |
|
302 |
|
303 // Returns the closest node to the specified path |
|
304 unsigned short findClosest(const char * path, |
|
305 const char ** matched); |
|
306 unsigned short findClosest(unsigned int from, |
|
307 const char * subPath, |
|
308 const char ** matched); |
|
309 |
|
310 NodeDatum * data(unsigned short node); |
|
311 |
|
312 bool addWatch(const char * path, NodeWatch owner); |
|
313 bool remWatch(const char * path, NodeWatch owner); |
|
314 |
|
315 bool insert(const char * path, |
|
316 NodeDatum::Type type, |
|
317 const char * data, |
|
318 unsigned int dataLen, |
|
319 NodeOwner owner); |
|
320 |
|
321 unsigned short offsetOfSubNode(unsigned short node, |
|
322 unsigned short subNode); |
|
323 |
|
324 bool remove(const char * path, NodeOwner owner); |
|
325 |
|
326 inline Node * getNode(unsigned int); |
|
327 inline Node * subNode(unsigned int, unsigned short); |
|
328 inline unsigned int version(unsigned int); |
|
329 |
|
330 inline void * fromPtr(unsigned int ptr); |
|
331 |
|
332 #ifdef QVALUESPACE_UPDATE_STATS |
|
333 inline QMallocPool *mallocPool() const { return pool; } |
|
334 #endif |
|
335 |
|
336 typedef void (*NodeChangeFunction)(unsigned short node, void *ctxt); |
|
337 void setNodeChangeFunction(NodeChangeFunction, void *); |
|
338 |
|
339 private: |
|
340 static unsigned int growListSize(unsigned int currentSize); |
|
341 static unsigned int shrunkListSize(unsigned int currentSize, |
|
342 unsigned int toSize); |
|
343 |
|
344 bool setWatch(unsigned short node, NodeWatch owner); |
|
345 bool remWatch(unsigned short node, NodeWatch owner); |
|
346 bool setData(unsigned short node, NodeOwner owner, |
|
347 NodeDatum::Type type, const char * data, |
|
348 unsigned int dataLen); |
|
349 |
|
350 void removeFrom(unsigned short from, unsigned short subNodeNumber); |
|
351 |
|
352 unsigned short findRecur(unsigned short node, const char * path, |
|
353 const char ** consumed); |
|
354 |
|
355 bool insertRecur(unsigned short node, const char * path, |
|
356 NodeDatum::Type type, const char * data, |
|
357 unsigned int dataLen, NodeOwner owner); |
|
358 |
|
359 bool addWatchRecur(unsigned short node, const char * path, |
|
360 NodeWatch owner); |
|
361 |
|
362 bool remWatchRecur(unsigned short node, const char * path, |
|
363 NodeWatch owner); |
|
364 bool removeRecur(unsigned short node, const char * path, |
|
365 NodeOwner owner); |
|
366 unsigned short removeRecur(unsigned short, NodeOwner owner); |
|
367 |
|
368 unsigned int locateInNode(Node * node, const char * name, |
|
369 unsigned int len, bool * match); |
|
370 |
|
371 inline unsigned int ptr(void * mem); |
|
372 inline VersionTable * versionTable(); |
|
373 inline void bump(unsigned short node); |
|
374 |
|
375 unsigned short newNode(const char * name, unsigned int len, |
|
376 NodeWatch owner); |
|
377 unsigned short newNode(const char * name, |
|
378 unsigned int len, |
|
379 NodeOwner owner = INVALID_OWNER, |
|
380 NodeDatum::Type type = (NodeDatum::Type)0, |
|
381 const char * data = 0, |
|
382 unsigned int dataLen = 0); |
|
383 |
|
384 inline Node * node(unsigned int); |
|
385 |
|
386 char * poolMem; |
|
387 QMallocPool * pool; |
|
388 bool changed; |
|
389 NodeChangeFunction changeFunc; |
|
390 void * changeFuncContext; |
|
391 }; |
|
392 |
|
393 /////////////////////////////////////////////////////////////////////////////// |
|
394 // define FixedMemoryTree |
|
395 /////////////////////////////////////////////////////////////////////////////// |
|
396 FixedMemoryTree::FixedMemoryTree(void * mem, unsigned int size, |
|
397 bool initMemory ) |
|
398 : poolMem((char *)mem), pool(0), changed(false), changeFunc(0) |
|
399 { |
|
400 Q_ASSERT(size); |
|
401 Q_ASSERT(poolMem); |
|
402 |
|
403 if(initMemory) { |
|
404 /* Initialize layer version table - would be worth randomizing the |
|
405 nextFreeBlk chain to distribute entries across the 128-bit change |
|
406 notification. */ |
|
407 ::memset(poolMem,0, sizeof(VersionTable)); |
|
408 for(int ii = 0; ii < VERSION_TABLE_ENTRIES; ++ii) |
|
409 versionTable()->entries[ii].nxtFreeBlk = |
|
410 (ii + 1) % VERSION_TABLE_ENTRIES; |
|
411 |
|
412 /* Create malloc pool on the non-version table portion of the layer */ |
|
413 pool = |
|
414 new QMallocPool(poolMem + sizeof(VersionTable), |
|
415 size - sizeof(VersionTable), |
|
416 QMallocPool::Owned, QLatin1String("FixedMemoryTree")); |
|
417 |
|
418 /* Create root node and fixup free block pointer */ |
|
419 versionTable()->nxtFreeBlk = |
|
420 versionTable()->entries[ROOT_VERSION_ENTRY].nxtFreeBlk; |
|
421 Node * root = (Node *)pool->malloc(sizeof(Node)); |
|
422 ::memset(root,0, sizeof(Node)); |
|
423 root->creationId = versionTable()->nextCreationId++; |
|
424 root->parent = INVALID_HANDLE; |
|
425 Q_ASSERT((char *)root > poolMem); |
|
426 versionTable()->entries[ROOT_VERSION_ENTRY] = |
|
427 VersionTable::Entry(1, ptr(root)); |
|
428 } |
|
429 } |
|
430 |
|
431 unsigned short FixedMemoryTree::findClosest(const char * path, |
|
432 const char ** matched) |
|
433 { |
|
434 Q_ASSERT(path); |
|
435 Q_ASSERT(matched); |
|
436 Q_ASSERT(path[0] == '/'); |
|
437 |
|
438 ++path; // Skip initial '/' |
|
439 |
|
440 if('\0' == *path) |
|
441 return ROOT_VERSION_ENTRY; |
|
442 else |
|
443 return findRecur(ROOT_VERSION_ENTRY, path, matched); |
|
444 } |
|
445 |
|
446 unsigned short FixedMemoryTree::findClosest(unsigned int from, |
|
447 const char * subPath, |
|
448 const char ** matched) |
|
449 { |
|
450 Q_ASSERT(subPath); |
|
451 Q_ASSERT(matched); |
|
452 Q_ASSERT(subPath[0] == '/'); |
|
453 |
|
454 ++subPath; // Skip initial '/' |
|
455 if('\0' == *subPath) |
|
456 return from; |
|
457 else |
|
458 return findRecur(from, subPath, matched); |
|
459 } |
|
460 |
|
461 /*! |
|
462 Returns the default datum for \a node, or NULL if one doesn't exist. |
|
463 */ |
|
464 NodeDatum * FixedMemoryTree::data(unsigned short node) |
|
465 { |
|
466 Node * n = this->node(node); |
|
467 if(0 == n->dataCount) { |
|
468 return 0; |
|
469 } else if(1 == n->dataCount) { |
|
470 return (NodeDatum *)n->dataBegin(); |
|
471 } else { |
|
472 unsigned int * valueList = |
|
473 (unsigned int *)fromPtr(*(unsigned int *)n->dataBegin()); |
|
474 return (NodeDatum *)fromPtr(*valueList); |
|
475 } |
|
476 } |
|
477 |
|
478 /*! |
|
479 Inserts a watch for \a owner at the specified \a path |
|
480 */ |
|
481 bool FixedMemoryTree::addWatch(const char * path, NodeWatch owner) |
|
482 { |
|
483 Q_ASSERT(path); |
|
484 Q_ASSERT(path[0] == '/'); |
|
485 Q_ASSERT(INVALID_WATCH != owner); |
|
486 |
|
487 ++path; // Skip initial '/' |
|
488 |
|
489 if(*path == '\0') |
|
490 return setWatch(ROOT_VERSION_ENTRY, owner); |
|
491 else |
|
492 return addWatchRecur(ROOT_VERSION_ENTRY, path, owner); |
|
493 } |
|
494 |
|
495 /*! |
|
496 Removes an existing watch for \a owner from the specified \a path |
|
497 */ |
|
498 bool FixedMemoryTree::remWatch(const char * path, NodeWatch owner) |
|
499 { |
|
500 Q_ASSERT(path); |
|
501 Q_ASSERT(path[0] == '/'); |
|
502 Q_ASSERT(INVALID_WATCH != owner); |
|
503 |
|
504 ++path; // Skip initial '/' |
|
505 |
|
506 if(*path == '\0') |
|
507 return remWatch((unsigned short)ROOT_VERSION_ENTRY, owner); |
|
508 else |
|
509 return remWatchRecur(ROOT_VERSION_ENTRY, path, owner); |
|
510 } |
|
511 |
|
512 /*! |
|
513 Inserts \a data of length \a dataLen at \a path with the set \a owner. |
|
514 Returns true if the tree has visibly changed. |
|
515 */ |
|
516 bool FixedMemoryTree::insert(const char * path, NodeDatum::Type type, |
|
517 const char * data, unsigned int dataLen, |
|
518 NodeOwner owner) |
|
519 { |
|
520 Q_ASSERT(path); |
|
521 Q_ASSERT(path[0] == '/'); |
|
522 Q_ASSERT(data || !dataLen); |
|
523 Q_ASSERT(INVALID_OWNER != owner); |
|
524 |
|
525 if(dataLen > MAX_DATA_SIZE) |
|
526 return false; |
|
527 |
|
528 ++path; // Skip initial '/' |
|
529 |
|
530 // Special root case - no one can insert |
|
531 if(*path == '\0') return false; |
|
532 |
|
533 return insertRecur(ROOT_VERSION_ENTRY, path, type, data, dataLen, owner); |
|
534 } |
|
535 |
|
536 /*! |
|
537 Returns the linear offset of \a subNode within \a node. Asserts if not |
|
538 found. |
|
539 */ |
|
540 unsigned short FixedMemoryTree::offsetOfSubNode(unsigned short node, |
|
541 unsigned short subNode) |
|
542 { |
|
543 Node * me = getNode(node); |
|
544 if(!me) |
|
545 return INVALID_HANDLE; |
|
546 |
|
547 unsigned short * const subNodes = |
|
548 (unsigned short *)fromPtr(me->subNodePtr); |
|
549 for(unsigned short ii = 0; ii < me->subNodes; ++ii) { |
|
550 if(subNodes[ii] == subNode) |
|
551 return ii; |
|
552 } |
|
553 |
|
554 qFatal("SharedMemoryLayer: Unable to find sub-node %x of %x.", subNode, node); |
|
555 return 0; |
|
556 } |
|
557 |
|
558 bool FixedMemoryTree::remove(const char * path, NodeOwner owner) |
|
559 { |
|
560 Q_ASSERT(path); |
|
561 Q_ASSERT(path[0] == '/'); |
|
562 Q_ASSERT(INVALID_OWNER != owner); |
|
563 |
|
564 ++path; // Skip initial '/' |
|
565 |
|
566 if(*path == '\0') |
|
567 return INVALID_HANDLE != removeRecur(ROOT_VERSION_ENTRY, owner); |
|
568 else |
|
569 return removeRecur(ROOT_VERSION_ENTRY, path, owner); |
|
570 } |
|
571 |
|
572 /*! |
|
573 Given a list of size \a currentSize that needs another element, returns a |
|
574 new size designated by the following growth strategy: |
|
575 |
|
576 \list |
|
577 \i Initially (currentSize == 0) allocate a list of one entry. |
|
578 \i Up to 64 entries, double the size each allocation. |
|
579 \i From 64 onwards, grow in chunks of 64 |
|
580 \endlist |
|
581 */ |
|
582 unsigned int FixedMemoryTree::growListSize(unsigned int currentSize) |
|
583 { |
|
584 if(0 == currentSize) |
|
585 return 1; |
|
586 if(currentSize <= 32) |
|
587 return currentSize * 2; |
|
588 return currentSize + 64; |
|
589 } |
|
590 |
|
591 /*! |
|
592 Given that we have an allocated list of size \a currentSize, that needs to |
|
593 contain contentSize elements, returns an ideal list size designated by the |
|
594 following shrink strategy: |
|
595 |
|
596 \list |
|
597 \i For current size > 64, reduce in blocks of 64 |
|
598 \i For currentSize < 64, reduce by half if possible |
|
599 \i Otherwise, remain the same |
|
600 \endlist |
|
601 */ |
|
602 unsigned int FixedMemoryTree::shrunkListSize(unsigned int currentSize, |
|
603 unsigned int contentSize) |
|
604 { |
|
605 if(currentSize > 64) { |
|
606 return currentSize - 64 * ((currentSize - contentSize) / 64); |
|
607 } else if(contentSize < (currentSize / 2)) { |
|
608 return currentSize / 2; |
|
609 } |
|
610 |
|
611 return currentSize; |
|
612 } |
|
613 |
|
614 /*! |
|
615 Attempts to locate the sub node \a name (of length \a len) in \a node. If |
|
616 found, returns the offset and sets \a *match to true. If not found, |
|
617 sets \a *match to false and returns the offset where the node would be |
|
618 found, should it exist. Moving all nodes up one notch and inserting the |
|
619 new node at the returned offset maintains order. |
|
620 */ |
|
621 unsigned int FixedMemoryTree::locateInNode(Node * node, const char * name, |
|
622 unsigned int len, bool * match) |
|
623 { |
|
624 Q_ASSERT(node && name && match); |
|
625 |
|
626 // This is a linear search. It would be possible to replace this with a |
|
627 // binary search, which may or may not improve performance depending on the |
|
628 // number of sub nodes. |
|
629 unsigned short counter = 0; |
|
630 unsigned short * subNodes = (unsigned short *)fromPtr(node->subNodePtr); |
|
631 |
|
632 *match = false; |
|
633 for(counter = 0; counter < node->subNodes; ++counter) { |
|
634 Node * currentNode = this->node(subNodes[counter]); |
|
635 |
|
636 int memcmprv = vsmemcmp(name, len, currentNode->name, |
|
637 currentNode->nameLen); |
|
638 if(memcmprv < 0) { |
|
639 continue; |
|
640 } else if(memcmprv == 0) { |
|
641 *match = true; |
|
642 break; |
|
643 } else if(memcmprv > 0) { |
|
644 break; |
|
645 } |
|
646 } |
|
647 |
|
648 return counter; |
|
649 } |
|
650 |
|
651 /*! |
|
652 \internal |
|
653 Recursive implementation of FixedMemoryTree::findClosest |
|
654 */ |
|
655 unsigned short FixedMemoryTree::findRecur(unsigned short node, |
|
656 const char * path, |
|
657 const char ** consumed) |
|
658 { |
|
659 // Locate end of section |
|
660 const char * endOfSection = path; |
|
661 while(*endOfSection != '/' && *endOfSection != '\0') ++endOfSection; |
|
662 const unsigned int sectionLen = (endOfSection - path); |
|
663 |
|
664 bool match; |
|
665 Node * const me = this->node(node); |
|
666 const unsigned int matchId = locateInNode(me, path, sectionLen, &match); |
|
667 Q_ASSERT((match && matchId < me->subNodes) || |
|
668 (!match && matchId <= me->subNodes)); |
|
669 |
|
670 if(!match) { |
|
671 *consumed = path - 1; |
|
672 return node; |
|
673 } |
|
674 |
|
675 unsigned short * const subNodes = |
|
676 (unsigned short *)fromPtr(me->subNodePtr); |
|
677 if('\0' == *endOfSection) { |
|
678 *consumed = NULL; |
|
679 return subNodes[matchId]; |
|
680 } |
|
681 |
|
682 ++endOfSection; |
|
683 return findRecur(subNodes[matchId], endOfSection, consumed); |
|
684 } |
|
685 |
|
686 /*! Remove all nodes under node that match owner (or no-owner with no |
|
687 dependents). Returns the last node removed, which will be \a node if |
|
688 it was removed, or INVALID_HANDLE if no nodes were removed. This can |
|
689 be used by the parent to determine whether to increment the version |
|
690 number and whether to remove the sub node. |
|
691 */ |
|
692 unsigned short FixedMemoryTree::removeRecur(unsigned short node, |
|
693 NodeOwner owner) |
|
694 { |
|
695 Node * me = this->node(node); |
|
696 |
|
697 unsigned short * const subNodes = |
|
698 (unsigned short*)fromPtr(me->subNodePtr); |
|
699 |
|
700 unsigned short removedAny = INVALID_HANDLE; |
|
701 unsigned int removedSubNodes = 0; |
|
702 |
|
703 for(unsigned short ii = 0; ii < me->subNodes; ++ii) { |
|
704 |
|
705 unsigned short id = subNodes[ii]; |
|
706 // Blank recur |
|
707 unsigned short removedId = removeRecur(id, owner); |
|
708 |
|
709 if(removedId != INVALID_HANDLE) |
|
710 removedAny = removedId; |
|
711 |
|
712 if(removedId == id) { |
|
713 // This node was removed |
|
714 ++removedSubNodes; |
|
715 subNodes[ii] = INVALID_HANDLE; |
|
716 } |
|
717 |
|
718 } |
|
719 |
|
720 // If removed any sub nodes we need to collapse our subnode list |
|
721 if(removedSubNodes == me->subNodes) { |
|
722 // All removed! |
|
723 pool->free(subNodes); |
|
724 me->subNodes = 0; |
|
725 me->subNodePtr = 0; |
|
726 } else if(removedSubNodes) { |
|
727 // Some removed |
|
728 unsigned int fillUpto = 0; |
|
729 |
|
730 for(unsigned int sourceUpto = 0; |
|
731 sourceUpto < me->subNodes; |
|
732 ++sourceUpto) { |
|
733 |
|
734 if(INVALID_HANDLE != subNodes[sourceUpto]) { |
|
735 subNodes[fillUpto] = subNodes[sourceUpto]; |
|
736 ++fillUpto; |
|
737 } |
|
738 } |
|
739 |
|
740 me->subNodes = fillUpto; |
|
741 } |
|
742 |
|
743 // Now to remove data and possibly me as necessary |
|
744 if(1 == me->dataCount) { |
|
745 |
|
746 NodeDatum * datum = (NodeDatum *)me->dataBegin(); |
|
747 if(datum->owner == owner || |
|
748 (owner.data2 = 0xFFFFFFFF && owner.data1 == datum->owner.data1)) |
|
749 me->dataCount = 0; |
|
750 |
|
751 } else if(me->dataCount > 1) { |
|
752 |
|
753 // Data list time - sigh |
|
754 unsigned int * list = |
|
755 (unsigned int *)fromPtr(*((unsigned int *)me->dataBegin())); |
|
756 unsigned int removed = 0; |
|
757 for(int ii = 0; ii < me->dataCount; ++ii) { |
|
758 NodeDatum * datum = (NodeDatum *)fromPtr(list[ii]); |
|
759 if(datum->owner == owner || |
|
760 (owner.data2 == 0xFFFFFFFF && |
|
761 owner.data1 == datum->owner.data1)) { |
|
762 // Remove this datum |
|
763 ++removed; |
|
764 pool->free(datum); |
|
765 list[ii] = 0xFFFFFFFF; |
|
766 } |
|
767 } |
|
768 |
|
769 if(removed) { |
|
770 // Three cases: Only one left in list - move into node |
|
771 // All removed - remove list |
|
772 // Some removed - shorten list if necessary |
|
773 if((removed + 1)== me->dataCount) { |
|
774 // Find remaining node |
|
775 bool found = false; |
|
776 for(int ii = 0; !found && ii < me->dataCount; ++ii) { |
|
777 if(0xFFFFFFFF != list[ii]) { |
|
778 NodeDatum * datum = (NodeDatum *)fromPtr(list[ii]); |
|
779 me->dataCount = 0; |
|
780 setData(node, datum->owner, |
|
781 (NodeDatum::Type)datum->type, |
|
782 datum->data, datum->len); |
|
783 me = this->node(node); |
|
784 found = true; |
|
785 } |
|
786 } |
|
787 Q_ASSERT(found); |
|
788 pool->free(list); |
|
789 } else if(removed == me->dataCount) { |
|
790 // Easy! |
|
791 me->dataCount = 0; |
|
792 pool->free(list); |
|
793 } else { |
|
794 // Some removed |
|
795 unsigned int * newList = list; |
|
796 unsigned int allocatedListSize = pool->size_of(list) / |
|
797 sizeof(unsigned int); |
|
798 unsigned int newListSize = shrunkListSize(allocatedListSize, |
|
799 me->dataCount - removed); |
|
800 if(newListSize != allocatedListSize) { |
|
801 newList = (unsigned int *)pool->malloc(newListSize * |
|
802 sizeof(unsigned int)); |
|
803 } else { |
|
804 newList = list; |
|
805 } |
|
806 |
|
807 unsigned int newListCntr = 0; |
|
808 for(int ii = 0; ii < me->dataCount; ++ii) { |
|
809 if(list[ii] != 0xFFFFFFFF) |
|
810 newList[newListCntr++] = list[ii]; |
|
811 } |
|
812 |
|
813 me->dataCount = me->dataCount - removed; |
|
814 if(list != newList) { |
|
815 pool->free(list); |
|
816 *((unsigned int *)me->dataBegin()) = ptr(newList); |
|
817 } |
|
818 } |
|
819 } |
|
820 } |
|
821 |
|
822 // Attempt watch cleanup |
|
823 if(1 == me->watchCount) { |
|
824 NodeWatch * watch = (NodeWatch *)me->watchBegin(); |
|
825 if(watch->data1 == owner.data1 && |
|
826 (owner.data2 == 0xFFFFFFFF || watch->data2 == owner.data2)) |
|
827 me->watchCount = 0; |
|
828 |
|
829 } else if(me->watchCount > 1) { |
|
830 // Watch list time... |
|
831 NodeWatch * watch = |
|
832 (NodeWatch *)fromPtr(*(unsigned int *)me->watchBegin()); |
|
833 |
|
834 unsigned int lastSpot = 0; |
|
835 unsigned int watchers = 0; |
|
836 for(unsigned int ii = 0; ii < me->watchCount; ++ii) { |
|
837 if(watch[ii].data1 == owner.data1 && |
|
838 (owner.data2 == 0xFFFFFFFF || watch[ii].data2 == owner.data2)) { |
|
839 // Do nothing |
|
840 } else { |
|
841 ++watchers; |
|
842 if(ii != lastSpot) |
|
843 watch[lastSpot] = watch[ii]; |
|
844 ++lastSpot; |
|
845 } |
|
846 } |
|
847 |
|
848 if(watchers == me->watchCount) { |
|
849 // Nothing to do |
|
850 } else if(0 == watchers) { |
|
851 // Remove list and set watchCount appropriately |
|
852 pool->free(watch); |
|
853 me->watchCount = 0; |
|
854 } else if(1 == watchers) { |
|
855 // Set in main node |
|
856 me->watchCount = 0; |
|
857 setWatch(node, watch[0]); |
|
858 pool->free(watch); |
|
859 Q_ASSERT(1 == me->watchCount); |
|
860 } else { |
|
861 // Check if we need to shrink the list |
|
862 unsigned int allocatedLength = pool->size_of(watch) / sizeof(NodeWatch); |
|
863 unsigned int newLength = shrunkListSize(allocatedLength, watchers); |
|
864 if(newLength != allocatedLength) { |
|
865 NodeWatch * newList = |
|
866 (NodeWatch *)pool->malloc(sizeof(NodeWatch) * newLength); |
|
867 ::memcpy(newList, watch, sizeof(NodeWatch) * watchers); |
|
868 *(unsigned int *)me->watchBegin() = ptr(newList); |
|
869 pool->free(watch); |
|
870 } |
|
871 me->watchCount = watchers; |
|
872 } |
|
873 } |
|
874 |
|
875 if(!me->valid() && node != ROOT_VERSION_ENTRY) { |
|
876 // Remove me :( |
|
877 VersionTable::Entry * const entry = |
|
878 &(versionTable()->entries[node]); |
|
879 entry->nxtFreeBlk = versionTable()->nxtFreeBlk; |
|
880 versionTable()->nxtFreeBlk = node; |
|
881 pool->free(me); |
|
882 bump(node); |
|
883 return node; |
|
884 } else if(removedAny != INVALID_HANDLE) { |
|
885 bump(node); |
|
886 } |
|
887 |
|
888 return removedAny; |
|
889 } |
|
890 |
|
891 /*! |
|
892 Removes sub node number \a subNodeNumber from \a from's sub node list. Does |
|
893 bump \a from's version number. Does not touch removed sub node. |
|
894 */ |
|
895 void FixedMemoryTree::removeFrom(unsigned short from, |
|
896 unsigned short subNodeNumber) |
|
897 { |
|
898 Node * const me = node(from); |
|
899 |
|
900 Q_ASSERT(subNodeNumber < me->subNodes); |
|
901 |
|
902 unsigned short * const subNodes = |
|
903 (unsigned short *)fromPtr(me->subNodePtr); |
|
904 |
|
905 unsigned int currentSize = pool->size_of(subNodes) / sizeof(unsigned short); |
|
906 unsigned int scaleSize = shrunkListSize(currentSize, me->subNodes - 1); |
|
907 if(scaleSize != currentSize) { |
|
908 // Resize |
|
909 unsigned short * newSubNodes = |
|
910 (unsigned short *)pool->malloc(scaleSize * sizeof(unsigned short)); |
|
911 ::memcpy(newSubNodes, subNodes, subNodeNumber * sizeof(unsigned short)); |
|
912 ::memcpy(newSubNodes + subNodeNumber, subNodes + subNodeNumber + 1, |
|
913 (me->subNodes - subNodeNumber - 1) * sizeof(unsigned short)); |
|
914 me->subNodePtr = ptr(newSubNodes); |
|
915 pool->free(subNodes); |
|
916 } else { |
|
917 // Do not resize |
|
918 ::memmove(subNodes + subNodeNumber, subNodes + subNodeNumber + 1, |
|
919 (me->subNodes - subNodeNumber - 1) * sizeof(unsigned short)); |
|
920 } |
|
921 --me->subNodes; |
|
922 |
|
923 // Bump version number |
|
924 bump(from); |
|
925 } |
|
926 |
|
927 bool FixedMemoryTree::remWatchRecur(unsigned short node, const char * path, |
|
928 NodeWatch owner) |
|
929 { |
|
930 // Locate end of section |
|
931 const char * endOfSection = path; |
|
932 while(*endOfSection != '/' && *endOfSection != '\0') ++endOfSection; |
|
933 unsigned int sectionLen = (endOfSection - path); |
|
934 |
|
935 Node * const me = this->node(node); |
|
936 bool match; |
|
937 unsigned int matchId = locateInNode(me, path, sectionLen, &match); |
|
938 Q_ASSERT((match && matchId < me->subNodes) || |
|
939 (!match && matchId <= me->subNodes)); |
|
940 |
|
941 if(!match) |
|
942 return false; |
|
943 |
|
944 unsigned short * const subNodes = |
|
945 (unsigned short *)fromPtr(me->subNodePtr); |
|
946 |
|
947 if('\0' == *endOfSection) { |
|
948 unsigned int id = subNodes[matchId]; |
|
949 |
|
950 // We must remove this node |
|
951 if(remWatch((unsigned short)id, owner)) { |
|
952 bump(node); |
|
953 Node * them = this->node(id); |
|
954 if(!them->valid()) { |
|
955 // Remove from node list |
|
956 removeFrom(node, matchId); |
|
957 return true; |
|
958 } |
|
959 return false; |
|
960 } |
|
961 return false; |
|
962 } else { |
|
963 ++endOfSection; |
|
964 bool rv = remWatchRecur((unsigned short)subNodes[matchId], endOfSection, owner); |
|
965 |
|
966 if(rv) { |
|
967 bump(node); |
|
968 Node * const subNode = this->node(subNodes[matchId]); |
|
969 if(!subNode->valid()) { |
|
970 // Remove this one too |
|
971 if(subNode->subNodePtr) |
|
972 pool->free(fromPtr(subNode->subNodePtr)); |
|
973 pool->free(subNode); |
|
974 removeFrom(node, matchId); |
|
975 } |
|
976 } |
|
977 return rv; |
|
978 } |
|
979 } |
|
980 |
|
981 bool FixedMemoryTree::removeRecur(unsigned short node, const char * path, |
|
982 NodeOwner owner) |
|
983 { |
|
984 // Locate end of section |
|
985 const char * endOfSection = path; |
|
986 while(*endOfSection != '/' && *endOfSection != '\0') ++endOfSection; |
|
987 unsigned int sectionLen = (endOfSection - path); |
|
988 |
|
989 Node * const me = this->node(node); |
|
990 bool match; |
|
991 unsigned int matchId = locateInNode(me, path, sectionLen, &match); |
|
992 Q_ASSERT((match && matchId < me->subNodes) || |
|
993 (!match && matchId <= me->subNodes)); |
|
994 |
|
995 if(!match) |
|
996 return false; |
|
997 |
|
998 unsigned short * const subNodes = |
|
999 (unsigned short *)fromPtr(me->subNodePtr); |
|
1000 |
|
1001 if('\0' == *endOfSection) { |
|
1002 |
|
1003 unsigned int id = subNodes[matchId]; |
|
1004 |
|
1005 // We must remove this node |
|
1006 unsigned short removeId = removeRecur(id, owner); |
|
1007 |
|
1008 if(removeId == id) { |
|
1009 // Remove from node list |
|
1010 removeFrom(node, matchId); |
|
1011 // Bump my version |
|
1012 bump(node); |
|
1013 return true; |
|
1014 } else if(INVALID_HANDLE != removeId) { |
|
1015 // Bump my version |
|
1016 bump(node); |
|
1017 return true; |
|
1018 } else { |
|
1019 return false; |
|
1020 } |
|
1021 } else { |
|
1022 ++endOfSection; |
|
1023 bool rv = removeRecur(subNodes[matchId], endOfSection, owner); |
|
1024 if(rv) { |
|
1025 bump(node); |
|
1026 Node * const subNode = this->node(subNodes[matchId]); |
|
1027 if(!subNode->valid()) { |
|
1028 // Remove this one too |
|
1029 if(subNode->subNodePtr) |
|
1030 pool->free(fromPtr(subNode->subNodePtr)); |
|
1031 pool->free(subNode); |
|
1032 removeFrom(node, matchId); |
|
1033 } |
|
1034 } |
|
1035 return rv; |
|
1036 } |
|
1037 } |
|
1038 |
|
1039 /*! |
|
1040 Removes \a owner as a watch on \a node. Returns true if owner was removed, |
|
1041 false if owner was not a watch. |
|
1042 */ |
|
1043 bool FixedMemoryTree::remWatch(unsigned short node, NodeWatch owner) |
|
1044 { |
|
1045 Node * me = this->node(node); |
|
1046 |
|
1047 if(0 == me->watchCount) { |
|
1048 return false; |
|
1049 } else if(1 == me->watchCount) { |
|
1050 NodeWatch * watch = (NodeWatch *)me->watchBegin(); |
|
1051 if(*watch == owner) { |
|
1052 me->watchCount = 0; |
|
1053 return true; |
|
1054 } else { |
|
1055 return false; |
|
1056 } |
|
1057 } else if(me->watchCount == 2) { |
|
1058 NodeWatch * list = (NodeWatch *)fromPtr(*(unsigned int *)me->watchBegin()); |
|
1059 for(int ii = 0; ii < me->watchCount; ++ii) { |
|
1060 if(list[ii] == owner) { |
|
1061 // Found! |
|
1062 int remaining = (ii = 0)?1:0; |
|
1063 me->watchCount = 0; |
|
1064 setWatch(node, list[remaining]); |
|
1065 pool->free(list); |
|
1066 return true; |
|
1067 } |
|
1068 } |
|
1069 return false; |
|
1070 } else if(me->watchCount > 2) { |
|
1071 NodeWatch * list = (NodeWatch *)fromPtr(*(unsigned int *)me->watchBegin()); |
|
1072 for(unsigned short ii = 0; ii < me->watchCount; ++ii) { |
|
1073 if(list[ii] == owner) { |
|
1074 // Found! |
|
1075 unsigned int currentListSize = |
|
1076 pool->size_of(list) / sizeof(NodeWatch); |
|
1077 unsigned int newListSize = |
|
1078 shrunkListSize(currentListSize, me->watchCount - 1); |
|
1079 if(currentListSize != newListSize) { |
|
1080 // Create a new list |
|
1081 NodeWatch *newList = (NodeWatch *)pool->malloc(newListSize * sizeof(NodeWatch)); |
|
1082 ::memcpy(newList, list, ii * sizeof(NodeWatch)); |
|
1083 ::memcpy(newList + ii, list + ii + 1, |
|
1084 (me->watchCount - 1 - ii) * sizeof(NodeWatch)); |
|
1085 *(unsigned int *)me->watchBegin() = ptr(newList); |
|
1086 pool->free(list); |
|
1087 } else { |
|
1088 // Simply left shift everything |
|
1089 ::memmove(list + ii, list + ii + 1, |
|
1090 (me->watchCount - 1 - ii) * sizeof(NodeWatch)); |
|
1091 } |
|
1092 return true; |
|
1093 } |
|
1094 } |
|
1095 } |
|
1096 |
|
1097 return false; |
|
1098 } |
|
1099 |
|
1100 /*! |
|
1101 Inserts \a owner as a watch on \a node. |
|
1102 */ |
|
1103 bool FixedMemoryTree::setWatch(unsigned short node, NodeWatch owner) |
|
1104 { |
|
1105 Node * me = this->node(node); |
|
1106 |
|
1107 /* |
|
1108 if 0 == node->watchCount |
|
1109 add to end of node |
|
1110 else if 1 == node->watchCount |
|
1111 move existing watch into new watch list and append to list |
|
1112 else |
|
1113 append to existing watch list |
|
1114 */ |
|
1115 |
|
1116 if(0 == me->watchCount) { |
|
1117 unsigned int spareLen = pool->size_of(me) - me->size(); |
|
1118 |
|
1119 if(spareLen < sizeof(NodeWatch)) { |
|
1120 // Need a new node |
|
1121 Node * newNode = |
|
1122 (Node *)pool->malloc(me->size() + sizeof(NodeWatch)); |
|
1123 ::memcpy(newNode, me, me->size()); |
|
1124 versionTable()->entries[node].nodePtr = ptr(newNode); |
|
1125 pool->free(me); |
|
1126 me = newNode; |
|
1127 } |
|
1128 me->watchCount = 1; |
|
1129 *(NodeWatch *)(me->watchBegin()) = owner; |
|
1130 } else if(1 == me->watchCount) { |
|
1131 // Need to create a list |
|
1132 NodeWatch * list = (NodeWatch *)pool->malloc(2 * sizeof(NodeWatch)); |
|
1133 list[0] = *(NodeWatch *)(me->watchBegin()); |
|
1134 list[1] = owner; |
|
1135 *(unsigned int *)(me->watchBegin()) = ptr(list); |
|
1136 ++me->watchCount; |
|
1137 } else { |
|
1138 // Append to list |
|
1139 NodeWatch * list = (NodeWatch *)fromPtr(*(unsigned int *)me->watchBegin()); |
|
1140 int availableSize = pool->size_of(list) / sizeof(NodeWatch); |
|
1141 if(availableSize < me->watchCount + 1) { |
|
1142 // Reallocate |
|
1143 NodeWatch * newList = |
|
1144 (NodeWatch *)pool->malloc(growListSize(availableSize) * |
|
1145 sizeof(NodeWatch)); |
|
1146 ::memcpy(newList, list, me->watchCount * sizeof(NodeWatch)); |
|
1147 pool->free(list); |
|
1148 list = newList; |
|
1149 *(unsigned int *)me->watchBegin() = ptr(newList); |
|
1150 } |
|
1151 list[me->watchCount] = owner; |
|
1152 ++me->watchCount; |
|
1153 } |
|
1154 return true; |
|
1155 } |
|
1156 |
|
1157 /*! |
|
1158 Inserts \a data of length \a dataLen into \a node. Returns true if the |
|
1159 version number of \a node has increased to handle this set. |
|
1160 */ |
|
1161 bool FixedMemoryTree::setData(unsigned short node, |
|
1162 NodeOwner owner, |
|
1163 NodeDatum::Type type, |
|
1164 const char * data, |
|
1165 unsigned int dataLen) |
|
1166 { |
|
1167 Q_ASSERT(!dataLen || data); |
|
1168 |
|
1169 Node * me = this->node(node); |
|
1170 |
|
1171 /* |
|
1172 if 0 == node->dataCount |
|
1173 insert directly into node |
|
1174 else if 1 == node->dataCount && node->dataOwner == owner |
|
1175 insert directly into node |
|
1176 else if 1 == node->dataCount |
|
1177 move existing data into new data list and append new data to list |
|
1178 else |
|
1179 locate or append data to existing data list |
|
1180 */ |
|
1181 |
|
1182 if (0 == me->dataCount || |
|
1183 (1 == me->dataCount && ((NodeDatum *)me->dataBegin())->owner == owner)) { |
|
1184 unsigned int allocatedDataLen = |
|
1185 pool->size_of(me) - |
|
1186 sizeof(Node) - |
|
1187 me->watchBlockSize() - |
|
1188 ALIGN4b(me->nameLen); |
|
1189 |
|
1190 if(allocatedDataLen > sizeof(NodeDatum)) |
|
1191 allocatedDataLen -= sizeof(NodeDatum); |
|
1192 else |
|
1193 allocatedDataLen = 0; |
|
1194 |
|
1195 if(dataLen <= allocatedDataLen) { |
|
1196 // Sweet, reuse existing |
|
1197 NodeDatum * datum = (NodeDatum *)me->dataBegin(); |
|
1198 datum->owner = owner; |
|
1199 datum->type = type; |
|
1200 if(me->watchBlockSize()) |
|
1201 ::memcpy(datum->data + ALIGN4b(dataLen), me->watchBegin(), |
|
1202 me->watchBlockSize()); |
|
1203 datum->len = dataLen; |
|
1204 ::memcpy(datum->data, data, dataLen); |
|
1205 me->dataCount = 1; |
|
1206 } else { |
|
1207 // Need new node |
|
1208 Node * newNode = |
|
1209 (Node *)pool->malloc(sizeof(Node) + ALIGN4b(me->nameLen) + |
|
1210 sizeof(NodeDatum) + ALIGN4b(dataLen) + |
|
1211 me->watchBlockSize()); |
|
1212 ::memcpy(newNode, me, sizeof(Node) + ALIGN4b(me->nameLen)); |
|
1213 versionTable()->entries[node].nodePtr = ptr(newNode); |
|
1214 |
|
1215 NodeDatum * datum = (NodeDatum *)newNode->dataBegin(); |
|
1216 datum->owner = owner; |
|
1217 datum->type = type; |
|
1218 if(me->watchBlockSize()) |
|
1219 ::memcpy(datum->data + ALIGN4b(dataLen), me->watchBegin(), |
|
1220 me->watchBlockSize()); |
|
1221 datum->len = dataLen; |
|
1222 ::memcpy(datum->data, data, dataLen); |
|
1223 me->dataCount = 1; |
|
1224 pool->free(me); |
|
1225 me = newNode; |
|
1226 } |
|
1227 |
|
1228 bump(node); |
|
1229 |
|
1230 return true; |
|
1231 } else if(1 == me->dataCount) { |
|
1232 // Damn, need to create a value chain list |
|
1233 NodeDatum * existingDatum = (NodeDatum *)me->dataBegin(); |
|
1234 unsigned int * list = |
|
1235 (unsigned int *)pool->malloc(2 * sizeof(unsigned int)); |
|
1236 NodeDatum * currentDatum = |
|
1237 (NodeDatum *)pool->malloc(sizeof(NodeDatum) + existingDatum->len); |
|
1238 NodeDatum * newDatum = |
|
1239 (NodeDatum *)pool->malloc(sizeof(NodeDatum) + dataLen); |
|
1240 list[0] = ptr(currentDatum); |
|
1241 list[1] = ptr(newDatum); |
|
1242 |
|
1243 // Copy existing data |
|
1244 ::memcpy(currentDatum, existingDatum, |
|
1245 sizeof(NodeDatum) + existingDatum->len); |
|
1246 // Copy new data |
|
1247 newDatum->owner = owner; |
|
1248 newDatum->type = type; |
|
1249 newDatum->len = dataLen; |
|
1250 ::memcpy(newDatum->data, data, dataLen); |
|
1251 if(me->watchBlockSize()) |
|
1252 ::memcpy(((unsigned int *)me->dataBegin()) + 1, me->watchBegin(), |
|
1253 me->watchBlockSize()); |
|
1254 // Add value chain list to node |
|
1255 *(unsigned int *)me->dataBegin() = ptr(list); |
|
1256 me->dataCount = 2; |
|
1257 return false; |
|
1258 } else { |
|
1259 // Attempt to locate in existing chain |
|
1260 unsigned int * list = |
|
1261 (unsigned int *)fromPtr(*(unsigned int *)me->dataBegin()); |
|
1262 for(int ii = 0; ii < me->dataCount; ++ii) { |
|
1263 NodeDatum * ndata = (NodeDatum *)fromPtr(list[ii]); |
|
1264 if(ndata->owner == owner) { |
|
1265 // Found - but is it big enough? |
|
1266 unsigned int allocatedDataLen = |
|
1267 pool->size_of(ndata) - sizeof(NodeDatum); |
|
1268 if(allocatedDataLen >= dataLen) { |
|
1269 // Copy over the top |
|
1270 ::memcpy(ndata->data, data, dataLen); |
|
1271 ndata->len = dataLen; |
|
1272 ndata->type = type; |
|
1273 } else { |
|
1274 // Reallocate |
|
1275 NodeDatum * newData = |
|
1276 (NodeDatum *)pool->malloc(sizeof(NodeDatum) + |
|
1277 dataLen); |
|
1278 newData->owner = owner; |
|
1279 newData->type = type; |
|
1280 newData->len = dataLen; |
|
1281 ::memcpy(newData->data, data, dataLen); |
|
1282 list[ii] = ptr(newData); |
|
1283 pool->free(ndata); |
|
1284 } |
|
1285 return ii == 0; |
|
1286 } |
|
1287 } |
|
1288 |
|
1289 // Not found - append |
|
1290 unsigned int allocatedListLen = |
|
1291 pool->size_of(list) / sizeof(unsigned int); |
|
1292 if(allocatedListLen >= (unsigned int)me->dataCount + 1) { |
|
1293 // We fit! |
|
1294 } else { |
|
1295 // We don't fit |
|
1296 unsigned int * newList = |
|
1297 (unsigned int *)pool->malloc(growListSize(allocatedListLen) * |
|
1298 sizeof(unsigned int)); |
|
1299 ::memcpy(newList, list, allocatedListLen * sizeof(unsigned int)); |
|
1300 pool->free(list); |
|
1301 list = newList; |
|
1302 *(unsigned int *)me->dataBegin() = ptr(newList); |
|
1303 } |
|
1304 |
|
1305 NodeDatum * datum = (NodeDatum *)pool->malloc(sizeof(NodeDatum) + |
|
1306 dataLen); |
|
1307 datum->owner = owner; |
|
1308 datum->len = dataLen; |
|
1309 datum->type = type; |
|
1310 ::memcpy(datum->data, data, dataLen); |
|
1311 list[me->dataCount] = ptr(datum); |
|
1312 ++me->dataCount; |
|
1313 |
|
1314 return false; |
|
1315 } |
|
1316 } |
|
1317 |
|
1318 bool FixedMemoryTree::addWatchRecur(unsigned short node, const char * path, |
|
1319 NodeWatch owner) |
|
1320 { |
|
1321 // Locate end of section |
|
1322 const char * endOfSection = path; |
|
1323 while(*endOfSection != '/' && *endOfSection != '\0') ++endOfSection; |
|
1324 const unsigned int sectionLen = (endOfSection - path); |
|
1325 |
|
1326 // We operate on structures, not numbers |
|
1327 Node * const me = this->node(node); |
|
1328 unsigned short * subNodes = |
|
1329 me->subNodePtr?(unsigned short *)fromPtr(me->subNodePtr):0; |
|
1330 |
|
1331 // Attempt to locate the sub node within the current node |
|
1332 bool match; |
|
1333 const unsigned int matchId = locateInNode(me, path, sectionLen, &match); |
|
1334 Q_ASSERT((match && matchId < me->subNodes) || |
|
1335 (!match && matchId <= me->subNodes)); |
|
1336 |
|
1337 if(match) { |
|
1338 |
|
1339 // There is a sub node of the correct name |
|
1340 const unsigned short id = subNodes[matchId]; |
|
1341 |
|
1342 if('\0' == *endOfSection) { |
|
1343 // Update the node. Bumps *their* version if necessary. |
|
1344 bool rv = setWatch(id, owner); |
|
1345 if(rv) bump(node); |
|
1346 return rv; |
|
1347 } |
|
1348 ++endOfSection; |
|
1349 |
|
1350 bool rv = addWatchRecur(id, endOfSection, owner); |
|
1351 if(rv) bump(node); |
|
1352 return rv; |
|
1353 |
|
1354 } else { /* !match */ |
|
1355 |
|
1356 // We *may* need to lengthen our list |
|
1357 unsigned short maxSubNodesLen = subNodes? |
|
1358 pool->size_of(subNodes) / sizeof(unsigned short):0; |
|
1359 unsigned int newSubNode = 0; |
|
1360 |
|
1361 if('\0' == *endOfSection) |
|
1362 newSubNode = newNode(path, sectionLen, owner); |
|
1363 else |
|
1364 newSubNode = newNode(path, sectionLen); |
|
1365 |
|
1366 if (newSubNode == ROOT_VERSION_ENTRY) |
|
1367 return false; |
|
1368 |
|
1369 Node * const newNode = this->node(newSubNode); |
|
1370 newNode->parent = node; |
|
1371 |
|
1372 if(maxSubNodesLen < me->subNodes + 1) { |
|
1373 // Grow list |
|
1374 unsigned short * newSubNodes = |
|
1375 (unsigned short *)pool->malloc(growListSize(me->subNodes) * |
|
1376 sizeof(unsigned short)); |
|
1377 ::memcpy(newSubNodes, subNodes, matchId * sizeof(unsigned short)); |
|
1378 ::memcpy(newSubNodes + matchId + 1, subNodes + matchId, |
|
1379 (me->subNodes - matchId) * sizeof(unsigned short)); |
|
1380 pool->free(fromPtr(me->subNodePtr)); |
|
1381 me->subNodePtr = ptr(newSubNodes); |
|
1382 subNodes = newSubNodes; |
|
1383 } else { |
|
1384 // Split list |
|
1385 ::memmove(subNodes + matchId + 1, subNodes + matchId, |
|
1386 (me->subNodes - matchId) * sizeof(unsigned short)); |
|
1387 } |
|
1388 subNodes[matchId] = newSubNode; |
|
1389 ++me->subNodes; |
|
1390 |
|
1391 // Bump my version |
|
1392 bump(node); |
|
1393 |
|
1394 if('\0' != *endOfSection) { |
|
1395 ++endOfSection; |
|
1396 addWatchRecur(newSubNode, endOfSection, owner); |
|
1397 } |
|
1398 return true; |
|
1399 } |
|
1400 } |
|
1401 |
|
1402 /*! |
|
1403 Returns true if the insert should force a version bump. |
|
1404 */ |
|
1405 bool FixedMemoryTree::insertRecur(unsigned short node, |
|
1406 const char * path, |
|
1407 NodeDatum::Type type, |
|
1408 const char * data, |
|
1409 unsigned int dataLen, |
|
1410 NodeOwner owner) |
|
1411 { |
|
1412 // Locate end of section |
|
1413 const char * endOfSection = path; |
|
1414 while(*endOfSection != '/' && *endOfSection != '\0') ++endOfSection; |
|
1415 const unsigned int sectionLen = (endOfSection - path); |
|
1416 |
|
1417 // We operate on structures, not numbers |
|
1418 Node * const me = this->node(node); |
|
1419 unsigned short * subNodes = |
|
1420 me->subNodePtr?(unsigned short *)fromPtr(me->subNodePtr):0; |
|
1421 |
|
1422 // Attempt to locate the sub node within the current node |
|
1423 bool match; |
|
1424 const unsigned int matchId = locateInNode(me, path, sectionLen, &match); |
|
1425 Q_ASSERT((match && matchId < me->subNodes) || |
|
1426 (!match && matchId <= me->subNodes)); |
|
1427 |
|
1428 if(match) { |
|
1429 |
|
1430 // There is a sub node of the correct name |
|
1431 const unsigned short id = subNodes[matchId]; |
|
1432 |
|
1433 if('\0' == *endOfSection) { |
|
1434 // Update the node. Bumps *their* version if necessary. |
|
1435 bool rv = setData(id, owner, type, data, dataLen); |
|
1436 if(rv) bump(node); |
|
1437 return rv; |
|
1438 } |
|
1439 ++endOfSection; |
|
1440 |
|
1441 bool rv = insertRecur(id, endOfSection, type, data, dataLen, owner); |
|
1442 if(rv) bump(node); |
|
1443 return rv; |
|
1444 |
|
1445 } else { /* !match */ |
|
1446 |
|
1447 // We *may* need to lengthen our list |
|
1448 unsigned short maxSubNodesLen = subNodes? |
|
1449 pool->size_of(subNodes) / sizeof(unsigned short):0; |
|
1450 unsigned int newSubNode = 0; |
|
1451 |
|
1452 if('\0' == *endOfSection) |
|
1453 newSubNode = newNode(path, sectionLen, owner, type, data, dataLen); |
|
1454 else |
|
1455 newSubNode = newNode(path, sectionLen); |
|
1456 |
|
1457 if (newSubNode == ROOT_VERSION_ENTRY) |
|
1458 return false; |
|
1459 |
|
1460 Node * const newNode = this->node(newSubNode); |
|
1461 newNode->parent = node; |
|
1462 |
|
1463 if(maxSubNodesLen < me->subNodes + 1) { |
|
1464 // Grow list |
|
1465 unsigned short * newSubNodes = |
|
1466 (unsigned short *)pool->malloc(growListSize(me->subNodes) * |
|
1467 sizeof(unsigned short)); |
|
1468 ::memcpy(newSubNodes, subNodes, matchId * sizeof(unsigned short)); |
|
1469 ::memcpy(newSubNodes + matchId + 1, subNodes + matchId, |
|
1470 (me->subNodes - matchId) * sizeof(unsigned short)); |
|
1471 pool->free(fromPtr(me->subNodePtr)); |
|
1472 me->subNodePtr = ptr(newSubNodes); |
|
1473 subNodes = newSubNodes; |
|
1474 } else { |
|
1475 // Split list |
|
1476 ::memmove(subNodes + matchId + 1, subNodes + matchId, |
|
1477 (me->subNodes - matchId) * sizeof(unsigned short)); |
|
1478 } |
|
1479 subNodes[matchId] = newSubNode; |
|
1480 ++me->subNodes; |
|
1481 |
|
1482 // Bump my version |
|
1483 bump(node); |
|
1484 |
|
1485 if('\0' != *endOfSection) { |
|
1486 ++endOfSection; |
|
1487 insertRecur(newSubNode, endOfSection, type, data, dataLen, owner); |
|
1488 } |
|
1489 return true; |
|
1490 } |
|
1491 } |
|
1492 |
|
1493 VersionTable * FixedMemoryTree::versionTable() |
|
1494 { |
|
1495 return (VersionTable *)poolMem; |
|
1496 } |
|
1497 |
|
1498 void * FixedMemoryTree::fromPtr(unsigned int ptr) |
|
1499 { |
|
1500 if(!ptr) |
|
1501 return 0; |
|
1502 return (void *)(poolMem + ptr); |
|
1503 } |
|
1504 |
|
1505 void FixedMemoryTree::setNodeChangeFunction(NodeChangeFunction func, void *ctxt) |
|
1506 { |
|
1507 changeFunc = func; |
|
1508 changeFuncContext = ctxt; |
|
1509 } |
|
1510 |
|
1511 unsigned int FixedMemoryTree::ptr(void * mem) |
|
1512 { |
|
1513 Q_ASSERT(mem > poolMem); |
|
1514 return (unsigned int)((char *)mem - poolMem); |
|
1515 } |
|
1516 |
|
1517 /*! Increment \a node's version number */ |
|
1518 void FixedMemoryTree::bump(unsigned short node) |
|
1519 { |
|
1520 ++(versionTable()->entries[node].version); |
|
1521 if(changeFunc) |
|
1522 changeFunc(node, changeFuncContext); |
|
1523 } |
|
1524 |
|
1525 Node * FixedMemoryTree::node(unsigned int entry) |
|
1526 { |
|
1527 Q_ASSERT(entry < VERSION_TABLE_ENTRIES); |
|
1528 return (Node *)fromPtr(versionTable()->entries[entry].nodePtr); |
|
1529 } |
|
1530 |
|
1531 /*! Returns the node identified by \a entry, or null if there is no node in that |
|
1532 slot. This is different to FixedMemoryTree::node() in that it checks the |
|
1533 return value (and is thus slower). |
|
1534 */ |
|
1535 Node * FixedMemoryTree::getNode(unsigned int entry) |
|
1536 { |
|
1537 Q_ASSERT(entry < VERSION_TABLE_ENTRIES); |
|
1538 void * rv = fromPtr(versionTable()->entries[entry].nodePtr); |
|
1539 if(rv < poolMem + sizeof(VersionTable)) { |
|
1540 return 0; |
|
1541 } else { |
|
1542 return (Node *)rv; |
|
1543 } |
|
1544 } |
|
1545 |
|
1546 Node * FixedMemoryTree::subNode(unsigned int node, unsigned short sub) |
|
1547 { |
|
1548 Q_ASSERT(node < VERSION_TABLE_ENTRIES); |
|
1549 Node * me = this->node(node); |
|
1550 Q_ASSERT(sub < me->subNodes); |
|
1551 unsigned short * const subNodes = |
|
1552 (unsigned short *)fromPtr(me->subNodePtr); |
|
1553 return this->node(subNodes[sub]); |
|
1554 } |
|
1555 |
|
1556 unsigned int FixedMemoryTree::version(unsigned int entry) |
|
1557 { |
|
1558 Q_ASSERT(entry < VERSION_TABLE_ENTRIES); |
|
1559 return versionTable()->entries[entry].version; |
|
1560 } |
|
1561 |
|
1562 /*! |
|
1563 Creates a new node of \a name (name length \a len) and sets a single \a watch on it. Returns |
|
1564 ROOT_VERSION_ENTRY if the new node could not be created. |
|
1565 */ |
|
1566 unsigned short FixedMemoryTree::newNode(const char * name, unsigned int len, |
|
1567 NodeWatch owner) |
|
1568 { |
|
1569 Q_ASSERT(owner != INVALID_WATCH); |
|
1570 |
|
1571 // Find an empty node entry |
|
1572 unsigned int node = versionTable()->nxtFreeBlk; |
|
1573 if (node == ROOT_VERSION_ENTRY) |
|
1574 return node; |
|
1575 |
|
1576 // Reset the next free blk |
|
1577 versionTable()->nxtFreeBlk = versionTable()->entries[node].nxtFreeBlk; |
|
1578 |
|
1579 int nodeSize = sizeof(Node) + ALIGN4b(len) + sizeof(NodeWatch); |
|
1580 |
|
1581 // Allocate a new node |
|
1582 Node * nodePtr = (Node *)pool->malloc(nodeSize); |
|
1583 Q_ASSERT((char *)nodePtr > poolMem); |
|
1584 ::memset(nodePtr,0, sizeof(Node)); |
|
1585 nodePtr->creationId = versionTable()->nextCreationId++; |
|
1586 |
|
1587 // Setup name |
|
1588 nodePtr->nameLen = len; |
|
1589 ::memcpy(nodePtr->name, name, len); |
|
1590 |
|
1591 // Setup watch |
|
1592 nodePtr->watchCount = 1; |
|
1593 *(NodeWatch *)(nodePtr->name + ALIGN4b(len)) = owner; |
|
1594 |
|
1595 // Enter node |
|
1596 versionTable()->entries[node] = VersionTable::Entry(1, ptr(nodePtr)); |
|
1597 // Bump version |
|
1598 bump(node); |
|
1599 |
|
1600 // Done |
|
1601 return node; |
|
1602 |
|
1603 } |
|
1604 |
|
1605 /*! |
|
1606 Creates a new node of \a name (name length \a len) and pre-fills it with \a data of length |
|
1607 \a dataLen owned by \a owner. If \a owner is an invalid owner, the node is a virtual node and |
|
1608 not prefilled with data. Returns ROOT_VERSION_ENTRY if the new node could not be created. |
|
1609 */ |
|
1610 unsigned short FixedMemoryTree::newNode(const char * name, unsigned int len, |
|
1611 NodeOwner owner, NodeDatum::Type type, |
|
1612 const char * data, unsigned int dataLen) |
|
1613 { |
|
1614 Q_ASSERT(owner != INVALID_OWNER || (!data && 0 == dataLen)); |
|
1615 |
|
1616 // Find an empty node entry |
|
1617 unsigned int node = versionTable()->nxtFreeBlk; |
|
1618 if (node == ROOT_VERSION_ENTRY) |
|
1619 return node; |
|
1620 |
|
1621 // Reset the next free blk |
|
1622 versionTable()->nxtFreeBlk = versionTable()->entries[node].nxtFreeBlk; |
|
1623 |
|
1624 int nodeSize = sizeof(Node) + ALIGN4b(len); |
|
1625 if(INVALID_OWNER != owner) |
|
1626 nodeSize += sizeof(NodeDatum) + ALIGN4b(dataLen); |
|
1627 |
|
1628 // Allocate a new node |
|
1629 Node * nodePtr = (Node *)pool->malloc(nodeSize); |
|
1630 Q_ASSERT((char *)nodePtr > poolMem); |
|
1631 ::memset(nodePtr, 0, sizeof(Node)); |
|
1632 nodePtr->creationId = versionTable()->nextCreationId++; |
|
1633 |
|
1634 // Setup name |
|
1635 nodePtr->nameLen = len; |
|
1636 ::memcpy(nodePtr->name, name, len); |
|
1637 |
|
1638 if(INVALID_OWNER != owner) { |
|
1639 // Setup data |
|
1640 nodePtr->dataCount = 1; |
|
1641 NodeDatum * datum = (NodeDatum *)nodePtr->dataBegin(); |
|
1642 datum->owner = owner; |
|
1643 datum->len = dataLen; |
|
1644 datum->type = type; |
|
1645 if(dataLen) |
|
1646 ::memcpy(datum->data, data, dataLen); |
|
1647 } |
|
1648 |
|
1649 // Enter node |
|
1650 versionTable()->entries[node] = VersionTable::Entry(1, ptr(nodePtr)); |
|
1651 // Bump version |
|
1652 bump(node); |
|
1653 |
|
1654 // Done |
|
1655 return node; |
|
1656 } |
|
1657 |
|
1658 // Use aggregation/composition - the SharedMemoryLayer "has a" server socket |
|
1659 // rather than "is a" server socket - also gets around multiple inheritance |
|
1660 // issues with QObject since the QLocalServer in Qt is a QObject |
|
1661 class ALServerImpl : public QLocalServer |
|
1662 { |
|
1663 public: |
|
1664 ALServerImpl( QObject *p ) : QLocalServer( p ) {} |
|
1665 virtual ~ALServerImpl(); |
|
1666 protected: |
|
1667 virtual void incomingConnection(quintptr socketDescriptor); |
|
1668 }; |
|
1669 |
|
1670 ALServerImpl::~ALServerImpl() |
|
1671 { |
|
1672 } |
|
1673 |
|
1674 // declare SharedMemoryLayer |
|
1675 class SharedMemoryLayer : public QAbstractValueSpaceLayer |
|
1676 { |
|
1677 Q_OBJECT |
|
1678 public: |
|
1679 SharedMemoryLayer(); |
|
1680 virtual ~SharedMemoryLayer(); |
|
1681 |
|
1682 /* Common functions */ |
|
1683 QString name(); |
|
1684 |
|
1685 bool startup(Type); |
|
1686 |
|
1687 QUuid id(); |
|
1688 unsigned int order(); |
|
1689 |
|
1690 Handle item(Handle parent, const QString &); |
|
1691 void removeHandle(Handle); |
|
1692 void setProperty(Handle handle, Properties); |
|
1693 |
|
1694 bool value(Handle, QVariant *); |
|
1695 bool value(Handle, const QString &, QVariant *); |
|
1696 QSet<QString> children(Handle); |
|
1697 |
|
1698 QValueSpace::LayerOptions layerOptions() const; |
|
1699 |
|
1700 /* QValueSpaceSubscriber functions */ |
|
1701 bool supportsInterestNotification() const; |
|
1702 bool notifyInterest(Handle handle, bool interested); |
|
1703 |
|
1704 /* QValueSpacePublisher functions */ |
|
1705 bool setValue(QValueSpacePublisher *creator, Handle handle, const QString &, const QVariant &); |
|
1706 bool removeValue(QValueSpacePublisher *creator, Handle handle, const QString &); |
|
1707 bool removeSubTree(QValueSpacePublisher *creator, Handle handle); |
|
1708 void addWatch(QValueSpacePublisher *creator, Handle handle); |
|
1709 void removeWatches(QValueSpacePublisher *creator, Handle parent); |
|
1710 void sync(); |
|
1711 |
|
1712 void nodeChanged(unsigned short); |
|
1713 |
|
1714 static SharedMemoryLayer * instance(); |
|
1715 |
|
1716 private slots: |
|
1717 void disconnected(); |
|
1718 void readyRead(); |
|
1719 void closeConnections(); |
|
1720 |
|
1721 void doClientSync(); |
|
1722 |
|
1723 protected: |
|
1724 virtual void timerEvent(QTimerEvent *); |
|
1725 |
|
1726 private: |
|
1727 #ifdef QVALUESPACE_UPDATE_STATS |
|
1728 void updateStats(); |
|
1729 #else |
|
1730 inline void updateStats() {} |
|
1731 #endif |
|
1732 QList<NodeWatch> watchers(const QByteArray &); |
|
1733 void doClientEmit(); |
|
1734 void doClientTransmit(); |
|
1735 void doServerTransmit(); |
|
1736 bool doRemove(const QByteArray &path); |
|
1737 bool doWriteItem(const QByteArray &path, const QVariant &val); |
|
1738 bool setItem(NodeOwner owner, const QByteArray &path, const QVariant &val); |
|
1739 bool doSetItem(NodeOwner owner, const QByteArray &path, const QVariant &val); |
|
1740 bool remItems(NodeOwner owner, const QByteArray &path); |
|
1741 bool doRemItems(NodeOwner owner, const QByteArray &path); |
|
1742 bool setWatch(NodeWatch watch, const QByteArray &path); |
|
1743 bool doSetWatch(NodeWatch watch, const QByteArray &path); |
|
1744 bool remWatch(NodeWatch watch, const QByteArray &path); |
|
1745 bool doRemWatch(NodeWatch watch, const QByteArray &path); |
|
1746 void doNotify(const QByteArray &path, const QPacketProtocol *protocol, bool interested); |
|
1747 void doClientNotify(QValueSpacePublisher *publisher, const QByteArray &path, bool interested); |
|
1748 void doNotifyObject(unsigned long own, unsigned long protocol); |
|
1749 |
|
1750 QString socket() const; |
|
1751 |
|
1752 static QVariant fromDatum(const NodeDatum * data); |
|
1753 |
|
1754 struct ReadHandle |
|
1755 { |
|
1756 ReadHandle(const QByteArray &_path) |
|
1757 : refCount(1), path(_path), currentPath(0), |
|
1758 currentNode(INVALID_HANDLE), version(0), creationId(0), |
|
1759 forceChange(false) |
|
1760 { |
|
1761 } |
|
1762 |
|
1763 unsigned int refCount; |
|
1764 |
|
1765 /* Path this read handle is *intended* to point to */ |
|
1766 QByteArray path; |
|
1767 /* Offset into path indicating where we currently point to. 0xFFFFFFFF |
|
1768 means we point to the full path (saves path.size() call) */ |
|
1769 unsigned int currentPath; |
|
1770 /* Node we are currently pointing to. */ |
|
1771 unsigned short currentNode; |
|
1772 /* Last version of current node */ |
|
1773 unsigned int version; |
|
1774 /* Last creation Id of current node */ |
|
1775 unsigned int creationId; |
|
1776 |
|
1777 /* Indicates that version has been updated in a value() call, but |
|
1778 a change should be emitted anyway. */ |
|
1779 bool forceChange; |
|
1780 }; |
|
1781 ReadHandle * rh(QAbstractValueSpaceLayer::Handle handle) const |
|
1782 { |
|
1783 Q_ASSERT(handle && INVALID_HANDLE != handle); |
|
1784 return reinterpret_cast<ReadHandle *>(handle); |
|
1785 } |
|
1786 bool refreshHandle(ReadHandle *); |
|
1787 void clearHandle(ReadHandle *); |
|
1788 |
|
1789 QLocalServer *sserver; |
|
1790 |
|
1791 Type type; |
|
1792 FixedMemoryTree * layer; |
|
1793 QSystemReadWriteLock * lock; |
|
1794 QMutex localLock; |
|
1795 QMap<QString, ReadHandle *> handles; |
|
1796 |
|
1797 void triggerTodo(); |
|
1798 bool triggeredTodo; |
|
1799 QPacket todo; |
|
1800 QSet<QPacketProtocol *> connections; |
|
1801 |
|
1802 unsigned int newPackId() { |
|
1803 lastSentId = nextPackId++; |
|
1804 return lastSentId; |
|
1805 } |
|
1806 unsigned int nextPackId; |
|
1807 |
|
1808 unsigned int lastSentId; |
|
1809 unsigned int lastRecvId; |
|
1810 |
|
1811 bool valid; |
|
1812 friend class ALServerImpl; |
|
1813 |
|
1814 unsigned int forceChangeCount; |
|
1815 |
|
1816 uchar *clientIndex; |
|
1817 void incNode(unsigned short); |
|
1818 void decNode(unsigned short); |
|
1819 QHash<unsigned short, unsigned int> m_nodeInterest; |
|
1820 |
|
1821 |
|
1822 unsigned int changedNodesCount; |
|
1823 unsigned short changedNodes[VERSION_TABLE_ENTRIES]; |
|
1824 |
|
1825 // Stats memory |
|
1826 unsigned long *m_statPoolSize; |
|
1827 unsigned long *m_statMaxSystemBytes; |
|
1828 unsigned long *m_statSystemBytes; |
|
1829 unsigned long *m_statInuseBytes; |
|
1830 unsigned long *m_statKeepCost; |
|
1831 |
|
1832 QSharedMemory* shm; |
|
1833 QSharedMemory* subShm; |
|
1834 }; |
|
1835 |
|
1836 QVALUESPACE_AUTO_INSTALL_LAYER(SharedMemoryLayer); |
|
1837 |
|
1838 /////////////////////////////////////////////////////////////////////////////// |
|
1839 // define SharedMemoryLayer |
|
1840 /////////////////////////////////////////////////////////////////////////////// |
|
1841 #define SHMLAYER_SIZE 1000000 |
|
1842 #define SHMLAYER_ADD 0 |
|
1843 #define SHMLAYER_REM 1 |
|
1844 #define SHMLAYER_DONE 2 |
|
1845 #define SHMLAYER_ADDWATCH 5 |
|
1846 #define SHMLAYER_REMWATCH 6 |
|
1847 #define SHMLAYER_SYNC 7 |
|
1848 #define SHMLAYER_SUBINDEX 8 |
|
1849 #define SHMLAYER_NOTIFY 9 |
|
1850 |
|
1851 struct SharedMemoryLayerClient : public QPacketProtocol |
|
1852 { |
|
1853 SharedMemoryLayerClient(QIODevice *dev, QObject *parent = 0) |
|
1854 : QPacketProtocol(dev, parent), index(0) {} |
|
1855 |
|
1856 uchar *index; |
|
1857 }; |
|
1858 |
|
1859 SharedMemoryLayer::SharedMemoryLayer() |
|
1860 : type(Client), layer(0), lock(0), localLock(QMutex::Recursive), triggeredTodo(false), |
|
1861 nextPackId(1), lastSentId(0), lastRecvId(0), valid(false), |
|
1862 forceChangeCount(0), clientIndex(0), |
|
1863 changedNodesCount(0), |
|
1864 m_statPoolSize(0), m_statMaxSystemBytes(0), m_statSystemBytes(0), |
|
1865 m_statInuseBytes(0), m_statKeepCost(0), shm(0), subShm(0) |
|
1866 { |
|
1867 sserver = new ALServerImpl( this ); |
|
1868 |
|
1869 connect(qApp, SIGNAL(destroyed()), this, SLOT(closeConnections())); |
|
1870 } |
|
1871 |
|
1872 SharedMemoryLayer::~SharedMemoryLayer() |
|
1873 { |
|
1874 if(Server == type) { |
|
1875 delete lock; |
|
1876 lock = 0; |
|
1877 } |
|
1878 } |
|
1879 |
|
1880 QString SharedMemoryLayer::name() |
|
1881 { |
|
1882 return QLatin1String("Shared Memory Layer"); |
|
1883 } |
|
1884 |
|
1885 static void ShmLayerNodeChanged(unsigned short, void *); |
|
1886 bool SharedMemoryLayer::startup(Type type) |
|
1887 { |
|
1888 QMutexLocker locker(&localLock); |
|
1889 |
|
1890 valid = false; |
|
1891 |
|
1892 Q_ASSERT(!layer); |
|
1893 if(Server == type) { |
|
1894 if(!sserver->listen(socket())) { |
|
1895 qWarning() << "SharedMemoryLayer: Unable to create server socket. Only " |
|
1896 "local connections will be allowed." << sserver->errorString(); |
|
1897 } |
|
1898 } else { |
|
1899 QLocalSocket * sock = new QLocalSocket; |
|
1900 sock->connectToServer(socket()); |
|
1901 if(!sock->waitForConnected(1000)) { |
|
1902 qWarning("SharedMemoryLayer: Unable to connect to server, " |
|
1903 "shared memory layer will be disabled."); |
|
1904 delete sock; |
|
1905 return false; |
|
1906 } |
|
1907 |
|
1908 QPacketProtocol * protocol; |
|
1909 protocol = new QPacketProtocol(sock, this); |
|
1910 sock->setParent(protocol); |
|
1911 |
|
1912 QObject::connect(sock, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)), |
|
1913 protocol, SIGNAL(invalidPacket())); |
|
1914 QObject::connect(protocol, SIGNAL(invalidPacket()), |
|
1915 this, SLOT(disconnected())); |
|
1916 QObject::connect(protocol, SIGNAL(readyRead()), |
|
1917 this, SLOT(readyRead())); |
|
1918 |
|
1919 connections.insert(protocol); |
|
1920 } |
|
1921 |
|
1922 if(Server == type) { |
|
1923 shm = new QSharedMemory(socket(), this); |
|
1924 bool created = shm->create(SHMLAYER_SIZE); |
|
1925 if (!created) { |
|
1926 //qDebug() << "Reattaching to existing memory"; |
|
1927 shm->attach(); |
|
1928 } |
|
1929 lock = new QSystemReadWriteLock(socket() + "_lock", QSystemReadWriteLock::Create); |
|
1930 } else { |
|
1931 shm = new QSharedMemory(socket(), this); |
|
1932 shm->attach(QSharedMemory::ReadOnly); |
|
1933 qsrand(QTime(0,0,0).secsTo(QTime::currentTime())+QCoreApplication::applicationPid()); |
|
1934 subShm = new QSharedMemory(socket()+QString::number(qrand()), this); |
|
1935 if (!subShm->create((VERSION_TABLE_ENTRIES + 7) / 8, QSharedMemory::ReadWrite)) { |
|
1936 qWarning() << "SharedMemoryLayer client cannot create clientIndex:" |
|
1937 << subShm->errorString() << subShm->key(); |
|
1938 } |
|
1939 |
|
1940 lock = new QSystemReadWriteLock(socket() + "_lock", QSystemReadWriteLock::Open); |
|
1941 } |
|
1942 |
|
1943 if (shm->error() != QSharedMemory::NoError || |
|
1944 ((!subShm || subShm->error()!= QSharedMemory::NoError) && Server != type)) { |
|
1945 qFatal("SharedMemoryLayer: Unable to create or access shared resources. (%s - %s)", |
|
1946 shm->errorString().toLatin1().constData(), |
|
1947 subShm->errorString().toLatin1().constData()); |
|
1948 return false; |
|
1949 } |
|
1950 |
|
1951 if (subShm) |
|
1952 clientIndex = (uchar *)subShm->data(); |
|
1953 if(Client == type) { |
|
1954 QPacket mem; |
|
1955 mem << (unsigned int)0 |
|
1956 << (quint8)SHMLAYER_SUBINDEX << subShm->key() |
|
1957 << (quint8)SHMLAYER_DONE; |
|
1958 (*connections.begin())->send(mem); |
|
1959 } |
|
1960 |
|
1961 layer = new FixedMemoryTree((char*)shm->data(), |
|
1962 SHMLAYER_SIZE, |
|
1963 (Server == type)); |
|
1964 if(Server == type) |
|
1965 layer->setNodeChangeFunction(&ShmLayerNodeChanged, (void *)this); |
|
1966 |
|
1967 this->type = type; |
|
1968 |
|
1969 valid = (lock != 0) && (layer != 0); |
|
1970 if (!valid) |
|
1971 qWarning("SharedMemoryLayer::startup failed"); |
|
1972 return valid; |
|
1973 } |
|
1974 |
|
1975 void ALServerImpl::incomingConnection(quintptr socketDescriptor) |
|
1976 { |
|
1977 QLocalSocket * sock = new QLocalSocket; |
|
1978 sock->setSocketDescriptor(socketDescriptor); |
|
1979 |
|
1980 QPacketProtocol * protocol; |
|
1981 protocol = new SharedMemoryLayerClient(sock, this); |
|
1982 sock->setParent(protocol); |
|
1983 |
|
1984 SharedMemoryLayer *al = static_cast<SharedMemoryLayer*>( QObject::parent() ); |
|
1985 |
|
1986 QObject::connect(sock, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)), |
|
1987 protocol, SIGNAL(invalidPacket())); |
|
1988 QObject::connect(protocol, SIGNAL(invalidPacket()), |
|
1989 al, SLOT(disconnected())); |
|
1990 QObject::connect(protocol, SIGNAL(readyRead()), |
|
1991 al, SLOT(readyRead())); |
|
1992 |
|
1993 qDebug() << "New client" << protocol << "connected"; |
|
1994 |
|
1995 al->connections.insert(protocol); |
|
1996 } |
|
1997 |
|
1998 void SharedMemoryLayer::timerEvent(QTimerEvent *) |
|
1999 { |
|
2000 QMutexLocker locker(&localLock); |
|
2001 |
|
2002 if(Client == type) |
|
2003 doClientTransmit(); |
|
2004 else |
|
2005 doServerTransmit(); |
|
2006 } |
|
2007 |
|
2008 void SharedMemoryLayer::doServerTransmit() |
|
2009 { |
|
2010 QMutexLocker locker(&localLock); |
|
2011 |
|
2012 Q_ASSERT(Server == type); |
|
2013 |
|
2014 triggeredTodo = false; |
|
2015 |
|
2016 QPacket others; |
|
2017 others << (quint8)SHMLAYER_SYNC << (unsigned int)0; |
|
2018 |
|
2019 for(QSet<QPacketProtocol *>::ConstIterator iter = connections.begin(); |
|
2020 iter != connections.end(); |
|
2021 ++iter) { |
|
2022 |
|
2023 SharedMemoryLayerClient *client = |
|
2024 (SharedMemoryLayerClient *)(*iter); |
|
2025 if(!client->index) { |
|
2026 (*iter)->send(others); |
|
2027 } else { |
|
2028 bool found = false; |
|
2029 for(unsigned int ii = 0;!found && ii < changedNodesCount; ++ii) { |
|
2030 if(client->index[changedNodes[ii] >> 3] & (1 << (changedNodes[ii] & 0x7))) |
|
2031 found = true; |
|
2032 } |
|
2033 if(found) { |
|
2034 //qDebug() << "GGGGGGGGGGGGGGGG"; |
|
2035 (*iter)->send(others); |
|
2036 } |
|
2037 } |
|
2038 |
|
2039 } |
|
2040 |
|
2041 changedNodesCount = 0; |
|
2042 doClientEmit(); |
|
2043 } |
|
2044 |
|
2045 void SharedMemoryLayer::doClientTransmit() |
|
2046 { |
|
2047 QMutexLocker locker(&localLock); |
|
2048 |
|
2049 Q_ASSERT(Client == type); |
|
2050 |
|
2051 triggeredTodo = false; |
|
2052 |
|
2053 if(!todo.isEmpty()) { |
|
2054 todo << (quint8)SHMLAYER_DONE; |
|
2055 (*connections.begin())->send(todo); |
|
2056 todo.clear(); |
|
2057 } |
|
2058 } |
|
2059 |
|
2060 typedef QHash<QByteArray, QMap<const QPacketProtocol *, uint> > PathsOfInterest; |
|
2061 Q_GLOBAL_STATIC(PathsOfInterest, pathsOfInterest); |
|
2062 |
|
2063 void SharedMemoryLayer::disconnected() |
|
2064 { |
|
2065 Q_ASSERT(sender()); |
|
2066 |
|
2067 QMutexLocker locker(&localLock); |
|
2068 |
|
2069 QPacketProtocol * protocol = (QPacketProtocol *)sender(); |
|
2070 protocol->disconnect(); |
|
2071 protocol->deleteLater(); |
|
2072 |
|
2073 if(Client == type) { |
|
2074 qFatal("SharedMemoryLayer: Shared memory layer server unexpectedly terminated."); |
|
2075 } else { |
|
2076 qDebug() << "Removing" << protocol << "from space"; |
|
2077 |
|
2078 NodeOwner owner; |
|
2079 owner.data1 = (unsigned long)protocol; |
|
2080 owner.data2 = 0xFFFFFFFF; |
|
2081 |
|
2082 connections.remove(protocol); |
|
2083 if(layer->remove("/", owner)) { |
|
2084 QPacket others; |
|
2085 others << (quint8)SHMLAYER_SYNC << (unsigned int)0; |
|
2086 for(QSet<QPacketProtocol *>::ConstIterator iter = connections.begin(); |
|
2087 iter != connections.end(); |
|
2088 ++iter) |
|
2089 (*iter)->send(others); |
|
2090 doClientEmit(); |
|
2091 } |
|
2092 |
|
2093 QList<QByteArray> paths = pathsOfInterest()->keys(); |
|
2094 |
|
2095 for (int i = 0; i < paths.count(); ++i) { |
|
2096 const QByteArray interestPath = paths.at(i); |
|
2097 |
|
2098 if (!(*pathsOfInterest())[interestPath].remove(protocol)) |
|
2099 continue; |
|
2100 |
|
2101 if (!(*pathsOfInterest())[interestPath].isEmpty()) |
|
2102 continue; |
|
2103 |
|
2104 pathsOfInterest()->remove(interestPath); |
|
2105 |
|
2106 QList<NodeWatch> owners = watchers(interestPath); |
|
2107 |
|
2108 QSet<unsigned long> written; |
|
2109 QSet<QValueSpacePublisher *> notified; |
|
2110 |
|
2111 for (int ii = 0; ii < owners.count(); ++ii) { |
|
2112 const NodeWatch &watch = owners.at(ii); |
|
2113 |
|
2114 if (watch.data1 != (unsigned long)protocol) |
|
2115 continue; |
|
2116 |
|
2117 if (watch.data1 == 0) { |
|
2118 QValueSpacePublisher *publisher = |
|
2119 reinterpret_cast<QValueSpacePublisher *>(watch.data2); |
|
2120 if (!notified.contains(publisher)) { |
|
2121 doClientNotify(publisher, interestPath, false); |
|
2122 notified.insert(publisher); |
|
2123 } |
|
2124 } else { |
|
2125 if (!written.contains(watch.data1)) { |
|
2126 ((QPacketProtocol *)watch.data1)->send() << quint8(SHMLAYER_NOTIFY) |
|
2127 << watch.data2 << interestPath |
|
2128 << false; |
|
2129 written.insert(watch.data1); |
|
2130 } |
|
2131 } |
|
2132 } |
|
2133 |
|
2134 } |
|
2135 } |
|
2136 } |
|
2137 |
|
2138 static void ShmLayerNodeChanged(unsigned short node, void *ctxt) |
|
2139 { |
|
2140 SharedMemoryLayer *layer = (SharedMemoryLayer *)ctxt; |
|
2141 layer->nodeChanged(node); |
|
2142 } |
|
2143 |
|
2144 void SharedMemoryLayer::nodeChanged(unsigned short node) |
|
2145 { |
|
2146 QMutexLocker locker(&localLock); |
|
2147 |
|
2148 if(changedNodesCount != VERSION_TABLE_ENTRIES) |
|
2149 changedNodes[changedNodesCount++] = node; |
|
2150 } |
|
2151 |
|
2152 void SharedMemoryLayer::readyRead() |
|
2153 { |
|
2154 QMutexLocker locker(&localLock); |
|
2155 |
|
2156 Q_ASSERT(sender()); |
|
2157 QPacketProtocol * protocol = (QPacketProtocol *)sender(); |
|
2158 |
|
2159 QPacket pack = protocol->read(); |
|
2160 if (Client == type) { |
|
2161 //qDebug() << "Client" << protocol << "woken"; |
|
2162 if (pack.isEmpty()) |
|
2163 return; |
|
2164 |
|
2165 quint8 op = 0; |
|
2166 pack >> op; |
|
2167 switch(op) { |
|
2168 case SHMLAYER_SYNC: { |
|
2169 unsigned int recvId = 0; |
|
2170 pack >> recvId; |
|
2171 if(0 != recvId) |
|
2172 lastRecvId = recvId; |
|
2173 doClientEmit(); |
|
2174 break; |
|
2175 } |
|
2176 case SHMLAYER_NOTIFY: { |
|
2177 unsigned long owner; |
|
2178 QByteArray path; |
|
2179 bool interested; |
|
2180 pack >> owner >> path >> interested; |
|
2181 doClientNotify(reinterpret_cast<QValueSpacePublisher *>(owner), path, interested); |
|
2182 break; |
|
2183 } |
|
2184 default: |
|
2185 qFatal("SharedMemoryLayer: Invalid message type %d " |
|
2186 "received from shared memory layer server.", op); |
|
2187 break; |
|
2188 } |
|
2189 } else { |
|
2190 unsigned int packId = 0; |
|
2191 pack >> packId; |
|
2192 |
|
2193 bool changed = false; |
|
2194 bool done = false; |
|
2195 |
|
2196 changedNodesCount = 0; |
|
2197 while(!done && !pack.isEmpty()) { |
|
2198 quint8 op; |
|
2199 pack >> op; |
|
2200 |
|
2201 switch(op) { |
|
2202 case SHMLAYER_ADD: |
|
2203 { |
|
2204 unsigned long own; |
|
2205 QByteArray path; |
|
2206 QVariant value; |
|
2207 pack >> own >> path >> value; |
|
2208 NodeOwner owner; |
|
2209 owner.data1 = (unsigned long)protocol; |
|
2210 owner.data2 = own; |
|
2211 changed |= doSetItem(owner, path, value); |
|
2212 } |
|
2213 break; |
|
2214 |
|
2215 case SHMLAYER_REM: |
|
2216 { |
|
2217 unsigned long own; |
|
2218 QByteArray path; |
|
2219 pack >> own >> path; |
|
2220 NodeOwner owner; |
|
2221 owner.data1 = (unsigned long)protocol; |
|
2222 owner.data2 = own; |
|
2223 changed |= doRemItems(owner, path); |
|
2224 } |
|
2225 break; |
|
2226 |
|
2227 case SHMLAYER_ADDWATCH: |
|
2228 { |
|
2229 unsigned long own; |
|
2230 QByteArray path; |
|
2231 pack >> own >> path; |
|
2232 NodeWatch owner; |
|
2233 owner.data1 = (unsigned long)protocol; |
|
2234 owner.data2 = own; |
|
2235 changed |= doSetWatch(owner, path); |
|
2236 } |
|
2237 break; |
|
2238 |
|
2239 case SHMLAYER_REMWATCH: |
|
2240 { |
|
2241 unsigned long own; |
|
2242 QByteArray path; |
|
2243 pack >> own >> path; |
|
2244 NodeWatch owner; |
|
2245 owner.data1 = (unsigned long)protocol; |
|
2246 owner.data2 = own; |
|
2247 changed |= doRemWatch(owner, path); |
|
2248 } |
|
2249 break; |
|
2250 |
|
2251 case SHMLAYER_DONE: |
|
2252 done = true; |
|
2253 break; |
|
2254 |
|
2255 case SHMLAYER_SUBINDEX: |
|
2256 { |
|
2257 QString shmkey; |
|
2258 pack >> shmkey; |
|
2259 |
|
2260 QSharedMemory* mem = new QSharedMemory(shmkey, protocol); |
|
2261 if (!mem->attach(QSharedMemory::ReadOnly)) { |
|
2262 qWarning() << "SharedMemoryLayer: Unable to shmat with id:" |
|
2263 << shmkey << "error:" << mem->errorString(); |
|
2264 delete mem; |
|
2265 } else { |
|
2266 static_cast<SharedMemoryLayerClient *>(protocol)->index = |
|
2267 reinterpret_cast<uchar *>(mem->data()); |
|
2268 } |
|
2269 } |
|
2270 break; |
|
2271 |
|
2272 case SHMLAYER_NOTIFY: |
|
2273 { |
|
2274 QByteArray path; |
|
2275 bool interested; |
|
2276 pack >> path >> interested; |
|
2277 doNotify(path, protocol, interested); |
|
2278 } |
|
2279 break; |
|
2280 default: |
|
2281 qWarning("SharedMemoryLayer: Invalid client request %x received.", op); |
|
2282 disconnected(); |
|
2283 return; |
|
2284 } |
|
2285 } |
|
2286 |
|
2287 // Send change notification |
|
2288 QPacket causal; |
|
2289 causal << (quint8)SHMLAYER_SYNC << packId; |
|
2290 protocol->send(causal); |
|
2291 |
|
2292 if(changed) |
|
2293 doServerTransmit(); |
|
2294 } |
|
2295 } |
|
2296 |
|
2297 void SharedMemoryLayer::closeConnections() |
|
2298 { |
|
2299 QMutexLocker locker(&localLock); |
|
2300 |
|
2301 QMutableSetIterator<QPacketProtocol *> i(connections); |
|
2302 while (i.hasNext()) { |
|
2303 delete i.next(); |
|
2304 i.remove(); |
|
2305 } |
|
2306 } |
|
2307 |
|
2308 void SharedMemoryLayer::doClientEmit() |
|
2309 { |
|
2310 QMutexLocker locker(&localLock); |
|
2311 |
|
2312 QMap<QString, ReadHandle *> cpy = handles; |
|
2313 for(QMap<QString, ReadHandle *>::ConstIterator iter = cpy.begin(); |
|
2314 iter != cpy.end(); |
|
2315 ++iter) |
|
2316 ++(*iter)->refCount; |
|
2317 |
|
2318 for(QMap<QString, ReadHandle *>::ConstIterator iter = cpy.begin(); |
|
2319 iter != cpy.end(); |
|
2320 ++iter) { |
|
2321 if(refreshHandle(*iter)) { |
|
2322 if((*iter)->forceChange) { |
|
2323 Q_ASSERT(forceChangeCount); |
|
2324 --forceChangeCount; |
|
2325 (*iter)->forceChange = false; |
|
2326 } |
|
2327 |
|
2328 emit handleChanged((Handle)*iter); |
|
2329 } else { |
|
2330 |
|
2331 if((*iter)->forceChange) { |
|
2332 Q_ASSERT(forceChangeCount); |
|
2333 --forceChangeCount; |
|
2334 (*iter)->forceChange = false; |
|
2335 emit handleChanged((Handle)*iter); |
|
2336 } |
|
2337 } |
|
2338 } |
|
2339 |
|
2340 while(forceChangeCount) { |
|
2341 for(QMap<QString, ReadHandle *>::ConstIterator iter = cpy.begin(); |
|
2342 forceChangeCount && iter != cpy.end(); |
|
2343 ++iter) { |
|
2344 |
|
2345 if((*iter)->forceChange) { |
|
2346 Q_ASSERT(forceChangeCount); |
|
2347 --forceChangeCount; |
|
2348 (*iter)->forceChange = false; |
|
2349 emit handleChanged((Handle)*iter); |
|
2350 } |
|
2351 |
|
2352 } |
|
2353 } |
|
2354 |
|
2355 for(QMap<QString, ReadHandle *>::ConstIterator iter = cpy.begin(); |
|
2356 iter != cpy.end(); |
|
2357 ++iter) |
|
2358 removeHandle((Handle)*iter); |
|
2359 } |
|
2360 |
|
2361 QUuid SharedMemoryLayer::id() |
|
2362 { |
|
2363 return QVALUESPACE_SHAREDMEMORY_LAYER; |
|
2364 } |
|
2365 |
|
2366 unsigned int SharedMemoryLayer::order() |
|
2367 { |
|
2368 return 0x10000000; |
|
2369 } |
|
2370 |
|
2371 bool SharedMemoryLayer::value(Handle handle, QVariant *data) |
|
2372 { |
|
2373 QMutexLocker locker(&localLock); |
|
2374 |
|
2375 if (!valid) |
|
2376 return false; |
|
2377 Q_ASSERT(layer); |
|
2378 Q_ASSERT(data); |
|
2379 |
|
2380 ReadHandle * rhandle = rh(handle); |
|
2381 |
|
2382 lock->lockForRead(); |
|
2383 |
|
2384 if(0xFFFFFFFF != rhandle->currentPath) |
|
2385 if(refreshHandle(rhandle)) { |
|
2386 if(!rhandle->forceChange) { |
|
2387 ++forceChangeCount; |
|
2388 rhandle->forceChange = true; |
|
2389 } |
|
2390 } |
|
2391 |
|
2392 Node * node = 0; |
|
2393 if(0xFFFFFFFF == rhandle->currentPath) { |
|
2394 node = layer->getNode(rhandle->currentNode); |
|
2395 if(!node || node->creationId != rhandle->creationId) { |
|
2396 refreshHandle(rhandle); |
|
2397 node = layer->getNode(rhandle->currentNode); |
|
2398 if(!rhandle->forceChange) { |
|
2399 ++forceChangeCount; |
|
2400 rhandle->forceChange = true; |
|
2401 } |
|
2402 } |
|
2403 } |
|
2404 |
|
2405 bool rv = false; |
|
2406 if(0xFFFFFFFF == rhandle->currentPath) { |
|
2407 Q_ASSERT(node); |
|
2408 NodeDatum const * const datum = layer->data(rhandle->currentNode); |
|
2409 if(datum) { |
|
2410 *data = fromDatum(datum); |
|
2411 rv = true; |
|
2412 } |
|
2413 } |
|
2414 |
|
2415 lock->unlock(); |
|
2416 |
|
2417 return rv; |
|
2418 } |
|
2419 |
|
2420 bool SharedMemoryLayer::value(Handle handle, const QString &subPath, |
|
2421 QVariant *data) |
|
2422 { |
|
2423 QMutexLocker locker(&localLock); |
|
2424 |
|
2425 Q_ASSERT(layer); |
|
2426 Q_ASSERT(data); |
|
2427 Q_ASSERT(!subPath.isEmpty()); |
|
2428 Q_ASSERT(*subPath.constData() == QLatin1Char('/')); |
|
2429 |
|
2430 ReadHandle * rhandle = rh(handle); |
|
2431 |
|
2432 lock->lockForRead(); |
|
2433 |
|
2434 if(0xFFFFFFFF != rhandle->currentPath) |
|
2435 if(refreshHandle(rhandle)) { |
|
2436 if(!rhandle->forceChange) { |
|
2437 ++forceChangeCount; |
|
2438 rhandle->forceChange = true; |
|
2439 } |
|
2440 } |
|
2441 |
|
2442 bool rv = false; |
|
2443 if(0xFFFFFFFF == rhandle->currentPath) { |
|
2444 QByteArray abs_path = rhandle->path + subPath.toUtf8(); |
|
2445 if (rhandle->path.length() == 1) |
|
2446 abs_path = subPath.toUtf8(); |
|
2447 ReadHandle vhandle(abs_path); |
|
2448 clearHandle(&vhandle); |
|
2449 refreshHandle(&vhandle); |
|
2450 if(0xFFFFFFFF == vhandle.currentPath) { |
|
2451 // Valid! |
|
2452 NodeDatum const * const datum = layer->data(vhandle.currentNode); |
|
2453 if(datum) { |
|
2454 *data = fromDatum(datum); |
|
2455 rv = true; |
|
2456 } |
|
2457 } |
|
2458 } |
|
2459 |
|
2460 lock->unlock(); |
|
2461 |
|
2462 return rv; |
|
2463 } |
|
2464 |
|
2465 QSet<QString> SharedMemoryLayer::children(Handle handle) |
|
2466 { |
|
2467 QMutexLocker locker(&localLock); |
|
2468 |
|
2469 Q_ASSERT(layer); |
|
2470 ReadHandle * rhandle = rh(handle); |
|
2471 |
|
2472 QSet<QString> rv; |
|
2473 lock->lockForRead(); |
|
2474 |
|
2475 if(0xFFFFFFFF != rhandle->currentPath) |
|
2476 if(refreshHandle(rhandle)) { |
|
2477 if(!rhandle->forceChange) { |
|
2478 ++forceChangeCount; |
|
2479 rhandle->forceChange = true; |
|
2480 } |
|
2481 } |
|
2482 |
|
2483 Node * node = 0; |
|
2484 if(0xFFFFFFFF == rhandle->currentPath) { |
|
2485 node = layer->getNode(rhandle->currentNode); |
|
2486 if(!node || node->creationId != rhandle->creationId) { |
|
2487 if(refreshHandle(rhandle)) { |
|
2488 if(0xFFFFFFFF == rhandle->currentPath) |
|
2489 node = layer->getNode(rhandle->currentNode); |
|
2490 else |
|
2491 node = 0; |
|
2492 if(!rhandle->forceChange) { |
|
2493 ++forceChangeCount; |
|
2494 rhandle->forceChange = true; |
|
2495 } |
|
2496 } |
|
2497 } |
|
2498 } |
|
2499 |
|
2500 if(0xFFFFFFFF == rhandle->currentPath) { |
|
2501 Q_ASSERT(node); |
|
2502 for(unsigned short ii = 0; ii < node->subNodes; ++ii) { |
|
2503 Node * n = layer->subNode(rhandle->currentNode, ii); |
|
2504 rv.insert(QString::fromUtf8(n->name, n->nameLen)); |
|
2505 } |
|
2506 } |
|
2507 |
|
2508 lock->unlock(); |
|
2509 return rv; |
|
2510 } |
|
2511 |
|
2512 QValueSpace::LayerOptions SharedMemoryLayer::layerOptions() const |
|
2513 { |
|
2514 return QValueSpace::TransientLayer | QValueSpace::WritableLayer; |
|
2515 } |
|
2516 |
|
2517 SharedMemoryLayer::Handle SharedMemoryLayer::item(Handle parent, const QString &key) |
|
2518 { |
|
2519 QMutexLocker locker(&localLock); |
|
2520 |
|
2521 Q_UNUSED(parent); |
|
2522 Q_ASSERT(layer); |
|
2523 Q_ASSERT(*key.constData() == QLatin1Char('/')); |
|
2524 Q_ASSERT(InvalidHandle == parent); |
|
2525 QMap<QString, ReadHandle *>::Iterator iter = handles.find(key); |
|
2526 if(iter != handles.end()) { |
|
2527 ++(*iter)->refCount; |
|
2528 return (QAbstractValueSpaceLayer::Handle)*iter; |
|
2529 } else { |
|
2530 ReadHandle * handle = new ReadHandle(key.toUtf8()); |
|
2531 clearHandle(handle); |
|
2532 lock->lockForRead(); |
|
2533 refreshHandle(handle); |
|
2534 lock->unlock(); |
|
2535 handles.insert(key, handle); |
|
2536 return (QAbstractValueSpaceLayer::Handle)(handle); |
|
2537 } |
|
2538 } |
|
2539 |
|
2540 /*! |
|
2541 Attempt to advance \a handle to point to the true path or update it if it |
|
2542 does. Returns true if the handle has either: |
|
2543 |
|
2544 \list 1 |
|
2545 \i Changed value |
|
2546 \i Moved from being a partial reference to a true reference |
|
2547 \i Moved from being a true reference to a partial reference |
|
2548 \endlist |
|
2549 |
|
2550 That is, returns true if a handleChanged() signal is needed :) |
|
2551 |
|
2552 The layer MUST be locked for reading. |
|
2553 */ |
|
2554 |
|
2555 bool SharedMemoryLayer::refreshHandle(ReadHandle * handle) |
|
2556 { |
|
2557 QMutexLocker locker(&localLock); |
|
2558 |
|
2559 Q_ASSERT(handle); |
|
2560 |
|
2561 ReadHandle old = *handle; |
|
2562 unsigned short oldNode = handle->currentNode; |
|
2563 |
|
2564 // Refresh handle |
|
2565 if(0xFFFFFFFF == handle->currentPath) { |
|
2566 // True path! |
|
2567 Node * node = layer->getNode(handle->currentNode); |
|
2568 if(!node || node->creationId != handle->creationId) { |
|
2569 // Bad news! |
|
2570 clearHandle(handle); |
|
2571 oldNode = INVALID_HANDLE; // prevent double dec |
|
2572 } else { |
|
2573 // Super - still a true path |
|
2574 handle->version = layer->version(handle->currentNode); |
|
2575 } |
|
2576 } |
|
2577 |
|
2578 if(0xFFFFFFFF != handle->currentPath && |
|
2579 INVALID_HANDLE != handle->currentNode) { |
|
2580 // Partial |
|
2581 Node * node = layer->getNode(handle->currentNode); |
|
2582 if(!node || node->creationId != handle->creationId) { |
|
2583 // Bad news! |
|
2584 clearHandle(handle); |
|
2585 oldNode = INVALID_HANDLE; // prevent double dec |
|
2586 } else if(handle->version != layer->version(handle->currentNode)) { |
|
2587 // Something changed - try and advance! |
|
2588 const char * out = 0; |
|
2589 handle->currentNode = layer->findClosest(handle->currentNode, |
|
2590 handle->path.constData() + handle->currentPath, |
|
2591 &out); |
|
2592 |
|
2593 Node * newNode = layer->getNode(handle->currentNode); |
|
2594 Q_ASSERT(newNode); |
|
2595 handle->version = layer->version(handle->currentNode); |
|
2596 handle->creationId = newNode->creationId; |
|
2597 if(out) |
|
2598 handle->currentPath = (out - handle->path.constData()); |
|
2599 else |
|
2600 handle->currentPath = 0xFFFFFFFF; |
|
2601 } |
|
2602 } |
|
2603 |
|
2604 if(INVALID_HANDLE == handle->currentNode) { |
|
2605 // Start from scratch |
|
2606 const char * out = 0; |
|
2607 handle->currentNode = layer->findClosest(handle->path.constData(), |
|
2608 &out); |
|
2609 |
|
2610 Node * newNode = layer->getNode(handle->currentNode); |
|
2611 Q_ASSERT(newNode); |
|
2612 handle->version = layer->version(handle->currentNode); |
|
2613 handle->creationId = newNode->creationId; |
|
2614 if(out) |
|
2615 handle->currentPath = (out - handle->path.constData()); |
|
2616 else |
|
2617 handle->currentPath = 0xFFFFFFFF; |
|
2618 } |
|
2619 |
|
2620 if(handle->currentNode != oldNode) { |
|
2621 decNode(oldNode); |
|
2622 incNode(handle->currentNode); |
|
2623 } |
|
2624 |
|
2625 bool rv = false; |
|
2626 if(0xFFFFFFFF == handle->currentPath) { |
|
2627 // Valid! |
|
2628 rv = (handle->currentNode != old.currentNode || |
|
2629 handle->currentPath != old.currentPath || |
|
2630 handle->creationId != old.creationId || |
|
2631 handle->version != old.version); |
|
2632 } else { |
|
2633 // Returns true if old was valid |
|
2634 rv = (0xFFFFFFFF == old.currentPath); |
|
2635 } |
|
2636 |
|
2637 return rv; |
|
2638 } |
|
2639 |
|
2640 void SharedMemoryLayer::clearHandle(ReadHandle *handle) |
|
2641 { |
|
2642 QMutexLocker locker(&localLock); |
|
2643 |
|
2644 handle->currentPath = 0; |
|
2645 decNode(handle->currentNode); |
|
2646 handle->currentNode = INVALID_HANDLE; |
|
2647 handle->version = 0; |
|
2648 handle->creationId = 0; |
|
2649 } |
|
2650 |
|
2651 void SharedMemoryLayer::triggerTodo() |
|
2652 { |
|
2653 QMutexLocker locker(&localLock); |
|
2654 |
|
2655 if (triggeredTodo || !valid) |
|
2656 return; |
|
2657 |
|
2658 QCoreApplication::postEvent(this, new QTimerEvent(0), Qt::LowEventPriority); |
|
2659 } |
|
2660 |
|
2661 void SharedMemoryLayer::setProperty(Handle, Properties) |
|
2662 { |
|
2663 // Properties aren't used by shared memory layer (always emits changed) |
|
2664 } |
|
2665 |
|
2666 void SharedMemoryLayer::removeHandle(Handle h) |
|
2667 { |
|
2668 QMutexLocker locker(&localLock); |
|
2669 |
|
2670 Q_ASSERT(layer); |
|
2671 Q_ASSERT(h && INVALID_HANDLE != h); |
|
2672 |
|
2673 ReadHandle * rhandle = rh(h); |
|
2674 Q_ASSERT(rhandle->refCount); |
|
2675 --rhandle->refCount; |
|
2676 if(!rhandle->refCount) { |
|
2677 handles.remove(QString::fromUtf8(rhandle->path.constData(), rhandle->path.length())); |
|
2678 clearHandle(rhandle); |
|
2679 delete rhandle; |
|
2680 } |
|
2681 } |
|
2682 |
|
2683 #ifdef QVALUESPACE_UPDATE_STATS |
|
2684 |
|
2685 void SharedMemoryLayer::updateStats() |
|
2686 { |
|
2687 QMutexLocker locker(&localLock); |
|
2688 |
|
2689 if(!m_statPoolSize) { |
|
2690 // Hasn't initialized stats! |
|
2691 Q_ASSERT(layer); |
|
2692 unsigned int v = 0; |
|
2693 NodeOwner owner = { 1, 1 }; |
|
2694 |
|
2695 layer->insert("/.ValueSpace/SharedMemoryLayer/Memory/PoolSize", |
|
2696 NodeDatum::UInt, (const char *)&v, sizeof(unsigned int), |
|
2697 owner); |
|
2698 layer->insert("/.ValueSpace/SharedMemoryLayer/Memory/MaxSystemBytes", |
|
2699 NodeDatum::UInt, (const char *)&v, sizeof(unsigned int), |
|
2700 owner); |
|
2701 layer->insert("/.ValueSpace/SharedMemoryLayer/Memory/SystemBytes", |
|
2702 NodeDatum::UInt, (const char *)&v, sizeof(unsigned int), |
|
2703 owner); |
|
2704 layer->insert("/.ValueSpace/SharedMemoryLayer/Memory/InuseBytes", |
|
2705 NodeDatum::UInt, (const char *)&v, sizeof(unsigned int), |
|
2706 owner); |
|
2707 layer->insert("/.ValueSpace/SharedMemoryLayer/Memory/KeepCost", |
|
2708 NodeDatum::UInt, (const char *)&v, sizeof(unsigned int), |
|
2709 owner); |
|
2710 |
|
2711 const char * out; |
|
2712 unsigned short node; |
|
2713 unsigned short baseNode = |
|
2714 layer->findClosest("/.ValueSpace/SharedMemoryLayer/Memory", &out); |
|
2715 |
|
2716 node = layer->findClosest(baseNode, "/PoolSize", &out); |
|
2717 m_statPoolSize = (unsigned long *)layer->data(node)->data; |
|
2718 node = layer->findClosest(baseNode, "/MaxSystemBytes", &out); |
|
2719 m_statMaxSystemBytes = (unsigned long *)layer->data(node)->data; |
|
2720 node = layer->findClosest(baseNode, "/SystemBytes", &out); |
|
2721 m_statSystemBytes = (unsigned long *)layer->data(node)->data; |
|
2722 node = layer->findClosest(baseNode, "/InuseBytes", &out); |
|
2723 m_statInuseBytes = (unsigned long *)layer->data(node)->data; |
|
2724 node = layer->findClosest(baseNode, "/KeepCost", &out); |
|
2725 m_statKeepCost = (unsigned long *)layer->data(node)->data; |
|
2726 } |
|
2727 |
|
2728 QMallocPool::MemoryStats mstats = layer->mallocPool()->memoryStatistics(); |
|
2729 *m_statPoolSize = mstats.poolSize; |
|
2730 *m_statMaxSystemBytes = mstats.maxSystemBytes; |
|
2731 *m_statSystemBytes = mstats.systemBytes; |
|
2732 *m_statInuseBytes = mstats.inuseBytes; |
|
2733 *m_statKeepCost = mstats.keepCost; |
|
2734 } |
|
2735 |
|
2736 #endif |
|
2737 |
|
2738 QList<NodeWatch> SharedMemoryLayer::watchers(const QByteArray &path) |
|
2739 { |
|
2740 QMutexLocker locker(&localLock); |
|
2741 |
|
2742 Q_ASSERT(layer); |
|
2743 |
|
2744 lock->lockForRead(); |
|
2745 |
|
2746 const char * matched = 0; |
|
2747 unsigned short node = layer->findClosest(path.constData(), &matched); |
|
2748 QList<NodeWatch> owners; |
|
2749 while(INVALID_HANDLE != node) { |
|
2750 Node * n = layer->getNode(node); |
|
2751 if(1 == n->watchCount) { |
|
2752 owners.append(*(NodeWatch *)n->watchBegin()); |
|
2753 } else if(2 <= n->watchCount) { |
|
2754 NodeWatch *watches = |
|
2755 (NodeWatch *)layer->fromPtr(*(unsigned int*)n->watchBegin()); |
|
2756 for(unsigned int ii = 0; ii < n->watchCount; ++ii) { |
|
2757 owners.append(watches[ii]); |
|
2758 } |
|
2759 } |
|
2760 |
|
2761 node = n->parent; |
|
2762 } |
|
2763 |
|
2764 lock->unlock(); |
|
2765 |
|
2766 return owners; |
|
2767 } |
|
2768 |
|
2769 void SharedMemoryLayer::doNotify(const QByteArray &path, const QPacketProtocol *protocol, |
|
2770 bool interested) |
|
2771 { |
|
2772 QMutexLocker locker(&localLock); |
|
2773 |
|
2774 bool sendNotification = false; |
|
2775 if (interested) { |
|
2776 if ((++(*pathsOfInterest())[path][protocol]) == 1) |
|
2777 sendNotification = true; |
|
2778 } else { |
|
2779 if ((--(*pathsOfInterest())[path][protocol]) == 0) { |
|
2780 (*pathsOfInterest())[path].remove(protocol); |
|
2781 |
|
2782 if ((*pathsOfInterest())[path].isEmpty()) |
|
2783 pathsOfInterest()->remove(path); |
|
2784 |
|
2785 sendNotification = true; |
|
2786 } |
|
2787 } |
|
2788 |
|
2789 if (!sendNotification) |
|
2790 return; |
|
2791 |
|
2792 QList<NodeWatch> owners = watchers(path); |
|
2793 |
|
2794 QSet<unsigned long> written; |
|
2795 QSet<QValueSpacePublisher *> notified; |
|
2796 |
|
2797 for (int ii = 0; ii < owners.count(); ++ii) { |
|
2798 const NodeWatch &watch = owners.at(ii); |
|
2799 |
|
2800 if (watch.data1 == 0) { |
|
2801 QValueSpacePublisher *publisher = |
|
2802 reinterpret_cast<QValueSpacePublisher *>(watch.data2); |
|
2803 if (!notified.contains(publisher)) { |
|
2804 doClientNotify(publisher, path, interested); |
|
2805 notified.insert(publisher); |
|
2806 } |
|
2807 } else { |
|
2808 if (!written.contains(watch.data1)) { |
|
2809 ((QPacketProtocol *)watch.data1)->send() << quint8(SHMLAYER_NOTIFY) |
|
2810 << watch.data2 << path << interested; |
|
2811 written.insert(watch.data1); |
|
2812 } |
|
2813 } |
|
2814 } |
|
2815 } |
|
2816 |
|
2817 void SharedMemoryLayer::doNotifyObject(unsigned long own, unsigned long protocol) |
|
2818 { |
|
2819 QMutexLocker locker(&localLock); |
|
2820 |
|
2821 QList<QByteArray> paths = pathsOfInterest()->keys(); |
|
2822 |
|
2823 for (int i = 0; i < paths.count(); ++i) { |
|
2824 const QByteArray &interestPath = paths.at(i); |
|
2825 |
|
2826 QList<NodeWatch> owners = watchers(interestPath); |
|
2827 |
|
2828 QSet<unsigned long> written; |
|
2829 QSet<QValueSpacePublisher *> notified; |
|
2830 |
|
2831 for (int ii = 0; ii < owners.count(); ++ii) { |
|
2832 const NodeWatch &watch = owners.at(ii); |
|
2833 |
|
2834 if (watch.data1 != protocol || watch.data2 != own) |
|
2835 continue; |
|
2836 |
|
2837 if (watch.data1 == 0) { |
|
2838 QValueSpacePublisher *publisher = |
|
2839 reinterpret_cast<QValueSpacePublisher *>(watch.data2); |
|
2840 if (!notified.contains(publisher)) { |
|
2841 doClientNotify(publisher, interestPath, true); |
|
2842 notified.insert(publisher); |
|
2843 } |
|
2844 } else { |
|
2845 if (!written.contains(watch.data1)) { |
|
2846 ((QPacketProtocol *)watch.data1)->send() << quint8(SHMLAYER_NOTIFY) |
|
2847 << watch.data2 << interestPath |
|
2848 << true; |
|
2849 written.insert(watch.data1); |
|
2850 } |
|
2851 } |
|
2852 } |
|
2853 } |
|
2854 } |
|
2855 |
|
2856 bool SharedMemoryLayer::setWatch(NodeWatch watch, const QByteArray &path) |
|
2857 { |
|
2858 QMutexLocker locker(&localLock); |
|
2859 |
|
2860 if(path.count() > MAX_PATH_SIZE || path.startsWith("/.ValueSpace") || !valid) |
|
2861 return false; |
|
2862 Q_ASSERT(layer); |
|
2863 |
|
2864 if(Client == type) { |
|
2865 if(todo.isEmpty()) |
|
2866 todo << newPackId(); |
|
2867 |
|
2868 todo << (quint8)SHMLAYER_ADDWATCH << watch.data2 << path; |
|
2869 triggerTodo(); |
|
2870 return true; |
|
2871 } else { |
|
2872 bool changed = doSetWatch(watch, path); |
|
2873 if(changed) triggerTodo(); |
|
2874 return changed; |
|
2875 } |
|
2876 } |
|
2877 |
|
2878 bool SharedMemoryLayer::doSetWatch(NodeWatch watch, const QByteArray &path) |
|
2879 { |
|
2880 QMutexLocker locker(&localLock); |
|
2881 |
|
2882 Q_ASSERT(layer); |
|
2883 |
|
2884 lock->lockForWrite(); |
|
2885 bool rv = layer->addWatch(path.constData(), watch); |
|
2886 updateStats(); |
|
2887 lock->unlock(); |
|
2888 |
|
2889 doNotifyObject(watch.data2, watch.data1); |
|
2890 |
|
2891 return rv; |
|
2892 } |
|
2893 |
|
2894 bool SharedMemoryLayer::remWatch(NodeWatch watch, const QByteArray &path) |
|
2895 { |
|
2896 QMutexLocker locker(&localLock); |
|
2897 |
|
2898 if(path.count() > MAX_PATH_SIZE || !valid) |
|
2899 return false; |
|
2900 Q_ASSERT(layer); |
|
2901 |
|
2902 if(Client == type) { |
|
2903 if(todo.isEmpty()) |
|
2904 todo << newPackId(); |
|
2905 |
|
2906 todo << (quint8)SHMLAYER_REMWATCH << watch.data2 << path; |
|
2907 triggerTodo(); |
|
2908 return true; |
|
2909 } else { |
|
2910 bool changed = doRemWatch(watch, path); |
|
2911 if(changed) triggerTodo(); |
|
2912 return changed; |
|
2913 } |
|
2914 } |
|
2915 |
|
2916 bool SharedMemoryLayer::doRemWatch(NodeWatch watch, const QByteArray &path) |
|
2917 { |
|
2918 QMutexLocker locker(&localLock); |
|
2919 |
|
2920 Q_ASSERT(layer); |
|
2921 |
|
2922 lock->lockForWrite(); |
|
2923 bool rv = layer->remWatch(path.constData(), watch); |
|
2924 updateStats(); |
|
2925 lock->unlock(); |
|
2926 |
|
2927 return rv; |
|
2928 } |
|
2929 |
|
2930 bool SharedMemoryLayer::setItem(NodeOwner owner, const QByteArray &path, |
|
2931 const QVariant &val) |
|
2932 { |
|
2933 QMutexLocker locker(&localLock); |
|
2934 |
|
2935 if(path.count() > MAX_PATH_SIZE || path.startsWith("/.ValueSpace") || !valid) |
|
2936 return false; |
|
2937 Q_ASSERT(layer); |
|
2938 bool changed = false; |
|
2939 |
|
2940 if(Client == type) { |
|
2941 if(todo.isEmpty()) |
|
2942 todo << newPackId(); |
|
2943 |
|
2944 todo << (quint8)SHMLAYER_ADD << owner.data2 << path << val; |
|
2945 triggerTodo(); |
|
2946 return true; |
|
2947 } else { |
|
2948 changed = doSetItem(owner, path, val); |
|
2949 if(changed) |
|
2950 triggerTodo(); |
|
2951 } |
|
2952 return changed; |
|
2953 } |
|
2954 |
|
2955 bool SharedMemoryLayer::doSetItem(NodeOwner owner, const QByteArray &path, |
|
2956 const QVariant &val) |
|
2957 { |
|
2958 QMutexLocker locker(&localLock); |
|
2959 |
|
2960 bool rv = false; |
|
2961 |
|
2962 lock->lockForWrite(); |
|
2963 |
|
2964 switch(val.type()) { |
|
2965 case QVariant::Bool: |
|
2966 { |
|
2967 unsigned int v = val.toBool()?1:0; |
|
2968 rv = layer->insert(path.constData(), NodeDatum::Boolean, (const char *)&v, |
|
2969 sizeof(unsigned int), owner); |
|
2970 } |
|
2971 break; |
|
2972 case QVariant::Int: |
|
2973 { |
|
2974 int v = val.toInt(); |
|
2975 rv = layer->insert(path.constData(), NodeDatum::Int, (const char *)&v, |
|
2976 sizeof(int), owner); |
|
2977 } |
|
2978 break; |
|
2979 case QVariant::UInt: |
|
2980 { |
|
2981 unsigned int v = val.toUInt(); |
|
2982 rv = layer->insert(path.constData(), NodeDatum::UInt, (const char *)&v, |
|
2983 sizeof(unsigned int), owner); |
|
2984 } |
|
2985 break; |
|
2986 case QVariant::LongLong: |
|
2987 { |
|
2988 long long v = val.toLongLong(); |
|
2989 rv = layer->insert(path.constData(), NodeDatum::LongLong, (const char *)&v, |
|
2990 sizeof(long long), owner); |
|
2991 } |
|
2992 break; |
|
2993 case QVariant::ULongLong: |
|
2994 { |
|
2995 unsigned long long v = val.toULongLong(); |
|
2996 rv = layer->insert(path.constData(), NodeDatum::ULongLong, (const char *)&v, |
|
2997 sizeof(unsigned long long), owner); |
|
2998 } |
|
2999 break; |
|
3000 case QVariant::Double: |
|
3001 { |
|
3002 double v = val.toDouble(); |
|
3003 rv = layer->insert(path.constData(), NodeDatum::Double, (const char *)&v, |
|
3004 sizeof(double), owner); |
|
3005 } |
|
3006 break; |
|
3007 case QVariant::Char: |
|
3008 { |
|
3009 QChar v = val.toChar(); |
|
3010 rv = layer->insert(path.constData(), NodeDatum::Char, (const char *)&v, |
|
3011 sizeof(QChar), owner); |
|
3012 } |
|
3013 break; |
|
3014 case QVariant::String: |
|
3015 { |
|
3016 QString v = val.toString(); |
|
3017 rv = layer->insert(path.constData(), NodeDatum::String, |
|
3018 (const char *)v.constData(), v.length() * sizeof(QChar), owner); |
|
3019 } |
|
3020 break; |
|
3021 case QVariant::ByteArray: |
|
3022 { |
|
3023 QByteArray v = val.toByteArray(); |
|
3024 rv = layer->insert(path.constData(), NodeDatum::ByteArray, |
|
3025 v.constData(), v.length(), owner); |
|
3026 } |
|
3027 break; |
|
3028 default: |
|
3029 { |
|
3030 QByteArray v; |
|
3031 QDataStream ds(&v, QIODevice::WriteOnly); |
|
3032 ds << val; |
|
3033 rv = layer->insert(path.constData(), NodeDatum::SerializedType, |
|
3034 v.constData(), v.length(), owner); |
|
3035 } |
|
3036 break; |
|
3037 } |
|
3038 |
|
3039 updateStats(); |
|
3040 lock->unlock(); |
|
3041 |
|
3042 return rv; |
|
3043 } |
|
3044 |
|
3045 bool SharedMemoryLayer::remItems(NodeOwner owner, const QByteArray &path) |
|
3046 { |
|
3047 QMutexLocker locker(&localLock); |
|
3048 |
|
3049 if (!valid) |
|
3050 return false; |
|
3051 bool rv = false; |
|
3052 |
|
3053 if(Client == type) { |
|
3054 if(todo.isEmpty()) |
|
3055 todo << newPackId(); |
|
3056 |
|
3057 todo << (quint8)SHMLAYER_REM << owner.data2 << path; |
|
3058 triggerTodo(); |
|
3059 } else { |
|
3060 rv = doRemItems(owner, path); |
|
3061 if(rv) triggerTodo(); |
|
3062 } |
|
3063 |
|
3064 return rv; |
|
3065 } |
|
3066 |
|
3067 bool SharedMemoryLayer::doRemItems(NodeOwner owner, const QByteArray &path) |
|
3068 { |
|
3069 QMutexLocker locker(&localLock); |
|
3070 |
|
3071 if (!valid) |
|
3072 return false; |
|
3073 bool rv = false; |
|
3074 |
|
3075 if(Client == type) { |
|
3076 if(todo.isEmpty()) |
|
3077 todo << newPackId(); |
|
3078 |
|
3079 todo << (quint8)SHMLAYER_REM << owner.data2 << path; |
|
3080 triggerTodo(); |
|
3081 |
|
3082 } else { |
|
3083 Q_ASSERT(layer); |
|
3084 lock->lockForWrite(); |
|
3085 rv = layer->remove(path.constData(), owner); |
|
3086 updateStats(); |
|
3087 lock->unlock(); |
|
3088 } |
|
3089 |
|
3090 return rv; |
|
3091 } |
|
3092 |
|
3093 QString SharedMemoryLayer::socket() const |
|
3094 { |
|
3095 QString socketPath(QLatin1String("qt/")); |
|
3096 |
|
3097 #ifdef Q_OS_UNIX |
|
3098 static bool pipePathExists = false; |
|
3099 if (!pipePathExists) { |
|
3100 if (QDir::temp().mkpath(socketPath)) |
|
3101 pipePathExists = true; |
|
3102 } |
|
3103 socketPath = QDir::temp().absoluteFilePath(socketPath); |
|
3104 #endif |
|
3105 |
|
3106 QByteArray key = qgetenv("QT_VALUESPACE_SHMLAYER"); |
|
3107 if (!key.isEmpty()) |
|
3108 socketPath.append(QString::fromLocal8Bit(key.constData(), key.length())); |
|
3109 else |
|
3110 socketPath.append(QLatin1String("valuespace_shmlayer")); |
|
3111 |
|
3112 return socketPath; |
|
3113 } |
|
3114 |
|
3115 void SharedMemoryLayer::sync() |
|
3116 { |
|
3117 if (type == Client) { |
|
3118 if (QThread::currentThread() != thread()) |
|
3119 QMetaObject::invokeMethod(this, "doClientSync", Qt::BlockingQueuedConnection); |
|
3120 else |
|
3121 doClientSync(); |
|
3122 } else { |
|
3123 doServerTransmit(); |
|
3124 } |
|
3125 } |
|
3126 |
|
3127 void SharedMemoryLayer::doClientSync() |
|
3128 { |
|
3129 QMutexLocker locker(&localLock); |
|
3130 |
|
3131 Q_ASSERT(1 == connections.count()); |
|
3132 |
|
3133 unsigned int waitId = lastSentId; |
|
3134 |
|
3135 if (lastRecvId >= waitId) |
|
3136 return; // Done |
|
3137 |
|
3138 // Send any outstanding messages |
|
3139 doClientTransmit(); |
|
3140 |
|
3141 // Get transmission socket |
|
3142 QLocalSocket *socket = static_cast<QLocalSocket *>((*connections.begin())->device()); |
|
3143 socket->flush(); |
|
3144 |
|
3145 // Wait |
|
3146 while (QLocalSocket::UnconnectedState != socket->state() && waitId > lastRecvId) |
|
3147 socket->waitForReadyRead(-1); |
|
3148 } |
|
3149 |
|
3150 QVariant SharedMemoryLayer::fromDatum(const NodeDatum * data) |
|
3151 { |
|
3152 switch(data->type) { |
|
3153 case NodeDatum::Boolean: |
|
3154 Q_ASSERT(4 == data->len); |
|
3155 return QVariant(0 != (*(unsigned int *)data->data)); |
|
3156 case NodeDatum::Int: |
|
3157 Q_ASSERT(4 == data->len); |
|
3158 return QVariant((*(int *)data->data)); |
|
3159 case NodeDatum::UInt: |
|
3160 Q_ASSERT(4 == data->len); |
|
3161 return QVariant((*(unsigned int *)data->data)); |
|
3162 case NodeDatum::LongLong: |
|
3163 Q_ASSERT(8 == data->len); |
|
3164 return QVariant((*(long long*)data->data)); |
|
3165 case NodeDatum::ULongLong: |
|
3166 Q_ASSERT(8 == data->len); |
|
3167 return QVariant((*(unsigned long long*)data->data)); |
|
3168 case NodeDatum::Double: |
|
3169 Q_ASSERT(8 == data->len); |
|
3170 return QVariant((*(double*)data->data)); |
|
3171 case NodeDatum::Char: |
|
3172 Q_ASSERT(2 == data->len); |
|
3173 return QVariant(QChar((unsigned short)(0xFFFF & (*(unsigned int*)data->data)))); |
|
3174 case NodeDatum::String: |
|
3175 return QVariant(QString((QChar *)data->data, |
|
3176 data->len / sizeof(QChar))); |
|
3177 case NodeDatum::ByteArray: |
|
3178 return QVariant(QByteArray(data->data, data->len)); |
|
3179 case NodeDatum::SerializedType: |
|
3180 { |
|
3181 QByteArray ba(data->data, data->len); |
|
3182 QDataStream ds(ba); |
|
3183 QVariant rv; |
|
3184 ds >> rv; |
|
3185 return rv; |
|
3186 } |
|
3187 default: |
|
3188 qFatal("SharedMemoryLayer: Unknown datum type."); |
|
3189 return QVariant(); |
|
3190 } |
|
3191 } |
|
3192 |
|
3193 void SharedMemoryLayer::incNode(unsigned short node) |
|
3194 { |
|
3195 QMutexLocker locker(&localLock); |
|
3196 |
|
3197 if(type == Server || node == INVALID_HANDLE) |
|
3198 return; |
|
3199 |
|
3200 QHash<unsigned short, unsigned int>::Iterator iter = |
|
3201 m_nodeInterest.find(node); |
|
3202 if(iter == m_nodeInterest.end()) { |
|
3203 clientIndex[node >> 3] |= (1 << (node & 0x7)); |
|
3204 m_nodeInterest.insert(node, 1); |
|
3205 } else { |
|
3206 (*iter)++; |
|
3207 } |
|
3208 } |
|
3209 |
|
3210 void SharedMemoryLayer::decNode(unsigned short node) |
|
3211 { |
|
3212 QMutexLocker locker(&localLock); |
|
3213 |
|
3214 if(type == Server || node == INVALID_HANDLE) |
|
3215 return; |
|
3216 |
|
3217 QHash<unsigned short, unsigned int>::Iterator iter = |
|
3218 m_nodeInterest.find(node); |
|
3219 Q_ASSERT(iter != m_nodeInterest.end()); |
|
3220 (*iter)--; |
|
3221 if(!*iter) { |
|
3222 clientIndex[node >> 3] &= ~(1 << (node & 0x7)); |
|
3223 m_nodeInterest.erase(iter); |
|
3224 } |
|
3225 } |
|
3226 |
|
3227 Q_GLOBAL_STATIC(SharedMemoryLayer, sharedMemoryLayer); |
|
3228 SharedMemoryLayer * SharedMemoryLayer::instance() |
|
3229 { |
|
3230 return sharedMemoryLayer(); |
|
3231 } |
|
3232 |
|
3233 typedef QSet<QValueSpacePublisher *> WatchObjects; |
|
3234 Q_GLOBAL_STATIC(WatchObjects, watchObjects); |
|
3235 |
|
3236 void SharedMemoryLayer::doClientNotify(QValueSpacePublisher *publisher, const QByteArray &path, |
|
3237 bool interested) |
|
3238 { |
|
3239 QMutexLocker locker(&localLock); |
|
3240 |
|
3241 // Invalid publisher. |
|
3242 if (!watchObjects()->contains(publisher)) |
|
3243 return; |
|
3244 |
|
3245 QByteArray emitPath; |
|
3246 |
|
3247 const QByteArray publisherPath = publisher->path().toUtf8(); |
|
3248 if (path.startsWith(publisherPath)) { |
|
3249 // path is under publisherPath |
|
3250 emitPath = path.mid(publisherPath.length()); |
|
3251 } else if (publisherPath.startsWith(path)) { |
|
3252 // path is a parent of publisherPath |
|
3253 } else { |
|
3254 // path is not for this publisher. |
|
3255 return; |
|
3256 } |
|
3257 |
|
3258 emitInterestChanged(publisher, QString::fromUtf8(emitPath.constData()), interested); |
|
3259 } |
|
3260 |
|
3261 bool SharedMemoryLayer::supportsInterestNotification() const |
|
3262 { |
|
3263 return true; |
|
3264 } |
|
3265 |
|
3266 bool SharedMemoryLayer::notifyInterest(Handle handle, bool interested) |
|
3267 { |
|
3268 QMutexLocker locker(&localLock); |
|
3269 |
|
3270 if (!valid) |
|
3271 return false; |
|
3272 Q_ASSERT(layer); |
|
3273 |
|
3274 ReadHandle *rhandle = rh(handle); |
|
3275 if (type == Client) { |
|
3276 if (todo.isEmpty()) |
|
3277 todo << newPackId(); |
|
3278 |
|
3279 todo << quint8(SHMLAYER_NOTIFY) << rhandle->path << interested; |
|
3280 |
|
3281 triggerTodo(); |
|
3282 } else { |
|
3283 doNotify(rhandle->path, 0, interested); |
|
3284 } |
|
3285 |
|
3286 return true; |
|
3287 } |
|
3288 |
|
3289 bool SharedMemoryLayer::setValue(QValueSpacePublisher *creator, Handle handle, const QString &path, |
|
3290 const QVariant &data) |
|
3291 { |
|
3292 QMutexLocker locker(&localLock); |
|
3293 |
|
3294 ReadHandle *readHandle = reinterpret_cast<ReadHandle *>(handle); |
|
3295 |
|
3296 if (!handles.values().contains(readHandle)) |
|
3297 return false; |
|
3298 |
|
3299 NodeOwner owner; |
|
3300 owner.data1 = 0; |
|
3301 owner.data2 = reinterpret_cast<unsigned long>(creator); |
|
3302 |
|
3303 QByteArray fullPath(readHandle->path); |
|
3304 if (!fullPath.endsWith('/') && path != QLatin1String("/")) |
|
3305 fullPath.append('/'); |
|
3306 |
|
3307 fullPath.append(path.mid(1)); |
|
3308 |
|
3309 return setItem(owner, fullPath, data); |
|
3310 } |
|
3311 |
|
3312 bool SharedMemoryLayer::removeValue(QValueSpacePublisher *creator, |
|
3313 Handle handle, |
|
3314 const QString &path) |
|
3315 { |
|
3316 QMutexLocker locker(&localLock); |
|
3317 |
|
3318 ReadHandle *readHandle = reinterpret_cast<ReadHandle *>(handle); |
|
3319 |
|
3320 if (!handles.values().contains(readHandle)) |
|
3321 return false; |
|
3322 |
|
3323 NodeOwner owner; |
|
3324 owner.data1 = 0; |
|
3325 owner.data2 = reinterpret_cast<quintptr>(creator); |
|
3326 |
|
3327 QByteArray fullPath(readHandle->path); |
|
3328 if (!fullPath.endsWith('/')) |
|
3329 fullPath.append('/'); |
|
3330 |
|
3331 int index = 0; |
|
3332 while (index < path.length() && path[index] == QLatin1Char('/')) |
|
3333 ++index; |
|
3334 |
|
3335 fullPath.append(path.mid(index)); |
|
3336 |
|
3337 return remItems(owner, fullPath); |
|
3338 } |
|
3339 |
|
3340 bool SharedMemoryLayer::removeSubTree(QValueSpacePublisher *creator, Handle handle) |
|
3341 { |
|
3342 QMutexLocker locker(&localLock); |
|
3343 |
|
3344 ReadHandle *readHandle = reinterpret_cast<ReadHandle *>(handle); |
|
3345 |
|
3346 if (!handles.values().contains(readHandle)) |
|
3347 return false; |
|
3348 |
|
3349 NodeOwner owner; |
|
3350 owner.data1 = 0; |
|
3351 owner.data2 = reinterpret_cast<quintptr>(creator); |
|
3352 |
|
3353 return remItems(owner, readHandle->path); |
|
3354 } |
|
3355 |
|
3356 void SharedMemoryLayer::addWatch(QValueSpacePublisher *creator, Handle handle) |
|
3357 { |
|
3358 QMutexLocker locker(&localLock); |
|
3359 |
|
3360 watchObjects()->insert(creator); |
|
3361 |
|
3362 ReadHandle *readHandle = reinterpret_cast<ReadHandle *>(handle); |
|
3363 |
|
3364 if (!handles.values().contains(readHandle)) |
|
3365 return; |
|
3366 |
|
3367 NodeWatch owner; |
|
3368 owner.data1 = 0; |
|
3369 owner.data2 = reinterpret_cast<unsigned long>(creator); |
|
3370 |
|
3371 setWatch(owner, readHandle->path); |
|
3372 } |
|
3373 |
|
3374 void SharedMemoryLayer::removeWatches(QValueSpacePublisher *creator, Handle parent) |
|
3375 { |
|
3376 QMutexLocker locker(&localLock); |
|
3377 |
|
3378 watchObjects()->remove(creator); |
|
3379 |
|
3380 ReadHandle *readHandle = reinterpret_cast<ReadHandle *>(parent); |
|
3381 |
|
3382 if (!handles.values().contains(readHandle)) |
|
3383 return; |
|
3384 |
|
3385 NodeWatch owner; |
|
3386 owner.data1 = 0; |
|
3387 owner.data2 = reinterpret_cast<unsigned long>(creator); |
|
3388 |
|
3389 remWatch(owner, readHandle->path); |
|
3390 } |
|
3391 |
|
3392 #include "sharedmemorylayer.moc" |
|
3393 QTM_END_NAMESPACE |
|
3394 |