4 #include "kobject_helper.h"
6 #include "slab_cache.h"
7 #include "thread_object.h"
13 class Ipc_gate_ctl : public Kobject_h<Ipc_gate_ctl, Kobject_iface>
23 class Ipc_gate : public Kobject
25 friend class Ipc_gate_ctl;
26 friend class Jdb_sender_list;
29 Ref_ptr<Thread> _thread;
32 Locked_prio_list _wait_q;
35 class Ipc_gate_obj : public Ipc_gate, public Ipc_gate_ctl
37 FIASCO_DECLARE_KOBJ();
40 friend class Ipc_gate;
41 typedef Slab_cache Self_alloc;
44 bool put() { return Ipc_gate::put(); }
46 Thread *thread() const { return _thread.ptr(); }
47 Mword id() const { return _id; }
48 Mword obj_id() const { return _id; }
49 bool is_local(Space *s) const { return _thread && _thread->space() == s; }
52 //---------------------------------------------------------------------------
55 EXTENSION class Ipc_gate
58 struct Log_ipc_gate_invoke
65 static unsigned log_fmt(Tb_entry *, int max, char *buf) asm ("__fmt_ipc_gate_invoke");
68 //---------------------------------------------------------------------------
73 #include "assert_opt.h"
74 #include "entry_frame.h"
75 #include "ipc_timeout.h"
76 #include "kmem_slab.h"
78 #include "ram_quota.h"
79 #include "static_init.h"
81 #include "thread_state.h"
84 FIASCO_DEFINE_KOBJ(Ipc_gate_obj);
88 Ipc_gate_obj::map_root()
89 { return Ipc_gate::map_root(); }
93 Ipc_gate_obj::downgrade(unsigned long attr)
95 if (attr & L4_msg_item::C_obj_right_1)
96 return static_cast<Ipc_gate*>(this);
98 return static_cast<Ipc_gate_ctl*>(this);
102 Ipc_gate::Ipc_gate(Ram_quota *q, Thread *t, Mword id)
103 : _thread(t), _id(id), _quota(q), _wait_q()
107 Ipc_gate_obj::Ipc_gate_obj(Ram_quota *q, Thread *t, Mword id)
113 Ipc_gate_obj::unblock_all()
115 while (::Prio_list_elem *h = _wait_q.first())
117 Lock_guard<Cpu_lock> g1(&cpu_lock);
120 Lock_guard<decltype(_wait_q.lock())> g2(_wait_q.lock());
121 if (EXPECT_FALSE(h != _wait_q.first()))
124 w = static_cast<Thread*>(Sender::cast(h));
125 w->sender_dequeue(&_wait_q);
133 Ipc_gate_obj::initiate_deletion(Kobject ***r)
136 _thread->ipc_gate_deleted(_id);
138 Kobject::initiate_deletion(r);
143 Ipc_gate_obj::destroy(Kobject ***r)
151 Ipc_gate_obj::~Ipc_gate_obj()
156 PUBLIC inline NEEDS[<cstddef>]
158 Ipc_gate_obj::operator new (size_t, void *b) throw()
161 static Kmem_slab_t<Ipc_gate_obj> _ipc_gate_allocator("Ipc_gate");
164 Ipc_gate_obj::Self_alloc *
165 Ipc_gate_obj::allocator()
166 { return &_ipc_gate_allocator; }
170 Ipc_gate::create(Ram_quota *q, Thread *t, Mword id)
172 Auto_quota<Ram_quota> quota(q, sizeof(Ipc_gate_obj));
174 if (EXPECT_FALSE(!quota))
177 void *nq = Ipc_gate_obj::allocator()->alloc();
178 if (EXPECT_FALSE(!nq))
182 return new (nq) Ipc_gate_obj(q, t, id);
186 void Ipc_gate_obj::operator delete (void *_f)
188 register Ipc_gate_obj *f = (Ipc_gate_obj*)_f;
189 Ram_quota *p = f->_quota;
191 allocator()->free(f);
193 p->free(sizeof(Ipc_gate_obj));
196 PRIVATE inline NOEXPORT NEEDS["assert_opt.h"]
198 Ipc_gate_ctl::bind_thread(L4_obj_ref, Mword, Syscall_frame *f, Utcb const *in, Utcb *)
200 L4_msg_tag tag = f->tag();
201 L4_snd_item_iter snd_items(in, tag.words());
203 if (tag.words() < 2 || !tag.items() || !snd_items.next())
204 return commit_result(-L4_err::EInval);
206 L4_fpage bind_thread(snd_items.get()->d);
207 if (EXPECT_FALSE(!bind_thread.is_objpage()))
208 return commit_error(in, L4_error::Overflow);
210 register Context *const c_thread = ::current();
211 assert_opt(c_thread);
212 register Space *const c_space = c_thread->space();
213 assert_opt (c_space);
214 unsigned char t_rights = 0;
215 Thread *t = Kobject::dcast<Thread_object*>(c_space->lookup_local(bind_thread.obj_index(), &t_rights));
217 if (!(t_rights & L4_fpage::CS))
218 return commit_result(-L4_err::EPerm);
221 Ipc_gate_obj *g = static_cast<Ipc_gate_obj*>(this);
222 g->_id = in->values[1];
227 c_thread->rcu_wait();
230 return commit_result(0);
233 PRIVATE inline NOEXPORT
235 Ipc_gate_ctl::get_infos(L4_obj_ref, Mword, Syscall_frame *, Utcb const *, Utcb *out)
237 Ipc_gate_obj *g = static_cast<Ipc_gate_obj*>(this);
238 out->values[0] = g->_id;
239 return commit_result(0, 1);
244 Ipc_gate_ctl::invoke(L4_obj_ref self, Mword rights, Syscall_frame *f, Utcb *utcb)
246 if (f->tag().proto() == L4_msg_tag::Label_kobject)
247 Kobject_h<Ipc_gate_ctl, Kobject_iface>::invoke(self, rights, f, utcb);
249 static_cast<Ipc_gate_obj*>(this)->Ipc_gate::invoke(self, rights, f, utcb);
255 Ipc_gate_ctl::kinvoke(L4_obj_ref self, Mword rights, Syscall_frame *f, Utcb const *in, Utcb *out)
257 L4_msg_tag tag = f->tag();
259 if (EXPECT_FALSE(tag.proto() != L4_msg_tag::Label_kobject))
260 return commit_result(-L4_err::EBadproto);
262 if (EXPECT_FALSE(tag.words() < 1))
263 return commit_result(-L4_err::EInval);
265 switch (in->values[0])
268 return bind_thread(self, rights, f, in, out);
270 return get_infos(self, rights, f, in, out);
272 return static_cast<Ipc_gate_obj*>(this)->kobject_invoke(self, rights, f, in, out);
276 PRIVATE inline NOEXPORT
278 Ipc_gate::block(Thread *ct, L4_timeout const &to, Utcb *u)
283 t = to.microsecs(Timer::system_clock(), u);
285 return L4_error::Timeout;
289 Lock_guard<decltype(_wait_q.lock())> g(_wait_q.lock());
290 ct->set_wait_queue(&_wait_q);
291 ct->sender_enqueue(&_wait_q, ct->sched_context()->prio());
293 ct->state_change_dirty(~Thread_ready, Thread_send_wait);
298 timeout.set(t, ct->cpu());
299 ct->set_timeout(&timeout);
304 ct->state_change(~Thread_ipc_mask, Thread_ready);
307 if (EXPECT_FALSE(ct->in_sender_list() && timeout.has_hit()))
309 Lock_guard<decltype(_wait_q.lock())> g(_wait_q.lock());
310 if (!ct->in_sender_list())
311 return L4_error::None;
313 ct->sender_dequeue(&_wait_q);
314 return L4_error::Timeout;
316 return L4_error::None;
322 Ipc_gate::invoke(L4_obj_ref /*self*/, Mword rights, Syscall_frame *f, Utcb *utcb)
324 Syscall_frame *ipc_f = f;
325 //LOG_MSG_3VAL(current(), "gIPC", Mword(_thread), _id, f->obj_2_flags());
326 //printf("Invoke: Ipc_gate(%lx->%p)...\n", _id, _thread);
327 Thread *ct = current_thread();
330 bool have_rcv = false;
332 if (EXPECT_FALSE(!_thread.ptr()))
334 L4_error e = block(ct, f->timeout().snd, utcb);
337 f->tag(commit_error(utcb, e));
341 if (EXPECT_FALSE(!_thread.ptr()))
343 f->tag(commit_error(utcb, L4_error::Not_existent));
348 bool ipc = _thread->check_sys_ipc(f->ref().op(), &partner, &sender, &have_rcv);
350 LOG_TRACE("IPC Gate invoke", "gate", current(), __fmt_ipc_gate_invoke,
351 Log_ipc_gate_invoke *l = tbe->payload<Log_ipc_gate_invoke>();
352 l->gate_dbg_id = dbg_id();
353 l->thread_dbg_id = _thread->dbg_id();
354 l->label = _id | rights;
357 if (EXPECT_FALSE(!ipc))
358 f->tag(commit_error(utcb, L4_error::Not_existent));
361 ipc_f->from(_id | rights);
362 ct->do_ipc(f->tag(), partner, partner, have_rcv, sender,
363 f->timeout(), f, rights);
367 //---------------------------------------------------------------------------
368 IMPLEMENTATION [debug]:
372 Ipc_gate_obj::dbg_info() const
373 { return Ipc_gate::dbg_info(); }
377 Ipc_gate::log_fmt(Tb_entry *e, int max, char *buf)
379 Log_ipc_gate_invoke *l = e->payload<Log_ipc_gate_invoke>();
380 return snprintf(buf, max, "D-gate=%lx D-thread=%lx L=%lx",
381 l->gate_dbg_id, l->thread_dbg_id, l->label);