int ClientCursor::suggestYieldMicros() { int writers = 0; int readers = 0; int micros = Client::recommendedYieldMicros( &writers , &readers ); if ( micros > 0 && writers == 0 && Lock::isR() ) { // we have a read lock, and only reads are coming on, so why bother unlocking return 0; } wassert( micros < 10000000 ); dassert( micros < 1000001 ); return micros; }
void wsheet_ucmd_end(struct wsheet* wsh) { /* nothing to do */ switch(wsh->ucmd->ty) { case UCMD_CURVE: case UCMD_ZMV: case UCMD_CUT: { } break; default: wassert(0); /* shouldn't reach here! */ } _ucmd_quick_end(wsh); }
ClientCursor::~ClientCursor() { if( _pos == -2 ) { // defensive: destructor called twice wassert(false); return; } { recursive_scoped_lock lock(ccmutex); clientCursorsById.erase(_cursorid); // defensive: _cursorid = INVALID_CURSOR_ID; _pos = -2; _pinValue = 0; } }
ClientCursor::~ClientCursor() { if( _pos == -2 ) { // defensive: destructor called twice wassert(false); return; } { recursive_scoped_lock lock(ccmutex); setLastLoc_inlock( DiskLoc() ); // removes us from bylocation multimap clientCursorsById.erase(_cursorid); // defensive: (CursorId&)_cursorid = -1; _pos = -2; } }
BSONElement getErrField(const BSONObj& o) { BSONElement first = o.firstElement(); if( strcmp(first.fieldName(), "$err") == 0 ) return first; // temp - will be DEV only later /*DEV*/ if( 1 ) { BSONElement e = o["$err"]; if( !e.eoo() ) { wassert(false); } return e; } return BSONElement(); }
/*template <class T_t, class G_t>*/ static int tree_dec_lospre (tree_dec_lospre_t/*T_t*/ &T, cfg_lospre_t/*G_t*/ &G, const iCode *ic) { if(tree_dec_lospre_nodes(T, find_root(T), G)) return(-1); wassert(T[find_root(T)].assignments.begin() != T[find_root(T)].assignments.end()); const assignment_lospre &winner = *(T[find_root(T)].assignments.begin()); //std::cout << "Winner (lospre): "; //print_assignment(winner, G); int change; if (change = implement_lospre_assignment(winner, T, G, ic)) nicify (T); T[find_root(T)].assignments.clear(); return(change); }
/*template <class T_t, class G_t>*/ static int tree_dec_safety (tree_dec_lospre_t/*T_t*/ &T, cfg_lospre_t/*G_t*/ &G, const iCode *ic) { if(tree_dec_safety_nodes(T, find_root(T), G)) return(-1); wassert(T[find_root(T)].assignments.begin() != T[find_root(T)].assignments.end()); const assignment_lospre &winner = *(T[find_root(T)].assignments.begin()); implement_safety(winner, G); #ifdef DEBUG_LOSPRE std::cout << "Winner (safety): "; print_assignment(winner, G); #endif T[find_root(T)].assignments.clear(); return (0); }
void Lock::DBRead::unlockDB() { if( _weLocked ) { recordTime(); // for lock stats if( _nested ) _lockState->unlockedNestable(); else _lockState->unlockedOther(); _weLocked->unlock_shared(); } if( _locked_r ) { wassert(_lockState->threadState() == 'r'); _lockState->unlocked(); qlk.q.unlock_r(); } _weLocked = 0; _locked_r = false; }
bool DatabaseHolder::closeAll( const string& path , BSONObjBuilder& result , bool force ) { log() << "DatabaseHolder::closeAll path:" << path << endl; verify( Lock::isW() ); getDur().commitNow(); // bad things happen if we close a DB with outstanding writes map<string,Database*>& m = _paths[path]; _size -= m.size(); set< string > dbs; for ( map<string,Database*>::iterator i = m.begin(); i != m.end(); i++ ) { wassert( i->second->path() == path ); dbs.insert( i->first ); } currentClient.get()->getContext()->_clear(); BSONObjBuilder bb( result.subarrayStart( "dbs" ) ); int n = 0; int nNotClosed = 0; for( set< string >::iterator i = dbs.begin(); i != dbs.end(); ++i ) { string name = *i; LOG(2) << "DatabaseHolder::closeAll path:" << path << " name:" << name << endl; Client::Context ctx( name , path ); if( !force && BackgroundOperation::inProgForDb(name) ) { log() << "WARNING: can't close database " << name << " because a bg job is in progress - try killOp command" << endl; nNotClosed++; } else { Database::closeDatabase( name.c_str() , path ); bb.append( bb.numStr( n++ ) , name ); } } bb.done(); if( nNotClosed ) result.append("nNotClosed", nNotClosed); else { ClientCursor::assertNoCursors(); } return true; }
/* "slow"/infrequent portion of 'grow()' */ void NOINLINE_DECL AlignedBuilder::growReallocate(unsigned oldLen) { dassert( _len > _p._size ); unsigned a = _p._size; verify( a ); while( 1 ) { if( a < 128 * 1024 * 1024 ) a *= 2; else if( sizeof(int*) == 4 ) a += 32 * 1024 * 1024; else a += 64 * 1024 * 1024; DEV if( a > 256*1024*1024 ) { log() << "dur AlignedBuilder too big, aborting in _DEBUG build" << endl; abort(); } wassert( a <= 256*1024*1024 ); verify( a <= 512*1024*1024 ); if( _len < a ) break; } _realloc(a, oldLen); }
ClientCursor::~ClientCursor() { if( _pos == -2 ) { // defensive: destructor called twice wassert(false); return; } { recursive_scoped_lock lock(ccmutex); if (NULL != _c.get()) { // Removes 'this' from bylocation map setLastLoc_inlock( DiskLoc() ); } clientCursorsById.erase(_cursorid); // defensive: _cursorid = INVALID_CURSOR_ID; _pos = -2; _pinValue = 0; } }
void GhostSync::associateSlave(const BSONObj& id, const int memberId) { const OID rid = id["_id"].OID(); rwlock lk( _lock , true ); shared_ptr<GhostSlave> &g = _ghostCache[rid]; if( g.get() == 0 ) { g.reset( new GhostSlave() ); wassert( _ghostCache.size() < 10000 ); } GhostSlave &slave = *g; if (slave.init) { LOG(1) << "tracking " << slave.slave->h().toString() << " as " << rid << rsLog; return; } slave.slave = (Member*)rs->findById(memberId); if (slave.slave != 0) { slave.init = true; } else { log() << "replset couldn't find a slave with id " << memberId << ", not tracking " << rid << rsLog; } }
/* delete this index. does NOT clean up the system catalog (system.indexes or system.namespaces) -- only NamespaceIndex. */ void IndexDetails::kill_idx() { string ns = indexNamespace(); // e.g. foo.coll.$ts_1 string pns = parentNS(); // note we need a copy, as parentNS() won't work after the drop() below // clean up parent namespace index cache NamespaceDetailsTransient::get_w( pns.c_str() ).deletedIndex(); string name = indexName(); /* important to catch exception here so we can finish cleanup below. */ try { btreeStore->drop(ns.c_str()); } catch(DBException& ) { log(2) << "IndexDetails::kill(): couldn't drop ns " << ns << endl; } head.setInvalid(); info.setInvalid(); // clean up in system.indexes. we do this last on purpose. int n = removeFromSysIndexes(pns.c_str(), name.c_str()); wassert( n == 1 ); }
void appendReplicationInfo(BSONObjBuilder& result, int level) { if ( replSet ) { if( theReplSet == 0 || theReplSet->state().shunned() ) { result.append("ismaster", false); result.append("secondary", false); result.append("info", ReplSet::startupStatusMsg.get()); result.append( "isreplicaset" , true ); } else { theReplSet->fillIsMaster(result); } return; } if ( replAllDead ) { result.append("ismaster", 0); string s = string("dead: ") + replAllDead; result.append("info", s); } else { result.appendBool("ismaster", _isMaster() ); } if ( level && replSet ) { result.append( "info" , "is replica set" ); } else if ( level ) { BSONObjBuilder sources( result.subarrayStart( "sources" ) ); int n = 0; list<BSONObj> src; { Client::ReadContext ctx("local.sources", dbpath); shared_ptr<Cursor> c = findTableScan("local.sources", BSONObj()); while ( c->ok() ) { src.push_back(c->current()); c->advance(); } } for( list<BSONObj>::const_iterator i = src.begin(); i != src.end(); i++ ) { BSONObj s = *i; BSONObjBuilder bb; bb.append( s["host"] ); string sourcename = s["source"].valuestr(); if ( sourcename != "main" ) bb.append( s["source"] ); { BSONElement e = s["syncedTo"]; BSONObjBuilder t( bb.subobjStart( "syncedTo" ) ); t.appendDate( "time" , e.timestampTime() ); t.append( "inc" , e.timestampInc() ); t.done(); } if ( level > 1 ) { wassert( !Lock::isLocked() ); // note: there is no so-style timeout on this connection; perhaps we should have one. ScopedDbConnection conn(s["host"].valuestr()); DBClientConnection *cliConn = dynamic_cast< DBClientConnection* >( &conn.conn() ); if ( cliConn && replAuthenticate(cliConn, false) ) { BSONObj first = conn->findOne( (string)"local.oplog.$" + sourcename, Query().sort( BSON( "$natural" << 1 ) ) ); BSONObj last = conn->findOne( (string)"local.oplog.$" + sourcename, Query().sort( BSON( "$natural" << -1 ) ) ); bb.appendDate( "masterFirst" , first["ts"].timestampTime() ); bb.appendDate( "masterLast" , last["ts"].timestampTime() ); double lag = (double) (last["ts"].timestampTime() - s["syncedTo"].timestampTime()); bb.append( "lagSeconds" , lag / 1000 ); } conn.done(); } sources.append( BSONObjBuilder::numStr( n++ ) , bb.obj() ); } sources.done(); } }
UpdateResult _updateObjects( bool su, const char* ns, const BSONObj& updateobj, const BSONObj& patternOrig, bool upsert, bool multi, bool logop , OpDebug& debug, RemoveSaver* rs, bool fromMigrate, const QueryPlanSelectionPolicy& planPolicy, bool forReplication ) { DEBUGUPDATE( "update: " << ns << " update: " << updateobj << " query: " << patternOrig << " upsert: " << upsert << " multi: " << multi ); Client& client = cc(); debug.updateobj = updateobj; // The idea with these here it to make them loop invariant for // multi updates, and thus be a bit faster for that case. The // pointers may be left invalid on a failed or terminal yield // recovery. NamespaceDetails* d = nsdetails(ns); // can be null if an upsert... NamespaceDetailsTransient* nsdt = &NamespaceDetailsTransient::get(ns); auto_ptr<ModSet> mods; bool isOperatorUpdate = updateobj.firstElementFieldName()[0] == '$'; int modsIsIndexed = false; // really the # of indexes if ( isOperatorUpdate ) { mods.reset( new ModSet(updateobj, nsdt->indexKeys(), forReplication) ); modsIsIndexed = mods->maxNumIndexUpdated(); } if( planPolicy.permitOptimalIdPlan() && !multi && isSimpleIdQuery(patternOrig) && d && !modsIsIndexed ) { int idxNo = d->findIdIndex(); if( idxNo >= 0 ) { debug.idhack = true; UpdateResult result = _updateById( isOperatorUpdate, idxNo, mods.get(), d, nsdt, su, ns, updateobj, patternOrig, logop, debug, fromMigrate); if ( result.existing || ! upsert ) { return result; } else if ( upsert && ! isOperatorUpdate ) { // this handles repl inserts checkNoMods( updateobj ); debug.upsert = true; BSONObj no = updateobj; theDataFileMgr.insertWithObjMod(ns, no, false, su); if ( logop ) logOp( "i", ns, no, 0, 0, fromMigrate, &no ); return UpdateResult( 0 , 0 , 1 , no ); } } } int numModded = 0; debug.nscanned = 0; shared_ptr<Cursor> c = getOptimizedCursor( ns, patternOrig, BSONObj(), planPolicy ); d = nsdetails(ns); nsdt = &NamespaceDetailsTransient::get(ns); bool autoDedup = c->autoDedup(); if( c->ok() ) { set<DiskLoc> seenObjects; MatchDetails details; auto_ptr<ClientCursor> cc; do { if ( cc.get() == 0 && client.allowedToThrowPageFaultException() && ! c->currLoc().isNull() && ! c->currLoc().rec()->likelyInPhysicalMemory() ) { throw PageFaultException( c->currLoc().rec() ); } bool atomic = c->matcher() && c->matcher()->docMatcher().atomic(); if ( ! atomic && debug.nscanned > 0 ) { // we need to use a ClientCursor to yield if ( cc.get() == 0 ) { shared_ptr< Cursor > cPtr = c; cc.reset( new ClientCursor( QueryOption_NoCursorTimeout , cPtr , ns ) ); } bool didYield; if ( ! cc->yieldSometimes( ClientCursor::WillNeed, &didYield ) ) { cc.release(); break; } if ( !c->ok() ) { break; } if ( didYield ) { d = nsdetails(ns); if ( ! d ) break; nsdt = &NamespaceDetailsTransient::get(ns); if ( mods.get() ) { mods->setIndexedStatus( nsdt->indexKeys() ); modsIsIndexed = mods->maxNumIndexUpdated(); } } } // end yielding block debug.nscanned++; if ( mods.get() && mods->hasDynamicArray() ) { details.requestElemMatchKey(); } if ( !c->currentMatches( &details ) ) { c->advance(); continue; } Record* r = c->_current(); DiskLoc loc = c->currLoc(); if ( c->getsetdup( loc ) && autoDedup ) { c->advance(); continue; } BSONObj js = BSONObj::make(r); BSONObj pattern = patternOrig; if ( logop ) { BSONObjBuilder idPattern; BSONElement id; // NOTE: If the matching object lacks an id, we'll log // with the original pattern. This isn't replay-safe. // It might make sense to suppress the log instead // if there's no id. if ( js.getObjectID( id ) ) { idPattern.append( id ); pattern = idPattern.obj(); } else { uassert( 10157 , "multi-update requires all modified objects to have an _id" , ! multi ); } } /* look for $inc etc. note as listed here, all fields to inc must be this type, you can't set some regular ones at the moment. */ if ( isOperatorUpdate ) { if ( multi ) { // go to next record in case this one moves c->advance(); // Update operations are deduped for cursors that implement their own // deduplication. In particular, some geo cursors are excluded. if ( autoDedup ) { if ( seenObjects.count( loc ) ) { continue; } // SERVER-5198 Advance past the document to be modified, provided // deduplication is enabled, but see SERVER-5725. while( c->ok() && loc == c->currLoc() ) { c->advance(); } } } const BSONObj& onDisk = loc.obj(); ModSet* useMods = mods.get(); auto_ptr<ModSet> mymodset; if ( details.hasElemMatchKey() && mods->hasDynamicArray() ) { useMods = mods->fixDynamicArray( details.elemMatchKey() ); mymodset.reset( useMods ); } auto_ptr<ModSetState> mss = useMods->prepare( onDisk, false /* not an insertion */ ); bool willAdvanceCursor = multi && c->ok() && ( modsIsIndexed || ! mss->canApplyInPlace() ); if ( willAdvanceCursor ) { if ( cc.get() ) { cc->setDoingDeletes( true ); } c->prepareToTouchEarlierIterate(); } // If we've made it this far, "ns" must contain a valid collection name, and so // is of the form "db.collection". Therefore, the following expression must // always be valid. "system.users" updates must never be done in place, in // order to ensure that they are validated inside DataFileMgr::updateRecord(.). bool isSystemUsersMod = (NamespaceString(ns).coll == "system.users"); BSONObj newObj; if ( !mss->isUpdateIndexed() && mss->canApplyInPlace() && !isSystemUsersMod ) { mss->applyModsInPlace( true );// const_cast<BSONObj&>(onDisk) ); DEBUGUPDATE( "\t\t\t doing in place update" ); if ( !multi ) debug.fastmod = true; if ( modsIsIndexed ) { seenObjects.insert( loc ); } newObj = loc.obj(); d->paddingFits(); } else { newObj = mss->createNewFromMods(); checkTooLarge(newObj); DiskLoc newLoc = theDataFileMgr.updateRecord(ns, d, nsdt, r, loc, newObj.objdata(), newObj.objsize(), debug); if ( newLoc != loc || modsIsIndexed ){ // log() << "Moved obj " << newLoc.obj()["_id"] << " from " << loc << " to " << newLoc << endl; // object moved, need to make sure we don' get again seenObjects.insert( newLoc ); } } if ( logop ) { DEV verify( mods->size() ); BSONObj logObj = mss->getOpLogRewrite(); DEBUGUPDATE( "\t rewrite update: " << logObj ); // It is possible that the entire mod set was a no-op over this // document. We would have an empty log record in that case. If we // call logOp, with an empty record, that would be replicated as "clear // this record", which is not what we want. Therefore, to get a no-op // in the replica, we simply don't log. if ( logObj.nFields() ) { logOp("u", ns, logObj , &pattern, 0, fromMigrate, &newObj ); } } numModded++; if ( ! multi ) return UpdateResult( 1 , 1 , numModded , BSONObj() ); if ( willAdvanceCursor ) c->recoverFromTouchingEarlierIterate(); getDur().commitIfNeeded(); continue; } uassert( 10158 , "multi update only works with $ operators" , ! multi ); BSONElementManipulator::lookForTimestamps( updateobj ); checkNoMods( updateobj ); theDataFileMgr.updateRecord(ns, d, nsdt, r, loc , updateobj.objdata(), updateobj.objsize(), debug, su); if ( logop ) { DEV wassert( !su ); // super used doesn't get logged, this would be bad. logOp("u", ns, updateobj, &pattern, 0, fromMigrate, &updateobj ); } return UpdateResult( 1 , 0 , 1 , BSONObj() ); } while ( c->ok() ); } // endif if ( numModded ) return UpdateResult( 1 , 1 , numModded , BSONObj() ); if ( upsert ) { if ( updateobj.firstElementFieldName()[0] == '$' ) { // upsert of an $operation. build a default object BSONObj newObj = mods->createNewFromQuery( patternOrig ); checkNoMods( newObj ); debug.fastmodinsert = true; theDataFileMgr.insertWithObjMod(ns, newObj, false, su); if ( logop ) logOp( "i", ns, newObj, 0, 0, fromMigrate, &newObj ); return UpdateResult( 0 , 1 , 1 , newObj ); } uassert( 10159 , "multi update only works with $ operators" , ! multi ); checkNoMods( updateobj ); debug.upsert = true; BSONObj no = updateobj; theDataFileMgr.insertWithObjMod(ns, no, false, su); if ( logop ) logOp( "i", ns, no, 0, 0, fromMigrate, &no ); return UpdateResult( 0 , 0 , 1 , no ); } return UpdateResult( 0 , isOperatorUpdate , 0 , BSONObj() ); }
/** Mark variables for assignment by the register allocator. */ static void serialRegMark (eBBlock ** ebbs, int count) { int i; short int max_alloc_bytes = SHRT_MAX; // Byte limit. Set this to a low value to pass only few variables to the register allocator. This can be useful for debugging. stm8_call_stack_size = 2; // Saving of register to stack temporarily. /* for all blocks */ for (i = 0; i < count; i++) { iCode *ic; if (ebbs[i]->noPath && (ebbs[i]->entryLabel != entryLabel && ebbs[i]->entryLabel != returnLabel)) continue; /* for all instructions do */ for (ic = ebbs[i]->sch; ic; ic = ic->next) { if ((ic->op == CALL || ic->op == PCALL) && ic->parmBytes + 5 > stm8_call_stack_size) { sym_link *dtype = operandType (IC_LEFT (ic)); sym_link *ftype = IS_FUNCPTR (dtype) ? dtype->next : dtype; /* 5 for saving all registers at call site + 2 for big return value */ stm8_call_stack_size = ic->parmBytes + 5 + 2 * (getSize (ftype->next) > 4); } if (ic->op == IPOP) wassert (0); /* if result is present && is a true symbol */ if (IC_RESULT (ic) && ic->op != IFX && IS_TRUE_SYMOP (IC_RESULT (ic))) OP_SYMBOL (IC_RESULT (ic))->allocreq++; /* some don't need registers, since there is no result. */ if (SKIP_IC2 (ic) || ic->op == JUMPTABLE || ic->op == IFX || ic->op == IPUSH || ic->op == IPOP || (IC_RESULT (ic) && POINTER_SET (ic))) continue; /* now we need to allocate registers only for the result */ if (IC_RESULT (ic)) { symbol *sym = OP_SYMBOL (IC_RESULT (ic)); D (D_ALLOC, ("serialRegAssign: in loop on result %p\n", sym)); if (sym->isspilt && sym->usl.spillLoc) // todo: Remove once remat is supported! { sym->usl.spillLoc->allocreq--; sym->isspilt = FALSE; } /* Make sure any spill location is definately allocated */ if (sym->isspilt && !sym->remat && sym->usl.spillLoc && !sym->usl.spillLoc->allocreq) sym->usl.spillLoc->allocreq++; /* if it does not need or is spilt or is already marked for the new allocator or will not live beyond this instructions */ if (!sym->nRegs || sym->isspilt || sym->for_newralloc || sym->liveTo <= ic->seq) { D (D_ALLOC, ("serialRegAssign: won't live long enough.\n")); continue; } if (sym->nRegs > 4 && ic->op == CALL) { spillThis (sym, TRUE); } else if (max_alloc_bytes >= sym->nRegs) { sym->for_newralloc = 1; max_alloc_bytes -= sym->nRegs; } else if (!sym->for_newralloc) { spillThis (sym, TRUE); printf ("Spilt %s due to byte limit.\n", sym->name); } } } } }
/*-----------------------------------------------------------------*/ void separateLiveRanges (iCode *sic, ebbIndex *ebbi) { iCode *ic; set *candidates = 0; symbol *sym; // printf("separateLiveRanges()\n"); for (ic = sic; ic; ic = ic->next) { if (ic->op == IFX || ic->op == GOTO || ic->op == JUMPTABLE || !IC_RESULT (ic) || !IS_ITEMP (IC_RESULT (ic)) || bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) <= 1 || isinSet (candidates, OP_SYMBOL (IC_RESULT (ic)))) continue; addSet (&candidates, OP_SYMBOL (IC_RESULT (ic))); } if (!candidates) return; for(sym = setFirstItem (candidates); sym; sym = setNextItem (candidates)) { // printf("Looking at %s, %d definitions\n", sym->name, bitVectnBitsOn (sym->defs)); int i; set *defs = 0; for (i = 0; i < sym->defs->size; i++) if (bitVectBitValue (sym->defs, i)) { iCode *dic; if(dic = hTabItemWithKey (iCodehTab, i)) addSet (&defs, hTabItemWithKey (iCodehTab, i)); else { werror (W_INTERNAL_ERROR, __FILE__, __LINE__, "Definition not found"); return; } } do { set *visited = 0; set *newdefs = 0; int oldsize; wassert (defs); wassert (setFirstItem (defs)); // printf("Looking at def at %d now\n", ((iCode *)(setFirstItem (defs)))->key); if (!bitVectBitValue (((iCode *)(setFirstItem (defs)))->rlive, sym->key)) { werror (W_INTERNAL_ERROR, __FILE__, __LINE__, "Variable is not alive at one of its definitions"); break; } visit (&visited, setFirstItem (defs), sym->key); addSet (&newdefs, setFirstItem (defs)); do { oldsize = elementsInSet(visited); ic = setFirstItem (defs); for(ic = setNextItem (defs); ic; ic = setNextItem (defs)) { // printf("Looking at other def at %d now\n", ic->key); set *visited2 = 0; set *intersection = 0; visit (&visited2, ic, sym->key); intersection = intersectSets (visited, visited2, THROW_NONE); intersection = subtractFromSet (intersection, defs, THROW_DEST); if (intersection) { visited = unionSets (visited, visited2, THROW_DEST); addSet (&newdefs, ic); } deleteSet (&intersection); deleteSet (&visited2); } } while (oldsize < elementsInSet(visited)); defs = subtractFromSet (defs, newdefs, THROW_DEST); if (newdefs && defs) { operand *tmpop = newiTempOperand (operandType (IC_RESULT ((iCode *)(setFirstItem (newdefs)))), TRUE); // printf("Splitting %s from %s, using def at %d, op %d\n", OP_SYMBOL_CONST(tmpop)->name, sym->name, ((iCode *)(setFirstItem (newdefs)))->key, ((iCode *)(setFirstItem (newdefs)))->op); for (ic = setFirstItem (visited); ic; ic = setNextItem (visited)) { if (IC_LEFT (ic) && IS_ITEMP (IC_LEFT (ic)) && OP_SYMBOL (IC_LEFT (ic)) == sym) IC_LEFT (ic) = operandFromOperand (tmpop); if (IC_RIGHT (ic) && IS_ITEMP (IC_RIGHT (ic)) && OP_SYMBOL (IC_RIGHT (ic)) == sym) IC_RIGHT (ic) = operandFromOperand (tmpop); if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)) && OP_SYMBOL (IC_RESULT (ic)) == sym && !POINTER_SET(ic) && ic->next && !isinSet (visited, ic->next)) continue; if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)) && OP_SYMBOL (IC_RESULT (ic)) == sym) { bool pset = POINTER_SET(ic); IC_RESULT (ic) = operandFromOperand (tmpop); if (pset) IC_RESULT(ic)->isaddr = TRUE; } bitVectUnSetBit (sym->uses, ic->key); } } deleteSet (&newdefs); deleteSet (&visited); } while (elementsInSet(defs) > 1); deleteSet (&defs); } deleteSet (&candidates); }
void wsheet_add_curve(struct wsheet* wsh, const int32_t* pts, uint16_t nrpts, uint8_t thick, uint16_t color) { void _add_pointnd_last(struct list_link* hd, int32_t x, int32_t y) { if (hd) pointnd_add_last(hd, x, y); } void __add_curve(struct div* div, struct list_link* hd) { if (hd && list_size(hd) > 0) { struct curve* crv = _create_curve_pointnd_list(hd); crv->color = color; crv->thick = thick; div_add_curve(div, crv); if (wsh->ucmd) ucmd_crv_data(wsh->ucmd, crv); /* free memory for new start */ pointnd_free_list(hd); } } int32_t x0, y0, x1, y1, itx, ity; int32_t ri, ci; /* row/column index */ const int32_t *pt, *ptend; struct list_link hd, *phd; if (nrpts < 2) { wwarn(); return; } /* * "NULL == wsh->ucmd" means this is NOT USER Command! */ wassert(!wsh->ucmd || UCMD_CURVE == wsh->ucmd->ty); list_init_link(&hd); pt = pts; ptend = pts + (nrpts * 2); /* * initial setting */ x0 = *pt++; y0 = *pt++; x1 = *pt++; y1 = *pt++; /* wlogd("ADD : %d, %d, %d, %d", x0, y0, x1, y1); */ #define __update_division_info(x, y) \ do { \ ci = _divI(x, wsh->divW); \ ri = _divI(y, wsh->divH); \ phd = (_is_valid_div_index(wsh, ri, ci))? &hd: NULL; \ } while (0) __update_division_info(x0, y0); while (pt <= ptend) { _add_pointnd_last(phd, x0, y0); if (_add_line(phd, _divL(wsh, ci), _divT(wsh, ri), _divR(wsh, ci), _divB(wsh, ri), x0, y0, x1, y1, &itx, &ity)) { /* * add intersection point * this is last point of this curve. */ _add_pointnd_last(phd, itx, ity); __add_curve(&wsh->divs[ri][ci], phd); /* * division is changed!! * update division */ x0 = itx; y0 = ity; __update_division_info(x0, y0); } else { x0 = x1; y0 = y1; x1 = *pt++; y1 = *pt++; } } /* add last point */ _add_pointnd_last(phd, x0, y0); __add_curve(&wsh->divs[ri][ci], phd); #undef __update_division_info }
/* * @return : 0 (next point) * others (new division. again with updated point.) */ static int _add_line(struct list_link* hd, int32_t l, int32_t t, int32_t r, int32_t b, int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t* itx, int32_t* ity) { int32_t i0, i1; /* intersect */ wassert(!(x0 == x1 && y0 == y1) && rect_is_in(l, t, r, b, x0, y0)); /* * Trivial case. * x1, y1 is already in boundary */ if (rect_is_line_in(l, t, r, b, x0, y0, x1, y1)) return 0; /* * General case. */ /* * NOTE * ---- * 1-pixel-error caused by open/close concept of line and rect * may leads that some line-drawn-pixels are out of * division pixel * * See below * [ Notation ] * I : intersection point(pixel) * X : filled pixel (drawn) * m : missing pixel * * [Point1] * +---+---+---+---+---+ * | | X | I | X | | <-- This is area of div1 * +---+---+---+---+---+ * | | | | X | X | <-- top of div0 / bottom of div1 * +---+---+---+---+---+ [Point0] * * This 1-pixel-error may cause memory corruption. * (Accessing out of allocated pixels) * So, this should be compensated and resolved at * LINE-DRAWING-ALGORITHM !!! * Important! * There is NO ERROR LARGER THAN 1-pixel! * This SPLIT ALGORITHM guarantees this!! * * WARNING * ------- * If we don't use open/close concept at line * There may be several pixel lost. * This is critical * * +---+---+---+---+---+ * | X | I | m | | | <-- bottom of div1 * +---+---+---+---+---+ * | | | m | m | I | <-- top of div0 * +---+---+---+---+---+ [Point0] * */ #define __split(func, v, pv, pit, min, max) \ switch (func(&i0, &i1, x0, y0, x1, y1, v, min, max)) { \ case 1: \ (pv) = (v); \ (pit) = i0; \ return 1; \ \ case 2: \ wassert(0); /* this shouldn't happen! */ \ break; \ } /* * There should be one intersection point that is inside boundary! * * For example, if intersection with right is out of bounary (if slop * is large.), intersection with top should be inside boundary * vice versa. * * +-----------------------+ <- 1 pixel out * | +-------------------+ | * | | | | * | | | | * * (l - 1, t - 1, r, b) is rect i-pixel-out */ __split(line_intersectx, l - 1, *itx, *ity, t - 1, b); __split(line_intersectx, r, *itx, *ity, t - 1, b); __split(line_intersecty, t - 1, *ity, *itx, l - 1, r); /* last 'r + 1' to fill open point (r, b). */ __split(line_intersecty, b, *ity, *itx, l - 1, r + 1); #undef __split /* SHOULDN'T reach here!! */ wloge("***(%d, %d, %d, %d / (%d, %d) (%d, %d)***\n", l, t, r, b, x0, y0, x1, y1); wassert(0); return 0; #undef __add_to_list }
/* must call this on a delete so we clean up the cursors. */ void ClientCursor::aboutToDelete(const DiskLoc& dl) { recursive_scoped_lock lock(ccmutex); Database *db = cc().database(); assert(db); aboutToDeleteForSharding( db , dl ); CCByLoc& bl = db->ccByLoc; CCByLoc::iterator j = bl.lower_bound(ByLocKey::min(dl)); CCByLoc::iterator stop = bl.upper_bound(ByLocKey::max(dl)); if ( j == stop ) return; vector<ClientCursor*> toAdvance; while ( 1 ) { toAdvance.push_back(j->second); DEV assert( j->first.loc == dl ); ++j; if ( j == stop ) break; } if( toAdvance.size() >= 3000 ) { log() << "perf warning MPW101: " << toAdvance.size() << " cursors for one diskloc " << dl.toString() << ' ' << toAdvance[1000]->_ns << ' ' << toAdvance[2000]->_ns << ' ' << toAdvance[1000]->_pinValue << ' ' << toAdvance[2000]->_pinValue << ' ' << toAdvance[1000]->_pos << ' ' << toAdvance[2000]->_pos << ' ' << toAdvance[1000]->_idleAgeMillis << ' ' << toAdvance[2000]->_idleAgeMillis << ' ' << toAdvance[1000]->_doingDeletes << ' ' << toAdvance[2000]->_doingDeletes << endl; //wassert( toAdvance.size() < 5000 ); } for ( vector<ClientCursor*>::iterator i = toAdvance.begin(); i != toAdvance.end(); ++i ) { ClientCursor* cc = *i; wassert(cc->_db == db); if ( cc->_doingDeletes ) continue; Cursor *c = cc->_c.get(); if ( c->capped() ) { /* note we cannot advance here. if this condition occurs, writes to the oplog have "caught" the reader. skipping ahead, the reader would miss postentially important data. */ delete cc; continue; } c->checkLocation(); DiskLoc tmp1 = c->refLoc(); if ( tmp1 != dl ) { // This might indicate a failure to call ClientCursor::updateLocation() but it can // also happen during correct operation, see SERVER-2009. problem() << "warning: cursor loc " << tmp1 << " does not match byLoc position " << dl << " !" << endl; } else { c->advance(); } if ( c->eof() ) { // advanced to end // leave ClientCursor in place so next getMore doesn't fail // still need to mark new location though cc->updateLocation(); } else { wassert( c->refLoc() != dl ); cc->updateLocation(); } } }
static void _init(void) { wassert(!_initialized); _initialized = true; }
void appendReplicationInfo(OperationContext* txn, BSONObjBuilder& result, int level) { ReplicationCoordinator* replCoord = getGlobalReplicationCoordinator(); if (replCoord->getSettings().usingReplSets()) { if (replCoord->getReplicationMode() != ReplicationCoordinator::modeReplSet || replCoord->getCurrentMemberState().shunned()) { result.append("ismaster", false); result.append("secondary", false); result.append("info", ReplSet::startupStatusMsg.get()); result.append( "isreplicaset" , true ); } else { theReplSet->fillIsMaster(result); } return; } if ( replAllDead ) { result.append("ismaster", 0); string s = string("dead: ") + replAllDead; result.append("info", s); } else { result.appendBool("ismaster", getGlobalReplicationCoordinator()->isMasterForReportingPurposes()); } if (level && replCoord->getSettings().usingReplSets()) { result.append( "info" , "is replica set" ); } else if ( level ) { BSONObjBuilder sources( result.subarrayStart( "sources" ) ); int n = 0; list<BSONObj> src; { const char* localSources = "local.sources"; Client::ReadContext ctx(txn, localSources); auto_ptr<PlanExecutor> exec( InternalPlanner::collectionScan(txn, localSources, ctx.ctx().db()->getCollection(txn, localSources))); BSONObj obj; Runner::RunnerState state; while (Runner::RUNNER_ADVANCED == (state = exec->getNext(&obj, NULL))) { src.push_back(obj); } } for( list<BSONObj>::const_iterator i = src.begin(); i != src.end(); i++ ) { BSONObj s = *i; BSONObjBuilder bb; bb.append( s["host"] ); string sourcename = s["source"].valuestr(); if ( sourcename != "main" ) bb.append( s["source"] ); { BSONElement e = s["syncedTo"]; BSONObjBuilder t( bb.subobjStart( "syncedTo" ) ); t.appendDate( "time" , e.timestampTime() ); t.append( "inc" , e.timestampInc() ); t.done(); } if ( level > 1 ) { wassert(txn->lockState()->threadState() == 0); // note: there is no so-style timeout on this connection; perhaps we should have one. ScopedDbConnection conn(s["host"].valuestr()); DBClientConnection *cliConn = dynamic_cast< DBClientConnection* >( &conn.conn() ); if ( cliConn && replAuthenticate(cliConn) ) { BSONObj first = conn->findOne( (string)"local.oplog.$" + sourcename, Query().sort( BSON( "$natural" << 1 ) ) ); BSONObj last = conn->findOne( (string)"local.oplog.$" + sourcename, Query().sort( BSON( "$natural" << -1 ) ) ); bb.appendDate( "masterFirst" , first["ts"].timestampTime() ); bb.appendDate( "masterLast" , last["ts"].timestampTime() ); double lag = (double) (last["ts"].timestampTime() - s["syncedTo"].timestampTime()); bb.append( "lagSeconds" , lag / 1000 ); } conn.done(); } sources.append( BSONObjBuilder::numStr( n++ ) , bb.obj() ); } sources.done(); } }
static int do_pragma(int id, const char *name, const char *cp) { struct pragma_token_s token; int err = 0; int processed = 1; init_pragma_token(&token); switch (id) { case P_BANK: { struct dbuf_s buffer; dbuf_init(&buffer, 128); cp = get_pragma_token(cp, &token); switch (token.type) { case TOKEN_EOL: err = 1; break; case TOKEN_INT: switch (_G.asmType) { case ASM_TYPE_ASXXXX: dbuf_printf (&buffer, "CODE_%d", token.val.int_val); break; case ASM_TYPE_RGBDS: dbuf_printf (&buffer, "CODE,BANK[%d]", token.val.int_val); break; case ASM_TYPE_ISAS: /* PENDING: what to use for ISAS? */ dbuf_printf (&buffer, "CODE,BANK(%d)", token.val.int_val); break; default: wassert (0); } break; default: { const char *str = get_pragma_string (&token); dbuf_append_str (&buffer, (0 == strcmp("BASE", str)) ? "HOME" : str); } break; } cp = get_pragma_token (cp, &token); if (TOKEN_EOL != token.type) { err = 1; break; } dbuf_c_str (&buffer); /* ugly, see comment in src/port.h (borutr) */ gbz80_port.mem.code_name = dbuf_detach (&buffer); code->sname = gbz80_port.mem.code_name; options.code_seg = (char *)gbz80_port.mem.code_name; } break; case P_PORTMODE: { /*.p.t.20030716 - adding pragma to manipulate z80 i/o port addressing modes */ const char *str; cp = get_pragma_token (cp, &token); if (TOKEN_EOL == token.type) { err = 1; break; } str = get_pragma_string (&token); cp = get_pragma_token (cp, &token); if (TOKEN_EOL != token.type) { err = 1; break; } if (!strcmp(str, "z80")) { z80_opts.port_mode = 80; } else if(!strcmp(str, "z180")) { z80_opts.port_mode = 180; } else if(!strcmp(str, "save")) { z80_opts.port_back = z80_opts.port_mode; } else if(!strcmp(str, "restore" )) { z80_opts.port_mode = z80_opts.port_back; } else err = 1; } break; case P_CODESEG: case P_CONSTSEG: { char *segname; cp = get_pragma_token (cp, &token); if (token.type == TOKEN_EOL) { err = 1; break; } segname = Safe_strdup (get_pragma_string(&token)); cp = get_pragma_token (cp, &token); if (token.type != TOKEN_EOL) { Safe_free (segname); err = 1; break; } if (id == P_CODESEG) { if (options.code_seg) Safe_free(options.code_seg); options.code_seg = segname; } else { if (options.const_seg) Safe_free(options.const_seg); options.const_seg = segname; } } break; default: processed = 0; break; } get_pragma_token(cp, &token); if (1 == err) werror(W_BAD_PRAGMA_ARGUMENTS, name); free_pragma_token(&token); return processed; }
void appendReplicationInfo(OperationContext* txn, BSONObjBuilder& result, int level) { ReplicationCoordinator* replCoord = getGlobalReplicationCoordinator(); if (replCoord->getSettings().usingReplSets()) { IsMasterResponse isMasterResponse; replCoord->fillIsMasterForReplSet(&isMasterResponse); result.appendElements(isMasterResponse.toBSON()); if (level) { replCoord->appendSlaveInfoData(&result); } return; } // TODO(dannenberg) replAllDead is bad and should be removed when master slave is removed if (replAllDead) { result.append("ismaster", 0); string s = string("dead: ") + replAllDead; result.append("info", s); } else { result.appendBool("ismaster", getGlobalReplicationCoordinator()->isMasterForReportingPurposes()); } if (level) { BSONObjBuilder sources(result.subarrayStart("sources")); int n = 0; list<BSONObj> src; { const char* localSources = "local.sources"; AutoGetCollectionForRead ctx(txn, localSources); unique_ptr<PlanExecutor> exec( InternalPlanner::collectionScan(txn, localSources, ctx.getCollection())); BSONObj obj; PlanExecutor::ExecState state; while (PlanExecutor::ADVANCED == (state = exec->getNext(&obj, NULL))) { src.push_back(obj); } } for (list<BSONObj>::const_iterator i = src.begin(); i != src.end(); i++) { BSONObj s = *i; BSONObjBuilder bb; bb.append(s["host"]); string sourcename = s["source"].valuestr(); if (sourcename != "main") bb.append(s["source"]); { BSONElement e = s["syncedTo"]; BSONObjBuilder t(bb.subobjStart("syncedTo")); t.appendDate("time", e.timestampTime()); t.append("inc", e.timestampInc()); t.done(); } if (level > 1) { wassert(!txn->lockState()->isLocked()); // note: there is no so-style timeout on this connection; perhaps we should have // one. ScopedDbConnection conn(s["host"].valuestr()); DBClientConnection* cliConn = dynamic_cast<DBClientConnection*>(&conn.conn()); if (cliConn && replAuthenticate(cliConn)) { BSONObj first = conn->findOne((string) "local.oplog.$" + sourcename, Query().sort(BSON("$natural" << 1))); BSONObj last = conn->findOne((string) "local.oplog.$" + sourcename, Query().sort(BSON("$natural" << -1))); bb.appendDate("masterFirst", first["ts"].timestampTime()); bb.appendDate("masterLast", last["ts"].timestampTime()); const auto lag = (last["ts"].timestampTime() - s["syncedTo"].timestampTime()); bb.append("lagSeconds", durationCount<Milliseconds>(lag) / 1000.0); } conn.done(); } sources.append(BSONObjBuilder::numStr(n++), bb.obj()); } sources.done(); replCoord->appendSlaveInfoData(&result); } }
static void unlock_r() { wassert( threadState() == 'r' ); threadState() = 0; q.unlock_r(); }
static void unlock_w() { unlocking_w(); wassert( threadState() == 'w' ); threadState() = 0; q.unlock_w(); }
void wassertExtentNonempty( const Extent *e ) { // TODO ensure this requirement is clearly enforced, or fix. wassert( !e->firstRecord.isNull() ); }
/* must call this on a delete so we clean up the cursors. */ void ClientCursor::aboutToDelete(const StringData& ns, const NamespaceDetails* nsd, const DiskLoc& dl) { // Begin cursor-only NoPageFaultsAllowed npfa; // End cursor-only recursive_scoped_lock lock(ccmutex); Database *db = cc().database(); verify(db); aboutToDeleteForSharding( ns, db, nsd, dl ); // Check our non-cached active runner list. for (set<Runner*>::iterator it = nonCachedRunners.begin(); it != nonCachedRunners.end(); ++it) { Runner* runner = *it; if (0 == ns.compare(runner->ns())) { runner->invalidate(dl); } } // TODO: This requires optimization. We walk through *all* CCs and send the delete to every // CC open on the db we're deleting from. We could: // 1. Map from ns to open runners, // 2. Map from ns -> (a map of DiskLoc -> runners who care about that DL) // // We could also queue invalidations somehow and have them processed later in the runner's // read locks. for (CCById::const_iterator it = clientCursorsById.begin(); it != clientCursorsById.end(); ++it) { ClientCursor* cc = it->second; // We're only interested in cursors over one db. if (cc->_db != db) { continue; } if (NULL == cc->_runner.get()) { continue; } cc->_runner->invalidate(dl); } // Begin cursor-only. Only cursors that are in ccByLoc are processed here. CCByLoc& bl = db->ccByLoc(); CCByLoc::iterator j = bl.lower_bound(ByLocKey::min(dl)); CCByLoc::iterator stop = bl.upper_bound(ByLocKey::max(dl)); if ( j == stop ) return; vector<ClientCursor*> toAdvance; while ( 1 ) { toAdvance.push_back(j->second); DEV verify( j->first.loc == dl ); ++j; if ( j == stop ) break; } if( toAdvance.size() >= 3000 ) { log() << "perf warning MPW101: " << toAdvance.size() << " cursors for one diskloc " << dl.toString() << ' ' << toAdvance[1000]->_ns << ' ' << toAdvance[2000]->_ns << ' ' << toAdvance[1000]->_pinValue << ' ' << toAdvance[2000]->_pinValue << ' ' << toAdvance[1000]->_pos << ' ' << toAdvance[2000]->_pos << ' ' << toAdvance[1000]->_idleAgeMillis << ' ' << toAdvance[2000]->_idleAgeMillis << ' ' << toAdvance[1000]->_doingDeletes << ' ' << toAdvance[2000]->_doingDeletes << endl; //wassert( toAdvance.size() < 5000 ); } for ( vector<ClientCursor*>::iterator i = toAdvance.begin(); i != toAdvance.end(); ++i ) { ClientCursor* cc = *i; wassert(cc->_db == db); if ( cc->_doingDeletes ) continue; Cursor *c = cc->_c.get(); if ( c->capped() ) { /* note we cannot advance here. if this condition occurs, writes to the oplog have "caught" the reader. skipping ahead, the reader would miss postentially important data. */ delete cc; continue; } c->recoverFromYield(); DiskLoc tmp1 = c->refLoc(); if ( tmp1 != dl ) { // This might indicate a failure to call ClientCursor::prepareToYield() but it can // also happen during correct operation, see SERVER-2009. problem() << "warning: cursor loc " << tmp1 << " does not match byLoc position " << dl << " !" << endl; } else { c->advance(); } while (!c->eof() && c->refLoc() == dl) { /* We don't delete at EOF because we want to return "no more results" rather than "no such cursor". * The loop is to handle MultiKey indexes where the deleted record is pointed to by multiple adjacent keys. * In that case we need to advance until we get to the next distinct record or EOF. * SERVER-4154 * SERVER-5198 * But see SERVER-5725. */ c->advance(); } cc->updateLocation(); } // End cursor-only }
/* must call this on a delete so we clean up the cursors. */ void ClientCursor::aboutToDelete(const DiskLoc& dl) { NoPageFaultsAllowed npfa; recursive_scoped_lock lock(ccmutex); Database *db = cc().database(); verify(db); aboutToDeleteForSharding( db , dl ); CCByLoc& bl = db->ccByLoc; CCByLoc::iterator j = bl.lower_bound(ByLocKey::min(dl)); CCByLoc::iterator stop = bl.upper_bound(ByLocKey::max(dl)); if ( j == stop ) return; vector<ClientCursor*> toAdvance; while ( 1 ) { toAdvance.push_back(j->second); DEV verify( j->first.loc == dl ); ++j; if ( j == stop ) break; } if( toAdvance.size() >= 3000 ) { log() << "perf warning MPW101: " << toAdvance.size() << " cursors for one diskloc " << dl.toString() << ' ' << toAdvance[1000]->_ns << ' ' << toAdvance[2000]->_ns << ' ' << toAdvance[1000]->_pinValue << ' ' << toAdvance[2000]->_pinValue << ' ' << toAdvance[1000]->_pos << ' ' << toAdvance[2000]->_pos << ' ' << toAdvance[1000]->_idleAgeMillis << ' ' << toAdvance[2000]->_idleAgeMillis << ' ' << toAdvance[1000]->_doingDeletes << ' ' << toAdvance[2000]->_doingDeletes << endl; //wassert( toAdvance.size() < 5000 ); } for ( vector<ClientCursor*>::iterator i = toAdvance.begin(); i != toAdvance.end(); ++i ) { ClientCursor* cc = *i; wassert(cc->_db == db); if ( cc->_doingDeletes ) continue; Cursor *c = cc->_c.get(); if ( c->capped() ) { /* note we cannot advance here. if this condition occurs, writes to the oplog have "caught" the reader. skipping ahead, the reader would miss postentially important data. */ delete cc; continue; } c->recoverFromYield(); DiskLoc tmp1 = c->refLoc(); if ( tmp1 != dl ) { // This might indicate a failure to call ClientCursor::prepareToYield() but it can // also happen during correct operation, see SERVER-2009. problem() << "warning: cursor loc " << tmp1 << " does not match byLoc position " << dl << " !" << endl; } else { c->advance(); } while (!c->eof() && c->refLoc() == dl) { /* We don't delete at EOF because we want to return "no more results" rather than "no such cursor". * The loop is to handle MultiKey indexes where the deleted record is pointed to by multiple adjacent keys. * In that case we need to advance until we get to the next distinct record or EOF. * SERVER-4154 * SERVER-5198 * But see SERVER-5725. */ c->advance(); } cc->updateLocation(); } }
static int _test_div(void) { int i; struct wsheet* wsh; struct obj objs[] = { /* * objs out of div. * ---------------- */ /* out at left */ {{OUTL_L, IN1_T, OUTL_R, IN1_B}, 0, 0, NULL}, /* out at right */ {{OUTR_L, IN1_T, OUTR_R, IN1_B}, 0, 0, NULL}, /* out at top */ {{IN12_L, OUTT_T, IN12_R, OUTT_B}, 0, 0, NULL}, /* out at bottom */ {{IN12_L, OUTB_T, IN12_R, OUTB_B}, 0, 0, NULL}, /* out at top left */ {{OUTL_L, OUTT_T, OUTL_R, OUTT_B}, 0, 0, NULL}, /* out at top right */ {{OUTR_L, OUTT_T, OUTR_R, OUTT_B}, 0, 0, NULL}, /* out at bottom left */ {{OUTL_L, OUTB_T, OUTL_R, OUTB_B}, 0, 0, NULL}, /* out at bottom right */ {{OUTR_L, OUTB_T, OUTR_R, OUTB_B}, 0, 0, NULL}, /* * objs overwrapped * ---------------- */ /* overwrapped at left */ {{OUTL_R, IN1_T, IN1_L, IN1_B}, 0, 0, NULL}, /* overwrapped at right */ {{IN2_R, IN1_T, OUTR_L, IN1_B}, 0, 0, NULL}, /* overwrapped at top */ {{IN1_L, OUTT_B, IN1_R, IN1_T}, 0, 0, NULL}, /* overwrapped at bottom */ {{IN1_L, IN1_B, IN1_R, OUTB_T}, 0, 0, NULL}, /* overwrapped at left top */ {{OUTL_R, OUTT_B, IN1_L, IN1_B}, 0, 0, NULL}, /* overwrapped at right top */ {{IN2_R, OUTT_B, OUTR_L, IN1_B}, 0, 0, NULL}, /* overwrapped at left bottom */ {{OUTL_R, IN1_B, IN1_R, OUTB_T}, 0, 0, NULL}, /* overwrapped at right bottom */ {{IN2_R, IN2_B, OUTR_L, OUTB_T}, 0, 0, NULL}, /* overwrapped at top with 1 and 2 */ {{OUTL_R, OUTT_B, OUTR_L, IN1_T}, 0, 0, NULL}, /* overwrapped at bottom with 1 and 2 */ {{OUTL_R, IN1_B, OUTR_L, OUTB_T}, 0, 0, NULL}, /* overwrapped at middle with 1 and 2 */ {{OUTL_R, IN1_T, OUTR_L, IN1_B}, 0, 0, NULL}, /* * objects covering 1 and 2 * ------------------------ */ /* overwrapped (covering 1 and 2) */ {{OUTL_R, OUTT_B, OUTR_L, OUTB_T}, 0, 0, NULL}, }; wsh = wsheet_create(); wsheet_init(wsh, 100, 100, 2, 1); for (i = 0; i < sizeof(objs)/sizeof(objs[0]); i++) { wsheet_add_obj(wsh, objs[i].ty, objs[i].priv, objs[i].extent.l, objs[i].extent.t, objs[i].extent.r, objs[i].extent.b); /* printf("%d, %d\n", list_size(&wsh->divs[0][0].objs), list_size(&wsh->divs[0][1].objs)); */ } wassert(9 == list_size(&wsh->divs[0][0].objs)); wassert(7 == list_size(&wsh->divs[0][1].objs)); wsheet_destroy(wsh); wsys_deinit(); return 0; }