GCC Code Coverage Report


Directory: src/
File: src/LB_comm/shmem_procinfo.c
Date: 2024-11-22 17:07:10
Exec Total Coverage
Lines: 530 691 76.7%
Functions: 29 40 72.5%
Branches: 395 558 70.8%

Line Branch Exec Source
1 /*********************************************************************************/
2 /* Copyright 2009-2021 Barcelona Supercomputing Center */
3 /* */
4 /* This file is part of the DLB library. */
5 /* */
6 /* DLB is free software: you can redistribute it and/or modify */
7 /* it under the terms of the GNU Lesser General Public License as published by */
8 /* the Free Software Foundation, either version 3 of the License, or */
9 /* (at your option) any later version. */
10 /* */
11 /* DLB is distributed in the hope that it will be useful, */
12 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14 /* GNU Lesser General Public License for more details. */
15 /* */
16 /* You should have received a copy of the GNU Lesser General Public License */
17 /* along with DLB. If not, see <https://www.gnu.org/licenses/>. */
18 /*********************************************************************************/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include "LB_comm/shmem_procinfo.h"
25
26 #include "LB_comm/shmem.h"
27 #include "LB_numThreads/numThreads.h"
28 #include "apis/dlb_errors.h"
29 #include "support/atomic.h"
30 #include "support/debug.h"
31 #include "support/types.h"
32 #include "support/mytime.h"
33 #include "support/mask_utils.h"
34 #include "LB_core/spd.h"
35
36 #include <sched.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <pthread.h>
40 #include <sys/types.h>
41 #include <sys/resource.h>
42
43 enum { NOBODY = 0 };
44 enum { SYNC_POLL_DELAY = 10000 }; /* 10^4 ns = 10 ms */
45 enum { SYNC_POLL_TIMEOUT = 1000000000 }; /* 10^9 ns = 1s */
46
47
48 typedef struct DLB_ALIGN_CACHE pinfo_t {
49 pid_t pid;
50 bool dirty;
51 bool preregistered;
52 cpu_set_t current_process_mask;
53 cpu_set_t future_process_mask;
54 cpu_set_t stolen_cpus;
55 unsigned int active_cpus;
56 // Cpu Usage fields:
57 double cpu_usage;
58 double cpu_avg_usage;
59 #ifdef DLB_LOAD_AVERAGE
60 // Load average fields:
61 float load[3]; // 1min, 5min, 15mins
62 struct timespec last_ltime; // Last time that Load was updated
63 #endif
64 } pinfo_t;
65
66 typedef struct procinfo_flags {
67 bool initialized:1;
68 bool allow_cpu_sharing:1; // efectively, disables DROM functionalities
69 bool cpu_sharing_unknown:1; // set when flag is not not during initialization
70 } procinfo_flags_t;
71
72 typedef struct {
73 procinfo_flags_t flags;
74 struct timespec initial_time;
75 cpu_set_t free_mask; // Contains the CPUs in the system not owned
76 pinfo_t process_info[];
77 } shdata_t;
78
79 enum { SHMEM_PROCINFO_VERSION = 9 };
80
81 static shmem_handler_t *shm_handler = NULL;
82 static shdata_t *shdata = NULL;
83 static int max_cpus;
84 static int max_processes;
85 //static struct timespec last_ttime; // Total time
86 //static struct timespec last_utime; // Useful time (user+system)
87 static const char *shmem_name = "procinfo";
88 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
89 static int subprocesses_attached = 0;
90 static pinfo_t *my_pinfo = NULL;
91
92 static int set_new_mask(pinfo_t *process, const cpu_set_t *mask, bool sync,
93 bool return_stolen, cpu_set_t *free_cpu_mask);
94 static void close_shmem(void);
95
96 13 static pid_t get_parent_pid(pid_t pid) {
97 13 pid_t parent_pid = 0;
98 enum { BUF_LEN = 128 };
99 char buf[BUF_LEN];
100 enum { PID_FILE_MAX_LEN = 32 };
101 char pid_status_filename[PID_FILE_MAX_LEN];
102 13 snprintf(pid_status_filename, PID_FILE_MAX_LEN, "/proc/%d/status", pid);
103 13 FILE *fd = fopen(pid_status_filename, "r");
104
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
13 if (fd != NULL) {
105
2/2
✓ Branch 1 taken 420 times.
✓ Branch 2 taken 7 times.
427 while(fgets(buf, BUF_LEN, fd) != NULL) {
106 420 char *substring = strstr(buf, "PPid:");
107
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 413 times.
420 if (substring != NULL) {
108 7 substring += strlen("PPid:");
109 7 long ppid = strtol(substring, NULL, 10);
110
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (ppid > 0) {
111 parent_pid = ppid;
112 break;
113 }
114 }
115 }
116 7 fclose(fd);
117 }
118 13 return parent_pid;
119 }
120
121 208 static pinfo_t* get_process(pid_t pid) {
122
1/2
✓ Branch 0 taken 208 times.
✗ Branch 1 not taken.
208 if (shdata) {
123 /* Check first if pid is this process */
124
2/2
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 69 times.
208 if (my_pinfo != NULL
125
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 82 times.
139 && my_pinfo->pid == pid) {
126 57 return my_pinfo;
127 }
128
129 /* Iterate otherwise */
130 int p;
131
2/2
✓ Branch 0 taken 364 times.
✓ Branch 1 taken 13 times.
377 for (p = 0; p < max_processes; p++) {
132
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 226 times.
364 if (shdata->process_info[p].pid == pid) {
133 138 return &shdata->process_info[p];
134 }
135 }
136
137 /* Try parent PID */
138 13 pid_t parent_pid = get_parent_pid(pid);
139
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (parent_pid > 0) {
140 return get_process(parent_pid);
141 }
142 }
143 13 return NULL;
144 }
145
146 /*********************************************************************************/
147 /* Init / Register */
148 /*********************************************************************************/
149
150 /* This function may be called from shmem_init to cleanup pid */
151 1 static void cleanup_shmem(void *shdata_ptr, int pid) {
152 1 bool shmem_empty = true;
153 1 shdata_t *shared_data = shdata_ptr;
154 int p;
155
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 for (p = 0; p < max_processes; p++) {
156 8 pinfo_t *process = &shared_data->process_info[p];
157
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 if (process->pid == pid) {
158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (process->dirty) {
159 CPU_OR(&shared_data->free_mask, &shared_data->free_mask,
160 &process->future_process_mask);
161 } else {
162
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 times.
17 CPU_OR(&shared_data->free_mask, &shared_data->free_mask,
163 &process->current_process_mask);
164 }
165 1 *process = (const pinfo_t){0};
166
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 } else if (process->pid > 0) {
167 shmem_empty = false;
168 }
169 }
170
171 /* If there are no registered processes, make sure shmem is reset */
172
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (shmem_empty) {
173 1 memset(shared_data, 0, shmem_procinfo__size());
174 }
175 1 }
176
177 78 static bool is_shmem_empty(void) {
178 int p;
179
2/2
✓ Branch 0 taken 688 times.
✓ Branch 1 taken 62 times.
750 for (p = 0; p < max_processes; p++) {
180
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 672 times.
688 if (shdata->process_info[p].pid != NOBODY) {
181 16 return false;
182 }
183 }
184 62 return true;
185 }
186
187 150 static void open_shmem(const char *shmem_key) {
188 150 pthread_mutex_lock(&mutex);
189 {
190
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 72 times.
150 if (shm_handler == NULL) {
191 // We assume no more processes than CPUs
192 78 max_cpus = mu_get_system_size();
193 78 max_processes = max_cpus;
194
195 156 shm_handler = shmem_init((void**)&shdata,
196 78 &(const shmem_props_t) {
197 78 .size = shmem_procinfo__size(),
198 .name = shmem_name,
199 .key = shmem_key,
200 .version = SHMEM_PROCINFO_VERSION,
201 .cleanup_fn = cleanup_shmem,
202 });
203 78 subprocesses_attached = 1;
204 } else {
205 72 ++subprocesses_attached;
206 }
207 }
208 150 pthread_mutex_unlock(&mutex);
209 150 }
210
211 // Register a new set of CPUs. Remove them from the free_mask and assign them to new_owner if ok
212 131 static int register_mask(pinfo_t *new_owner, const cpu_set_t *mask) {
213 // Return if empty mask
214
2/2
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 100 times.
131 if (CPU_COUNT(mask) == 0) return DLB_SUCCESS;
215
216 // Return if sharing is allowed and, thus, we don't need to check CPU overlapping
217
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 91 times.
100 if (shdata->flags.allow_cpu_sharing) {
218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 verbose(VB_DROM, "Process %d registering shared mask %s", new_owner->pid, mu_to_str(mask));
219 9 return DLB_SUCCESS;
220 }
221
222
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 82 times.
91 verbose(VB_DROM, "Process %d registering mask %s", new_owner->pid, mu_to_str(mask));
223 91 int error = DLB_SUCCESS;
224
2/2
✓ Branch 1 taken 86 times.
✓ Branch 2 taken 5 times.
91 if (mu_is_subset(mask, &shdata->free_mask)) {
225 86 mu_substract(&shdata->free_mask, &shdata->free_mask, mask);
226
2/2
✓ Branch 0 taken 1376 times.
✓ Branch 1 taken 86 times.
1462 CPU_OR(&new_owner->future_process_mask, &new_owner->future_process_mask, mask);
227 86 mu_substract(&new_owner->stolen_cpus, &new_owner->stolen_cpus, mask);
228 86 new_owner->dirty = true;
229 } else {
230 cpu_set_t wrong_cpus;
231 5 mu_substract(&wrong_cpus, mask, &shdata->free_mask);
232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 verbose(VB_SHMEM, "Error registering CPUs: %s, already belong to other processes",
233 mu_to_str(&wrong_cpus));
234 5 error = DLB_ERR_PERM;
235 }
236 91 return error;
237 }
238
239 107 static int shmem_procinfo__init_(pid_t pid, pid_t preinit_pid, const cpu_set_t *process_mask,
240 cpu_set_t *new_process_mask, const char *shmem_key, bool allow_cpu_sharing) {
241 107 int error = DLB_SUCCESS;
242
243 // Shared memory creation
244 107 open_shmem(shmem_key);
245
246 107 pinfo_t *process = NULL;
247 107 shmem_lock(shm_handler);
248 {
249 // Initialize some values if this is the 1st process attached to the shmem
250
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 70 times.
107 if (!shdata->flags.initialized) {
251 37 shdata->flags = (const procinfo_flags_t) {
252 .initialized = true,
253 .allow_cpu_sharing = allow_cpu_sharing,
254 };
255 37 get_time(&shdata->initial_time);
256 37 mu_get_system_mask(&shdata->free_mask);
257
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 62 times.
70 } else if (shdata->flags.cpu_sharing_unknown) {
258 /* Already initialized but cpu_sharing unknown, probably due to
259 * initiazing the shared memory via shmem_procinfo_ext__init */
260 8 shdata->flags.allow_cpu_sharing = allow_cpu_sharing;
261 8 shdata->flags.cpu_sharing_unknown = false;
262
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 59 times.
62 } else if (shdata->flags.allow_cpu_sharing != allow_cpu_sharing) {
263 // For now we require all processes registering the procinfo
264 // to have the same value in 'allow_cpu_sharing'
265 3 error = DLB_ERR_NOCOMP;
266 }
267
268 // Iterate the processes array to find the two potential pointers:
269 107 pinfo_t *empty_spot = NULL;
270 107 pinfo_t *preinit_process = NULL;
271 int p;
272
4/4
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 259 times.
✓ Branch 3 taken 5 times.
268 for (p = 0; p < max_processes && error >= DLB_SUCCESS; p++) {
273
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 2 times.
259 if (empty_spot == NULL
274
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 158 times.
257 && shdata->process_info[p].pid == NOBODY) {
275 /* First empty spot */
276 99 empty_spot = &shdata->process_info[p];
277 }
278
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 125 times.
160 else if (preinit_pid != 0
279
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 10 times.
35 && preinit_process == NULL
280
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 5 times.
25 && shdata->process_info[p].pid == preinit_pid) {
281 /* This is the preregistered process */
282 20 preinit_process = &shdata->process_info[p];
283
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 1 times.
20 if (preinit_process->preregistered) {
284 19 error = DLB_NOTED;
285 } else {
286 // The process matches the preinit_pid but it's
287 // not flagged as preregistered
288 1 error = DLB_ERR_INIT;
289 }
290 }
291
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 139 times.
140 else if (shdata->process_info[p].pid == pid) {
292 /* This process is already registered */
293 1 error = DLB_ERR_INIT;
294 }
295
2/2
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 158 times.
259 if (empty_spot
296
6/6
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 80 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 80 times.
101 && ((preinit_pid && preinit_process) || !preinit_pid)) {
297 /* Everything needed is found */
298 break;
299 }
300 }
301
302 // If it's a new process, initialize structure
303
6/6
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 86 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 83 times.
✓ Branch 5 taken 4 times.
107 if ((preinit_pid == 0 || preinit_process == NULL) && !error) {
304
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 81 times.
83 if (empty_spot == NULL) {
305 2 error = DLB_ERR_NOMEM;
306 }
307 else {
308 81 process = empty_spot;
309 81 *process = (const pinfo_t) {.pid = pid};
310 81 error = register_mask(process, process_mask);
311
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 3 times.
81 if (error == DLB_SUCCESS) {
312 78 memcpy(&process->current_process_mask, process_mask, sizeof(cpu_set_t));
313 78 memcpy(&process->future_process_mask, process_mask, sizeof(cpu_set_t));
314 78 process->dirty = false; /* register_mask sets dirty flag, undo */
315 } else {
316 // Revert process registration if mask registration failed
317 3 process->pid = NOBODY;
318 }
319 }
320 }
321
322 // Pre-registered process, check if the spot is inherited or initialize a new one
323
4/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 1 times.
43 else if(preinit_process && error == DLB_NOTED) {
324 38 cpu_set_t *preinit_mask = preinit_process->dirty
325 ? &preinit_process->future_process_mask
326
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 18 times.
19 : &preinit_process->current_process_mask;
327
328 // A: Simple inheritance, mask is not provided, or masks are equal
329
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 2 times.
19 if (process_mask == NULL
330
2/2
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 2 times.
17 || CPU_COUNT(process_mask) == 0
331
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 10 times.
15 || CPU_EQUAL(process_mask, preinit_mask)) {
332 9 process = preinit_process;
333 9 process->pid = pid;
334 9 process->preregistered = false;
335 }
336
337 // B: Inheritance + expansion
338
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 7 times.
10 else if (mu_is_proper_superset(process_mask, preinit_mask)) {
339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (preinit_process->dirty) {
340 // This case does not allow a dirty process
341 error = DLB_ERR_PDIRTY;
342 } else {
343 // Register the new CPUs in a placeholder process
344 pinfo_t new_process;
345 cpu_set_t new_cpus;
346 3 CPU_ZERO(&new_cpus);
347 3 mu_substract(&new_cpus, process_mask, preinit_mask);
348 3 int register_error = register_mask(&new_process, &new_cpus);
349
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (register_error == DLB_SUCCESS) {
350 // Inherit and merge CPUs
351 2 process = preinit_process;
352 2 process->pid = pid;
353 2 process->preregistered = false;
354 2 memcpy(&process->current_process_mask, process_mask, sizeof(cpu_set_t));
355 2 memcpy(&process->future_process_mask, process_mask, sizeof(cpu_set_t));
356 } else {
357 1 error = DLB_ERR_PERM;
358 }
359 }
360 }
361
362 // C: New spot, subset
363
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
7 else if (mu_is_proper_subset(process_mask, preinit_mask)) {
364
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (preinit_process->dirty) {
365 // This case does not allow a dirty process
366 error = DLB_ERR_PDIRTY;
367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 } else if (empty_spot == NULL) {
368 error = DLB_ERR_NOMEM;
369 } else {
370 /* Initialize new spot with inherited CPUs */
371 cpu_set_t inherited_cpus;
372
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 6 times.
102 CPU_AND(&inherited_cpus, preinit_mask, process_mask);
373 6 process = empty_spot;
374 6 *process = (const pinfo_t) {.pid = pid};
375 6 memcpy(&process->current_process_mask, &inherited_cpus, sizeof(cpu_set_t));
376 6 memcpy(&process->future_process_mask, &inherited_cpus, sizeof(cpu_set_t));
377 /* Remove inherited CPUs from preregistered process */
378 6 mu_substract(&preinit_process->current_process_mask,
379 6 &preinit_process->current_process_mask, &inherited_cpus);
380 6 mu_substract(&preinit_process->future_process_mask,
381 6 &preinit_process->future_process_mask, &inherited_cpus);
382 }
383 }
384
385 // D: New spot + expansion
386 else {
387
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (preinit_process->dirty) {
388 // This case does not allow a dirty process
389 error = DLB_ERR_PDIRTY;
390
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 } else if (empty_spot == NULL) {
391 error = DLB_ERR_NOMEM;
392 } else {
393 // Register the new CPUs in a placeholder process
394 pinfo_t new_process;
395 cpu_set_t new_cpus;
396 1 CPU_ZERO(&new_cpus);
397 1 mu_substract(&new_cpus, process_mask, preinit_mask);
398 1 int register_error = register_mask(&new_process, &new_cpus);
399
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (register_error == DLB_SUCCESS) {
400 /* Initialize new spot with the mask provided */
401 1 process = empty_spot;
402 1 process->pid = pid;
403 1 process->preregistered = false;
404 1 memcpy(&process->current_process_mask, process_mask, sizeof(cpu_set_t));
405 1 memcpy(&process->future_process_mask, process_mask, sizeof(cpu_set_t));
406 /* Remove inherited CPUs from preregistered process */
407 1 mu_substract(&preinit_process->current_process_mask,
408 1 &preinit_process->current_process_mask, process_mask);
409 1 mu_substract(&preinit_process->future_process_mask,
410 1 &preinit_process->future_process_mask, process_mask);
411 } else {
412 error = DLB_ERR_PERM;
413 }
414 }
415 }
416
417
3/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
19 if (error == DLB_NOTED && new_process_mask) {
418 // If the process has correctly inherit all/some of the CPUs,
419 // update the output mask with the appropriate CPU mask
420 // we cannot resolve the dirty flag yet
421 18 memcpy(new_process_mask,
422
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17 times.
18 process->dirty ? &process->future_process_mask
423 : &process->current_process_mask,
424 sizeof(cpu_set_t));
425 }
426 }
427
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
5 else if (error != DLB_ERR_INIT && error != DLB_ERR_NOCOMP) {
428 shmem_unlock(shm_handler);
429 fatal("Unhandled case in %s: preinit_pid: %d, preinit_process: %p, error: %d.\n"
430 "Please, report bug at %s",
431 __FUNCTION__, preinit_pid, preinit_process, error, PACKAGE_BUGREPORT);
432 }
433
434
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 8 times.
107 if (process) {
435 // Save pointer for faster access
436 99 my_pinfo = process;
437 }
438 }
439 107 shmem_unlock(shm_handler);
440
441
6/6
✓ Branch 0 taken 105 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 101 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 98 times.
107 if (error == DLB_ERR_NOMEM || error == DLB_ERR_PERM || error == DLB_ERR_NOCOMP) {
442 9 warn_error(error);
443 }
444
445
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 96 times.
107 if (error < DLB_SUCCESS) {
446 // The shared memory contents are untouched, but the counter needs to
447 // be decremented, and the shared memory deleted if needed
448 11 close_shmem();
449 }
450
451 107 return error;
452 }
453
454 96 int shmem_procinfo__init(pid_t pid, pid_t preinit_pid, const cpu_set_t *process_mask,
455 cpu_set_t *new_process_mask, const char *shmem_key) {
456 96 return shmem_procinfo__init_(pid, preinit_pid, process_mask, new_process_mask, shmem_key, false);
457 }
458
459 11 int shmem_procinfo__init_with_cpu_sharing(pid_t pid, pid_t preinit_pid,
460 const cpu_set_t *process_mask, const char *shmem_key) {
461 11 return shmem_procinfo__init_(pid, preinit_pid, process_mask, NULL, shmem_key, true);
462 }
463
464 42 int shmem_procinfo_ext__init(const char *shmem_key) {
465 // Shared memory creation
466 42 open_shmem(shmem_key);
467
468 42 shmem_lock(shm_handler);
469 {
470 // Initialize some values if this is the 1st process attached to the shmem
471
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 15 times.
42 if (!shdata->flags.initialized) {
472 27 get_time(&shdata->initial_time);
473 27 mu_get_system_mask(&shdata->free_mask);
474 27 shdata->flags = (const procinfo_flags_t) {
475 .initialized = true,
476 .cpu_sharing_unknown = true,
477 };
478 }
479 }
480 42 shmem_unlock(shm_handler);
481
482 42 return DLB_SUCCESS;
483 }
484
485 28 int shmem_procinfo_ext__preinit(pid_t pid, const cpu_set_t *mask, dlb_drom_flags_t flags) {
486
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (shm_handler == NULL) return DLB_ERR_NOSHMEM;
487
488 28 bool steal = flags & DLB_STEAL_CPUS;
489 28 bool sync = flags & DLB_SYNC_QUERY;
490 28 bool return_stolen = flags & DLB_RETURN_STOLEN;
491 28 int error = DLB_SUCCESS;
492 28 pinfo_t *process = NULL;
493 28 shmem_lock(shm_handler);
494 {
495 int p;
496
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 for (p = 0; p < max_processes; p++) {
497
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
44 if (shdata->process_info[p].pid == pid) {
498 // PID already registered
499 error = DLB_ERR_INIT;
500 break;
501
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 16 times.
44 } else if (shdata->process_info[p].pid == NOBODY) {
502 28 process = &shdata->process_info[p];
503 28 *process = (const pinfo_t){
504 .pid = pid,
505 .preregistered = true};
506
507 // Register process mask into the system
508
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 13 times.
28 if (!steal) {
509 // If no stealing, register as usual
510 15 error = register_mask(process, mask);
511 } else {
512 // Otherwise, steal CPUs if necessary
513 13 error = set_new_mask(process, mask, sync, return_stolen, NULL);
514 }
515
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 26 times.
28 if (error) {
516 // Release shared memory spot
517 2 process->pid = NOBODY;
518 2 break;
519 }
520
521 // Set process initial values
522 26 memcpy(&process->current_process_mask, mask, sizeof(cpu_set_t));
523 26 memcpy(&process->future_process_mask, mask, sizeof(cpu_set_t));
524 26 process->dirty = false;
525
526 26 break;
527 }
528 }
529 }
530 28 shmem_unlock(shm_handler);
531
532
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (error == DLB_ERR_INIT) {
533 verbose(VB_SHMEM, "Process %d already registered", pid);
534
3/4
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
28 } else if (error == DLB_ERR_PERM || error == DLB_ERR_NOCOMP) {
535 1 warn_error(DLB_ERR_PERM);
536
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
27 } else if (process == NULL) {
537 error = DLB_ERR_NOMEM;
538 warn_error(DLB_ERR_NOMEM);
539 }
540
541 28 return error;
542 }
543
544
545 /*********************************************************************************/
546 /* Finalize / Unregister */
547 /*********************************************************************************/
548
549 // Unregister CPUs. Add them to the free_mask or give them back to their owner
550 138 static int unregister_mask(pinfo_t *owner, const cpu_set_t *mask, bool return_stolen) {
551 // Return if empty mask
552
2/2
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 108 times.
138 if (CPU_COUNT(mask) == 0) return DLB_SUCCESS;
553
554 // Return if sharing is allowed and, thus, we don't need keep track of free_mask
555 // nor stolen CPUs
556
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 99 times.
108 if (shdata->flags.allow_cpu_sharing) {
557
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 verbose(VB_DROM, "Process %d unregistering shared mask %s", owner->pid, mu_to_str(mask));
558 9 return DLB_SUCCESS;
559 }
560
561
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 90 times.
99 verbose(VB_DROM, "Process %d unregistering mask %s", owner->pid, mu_to_str(mask));
562
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 91 times.
99 if (return_stolen) {
563 // Look if each CPU belongs to some other process
564 int c, p;
565
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 8 times.
52 for (c = 0; c < max_cpus; c++) {
566
5/6
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 17 times.
✓ Branch 5 taken 27 times.
44 if (CPU_ISSET(c, mask)) {
567
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 for (p = 0; p < max_processes; p++) {
568 27 pinfo_t *process = &shdata->process_info[p];
569
6/8
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17 times.
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 17 times.
✓ Branch 7 taken 10 times.
27 if (process->pid != NOBODY && CPU_ISSET(c, &process->stolen_cpus)) {
570 // give it back to the process
571
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 CPU_SET(c, &process->future_process_mask);
572
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 CPU_CLR(c, &process->stolen_cpus);
573 17 process->dirty = true;
574
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 verbose(VB_DROM, "Giving back CPU %d to process %d", c, process->pid);
575 17 break;
576 }
577 }
578 // if we didn't find the owner, add it to the free_mask
579
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (p == max_processes) {
580 CPU_SET(c, &shdata->free_mask);
581 }
582 // remove CPU from owner
583
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 CPU_CLR(c, &owner->future_process_mask);
584 17 owner->dirty = true;
585 }
586 }
587 } else {
588 // Add mask to free_mask and remove them from owner
589
2/2
✓ Branch 0 taken 1456 times.
✓ Branch 1 taken 91 times.
1547 CPU_OR(&shdata->free_mask, &shdata->free_mask, mask);
590 91 mu_substract(&owner->future_process_mask, &owner->future_process_mask, mask);
591 91 owner->dirty = true;
592 }
593 99 return DLB_SUCCESS;
594 }
595
596 150 static void close_shmem(void) {
597 150 pthread_mutex_lock(&mutex);
598 {
599
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 72 times.
150 if (--subprocesses_attached == 0) {
600 78 shmem_finalize(shm_handler, is_shmem_empty);
601 78 shm_handler = NULL;
602 78 shdata = NULL;
603 }
604 }
605 150 pthread_mutex_unlock(&mutex);
606 150 }
607
608 111 int shmem_procinfo__finalize(pid_t pid, bool return_stolen, const char *shmem_key) {
609 111 int error = DLB_SUCCESS;
610 111 bool shmem_reopened = false;
611
612
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 103 times.
111 if (shm_handler == NULL) {
613 /* procinfo_finalize may be called to finalize existing process
614 * even if the file descriptor is not opened. (DLB_PreInit + forc-exec case) */
615
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 7 times.
8 if (shmem_exists(shmem_name, shmem_key)) {
616 1 open_shmem(shmem_key);
617 1 shmem_reopened = true;
618 } else {
619 7 return DLB_ERR_NOSHMEM;
620 }
621 }
622
623 // Check that pid exists
624 104 pinfo_t *process = get_process(pid);
625
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 97 times.
104 if (unlikely(process == NULL)) {
626 7 error = DLB_ERR_NOPROC;
627 }
628
629 104 shmem_lock(shm_handler);
630 {
631
2/2
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 7 times.
104 if (process) {
632 // Unregister our process mask, or future mask if we are dirty
633
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 96 times.
97 if (process->dirty) {
634 1 unregister_mask(process, &process->future_process_mask, return_stolen);
635 } else {
636 96 unregister_mask(process, &process->current_process_mask, return_stolen);
637 }
638
639 // Clear process fields
640 97 *process = (const pinfo_t){0};
641
642 // Clear local pointer
643 97 my_pinfo = NULL;
644 }
645 }
646 104 shmem_unlock(shm_handler);
647
648 // Close shared memory only if pid was succesfully removed or if shmem was reopened
649
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 97 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
104 if (process || shmem_reopened) {
650 97 close_shmem();
651 }
652
653 104 return error;
654 }
655
656 42 int shmem_procinfo_ext__finalize(void) {
657 // Protect double finalization
658
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (shm_handler == NULL) {
659 return DLB_ERR_NOSHMEM;
660 }
661
662 // Shared memory destruction
663 42 close_shmem();
664
665 42 return DLB_SUCCESS;
666 }
667
668 12 int shmem_procinfo_ext__postfinalize(pid_t pid, bool return_stolen) {
669
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (shm_handler == NULL) return DLB_ERR_NOSHMEM;
670
671 12 int error = DLB_SUCCESS;
672 12 shmem_lock(shm_handler);
673 {
674 12 pinfo_t *process = get_process(pid);
675
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
12 if (process == NULL) {
676
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 verbose(VB_DROM, "Cannot finalize process %d", pid);
677 1 error = DLB_ERR_NOPROC;
678 } else {
679 // Unregister process mask, or future mask if dirty
680
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (process->dirty) {
681 unregister_mask(process, &process->future_process_mask, return_stolen);
682 } else {
683 11 unregister_mask(process, &process->current_process_mask, return_stolen);
684 }
685
686 // Clear process fields
687 11 *process = (const pinfo_t){0};
688 }
689 }
690 12 shmem_unlock(shm_handler);
691 12 return error;
692 }
693
694 5 int shmem_procinfo_ext__recover_stolen_cpus(int pid) {
695
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (shm_handler == NULL) return DLB_ERR_NOSHMEM;
696
697 int error;
698 5 shmem_lock(shm_handler);
699 {
700 5 pinfo_t *process = get_process(pid);
701
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (process == NULL) {
702 verbose(VB_DROM, "Cannot find process %d", pid);
703 error = DLB_ERR_NOPROC;
704
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 times.
5 } else if (CPU_COUNT(&process->stolen_cpus) == 0) {
705 4 error = DLB_NOUPDT;
706 } else {
707 // Recover all stolen CPUs only if the CPU is set in the free_mask
708 cpu_set_t recovered_cpus;
709
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 times.
17 CPU_AND(&recovered_cpus, &process->stolen_cpus, &shdata->free_mask);
710 1 error = register_mask(process, &recovered_cpus);
711
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (error == DLB_SUCCESS) {
712 1 mu_substract(&process->stolen_cpus, &process->stolen_cpus, &recovered_cpus);
713 }
714 }
715 }
716 5 shmem_unlock(shm_handler);
717 5 return error;
718 }
719
720
721 /*********************************************************************************/
722 /* Get / Set Process mask */
723 /*********************************************************************************/
724
725 /* PRE: shm_handler and my_pinfo are not NULL */
726 9 static int shmem_procinfo__getprocessmask_self(cpu_set_t *mask) {
727 int error;
728 9 pinfo_t *process = my_pinfo;
729 9 shmem_lock(shm_handler);
730 {
731 /* If current process is dirty, update mask and return the new one */
732
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (process->dirty) {
733 memcpy(mask, &process->future_process_mask, sizeof(cpu_set_t));
734 memcpy(&process->current_process_mask, &process->future_process_mask,
735 sizeof(cpu_set_t));
736 process->dirty = false;
737 error = DLB_NOTED;
738 } else {
739 9 memcpy(mask, &process->current_process_mask, sizeof(cpu_set_t));
740 9 error = DLB_SUCCESS;
741 }
742 }
743 9 shmem_unlock(shm_handler);
744 9 return error;
745 }
746
747 40 int shmem_procinfo__getprocessmask(pid_t pid, cpu_set_t *mask, dlb_drom_flags_t flags) {
748
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 34 times.
40 if (shm_handler == NULL) return DLB_ERR_NOSHMEM;
749
750 /* Specific case, if pid is 0 the target is the current process */
751
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 31 times.
34 if (pid == 0) {
752
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (my_pinfo != NULL) {
753 2 return shmem_procinfo__getprocessmask_self(mask);
754 } else {
755 1 return DLB_ERR_NOPROC;
756 }
757 }
758
759 /* Specific case, if pid is current process */
760
4/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 19 times.
31 if (my_pinfo != NULL && my_pinfo->pid == pid) {
761 7 return shmem_procinfo__getprocessmask_self(mask);
762 }
763
764 24 int error = DLB_SUCCESS;
765 24 bool done = false;
766 pinfo_t *process;
767
768 24 shmem_lock(shm_handler);
769 {
770 // Find process
771 24 process = get_process(pid);
772
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 20 times.
24 if (process == NULL) {
773
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 verbose(VB_DROM, "Getting mask: cannot find process with pid %d", pid);
774 4 error = DLB_ERR_NOPROC;
775 }
776
777
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 4 times.
24 if (!error) {
778
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (!process->dirty) {
779 // Get current mask if not dirty
780 20 memcpy(mask, &process->current_process_mask, sizeof(cpu_set_t));
781 20 done = true;
782 } else if (!(flags & DLB_SYNC_QUERY)) {
783 // Get future mask if query is non-blocking
784 memcpy(mask, &process->future_process_mask, sizeof(cpu_set_t));
785 done = true;
786 }
787 }
788 }
789 24 shmem_unlock(shm_handler);
790
791
3/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
24 if (!error && !done) {
792 // process is valid, but it's dirty so we need to poll
793 int64_t elapsed;
794 struct timespec start, now;
795 get_time_coarse(&start);
796 while(true) {
797
798 // Delay
799 usleep(SYNC_POLL_DELAY);
800
801 // Polling
802 shmem_lock(shm_handler);
803 {
804 if (!process->dirty) {
805 memcpy(mask, &process->current_process_mask, sizeof(cpu_set_t));
806 done = true;
807 }
808 }
809 shmem_unlock(shm_handler);
810
811 // Break if done
812 if (done) break;
813
814 // Break if timeout
815 get_time_coarse(&now);
816 elapsed = timespec_diff(&start, &now);
817 if (elapsed > SYNC_POLL_TIMEOUT) {
818 error = DLB_ERR_TIMEOUT;
819 break;
820 }
821 }
822 }
823
824 24 return error;
825 }
826
827 /* PRE: shm_handler and my_pinfo are not NULL */
828 5 static int shmem_procinfo__setprocessmask_self(const cpu_set_t *mask, dlb_drom_flags_t flags,
829 cpu_set_t *free_cpu_mask) {
830 int error;
831 5 bool return_stolen = flags & DLB_RETURN_STOLEN;
832 5 bool skip_auto_update = flags & DLB_NO_SYNC;
833 5 pinfo_t *process = my_pinfo;
834 5 shmem_lock(shm_handler);
835 {
836
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
5 if (!process->dirty || CPU_EQUAL(mask, &process->future_process_mask)) {
837 5 error = set_new_mask(process, mask, false /* sync */, return_stolen, free_cpu_mask);
838 } else {
839 error = DLB_ERR_PDIRTY;
840 }
841
842 /* Update current mask now */
843
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 times.
5 if (error == DLB_SUCCESS && !skip_auto_update) {
844 3 memcpy(&process->current_process_mask, &process->future_process_mask,
845 sizeof(cpu_set_t));
846 3 process->dirty = false;
847 }
848 }
849 5 shmem_unlock(shm_handler);
850
851
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (error == DLB_ERR_PDIRTY) {
852 verbose(VB_DROM, "Setting mask: current process is already dirty");
853
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 } else if (error == DLB_ERR_PERM) {
854 verbose(VB_DROM, "Setting mask: cannot steal mask %s", mu_to_str(mask));
855
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 } else if (error == DLB_ERR_NOCOMP) {
856
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 verbose(VB_DROM, "Setting mask: cannot steal mask if shmem has been intialized with CPU sharing");
857 }
858
859 5 return error;
860 }
861
862 27 int shmem_procinfo__setprocessmask(pid_t pid, const cpu_set_t *mask, dlb_drom_flags_t flags,
863 cpu_set_t *free_cpu_mask) {
864
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 22 times.
27 if (shm_handler == NULL) return DLB_ERR_NOSHMEM;
865
866 /* Specific case, if pid is 0 the target is the current process */
867
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 19 times.
22 if (pid == 0) {
868
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (my_pinfo != NULL) {
869 2 return shmem_procinfo__setprocessmask_self(mask, flags, free_cpu_mask);
870 } else {
871 1 return DLB_ERR_NOPROC;
872 }
873 }
874
875 /* Specific case, if pid is current process */
876
4/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 11 times.
19 if (my_pinfo != NULL && my_pinfo->pid == pid) {
877 3 return shmem_procinfo__setprocessmask_self(mask, flags, free_cpu_mask);
878 }
879
880 16 bool sync = flags & DLB_SYNC_QUERY;
881 16 bool return_stolen = flags & DLB_RETURN_STOLEN;
882 16 int error = DLB_SUCCESS;
883 pinfo_t *process;
884 16 shmem_lock(shm_handler);
885 {
886 // Find process
887 16 process = get_process(pid);
888
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (process == NULL) {
889 error = DLB_ERR_NOPROC;
890 }
891
892 // Process already dirty
893
3/4
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 15 times.
16 if (!error && process->dirty) {
894 1 error = DLB_ERR_PDIRTY;
895 }
896
897 // Set new mask if everything ok
898
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1 times.
16 error = error ? error : set_new_mask(process, mask, sync, return_stolen, free_cpu_mask);
899 }
900 16 shmem_unlock(shm_handler);
901
902 // Polling until dirty is cleared
903
3/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
16 if (!error && sync) {
904 bool done = false;
905 struct timespec start, now;
906 get_time_coarse(&start);
907 do {
908
909 // Delay
910 usleep(SYNC_POLL_DELAY);
911
912 // Poll
913 shmem_lock(shm_handler);
914 {
915 if (process->pid != pid) {
916 // process no longer valid
917 error = DLB_ERR_NOPROC;
918 done = true;
919 }
920
921 if (!process->dirty) {
922 done = true;
923 }
924 }
925 shmem_unlock(shm_handler);
926
927 // Check timeout
928 if (!done) {
929 get_time_coarse(&now);
930 if (timespec_diff(&start, &now) > SYNC_POLL_TIMEOUT) {
931 error = DLB_ERR_TIMEOUT;
932 }
933 }
934 } while (!done && error == DLB_SUCCESS);
935 }
936
937
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (error == DLB_ERR_NOPROC) {
938 verbose(VB_DROM, "Setting mask: cannot find process with pid %d", pid);
939
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 15 times.
16 } else if (error == DLB_ERR_PDIRTY) {
940
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 verbose(VB_DROM, "Setting mask: process %d is already dirty", pid);
941
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 14 times.
15 } else if (error == DLB_ERR_PERM) {
942
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 verbose(VB_DROM, "Setting mask: cannot steal mask %s", mu_to_str(mask));
943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 } else if (error == DLB_ERR_NOCOMP) {
944 verbose(VB_DROM, "Setting mask: cannot steal mask if shmem has been intialized with CPU sharing");
945 }
946
947 16 return error;
948 }
949
950
951 /*********************************************************************************/
952 /* Generic Getters */
953 /*********************************************************************************/
954
955 48 int shmem_procinfo__polldrom(pid_t pid, int *new_cpus, cpu_set_t *new_mask) {
956 int error;
957
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 47 times.
48 if (shm_handler == NULL) {
958 1 error = DLB_ERR_NOSHMEM;
959 } else {
960 47 pinfo_t *process = get_process(pid);
961
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 46 times.
47 if (!process) {
962 1 error = DLB_ERR_NOPROC;
963
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 36 times.
46 } else if (!process->dirty) {
964 10 error = DLB_NOUPDT;
965 } else {
966 36 shmem_lock(shm_handler);
967 {
968 // Update output parameters
969 36 memcpy(new_mask, &process->future_process_mask, sizeof(cpu_set_t));
970
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 35 times.
36 if (new_cpus != NULL) *new_cpus = CPU_COUNT(&process->future_process_mask);
971
972 // Upate local info
973 36 memcpy(&process->current_process_mask, &process->future_process_mask,
974 sizeof(cpu_set_t));
975 36 process->dirty = false;
976 }
977 36 shmem_unlock(shm_handler);
978 36 error = DLB_SUCCESS;
979 }
980 }
981 48 return error;
982 }
983
984 5 int shmem_procinfo__getpidlist(pid_t *pidlist, int *nelems, int max_len) {
985 5 *nelems = 0;
986
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (shm_handler == NULL) return DLB_ERR_NOSHMEM;
987 5 shmem_lock(shm_handler);
988 {
989 int p;
990
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 3 times.
29 for (p = 0; p < max_processes; p++) {
991 26 pid_t pid = shdata->process_info[p].pid;
992
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 24 times.
26 if (pid != NOBODY) {
993 2 pidlist[(*nelems)++] = pid;
994 }
995
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 24 times.
26 if (*nelems == max_len) {
996 2 break;
997 }
998 }
999 }
1000 5 shmem_unlock(shm_handler);
1001 5 return DLB_SUCCESS;
1002 }
1003
1004
1005 /*********************************************************************************/
1006 /* Statistics */
1007 /*********************************************************************************/
1008
1009 double shmem_procinfo__getcpuusage(pid_t pid) {
1010 if (shm_handler == NULL) return -1.0;
1011
1012 double cpu_usage = -1.0;
1013 shmem_lock(shm_handler);
1014 {
1015 pinfo_t *process = get_process(pid);
1016 if (process) {
1017 cpu_usage = process->cpu_usage;
1018 }
1019 }
1020 shmem_unlock(shm_handler);
1021
1022 return cpu_usage;
1023 }
1024
1025 double shmem_procinfo__getcpuavgusage(pid_t pid) {
1026 if (shm_handler == NULL) return -1.0;
1027
1028 double cpu_avg_usage = -1.0;
1029 shmem_lock(shm_handler);
1030 {
1031 pinfo_t *process = get_process(pid);
1032 if (process) {
1033 cpu_avg_usage = process->cpu_avg_usage;
1034 }
1035 }
1036 shmem_unlock(shm_handler);
1037
1038 return cpu_avg_usage;
1039 }
1040
1041 void shmem_procinfo__getcpuusage_list(double *usagelist, int *nelems, int max_len) {
1042 *nelems = 0;
1043 if (shm_handler == NULL) return;
1044 shmem_lock(shm_handler);
1045 {
1046 int p;
1047 for (p = 0; p < max_processes; p++) {
1048 if (shdata->process_info[p].pid != NOBODY) {
1049 usagelist[(*nelems)++] = shdata->process_info[p].cpu_usage;
1050 }
1051 if (*nelems == max_len) {
1052 break;
1053 }
1054 }
1055 }
1056 shmem_unlock(shm_handler);
1057 }
1058
1059 void shmem_procinfo__getcpuavgusage_list(double *avgusagelist, int *nelems, int max_len) {
1060 *nelems = 0;
1061 if (shm_handler == NULL) return;
1062 shmem_lock(shm_handler);
1063 {
1064 int p;
1065 for (p = 0; p < max_processes; p++) {
1066 if (shdata->process_info[p].pid != NOBODY) {
1067 avgusagelist[(*nelems)++] = shdata->process_info[p].cpu_avg_usage;
1068 }
1069 if (*nelems == max_len) {
1070 break;
1071 }
1072 }
1073 }
1074 shmem_unlock(shm_handler);
1075 }
1076
1077 double shmem_procinfo__getnodeusage(void) {
1078 if (shm_handler == NULL) return -1.0;
1079
1080 double cpu_usage = 0.0;
1081 shmem_lock(shm_handler);
1082 {
1083 int p;
1084 for (p = 0; p < max_processes; p++) {
1085 if (shdata->process_info[p].pid != NOBODY) {
1086 cpu_usage += shdata->process_info[p].cpu_usage;
1087 }
1088 }
1089 }
1090 shmem_unlock(shm_handler);
1091
1092 return cpu_usage;
1093 }
1094
1095 double shmem_procinfo__getnodeavgusage(void) {
1096 if (shm_handler == NULL) return -1.0;
1097
1098 double cpu_avg_usage = 0.0;
1099 shmem_lock(shm_handler);
1100 {
1101 int p;
1102 for (p = 0; p < max_processes; p++) {
1103 if (shdata->process_info[p].pid != NOBODY) {
1104 cpu_avg_usage += shdata->process_info[p].cpu_avg_usage;
1105 }
1106 }
1107 }
1108 shmem_unlock(shm_handler);
1109
1110 return cpu_avg_usage;
1111 }
1112
1113 int shmem_procinfo__getactivecpus(pid_t pid) {
1114 if (shm_handler == NULL) return DLB_ERR_NOSHMEM;
1115
1116 int active_cpus = -1;
1117 shmem_lock(shm_handler);
1118 {
1119 pinfo_t *process = get_process(pid);
1120 if (process) {
1121 active_cpus = process->active_cpus;
1122 }
1123 }
1124 shmem_unlock(shm_handler);
1125 return active_cpus;
1126 }
1127
1128 void shmem_procinfo__getactivecpus_list(pid_t *cpuslist, int *nelems, int max_len) {
1129 *nelems = 0;
1130 if (shm_handler == NULL) return;
1131 shmem_lock(shm_handler);
1132 {
1133 int p;
1134 for (p = 0; p < max_processes; p++) {
1135 if (shdata->process_info[p].pid != NOBODY) {
1136 cpuslist[(*nelems)++] = shdata->process_info[p].active_cpus;
1137 }
1138 if (*nelems == max_len) {
1139 break;
1140 }
1141 }
1142 }
1143 shmem_unlock(shm_handler);
1144 }
1145
1146 int shmem_procinfo__getloadavg(pid_t pid, double *load) {
1147 if (shm_handler == NULL) return DLB_ERR_NOSHMEM;
1148 int error = DLB_ERR_UNKNOWN;
1149 #ifdef DLB_LOAD_AVERAGE
1150 shmem_lock(shm_handler);
1151 {
1152 pinfo_t *process = get_process(pid);
1153 if (process) {
1154 load[0] = process->load[0];
1155 load[1] = process->load[1];
1156 load[2] = process->load[2];
1157 error = 0;
1158 }
1159 }
1160 shmem_unlock(shm_handler);
1161 #endif
1162 return error;
1163 }
1164
1165
1166 int shmem_procinfo__setcpuavgusage(pid_t pid, double new_avg_usage) {
1167
1168 if (shm_handler == NULL) return -1.0;
1169
1170 shmem_lock(shm_handler);
1171 {
1172 pinfo_t *process = get_process(pid);
1173 if (process) {
1174 process->cpu_avg_usage = new_avg_usage;
1175 }
1176 }
1177 shmem_unlock(shm_handler);
1178
1179 return DLB_SUCCESS;
1180 }
1181
1182 int shmem_procinfo__setcpuusage(pid_t pid,int index, double new_avg_usage) {
1183 if (shm_handler == NULL) return -1.0;
1184
1185 shmem_lock(shm_handler);
1186 {
1187 pinfo_t *process = get_process(pid);
1188 if (process) {
1189 process->cpu_avg_usage = new_avg_usage;
1190 }
1191 }
1192 shmem_unlock(shm_handler);
1193
1194 return DLB_SUCCESS;
1195 }
1196
1197
1198 /*********************************************************************************/
1199 /* Misc */
1200 /*********************************************************************************/
1201
1202 9 void shmem_procinfo__print_info(const char *shmem_key) {
1203
1204 /* If the shmem is not opened, obtain a temporary fd */
1205 9 bool temporary_shmem = shm_handler == NULL;
1206
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
9 if (temporary_shmem) {
1207 4 shmem_procinfo_ext__init(shmem_key);
1208 }
1209
1210 /* Make a full copy of the shared memory */
1211 9 shdata_t *shdata_copy = malloc(shmem_procinfo__size());
1212 9 shmem_lock(shm_handler);
1213 {
1214 9 memcpy(shdata_copy, shdata, shmem_procinfo__size());
1215 }
1216 9 shmem_unlock(shm_handler);
1217
1218 /* Close shmem if needed */
1219
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
9 if (temporary_shmem) {
1220 4 shmem_procinfo_ext__finalize();
1221 }
1222
1223 /* Find the max number of characters per column */
1224 9 pid_t max_pid = 111; /* 3 digits for 'PID' */
1225 9 int max_current = 4; /* 'Mask' */
1226 9 int max_future = 6; /* 'Future' */
1227 9 int max_stolen = 6; /* 'Stolen' */
1228 int p;
1229
2/2
✓ Branch 0 taken 184 times.
✓ Branch 1 taken 9 times.
193 for (p = 0; p < max_processes; ++p) {
1230 184 pinfo_t *process = &shdata_copy->process_info[p];
1231
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 177 times.
184 if (process->pid != NOBODY) {
1232 int len;
1233 /* pid */
1234 7 max_pid = process->pid > max_pid ? process->pid : max_pid;
1235 /* current_mask */
1236 7 len = strlen(mu_to_str(&process->current_process_mask));
1237 7 max_current = len > max_current ? len : max_current;
1238 /* future_mask */
1239 7 len = strlen(mu_to_str(&process->future_process_mask));
1240 7 max_future = len > max_future ? len : max_future;
1241 /* stolen_mask */
1242 7 len = strlen(mu_to_str(&process->stolen_cpus));
1243 7 max_stolen = len > max_stolen ? len : max_stolen;
1244 }
1245 }
1246 9 int max_pid_digits = snprintf(NULL, 0, "%d", max_pid);
1247
1248 /* Initialize buffer */
1249 print_buffer_t buffer;
1250 9 printbuffer_init(&buffer);
1251
1252 /* Set up line buffer */
1253 enum { MAX_LINE_LEN = 512 };
1254 char line[MAX_LINE_LEN];
1255
1256
2/2
✓ Branch 0 taken 184 times.
✓ Branch 1 taken 9 times.
193 for (p = 0; p < max_processes; p++) {
1257 184 pinfo_t *process = &shdata_copy->process_info[p];
1258
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 177 times.
184 if (process->pid != NOBODY) {
1259 const char *mask_str;
1260
1261 /* Copy current mask */
1262 7 mask_str = mu_to_str(&process->current_process_mask);
1263 7 char *current = malloc((strlen(mask_str)+1)*sizeof(char));
1264 7 strcpy(current, mask_str);
1265
1266 /* Copy future mask */
1267 7 mask_str = mu_to_str(&process->future_process_mask);
1268 7 char *future = malloc((strlen(mask_str)+1)*sizeof(char));
1269 7 strcpy(future, mask_str);
1270
1271 /* Copy stolen mask */
1272 7 mask_str = mu_to_str(&process->stolen_cpus);
1273 7 char *stolen = malloc((strlen(mask_str)+1)*sizeof(char));
1274 7 strcpy(stolen, mask_str);
1275
1276 /* Append line to buffer */
1277 7 snprintf(line, MAX_LINE_LEN,
1278 " | %*d | %*s | %*s | %*s | %6d |",
1279 max_pid_digits, process->pid,
1280 max_current, current,
1281 max_future, future,
1282 max_stolen, stolen,
1283 7 process->dirty);
1284 7 printbuffer_append(&buffer, line);
1285
1286 7 free(current);
1287 7 free(future);
1288 7 free(stolen);
1289 }
1290 }
1291
1292
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 if (buffer.addr[0] != '\0' ) {
1293 /* Construct header */
1294 5 snprintf(line, MAX_LINE_LEN,
1295 " | %*s | %*s | %*s | %*s | Dirty? |",
1296 max_pid_digits, "PID",
1297 max_current, "Mask",
1298 max_future, "Future",
1299 max_stolen, "Stolen");
1300
1301 /* Print header + buffer */
1302 5 info0("=== Processes Masks ===\n"
1303 "%s\n"
1304 "%s", line, buffer.addr);
1305 }
1306 9 printbuffer_destroy(&buffer);
1307 9 free(shdata_copy);
1308 9 }
1309
1310 8 bool shmem_procinfo__exists(void) {
1311 8 return shm_handler != NULL;
1312 }
1313
1314 1 int shmem_procinfo__version(void) {
1315 1 return SHMEM_PROCINFO_VERSION;
1316 }
1317
1318 98 size_t shmem_procinfo__size(void) {
1319 98 return sizeof(shdata_t) + sizeof(pinfo_t)*mu_get_system_size();
1320 }
1321
1322
1323 /*** Helper functions, the shm lock must have been acquired beforehand ***/
1324
1325
1326 // FIXME Update statistics temporarily disabled
1327 #if 0
1328 static void update_process_loads(void) {
1329 // Get the active CPUs
1330 cpu_set_t mask;
1331 memcpy(&mask, &global_spd.active_mask, sizeof(cpu_set_t));
1332 shdata->process_info[my_process].active_cpus = CPU_COUNT(&mask);
1333
1334 // Compute elapsed total time
1335 struct timespec current_ttime;
1336 int64_t elapsed_ttime_since_last;
1337 int64_t elapsed_ttime_since_init;;
1338 get_time_coarse(&current_ttime);
1339 elapsed_ttime_since_last = timespec_diff(&last_ttime, &current_ttime);
1340 elapsed_ttime_since_init = timespec_diff(&shdata->initial_time, &current_ttime );
1341
1342 // Compute elapsed useful time (user+system)
1343 struct rusage usage;
1344 struct timespec current_utime;
1345 int64_t elapsed_utime_since_last;
1346 int64_t elapsed_utime_since_init;
1347 getrusage(RUSAGE_SELF, &usage);
1348 add_tv_to_ts(&usage.ru_utime, &usage.ru_stime, &current_utime);
1349 elapsed_utime_since_last = timespec_diff(&last_utime, &current_utime);
1350 elapsed_utime_since_init = to_nsecs(&current_utime);
1351
1352 // Update times for next update
1353 last_ttime = current_ttime;
1354 last_utime = current_utime;
1355
1356 // Compute usage
1357 shdata->process_info[my_process].cpu_usage = 100 *
1358 (double)elapsed_utime_since_last / (double)elapsed_ttime_since_last;
1359
1360 // Compute avg usage
1361 shdata->process_info[my_process].cpu_avg_usage = 100 *
1362 (double)elapsed_utime_since_init / (double)elapsed_ttime_since_init;
1363
1364 #ifdef DLB_LOAD_AVERAGE
1365 // Do not update the Load Average if the elapsed is less that a threshold
1366 if (elapsed_ttime > UPDATE_LOADAVG_MIN_THRESHOLD) {
1367 shdata->process_info[my_process].last_ltime = current_ttime;
1368 // WIP
1369 }
1370 #endif
1371 }
1372 #endif
1373
1374
1375 // Steal every CPU in mask from other processes
1376 63 static int steal_mask(pinfo_t* new_owner, const cpu_set_t *mask, bool sync, bool dry_run) {
1377 // Return if empty mask
1378
2/2
✓ Branch 1 taken 38 times.
✓ Branch 2 taken 25 times.
63 if (CPU_COUNT(mask) == 0) return DLB_SUCCESS;
1379
1380 25 int error = DLB_SUCCESS;
1381 cpu_set_t cpus_left_to_steal;
1382 25 memcpy(&cpus_left_to_steal, mask, sizeof(cpu_set_t));
1383
1384 // Iterate per process, steal in batch
1385 int p;
1386
1/2
✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
43 for (p = 0; p < max_processes; ++p) {
1387 43 pinfo_t *victim = &shdata->process_info[p];
1388
3/4
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 35 times.
✗ Branch 3 not taken.
43 if (victim != new_owner && victim->pid != NOBODY) {
1389 cpu_set_t target_cpus;
1390
2/2
✓ Branch 0 taken 560 times.
✓ Branch 1 taken 35 times.
595 CPU_AND(&target_cpus, &victim->current_process_mask, mask);
1391
1/2
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
35 if (CPU_COUNT(&target_cpus) > 0) {
1392 // victim contains target CPUs
1393
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 1 times.
35 if (!victim->dirty) {
1394 // Steal target_cpus from victim
1395
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 17 times.
34 if (!dry_run) {
1396 17 victim->dirty = true;
1397 17 mu_substract(&victim->future_process_mask,
1398 17 &victim->current_process_mask, &target_cpus);
1399
2/2
✓ Branch 0 taken 272 times.
✓ Branch 1 taken 17 times.
289 CPU_OR(&victim->stolen_cpus, &victim->stolen_cpus, &target_cpus);
1400
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 verbose(VB_DROM, "CPUs %s have been removed from process %d",
1401 mu_to_str(mask), victim->pid);
1402 }
1403 34 mu_substract(&cpus_left_to_steal, &cpus_left_to_steal, &target_cpus);
1404
2/2
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 10 times.
34 if (CPU_COUNT(&cpus_left_to_steal) == 0)
1405 25 break;
1406 } else {
1407 1 error = DLB_ERR_PERM;
1408 1 break;
1409 }
1410 }
1411 }
1412 }
1413
1414
3/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
25 if (unlikely(!error && CPU_COUNT(&cpus_left_to_steal) > 0)) {
1415 warning("Could not find candidate for stealing mask %s. Please report to "
1416 PACKAGE_BUGREPORT, mu_to_str(mask));
1417 error = DLB_ERR_PERM;
1418 }
1419
1420
6/6
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 3 times.
25 if (!error && sync && !dry_run) {
1421 // Relase lock and poll until victims update their masks or timeout
1422 3 shmem_unlock(shm_handler);
1423
1424 3 bool done = false;
1425 struct timespec start, now;
1426 3 get_time_coarse(&start);
1427 do {
1428 // Delay
1429 95 usleep(SYNC_POLL_DELAY);
1430
1431 // Poll
1432 95 shmem_lock(shm_handler);
1433 {
1434 cpu_set_t all_current_masks;
1435 95 CPU_ZERO(&all_current_masks);
1436
2/2
✓ Branch 0 taken 380 times.
✓ Branch 1 taken 95 times.
475 for (p = 0; p < max_processes; ++p) {
1437 380 pinfo_t *victim = &shdata->process_info[p];
1438
4/4
✓ Branch 0 taken 285 times.
✓ Branch 1 taken 95 times.
✓ Branch 2 taken 190 times.
✓ Branch 3 taken 95 times.
380 if (victim != new_owner && victim->pid != NOBODY) {
1439 // Accumulate updated masks of other processes
1440
2/2
✓ Branch 0 taken 3040 times.
✓ Branch 1 taken 190 times.
3230 CPU_OR(&all_current_masks, &all_current_masks,
1441 &victim->current_process_mask);
1442 }
1443 }
1444
1445 // Polling is complete when no current_mask of any process
1446 // contains any CPU from the mask we are stealing
1447 cpu_set_t common_cpus;
1448
2/2
✓ Branch 0 taken 1520 times.
✓ Branch 1 taken 95 times.
1615 CPU_AND(&common_cpus, &all_current_masks, mask);
1449 95 done = CPU_COUNT(&common_cpus) == 0;
1450 }
1451 95 shmem_unlock(shm_handler);
1452
1453 // Check timeout
1454
2/2
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 2 times.
95 if (!done) {
1455 93 get_time_coarse(&now);
1456
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 92 times.
93 if (timespec_diff(&start, &now) > SYNC_POLL_TIMEOUT) {
1457 1 error = DLB_ERR_TIMEOUT;
1458 }
1459 }
1460
4/4
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 92 times.
✓ Branch 3 taken 1 times.
95 } while (!done && error == DLB_SUCCESS);
1461
1462 3 shmem_lock(shm_handler);
1463 }
1464
1465
4/4
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 12 times.
25 if (!error && !dry_run) {
1466 /* Assign stolen CPUs to the new owner */
1467
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 11 times.
187 CPU_OR(&new_owner->future_process_mask, &new_owner->future_process_mask, mask);
1468 11 mu_substract(&new_owner->stolen_cpus, &new_owner->stolen_cpus, mask);
1469 11 new_owner->dirty = true;
1470 }
1471
1472
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
25 if (error && !dry_run) {
1473 // Some CPUs could not be stolen, roll everything back
1474
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (p = 0; p < max_processes; ++p) {
1475 4 pinfo_t *victim = &shdata->process_info[p];
1476
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
4 if (victim != new_owner && victim->pid != NOBODY) {
1477 cpu_set_t cpus_to_return;
1478
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 2 times.
34 CPU_AND(&cpus_to_return, &victim->stolen_cpus, mask);
1479
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (CPU_COUNT(&cpus_to_return) > 0) {
1480 // warning: we may return some CPU to a wrong process
1481 // if more than one contains that CPU as stolen
1482
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 2 times.
34 CPU_OR(&victim->future_process_mask, &victim->future_process_mask,
1483 &cpus_to_return);
1484 2 mu_substract(&victim->stolen_cpus, &victim->stolen_cpus, &cpus_to_return);
1485 2 victim->dirty = !CPU_EQUAL(
1486 &victim->current_process_mask, &victim->future_process_mask);
1487 }
1488 }
1489 }
1490 }
1491
1492 25 return error;
1493 }
1494
1495
1496 /* Set new mask for process, stealing if necessary
1497 * - If the CPU is SET and unused -> register
1498 * - If the CPU is SET, used and not owned -> steal
1499 * - If the CPU is UNSET and owned by the process -> unregister
1500 */
1501 33 static int set_new_mask(pinfo_t *process, const cpu_set_t *mask, bool sync,
1502 bool return_stolen, cpu_set_t *free_cpu_mask) {
1503 // this function cannot be used if allowing CPU sharing
1504
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 32 times.
33 if (shdata->flags.allow_cpu_sharing) return DLB_ERR_NOCOMP;
1505
1506 cpu_set_t cpus_to_acquire;
1507 cpu_set_t cpus_to_steal;
1508 cpu_set_t cpus_to_free;
1509 32 CPU_ZERO(&cpus_to_acquire);
1510 32 CPU_ZERO(&cpus_to_steal);
1511 32 CPU_ZERO(&cpus_to_free);
1512
1513 int c;
1514
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 32 times.
236 for (c = 0; c < max_cpus; c++) {
1515
5/6
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 120 times.
✓ Branch 4 taken 84 times.
✓ Branch 5 taken 120 times.
204 if (CPU_ISSET(c, mask)) {
1516
5/6
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 66 times.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 66 times.
84 if (CPU_ISSET(c, &shdata->free_mask)) {
1517 // CPU is not being used
1518
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 CPU_SET(c, &cpus_to_acquire);
1519 } else {
1520
5/6
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 42 times.
66 if (!CPU_ISSET(c, &process->current_process_mask)) {
1521 // CPU is being used by other process
1522
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 CPU_SET(c, &cpus_to_steal);
1523 }
1524 }
1525 } else {
1526
5/6
✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 109 times.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 109 times.
120 if (CPU_ISSET(c, &process->current_process_mask)) {
1527 // CPU no longer used by this process
1528
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 CPU_SET(c, &cpus_to_free);
1529 }
1530 }
1531 }
1532
1533 /* Run first a dry run to check if CPUs can be stolen */
1534 32 int error = steal_mask(process, &cpus_to_steal, sync, /* dry_run */ true);
1535
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 1 times.
32 error = error ? error : steal_mask(process, &cpus_to_steal, sync, /* dry_run */ false);
1536
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 2 times.
32 error = error ? error : register_mask(process, &cpus_to_acquire);
1537
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 2 times.
32 error = error ? error : unregister_mask(process, &cpus_to_free, return_stolen);
1538
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 23 times.
32 if (error == DLB_SUCCESS && free_cpu_mask != NULL) {
1539 7 memcpy(free_cpu_mask, &cpus_to_free, sizeof(cpu_set_t));
1540 }
1541
1542 32 return error;
1543 }
1544