void subcm_CheckTimeout () { pool_sQlink *cl; sub_sClient *cp; pwr_tTime curtim; pwr_tTime restim; pwr_tDeltaTime tmotim; pwr_tInt32 n; pwr_tInt32 i; gdb_AssumeLocked; gdbroot->db->tmocnt++; /* Statistics */ time_GetTime( &curtim); /* Calculate # of remote object clients to process this time */ n = gdbroot->db->subt_lc; if (n == 0) n = MIN(1, gdbroot->db->subt_lc); for (i=0; i<n; i++) { /* Temporarily remove the first entry from the queue for processing. */ cl = pool_QremoveSucc(NULL, gdbroot->pool, &gdbroot->db->subt_lh); cp = pool_Qitem(cl, sub_sClient, subt_ll); /* Find out if the client has timed out */ if (!cp->old) { /* cp->tmo in 10ths of seconds */ tmotim.tv_sec = cp->tmo / 10; tmotim.tv_nsec = (cp->tmo - tmotim.tv_sec * 10) * 100000000; time_Aadd(&restim, &cp->lastupdate, &tmotim); /* curtim >= tmotim + lastupdate */ if (time_Acomp(&curtim, &restim) >= 0) subc_SetOld(cp); } /* If it was old already */ /* Reinsert the entry last in the queue. */ pool_QinsertPred(NULL, gdbroot->pool, cl, &gdbroot->db->subt_lh); } }
void subc_ActivateList ( pool_sQlink *lh, pwr_tObjid oid ) { pwr_tStatus sts; tree_sTable *add; #if 0 tree_sTable *remove; sRemove *rep; #endif net_sSubSpec *specp; qcom_sQid tgt; pool_sQlink *my_lh; pwr_tUInt32 my_subc_lc; gdb_sNode *np; gdb_sNode *old_np; sub_sClient *cp; pool_sQlink *cl; sAdd *aep; /* Test each client. If existing object, fill in nid field and move the client to the appropriate nodes's subc_lh list. Turn on timeouts. Put request in subadd message buffer. We must do it all in one pass, since a user can come in during a cache query for a later subcli and cancel the subscription for an earlier subcli. */ add = tree_CreateTable(&sts, sizeof(pwr_tNodeId), offsetof(sAdd, nid), sizeof(sAdd), 10, tree_Comp_nid); #if 0 remove = tree_CreateTable(&sts, sizeof(pwr_tNodeId), offsetof(sRemove, nid), sizeof(sRemove), 10, tree_eComp_nid); #endif /* Move all objects to a new, temporary root */ my_lh = pool_Qalloc(NULL, gdbroot->pool); my_subc_lc = 0; for (cl = pool_Qsucc(NULL, gdbroot->pool, lh); cl != lh;) { cp = pool_Qitem(cl, sub_sClient, subc_ll); cl = pool_Qsucc(NULL, gdbroot->pool, cl); if (cdh_ObjidIsNull(oid) || cdh_ObjidIsEqual(oid, cp->aref.Objid)) { pool_Qremove(NULL, gdbroot->pool, &cp->subc_ll); pool_QinsertPred(NULL, gdbroot->pool, &cp->subc_ll, my_lh); my_subc_lc++; } } /* Now start testing clients from 'my_lh', and move them to other lists Make sure the clients are still there after the test. */ for (cl = pool_Qsucc(NULL, gdbroot->pool, my_lh); cl != my_lh; ) { cp = pool_Qitem(cl, sub_sClient, subc_ll); cl = pool_Qsucc(NULL, gdbroot->pool, cl); np = testClient(&sts, cp); /* If an error is returned the client doesn't exist anymore. Some other user removed it while TestSubcli had the database unlocked. Just go on with the next client... */ if (np == NULL) continue; /* Move the client to the list for the node where the object resides. nid = pwr_cNNodeId is used for all objects we don't know. */ old_np = hash_Search(&sts, gdbroot->nid_ht, &cp->nid); if (old_np == NULL) errh_Bugcheck(GDH__WEIRD, ""); pool_Qremove(NULL, gdbroot->pool, &cp->subc_ll); old_np->subc_lc--; pool_QinsertPred(NULL, gdbroot->pool, &cp->subc_ll, &np->subc_lh); np->subc_lc++; cp->nid = np->nid; /* If the object's nid changed, then take the appropriate actions. */ if (np != old_np) { if (np->nid != pwr_cNNodeId) { /* Object is known. */ activateTimeoutWatch(cp); aep = tree_Insert(&sts, add, &np->nid); if (aep == NULL) errh_Bugcheck(GDH__WEIRD, ""); if (aep->msg == NULL) { aep->cnt = MIN(my_subc_lc, net_cSubMaxAdd); aep->msg = malloc(sizeof(net_sSubAdd) + sizeof(net_sSubSpec) * aep->cnt); aep->msg->count = 0; } /* If there was no message allocated */ specp = &aep->msg->spec[aep->msg->count]; specp->sid = cp->sid; specp->dt = cp->dt; specp->sub_by_name = cp->sub_by_name; specp->aref = cp->cclass != pool_cNRef ? cp->raref : cp->aref; if (++aep->msg->count >= aep->cnt) { /* The message buffer is full and must be sent. */ tgt = np->handler; pwr_Assert(tgt.nid != pwr_cNNodeId); gdb_Unlock; net_Put(NULL, &tgt, aep->msg, net_eMsg_subAdd, 0, pwr_Offset(aep->msg, spec[aep->msg->count]), 0); gdb_Lock; aep->msg->count = 0; } } else { /* The object became unknown... */ cancelTimeoutWatch(cp); subc_SetOld(cp); /* Data gets old immediately */ #if 0 /** @todo Maybe we should unlock the cached class? */ if (cp->cclass != pwr_cNRefId) { ccp = pool_Address(NULL, gdbroot->pool, cp->cclass); if (ccp == NULL) errh_Bugcheck(GDH__WEIRD, "Cached class address"); cmvolc_UnlockClass(NULL, ccp); cp->cclass = pwr_cNRefId; } #endif #if 0 if (old_np->nid != pwr_cNNodeId) { rep = tree_Insert(&sts, remove, &old_np->nid); if (rep == NULL) errh_Bugcheck(GDH__WEIRD, ""); if (rep->msg == NULL) { rep->nid = old_np->nid; rep->cnt = MIN(my_subc_lc, net_cSubMaxRemove); rep->msg = malloc(sizeof(net_sSubRemove) + sizeof(rep->msg->sid[0]) * rep->cnt); rep->msg->count = 0; } rep->msg->sid[rep->msg->count++] = cp->sid; if (rep->msg->count >= net_cSubMaxRemove) { np = hash_Search(&sts, gdbroot->nid_ht, &old_np->nid); if (np == NULL) errh_Bugcheck(sts, ""); tgt.nid = rep->nid; pwr_Assert(tgt.nid != pwr_cNNodeId); gdb_Unlock; net_Put(NULL, &tgt, rep->msg, net_eMsg_subRemove, 0, pwr_Offset(rep->msg, sid[rep->msg->count]), 0); gdb_Lock; rep->msg->count = 0; } } #endif } } } pool_Free(NULL, gdbroot->pool, my_lh); /* Now walk through the addmsg & remmsg and send all unsent messages. */ gdb_Unlock; #if 0 for (rep = tree_Minimum(remove); rep != NULL; rep = tree_Successor(remove, rep)) { if (rep->msg != NULL) { if (rep->msg->count > 0) { tgt.nid = rep->nid; pwr_Assert(tgt.nid != pwr_cNNodeId); net_Put(NULL, &tgt, rep->msg, net_eMsg_subRemove, 0, pwr_Offset(rep->msg, sid[rep->msg->count]), 0); } free(rep->msg); } } #endif for (aep = tree_Minimum(&sts, add); aep != NULL; aep = tree_Successor(&sts, add, aep)) { if (aep->msg != NULL) { if (aep->msg->count > 0) { np = hash_Search(&sts, gdbroot->nid_ht, &aep->nid); if (np == NULL) errh_Bugcheck(GDH__WEIRD, ""); tgt = np->handler; pwr_Assert(tgt.nid != pwr_cNNodeId); net_Put(NULL, &tgt, aep->msg, net_eMsg_subAdd, 0, pwr_Offset(aep->msg, spec[aep->msg->count]), 0); } free(aep->msg); } } gdb_Lock; tree_DeleteTable(&sts, add); #if 0 tree_DeleteTable(remove); #endif }