1// Copyright 2016 The Fuchsia Authors 2// 3// Use of this source code is governed by a MIT-style 4// license that can be found in the LICENSE file or at 5// https://opensource.org/licenses/MIT 6 7#include <err.h> 8#include <inttypes.h> 9#include <trace.h> 10 11#include <lib/ktrace.h> 12#include <object/handle.h> 13#include <object/port_dispatcher.h> 14#include <object/process_dispatcher.h> 15 16#include <fbl/alloc_checker.h> 17#include <fbl/ref_ptr.h> 18 19#include <zircon/syscalls/policy.h> 20#include <zircon/types.h> 21 22#include "priv.h" 23 24#define LOCAL_TRACE 0 25 26zx_status_t sys_port_create(uint32_t options, user_out_handle* out) { 27 LTRACEF("options %u\n", options); 28 auto up = ProcessDispatcher::GetCurrent(); 29 zx_status_t result = up->QueryPolicy(ZX_POL_NEW_PORT); 30 if (result != ZX_OK) 31 return result; 32 33 fbl::RefPtr<Dispatcher> dispatcher; 34 zx_rights_t rights; 35 36 result = PortDispatcher::Create(options, &dispatcher, &rights); 37 if (result != ZX_OK) 38 return result; 39 40 uint32_t koid = (uint32_t)dispatcher->get_koid(); 41 42 result = out->make(fbl::move(dispatcher), rights); 43 44 ktrace(TAG_PORT_CREATE, koid, 0, 0, 0); 45 return result; 46} 47 48zx_status_t sys_port_queue(zx_handle_t handle, user_in_ptr<const zx_port_packet_t> packet_in) { 49 LTRACEF("handle %x\n", handle); 50 51 auto up = ProcessDispatcher::GetCurrent(); 52 53 fbl::RefPtr<PortDispatcher> port; 54 zx_status_t status = up->GetDispatcherWithRights(handle, ZX_RIGHT_WRITE, &port); 55 if (status != ZX_OK) 56 return status; 57 58 zx_port_packet_t packet; 59 status = packet_in.copy_from_user(&packet); 60 if (status != ZX_OK) 61 return status; 62 63 return port->QueueUser(packet); 64} 65 66zx_status_t sys_port_wait(zx_handle_t handle, zx_time_t deadline, 67 user_out_ptr<zx_port_packet_t> packet_out) { 68 LTRACEF("handle %x\n", handle); 69 70 auto up = ProcessDispatcher::GetCurrent(); 71 72 fbl::RefPtr<PortDispatcher> port; 73 zx_status_t status = up->GetDispatcherWithRights(handle, ZX_RIGHT_READ, &port); 74 if (status != ZX_OK) 75 return status; 76 77 ktrace(TAG_PORT_WAIT, (uint32_t)port->get_koid(), 0, 0, 0); 78 79 zx_port_packet_t pp; 80 zx_status_t st = port->Dequeue(deadline, &pp); 81 82 ktrace(TAG_PORT_WAIT_DONE, (uint32_t)port->get_koid(), st, 0, 0); 83 84 if (st != ZX_OK) 85 return st; 86 87 status = packet_out.copy_to_user(pp); 88 if (status != ZX_OK) 89 return status; 90 91 return ZX_OK; 92} 93 94zx_status_t sys_port_cancel(zx_handle_t handle, zx_handle_t source, uint64_t key) { 95 auto up = ProcessDispatcher::GetCurrent(); 96 97 fbl::RefPtr<PortDispatcher> port; 98 zx_status_t status = up->GetDispatcherWithRights(handle, ZX_RIGHT_WRITE, &port); 99 if (status != ZX_OK) 100 return status; 101 102 { 103 Guard<fbl::Mutex> guard{up->handle_table_lock()}; 104 Handle* watched = up->GetHandleLocked(source); 105 if (!watched) 106 return ZX_ERR_BAD_HANDLE; 107 if (!watched->HasRights(ZX_RIGHT_WAIT)) 108 return ZX_ERR_ACCESS_DENIED; 109 110 auto dispatcher = watched->dispatcher(); 111 if (!dispatcher->has_state_tracker()) 112 return ZX_ERR_NOT_SUPPORTED; 113 114 bool had_observer = dispatcher->CancelByKey(watched, port.get(), key); 115 bool packet_removed = port->CancelQueued(watched, key); 116 return (had_observer || packet_removed) ? ZX_OK : ZX_ERR_NOT_FOUND; 117 } 118} 119