blob: 50258dc74404e72aa1a4b24a3db9f421940453c7 [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/log_dispatcher.h"
#include <lib/counters.h>
#include <zircon/errors.h>
#include <zircon/rights.h>
#include <zircon/syscalls/log.h>
#include <fbl/alloc_checker.h>
#include <fbl/auto_lock.h>
KCOUNTER(dispatcher_log_create_count, "dispatcher.log.create")
KCOUNTER(dispatcher_log_destroy_count, "dispatcher.log.destroy")
zx_status_t LogDispatcher::Create(uint32_t flags, KernelHandle<LogDispatcher>* handle,
zx_rights_t* rights) {
fbl::AllocChecker ac;
KernelHandle new_handle(fbl::AdoptRef(new (&ac) LogDispatcher(flags)));
if (!ac.check())
return ZX_ERR_NO_MEMORY;
if (flags & ZX_LOG_FLAG_READABLE) {
// Thread safety analysis is disabled here. Calling Initialize could
// immediately call Notify, calling back into the dispatcher. Thus the lock
// cannot be held. So far, the log dispatcher holding |reader_| has not
// escaped beyond this thread, so it is safe to call Initialize.
[&]() TA_NO_THREAD_SAFETY_ANALYSIS {
new_handle.dispatcher()->reader_.Initialize(&LogDispatcher::Notify,
new_handle.dispatcher().get());
}();
}
// Note: ZX_RIGHT_READ is added by sys_debuglog_create when ZX_LOG_FLAG_READABLE.
*rights = default_rights();
*handle = ktl::move(new_handle);
return ZX_OK;
}
LogDispatcher::LogDispatcher(uint32_t flags) : SoloDispatcher(ZX_LOG_WRITABLE), flags_(flags) {
kcounter_add(dispatcher_log_create_count, 1);
}
LogDispatcher::~LogDispatcher() {
kcounter_add(dispatcher_log_destroy_count, 1);
if (flags_ & ZX_LOG_FLAG_READABLE) {
reader_.Disconnect();
}
}
void LogDispatcher::Signal() {
canary_.Assert();
UpdateState(0, ZX_CHANNEL_READABLE);
}
// static
void LogDispatcher::Notify(void* cookie) {
LogDispatcher* log = static_cast<LogDispatcher*>(cookie);
log->Signal();
}
zx_status_t LogDispatcher::Write(uint32_t severity, uint32_t flags, ktl::string_view str) {
canary_.Assert();
return dlog_write(severity, flags_ | flags, str);
}
zx_status_t LogDispatcher::Read(uint32_t flags, dlog_record_t* record, size_t* actual) {
canary_.Assert();
if (!(flags_ & ZX_LOG_FLAG_READABLE))
return ZX_ERR_BAD_STATE;
Guard<Mutex> guard{get_lock()};
zx_status_t status = reader_.Read(0, record, actual);
if (status == ZX_ERR_SHOULD_WAIT) {
UpdateStateLocked(ZX_CHANNEL_READABLE, 0);
}
return status;
}