コード例 #1
0
ファイル: gwobjecthost.cpp プロジェクト: dmerejkowsky/libqi
void GwObjectHost::serviceDisconnected(ServiceId id)
{
  boost::upgrade_lock<boost::shared_mutex> lock(_mutex);
  boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(lock);
  _servicesMetaObjects.erase(id);
  std::map<ServiceId, std::list<GwObjectId> >::iterator findIt = _objectsUsedOnServices.find(id);
  if (findIt == _objectsUsedOnServices.end())
    return;
  std::list<GwObjectId>& objects = findIt->second;

  for (std::list<GwObjectId>::iterator it = objects.begin(), end = objects.end(); it != end; ++it)
  {
    std::pair<TransportSocketPtr, ObjectAddress>& addr = _objectsOrigin[*it];
    Message terminateMessage;

    terminateMessage.setFunction(Message::BoundObjectFunction_Terminate);
    terminateMessage.setObject(addr.second.object);
    terminateMessage.setService(addr.second.service);
    terminateMessage.setType(Message::Type_Call);
    terminateMessage.setValue(AnyReference::from(addr.second.object), "I");
    addr.first->send(terminateMessage);
  }
  objects.clear();
  _objectsUsedOnServices.erase(id);
}
コード例 #2
0
ファイル: mapsector.cpp プロジェクト: hdastwb/freeminer
MapBlock * Map::getBlockBuffered(v3s16 & p)
{
	MapBlock *block;

	{
		auto lock = try_shared_lock(m_block_cache_mutex);
		if(m_block_cache && p == m_block_cache_p)
			return m_block_cache;
	}
	
	// If block doesn't exist, return NULL
	{
	auto lock = m_blocks.lock_shared_rec();
	auto n = m_blocks.find(p);
	if(n == m_blocks.end())
	{
		block = NULL;
	}
	// If block exists, return it
	else{
		block = n->second;
	}
	}
	
	// Cache the last result
	auto lock = unique_lock(m_block_cache_mutex);
	m_block_cache_p = p;
	m_block_cache = block;
	
	return block;
}
コード例 #3
0
ファイル: gwobjecthost.cpp プロジェクト: dmerejkowsky/libqi
void GwObjectHost::clientDisconnected(TransportSocketPtr socket)
{
  boost::upgrade_lock<boost::shared_mutex> lock(_mutex);
  // If the client had not registered any object, return.
  if (_hostObjectBank.find(socket) == _hostObjectBank.end())
    return;

  std::map<ObjectAddress, GwObjectId>& bank = _hostObjectBank[socket];
  if (bank.size() == 0)
    return;

  std::vector<GwObjectId> allIds;
  allIds.reserve(bank.size());
  boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(lock);
  for (std::map<ObjectAddress, GwObjectId>::iterator it = bank.begin(), end = bank.end(); it != end; ++it)
  {
    ServiceId service = it->first.service;
    GwObjectId object = it->second;
    std::list<GwObjectId>& used = _objectsUsedOnServices[service];

    allIds.push_back(object);
    std::list<GwObjectId>::iterator uit = std::find(used.begin(), used.end(), object);
    if (uit != used.end())
      used.erase(uit);
    if (used.size() == 0)
      _objectsUsedOnServices.erase(service);
  }

  for (std::vector<GwObjectId>::iterator it = allIds.begin(), end = allIds.end(); it != end; ++it)
  {
    _objectsMetaObjects.erase(*it);
    _objectsOrigin.erase(*it);
  }
  _hostObjectBank.erase(socket);
}
コード例 #4
0
ファイル: config.cpp プロジェクト: JessicaWhite17/osquery
Status Config::update(const std::map<std::string, std::string>& config) {
  // A config plugin may call update from an extension. This will update
  // the config instance within the extension process and the update must be
  // reflected in the core.
  if (Registry::external()) {
    for (const auto& source : config) {
      PluginRequest request = {
          {"action", "update"},
          {"source", source.first},
          {"data", source.second},
      };
      // A "update" registry item within core should call the core's update
      // method. The config plugin call action handling must also know to
      // update.
      Registry::call("config", "update", request);
    }
  }

  // Request a unique write lock when updating config.
  boost::unique_lock<boost::shared_mutex> unique_lock(getInstance().mutex_);

  ConfigData conf;
  for (const auto& source : config) {
    if (Registry::external()) {
      VLOG(1) << "Updating extension config source: " << source.first;
    } else {
      VLOG(1) << "Updating config source: " << source.first;
    }
    getInstance().raw_[source.first] = source.second;
  }

  // Now merge all sources together.
  for (const auto& source : getInstance().raw_) {
    mergeConfig(source.second, conf);
  }

  // Call each parser with the optionally-empty, requested, top level keys.
  for (const auto& plugin : Registry::all("config_parser")) {
    auto parser = std::static_pointer_cast<ConfigParserPlugin>(plugin.second);
    if (parser == nullptr || parser.get() == nullptr) {
      continue;
    }

    // For each key requested by the parser, add a property tree reference.
    std::map<std::string, ConfigTree> parser_config;
    for (const auto& key : parser->keys()) {
      if (conf.all_data.count(key) > 0) {
        parser_config[key] = conf.all_data.get_child(key);
      } else {
        parser_config[key] = pt::ptree();
      }
    }
    parser->update(parser_config);
  }

  getInstance().data_ = conf;
  return Status(0, "OK");
}
コード例 #5
0
ファイル: fm_map.cpp プロジェクト: Selat/freeminer
void Map::deleteBlock(MapBlockP block) {
	auto block_p = block->getPos();
	(*m_blocks_delete)[block] = 1;
	m_blocks.erase(block_p);
#if CMAKE_THREADS && !CMAKE_HAVE_THREAD_LOCAL
	auto lock = unique_lock(m_block_cache_mutex);
#endif
	m_block_cache = nullptr;
}
コード例 #6
0
ファイル: meters.cpp プロジェクト: krambn/behavioral-model
MeterErrorCode
Meter::reset_rates() {
  auto lock = unique_lock();
  for (MeterRate &rate : rates) {
    rate.valid = false;
  }
  configured = false;
  return SUCCESS;
}
コード例 #7
0
ファイル: meters.cpp プロジェクト: krambn/behavioral-model
void
Meter::serialize(std::ostream *out) const {
  auto lock = unique_lock();
  (*out) << configured << "\n";
  if (configured) {
    for (const auto &rate : rates)
      (*out) << rate.info_rate << " " << rate.burst_size << "\n";
  }
}
コード例 #8
0
void wait_for_data_to_process()
{
	boost::unique_lock<boost::mutex> unique_lock(mutex);
	while(!data_ready)
	{
		condition_variable.wait(unique_lock);
	}
	process_data();
}
コード例 #9
0
void
FailOverCacheAsyncBridge::run()
{
    boost::unique_lock<decltype(mutex_)> unique_lock(mutex_);

    while (not stop_)
    {
        try
        {
            if (not oldOnes.empty())
            {
                LOG_DEBUG("Writing " << oldOnes.size() << " entries to the failover cache");
                cache_->addEntries(oldOnes);
                oldOnes.clear();
                LOG_DEBUG("Written");
            }
            else
            {
                // Y42 The machine that goes ping
                cache_->flush();
            }

            condvar_.wait_for(unique_lock,
                              timeout_);

            if (oldOnes.empty())
            {
                //we get here by a timeout -> time to swap
                //no risk for deadlock as addEntry only does a tryLock on mutex_
                LOCK_NEW_ONES();

                std::swap(newOnes, oldOnes);
                std::swap(newData, oldData);
            }
        }
        catch (std::exception& e)
        {
            LOG_ERROR("Exception in failover thread: " << e.what());
            if(degraded_fun_)
            {
                degraded_fun_();
            }

            LOCK_NEW_ONES();

            stop_ = true;
            newOnes.clear();
            oldOnes.clear();

            // This thread cleans up itself when it is detached
            thread_->detach();
            thread_ = nullptr;
            cache_ = nullptr;
        }
        // Z42: catch (...) ?
    }
}
コード例 #10
0
ファイル: meters.cpp プロジェクト: krambn/behavioral-model
std::vector<Meter::rate_config_t>
Meter::get_rates() const {
  std::vector<rate_config_t> configs;
  auto lock = unique_lock();
  if (!configured) return configs;
  // elegant but probably not the most efficient
  for (const MeterRate &rate : rates)
    configs.push_back(rate_config_t::make(rate.info_rate, rate.burst_size));
  std::reverse(configs.begin(), configs.end());
  return configs;
}
コード例 #11
0
ファイル: localfiberref.cpp プロジェクト: respu/fiberize
void LocalFiberRef::send(const PendingEvent& pendingEvent) {
    boost::shared_lock<boost::upgrade_mutex> shared_lock(block->mutex);
    block->mailbox->enqueue(pendingEvent);

    if (block->status == Suspended) {
        boost::upgrade_lock<boost::upgrade_mutex> upgrade_lock(std::move(shared_lock), boost::try_to_lock);
        if (upgrade_lock.owns_lock()) {
            boost::unique_lock<boost::upgrade_mutex> unique_lock(std::move(upgrade_lock));
            system->schedule(block, std::move(unique_lock));
        }
    }
}
コード例 #12
0
ファイル: gwobjecthost.cpp プロジェクト: dmerejkowsky/libqi
void GwObjectHost::assignClientMessageObjectsGwIds(const Signature& signature, Message& msg, TransportSocketPtr sender)
{
  // if there's no chance of any object being in the call we're done.
  if (!hasObjectsSomewhere(signature))
    return;

  AnyReference callParameters = msg.value(signature, sender);

  // re-serialize the arguments so that the objects can receive a GW-specific objectId
  // ObjectHost uses a static int for its objectId so we're OK instantiating multiple
  // ones.
  Message forward;
  MockObjectHost host(Message::Service_Server);

  forward.setFlags(msg.flags());
  forward.setValue(callParameters, signature, &host, sender.get());
  msg.setBuffer(forward.buffer());

  // The message will store all the objects it serializes in the host.
  const ObjectHost::ObjectMap& objects = host.objects();
  std::map<GwObjectId, MetaObject> newObjectsMetaObjects;
  std::map<GwObjectId, std::pair<TransportSocketPtr, ObjectAddress> > newObjectsOrigin;
  std::map<ObjectAddress, GwObjectId> newHostObjectBank;
  for (ObjectHost::ObjectMap::const_iterator it = objects.begin(), end = objects.end(); it != end; ++it)
  {
    GwObjectId oid = it->first;
    ServiceBoundObject* sbo = static_cast<ServiceBoundObject*>(it->second.get());
    RemoteObject* ro = static_cast<RemoteObject*>(sbo->object().asGenericObject()->value);
    ObjectAddress addr;
    addr.service = ro->service();
    addr.object = ro->object();
    ro->setTransportSocket(TransportSocketPtr());

    newObjectsMetaObjects[oid] = ro->metaObject();
    newObjectsOrigin[oid] = std::make_pair(sender, addr);
    newHostObjectBank[addr] = oid;
    // We set an empty transportsocket.
    // Otherwise when we destroy `passed` below, the remoteobject
    // will attempt to send back home a `terminate` message, which we don't want.
    // By setting a null socket the object will stay alive on the remote end.

    qiLogDebug() << "Message " << msg.address() << ", Object connection: {" << addr.service << "," << addr.object
                 << "} <=> {0," << oid << "}";
  }
  {
    boost::upgrade_lock<boost::shared_mutex> lock(_mutex);
    boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(lock);
    _objectsMetaObjects.insert(newObjectsMetaObjects.begin(), newObjectsMetaObjects.end());
    _objectsOrigin.insert(newObjectsOrigin.begin(), newObjectsOrigin.end());
    _hostObjectBank[sender].insert(newHostObjectBank.begin(), newHostObjectBank.end());
  }
  callParameters.destroy();
}
コード例 #13
0
ファイル: simple_memoization.hpp プロジェクト: ggeorgiev/dbs
    Value get(const CalculateFunction& calculate)
    {
        boost::upgrade_lock<boost::upgrade_mutex> shared_lock(mContainerMutex);
        if (mHas)
            return mValue;

        // This is controversial but we prefer to block any other access while
        // calculating. This will prevent double calculation.
        boost::upgrade_to_unique_lock<boost::upgrade_mutex> unique_lock(shared_lock);
        mHas = true;
        return mValue = calculate();
    }
コード例 #14
0
ファイル: meters.cpp プロジェクト: krambn/behavioral-model
void
Meter::deserialize(std::istream *in) {
  auto lock = unique_lock();
  (*in) >> configured;
  if (configured) {
    for (size_t i = 0; i < rates.size(); i++) {
      rate_config_t config;
      (*in) >> config.info_rate;
      (*in) >> config.burst_size;
      set_rate(i, config);
    }
  }
}
コード例 #15
0
ファイル: fm_map.cpp プロジェクト: hellotanm/freeminer
//TODO: REMOVE THIS func and use Map::getBlock
MapBlock* Map::getBlockNoCreateNoEx(v3POS p, bool trylock, bool nocache) {

#ifndef NDEBUG
	ScopeProfiler sp(g_profiler, "Map: getBlock");
#endif

#if !ENABLE_THREADS
	nocache = true; //very dirty hack. fix and remove. Also compare speed: no cache and cache with lock
#endif

	if (!nocache) {
#if ENABLE_THREADS && !HAVE_THREAD_LOCAL
		auto lock = try_shared_lock(m_block_cache_mutex, TRY_TO_LOCK);
		if(lock.owns_lock())
#endif
			if(m_block_cache && p == m_block_cache_p) {
#ifndef NDEBUG
				g_profiler->add("Map: getBlock cache hit", 1);
#endif
				return m_block_cache;
			}
	}

	MapBlockP block;
	{
		auto lock = trylock ? m_blocks.try_lock_shared_rec() : m_blocks.lock_shared_rec();
		if (!lock->owns_lock())
			return nullptr;
		auto n = m_blocks.find(p);
		if(n == m_blocks.end())
			return nullptr;
		block = n->second;
	}

	if (!nocache) {
#if ENABLE_THREADS && !HAVE_THREAD_LOCAL
		auto lock = unique_lock(m_block_cache_mutex, TRY_TO_LOCK);
		if(lock.owns_lock())
#endif
		{
			m_block_cache_p = p;
			m_block_cache = block;
		}
	}

	return block;
}
コード例 #16
0
ファイル: memoization.hpp プロジェクト: ggeorgiev/dbs
    Value get(const HandleSPtr& handle, Args... args, const CalculateFunction& calculate)
    {
        const auto& key = mContainer.key(handle, args...);

        boost::upgrade_lock<boost::shared_mutex> shared_lock(mContainerMutex);
        const auto& holder = mContainer.holder(key);
        if (mContainer.has(holder))
            return mContainer.get(holder);

        // This is controversial but we prefer to block any other access while
        // calculating. This will prevent double calculation.
        boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(shared_lock);

        const Value& value = calculate(args...);
        mContainer.put(key, value);

        return value;
    }
コード例 #17
0
ファイル: config.cpp プロジェクト: MetaStackers/osquery
Status Config::update(const std::map<std::string, std::string>& config) {
  // A config plugin may call update from an extension. This will update
  // the config instance within the extension process and the update must be
  // reflected in the core.
  if (Registry::external()) {
    for (const auto& source : config) {
      PluginRequest request = {
          {"action", "update"},
          {"source", source.first},
          {"data", source.second},
      };
      // A "update" registry item within core should call the core's update
      // method. The config plugin call action handling must also know to
      // update.
      Registry::call("config", "update", request);
    }
  }

  // Request a unique write lock when updating config.
  boost::unique_lock<boost::shared_mutex> unique_lock(getInstance().mutex_);

  ConfigData conf;
  for (const auto& source : config) {
    if (Registry::external()) {
      VLOG(1) << "Updating extension config source: " << source.first;
    } else {
      VLOG(1) << "Updating config source: " << source.first;
    }
    getInstance().raw_[source.first] = source.second;
  }

  // Now merge all sources together.
  for (const auto& source : getInstance().raw_) {
    mergeConfig(source.second, conf);
  }

  getInstance().data_ = conf;
  return Status(0, "OK");
}
コード例 #18
0
    /**
     * @brief Remove all in progress timeouts.
     */
    void CancelAll()
    {
        UniqueLock unique_lock(mutex_);

        timeout_timer_.cancel();

        while (!data_.empty())
        {
            auto event = std::move( data_.begin()->second );
            data_.erase(data_.begin());

#ifdef MINGW32_LIMITED_ERRC
            std::errc errc_error = std::errc::interrupted;
#else
            std::errc errc_error = std::errc::operation_canceled;
#endif
            io_service_->post( boost::bind( event_processor_, std::move(event),
                    std::make_error_code(errc_error)));
        }

        data_.clear();
    }
コード例 #19
0
ファイル: meters.cpp プロジェクト: krambn/behavioral-model
Meter::color_t
Meter::execute(const Packet &pkt) {
  color_t packet_color = 0;

  if (!configured) return packet_color;

  clock::time_point now = clock::now();
  int64_t micros_since_init = duration_cast<ticks>(now - time_init).count();

  auto lock = unique_lock();

  /* I tried to make this as accurate as I could. Everything is computed
     compared to a single time point (init). I do not use the interval since
     last update, because it would require multiple consecutive
     approximations. Maybe this is an overkill or I am underestimating the code
     I wrote for BMv1.
     The only thing that could go wrong is if tokens_since_init grew too large,
     but I think it would take years even at high throughput */
  for (MeterRate &rate : rates) {
    uint64_t tokens_since_init =
      static_cast<uint64_t>(micros_since_init * rate.info_rate);
    assert(tokens_since_init >= rate.tokens_last);
    size_t new_tokens = tokens_since_init - rate.tokens_last;
    rate.tokens_last = tokens_since_init;
    rate.tokens = std::min(rate.tokens + new_tokens, rate.burst_size);

    size_t input = (type == MeterType::PACKETS) ? 1u : pkt.get_ingress_length();

    if (rate.tokens < input) {
      packet_color = rate.color;
      break;
    } else {
      rate.tokens -= input;
    }
  }

  return packet_color;
}
コード例 #20
0
    // Only call on io_service
    void ResetTimer()
    {
        const auto now = std::chrono::steady_clock::now();

        UniqueLock unique_lock(mutex_);

        while (running_ && !data_.empty())
        {
            auto map_front_it = data_.begin();
            const auto timeout = map_front_it->first;
            if ( timeout <= now )
            {
                // Effeciently extract the value so we can move it.
                auto event = std::move( map_front_it->second );
                data_.erase(map_front_it);

                // Unlock incase callback calls a TimedActions method.
                unique_lock.unlock();
                event_processor_(std::move(event), std::error_code());
                unique_lock.lock();
            }
            else
            {
                timeout_timer_.expires_at(timeout);

                timeout_timer_.async_wait(
                    boost::bind(
                        &TimedEvents<Event>::HandleTimeout,
                        this->shared_from_this(),
                        boost::asio::placeholders::error
                    )
                );
                break;
            }
        }
    }
コード例 #21
0
 void blockingSet(const K& key, const V& value) {
     size_t index = _hasher(key) % _size;
     boost::unique_lock<boost::shared_mutex> unique_lock(_mutexs[index]);
     _maps[index][key] = value;
 }
コード例 #22
0
 void blockingSet(const K& key, const V& value) {
     boost::unique_lock<boost::shared_mutex> unique_lock(_mutex);
     (*this)[key] = value;
 }
コード例 #23
0
ファイル: fm_map.cpp プロジェクト: hellotanm/freeminer
void Map::getBlockCacheFlush() {
#if ENABLE_THREADS && !HAVE_THREAD_LOCAL
	auto lock = unique_lock(m_block_cache_mutex);
#endif
	m_block_cache = nullptr;
}
コード例 #24
0
void InterfaceManagerImpl::updateDevices()
{
    unique_lock(mMutex);

    GVariant* deviceList = nullptr;
    GError* error = nullptr;
    GCancellable* c = nullptr;

    try
    {
        if(mNetManagerProxy == nullptr){
            throw std::runtime_error("Network Manager proxy not initialized");
        }

        deviceList = g_dbus_proxy_call_sync(mNetManagerProxy,
                                            NM_METHOD_GET_DEVICES,
                                            NULL,
                                            G_DBUS_CALL_FLAGS_NONE,
                                            1000, //timout of operation
                                            c,
                                            &error);


        if (deviceList == NULL && error != NULL){
            throw std::runtime_error(error->message);
        }

        /**< iteration through the list */
        GVariantIter deviceIter1, deviceIter2;
        GVariant *deviceNode1, *deviceNode2;

        g_variant_iter_init(&deviceIter1, deviceList);
        while ((deviceNode1 = g_variant_iter_next_value(&deviceIter1)))
        {
            g_variant_iter_init(&deviceIter2, deviceNode1);
            while ((deviceNode2 = g_variant_iter_next_value(&deviceIter2)))
            {
                gsize strlength = 256;
                const gchar* devicePath = g_variant_get_string(deviceNode2, &strlength);
                InterfaceInfo info = getDeviceInfo(devicePath);
                mInterfaces.insert(InterfaceInfoPair(devicePath, info));
            }
        }                
    }
    catch(const std::exception& e)
    {
        if(deviceList != nullptr){
            g_variant_unref(deviceList);
        }

        if(error != nullptr){
            g_error_free(error);
        }

        if(c != nullptr){
            g_cancellable_release_fd(c);
        }

        std::cout<<e.what()<<std::endl;
        updateFailedSignal();
    }
}
コード例 #25
0
ファイル: gwobjecthost.cpp プロジェクト: dmerejkowsky/libqi
void GwObjectHost::harvestServiceOriginatingObjects(Message& msg, TransportSocketPtr sender)
{
  Signature signature;
  {
    boost::upgrade_lock<boost::shared_mutex> lock(_mutex);
    MetaObject* metaObject = NULL;
    const Signature& (MetaMethod::*signatureGetter)() const = NULL;
    if (msg.type() == Message::Type_Reply || msg.type() == Message::Type_Error)
    {
      std::map<ServiceId, std::map<ObjectId, MetaObject> >::iterator sit = _servicesMetaObjects.find(msg.service());
      if (msg.function() == Message::BoundObjectFunction_MetaObject &&
          sit->second.find(msg.object()) == sit->second.end())
      {
        boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(lock);
        _servicesMetaObjects[msg.service()][Message::GenericObject_Main] = extractReturnedMetaObject(msg, sender);
        return;
      }
      metaObject = &_servicesMetaObjects[msg.service()][msg.object()];
      signatureGetter = &MetaMethod::returnSignature;
    }
    else if (msg.type() == Message::Type_Call || msg.type() == Message::Type_Post)
    {
      // if a service does a CALL, he does so on a user-supplied object.
      std::map<GwObjectId, MetaObject>::iterator mit = _objectsMetaObjects.find(msg.object());
      assert(mit != _objectsMetaObjects.end());
      metaObject = &mit->second;
      signatureGetter = &MetaMethod::parametersSignature;
    }
    const MetaMethod* method = metaObject->method(msg.function());
    if (!method)
      return;
    signature = (method->*signatureGetter)();
  }
  if (!hasObjectsSomewhere(signature))
  {
    // no object can be here
    return;
  }

  AnyReference passed = msg.value(signature, sender);
  StreamContext filler;
  MockObjectHost host(Message::Service_Server);
  Message dummy;

  // we don't want to pollute the original message and potentially change valid id
  // of contained objects, so we do it in an unrelated message.
  dummy.setValue(passed, signature, &host, &filler);

  const ObjectHost::ObjectMap& objects = host.objects();
  std::map<ObjectId, MetaObject> newServicesMetaObject;
  for (ObjectHost::ObjectMap::const_iterator it = objects.begin(), end = objects.end(); it != end; ++it)
  {
    ServiceBoundObject* sbo = static_cast<ServiceBoundObject*>(it->second.get());
    RemoteObject* ro = static_cast<RemoteObject*>(sbo->object().asGenericObject()->value);

    // We set an empty transportsocket.
    // Otherwise when we destroy `passed` below, the remoteobject
    // will attempt to send back home a `terminate` message, which we don't want.
    // By setting a null socket the object will stay alive on the remote end.
    ro->setTransportSocket(TransportSocketPtr());
    newServicesMetaObject[ro->object()] = ro->metaObject();
  }
  {
    boost::upgrade_lock<boost::shared_mutex> lock(_mutex);
    boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(lock);
    _servicesMetaObjects[msg.service()].insert(newServicesMetaObject.begin(), newServicesMetaObject.end());
  }
  passed.destroy();
}