]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/thread.cpp
cf78462fd43cbd531247770ea187e625d5f8d0b9
[l4.git] / kernel / fiasco / src / kern / thread.cpp
1 INTERFACE:
2
3 #include "l4_types.h"
4 #include "config.h"
5 #include "continuation.h"
6 #include "helping_lock.h"
7 #include "kobject.h"
8 #include "mem_layout.h"
9 #include "member_offs.h"
10 #include "receiver.h"
11 #include "ref_obj.h"
12 #include "sender.h"
13 #include "spin_lock.h"
14 #include "thread_lock.h"
15
16 class Return_frame;
17 class Syscall_frame;
18 class Task;
19 class Thread;
20 class Vcpu_state;
21 class Irq_base;
22
23 typedef Context_ptr_base<Thread> Thread_ptr;
24
25
26 /** A thread.  This class is the driver class for most kernel functionality.
27  */
28 class Thread :
29   public Receiver,
30   public Sender,
31   public Kobject
32 {
33   MEMBER_OFFSET();
34   FIASCO_DECLARE_KOBJ();
35
36   friend class Jdb;
37   friend class Jdb_bt;
38   friend class Jdb_tcb;
39   friend class Jdb_thread;
40   friend class Jdb_thread_list;
41   friend class Jdb_list_threads;
42   friend class Jdb_list_timeouts;
43   friend class Jdb_tbuf_show;
44
45 public:
46   enum Context_mode_kernel { Kernel = 0 };
47   enum Operation
48   {
49     Opcode_mask = 0xffff,
50     Op_control = 0,
51     Op_ex_regs = 1,
52     Op_switch  = 2,
53     Op_stats   = 3,
54     Op_vcpu_resume = 4,
55     Op_register_del_irq = 5,
56     Op_modify_senders = 6,
57     Op_vcpu_control= 7,
58     Op_gdt_x86 = 0x10,
59     Op_set_tpidruro_arm = 0x10,
60     Op_set_fs_amd64 = 0x12,
61   };
62
63   enum Control_flags
64   {
65     Ctl_set_pager       = 0x0010000,
66     Ctl_bind_task       = 0x0200000,
67     Ctl_alien_thread    = 0x0400000,
68     Ctl_ux_native       = 0x0800000,
69     Ctl_set_exc_handler = 0x1000000,
70   };
71
72   enum Ex_regs_flags
73   {
74     Exr_cancel            = 0x10000,
75     Exr_trigger_exception = 0x20000,
76   };
77
78   enum Vcpu_ctl_flags
79   {
80     Vcpu_ctl_extendet_vcpu = 0x10000,
81   };
82
83
84   class Dbg_stack
85   {
86   public:
87     enum { Stack_size = Config::PAGE_SIZE };
88     void *stack_top;
89     Dbg_stack();
90   };
91
92   static Per_cpu<Dbg_stack> dbg_stack;
93
94 public:
95   typedef void (Utcb_copy_func)(Thread *sender, Thread *receiver);
96
97   /**
98    * Constructor.
99    *
100    * @param task the task the thread should reside in.
101    * @param id user-visible thread ID of the sender.
102    * @param init_prio initial priority.
103    * @param mcp maximum controlled priority.
104    *
105    * @post state() != Thread_invalid.
106    */
107   Thread();
108
109   int handle_page_fault (Address pfa, Mword error, Mword pc,
110       Return_frame *regs);
111
112 private:
113   struct Migration_helper_info
114   {
115     Migration *inf;
116     Thread *victim;
117   };
118
119   Thread(const Thread&);        ///< Default copy constructor is undefined
120   void *operator new(size_t);   ///< Default new operator undefined
121
122   bool handle_sigma0_page_fault (Address pfa);
123
124   /**
125    * Return to user.
126    *
127    * This function is the default routine run if a newly
128    * initialized context is being switch_exec()'ed.
129    */
130   static void user_invoke();
131
132 public:
133   static bool pagein_tcb_request(Return_frame *regs);
134
135   inline Mword user_ip() const;
136   inline void user_ip(Mword);
137
138   inline Mword user_sp() const;
139   inline void user_sp(Mword);
140
141   inline Mword user_flags() const;
142
143   /** nesting level in debugger (always critical) if >1 */
144   static Per_cpu<unsigned long> nested_trap_recover;
145   static void handle_remote_requests_irq() asm ("handle_remote_cpu_requests");
146   static void handle_global_remote_requests_irq() asm ("ipi_remote_call");
147
148 protected:
149   explicit Thread(Context_mode_kernel);
150
151   // Another critical TCB cache line:
152   Thread_lock  _thread_lock;
153
154   // More ipc state
155   Thread_ptr _pager;
156   Thread_ptr _exc_handler;
157
158 protected:
159   Ram_quota *_quota;
160   Irq_base *_del_observer;
161
162   // debugging stuff
163   unsigned _magic;
164   static const unsigned magic = 0xf001c001;
165 };
166
167
168 IMPLEMENTATION:
169
170 #include <cassert>
171 #include <cstdlib>              // panic()
172 #include <cstring>
173 #include "atomic.h"
174 #include "entry_frame.h"
175 #include "fpu_alloc.h"
176 #include "globals.h"
177 #include "irq_chip.h"
178 #include "kdb_ke.h"
179 #include "kernel_task.h"
180 #include "kmem_alloc.h"
181 #include "logdefs.h"
182 #include "map_util.h"
183 #include "ram_quota.h"
184 #include "sched_context.h"
185 #include "space.h"
186 #include "std_macros.h"
187 #include "task.h"
188 #include "thread_state.h"
189 #include "timeout.h"
190
191 FIASCO_DEFINE_KOBJ(Thread);
192
193 DEFINE_PER_CPU Per_cpu<unsigned long> Thread::nested_trap_recover;
194
195
196 IMPLEMENT
197 Thread::Dbg_stack::Dbg_stack()
198 {
199   stack_top = Kmem_alloc::allocator()->unaligned_alloc(Stack_size); 
200   if (stack_top)
201     stack_top = (char *)stack_top + Stack_size;
202   //printf("JDB STACK start= %p - %p\n", (char *)stack_top - Stack_size, (char *)stack_top);
203 }
204
205
206 PUBLIC inline NEEDS[Thread::thread_lock]
207 void
208 Thread::kill_lock()
209 { thread_lock()->lock(); }
210
211
212 PUBLIC inline
213 void *
214 Thread::operator new(size_t, Ram_quota *q) throw ()
215 {
216   void *t = Kmem_alloc::allocator()->q_unaligned_alloc(q, Thread::Size);
217   if (t)
218     {
219       memset(t, 0, sizeof(Thread));
220       reinterpret_cast<Thread*>(t)->_quota = q;
221     }
222   return t;
223 }
224
225 PUBLIC
226 bool
227 Thread::bind(Task *t, User<Utcb>::Ptr utcb)
228 {
229   // _utcb == 0 for all kernel threads
230   Space::Ku_mem const *u = t->find_ku_mem(utcb, sizeof(Utcb));
231
232   // kernel thread?
233   if (EXPECT_FALSE(utcb && !u))
234     return false;
235
236   auto guard = lock_guard(_space.lock());
237   if (_space.space() != Kernel_task::kernel_task())
238     return false;
239
240   _space.space(t);
241   t->inc_ref();
242
243   if (u)
244     {
245       _utcb.set(utcb, u->kern_addr(utcb));
246       arch_setup_utcb_ptr();
247     }
248
249   return true;
250 }
251
252
253 PUBLIC inline NEEDS["kdb_ke.h", "kernel_task.h", "cpu_lock.h", "space.h"]
254 bool
255 Thread::unbind()
256 {
257   Task *old;
258
259     {
260       auto guard = lock_guard(_space.lock());
261
262       if (_space.space() == Kernel_task::kernel_task())
263         return true;
264
265       old = static_cast<Task*>(_space.space());
266       _space.space(Kernel_task::kernel_task());
267
268       // switch to a safe page table
269       if (Mem_space::current_mem_space(current_cpu()) == old)
270         Kernel_task::kernel_task()->switchin_context(old);
271
272       if (old->dec_ref())
273         old = 0;
274     }
275
276   if (old)
277     {
278       current()->rcu_wait();
279       delete old;
280     }
281
282   return true;
283 }
284
285 /** Cut-down version of Thread constructor; only for kernel threads
286     Do only what's necessary to get a kernel thread started --
287     skip all fancy stuff, no locking is necessary.
288     @param task the address space
289     @param id user-visible thread ID of the sender
290  */
291 IMPLEMENT inline
292 Thread::Thread(Context_mode_kernel)
293   : Receiver(), Sender(), _del_observer(0), _magic(magic)
294 {
295   *reinterpret_cast<void(**)()>(--_kernel_sp) = user_invoke;
296
297   inc_ref();
298   _space.space(Kernel_task::kernel_task());
299
300   if (Config::Stack_depth)
301     std::memset((char*)this + sizeof(Thread), '5',
302                 Thread::Size-sizeof(Thread)-64);
303 }
304
305
306 /** Destructor.  Reestablish the Context constructor's precondition.
307     @pre current() == thread_lock()->lock_owner()
308          && state() == Thread_dead
309     @pre lock_cnt() == 0
310     @post (_kernel_sp == 0)  &&  (* (stack end) == 0)  &&  !exists()
311  */
312 PUBLIC virtual
313 Thread::~Thread()               // To be called in locked state.
314 {
315
316   unsigned long *init_sp = reinterpret_cast<unsigned long*>
317     (reinterpret_cast<unsigned long>(this) + Size - sizeof(Entry_frame));
318
319
320   _kernel_sp = 0;
321   *--init_sp = 0;
322   Fpu_alloc::free_state(fpu_state());
323   _state = Thread_invalid;
324 }
325
326
327 // IPC-gate deletion stuff ------------------------------------
328
329 /**
330  * Fake IRQ Chip class for IPC-gate-delete notifications.
331  * This chip uses the IRQ number as thread pointer and implements
332  * the bind and unbind functionality.
333  */
334 class Del_irq_chip : public Irq_chip_soft
335 {
336 public:
337   static Del_irq_chip chip;
338 };
339
340 Del_irq_chip Del_irq_chip::chip;
341
342 PUBLIC static inline
343 Thread *Del_irq_chip::thread(Mword pin)
344 { return (Thread*)pin; }
345
346 PUBLIC static inline
347 Mword Del_irq_chip::pin(Thread *t)
348 { return (Mword)t; }
349
350 PUBLIC inline
351 void
352 Del_irq_chip::unbind(Irq_base *irq)
353 { thread(irq->pin())->remove_delete_irq(); }
354
355
356 PUBLIC inline NEEDS["irq_chip.h"]
357 void
358 Thread::ipc_gate_deleted(Mword id)
359 {
360   (void) id;
361   auto g = lock_guard(cpu_lock);
362   if (_del_observer)
363     _del_observer->hit(0);
364 }
365
366 PUBLIC
367 void
368 Thread::register_delete_irq(Irq_base *irq)
369 {
370   irq->unbind();
371   Del_irq_chip::chip.bind(irq, (Mword)this);
372   _del_observer = irq;
373 }
374
375 PUBLIC
376 void
377 Thread::remove_delete_irq()
378 {
379   if (!_del_observer)
380     return;
381
382   Irq_base *tmp = _del_observer;
383   _del_observer = 0;
384   tmp->unbind();
385 }
386
387 // end of: IPC-gate deletion stuff -------------------------------
388
389
390 /** Currently executing thread.
391     @return currently executing thread.
392  */
393 inline
394 Thread*
395 current_thread()
396 { return nonull_static_cast<Thread*>(current()); }
397
398 PUBLIC inline
399 bool
400 Thread::exception_triggered() const
401 { return _exc_cont.valid(); }
402
403 PUBLIC inline
404 bool
405 Thread::continuation_test_and_restore()
406 {
407   bool v = _exc_cont.valid();
408   if (v)
409     _exc_cont.restore(regs());
410   return v;
411 }
412
413 //
414 // state requests/manipulation
415 //
416
417
418 /** Thread lock.
419     Overwrite Context's version of thread_lock() with a semantically
420     equivalent, but more efficient version.
421     @return lock used to synchronize accesses to the thread.
422  */
423 PUBLIC inline
424 Thread_lock *
425 Thread::thread_lock()
426 { return &_thread_lock; }
427
428
429 PUBLIC inline NEEDS ["config.h", "timeout.h"]
430 void
431 Thread::handle_timer_interrupt()
432 {
433   unsigned _cpu = cpu(true);
434   // XXX: This assumes periodic timers (i.e. bogus in one-shot mode)
435   if (!Config::Fine_grained_cputime)
436     consume_time(Config::Scheduler_granularity);
437
438   bool resched = Rcu::do_pending_work(_cpu);
439
440   // Check if we need to reschedule due to timeouts or wakeups
441   if ((Timeout_q::timeout_queue.cpu(_cpu).do_timeouts() || resched)
442       && !Sched_context::rq.current().schedule_in_progress)
443     {
444       schedule();
445       assert (timeslice_timeout.cpu(cpu(true))->is_set());      // Coma check
446     }
447 }
448
449
450 PUBLIC
451 void
452 Thread::halt()
453 {
454   // Cancel must be cleared on all kernel entry paths. See slowtraps for
455   // why we delay doing it until here.
456   state_del(Thread_cancel);
457
458   // we haven't been re-initialized (cancel was not set) -- so sleep
459   if (state_change_safely(~Thread_ready, Thread_cancel | Thread_dead))
460     while (! (state() & Thread_ready))
461       schedule();
462 }
463
464 PUBLIC static
465 void
466 Thread::halt_current()
467 {
468   for (;;)
469     {
470       current_thread()->halt();
471       kdb_ke("Thread not halted");
472     }
473 }
474
475 PRIVATE static inline
476 void
477 Thread::user_invoke_generic()
478 {
479   Context *const c = current();
480   assert_kdb (c->state() & Thread_ready_mask);
481
482   if (c->handle_drq())
483     c->schedule();
484
485   // release CPU lock explicitly, because
486   // * the context that switched to us holds the CPU lock
487   // * we run on a newly-created stack without a CPU lock guard
488   cpu_lock.clear();
489 }
490
491
492 PRIVATE static void
493 Thread::leave_and_kill_myself()
494 {
495   current_thread()->do_kill();
496 #ifdef CONFIG_JDB
497   WARN("dead thread scheduled: %lx\n", current_thread()->dbg_id());
498 #endif
499   kdb_ke("DEAD SCHED");
500 }
501
502 PUBLIC static
503 unsigned
504 Thread::handle_kill_helper(Drq *src, Context *, void *)
505 {
506   delete nonull_static_cast<Thread*>(src->context());
507   return Drq::No_answer | Drq::Need_resched;
508 }
509
510
511 PRIVATE
512 bool
513 Thread::do_kill()
514 {
515   auto guard = lock_guard(thread_lock());
516
517   if (state() == Thread_invalid)
518     return false;
519
520   //
521   // Kill this thread
522   //
523
524   // But first prevent it from being woken up by asynchronous events
525
526   {
527     auto guard = lock_guard(cpu_lock);
528
529     // if IPC timeout active, reset it
530     if (_timeout)
531       _timeout->reset();
532
533     // Switch to time-sharing mode
534     set_mode(Sched_mode(0));
535
536     Sched_context::Ready_queue &rq = Sched_context::rq.current();
537
538     // Switch to time-sharing scheduling context
539     if (sched() != sched_context())
540       switch_sched(sched_context(), &rq);
541
542     if (!rq.current_sched() || rq.current_sched()->context() == this)
543       rq.set_current_sched(current()->sched());
544   }
545
546   // if other threads want to send me IPC messages, abort these
547   // operations
548   {
549     auto guard = lock_guard(cpu_lock);
550     while (Sender *s = Sender::cast(sender_list()->first()))
551       {
552         s->sender_dequeue(sender_list());
553         vcpu_update_state();
554         s->ipc_receiver_aborted();
555         Proc::preemption_point();
556       }
557   }
558
559   // if engaged in IPC operation, stop it
560   if (in_sender_list())
561     {
562       while (Locked_prio_list *q = wait_queue())
563         {
564           auto g = lock_guard(q->lock());
565           if (wait_queue() == q)
566             {
567               sender_dequeue(q);
568               set_wait_queue(0);
569               break;
570             }
571         }
572     }
573
574   Context::do_kill();
575
576   vcpu_update_state();
577
578   unbind();
579   vcpu_set_user_space(0);
580
581   cpu_lock.lock();
582
583   state_change_dirty(0, Thread_dead);
584
585   // dequeue from system queues
586   Sched_context::rq.current().ready_dequeue(sched());
587
588   if (_del_observer)
589     {
590       _del_observer->unbind();
591       _del_observer = 0;
592     }
593
594   if (dec_ref())
595     while (1)
596       {
597         state_del_dirty(Thread_ready_mask);
598         schedule();
599         WARN("woken up dead thread %lx\n", dbg_id());
600         kdb_ke("X");
601       }
602
603   rcu_wait();
604
605   state_del_dirty(Thread_ready_mask);
606
607   Sched_context::rq.current().ready_dequeue(sched());
608
609   kernel_context_drq(handle_kill_helper, 0);
610   kdb_ke("Im dead");
611   return true;
612 }
613
614 PRIVATE static
615 unsigned
616 Thread::handle_remote_kill(Drq *, Context *self, void *)
617 {
618   Thread *c = nonull_static_cast<Thread*>(self);
619   c->state_add_dirty(Thread_cancel | Thread_ready);
620   c->_exc_cont.restore(c->regs());
621   c->do_trigger_exception(c->regs(), (void*)&Thread::leave_and_kill_myself);
622   return 0;
623 }
624
625
626 PROTECTED
627 bool
628 Thread::kill()
629 {
630   auto guard = lock_guard(cpu_lock);
631   inc_ref();
632
633
634   if (cpu() == current_cpu())
635     {
636       state_add_dirty(Thread_cancel | Thread_ready);
637       Sched_context::rq.current().deblock(sched());
638       _exc_cont.restore(regs()); // overwrite an already triggered exception
639       do_trigger_exception(regs(), (void*)&Thread::leave_and_kill_myself);
640 //          current()->switch_exec (this, Helping);
641       return true;
642     }
643
644   drq(Thread::handle_remote_kill, 0, 0, Drq::Any_ctxt);
645
646   return true;
647 }
648
649
650 PUBLIC
651 void
652 Thread::set_sched_params(L4_sched_param const *p)
653 {
654   Sched_context *sc = sched_context();
655   // FIXME: do not know how to figure this out currently, however this
656   // seems to be just an optimization
657 #if 0
658   bool const change = prio != sc->prio()
659                    || quantum != sc->quantum();
660   bool const ready_queued = in_ready_list();
661
662   if (!change && (ready_queued || this == current()))
663     return;
664 #endif
665
666   Sched_context::Ready_queue &rq = Sched_context::rq.cpu(cpu());
667   rq.ready_dequeue(sched());
668
669   sc->set(p);
670   sc->replenish();
671
672   if (sc == rq.current_sched())
673     rq.set_current_sched(sc);
674
675   if (state() & Thread_ready_mask) // maybe we could ommit enqueueing current
676     rq.ready_enqueue(sched());
677 }
678
679 PUBLIC
680 long
681 Thread::control(Thread_ptr const &pager, Thread_ptr const &exc_handler)
682 {
683   if (pager.is_valid())
684     _pager = pager;
685
686   if (exc_handler.is_valid())
687     _exc_handler = exc_handler;
688
689   return 0;
690 }
691
692 // used by UX only
693 PUBLIC static inline
694 bool
695 Thread::is_tcb_address(Address a)
696 {
697   a &= ~(Thread::Size - 1);
698   return reinterpret_cast<Thread *>(a)->_magic == magic;
699 }
700
701 PUBLIC static inline
702 void
703 Thread::assert_irq_entry()
704 {
705   assert_kdb(Sched_context::rq.current().schedule_in_progress
706              || current_thread()->state() & (Thread_ready_mask | Thread_drq_wait | Thread_waiting | Thread_ipc_transfer));
707 }
708
709
710
711 // ---------------------------------------------------------------------------
712
713 PUBLIC inline
714 bool
715 Thread::check_sys_ipc(unsigned flags, Thread **partner, Thread **sender,
716                       bool *have_recv) const
717 {
718   if (flags & L4_obj_ref::Ipc_recv)
719     {
720       *sender = flags & L4_obj_ref::Ipc_open_wait ? 0 : const_cast<Thread*>(this);
721       *have_recv = true;
722     }
723
724   if (flags & L4_obj_ref::Ipc_send)
725     *partner = const_cast<Thread*>(this);
726
727   // FIXME: shall be removed flags == 0 is no-op
728   if (!flags)
729     {
730       *sender = const_cast<Thread*>(this);
731       *partner = const_cast<Thread*>(this);
732       *have_recv = true;
733     }
734
735   return *have_recv || ((flags & L4_obj_ref::Ipc_send) && *partner);
736 }
737
738 PUBLIC static
739 unsigned
740 Thread::handle_migration_helper(Drq *rq, Context *, void *p)
741 {
742   Migration *inf = reinterpret_cast<Migration *>(p);
743   Thread *v = static_cast<Thread*>(context_of(rq));
744   unsigned target_cpu = access_once(&inf->cpu);
745   v->migrate_away(inf, false);
746   v->migrate_to(target_cpu);
747   return Drq::Need_resched | Drq::No_answer;
748 }
749
750 PRIVATE inline
751 Thread::Migration *
752 Thread::start_migration()
753 {
754   assert_kdb(cpu_lock.test());
755   Migration *m = _migration;
756
757   assert (!((Mword)m & 0x3)); // ensure alignment
758
759   if (!m || !mp_cas(&_migration, m, (Migration*)0))
760     return reinterpret_cast<Migration*>(0x2); // bit one == 0 --> no need to reschedule
761
762   if (m->cpu == cpu())
763     {
764       set_sched_params(m->sp);
765       Mem::mp_mb();
766       write_now(&m->in_progress, true);
767       return reinterpret_cast<Migration*>(0x1); // bit one == 1 --> need to reschedule
768     }
769
770   return m; // need to do real migration
771 }
772
773 PRIVATE
774 bool
775 Thread::do_migration()
776 {
777   Migration *inf = start_migration();
778
779   if ((Mword)inf & 3)
780     return (Mword)inf & 1; // already migrated, nothing to do
781
782   spill_fpu_if_owner();
783
784   if (current() == this)
785     {
786       assert_kdb (current_cpu() == cpu());
787       kernel_context_drq(handle_migration_helper, inf);
788     }
789   else
790     {
791       unsigned target_cpu = access_once(&inf->cpu);
792       migrate_away(inf, false);
793       migrate_to(target_cpu);
794     }
795   return false; // we already are chosen by the scheduler...
796 }
797 PUBLIC
798 bool
799 Thread::initiate_migration()
800 {
801   assert (current() != this);
802   Migration *inf = start_migration();
803
804   if ((Mword)inf & 3)
805     return (Mword)inf & 1;
806
807   spill_fpu_if_owner();
808
809   unsigned target_cpu = access_once(&inf->cpu);
810   migrate_away(inf, false);
811   migrate_to(target_cpu);
812   return false;
813 }
814
815 PUBLIC
816 void
817 Thread::finish_migration()
818 { enqueue_timeout_again(); }
819
820
821
822
823 //---------------------------------------------------------------------------
824 IMPLEMENTATION [fpu && !ux]:
825
826 #include "fpu.h"
827 #include "fpu_alloc.h"
828 #include "fpu_state.h"
829
830
831 /*
832  * Handle FPU trap for this context. Assumes disabled interrupts
833  */
834 PUBLIC inline NEEDS ["fpu_alloc.h","fpu_state.h"]
835 int
836 Thread::switchin_fpu(bool alloc_new_fpu = true)
837 {
838   if (state() & Thread_vcpu_fpu_disabled)
839     return 0;
840
841   Fpu &f = Fpu::fpu.current();
842   // If we own the FPU, we should never be getting an "FPU unavailable" trap
843   assert_kdb (f.owner() != this);
844
845   // Allocate FPU state slab if we didn't already have one
846   if (!fpu_state()->state_buffer()
847       && (EXPECT_FALSE((!alloc_new_fpu
848                         || (state() & Thread_alien))
849                        || !Fpu_alloc::alloc_state(_quota, fpu_state()))))
850     return 0;
851
852   // Enable the FPU before accessing it, otherwise recursive trap
853   f.enable();
854
855   // Save the FPU state of the previous FPU owner (lazy) if applicable
856   if (f.owner())
857     nonull_static_cast<Thread*>(f.owner())->spill_fpu();
858
859   // Become FPU owner and restore own FPU state
860   f.restore_state(fpu_state());
861
862   state_add_dirty(Thread_fpu_owner);
863   f.set_owner(this);
864   return 1;
865 }
866
867 PUBLIC inline NEEDS["fpu.h", "fpu_alloc.h"]
868 void
869 Thread::transfer_fpu(Thread *to)
870 {
871   if (cpu() != to->cpu())
872     return;
873
874   if (to->fpu_state()->state_buffer())
875     Fpu_alloc::free_state(to->fpu_state());
876
877   to->fpu_state()->state_buffer(fpu_state()->state_buffer());
878   fpu_state()->state_buffer(0);
879
880   assert (current() == this || current() == to);
881
882   Fpu &f = Fpu::fpu.current();
883
884   f.disable(); // it will be reanabled in switch_fpu
885
886   if (EXPECT_FALSE(f.owner() == to))
887     {
888       assert_kdb (to->state() & Thread_fpu_owner);
889
890       f.set_owner(0);
891       to->state_del_dirty(Thread_fpu_owner);
892     }
893   else if (f.owner() == this)
894     {
895       assert_kdb (state() & Thread_fpu_owner);
896
897       state_del_dirty(Thread_fpu_owner);
898
899       to->state_add_dirty (Thread_fpu_owner);
900       f.set_owner(to);
901       if (EXPECT_FALSE(current() == to))
902         f.enable();
903     }
904 }
905
906 //---------------------------------------------------------------------------
907 IMPLEMENTATION [!fpu]:
908
909 PUBLIC inline
910 int
911 Thread::switchin_fpu(bool alloc_new_fpu = true)
912 {
913   (void)alloc_new_fpu;
914   return 0;
915 }
916
917 //---------------------------------------------------------------------------
918 IMPLEMENTATION [!fpu || ux]:
919
920 PUBLIC inline
921 void
922 Thread::transfer_fpu(Thread *)
923 {}
924
925 //---------------------------------------------------------------------------
926 IMPLEMENTATION [!log]:
927
928 PUBLIC inline
929 unsigned Thread::sys_ipc_log(Syscall_frame *)
930 { return 0; }
931
932 PUBLIC inline
933 unsigned Thread::sys_ipc_trace(Syscall_frame *)
934 { return 0; }
935
936 static inline
937 void Thread::page_fault_log(Address, unsigned, unsigned)
938 {}
939
940 PUBLIC static inline
941 int Thread::log_page_fault()
942 { return 0; }
943
944 PUBLIC inline
945 unsigned Thread::sys_fpage_unmap_log(Syscall_frame *)
946 { return 0; }
947
948
949 // ----------------------------------------------------------------------------
950 IMPLEMENTATION [!mp]:
951
952
953 PRIVATE inline
954 void
955 Thread::migrate_away(Migration *inf, bool /*remote*/)
956 {
957   assert_kdb (current() != this);
958   assert_kdb (cpu_lock.test());
959
960   unsigned cpu = inf->cpu;
961   //  LOG_MSG_3VAL(this, "MGi ", Mword(current()), (current_cpu() << 16) | cpu(), Context::current_sched());
962   if (_timeout)
963     _timeout->reset();
964
965   auto &rq = Sched_context::rq.current();
966
967   // if we are in the middle of the scheduler, leave it now
968   if (rq.schedule_in_progress == this)
969     rq.schedule_in_progress = 0;
970
971   rq.ready_dequeue(sched());
972
973     {
974       // Not sure if this can ever happen
975       Sched_context *csc = rq.current_sched();
976       if (!csc || csc->context() == this)
977         rq.set_current_sched(current()->sched());
978     }
979
980   Sched_context *sc = sched_context();
981   sc->set(inf->sp);
982   sc->replenish();
983   set_sched(sc);
984
985   set_cpu_of(this, cpu);
986   inf->in_progress = true;
987   _need_to_finish_migration = true;
988 }
989
990 PRIVATE inline
991 void
992 Thread::migrate_to(unsigned target_cpu)
993 {
994   if (!Cpu::online(target_cpu))
995     {
996       handle_drq();
997       return;
998     }
999
1000   auto &rq = Sched_context::rq.current();
1001   if (state() & Thread_ready_mask && !in_ready_list())
1002     rq.ready_enqueue(sched());
1003
1004   enqueue_timeout_again();
1005 }
1006
1007 PUBLIC
1008 void
1009 Thread::migrate(Migration *info)
1010 {
1011   assert_kdb (cpu_lock.test());
1012
1013   LOG_TRACE("Thread migration", "mig", this, Migration_log,
1014       l->state = state(false);
1015       l->src_cpu = cpu();
1016       l->target_cpu = info->cpu;
1017       l->user_ip = regs()->ip();
1018   );
1019
1020   _migration = info;
1021   current()->schedule_if(do_migration());
1022 }
1023
1024
1025 //----------------------------------------------------------------------------
1026 INTERFACE [debug]:
1027
1028 #include "tb_entry.h"
1029
1030 EXTENSION class Thread
1031 {
1032 protected:
1033   struct Migration_log : public Tb_entry
1034   {
1035     Mword    state;
1036     Address  user_ip;
1037     unsigned src_cpu;
1038     unsigned target_cpu;
1039
1040     unsigned print(int, char *) const;
1041   };
1042 };
1043
1044
1045 // ----------------------------------------------------------------------------
1046 IMPLEMENTATION [mp]:
1047
1048 #include "ipi.h"
1049
1050 PUBLIC
1051 void
1052 Thread::migrate(Migration *info)
1053 {
1054   assert_kdb (cpu_lock.test());
1055
1056   LOG_TRACE("Thread migration", "mig", this, Migration_log,
1057       l->state = state(false);
1058       l->src_cpu = cpu();
1059       l->target_cpu = info->cpu;
1060       l->user_ip = regs()->ip();
1061   );
1062     {
1063       Migration *old;
1064       do
1065         old = _migration;
1066       while (!mp_cas(&_migration, old, info));
1067       // flag old migration to be done / stale
1068       if (old)
1069         old->in_progress = true;
1070     }
1071
1072   unsigned cpu = this->cpu();
1073
1074   if (current_cpu() == cpu || Config::Max_num_cpus == 1)
1075     current()->schedule_if(do_migration());
1076   else
1077     migrate_xcpu(cpu);
1078
1079   cpu_lock.clear();
1080   // FIXME: use monitor & mwait or wfe & sev if available
1081   while (!access_once(&info->in_progress))
1082     Proc::pause();
1083   cpu_lock.lock();
1084
1085 }
1086
1087 IMPLEMENT
1088 void
1089 Thread::handle_remote_requests_irq()
1090 {
1091   assert_kdb (cpu_lock.test());
1092   // printf("CPU[%2u]: > RQ IPI (current=%p)\n", current_cpu(), current());
1093   Context *const c = current();
1094   Ipi::eoi(Ipi::Request, c->cpu());
1095   //LOG_MSG_3VAL(c, "ipi", c->cpu(), (Mword)c, c->drq_pending());
1096
1097   // we might have to migrate the currently running thread, and we cannot do
1098   // this during the processing of the request queue. In this case we get the
1099   // thread in migration_q and do this here.
1100   Context *migration_q = 0;
1101   bool resched = _pending_rqq.current().handle_requests(&migration_q);
1102
1103   resched |= Rcu::do_pending_work(c->cpu());
1104
1105   if (migration_q)
1106     resched |= static_cast<Thread*>(migration_q)->do_migration();
1107
1108   resched |= c->handle_drq();
1109   if (Sched_context::rq.current().schedule_in_progress)
1110     {
1111       if (c->state() & Thread_ready_mask)
1112         Sched_context::rq.current().ready_enqueue(c->sched());
1113     }
1114   else if (resched)
1115     c->schedule();
1116 }
1117
1118 IMPLEMENT
1119 void
1120 Thread::handle_global_remote_requests_irq()
1121 {
1122   assert_kdb (cpu_lock.test());
1123   // printf("CPU[%2u]: > RQ IPI (current=%p)\n", current_cpu(), current());
1124   Ipi::eoi(Ipi::Global_request, current_cpu());
1125   Context::handle_global_requests();
1126 }
1127
1128 PRIVATE inline
1129 void
1130 Thread::migrate_away(Migration *inf, bool remote)
1131 {
1132   assert_kdb (check_for_current_cpu());
1133   assert_kdb (current() != this);
1134   assert_kdb (cpu_lock.test());
1135
1136   if (_timeout)
1137     _timeout->reset();
1138
1139   //printf("[%u] %lx: m %lx %u -> %u\n", current_cpu(), current_thread()->dbg_id(), this->dbg_id(), cpu(), inf->cpu);
1140     {
1141       Sched_context::Ready_queue &rq = Sched_context::rq.cpu(cpu());
1142
1143       // if we are in the middle of the scheduler, leave it now
1144       if (rq.schedule_in_progress == this)
1145         rq.schedule_in_progress = 0;
1146
1147       rq.ready_dequeue(sched());
1148
1149       // Not sure if this can ever happen
1150       Sched_context *csc = rq.current_sched();
1151       if (!remote && (!csc || csc->context() == this))
1152         rq.set_current_sched(current()->sched());
1153     }
1154
1155   unsigned target_cpu = inf->cpu;
1156
1157     {
1158       Queue &q = _pending_rqq.cpu(cpu());
1159       // The queue lock of the current CPU protects the cpu number in
1160       // the thread
1161
1162       auto g = !remote
1163                ? lock_guard(q.q_lock())
1164                : Lock_guard<cxx::remove_pointer<decltype(q.q_lock())>::type>();
1165
1166       assert_kdb (q.q_lock()->test());
1167       // potentailly dequeue from our local queue
1168       if (_pending_rq.queued())
1169         check_kdb (q.dequeue(&_pending_rq, Queue_item::Ok));
1170
1171       Sched_context *sc = sched_context();
1172       sc->set(inf->sp);
1173       sc->replenish();
1174       set_sched(sc);
1175
1176       Mem::mp_wmb();
1177
1178       assert_kdb (!in_ready_list());
1179       assert_kdb (!_pending_rq.queued());
1180
1181       set_cpu_of(this, target_cpu);
1182       Mem::mp_mb();
1183       write_now(&inf->in_progress, true);
1184       _need_to_finish_migration = true;
1185     }
1186 }
1187
1188 PRIVATE inline
1189 void
1190 Thread::migrate_to(unsigned target_cpu)
1191 {
1192   bool ipi = false;
1193
1194     {
1195       Queue &q = _pending_rqq.cpu(target_cpu);
1196       auto g = lock_guard(q.q_lock());
1197
1198       if (access_once(&this->_cpu) == target_cpu
1199           && EXPECT_FALSE(!Cpu::online(target_cpu)))
1200         {
1201           handle_drq();
1202           return;
1203         }
1204
1205       // migrated meanwhile
1206       if (access_once(&this->_cpu) != target_cpu || _pending_rq.queued())
1207         return;
1208
1209       if (!_pending_rq.queued())
1210         {
1211           if (!q.first())
1212             ipi = true;
1213
1214           q.enqueue(&_pending_rq);
1215         }
1216       else
1217         assert_kdb (_pending_rq.queue() == &q);
1218     }
1219
1220   if (ipi)
1221     {
1222       //LOG_MSG_3VAL(this, "sipi", current_cpu(), cpu(), (Mword)current());
1223       Ipi::send(Ipi::Request, current_cpu(), target_cpu);
1224     }
1225 }
1226
1227 PRIVATE inline
1228 void
1229 Thread::migrate_xcpu(unsigned cpu)
1230 {
1231   bool ipi = false;
1232
1233     {
1234       Queue &q = Context::_pending_rqq.cpu(cpu);
1235       auto g = lock_guard(q.q_lock());
1236
1237       // already migrated
1238       if (cpu != access_once(&this->_cpu))
1239         return;
1240
1241       // now we are shure that this thread stays on 'cpu' because
1242       // we have the rqq lock of 'cpu'
1243       if (!Cpu::online(cpu))
1244         {
1245           Migration *inf = start_migration();
1246
1247           if ((Mword)inf & 3)
1248             return; // all done, nothing to do
1249
1250           unsigned target_cpu = access_once(&inf->cpu);
1251           migrate_away(inf, true);
1252           g.reset();
1253           migrate_to(target_cpu);
1254           return;
1255           // FIXME: Wie lange dauert es ready dequeue mit WFQ zu machen?
1256           // wird unter spinlock gemacht !!!!
1257         }
1258
1259       if (!_pending_rq.queued())
1260         {
1261           if (!q.first())
1262             ipi = true;
1263
1264           q.enqueue(&_pending_rq);
1265         }
1266     }
1267
1268   if (ipi)
1269     Ipi::send(Ipi::Request, current_cpu(), cpu);
1270   return;
1271 }
1272
1273 //----------------------------------------------------------------------------
1274 IMPLEMENTATION [debug]:
1275
1276 IMPLEMENT
1277 unsigned
1278 Thread::Migration_log::print(int maxlen, char *buf) const
1279 {
1280   return snprintf(buf, maxlen, "migrate from %u to %u (state=%lx user ip=%lx)",
1281       src_cpu, target_cpu, state, user_ip);
1282 }
1283