]> rtime.felk.cvut.cz Git - l4.git/blobdiff - kernel/fiasco/src/kern/ipc_gate.cpp
Update
[l4.git] / kernel / fiasco / src / kern / ipc_gate.cpp
index aabd0570e91d87228002e8d0b9bc6b1d4cc0798b..bb58f898941390c86c916cfe5b487ab8cc15cb7a 100644 (file)
@@ -2,8 +2,7 @@ INTERFACE:
 
 #include "kobject.h"
 #include "kobject_helper.h"
-#include "ref_ptr.h"
-#include "slab_cache_anon.h"
+#include "slab_cache.h"
 #include "thread_object.h"
 
 class Ram_quota;
@@ -20,48 +19,49 @@ private:
   };
 };
 
-class Ipc_gate : public Kobject
+class Ipc_gate : public cxx::Dyn_castable<Ipc_gate, Kobject>
 {
   friend class Ipc_gate_ctl;
+  friend class Jdb_sender_list;
 protected:
 
-  Ref_ptr<Thread> _thread;
+  Thread *_thread;
   Mword _id;
   Ram_quota *_quota;
   Locked_prio_list _wait_q;
 };
 
-class Ipc_gate_obj : public Ipc_gate, public Ipc_gate_ctl
+class Ipc_gate_obj :
+  public cxx::Dyn_castable<Ipc_gate_obj, Ipc_gate, Ipc_gate_ctl>
 {
-  FIASCO_DECLARE_KOBJ();
-
-private:
   friend class Ipc_gate;
-  typedef slab_cache_anon Self_alloc;
+  typedef Slab_cache Self_alloc;
 
 public:
   bool put() { return Ipc_gate::put(); }
 
-  Thread *thread() const { return _thread.ptr(); }
+  Thread *thread() const { return _thread; }
   Mword id() const { return _id; }
   Mword obj_id() const { return _id; }
-  bool is_local(Space *s) const { return _thread->space() == s; }
+  bool is_local(Space *s) const { return _thread && _thread->space() == s; }
 };
 
 //---------------------------------------------------------------------------
 INTERFACE [debug]:
 
+#include "tb_entry.h"
+
 EXTENSION class Ipc_gate
 {
 protected:
-  struct Log_ipc_gate_invoke
+  struct Log_ipc_gate_invoke : public Tb_entry
   {
     Mword gate_dbg_id;
     Mword thread_dbg_id;
     Mword label;
+    void print(String_buffer *buf) const;
   };
 
-  static unsigned log_fmt(Tb_entry *, int max, char *buf) asm ("__fmt_ipc_gate_invoke");
 };
 
 //---------------------------------------------------------------------------
@@ -69,9 +69,11 @@ IMPLEMENTATION:
 
 #include <cstddef>
 
+#include "assert_opt.h"
 #include "entry_frame.h"
 #include "ipc_timeout.h"
 #include "kmem_slab.h"
+#include "kobject_rpc.h"
 #include "logdefs.h"
 #include "ram_quota.h"
 #include "static_init.h"
@@ -79,8 +81,6 @@ IMPLEMENTATION:
 #include "thread_state.h"
 #include "timer.h"
 
-FIASCO_DEFINE_KOBJ(Ipc_gate_obj);
-
 PUBLIC
 ::Kobject_mappable *
 Ipc_gate_obj::map_root()
@@ -98,25 +98,31 @@ Ipc_gate_obj::downgrade(unsigned long attr)
 
 PUBLIC inline
 Ipc_gate::Ipc_gate(Ram_quota *q, Thread *t, Mword id)
-  : _thread(t), _id(id), _quota(q), _wait_q()
-{}
+  : _thread(0), _id(id), _quota(q), _wait_q()
+{
+  if (t)
+    {
+      t->inc_ref();
+      _thread = t;
+    }
+}
 
 PUBLIC inline
 Ipc_gate_obj::Ipc_gate_obj(Ram_quota *q, Thread *t, Mword id)
-  : Ipc_gate(q, t, id)
+  : Dyn_castable_class(q, t, id)
 {}
 
 PUBLIC
 void
 Ipc_gate_obj::unblock_all()
 {
-  while (::Prio_list_elem *h = _wait_q.head())
+  while (::Prio_list_elem *h = _wait_q.first())
     {
-      Lock_guard<Cpu_lock> g1(&cpu_lock);
+      auto g1 = lock_guard(cpu_lock);
       Thread *w;
        {
-         Lock_guard<typeof(_wait_q)> g2(&_wait_q);
-         if (EXPECT_FALSE(h != _wait_q.head()))
+         auto g2 = lock_guard(_wait_q.lock());
+         if (EXPECT_FALSE(h != _wait_q.first()))
            continue;
 
          w = static_cast<Thread*>(Sender::cast(h));
@@ -141,8 +147,13 @@ void
 Ipc_gate_obj::destroy(Kobject ***r)
 {
   Kobject::destroy(r);
-  _thread = 0;
-  unblock_all();
+  Thread *tmp = access_once(&_thread);
+  if (tmp)
+    {
+      _thread = 0;
+      unblock_all();
+      tmp->put_n_reap(r);
+    }
 }
 
 PUBLIC
@@ -153,7 +164,7 @@ Ipc_gate_obj::~Ipc_gate_obj()
 
 PUBLIC inline NEEDS[<cstddef>]
 void *
-Ipc_gate_obj::operator new (size_t, void *b)
+Ipc_gate_obj::operator new (size_t, void *b) throw()
 { return b; }
 
 static Kmem_slab_t<Ipc_gate_obj> _ipc_gate_allocator("Ipc_gate");
@@ -161,67 +172,62 @@ static Kmem_slab_t<Ipc_gate_obj> _ipc_gate_allocator("Ipc_gate");
 PRIVATE static
 Ipc_gate_obj::Self_alloc *
 Ipc_gate_obj::allocator()
-{ return &_ipc_gate_allocator; }
+{ return _ipc_gate_allocator.slab(); }
 
 PUBLIC static
 Ipc_gate_obj *
 Ipc_gate::create(Ram_quota *q, Thread *t, Mword id)
 {
-  void *nq;
-  if (q->alloc(sizeof(Ipc_gate_obj)))
-    {
-      if (nq = Ipc_gate_obj::allocator()->alloc())
-       return new (nq) Ipc_gate_obj(q, t, id);
-      else
-       q->free(sizeof(Ipc_gate_obj));
-    }
+  Auto_quota<Ram_quota> quota(q, sizeof(Ipc_gate_obj));
 
-  return 0;
+  if (EXPECT_FALSE(!quota))
+    return 0;
+
+  void *nq = Ipc_gate_obj::allocator()->alloc();
+  if (EXPECT_FALSE(!nq))
+    return 0;
+
+  quota.release();
+  return new (nq) Ipc_gate_obj(q, t, id);
 }
 
 PUBLIC
 void Ipc_gate_obj::operator delete (void *_f)
 {
-  register Ipc_gate_obj *f = (Ipc_gate_obj*)_f;
+  Ipc_gate_obj *f = (Ipc_gate_obj*)_f;
   Ram_quota *p = f->_quota;
 
+  allocator()->free(f);
   if (p)
     p->free(sizeof(Ipc_gate_obj));
-
-  allocator()->free(f);
 }
 
-PRIVATE inline NOEXPORT
+PRIVATE inline NOEXPORT NEEDS["assert_opt.h"]
 L4_msg_tag
-Ipc_gate_ctl::bind_thread(L4_obj_ref, Mword, Syscall_frame *f, Utcb const *in, Utcb *)
+Ipc_gate_ctl::bind_thread(L4_obj_ref, L4_fpage::Rights,
+                          Syscall_frame *f, Utcb const *in, Utcb *)
 {
   L4_msg_tag tag = f->tag();
-  L4_snd_item_iter snd_items(in, tag.words());
-
-  if (tag.words() < 2 || !tag.items() || !snd_items.next())
-    return commit_result(-L4_err::EInval);
 
-  L4_fpage bind_thread(snd_items.get()->d);
-  if (EXPECT_FALSE(!bind_thread.is_objpage()))
-    return commit_error(in, L4_error::Overflow);
+  if (tag.words() < 2)
+    return commit_result(-L4_err::EMsgtooshort);
 
-  register Context *const c_thread = ::current();
-  register Space *const c_space = c_thread->space();
-  register Obj_space *const o_space = c_space->obj_space();
-  unsigned char t_rights = 0;
-  Thread *t = Kobject::dcast<Thread_object*>(o_space->lookup_local(bind_thread.obj_index(), &t_rights));
+  L4_fpage::Rights t_rights(0);
+  Thread *t = Ko::deref<Thread>(&tag, in, &t_rights);
+  if (!t)
+    return tag;
 
-  if (!(t_rights & L4_fpage::CS))
+  if (!(t_rights & L4_fpage::Rights::CS()))
     return commit_result(-L4_err::EPerm);
 
-
   Ipc_gate_obj *g = static_cast<Ipc_gate_obj*>(this);
   g->_id = in->values[1];
   Mem::mp_wmb();
+  t->inc_ref();
   g->_thread = t;
   Mem::mp_wmb();
   g->unblock_all();
-  c_thread->rcu_wait();
+  current()->rcu_wait();
   g->unblock_all();
 
   return commit_result(0);
@@ -229,7 +235,8 @@ Ipc_gate_ctl::bind_thread(L4_obj_ref, Mword, Syscall_frame *f, Utcb const *in, U
 
 PRIVATE inline NOEXPORT
 L4_msg_tag
-Ipc_gate_ctl::get_infos(L4_obj_ref, Mword, Syscall_frame *, Utcb const *, Utcb *out)
+Ipc_gate_ctl::get_infos(L4_obj_ref, L4_fpage::Rights,
+                        Syscall_frame *, Utcb const *, Utcb *out)
 {
   Ipc_gate_obj *g = static_cast<Ipc_gate_obj*>(this);
   out->values[0] = g->_id;
@@ -238,7 +245,7 @@ Ipc_gate_ctl::get_infos(L4_obj_ref, Mword, Syscall_frame *, Utcb const *, Utcb *
 
 PUBLIC
 void
-Ipc_gate_ctl::invoke(L4_obj_ref self, Mword rights, Syscall_frame *f, Utcb *utcb)
+Ipc_gate_ctl::invoke(L4_obj_ref self, L4_fpage::Rights rights, Syscall_frame *f, Utcb *utcb)
 {
   if (f->tag().proto() == L4_msg_tag::Label_kobject)
     Kobject_h<Ipc_gate_ctl, Kobject_iface>::invoke(self, rights, f, utcb);
@@ -249,7 +256,8 @@ Ipc_gate_ctl::invoke(L4_obj_ref self, Mword rights, Syscall_frame *f, Utcb *utcb
 
 PUBLIC
 L4_msg_tag
-Ipc_gate_ctl::kinvoke(L4_obj_ref self, Mword rights, Syscall_frame *f, Utcb const *in, Utcb *out)
+Ipc_gate_ctl::kinvoke(L4_obj_ref self, L4_fpage::Rights rights,
+                      Syscall_frame *f, Utcb const *in, Utcb *out)
 {
   L4_msg_tag tag = f->tag();
 
@@ -283,8 +291,8 @@ Ipc_gate::block(Thread *ct, L4_timeout const &to, Utcb *u)
     }
 
     {
-      Lock_guard<typeof(_wait_q)> g(&_wait_q);
-      ct->wait_queue(&_wait_q);
+      auto g = lock_guard(_wait_q.lock());
+      ct->set_wait_queue(&_wait_q);
       ct->sender_enqueue(&_wait_q, ct->sched_context()->prio());
     }
   ct->state_change_dirty(~Thread_ready, Thread_send_wait);
@@ -292,7 +300,7 @@ Ipc_gate::block(Thread *ct, L4_timeout const &to, Utcb *u)
   IPC_timeout timeout;
   if (t)
     {
-      timeout.set(t, ct->cpu());
+      timeout.set(t, current_cpu());
       ct->set_timeout(&timeout);
     }
 
@@ -303,7 +311,7 @@ Ipc_gate::block(Thread *ct, L4_timeout const &to, Utcb *u)
 
   if (EXPECT_FALSE(ct->in_sender_list() && timeout.has_hit()))
     {
-      Lock_guard<typeof(_wait_q)> g(&_wait_q);
+      auto g = lock_guard(_wait_q.lock());
       if (!ct->in_sender_list())
        return L4_error::None;
 
@@ -316,7 +324,7 @@ Ipc_gate::block(Thread *ct, L4_timeout const &to, Utcb *u)
 
 PUBLIC
 void
-Ipc_gate::invoke(L4_obj_ref /*self*/, Mword rights, Syscall_frame *f, Utcb *utcb)
+Ipc_gate::invoke(L4_obj_ref /*self*/, L4_fpage::Rights rights, Syscall_frame *f, Utcb *utcb)
 {
   Syscall_frame *ipc_f = f;
   //LOG_MSG_3VAL(current(), "gIPC", Mword(_thread), _id, f->obj_2_flags());
@@ -326,7 +334,7 @@ Ipc_gate::invoke(L4_obj_ref /*self*/, Mword rights, Syscall_frame *f, Utcb *utcb
   Thread *partner = 0;
   bool have_rcv = false;
 
-  if (EXPECT_FALSE(!_thread.ptr()))
+  if (EXPECT_FALSE(!_thread))
     {
       L4_error e = block(ct, f->timeout().snd, utcb);
       if (!e.ok())
@@ -335,7 +343,7 @@ Ipc_gate::invoke(L4_obj_ref /*self*/, Mword rights, Syscall_frame *f, Utcb *utcb
          return;
        }
 
-      if (EXPECT_FALSE(!_thread.ptr()))
+      if (EXPECT_FALSE(!_thread))
        {
          f->tag(commit_error(utcb, L4_error::Not_existent));
          return;
@@ -344,37 +352,72 @@ Ipc_gate::invoke(L4_obj_ref /*self*/, Mword rights, Syscall_frame *f, Utcb *utcb
 
   bool ipc = _thread->check_sys_ipc(f->ref().op(), &partner, &sender, &have_rcv);
 
-  LOG_TRACE("IPC Gate invoke", "gate", current(), __fmt_ipc_gate_invoke,
-      Log_ipc_gate_invoke *l = tbe->payload<Log_ipc_gate_invoke>();
+  LOG_TRACE("IPC Gate invoke", "gate", current(), Log_ipc_gate_invoke,
       l->gate_dbg_id = dbg_id();
       l->thread_dbg_id = _thread->dbg_id();
-      l->label = _id | rights;
+      l->label = _id | cxx::int_value<L4_fpage::Rights>(rights);
   );
 
   if (EXPECT_FALSE(!ipc))
     f->tag(commit_error(utcb, L4_error::Not_existent));
   else
     {
-      ipc_f->from(_id | rights);
+      ipc_f->from(_id | cxx::int_value<L4_fpage::Rights>(rights));
       ct->do_ipc(f->tag(), partner, partner, have_rcv, sender,
                  f->timeout(), f, rights);
     }
 }
 
+namespace {
+static Kobject_iface * FIASCO_FLATTEN
+ipc_gate_factory(Ram_quota *q, Space *space,
+                 L4_msg_tag tag, Utcb const *utcb,
+                 int *err)
+{
+  L4_snd_item_iter snd_items(utcb, tag.words());
+  Thread *thread = 0;
+
+  if (tag.items() && snd_items.next())
+    {
+      L4_fpage bind_thread(snd_items.get()->d);
+      *err = L4_err::EInval;
+      if (EXPECT_FALSE(!bind_thread.is_objpage()))
+        return 0;
+
+      L4_fpage::Rights thread_rights = L4_fpage::Rights(0);
+      thread = cxx::dyn_cast<Thread*>(space->lookup_local(bind_thread.obj_index(), &thread_rights));
+
+      *err = L4_err::EPerm;
+      if (EXPECT_FALSE(!(thread_rights & L4_fpage::Rights::W())))
+        return 0;
+    }
+
+  *err = L4_err::ENomem;
+  return static_cast<Ipc_gate_ctl*>(Ipc_gate::create(q, thread, utcb->values[2]));
+}
+
+static inline void __attribute__((constructor)) FIASCO_INIT
+register_factory()
+{
+  Kobject_iface::set_factory(0, ipc_gate_factory);
+}
+}
+
 //---------------------------------------------------------------------------
 IMPLEMENTATION [debug]:
 
+#include "string_buffer.h"
+
 PUBLIC
 ::Kobject_dbg *
 Ipc_gate_obj::dbg_info() const
 { return Ipc_gate::dbg_info(); }
 
 IMPLEMENT
-unsigned
-Ipc_gate::log_fmt(Tb_entry *e, int max, char *buf)
+void
+Ipc_gate::Log_ipc_gate_invoke::print(String_buffer *buf) const
 {
-  Log_ipc_gate_invoke *l = e->payload<Log_ipc_gate_invoke>();
-  return snprintf(buf, max, "D-gate=%lx D-thread=%lx L=%lx",
-                  l->gate_dbg_id, l->thread_dbg_id, l->label);
+  buf->printf("D-gate=%lx D-thread=%lx L=%lx",
+              gate_dbg_id, thread_dbg_id, label);
 }