]>
Commit | Line | Data |
---|---|---|
bd6521f0 A |
1 | // |
2 | // MachineThread.hpp | |
3 | // KDBG | |
4 | // | |
5 | // Created by James McIlree on 10/26/12. | |
6 | // Copyright (c) 2014 Apple. All rights reserved. | |
7 | // | |
8 | ||
9 | template <typename SIZE> class MachineProcess; | |
10 | ||
11 | enum class kMachineThreadFlag : std::uint32_t { | |
12 | CreatedByPreviousMachineState = 0x00000001, | |
13 | CreatedByThreadMap = 0x00000002, | |
14 | CreatedByTraceDataNewThread = 0x00000004, | |
15 | CreatedByUnknownTidInTrace = 0x00000008, | |
16 | CreatedByForkExecEvent = 0x00000010, | |
17 | CreatedByExecEvent = 0x00000020, | |
18 | IsMain = 0x00000040, | |
19 | IsIdle = 0x00000080, | |
20 | TraceTerminated = 0x00000200, // Set when a MACH_THREAD_TERMINATED is seen. This is definitive, no further trace events should reference this thread. | |
21 | }; | |
22 | ||
23 | template <typename SIZE> class Machine; | |
24 | template <typename SIZE> class JetsamActivity; | |
25 | template <typename SIZE> class MachineVoucher; | |
26 | ||
27 | template <typename SIZE> | |
28 | class MachineThread { | |
29 | protected: | |
30 | uint32_t _flags; | |
31 | typename SIZE::ptr_t _tid; // We're unlikely to ever look at K64 on a 32 bit machine, put this here as best chance to not increase struct size with useless padding bytes. | |
32 | MachineProcess<SIZE>* _process; | |
33 | AbsInterval _timespan; | |
34 | AbsTime _begin_blocked; | |
35 | AbsTime _begin_vm_fault; | |
36 | AbsTime _begin_jetsam_activity; | |
37 | uint32_t _begin_jetsam_activity_type; | |
38 | std::vector<AbsInterval> _blocked; | |
39 | std::vector<AbsInterval> _vm_faults; | |
40 | std::vector<AbsInterval> _jetsam_activity; | |
41 | std::vector<VoucherInterval<SIZE>> _vouchers_by_time; | |
42 | ||
43 | // | |
44 | // Mutable API | |
45 | // | |
46 | friend class Machine<SIZE>; | |
47 | friend class MachineProcess<SIZE>; | |
48 | ||
49 | MachineProcess<SIZE>& mutable_process() { return *_process; } | |
50 | ||
51 | void set_flags(kMachineThreadFlag flags) { _flags |= (uint32_t)flags; } | |
52 | void clear_flags(kMachineThreadFlag flags) { _flags &= ~(uint32_t)flags; } | |
53 | bool is_flag_set(kMachineThreadFlag flag) const { return (_flags & (uint32_t)flag) > 0; } | |
54 | ||
55 | // This can be discovered after the thread is created. | |
56 | void set_is_idle_thread(); | |
57 | void set_trace_terminated(AbsTime timestamp); | |
58 | ||
59 | void set_voucher(MachineVoucher<SIZE>* voucher, AbsTime timestamp); | |
60 | ||
61 | // | |
62 | // NOTE! Unrunnable/blocked isn't quite exact; it doesn't match | |
63 | // the scheduler view of unrunnable/blocked. | |
64 | // | |
65 | // 1) If you're not blocked, you're runnable | |
66 | // 2) A thread is considered "blocked" if the cpu it is on goes idle. | |
67 | // | |
68 | void make_runnable(AbsTime timestamp); | |
69 | void make_unrunnable(AbsTime timestamp); | |
70 | ||
71 | void begin_vm_fault(AbsTime timestamp); | |
72 | void end_vm_fault(AbsTime timestamp); | |
73 | ||
74 | void begin_jetsam_activity(uint32_t type, AbsTime timestamp); | |
75 | void end_jetsam_activity(uint32_t type, AbsTime timestamp); | |
76 | ||
77 | void add_io_activity(AbsInterval interval, uint32_t code, uint32_t page_count); | |
78 | ||
79 | AbsTime blocked_in_timespan(AbsInterval timespan) const; | |
80 | AbsTime next_blocked_after(AbsTime timestamp) const; | |
81 | ||
82 | // This is called after all events have been processed, to flush any pending state | |
83 | void post_initialize(AbsTime last_machine_timestamp); | |
84 | ||
85 | public: | |
86 | MachineThread(MachineProcess<SIZE>* process, typename SIZE::ptr_t tid, MachineVoucher<SIZE>* initial_voucher, AbsTime create_timestamp, kMachineThreadFlag flags) : | |
87 | _flags((uint32_t)flags), | |
88 | _tid(tid), | |
89 | _process(process), | |
90 | _timespan(create_timestamp, AbsTime(0)), | |
91 | _begin_jetsam_activity_type(0) | |
92 | { | |
93 | ASSERT(_tid != 0, "Sanity"); | |
94 | ASSERT(_process, "Sanity"); | |
95 | ASSERT(initial_voucher, "Sanity"); | |
96 | ||
97 | _vouchers_by_time.emplace_back(initial_voucher, AbsInterval(create_timestamp, AbsTime::END_OF_TIME - create_timestamp)); | |
98 | } | |
99 | ||
100 | typename SIZE::ptr_t tid() const { return _tid; } | |
101 | AbsInterval timespan() const { return _timespan; } | |
102 | const MachineProcess<SIZE>& process() const { return *_process; } | |
103 | uint32_t flags() const { return _flags; } | |
104 | ||
105 | const MachineVoucher<SIZE>* voucher(AbsTime timestamp) const; | |
106 | const MachineVoucher<SIZE>* last_voucher() const; | |
107 | ||
108 | const std::vector<AbsInterval>& vm_faults() const { return _vm_faults; } | |
109 | const std::vector<AbsInterval>& jetsam_activity() const { return _jetsam_activity; } | |
110 | ||
111 | bool is_created_by_previous_machine_state() const { return is_flag_set(kMachineThreadFlag::CreatedByPreviousMachineState); } | |
112 | bool is_created_by_thread_map() const { return is_flag_set(kMachineThreadFlag::CreatedByThreadMap); } | |
113 | bool is_created_by_trace_data_new_thread() const { return is_flag_set(kMachineThreadFlag::CreatedByTraceDataNewThread); } | |
114 | bool is_created_by_unknown_tid_in_trace() const { return is_flag_set(kMachineThreadFlag::CreatedByUnknownTidInTrace); } | |
115 | bool is_created_by_fork_exec() const { return is_flag_set(kMachineThreadFlag::CreatedByForkExecEvent); } | |
116 | bool is_created_by_exec() const { return is_flag_set(kMachineThreadFlag::CreatedByExecEvent); } | |
117 | ||
118 | bool is_idle_thread() const { return is_flag_set(kMachineThreadFlag::IsIdle); } | |
119 | bool is_main_thread() const { return is_flag_set(kMachineThreadFlag::IsMain); } | |
120 | ||
121 | bool is_trace_terminated() const { return is_flag_set(kMachineThreadFlag::TraceTerminated); } | |
122 | ||
123 | DEBUG_ONLY(void validate() const;) | |
124 | }; |