#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;
};
};
-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");
};
//---------------------------------------------------------------------------
#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"
#include "thread_state.h"
#include "timer.h"
-FIASCO_DEFINE_KOBJ(Ipc_gate_obj);
-
PUBLIC
::Kobject_mappable *
Ipc_gate_obj::map_root()
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));
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
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");
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);
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;
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);
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();
}
{
- 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);
IPC_timeout timeout;
if (t)
{
- timeout.set(t, ct->cpu());
+ timeout.set(t, current_cpu());
ct->set_timeout(&timeout);
}
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;
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());
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())
return;
}
- if (EXPECT_FALSE(!_thread.ptr()))
+ if (EXPECT_FALSE(!_thread))
{
f->tag(commit_error(utcb, L4_error::Not_existent));
return;
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);
}