| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file |
| |
| #include <lib/fake-object/object.h> |
| #include <lib/zx/status.h> |
| #include <zircon/types.h> |
| |
| #include <fbl/auto_lock.h> |
| #include <fbl/ref_ptr.h> |
| |
| namespace fake_object { |
| |
| zx::status<fbl::RefPtr<Object>> HandleTable::GetLocked(zx_handle_t handle) { |
| zx::status status = HandleToIndex(handle); |
| if (!status.is_ok() || status.value() >= handles_.size() || !handles_[status.value()]) { |
| ftracef("handle = 0x%x, not found\n", handle); |
| return zx::error(ZX_ERR_NOT_FOUND); |
| } |
| auto& obj = handles_[status.value()]; |
| ftracef("handle = 0x%x, obj = %p, type = %u, index = %zu\n", handle, obj.get(), obj->type(), |
| status.value()); |
| return zx::success(obj); |
| } |
| |
| __EXPORT |
| zx::status<zx_handle_t> HandleTable::Add(fbl::RefPtr<Object> obj) { |
| fbl::AutoLock guard(&lock_); |
| __UNUSED auto* obj_ptr = obj.get(); |
| zx_handle_t handle = ZX_HANDLE_INVALID; |
| bool found_slot = false; |
| size_t idx = 0; |
| |
| for (size_t i = 0; i < handles_.size(); ++i) { |
| if (!handles_[i]) { |
| idx = i; |
| handles_[idx] = std::move(obj); |
| found_slot = true; |
| break; |
| } |
| } |
| |
| if (!found_slot) { |
| idx = handles_.size(); |
| handles_.push_back(std::move(obj)); |
| } |
| handle = IndexToHandle(idx); |
| ftracef("handle = 0x%x, obj = %p, type = %u, index = %zu\n", handle, obj_ptr, obj_ptr->type(), |
| idx); |
| return zx::success(handle); |
| } |
| |
| __EXPORT |
| zx::status<> HandleTable::Remove(zx_handle_t handle) { |
| zx::status status = HandleToIndex(handle); |
| if (!status.is_ok()) { |
| return status.take_error(); |
| } |
| size_t idx = status.value(); |
| |
| // Pull the object out of the handle table so that we can release the handle |
| // table lock before running the object's dtor. This prevents issues like |
| // deadlocks if the object asserts in its dtor as a test object may do. |
| fbl::RefPtr<Object> obj; |
| { |
| fbl::AutoLock guard(&lock_); |
| obj = std::move(handles_[idx]); |
| } |
| ftracef("handle = 0x%x, obj = %p, type = %u, index = %zu\n", handle, obj.get(), obj->type(), idx); |
| obj.reset(); |
| return zx::ok(); |
| } |
| |
| __EXPORT |
| void HandleTable::Clear() { |
| fbl::AutoLock lock(&lock_); |
| for (auto& e : handles_) { |
| if (e) { |
| e.reset(); |
| } |
| } |
| } |
| |
| __EXPORT |
| void HandleTable::Dump() { |
| fbl::AutoLock lock(&lock_); |
| int pos = 0; |
| printf("Fake Handle Table [size: %zu]:\n", size_locked()); |
| for (auto& e : handles_) { |
| printf("[%d] %p", pos++, e.get()); |
| if (e) { |
| printf(" (type: %u)", static_cast<uint32_t>(e->type())); |
| } |
| printf("\n"); |
| } |
| } |
| |
| } // namespace fake_object |