4 #include "kobject_helper.h"
6 #include "slab_cache_anon.h"
13 class Ipc_gate_ctl : public Kobject_h<Ipc_gate_ctl>, public Kobject
17 class Ipc_gate : public Kobject_iface
19 friend class Ipc_gate_ctl;
22 Ref_ptr<Thread> _thread;
25 Locked_prio_list _wait_q;
28 class Ipc_gate_obj : public Ipc_gate, public Ipc_gate_ctl
30 FIASCO_DECLARE_KOBJ();
33 friend class Ipc_gate;
34 typedef slab_cache_anon Self_alloc;
37 Thread *thread() const { return _thread.ptr(); }
38 Mword id() const { return _id; }
39 Mword obj_id() const { return _id; }
40 bool is_local(Space *s) const { return _thread->space() == s; }
43 //---------------------------------------------------------------------------
46 EXTENSION class Ipc_gate
49 struct Log_ipc_gate_invoke
56 static unsigned log_fmt(Tb_entry *, int max, char *buf) asm ("__fmt_ipc_gate_invoke");
59 //---------------------------------------------------------------------------
64 #include "entry_frame.h"
65 #include "ipc_timeout.h"
66 #include "kmem_slab.h"
68 #include "ram_quota.h"
69 #include "static_init.h"
71 #include "thread_state.h"
74 FIASCO_DEFINE_KOBJ(Ipc_gate_obj);
78 Ipc_gate_obj::downgrade(unsigned long attr)
80 if (attr & L4_fpage::C_obj_right_1)
81 return static_cast<Ipc_gate*>(this);
83 return static_cast<Ipc_gate_ctl*>(this);
87 Ipc_gate::Ipc_gate(Ram_quota *q, Thread *t, Mword id)
88 : _thread(t), _id(id), _quota(q), _wait_q()
92 Ipc_gate_obj::Ipc_gate_obj(Ram_quota *q, Thread *t, Mword id)
98 Ipc_gate_obj::unblock_all()
100 while (::Prio_list_elem *h = _wait_q.head())
102 Lock_guard<Cpu_lock> g1(&cpu_lock);
105 Lock_guard<Spin_lock> g2(&_wait_q);
106 if (EXPECT_FALSE(h != _wait_q.head()))
109 w = static_cast<Thread*>(Sender::cast(h));
110 w->sender_dequeue(&_wait_q);
112 w->state_change_safely(~(Thread_ipc_in_progress | Thread_send_in_progress), Thread_ready);
120 Ipc_gate_obj::initiate_deletion(Kobject ***r)
123 _thread->ipc_gate_deleted(_id);
125 Kobject::initiate_deletion(r);
130 Ipc_gate_obj::destroy(Kobject ***r)
138 Ipc_gate_obj::~Ipc_gate_obj()
143 PUBLIC inline NEEDS[<cstddef>]
145 Ipc_gate_obj::operator new (size_t, void *b)
148 PRIVATE static inline NOEXPORT NEEDS["kmem_slab.h"]
149 Ipc_gate_obj::Self_alloc *
150 Ipc_gate_obj::allocator()
152 static Self_alloc* slabs =
153 new Kmem_slab_simple (sizeof (Ipc_gate_obj), sizeof (Mword), "Ipc_gate");
160 Ipc_gate::create(Ram_quota *q, Thread *t, Mword id)
163 if (q->alloc(sizeof(Ipc_gate_obj)))
165 if (nq = Ipc_gate_obj::allocator()->alloc())
166 return new (nq) Ipc_gate_obj(q, t, id);
168 q->free(sizeof(Ipc_gate_obj));
175 void Ipc_gate_obj::operator delete (void *_f)
177 register Ipc_gate_obj *f = (Ipc_gate_obj*)_f;
178 Ram_quota *p = f->_quota;
181 p->free(sizeof(Ipc_gate_obj));
183 allocator()->free(f);
186 PRIVATE inline NOEXPORT
188 Ipc_gate_ctl::bind_thread(L4_obj_ref, Mword, Syscall_frame *f, Utcb const *in, Utcb *)
190 L4_msg_tag tag = f->tag();
191 L4_snd_item_iter snd_items(in, tag.words());
193 if (tag.words() < 2 || !tag.items() || !snd_items.next())
194 return commit_result(-L4_err::EInval);
196 L4_fpage bind_thread(snd_items.get()->d);
197 if (EXPECT_FALSE(!bind_thread.is_objpage()))
198 return commit_error(in, L4_error::Overflow);
200 register Context *const c_thread = ::current();
201 register Space *const c_space = c_thread->space();
202 register Obj_space *const o_space = c_space->obj_space();
203 unsigned char t_rights = 0;
204 Thread *t = Kobject::dcast<Thread*>(o_space->lookup_local(bind_thread.obj_index(), &t_rights));
206 if (!(t_rights & L4_fpage::CS))
207 return commit_result(-L4_err::EPerm);
210 Ipc_gate_obj *g = static_cast<Ipc_gate_obj*>(this);
211 g->_id = in->values[1];
216 c_thread->rcu_wait();
219 return commit_result(0);
222 PRIVATE inline NOEXPORT
224 Ipc_gate_ctl::get_infos(L4_obj_ref, Mword, Syscall_frame *, Utcb const *, Utcb *out)
226 Ipc_gate_obj *g = static_cast<Ipc_gate_obj*>(this);
227 out->values[0] = g->_id;
228 return commit_result(0, 1);
233 Ipc_gate_ctl::invoke(L4_obj_ref self, Mword rights, Syscall_frame *f, Utcb *utcb)
235 if (f->tag().proto() == L4_msg_tag::Label_kobject)
236 Kobject_h<Ipc_gate_ctl>::invoke(self, rights, f, utcb);
238 static_cast<Ipc_gate_obj*>(this)->Ipc_gate::invoke(self, rights, f, utcb);
244 Ipc_gate_ctl::kinvoke(L4_obj_ref self, Mword rights, Syscall_frame *f, Utcb const *in, Utcb *out)
246 L4_msg_tag tag = f->tag();
248 if (EXPECT_FALSE(tag.proto() != L4_msg_tag::Label_kobject))
249 return commit_result(-L4_err::EBadproto);
251 if (EXPECT_FALSE(tag.words() < 1))
252 return commit_result(-L4_err::EInval);
254 switch (in->values[0])
257 return bind_thread(self, rights, f, in, out);
259 return get_infos(self, rights, f, in, out);
261 return kobject_invoke(self, rights, f, in, out);
265 PRIVATE inline NOEXPORT
267 Ipc_gate::block(Thread *ct, L4_timeout const &to, Utcb *u)
272 t = to.microsecs(Timer::system_clock(), u);
274 return L4_error::Timeout;
278 Lock_guard<Spin_lock> g(&_wait_q);
279 ct->wait_queue(&_wait_q);
280 ct->sender_enqueue(&_wait_q, ct->sched_context()->prio());
282 ct->state_change_dirty(~Thread_ready, Thread_ipc_in_progress | Thread_send_in_progress);
287 timeout.set(t, ct->cpu());
288 ct->set_timeout(&timeout);
292 if (EXPECT_FALSE(ct->in_sender_list() && timeout.has_hit()))
294 Lock_guard<Spin_lock> g(&_wait_q);
295 if (!ct->in_sender_list())
296 return L4_error::None;
298 ct->sender_dequeue(&_wait_q);
299 return L4_error::Timeout;
301 return L4_error::None;
307 Ipc_gate::invoke(L4_obj_ref /*self*/, Mword rights, Syscall_frame *f, Utcb *utcb)
309 Syscall_frame *ipc_f = f;
310 //LOG_MSG_3VAL(current(), "gIPC", Mword(_thread), _id, f->obj_2_flags());
311 //printf("Invoke: Ipc_gate(%lx->%p)...\n", _id, _thread);
312 Thread *ct = current_thread();
315 bool have_rcv = false;
317 if (EXPECT_FALSE(!_thread.ptr()))
319 L4_error e = block(ct, f->timeout().snd, utcb);
322 f->tag(commit_error(utcb, e));
326 if (EXPECT_FALSE(!_thread.ptr()))
328 f->tag(commit_error(utcb, L4_error::Not_existent));
333 bool ipc = _thread->check_sys_ipc(f->ref().flags(), &partner, &sender, &have_rcv);
335 LOG_TRACE("IPC Gate invoke", "gate", current(), __fmt_ipc_gate_invoke,
336 Log_ipc_gate_invoke *l = tbe->payload<Log_ipc_gate_invoke>();
337 l->gate_dbg_id = dbg_info()->dbg_id();
338 l->thread_dbg_id = _thread->dbg_id();
339 l->label = _id | rights;
342 if (EXPECT_FALSE(!ipc))
343 f->tag(commit_error(utcb, L4_error::Not_existent));
346 ipc_f->from(_id | rights);
347 ct->do_ipc(f->tag(), partner, partner, have_rcv, sender,
348 f->timeout(), f, rights);
352 //---------------------------------------------------------------------------
353 IMPLEMENTATION [debug]:
357 Ipc_gate::log_fmt(Tb_entry *e, int max, char *buf)
359 Log_ipc_gate_invoke *l = e->payload<Log_ipc_gate_invoke>();
360 return snprintf(buf, max, "D-gate=%lx D-thread=%lx L=%lx",
361 l->gate_dbg_id, l->thread_dbg_id, l->label);