WIP(mg-isolate): ChannelDispatcher works with stubs

Change-Id: Id25aea21a44222b4369501224a2b4982d4565560
diff --git a/kernel/lib/magenta/channel_dispatcher.cpp b/kernel/lib/magenta/channel_dispatcher.cpp
index e4025d0..909581b 100644
--- a/kernel/lib/magenta/channel_dispatcher.cpp
+++ b/kernel/lib/magenta/channel_dispatcher.cpp
@@ -10,16 +10,18 @@
 
 #include <assert.h>
 #include <err.h>
-#include <trace.h>
+//#include <trace.h>
 
 #include <kernel/event.h>
-#include <platform.h>
+//#include <platform.h>
 
 #include <magenta/handle.h>
 #include <magenta/message_packet.h>
+#ifdef _KERNEL
 #include <magenta/process_dispatcher.h>
-#include <magenta/rights.h>
 #include <magenta/thread_dispatcher.h>
+#endif
+#include <magenta/rights.h>
 
 #include <mxtl/alloc_checker.h>
 #include <mxtl/auto_lock.h>
@@ -29,8 +31,14 @@
 
 #define LOCAL_TRACE 0
 
+#ifndef _KERNEL
+#define thread_reschedule(args...) ((void)0)
+#undef TA_NO_THREAD_SAFETY_ANALYSIS
+#define TA_NO_THREAD_SAFETY_ANALYSIS /**/
+#endif
+
 // static
-status_t ChannelDispatcher::Create(uint32_t flags,
+mx_status_t ChannelDispatcher::Create(uint32_t flags,
                                    mxtl::RefPtr<Dispatcher>* dispatcher0,
                                    mxtl::RefPtr<Dispatcher>* dispatcher1,
                                    mx_rights_t* rights) {
@@ -54,7 +62,7 @@
 
 ChannelDispatcher::ChannelDispatcher(uint32_t flags)
     : state_tracker_(MX_CHANNEL_WRITABLE) {
-    DEBUG_ASSERT(flags == 0);
+    MX_DEBUG_ASSERT(flags == 0);
 }
 
 // This is called before either ChannelDispatcher is accessible from threads other than the one
@@ -132,7 +140,7 @@
     }
 }
 
-status_t ChannelDispatcher::Read(uint32_t* msg_size,
+mx_status_t ChannelDispatcher::Read(uint32_t* msg_size,
                                  uint32_t* msg_handle_count,
                                  mxtl::unique_ptr<MessagePacket>* msg,
                                  bool may_discard) {
@@ -148,7 +156,7 @@
 
     *msg_size = messages_.front().data_size();
     *msg_handle_count = messages_.front().num_handles();
-    status_t rv = MX_OK;
+    mx_status_t rv = MX_OK;
     if (*msg_size > max_size || *msg_handle_count > max_handle_count) {
         if (!may_discard)
             return MX_ERR_BUFFER_TOO_SMALL;
@@ -163,7 +171,7 @@
     return rv;
 }
 
-status_t ChannelDispatcher::Write(mxtl::unique_ptr<MessagePacket> msg) {
+mx_status_t ChannelDispatcher::Write(mxtl::unique_ptr<MessagePacket> msg) {
     canary_.Assert();
 
     mxtl::RefPtr<ChannelDispatcher> other;
@@ -184,17 +192,23 @@
     return MX_OK;
 }
 
-status_t ChannelDispatcher::Call(mxtl::unique_ptr<MessagePacket> msg,
+mx_status_t ChannelDispatcher::Call(mxtl::unique_ptr<MessagePacket> msg,
                                  mx_time_t deadline, bool* return_handles,
                                  mxtl::unique_ptr<MessagePacket>* reply) {
 
     canary_.Assert();
 
+#ifdef _KERNEL
     auto waiter = ThreadDispatcher::GetCurrent()->GetMessageWaiter();
+#else
+    MessageWaiter *waiter = nullptr;
+#endif
     if (unlikely(waiter->BeginWait(mxtl::WrapRefPtr(this), msg->get_txid()) != MX_OK)) {
+#ifdef _KERNEL
         // If a thread tries BeginWait'ing twice, the VDSO contract around retrying
         // channel calls has been violated.  Shoot the misbehaving process.
         ProcessDispatcher::GetCurrent()->Kill();
+#endif
         return MX_ERR_BAD_STATE;
     }
 
@@ -224,7 +238,7 @@
     return ResumeInterruptedCall(waiter, deadline, reply);
 }
 
-status_t ChannelDispatcher::ResumeInterruptedCall(MessageWaiter* waiter,
+mx_status_t ChannelDispatcher::ResumeInterruptedCall(MessageWaiter* waiter,
                                                   mx_time_t deadline,
                                                   mxtl::unique_ptr<MessagePacket>* reply) {
     canary_.Assert();
@@ -285,7 +299,7 @@
     return 0;
 }
 
-status_t ChannelDispatcher::user_signal(uint32_t clear_mask, uint32_t set_mask, bool peer) {
+mx_status_t ChannelDispatcher::user_signal(uint32_t clear_mask, uint32_t set_mask, bool peer) {
     canary_.Assert();
 
     if ((set_mask & ~MX_USER_SIGNAL_ALL) || (clear_mask & ~MX_USER_SIGNAL_ALL))
@@ -307,7 +321,7 @@
     return other->UserSignalSelf(clear_mask, set_mask);
 }
 
-status_t ChannelDispatcher::UserSignalSelf(uint32_t clear_mask, uint32_t set_mask) {
+mx_status_t ChannelDispatcher::UserSignalSelf(uint32_t clear_mask, uint32_t set_mask) {
     canary_.Assert();
     state_tracker_.UpdateState(clear_mask, set_mask);
     return MX_OK;
@@ -317,7 +331,7 @@
     if (unlikely(channel_)) {
         channel_->RemoveWaiter(this);
     }
-    DEBUG_ASSERT(!InContainer());
+    MX_DEBUG_ASSERT(!InContainer());
 }
 
 mx_status_t ChannelDispatcher::MessageWaiter::BeginWait(mxtl::RefPtr<ChannelDispatcher> channel,
@@ -325,7 +339,7 @@
     if (unlikely(channel_)) {
         return MX_ERR_BAD_STATE;
     }
-    DEBUG_ASSERT(!InContainer());
+    MX_DEBUG_ASSERT(!InContainer());
 
     txid_ = txid;
     status_ = MX_ERR_TIMED_OUT;
@@ -335,16 +349,16 @@
 }
 
 int ChannelDispatcher::MessageWaiter::Deliver(mxtl::unique_ptr<MessagePacket> msg) {
-    DEBUG_ASSERT(channel_);
+    MX_DEBUG_ASSERT(channel_);
 
     msg_ = mxtl::move(msg);
     status_ = MX_OK;
     return event_.Signal(MX_OK);
 }
 
-int ChannelDispatcher::MessageWaiter::Cancel(status_t status) {
-    DEBUG_ASSERT(!InContainer());
-    DEBUG_ASSERT(channel_);
+int ChannelDispatcher::MessageWaiter::Cancel(mx_status_t status) {
+    MX_DEBUG_ASSERT(!InContainer());
+    MX_DEBUG_ASSERT(channel_);
     status_ = status;
     return event_.Signal(status);
 }
diff --git a/kernel/lib/magenta/include/magenta/channel_dispatcher.h b/kernel/lib/magenta/include/magenta/channel_dispatcher.h
index 9b999ae..1277fcb 100644
--- a/kernel/lib/magenta/include/magenta/channel_dispatcher.h
+++ b/kernel/lib/magenta/include/magenta/channel_dispatcher.h
@@ -25,15 +25,15 @@
 public:
     class MessageWaiter;
 
-    static status_t Create(uint32_t flags, mxtl::RefPtr<Dispatcher>* dispatcher0,
-                           mxtl::RefPtr<Dispatcher>* dispatcher1, mx_rights_t* rights);
+    static mx_status_t Create(uint32_t flags, mxtl::RefPtr<Dispatcher>* dispatcher0,
+                              mxtl::RefPtr<Dispatcher>* dispatcher1, mx_rights_t* rights);
 
     ~ChannelDispatcher() final;
     mx_obj_type_t get_type() const final { return MX_OBJ_TYPE_CHANNEL; }
     StateTracker* get_state_tracker() final { return &state_tracker_; }
     mx_status_t add_observer(StateObserver* observer) final;
     mx_koid_t get_related_koid() const final TA_REQ(lock_) { return other_koid_; }
-    status_t user_signal(uint32_t clear_mask, uint32_t set_mask, bool peer) final;
+    mx_status_t user_signal(uint32_t clear_mask, uint32_t set_mask, bool peer) final;
 
     void on_zero_handles() final;
 
@@ -42,21 +42,21 @@
     // size and handle count, respectively. On MX_OK or MX_ERR_BUFFER_TOO_SMALL, they specify the
     // actual size and handle count of the next message. The next message is returned in |*msg| on
     // MX_OK and also on MX_ERR_BUFFER_TOO_SMALL when |may_discard| is set.
-    status_t Read(uint32_t* msg_size,
-                  uint32_t* msg_handle_count,
-                  mxtl::unique_ptr<MessagePacket>* msg,
-                  bool may_disard);
+    mx_status_t Read(uint32_t* msg_size,
+                     uint32_t* msg_handle_count,
+                     mxtl::unique_ptr<MessagePacket>* msg,
+                     bool may_disard);
 
     // Write to the opposing endpoint's message queue.
-    status_t Write(mxtl::unique_ptr<MessagePacket> msg);
-    status_t Call(mxtl::unique_ptr<MessagePacket> msg,
-                  mx_time_t deadline, bool* return_handles,
-                  mxtl::unique_ptr<MessagePacket>* reply);
+    mx_status_t Write(mxtl::unique_ptr<MessagePacket> msg);
+    mx_status_t Call(mxtl::unique_ptr<MessagePacket> msg,
+                     mx_time_t deadline, bool* return_handles,
+                     mxtl::unique_ptr<MessagePacket>* reply);
 
     // Performs the wait-then-read half of Call.  This is meant for retrying
     // after an interruption caused by suspending.
-    status_t ResumeInterruptedCall(MessageWaiter* waiter, mx_time_t deadline,
-                                   mxtl::unique_ptr<MessagePacket>* reply);
+    mx_status_t ResumeInterruptedCall(MessageWaiter* waiter, mx_time_t deadline,
+                                      mxtl::unique_ptr<MessagePacket>* reply);
 
     // MessageWaiter's state is guarded by the lock of the
     // owning ChannelDispatcher, and Deliver(), Signal(), Cancel(),
@@ -70,14 +70,15 @@
     // See also: comments in ChannelDispatcher::Call()
     class MessageWaiter : public mxtl::DoublyLinkedListable<MessageWaiter*> {
     public:
-        MessageWaiter() : txid_(0), status_(MX_ERR_BAD_STATE) {
+        MessageWaiter()
+            : txid_(0), status_(MX_ERR_BAD_STATE) {
         }
 
         ~MessageWaiter();
 
         mx_status_t BeginWait(mxtl::RefPtr<ChannelDispatcher> channel, mx_txid_t txid);
         int Deliver(mxtl::unique_ptr<MessagePacket> msg);
-        int Cancel(status_t status);
+        int Cancel(mx_status_t status);
         mxtl::RefPtr<ChannelDispatcher> get_channel() { return channel_; }
         mx_txid_t get_txid() const { return txid_; }
         mx_status_t Wait(lk_time_t deadline);
@@ -103,7 +104,7 @@
     ChannelDispatcher(uint32_t flags);
     void Init(mxtl::RefPtr<ChannelDispatcher> other);
     int WriteSelf(mxtl::unique_ptr<MessagePacket> msg);
-    status_t UserSignalSelf(uint32_t clear_mask, uint32_t set_mask);
+    mx_status_t UserSignalSelf(uint32_t clear_mask, uint32_t set_mask);
     void OnPeerZeroHandles();
 
     mxtl::Canary<mxtl::magic("CHAN")> canary_;
diff --git a/system/utest/magenta-isolate/main.cpp b/system/utest/magenta-isolate/main.cpp
index 269af48..be81bf1 100644
--- a/system/utest/magenta-isolate/main.cpp
+++ b/system/utest/magenta-isolate/main.cpp
@@ -3,9 +3,11 @@
 #include <mxcpp/new.h>
 
 // kernel/lib/magenta
+#include <magenta/channel_dispatcher.h>
 #include <magenta/dispatcher.h>
 #include <magenta/event_dispatcher.h>
 #include <magenta/handle.h>
+#include <magenta/handle_reaper.h>
 #include <magenta/state_tracker.h>
 
 // system/public/magenta
@@ -21,6 +23,23 @@
 }
 } // namespace internal
 
+void DeleteHandle(Handle* handle) {
+    mxtl::RefPtr<Dispatcher> dispatcher(handle->dispatcher());
+    auto state_tracker = dispatcher->get_state_tracker();
+
+    if (state_tracker) {
+        state_tracker->Cancel(handle);
+    }
+
+    internal::TearDownHandle(handle);
+}
+
+void ReapHandles(Handle** handles, uint32_t num_handles) {
+    while (num_handles > 0) {
+        DeleteHandle(*handles++);
+    }
+}
+
 int main(int argc, char** argv) {
     Handle* h = MakeHandle(nullptr, MX_RIGHT_READ);
     StateTracker st(0x5);
@@ -28,8 +47,17 @@
     printf("rights 0x%x\n", h->rights());
 
     mxtl::RefPtr<Dispatcher> ev;
-    mx_rights_t rights;
-    EventDispatcher::Create(0u, &ev, &rights);
+    mx_rights_t evr;
+    EventDispatcher::Create(0u, &ev, &evr);
     printf("ev koid %" PRIu64 "\n", ev->get_koid());
+
+    mxtl::RefPtr<Dispatcher> ch0;
+    mxtl::RefPtr<Dispatcher> ch1;
+    mx_rights_t chr;
+    ChannelDispatcher::Create(0u, &ch0, &ch1, &chr);
+    printf("ch0 koid %" PRIu64 ", related %" PRIu64 "\n",
+           ch0->get_koid(), ch0->get_related_koid());
+    printf("ch1 koid %" PRIu64 ", related %" PRIu64 "\n",
+           ch1->get_koid(), ch1->get_related_koid());
     return 0;
 }
diff --git a/system/utest/magenta-isolate/rules.mk b/system/utest/magenta-isolate/rules.mk
index 1b2313f..55e6802 100644
--- a/system/utest/magenta-isolate/rules.mk
+++ b/system/utest/magenta-isolate/rules.mk
@@ -13,7 +13,9 @@
 MODULE_SRCS += \
 	$(LOCAL_DIR)/main.cpp \
 	kernel/lib/magenta/dispatcher.cpp \
+	kernel/lib/magenta/channel_dispatcher.cpp \
 	kernel/lib/magenta/event_dispatcher.cpp \
+	kernel/lib/magenta/message_packet.cpp \
 	kernel/lib/magenta/handle.cpp \
 	kernel/lib/magenta/state_tracker.cpp
 
@@ -29,6 +31,7 @@
 
 MODULE_COMPILEFLAGS := \
   -Ikernel/lib/magenta/include \
-  -Isystem/ulib/mxtl/include
+  -Isystem/ulib/mxtl/include \
+  -I$(LOCAL_DIR)/stub-include
 
 include make/module.mk
diff --git a/system/utest/magenta-isolate/stub-include/kernel/event.h b/system/utest/magenta-isolate/stub-include/kernel/event.h
new file mode 100644
index 0000000..0c79030
--- /dev/null
+++ b/system/utest/magenta-isolate/stub-include/kernel/event.h
@@ -0,0 +1,39 @@
+// Copyright 2017 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
+
+#pragma once
+
+#include <magenta/types.h>
+typedef uint64_t lk_time_t;
+
+class Event {
+public:
+    Event(uint32_t opts = 0) {
+    }
+    ~Event() {
+    }
+
+    Event(const Event&) = delete;
+    Event& operator=(const Event&) = delete;
+
+    // Returns:
+    // MX_OK - signaled
+    // MX_ERR_TIMED_OUT - time out expired
+    // MX_ERR_INTERNAL_INTR_KILLED - thread killed
+    // Or the |status| which the caller specified in Event::Signal(status)
+    mx_status_t Wait(lk_time_t deadline) {
+        return MX_OK;
+    }
+
+    // returns number of ready threads
+    int Signal(mx_status_t status = MX_OK) {
+        return MX_OK;
+    }
+
+    mx_status_t Unsignal() {
+        return MX_OK;
+    }
+};
diff --git a/system/utest/magenta-isolate/stub-include/kernel/thread.h b/system/utest/magenta-isolate/stub-include/kernel/thread.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/system/utest/magenta-isolate/stub-include/kernel/thread.h
diff --git a/system/utest/magenta-isolate/stub-include/lib/user_copy/user_ptr.h b/system/utest/magenta-isolate/stub-include/lib/user_copy/user_ptr.h
new file mode 100644
index 0000000..e2421a9
--- /dev/null
+++ b/system/utest/magenta-isolate/stub-include/lib/user_copy/user_ptr.h
@@ -0,0 +1,108 @@
+// Copyright 2017 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
+
+#pragma once
+
+#include <string.h>
+#include <mxtl/type_support.h>
+#include <magenta/types.h>
+
+namespace internal {
+template <typename T> inline constexpr size_t type_size() { return sizeof(T); }
+template <> inline constexpr size_t type_size<void>() { return 1u; }
+template <> inline constexpr size_t type_size<const void>() { return 1u; }
+template <> inline constexpr size_t type_size<volatile void>() { return 1u; }
+template <> inline constexpr size_t type_size<const volatile void>() { return 1u; }
+}
+
+template <typename T>
+class user_ptr {
+private:
+    static mx_status_t copy_to_user_unsafe(void *dst, const void* src, size_t size) {
+        memcpy(dst, src, size);
+        return MX_OK;
+    }
+    static mx_status_t copy_from_user_unsafe(void *dst, const void* src, size_t size) {
+        memcpy(dst, src, size);
+        return MX_OK;
+    }
+public:
+    explicit user_ptr(T* p) : ptr_(p) {}
+
+    T* get() const { return ptr_; }
+
+    template <typename C>
+    user_ptr<C> reinterpret() const { return user_ptr<C>(reinterpret_cast<C*>(ptr_)); }
+
+    // special operator to return the nullness of the pointer
+    explicit operator bool() const { return ptr_ != nullptr; }
+
+    // Returns a user_ptr pointing to the |index|-th element from this one, or a null user_ptr if
+    // this pointer is null. Note: This does no other validation, and the behavior is undefined on
+    // overflow. (Using this will fail to compile if T is |void|.)
+    user_ptr element_offset(size_t index) const {
+        return ptr_ ? user_ptr(ptr_ + index) : user_ptr(nullptr);
+    }
+
+    // Returns a user_ptr offset by |offset| bytes from this one.
+    user_ptr byte_offset(size_t offset) const {
+        return ptr_ ? user_ptr(reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(ptr_) + offset))
+                    : user_ptr(nullptr);
+    }
+
+    // Copies a single T to user memory. (Using this will fail to compile if T is |void|.)
+    // Note: The templatization is simply to allow the class to compile if T is |void|.
+    template <typename S = T>
+    mx_status_t copy_to_user(const S& src) const {
+        static_assert(mxtl::is_same<S, T>::value, "Do not use the template parameter.");
+        return copy_to_user_unsafe(ptr_, &src, sizeof(S));
+    }
+
+    // Copies an array of T to user memory. Note: This takes a count not a size, unless T is |void|.
+    // WARNING: This does not check that |count| is reasonable (i.e., that multiplication won't
+    // overflow).
+    mx_status_t copy_array_to_user(const T* src, size_t count) const {
+        return copy_to_user_unsafe(ptr_, src, count * internal::type_size<T>());
+    }
+
+    // Copies an array of T to user memory. Note: This takes a count not a size, unless T is |void|.
+    // WARNING: This does not check that |count| is reasonable (i.e., that multiplication won't
+    // overflow).
+    mx_status_t copy_array_to_user(const T* src, size_t count, size_t offset) const {
+        return copy_to_user_unsafe(ptr_ + offset, src, count * internal::type_size<T>());
+    }
+
+    // Copies a single T from user memory. (Using this will fail to compile if T is |void|.)
+    mx_status_t copy_from_user(typename mxtl::remove_const<T>::type* dst) const {
+        // Intentionally use sizeof(T) here, so *using* this method won't compile if T is |void|.
+        return copy_from_user_unsafe(dst, ptr_, sizeof(T));
+    }
+
+    // Copies an array of T from user memory. Note: This takes a count not a size, unless T is
+    // |void|.
+    // WARNING: This does not check that |count| is reasonable (i.e., that multiplication won't
+    // overflow).
+    mx_status_t copy_array_from_user(typename mxtl::remove_const<T>::type* dst, size_t count) const {
+        return copy_from_user_unsafe(dst, ptr_, count * internal::type_size<T>());
+    }
+
+    // Copies a sub-array of T from user memory. Note: This takes a count not a size, unless T is
+    // |void|.
+    // WARNING: This does not check that |count| is reasonable (i.e., that multiplication won't
+    // overflow).
+    mx_status_t copy_array_from_user(typename mxtl::remove_const<T>::type* dst, size_t count, size_t offset) const {
+        return copy_from_user_unsafe(dst, ptr_ + offset, count * internal::type_size<T>());
+    }
+
+private:
+    // It is very important that this class only wrap the pointer type itself
+    // and not include any other members so as not to break the ABI between
+    // the kernel and user space.
+    T* const ptr_;
+};
+
+template <typename T>
+user_ptr<T> make_user_ptr(T* p) { return user_ptr<T>(p); }