예제 #1
0
    DeadlockDetector::DeadlockDetector(const LockManager& lockMgr, const Locker* initialLocker)
            : _lockMgr(lockMgr),
              _initialLockerId(initialLocker->getId()),
              _foundCycle(false) {

        const ResourceId resId = initialLocker->getWaitingResource();

        // If there is no resource waiting there is nothing to do
        if (resId.isValid()) {
            _queue.push_front(UnprocessedNode(_initialLockerId, resId));
        }
    }
bool ResourceTable::markPublicImpl(const ResourceNameRef& name, const ResourceId& resId,
                                   const SourceLine& source, const char16_t* validChars) {
    if (!name.package.empty() && name.package != mPackage) {
        Logger::error(source)
                << "resource '"
                << name
                << "' has incompatible package. Must be '"
                << mPackage
                << "'."
            << std::endl;
        return false;
    }

    auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, validChars);
    if (badCharIter != name.entry.end()) {
        Logger::error(source)
                << "resource '"
                << name
                << "' has invalid entry name '"
                << name.entry
                << "'. Invalid character '"
                << StringPiece16(badCharIter, 1)
                << "'."
                << std::endl;
        return false;
    }

    std::unique_ptr<ResourceTableType>& type = findOrCreateType(name.type);
    if (resId.isValid() && type->typeId != ResourceTableType::kUnsetTypeId &&
            type->typeId != resId.typeId()) {
        Logger::error(source)
                << "trying to make resource '"
                << name
                << "' public with ID "
                << resId
                << " but type '"
                << type->type
                << "' already has ID "
                << std::hex << type->typeId << std::dec
                << "."
                << std::endl;
        return false;
    }

    std::unique_ptr<ResourceEntry>& entry = findOrCreateEntry(type, name.entry);
    if (resId.isValid() && entry->entryId != ResourceEntry::kUnsetEntryId &&
            entry->entryId != resId.entryId()) {
        Logger::error(source)
                << "trying to make resource '"
                << name
                << "' public with ID "
                << resId
                << " but resource already has ID "
                << ResourceId(mPackageId, type->typeId, entry->entryId)
                << "."
                << std::endl;
        return false;
    }

    type->publicStatus.isPublic = true;
    entry->publicStatus.isPublic = true;
    entry->publicStatus.source = source;

    if (resId.isValid()) {
        type->typeId = resId.typeId();
        entry->entryId = resId.entryId();
    }
    return true;
}
bool ResourceTable::addResourceImpl(const ResourceNameRef& name, const ResourceId& resId,
                                    const ConfigDescription& config, const SourceLine& source,
                                    std::unique_ptr<Value> value, const char16_t* validChars) {
    if (!name.package.empty() && name.package != mPackage) {
        Logger::error(source)
                << "resource '"
                << name
                << "' has incompatible package. Must be '"
                << mPackage
                << "'."
                << std::endl;
        return false;
    }

    auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, validChars);
    if (badCharIter != name.entry.end()) {
        Logger::error(source)
                << "resource '"
                << name
                << "' has invalid entry name '"
                << name.entry
                << "'. Invalid character '"
                << StringPiece16(badCharIter, 1)
                << "'."
                << std::endl;
        return false;
    }

    std::unique_ptr<ResourceTableType>& type = findOrCreateType(name.type);
    if (resId.isValid() && type->typeId != ResourceTableType::kUnsetTypeId &&
            type->typeId != resId.typeId()) {
        Logger::error(source)
                << "trying to add resource '"
                << name
                << "' with ID "
                << resId
                << " but type '"
                << type->type
                << "' already has ID "
                << std::hex << type->typeId << std::dec
                << "."
                << std::endl;
        return false;
    }

    std::unique_ptr<ResourceEntry>& entry = findOrCreateEntry(type, name.entry);
    if (resId.isValid() && entry->entryId != ResourceEntry::kUnsetEntryId &&
            entry->entryId != resId.entryId()) {
        Logger::error(source)
                << "trying to add resource '"
                << name
                << "' with ID "
                << resId
                << " but resource already has ID "
                << ResourceId(mPackageId, type->typeId, entry->entryId)
                << "."
                << std::endl;
        return false;
    }

    const auto endIter = std::end(entry->values);
    auto iter = std::lower_bound(std::begin(entry->values), endIter, config, compareConfigs);
    if (iter == endIter || iter->config != config) {
        // This resource did not exist before, add it.
        entry->values.insert(iter, ResourceConfigValue{ config, source, {}, std::move(value) });
    } else {
        int collisionResult = defaultCollisionHandler(*iter->value, *value);
        if (collisionResult > 0) {
            // Take the incoming value.
            *iter = ResourceConfigValue{ config, source, {}, std::move(value) };
        } else if (collisionResult == 0) {
            Logger::error(source)
                    << "duplicate value for resource '" << name << "' "
                    << "with config '" << iter->config << "'."
                    << std::endl;

            Logger::error(iter->source)
                    << "resource previously defined here."
                    << std::endl;
            return false;
        }
    }

    if (resId.isValid()) {
        type->typeId = resId.typeId();
        entry->entryId = resId.entryId();
    }
    return true;
}
예제 #4
0
    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);
                }
            }
        }
    }