blob: b4bd2c45accaf079b5ebea602c88c6aeb984fbae [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <object/event_pair_dispatcher.h>
#include <assert.h>
#include <err.h>
#include <zircon/rights.h>
#include <fbl/alloc_checker.h>
#include <fbl/auto_lock.h>
constexpr uint32_t kUserSignalMask = ZX_EVENT_SIGNALED | ZX_USER_SIGNAL_ALL;
zx_status_t EventPairDispatcher::Create(fbl::RefPtr<Dispatcher>* dispatcher0,
fbl::RefPtr<Dispatcher>* dispatcher1,
zx_rights_t* rights) {
fbl::AllocChecker ac;
auto holder0 = fbl::AdoptRef(new (&ac) PeerHolder<EventPairDispatcher>());
if (!ac.check())
return ZX_ERR_NO_MEMORY;
auto holder1 = holder0;
auto disp0 = fbl::AdoptRef(new (&ac) EventPairDispatcher(fbl::move(holder0)));
if (!ac.check())
return ZX_ERR_NO_MEMORY;
auto disp1 = fbl::AdoptRef(new (&ac) EventPairDispatcher(fbl::move(holder1)));
if (!ac.check())
return ZX_ERR_NO_MEMORY;
disp0->Init(disp1);
disp1->Init(disp0);
*rights = ZX_DEFAULT_EVENT_PAIR_RIGHTS;
*dispatcher0 = fbl::move(disp0);
*dispatcher1 = fbl::move(disp1);
return ZX_OK;
}
EventPairDispatcher::~EventPairDispatcher() {}
void EventPairDispatcher::on_zero_handles()
TA_NO_THREAD_SAFETY_ANALYSIS {
canary_.Assert();
fbl::AutoLock locker(get_lock());
DEBUG_ASSERT(peer_);
peer_->InvalidateCookieLocked(peer_->get_cookie_jar());
peer_->UpdateStateLocked(0u, ZX_EPAIR_PEER_CLOSED);
peer_.reset();
}
zx_status_t EventPairDispatcher::user_signal(uint32_t clear_mask, uint32_t set_mask, bool peer)
TA_NO_THREAD_SAFETY_ANALYSIS {
canary_.Assert();
if ((set_mask & ~kUserSignalMask) || (clear_mask & ~kUserSignalMask))
return ZX_ERR_INVALID_ARGS;
fbl::AutoLock locker(get_lock());
if (!peer) {
UpdateStateLocked(clear_mask, set_mask);
return ZX_OK;
}
// object_signal() may race with handle_close() on another thread.
if (!peer_)
return ZX_ERR_PEER_CLOSED;
peer_->UpdateStateLocked(clear_mask, set_mask);
return ZX_OK;
}
EventPairDispatcher::EventPairDispatcher(fbl::RefPtr<PeerHolder<EventPairDispatcher>> holder)
: PeeredDispatcher(fbl::move(holder))
{}
// This is called before either EventPairDispatcher is accessible from threads other than the one
// initializing the event pair, so it does not need locking.
void EventPairDispatcher::Init(fbl::RefPtr<EventPairDispatcher> other) TA_NO_THREAD_SAFETY_ANALYSIS {
DEBUG_ASSERT(other);
// No need to take |lock_| here.
DEBUG_ASSERT(!peer_);
peer_koid_ = other->get_koid();
peer_ = fbl::move(other);
}