1
#include "internal.h"
2
3
bool sched_proc_snapshot(pid_t pid, sched_proc_snapshot_t *out) {
4
if (!out || pid < 0 || !sched_state.procs.all_list) {
5
return false;
6
}7
8
u64 hz = arch_timer_hz();
9
10
bool found = false;
11
unsigned long flags = sched_lock_save();
12
sched_thread_t *thread = pid_get(pid);
13
14
if (!thread) {
15
ll_foreach(node, sched_state.procs.all_list) {
16
sched_thread_t *candidate = node->data;
17
18
if (!candidate || candidate->pid != pid) {
19
continue;
20
}21
22
thread = candidate;
23
pid_set(thread);
24
25
break;
26
}27
}28
29
if (thread) {
30
out->pid = thread->pid;
31
out->ppid = thread->ppid;
32
out->pgid = thread->pgid;
33
out->sid = thread->sid;
34
out->uid = thread->uid;
35
out->gid = thread->gid;
36
out->umask = thread->umask & 0777;
37
out->signal_pending = __atomic_load_n(&thread->signal_pending, __ATOMIC_ACQUIRE);
38
out->signal_mask = __atomic_load_n(&thread->signal_mask, __ATOMIC_ACQUIRE);
39
out->state = thread_get_state(thread);
40
out->core_id = -1;
41
out->tty_index = thread->tty_index;
42
43
for (size_t i = 0; i < MAX_CORES; i++) {
44
if (sched_state.cpus.cpu[i].current == thread) {
45
out->core_id = (int)i;
46
break;
47
}48
}49
50
u64 cpu_ticks = __atomic_load_n(&thread->cpu_time_ticks, __ATOMIC_RELAXED);
51
u64 user_ticks = __atomic_load_n(&thread->user_ticks, __ATOMIC_RELAXED);
52
u64 sys_ticks = __atomic_load_n(&thread->sys_ticks, __ATOMIC_RELAXED);
53
54
u64 child_cpu_ticks = __atomic_load_n(&thread->child_cpu_time_ticks, __ATOMIC_RELAXED);
55
u64 child_user_ticks = __atomic_load_n(&thread->child_user_ticks, __ATOMIC_RELAXED);
56
u64 child_sys_ticks = __atomic_load_n(&thread->child_sys_ticks, __ATOMIC_RELAXED);
57
58
out->cpu_time_ms = hz ? ((cpu_ticks * 1000ULL) / hz) : 0;
59
out->user_time_ms = hz ? ((user_ticks * 1000ULL) / hz) : 0;
60
out->sys_time_ms = hz ? ((sys_ticks * 1000ULL) / hz) : 0;
61
62
out->child_cpu_time_ms = hz ? ((child_cpu_ticks * 1000ULL) / hz) : 0;
63
out->child_user_time_ms = hz ? ((child_user_ticks * 1000ULL) / hz) : 0;
64
out->child_sys_time_ms = hz ? ((child_sys_ticks * 1000ULL) / hz) : 0;
65
out->vm_kib = sched_user_mem_kib(thread);
66
67
memset(out->name, 0, sizeof(out->name));
68
strncpy(out->name, thread->name, sizeof(out->name) - 1);
69
70
found = true;
71
}72
73
sched_lock_restore(flags);
74
75
return found;
76
}77
78
void sched_cpu_usage_snapshot(u64 *busy_ticks_out, u64 *total_ticks_out) {
79
if (busy_ticks_out) {
80
*busy_ticks_out = __atomic_load_n(&sched_state.usage.busy_ticks, __ATOMIC_RELAXED);
81
}82
83
if (total_ticks_out) {
84
*total_ticks_out = __atomic_load_n(&sched_state.usage.total_ticks, __ATOMIC_RELAXED);
85
}86
}87
88
void sched_cpu_usage_snapshot_core(size_t core_id, u64 *busy_ticks_out, u64 *total_ticks_out) {
89
if (core_id >= MAX_CORES) {
90
if (busy_ticks_out) {
91
*busy_ticks_out = 0;
92
}93
94
if (total_ticks_out) {
95
*total_ticks_out = 0;
96
}97
98
return;
99
}100
101
if (busy_ticks_out) {
102
*busy_ticks_out = __atomic_load_n(&sched_state.usage.core_busy_ticks[core_id], __ATOMIC_RELAXED);
103
}104
105
if (total_ticks_out) {
106
*total_ticks_out = __atomic_load_n(&sched_state.usage.core_total_ticks[core_id], __ATOMIC_RELAXED);
107
}108
}109
110
void sched_metrics_snapshot(sched_metrics_snapshot_t *out) {
111
if (!out) {
112
return;
113
}114
115
out->sched_switch_count = __atomic_load_n(&sched_state.metrics.switch_count, __ATOMIC_RELAXED);
116
out->syscall_count = __atomic_load_n(&sched_state.metrics.syscall_count, __ATOMIC_RELAXED);
117
out->sched_migrations = __atomic_load_n(&sched_state.metrics.migrations, __ATOMIC_RELAXED);
118
out->sched_steals = __atomic_load_n(&sched_state.metrics.steals, __ATOMIC_RELAXED);
119
out->sched_wake_ipi = __atomic_load_n(&sched_state.metrics.wake_ipi, __ATOMIC_RELAXED);
120
out->sched_runqueue_max = __atomic_load_n(&sched_state.metrics.runqueue_max, __ATOMIC_RELAXED);
121
out->sched_balance_runs = __atomic_load_n(&sched_state.metrics.balance_runs, __ATOMIC_RELAXED);
122
out->wait_timeout_count = __atomic_load_n(&sched_state.metrics.wait_timeout_count, __ATOMIC_RELAXED);
123
}124
125
void sched_metrics_record_syscall(void) {
126
__atomic_fetch_add(&sched_state.metrics.syscall_count, 1, __ATOMIC_RELAXED);
127
}128
129
int sched_getgroups_pid(
130
pid_t pid,
131
gid_t *primary_gid_out,
132
gid_t *groups_out,
133
size_t max_groups,
134
size_t *group_count_out
135
) {
136
if (pid <= 0 || !group_count_out || !sched_state.procs.all_list) {
137
return -EINVAL;
138
}139
140
unsigned long flags = sched_lock_save();
141
sched_thread_t *thread = find_thread(pid);
142
143
if (!thread) {
144
sched_lock_restore(flags);
145
return -ESRCH;
146
}147
148
if (primary_gid_out) {
149
*primary_gid_out = thread->gid;
150
}151
152
*group_count_out = thread->group_count;
153
154
if (groups_out && max_groups) {
155
size_t copy_count = thread->group_count < max_groups ? thread->group_count : max_groups;
156
157
for (size_t i = 0; i < copy_count; i++) {
158
groups_out[i] = thread->groups[i];
159
}160
}161
162
sched_lock_restore(flags);
163
164
return 0;
165
}166
167
bool sched_proc_cwd(pid_t pid, char *out, size_t out_len) {
168
if (!out || !out_len || pid <= 0 || !sched_state.procs.all_list) {
169
return false;
170
}171
172
bool found = false;
173
unsigned long flags = sched_lock_save();
174
sched_thread_t *thread = find_thread(pid);
175
176
if (thread) {
177
size_t len = strnlen(thread->cwd, sizeof(thread->cwd));
178
179
if (len + 1 <= out_len) {
180
memcpy(out, thread->cwd, len);
181
out[len] = '\0';
182
found = true;
183
}184
}185
186
sched_lock_restore(flags);
187
188
return found;
189
}190
191
int sched_signal_send_pgrp(pid_t pgid, int signum) {
192
if (!sched_state.procs.all_list || pgid <= 0) {
193
return -1;
194
}195
196
int count = 0;
197
unsigned long flags = sched_lock_save();
198
199
ll_foreach(node, sched_state.procs.all_list) {
200
sched_thread_t *thread = node->data;
201
202
if (!thread || thread->pgid != pgid) {
203
continue;
204
}205
206
if (sched_signal_send_thread(thread, signum) >= 0) {
207
count++;
208
}209
}210
211
sched_lock_restore(flags);
212
213
return count ? count : -1;
214
}215
216
int sched_signal_pgrp_as(pid_t pgid, int signum, const sched_thread_t *sender) {
217
if (!sched_state.procs.all_list || pgid <= 0) {
218
return -ESRCH;
219
}220
221
if (signum < 0 || signum >= NSIG) {
222
return -EINVAL;
223
}224
225
uid_t uid = sender ? sender->uid : 0;
226
bool root = uid == 0;
227
bool denied = false;
228
int count = 0;
229
230
unsigned long flags = sched_lock_save();
231
232
ll_foreach(node, sched_state.procs.all_list) {
233
sched_thread_t *thread = node->data;
234
235
if (!thread || thread->pgid != pgid) {
236
continue;
237
}238
239
if (!root && uid != thread->uid) {
240
denied = true;
241
continue;
242
}243
244
if (!signum || sched_signal_send_thread(thread, signum) >= 0) {
245
count++;
246
}247
}248
249
sched_lock_restore(flags);
250
251
if (count) {
252
return count;
253
}254
255
return denied ? -EPERM : -ESRCH;
256
}