BOOST_FOREACH (const std::string& s, req2) { elem m(s, "modification"); if (conflicts(elem1, m, true)) { return true; } }
static const struct babel_route * min_conflict(const struct zone *zone, const struct babel_route *rt) { struct babel_route *rt1 = NULL; const struct babel_route *min = NULL; struct route_stream *stream = NULL; struct zone curr_zone; stream = route_stream(ROUTE_INSTALLED); if(!stream) { fprintf(stderr, "Couldn't allocate route stream.\n"); return NULL; } while(1) { rt1 = route_stream_next(stream); if(rt1 == NULL) break; __builtin_prefetch(rt1->src,0,1); __builtin_prefetch(rt->src,0,1); if(!(conflicts(rt, rt1) && zone_equal(inter(rt, rt1, &curr_zone), zone))) continue; min = min_route(rt1, min); } route_stream_done(stream); return min; }
BOOST_FOREACH (const std::string& id1, req1) { elem m1(id1, "modification"); BOOST_FOREACH (const std::string& id2, req2) { elem m2(id2, "modification"); if (conflicts(m1, m2)) { return true; } }
/* * ./tp <ejercicio> <entrada> <salida> [corridas=1] */ int main(int argc, char *argv[]) { if (argc < 4) { std::cerr << "Formato de entrada: " << argv[0] << " <ejercicio> <entrada> <salida> <corridas>" << std::endl; #ifdef DEBUG std::cerr << "BUILD DE DEBUG" << std::endl; #endif #ifdef EXPS std::cerr << "BUILD DE EXPERIMENTACION" << std::endl; #endif return 1; } int exercise = std::atoi(argv[1]); std::string input(argv[2]); std::string output(argv[3]); int runs; if (argc == 4) { runs = 1; } else { runs = std::atoi(argv[4]); } Problem solver(input); Coloring result(solver.solve(exercise, runs)); #if defined(DEBUG) || defined(EXPS) ConflictColoring conflicts(result); std::cout << conflicts; #endif std::ofstream handle; handle.open(output, std::ofstream::out); if (!handle.is_open()) { throw std::runtime_error("Fallo al abrir el archivo de salida"); } #if defined(DEBUG) || defined(EXPS) handle << conflicts; #else handle << result; #endif handle.close(); std::string path = std::string(output); std::string basename = path.substr(0, path.find_last_of('.')); Statistics::getInstance().dump(basename + std::string(".sts")); return 0; }
std::vector<std::string> manager::get_conflicting_enabled(const elem& e) const { std::vector<std::string> result; BOOST_FOREACH(const std::string& mod, mods_) { if (conflicts(elem(mod, "modification"), e)) { result.push_back(mod); } } return result; }
static Clause conflicts_with_member(Clause c, Plist p) { if (p == NULL) return NULL; else { Clause empty = conflicts(c, p->v); if (empty) return empty; else return conflicts_with_member(c, p->next); } } /* conflicts_with_member */
/* recursively determine solution */ static int findSolution(Queenscreen *qs, int row, int col) { if(row == qs->BOARDSIZE) return 1; while(col < qs->BOARDSIZE) { if(!conflicts(qs, row, col)) { qs->board[row][col] = 1; if(findSolution(qs, row+1, 0)) return 1; qs->board[row][col] = 0; } ++col; } return 0; }
/** * @brief HashVector::insert Allows to insert the hashes managed by an other HashVector into this * one. If there is a conflict, neither HashVector is modified. * @param other The other HashVector. * @return true if the insertion was successful (e.g. no conflicts); false otherwise. */ bool HashSet::insert( const HashSet& other ) { std::vector<Hash*> vNewHashes; vNewHashes.reserve( other.hashCount() ); for ( quint8 i = 0; i < Hash::NO_OF_TYPES; ++i ) { // if there is a hash at position i if ( other.m_pHashes[i] ) { if ( !conflicts( *other.m_pHashes[i] ) ) { // if it doesn't clash with an existing hash // and we don't have a hash for that type yet if ( !m_pHashes[i] ) { // remember the hash for later insertion vNewHashes.push_back( new Hash( *other.m_pHashes[i] ) ); } } else { // conflict detected; clear remembered hashes for ( size_t i = 0, nMax = vNewHashes.size(); i < nMax; ++i ) { delete vNewHashes[i]; } return false; } } } // no conflicts detected; insert the hashes for ( size_t i = 0, nMax = vNewHashes.size(); i < nMax; ++i ) { const quint8 type = vNewHashes[i]->type(); m_pHashes[type] = vNewHashes[i]; } return true; }
static const struct babel_route * conflict_solution(const struct babel_route *rt) { const struct babel_route *rt1 = NULL, *rt2 = NULL; struct route_stream *stream1 = NULL; struct route_stream *stream2 = NULL; const struct babel_route *min = NULL; /* == solution */ struct zone zone; struct zone tmp; /* Having a conflict requires at least one specific route. */ stream1 = route_stream(ROUTE_SS_INSTALLED); if(!stream1) { return NULL; } while(1) { rt1 = route_stream_next(stream1); if(rt1 == NULL) break; stream2 = route_stream(ROUTE_INSTALLED); if(!stream2) { route_stream_done(stream1); fprintf(stderr, "Couldn't allocate route stream.\n"); return NULL; } while(1) { rt2 = route_stream_next(stream2); if(rt2 == NULL) break; if(!(conflicts(rt1, rt2) && zone_equal(inter(rt1, rt2, &tmp), to_zone(rt, &zone)) && rt_cmp(rt1, rt2) < 0)) continue; min = min_route(rt1, min); } route_stream_done(stream2); } route_stream_done(stream1); return min; }
bool MeshBVH::Intersect(const MeshBVH &left, const MeshBVH &right, MeshIntersectStatistics &stats) { if(left._root == NULL || right._root == NULL) return false; Vector< pair<const MeshBVHNode*, const MeshBVHNode*> > conflicts(1); conflicts[0] = make_pair(left._root, right._root); while(conflicts.Length() > 0) { const auto curConflict = conflicts.Last(); conflicts.PopEnd(); stats.bboxComparisons++; const Vec3f centerDiff = curConflict.first->center - curConflict.second->center; const Vec3f varianceSum = curConflict.first->variance + curConflict.second->variance; if(fabsf(centerDiff.x) <= varianceSum.x && fabsf(centerDiff.y) <= varianceSum.y && fabsf(centerDiff.z) <= varianceSum.z) { const bool leftIsLeaf = curConflict.first->isLeafNode(); const bool rightIsLeaf = curConflict.second->isLeafNode(); if(leftIsLeaf && rightIsLeaf) { if(MeshBVHDebugging) Console::WriteLine("l=" + String(curConflict.first->triCount) + " r=" + String(curConflict.second->triCount)); const UINT baseTri0Index = curConflict.first->triIndex; const UINT baseTri1Index = curConflict.second->triIndex; auto triStorage0 = left._storage.CArray(); auto triStorage1 = right._storage.CArray(); for(UINT tri0Index = 0; tri0Index < curConflict.first->triCount; tri0Index++) { const MeshBVHTriangleInfo &tri0 = *triStorage0[baseTri0Index + tri0Index]; for(UINT tri1Index = 0; tri1Index < curConflict.second->triCount; tri1Index++) { stats.triComparisons++; const MeshBVHTriangleInfo &tri1 = *triStorage1[baseTri1Index + tri1Index]; //if(Math::DistanceTriangleTriangleSq(tri0.v[0], tri0.v[1], tri0.v[2], tri1.v[0], tri1.v[1], tri1.v[2]) == 0.0f) if(Math::TriangleIntersectTriangle(tri0.v[0], tri0.v[1], tri0.v[2], tri1.v[0], tri1.v[1], tri1.v[2])) { return true; } } } } else { if(leftIsLeaf) { conflicts.PushEnd(make_pair(curConflict.first, curConflict.second->children[0])); conflicts.PushEnd(make_pair(curConflict.first, curConflict.second->children[1])); } else if(rightIsLeaf) { conflicts.PushEnd(make_pair(curConflict.first->children[0], curConflict.second)); conflicts.PushEnd(make_pair(curConflict.first->children[1], curConflict.second)); } else { conflicts.PushEnd(make_pair(curConflict.first->children[0], curConflict.second->children[0])); conflicts.PushEnd(make_pair(curConflict.first->children[0], curConflict.second->children[1])); conflicts.PushEnd(make_pair(curConflict.first->children[1], curConflict.second->children[0])); conflicts.PushEnd(make_pair(curConflict.first->children[1], curConflict.second->children[1])); } /*bool splitLeft = rightIsLeaf; if(!leftIsLeaf && !rightIsLeaf) { splitLeft = (curConflict.first->size() > curConflict.second->size()); } if(splitLeft) { conflicts.PushEnd(make_pair(curConflict.first->children[0], curConflict.second)); conflicts.PushEnd(make_pair(curConflict.first->children[1], curConflict.second)); } else { conflicts.PushEnd(make_pair(curConflict.first, curConflict.second->children[0])); conflicts.PushEnd(make_pair(curConflict.first, curConflict.second->children[1])); }*/ } } } return false; }
void ParanoidSolver::postConstraints(void) { provides(*this,install_,provides_,virtuals_); dependencies(*this,install_,deps_); conflicts(*this,install_,conflicts_); }
/** * Handle cp for a given src register. This additionally handles * the cases of collapsing immedate/const (which replace the src * register with a non-ssa src) or collapsing mov's from relative * src (which needs to also fixup the address src reference by the * instruction). */ static void reg_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr, struct ir3_register *reg, unsigned n) { struct ir3_instruction *src = ssa(reg); /* don't propagate copies into a PHI, since we don't know if the * src block executed: */ if (instr->opc == OPC_META_PHI) return; if (is_eligible_mov(src, true)) { /* simple case, no immed/const/relativ, only mov's w/ ssa src: */ struct ir3_register *src_reg = src->regs[1]; unsigned new_flags = reg->flags; combine_flags(&new_flags, src); if (valid_flags(instr, n, new_flags)) { if (new_flags & IR3_REG_ARRAY) { debug_assert(!(reg->flags & IR3_REG_ARRAY)); reg->array = src_reg->array; } reg->flags = new_flags; reg->instr = ssa(src_reg); } src = ssa(reg); /* could be null for IR3_REG_ARRAY case */ if (!src) return; } else if (is_same_type_mov(src) && /* cannot collapse const/immed/etc into meta instrs: */ !is_meta(instr)) { /* immed/const/etc cases, which require some special handling: */ struct ir3_register *src_reg = src->regs[1]; unsigned new_flags = reg->flags; combine_flags(&new_flags, src); if (!valid_flags(instr, n, new_flags)) { /* See if lowering an immediate to const would help. */ if (valid_flags(instr, n, (new_flags & ~IR3_REG_IMMED) | IR3_REG_CONST)) { debug_assert(new_flags & IR3_REG_IMMED); instr->regs[n + 1] = lower_immed(ctx, src_reg, new_flags); return; } /* special case for "normal" mad instructions, we can * try swapping the first two args if that fits better. * * the "plain" MAD's (ie. the ones that don't shift first * src prior to multiply) can swap their first two srcs if * src[0] is !CONST and src[1] is CONST: */ if ((n == 1) && is_mad(instr->opc) && !(instr->regs[0 + 1]->flags & (IR3_REG_CONST | IR3_REG_RELATIV)) && valid_flags(instr, 0, new_flags)) { /* swap src[0] and src[1]: */ struct ir3_register *tmp; tmp = instr->regs[0 + 1]; instr->regs[0 + 1] = instr->regs[1 + 1]; instr->regs[1 + 1] = tmp; n = 0; } else { return; } } /* Here we handle the special case of mov from * CONST and/or RELATIV. These need to be handled * specially, because in the case of move from CONST * there is no src ir3_instruction so we need to * replace the ir3_register. And in the case of * RELATIV we need to handle the address register * dependency. */ if (src_reg->flags & IR3_REG_CONST) { /* an instruction cannot reference two different * address registers: */ if ((src_reg->flags & IR3_REG_RELATIV) && conflicts(instr->address, reg->instr->address)) return; /* This seems to be a hw bug, or something where the timings * just somehow don't work out. This restriction may only * apply if the first src is also CONST. */ if ((opc_cat(instr->opc) == 3) && (n == 2) && (src_reg->flags & IR3_REG_RELATIV) && (src_reg->array.offset == 0)) return; src_reg = ir3_reg_clone(instr->block->shader, src_reg); src_reg->flags = new_flags; instr->regs[n+1] = src_reg; if (src_reg->flags & IR3_REG_RELATIV) ir3_instr_set_address(instr, reg->instr->address); return; } if ((src_reg->flags & IR3_REG_RELATIV) && !conflicts(instr->address, reg->instr->address)) { src_reg = ir3_reg_clone(instr->block->shader, src_reg); src_reg->flags = new_flags; instr->regs[n+1] = src_reg; ir3_instr_set_address(instr, reg->instr->address); return; } /* NOTE: seems we can only do immed integers, so don't * need to care about float. But we do need to handle * abs/neg *before* checking that the immediate requires * few enough bits to encode: * * TODO: do we need to do something to avoid accidentally * catching a float immed? */ if (src_reg->flags & IR3_REG_IMMED) { int32_t iim_val = src_reg->iim_val; debug_assert((opc_cat(instr->opc) == 1) || (opc_cat(instr->opc) == 6) || ir3_cat2_int(instr->opc)); if (new_flags & IR3_REG_SABS) iim_val = abs(iim_val); if (new_flags & IR3_REG_SNEG) iim_val = -iim_val; if (new_flags & IR3_REG_BNOT) iim_val = ~iim_val; /* other than category 1 (mov) we can only encode up to 10 bits: */ if ((instr->opc == OPC_MOV) || !((iim_val & ~0x3ff) && (-iim_val & ~0x3ff))) { new_flags &= ~(IR3_REG_SABS | IR3_REG_SNEG | IR3_REG_BNOT); src_reg = ir3_reg_clone(instr->block->shader, src_reg); src_reg->flags = new_flags; src_reg->iim_val = iim_val; instr->regs[n+1] = src_reg; } else if (valid_flags(instr, n, (new_flags & ~IR3_REG_IMMED) | IR3_REG_CONST)) { /* See if lowering an immediate to const would help. */ instr->regs[n+1] = lower_immed(ctx, src_reg, new_flags); } return; } } }
string getDBStructure() { return "----------------------------------------------------------------------\n\ --\n\ -- MOPSLinux package system\n\ -- Database creation script\n\ -- $Id: dbstruct.cpp,v 1.3 2007/11/02 20:19:45 i27249 Exp $\n\ --\n\ ----------------------------------------------------------------------\n\ \n\ create table packages (\n\ package_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,\n\ package_name TEXT NOT NULL,\n\ package_version TEXT NOT NULL,\n\ package_arch TEXT NOT NULL,\n\ package_build TEXT NULL,\n\ package_compressed_size TEXT NOT NULL,\n\ package_installed_size TEXT NOT NULL,\n\ package_short_description TEXT NULL,\n\ package_description TEXT NULL, \n\ package_changelog TEXT NULL,\n\ package_packager TEXT NULL,\n\ package_packager_email TEXT NULL,\n\ package_installed INTEGER NOT NULL,\n\ package_configexist INTEGER NOT NULL,\n\ package_action INTEGER NOT NULL,\n\ package_md5 TEXT NOT NULL,\n\ package_filename TEXT NOT NULL,\n\ package_betarelease TEXT NOT NULL,\n\ package_installed_by_dependency INTEGER NOT NULL DEFAULT '0',\n\ package_type INTEGER NOT NULL DEFAULT '0'\n\ );\n\ create index ppname on packages (package_id, package_name, package_version, package_action, package_installed, package_md5);\n\ \n\ create table files (\n\ file_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,\n\ file_name TEXT NOT NULL,\n\ file_type INTEGER NOT NULL,\n\ packages_package_id INTEGER NOT NULL\n\ );\n\ create index pname on files (file_name, packages_package_id);\n\ \n\ create table conflicts (\n\ conflict_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,\n\ conflict_file_name TEXT NOT NULL,\n\ backup_file TEXT NOT NULL,\n\ conflicted_package_id INTEGER NOT NULL\n\ );\n\ \n\ create table locations (\n\ location_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,\n\ packages_package_id INTEGER NOT NULL,\n\ server_url TEXT NOT NULL,\n\ location_path TEXT NOT NULL\n\ );\n\ create index locpid on locations(packages_package_id, location_path, server_url);\n\ create table tags (\n\ tags_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,\n\ tags_name TEXT NOT NULL\n\ );\n\ create index ptag on tags (tags_id, tags_name);\n\ \n\ create table tags_links (\n\ tags_link_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,\n\ packages_package_id INTEGER NOT NULL,\n\ tags_tag_id INTEGER NOT NULL\n\ );\n\ create index ptaglink on tags_links (packages_package_id, tags_tag_id);\n\ \n\ create table dependencies (\n\ dependency_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,\n\ packages_package_id INTEGER NOT NULL,\n\ dependency_condition INTEGER NOT NULL DEFAULT '1',\n\ dependency_type INTEGER NOT NULL DEFAULT '1',\n\ dependency_package_name TEXT NOT NULL,\n\ dependency_package_version TEXT NULL,\n\ dependency_build_only INTEGER NOT NULL DEFAULT '0' \ );\n\ \n\ create index pdeps on dependencies (packages_package_id, dependency_id, dependency_package_name, dependency_package_version, dependency_condition);\n\ \n\ -- INTERNATIONAL SUPPORT\n\ \n\ --create table descriptions (\n\ -- description_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,\n\ -- packages_package_id INTEGER NOT NULL,\n\ -- description_language TEXT NOT NULL,\n\ -- description_text TEXT NOT NULL,\n\ -- short_description_text TEXT NOT NULL\n\ --);\n\ \n\ --create table changelogs (\n\ -- changelog_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,\n\ -- packages_package_id INTEGER NOT NULL,\n\ -- changelog_language TEXT NOT NULL,\n\ -- changelog_text TEXT NOT NULL\n\ --);\n\ \n\ -- RATING SYSTEM - SUPPORT FOR FUTURE\n\ --create table ratings (\n\ -- rating_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,\n\ -- rating_value INTEGER NOT NULL,\n\ -- packages_package_name TEXT NOT NULL\n\ --);\n\ "; }
static void group_n(struct group_ops *ops, void *arr, unsigned n) { unsigned i, j; /* first pass, figure out what has conflicts and needs a mov * inserted. Do this up front, before starting to setup * left/right neighbor pointers. Trying to do it in a single * pass could result in a situation where we can't even setup * the mov's right neighbor ptr if the next instr also needs * a mov. */ restart: for (i = 0; i < n; i++) { struct ir3_instruction *instr = ops->get(arr, i); if (instr) { struct ir3_instruction *left = (i > 0) ? ops->get(arr, i - 1) : NULL; struct ir3_instruction *right = (i < (n-1)) ? ops->get(arr, i + 1) : NULL; bool conflict; /* check for left/right neighbor conflicts: */ conflict = conflicts(instr->cp.left, left) || conflicts(instr->cp.right, right); /* Mixing array elements and higher register classes * (ie. groups) doesn't really work out in RA. See: * * https://trello.com/c/DqeDkeVf/156-bug-with-stk-70frag */ if (instr->regs[0]->flags & IR3_REG_ARRAY) conflict = true; /* we also can't have an instr twice in the group: */ for (j = i + 1; (j < n) && !conflict; j++) if (in_neighbor_list(ops->get(arr, j), instr, i)) conflict = true; if (conflict) { ops->insert_mov(arr, i, instr); /* inserting the mov may have caused a conflict * against the previous: */ goto restart; } } } /* second pass, now that we've inserted mov's, fixup left/right * neighbors. This is guaranteed to succeed, since by definition * the newly inserted mov's cannot conflict with anything. */ for (i = 0; i < n; i++) { struct ir3_instruction *instr = ops->get(arr, i); if (instr) { struct ir3_instruction *left = (i > 0) ? ops->get(arr, i - 1) : NULL; struct ir3_instruction *right = (i < (n-1)) ? ops->get(arr, i + 1) : NULL; debug_assert(!conflicts(instr->cp.left, left)); if (left) { instr->cp.left_cnt++; instr->cp.left = left; } debug_assert(!conflicts(instr->cp.right, right)); if (right) { instr->cp.right_cnt++; instr->cp.right = right; } } } }
bool manager::conflicts(const elem& elem1, const elem& elem2, bool directonly) const { if (elem1 == elem2) { return false; } // We ignore inexistent elements at this point, they will generate // errors in change_era()/change_scenario() anyways. if (!exists(elem1) || !exists(elem2)) { return false; } config data1 = depinfo_.find_child(elem1.type, "id", elem1.id); config data2 = depinfo_.find_child(elem2.type, "id", elem2.id); // Whether we should skip the check entirely if (data1.has_attribute("ignore_incompatible_" + elem2.type)) { std::vector<std::string> ignored = utils::split(data1["ignore_incompatible_" + elem2.type]); if ( util::contains(ignored, elem2.id) ) { return false; } } if (data2.has_attribute("ignore_incompatible_" + elem1.type)) { std::vector<std::string> ignored = utils::split(data2["ignore_incompatible_" + elem1.type]); if ( util::contains(ignored, elem1.id) ) { return false; } } bool result = false; // Checking for direct conflicts between elem1 and elem2 if (data1.has_attribute("allow_" + elem2.type)) { std::vector<std::string> allowed = utils::split(data1["allow_" + elem2.type]); result = !util::contains(allowed, elem2.id) && !requires(elem1, elem2); } else if (data1.has_attribute("disallow_" + elem2.type)) { std::vector<std::string> disallowed = utils::split(data1["disallow_" + elem2.type]); result = util::contains(disallowed, elem2.id); } if (data2.has_attribute("allow_" + elem1.type)) { std::vector<std::string> allowed = utils::split(data2["allow_" + elem1.type]); result = result || (!util::contains(allowed, elem1.id) && !requires(elem2, elem1)); } else if (data2.has_attribute("disallow_" + elem1.type)) { std::vector<std::string> disallowed = utils::split(data2["disallow_" + elem1.type]); result = result || util::contains(disallowed, elem1.id); } if (result) { return true; } // Checking for indirect conflicts (i.e. conflicts between dependencies) if (!directonly) { std::vector<std::string> req1 = get_required(elem1), req2 = get_required(elem2); BOOST_FOREACH (const std::string& s, req1) { elem m(s, "modification"); if (conflicts(elem2, m, true)) { return true; } }
static void group_n(struct group_ops *ops, void *arr, unsigned n) { unsigned i, j; /* first pass, figure out what has conflicts and needs a mov * inserted. Do this up front, before starting to setup * left/right neighbor pointers. Trying to do it in a single * pass could result in a situation where we can't even setup * the mov's right neighbor ptr if the next instr also needs * a mov. */ restart: for (i = 0; i < n; i++) { struct ir3_instruction *instr = ops->get(arr, i); if (instr) { struct ir3_instruction *left = (i > 0) ? ops->get(arr, i - 1) : NULL; struct ir3_instruction *right = (i < (n-1)) ? ops->get(arr, i + 1) : NULL; bool conflict; /* check for left/right neighbor conflicts: */ conflict = conflicts(instr->cp.left, left) || conflicts(instr->cp.right, right); /* RA can't yet deal very well w/ group'd phi's: */ if (is_meta(instr) && (instr->opc == OPC_META_PHI)) conflict = true; /* we also can't have an instr twice in the group: */ for (j = i + 1; (j < n) && !conflict; j++) if (ops->get(arr, j) == instr) conflict = true; if (conflict) { ops->insert_mov(arr, i, instr); /* inserting the mov may have caused a conflict * against the previous: */ goto restart; } } } /* second pass, now that we've inserted mov's, fixup left/right * neighbors. This is guaranteed to succeed, since by definition * the newly inserted mov's cannot conflict with anything. */ for (i = 0; i < n; i++) { struct ir3_instruction *instr = ops->get(arr, i); if (instr) { struct ir3_instruction *left = (i > 0) ? ops->get(arr, i - 1) : NULL; struct ir3_instruction *right = (i < (n-1)) ? ops->get(arr, i + 1) : NULL; debug_assert(!conflicts(instr->cp.left, left)); if (left) { instr->cp.left_cnt++; instr->cp.left = left; } debug_assert(!conflicts(instr->cp.right, right)); if (right) { instr->cp.right_cnt++; instr->cp.right = right; } } } }
LockResult LockManager::lock(const ResourceId& resId, LockRequest* request, LockMode mode) { dassert(mode > MODE_NONE); // Fast path for acquiring the same lock multiple times in modes, which are already covered // by the current mode. It is safe to do this without locking, because 1) all calls for the // same lock request must be done on the same thread and 2) if there are lock requests // hanging off a given LockHead, then this lock will never disappear. if ((LockConflictsTable[request->mode] | LockConflictsTable[mode]) == LockConflictsTable[request->mode]) { request->recursiveCount++; return LOCK_OK; } // TODO: For the time being we do not need conversions between unrelated lock modes (i.e., // modes which both add and remove to the conflicts set), so these are not implemented yet // (e.g., S -> IX). invariant((LockConflictsTable[request->mode] | LockConflictsTable[mode]) == LockConflictsTable[mode]); LockBucket* bucket = _getBucket(resId); scoped_spinlock scopedLock(bucket->mutex); LockHead* lock; LockHeadMap::iterator it = bucket->data.find(resId); if (it == bucket->data.end()) { // Lock is free (not on the map) invariant(request->status == LockRequest::STATUS_NEW); lock = new LockHead(resId); bucket->data.insert(LockHeadPair(resId, lock)); } else { // Lock is not free lock = it->second; } // Sanity check if requests are being reused invariant(request->lock == NULL || request->lock == lock); request->lock = lock; request->recursiveCount++; if (request->status == LockRequest::STATUS_NEW) { invariant(request->recursiveCount == 1); // New lock request if (conflicts(mode, lock->grantedModes)) { request->status = LockRequest::STATUS_WAITING; request->mode = mode; request->convertMode = MODE_NONE; // Put it on the conflict queue. This is the place where various policies could be // applied for where in the wait queue does a request go. lock->addToConflictQueue(request); lock->changeConflictModeCount(mode, LockHead::Increment); return LOCK_WAITING; } else { // No conflict, new request request->status = LockRequest::STATUS_GRANTED; request->mode = mode; request->convertMode = MODE_NONE; lock->addToGrantedQueue(request); lock->changeGrantedModeCount(mode, LockHead::Increment); return LOCK_OK; } } else { // If we are here, we already hold the lock in some mode. In order to keep it simple, // we do not allow requesting a conversion while a lock is already waiting or pending // conversion, hence the assertion below. invariant(request->status == LockRequest::STATUS_GRANTED); invariant(request->recursiveCount > 1); invariant(request->mode != mode); // Construct granted mask without our current mode, so that it is not counted as // conflicting uint32_t grantedModesWithoutCurrentRequest = 0; // We start the counting at 1 below, because LockModesCount also includes MODE_NONE // at position 0, which can never be acquired/granted. for (uint32_t i = 1; i < LockModesCount; i++) { const uint32_t currentRequestHolds = (request->mode == static_cast<LockMode>(i) ? 1 : 0); if (lock->grantedCounts[i] > currentRequestHolds) { grantedModesWithoutCurrentRequest |= modeMask(static_cast<LockMode>(i)); } } // This check favours conversion requests over pending requests. For example: // // T1 requests lock L in IS // T2 requests lock L in X // T1 then upgrades L from IS -> S // // Because the check does not look into the conflict modes bitmap, it will grant L to // T1 in S mode, instead of block, which would otherwise cause deadlock. if (conflicts(mode, grantedModesWithoutCurrentRequest)) { request->status = LockRequest::STATUS_CONVERTING; request->convertMode = mode; lock->conversionsCount++; lock->changeGrantedModeCount(request->convertMode, LockHead::Increment); return LOCK_WAITING; } else { // No conflict, existing request lock->changeGrantedModeCount(mode, LockHead::Increment); lock->changeGrantedModeCount(request->mode, LockHead::Decrement); request->mode = mode; return LOCK_OK; } } }
void LockManager::_onLockModeChanged(LockHead* lock, bool checkConflictQueue) { // Unblock any converting requests (because conversions are still counted as granted and // are on the granted queue). for (LockRequest* iter = lock->grantedQueue; (iter != NULL) && (lock->conversionsCount > 0); iter = iter->next) { // Conversion requests are going in a separate queue if (iter->status == LockRequest::STATUS_CONVERTING) { invariant(iter->convertMode != 0); // Construct granted mask without our current mode, so that it is not accounted as // a conflict uint32_t grantedModesWithoutCurrentRequest = 0; // We start the counting at 1 below, because LockModesCount also includes // MODE_NONE at position 0, which can never be acquired/granted. for (uint32_t i = 1; i < LockModesCount; i++) { const uint32_t currentRequestHolds = (iter->mode == static_cast<LockMode>(i) ? 1 : 0); const uint32_t currentRequestWaits = (iter->convertMode == static_cast<LockMode>(i) ? 1 : 0); // We cannot both hold and wait on the same lock mode invariant(currentRequestHolds + currentRequestWaits <= 1); if (lock->grantedCounts[i] > (currentRequestHolds + currentRequestWaits)) { grantedModesWithoutCurrentRequest |= modeMask(static_cast<LockMode>(i)); } } if (!conflicts(iter->convertMode, grantedModesWithoutCurrentRequest)) { lock->conversionsCount--; lock->changeGrantedModeCount(iter->mode, LockHead::Decrement); iter->status = LockRequest::STATUS_GRANTED; iter->mode = iter->convertMode; iter->convertMode = MODE_NONE; iter->notify->notify(lock->resourceId, LOCK_OK); } } } // Grant any conflicting requests, which might now be unblocked LockRequest* iterNext = NULL; for (LockRequest* iter = lock->conflictQueueBegin; (iter != NULL) && checkConflictQueue; iter = iterNext) { invariant(iter->status == LockRequest::STATUS_WAITING); // Store the actual next pointer, because we muck with the iter below and move it to // the granted queue. iterNext = iter->next; if (conflicts(iter->mode, lock->grantedModes)) continue; iter->status = LockRequest::STATUS_GRANTED; lock->removeFromConflictQueue(iter); lock->addToGrantedQueue(iter); lock->changeGrantedModeCount(iter->mode, LockHead::Increment); lock->changeConflictModeCount(iter->mode, LockHead::Decrement); iter->notify->notify(lock->resourceId, LOCK_OK); } // This is a convenient place to check that the state of the two request queues is in sync // with the bitmask on the modes. invariant((lock->grantedModes == 0) ^ (lock->grantedQueue != NULL)); invariant((lock->conflictModes == 0) ^ (lock->conflictQueueBegin != NULL)); }
void DeadlockDetector::_processNextNode(const UnprocessedNode& node) { // Locate the request LockManager::LockBucket* bucket = _lockMgr._getBucket(node.resId); SimpleMutex::scoped_lock scopedLock(bucket->mutex); LockManager::LockHeadMap::const_iterator iter = bucket->data.find(node.resId); if (iter == bucket->data.end()) { return; } const LockHead* lock = iter->second; LockRequest* request = lock->findRequest(node.lockerId); // It is possible that a request which was thought to be waiting suddenly became // granted, so check that before proceeding if (!request || (request->status == LockRequest::STATUS_GRANTED)) { return; } std::pair<WaitForGraph::iterator, bool> val = _graph.insert(WaitForGraphPair(node.lockerId, Edges(node.resId))); if (!val.second) { // We already saw this locker id, which means we have a cycle. if (!_foundCycle) { _foundCycle = (node.lockerId == _initialLockerId); } return; } Edges& edges = val.first->second; bool seen = false; for (LockRequest* it = lock->grantedQueueEnd; it != NULL; it = it->prev) { // We can't conflict with ourselves if (it == request) { seen = true; continue; } // If we are a regular conflicting request, both granted and conversion modes need to // be checked for conflict, since conversions will be granted first. if (request->status == LockRequest::STATUS_WAITING) { if (conflicts(request->mode, modeMask(it->mode)) || conflicts(request->mode, modeMask(it->convertMode))) { const LockerId lockerId = it->locker->getId(); const ResourceId waitResId = it->locker->getWaitingResource(); if (waitResId.isValid()) { _queue.push_front(UnprocessedNode(lockerId, waitResId)); edges.owners.push_back(lockerId); } } continue; } // If we are a conversion request, only requests, which are before us need to be // accounted for. invariant(request->status == LockRequest::STATUS_CONVERTING); if (conflicts(request->convertMode, modeMask(it->mode)) || (seen && conflicts(request->convertMode, modeMask(it->convertMode)))) { const LockerId lockerId = it->locker->getId(); const ResourceId waitResId = it->locker->getWaitingResource(); if (waitResId.isValid()) { _queue.push_front(UnprocessedNode(lockerId, waitResId)); edges.owners.push_back(lockerId); } } } // All conflicting waits, which would be granted before us for (LockRequest* it = request->prev; (request->status == LockRequest::STATUS_WAITING) && (it != NULL); it = it->prev) { // We started from the previous element, so we should never see ourselves invariant(it != request); if (conflicts(request->mode, modeMask(it->mode))) { const LockerId lockerId = it->locker->getId(); const ResourceId waitResId = it->locker->getWaitingResource(); if (waitResId.isValid()) { _queue.push_front(UnprocessedNode(lockerId, waitResId)); edges.owners.push_back(lockerId); } } } }