qtmobility/src/publishsubscribe/sharedmemorylayer.cpp
changeset 1 2b40d63a9c3d
child 11 06b8e2af4411
equal deleted inserted replaced
0:cfcbf08528c4 1:2b40d63a9c3d
       
     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