00001 #include "stdafx.h"
00002 #include "mlinknode.h"
00003
00005 M_ImplementDynClass (LinkNode)
00006
00007 LinkNode::LinkNode (IndVect sizeData) : VectLnNdCnncn (sizeData), mChgCnncn (0), mProtected (0), mNotifyConnection (N_false), mLastChanged (NULL) {
00008 }
00009
00010 LinkNode::~LinkNode () {
00011 if (items ())
00012 disconnectAll () ;
00013 }
00014
00015 StsLnNB LinkNode::connect (LinkNode const &other) {
00016 ASSERT (&other != this) ;
00017 addProtect () ;
00018 ((LinkNode &) other).addProtect () ;
00019 StsLnNB ret = stsLnNd (setConnected (other), ((LinkNode &) other).setConnected (*this)) ;
00020 ((LinkNode &) other).removeProtect () ;
00021 removeProtect () ;
00022 return ret ;
00023 }
00024
00025 StsLnNd LinkNode::disconnect (LinkNode const &other, IndLnNd iOther) {
00026 LnNdCnncn const &cnn = (*this) [iOther] ;
00027 if (!(cnn.state & N_LnNdCnncnStt_Connected))
00028 return N_StsLnNd_Warning | N_StsLnNd_AlreadyDone ;
00029 addProtect () ;
00030 ((LinkNode &) other).addProtect () ;
00031 IndLnNd iThis = other.find (*this) ;
00032 if (iOther == N_IndLnNd_Invalid || iThis == N_IndLnNd_Invalid) {
00033 TRACE ("Trying disconnect %p:%s:%d and %p:%s:%d.\n", (CPtr) this, (CStr) getHost (NULL), (int) iOther, (CPtr) &other, (CStr) other.getHost (NULL), (int) iThis) ;
00034 trace (*this, 2, N_LnNdCnncnStt_) ;
00035 trace (other, 2, N_LnNdCnncnStt_) ;
00036 assert (0) ;
00037 }
00038 VERIFY_not_stsLnNdIsError (setDisconnected (iOther)) ;
00039 VERIFY_not_stsLnNdIsError (((LinkNode &) other).setDisconnected (iThis)) ;
00040 ((LinkNode &) other).removeProtect () ;
00041 removeProtect () ;
00042 return N_StsLnNd_OK ;
00043 }
00044
00045 StsLnNd LinkNode::disconnect (LinkNode const &other) {
00046 IndVect iOther = find (other) ;
00047 if (iOther == N_IndVect_Invalid)
00048 return N_StsLnNd_Warning | N_StsLnNd_NoSuchLnNd ;
00049 return disconnect (other, iOther) ;
00050 }
00051
00052 StsLnNd LinkNode::reserve (LinkNode const &other) {
00053 ASSERT (&other != this) ;
00054 addProtect () ;
00055 ((LinkNode &) other).addProtect () ;
00056 StsLnNd ret = setConnectedAnd (other, N_LnNdCnncnStt_Reserve, N_LnNdCnncnStt_ChgReserve) ;
00057 ((LinkNode &) other).setConnectedAnd (*this, N_LnNdCnncnStt_ReservedBy, N_LnNdCnncnStt_ChgReservedBy) ;
00058 ((LinkNode &) other).removeProtect () ;
00059 removeProtect () ;
00060 return ret ;
00061 }
00062
00063 StsLnNd LinkNode::release (LinkNode const &other) {
00064 IndLnNd i = find (other) ;
00065 if (i == N_IndLnNd_Invalid)
00066 return N_StsLnNd_Error | N_StsLnNd_NoSuchLnNd ;
00067 return release (i) ;
00068 }
00069
00070 StsLnNd LinkNode::release (IndLnNd iOther) {
00071 addProtect () ;
00072 LnNdCnncn &cnn = operator[] (iOther) ;
00073 if ((cnn.state & (N_LnNdCnncnStt_Reserve | N_LnNdCnncnStt_Connected)) != (N_LnNdCnncnStt_Reserve | N_LnNdCnncnStt_Connected))
00074 return N_StsLnNd_Warning | N_StsLnNd_AlreadyDone ;
00075 LinkNode *other = (LinkNode *) cnn.node ;
00076 other->addProtect () ;
00077 cnn.state &= ~N_LnNdCnncnStt_Reserve ;
00078 cnn.state |= N_LnNdCnncnStt_ChgRelease ;
00079 connectionChanged (&cnn, N_LnNdCnncnStt_ChgRelease) ;
00080 other->setReleasedBy (*this) ;
00081 other->removeProtect () ;
00082 removeProtect () ;
00083 return N_StsLnNd_OK ;
00084 }
00085
00086 void LinkNode::disconnectAll () {
00087 addProtect () ;
00088 LnNdCnncn const *cnn ;
00089 for (IndLnNd i = 0 ; !!(cnn = iterConnection (i)) ; i++) {
00090 if (cnn->node && (cnn->state & N_LnNdCnncnStt_Connected))
00091 disconnect (*cnn->node, i) ;
00092 }
00093 removeProtect () ;
00094 }
00095
00096 Bool LinkNode::isConnected (LinkNode const &other) const {
00097 IndLnNd i = find (other) ;
00098 if (i == N_IndLnNd_Invalid)
00099 return N_false ;
00100 return isConnected (i) ;
00101 }
00102
00103 Bool LinkNode::isConnected (ClassName clsName) const {
00104 for (IndLnNd i = 0 ; iterConnected (i, clsName) != NULL ; i++)
00105 return N_true ;
00106 return N_false ;
00107 }
00108
00109 Bool LinkNode::isReservedBy (LinkNode const &other) const {
00110 IndLnNd i = find (other) ;
00111 if (i == N_IndLnNd_Invalid)
00112 return N_false ;
00113 return isReservedBy (i) ;
00114 }
00115
00116 Bool LinkNode::isConnected () const {
00117 for (IndLnNd i = 0 ; i < items () ; i++)
00118 if ((*this) [i].state & N_LnNdCnncnStt_Connected)
00119 return N_true ;
00120 return N_false ;
00121 }
00122
00123 Bool LinkNode::isReserved () const {
00124 for (IndLnNd i = 0 ; i < items () ; i++)
00125 if ((*this) [i].state & N_LnNdCnncnStt_ReservedBy) {
00126 ASSERT ((*this) [i].state & N_LnNdCnncnStt_Connected) ;
00127 return N_true ;
00128 }
00129 return N_false ;
00130 }
00131
00132 Bool LinkNode::hasReserved () const {
00133 for (IndLnNd i = 0 ; i < items () ; i++)
00134 if ((*this) [i].state & N_LnNdCnncnStt_Reserve) {
00135 ASSERT ((*this) [i].state & N_LnNdCnncnStt_Connected) ;
00136 return N_true ;
00137 }
00138 return N_false ;
00139 }
00140
00141 LnNdCnncn const *LinkNode::iterChanged (IndLnNd &i) const {
00142 for (LnNdCnncn const *ret ; !!(ret = iterConnection (i)) ; i++)
00143 if (ret->state & N_LnNdCnncnStt_Chg_)
00144 return ret ;
00145 return NULL ;
00146 }
00147
00148 LnNdCnncn const *LinkNode::iterConnected (IndLnNd &i) const {
00149 for (LnNdCnncn const *ret ; !!(ret = iterConnection (i)) ; i++)
00150 if (ret->state & N_LnNdCnncnStt_Connected)
00151 return ret ;
00152 return NULL ;
00153 }
00154
00155 LnNdCnncn const *LinkNode::iterReserved (IndLnNd &i) const {
00156 for (LnNdCnncn const *ret ; !!(ret = iterConnection (i)) ; i++)
00157 if ((ret->state & (N_LnNdCnncnStt_Connected | N_LnNdCnncnStt_Reserve)) == (N_LnNdCnncnStt_Connected | N_LnNdCnncnStt_Reserve))
00158 return ret ;
00159 return NULL ;
00160 }
00161
00162 LnNdCnncn const *LinkNode::iterReserver (IndLnNd &i) const {
00163 for (LnNdCnncn const *ret ; !!(ret = iterConnection (i)) ; i++)
00164 if ((ret->state & (N_LnNdCnncnStt_Connected | N_LnNdCnncnStt_ReservedBy)) == (N_LnNdCnncnStt_Connected | N_LnNdCnncnStt_ReservedBy))
00165 return ret ;
00166 return NULL ;
00167 }
00168
00169 void const *LinkNode::iterConnected (IndLnNd &i, ClassName clsName) const {
00170 CPtr ret ;
00171 for (LnNdCnncn const *cnn ; !!(cnn = iterConnected (i)) ; i++)
00172 if (!!(ret = cnn->node->getHost (clsName)))
00173 return ret ;
00174 return NULL ;
00175 }
00176
00177 StsLnNd LinkNode::setConnected (LinkNode const &other) {
00178 ASSERT (mProtected) ;
00179 IndLnNd i ;
00180 LnNdCnncn *cnn ;
00181 if ((i = find (other)) != N_IndLnNd_Invalid) {
00182 cnn = &((*this) [i]) ;
00183 if (cnn->state & N_LnNdCnncnStt_Connected)
00184 return N_StsLnNd_Warning | N_StsLnNd_AlreadyDone ;
00185 cnn->state |= (N_LnNdCnncnStt_Connected | N_LnNdCnncnStt_ChgConnected) ;
00186 } else {
00187 i = allocNewItem () ;
00188 ASSERT (i != N_IndLnNd_Invalid) ;
00189 cnn = &((*this) [i]) ;
00190 cnn->node = &((LinkNode &) other) ;
00191 cnn->state = (N_LnNdCnncnStt_Connected | N_LnNdCnncnStt_ChgConnected) ;
00192 }
00193 connectionChanged (cnn, N_LnNdCnncnStt_Connected | N_LnNdCnncnStt_ChgConnected) ;
00194 return N_StsLnNd_OK ;
00195 }
00196
00197 StsLnNd LinkNode::setConnectedAnd (LinkNode const &other, LnNdCnncnType status, LnNdCnncnType change) {
00198 ASSERT (mProtected) ;
00199 IndLnNd i ;
00200 LnNdCnncn *cnn ;
00201 LnNdCnncnType chg ;
00202 if ((i = find (other)) != N_IndLnNd_Invalid) {
00203 cnn = &((*this) [i]) ;
00204 if ((cnn->state & status) == status) {
00205 ASSERT (cnn->state & N_LnNdCnncnStt_Connected) ;
00206 return N_StsLnNd_Warning | N_StsLnNd_AlreadyDone ;
00207 }
00208 if (!(cnn->state & N_LnNdCnncnStt_Connected)) {
00209 cnn->state |= (N_LnNdCnncnStt_Connected | N_LnNdCnncnStt_ChgConnected) ;
00210 chg = N_LnNdCnncnStt_Connected | N_LnNdCnncnStt_ChgConnected ;
00211 } else
00212 chg = 0 ;
00213 } else {
00214 i = allocNewItem () ;
00215 ASSERT (i != N_IndLnNd_Invalid) ;
00216 cnn = &((*this) [i]) ;
00217 cnn->node = &((LinkNode &) other) ;
00218 cnn->state = (N_LnNdCnncnStt_Connected | N_LnNdCnncnStt_ChgConnected) ;
00219 chg = N_LnNdCnncnStt_Connected | N_LnNdCnncnStt_ChgConnected ;
00220 }
00221 chg |= status | change ;
00222 cnn->state |= chg ;
00223 connectionChanged (cnn, chg) ;
00224 return N_StsLnNd_OK ;
00225 }
00226
00227 StsLnNd LinkNode::setDisconnected (IndLnNd iOther) {
00228 ASSERT (mProtected) ;
00229 if (iOther == N_IndLnNd_Invalid || items () < iOther)
00230 return N_StsLnNd_Error | N_StsLnNd_InvalidRef ;
00231 LnNdCnncn &cnn = operator[] (iOther) ;
00232 if (!(cnn.state & N_LnNdCnncnStt_Connected))
00233 return N_StsLnNd_Warning | N_StsLnNd_AlreadyDone ;
00234 StsLnNd ret = N_StsLnNd_OK ;
00235 LnNdCnncnType chg = 0 ;
00236 if (cnn.state & N_LnNdCnncnStt_ReservedBy) {
00237 chg |= N_LnNdCnncnStt_ChgReleasedBy ;
00238 ret |= N_StsLnNd_ReleasedBy ;
00239 }
00240 if (cnn.state & N_LnNdCnncnStt_Reserve) {
00241 chg |= N_LnNdCnncnStt_ChgRelease ;
00242 ret |= N_StsLnNd_Release ;
00243 }
00244 cnn.state &= ~(N_LnNdCnncnStt_Connected | N_LnNdCnncnStt_Reserve | N_LnNdCnncnStt_ReservedBy | N_LnNdCnncnStt_FlagA | N_LnNdCnncnStt_FlagB | N_LnNdCnncnStt_FlagC | N_LnNdCnncnStt_FlagD) ;
00245 chg |= N_LnNdCnncnStt_ChgDisconnected ;
00246 cnn.state |= chg ;
00247 connectionChanged (&cnn, chg) ;
00248 return ret ;
00249 }
00250
00251 void LinkNode::setReleasedBy (IndLnNd iOther) {
00252 ASSERT (mProtected) ;
00253 ASSERT (iOther != N_IndLnNd_Invalid && iOther < items ()) ;
00254 LnNdCnncn &cnn = operator[] (iOther) ;
00255 ASSERT ((cnn.state & (N_LnNdCnncnStt_ReservedBy | N_LnNdCnncnStt_Connected)) == (N_LnNdCnncnStt_ReservedBy | N_LnNdCnncnStt_Connected)) ;
00256 cnn.state &= ~N_LnNdCnncnStt_ReservedBy ;
00257 cnn.state |= N_LnNdCnncnStt_ChgReleasedBy ;
00258 connectionChanged (&cnn, N_LnNdCnncnStt_ChgReleasedBy) ;
00259 }
00260
00261 void LinkNode::removeProtect () {
00262 ASSERT (mProtected != 0) ;
00263 if (--mProtected == 0 && mChgCnncn) {
00264 notifyBeginNotify (mChgCnncn) ;
00265
00266
00267
00268 LnNdCnncnType changed = 0 ;
00269 while (mChgCnncn) {
00270 ASSERT (mLastChanged) ;
00271 changed |= mChgCnncn ;
00272 mProtected++ ;
00273 mChgCnncn = 0 ;
00274 sendNotifys () ;
00275 VERIFY (--mProtected == 0) ;
00276 }
00277
00278
00279
00280 if (changed & N_LnNdCnncnStt_ChgDisconnected)
00281 purgeDisconnectedConnections () ;
00282
00283
00284 notifyNotifiedAndPurged (changed) ;
00285 }
00286 }
00287
00288 void LinkNode::sendNotifys () {
00289 LnNdCnncn *cnn = (LnNdCnncn *) mLastChanged ;
00290 mLastChanged = NULL ;
00291 if (items ())
00292 if (mNotifyConnection) {
00293
00294 if (cnn != (LnNdCnncn *) -1) {
00295
00296
00297 LnNdCnncnType state = cnn->state ;
00298 cnn->state &= ~N_LnNdCnncnStt_Chg_ ;
00299 notifyConnection (state, cnn) ;
00300 } else {
00301
00302
00303 IndLnNd i = items () - 1 ;
00304 do {
00305 LnNdCnncn &cnn = (*this) [i] ;
00306 if (cnn.node)
00307 if (cnn.state & N_LnNdCnncnStt_Chg_) {
00308 LnNdCnncnType state = cnn.state ;
00309 cnn.state &= ~N_LnNdCnncnStt_Chg_ ;
00310 notifyConnection (state, &cnn) ;
00311 }
00312 } while (i-- != 0) ;
00313 }
00314 } else
00315 for (IndLnNd i = 0 ; i < items () ; i++)
00316 (*this) [i].state &= ~N_LnNdCnncnStt_Chg_ ;
00317 }
00318
00319 inline Bool isConnectionUsed (LnNdCnncnType state) {
00320 return (state & N_LnNdCnncnStt_Connected) ;
00321 }
00322
00323 Bool LinkNode::purgeDisconnectedConnections () {
00324 if (items ()) {
00325 Bool ret = N_false ;
00326 IndVect size = items () ;
00327 Bool purge = N_false ;
00328 for (IndLnNd i = 0 ; i < items () && isConnectionUsed ((*this) [i].state) ; i++) ;
00329 if (i < size) {
00330 IndLnNd iMoveTo = i ;
00331 do {
00332 for (i++ ; i < items () && !isConnectionUsed ((*this) [i].state) ; i++) ;
00333 if (i < items ()) {
00334 IndLnNd iMoveFrom = i ;
00335 for (i++ ; i < items () && isConnectionUsed ((*this) [i].state) ; i++) ;
00336 memmove (itemNT (iMoveTo), itemNT (iMoveFrom), (i - iMoveFrom) * mItemSize) ;
00337 size = iMoveTo = iMoveTo + (i - iMoveFrom) ;
00338 } else
00339 size = iMoveTo ;
00340 } while (i < items ()) ;
00341 setSize (size) ;
00342 return N_true ;
00343 }
00344 }
00345 return N_false ;
00346 }
00347
00348 void trace (LinkNode const &ob, IndVect indent, LnNdCnncnType show1) {
00349 String fill ;
00350 if (indent) {
00351 fill.set (' ', indent) ;
00352 TRACE ((CStr) fill) ;
00353 }
00354 TRACE ("%p: [%d/%d] %d %04lx %s %s ", (CPtr) &ob, (int) ob.connections ().items (), (int) ob.connections ().allocated (), (int) ob.gProtected (), (DWord) ob.gChgCnncn (), ob.clsName (), (CStr) ob.getHost (NULL)) ;
00355 char str [100] ;
00356 TRACE (ob.gLastChanged () ? (ob.gLastChanged () == (LnNdCnncn const *) -1 ? "-1" : type2Str (str, ob.connections ().index (ob.gLastChanged ()))) : "NULL") ;
00357 TRACE ("\n") ;
00358 LnNdCnncn const *cnn ;
00359 for (IndLnNd i = 0 ; (cnn = ob.iterConnection (i)) != NULL ; i++)
00360 if (show1 == N_LnNdCnncnStt_ || (cnn->state & show1)) {
00361 if (indent)
00362 TRACE ((CStr) fill) ;
00363 TRACE (" [%d] (%04lx %p %s %s)\n", (int) i, (DWord) cnn->state, (CPtr) cnn->node, (CStr) cnn->node->clsName (), (CStr) cnn->node->getHost (NULL)) ;
00364 }
00365 }
00366
00367 #ifdef __STRING_H__
00368 String& links2Str (String& ret, LinkNode const &ob) {
00369 char str [100] ;
00370 sprintf (str, "%p: %d [%d/%d] %04lx %s %s ", (CPtr) &ob, (int) ob.gProtected (), (int) ob.connections ().items (), (int) ob.connections ().allocated (), (DWord) ob.gChgCnncn (), ob.clsName (), (CStr) ob.getHost (NULL)) ;
00371 ret = str ;
00372 ret += (ob.gLastChanged () ? (ob.gLastChanged () == (LnNdCnncn const *) -1 ? "-1" : type2Str (str, ob.connections ().index (ob.gLastChanged ()))) : "NULL") ;
00373 LnNdCnncn const *cnn ;
00374 for (IndLnNd i = 0 ; (cnn = ob.iterConnected (i)) != NULL ; i++) {
00375 sprintf (str, " (%4lx %p %s %s)", (DWord) cnn->state, (CPtr) cnn->node, (CStr) cnn->node->clsName (), (CStr) cnn->node->getHost (NULL)) ;
00376 ret += str ;
00377 }
00378 return ret ;
00379 }
00380 #endif // __STRING_H__
00381
00383 IndLnNd VectLnNdCnncn::getGrow (IndLnNd minSize) const {
00384 IndLnNd ret = max ((IndLnNd) minSize, (IndLnNd) (mItems + (mItems ? mItems : 5))) ;
00385 return ret ;
00386 }
00387
00388 IndLnNd VectLnNdCnncn::find (LinkNode const *node) const {
00389 if (items ()) {
00390 IndLnNd i = items () - 1 ;
00391 do
00392 if (operator[] (i).node == node)
00393 return i ;
00394 while (i-- != 0) ;
00395 }
00396 return N_IndLnNd_Invalid ;
00397 }
00398
00399
00400
00402
00403
00404
00405
00406
00407
00408
00410
00411 SuspendLinkNodeNotify::~SuspendLinkNodeNotify () {
00412 releaseAll () ;
00413 }
00414
00415 void SuspendLinkNodeNotify::notifyConnection (LnNdCnncnType chg, LnNdCnncn const *cnncn) {
00416 if ((chg & (N_LnNdCnncnStt_Connected | N_LnNdCnncnStt_ChgConnected)) == (N_LnNdCnncnStt_Connected | N_LnNdCnncnStt_ChgConnected)) {
00417 LinkNode *node = (LinkNode *) cnncn->node ;
00418 ASSERT (node) ;
00419 node->addProtect () ;
00420 } else if ((chg & (N_LnNdCnncnStt_Connected | N_LnNdCnncnStt_ChgDisconnected)) == N_LnNdCnncnStt_ChgDisconnected) {
00421 LinkNode *node = (LinkNode *) cnncn->node ;
00422 ASSERT (node) ;
00423 node->removeProtect () ;
00424 }
00425 }
00426
00427 void SuspendLinkNodeNotify::notifyNotifiedAndPurged (LnNdCnncnType chg) {
00428 }
00429
00430 SuspendLinkNodeNotify &operator, (SuspendLinkNodeNotify &suspend, LinkNode &connect) {
00431 VERIFY_not_stsLnNdIsError (suspend.connect (connect)) ;
00432 return suspend ;
00433 }
00434
00435
00436
00438
00439
00440
00441
00442
00444
00445
00446
00447 ProcessNodes::ProcessNodes () {
00448 mCurrPrcNodes = &mNodesA ;
00449 mPendingCount = 0 ;
00450 }
00451
00452 ProcessNodes::~ProcessNodes () {
00453 }
00454
00455 void ProcessNodes::removeSuspend () {
00456 if (--mPendingCount == 0)
00457 process () ;
00458 }
00459
00460 void ProcessNodes::process () {
00461 while (pcrNodesCurr ().isConnected ()) {
00462 mPendingCount++ ;
00463 LinkNode &senders = pcrNodesCurr () ;
00464 mCurrPrcNodes = &prcNodesNotCurr () ;
00465
00466 senders.addProtect () ;
00467 LnNdCnncn const *cnn ;
00468 for (IndLnNd i = 0 ; !!(cnn = senders.iterConnected (i)) ; i++)
00469 process (*cnn) ;
00470 senders.disconnectAll () ;
00471 senders.removeProtect () ;
00472 mPendingCount-- ;
00473 }
00474 ASSERT (!mNodesA.isConnected ()) ;
00475 ASSERT (!mNodesB.isConnected ()) ;
00476 }
00477
00478 SuspendProcessNodes::SuspendProcessNodes (ProcessNodes *const *processors) : mProcessors (processors) {
00479 for (char i = 0 ; mProcessors [i] ; i++)
00480 mProcessors [i]->addSuspend () ;
00481 }
00482
00483 SuspendProcessNodes::~SuspendProcessNodes () {
00484 ASSERT (mProcessors [0]) ;
00485 char iPrc ;
00486 ProcessNodes *prc ;
00487 if (mProcessors [0]->gPendingCount () == 1) {
00488 char i ;
00489 for (iPrc = 0 ; !!(prc = mProcessors [iPrc]) ; iPrc++) {
00490 ASSERT (prc->gPendingCount () == 1) ;
00491 prc->process () ;
00492 for (i = 0 ; i < iPrc ; i++)
00493 if (mProcessors [i]->hasWaitingProcesses ())
00494 iPrc = i - i ;
00495 }
00496 }
00497 for (iPrc = 0 ; !!(prc = mProcessors [iPrc]) ; iPrc++)
00498 prc->removeSuspend () ;
00499 }
00500
00502
00503
00504
00505
00506
00507