/src/dovecot/src/lib/cpu-limit.h
Line | Count | Source |
1 | | #ifndef CPU_LIMIT |
2 | | #define CPU_LIMIT |
3 | | |
4 | | struct cpu_limit; |
5 | | |
6 | | enum cpu_limit_type { |
7 | | CPU_LIMIT_TYPE_USER = BIT(0), |
8 | | CPU_LIMIT_TYPE_SYSTEM = BIT(1), |
9 | | }; |
10 | | #define CPU_LIMIT_TYPE_ALL (CPU_LIMIT_TYPE_USER | CPU_LIMIT_TYPE_SYSTEM) |
11 | | |
12 | | /* Start tracking CPU usage. This internally uses setrlimit(RLIMIT_CPU) to |
13 | | trigger SIGXCPU to avoid constantly calling getrlimit() to check if the CPU |
14 | | usage has reached a limit. Once all limits created by this API are released, |
15 | | the original CPU resource limits are restored (if any). |
16 | | |
17 | | CPU time limits can be nested, i.e. they are never independent. The outer |
18 | | limits contain the bounded maximum limit for the inner limits. For example |
19 | | the code execution flow might be: |
20 | | - Set 30s CPU limit (outer limit) |
21 | | - Use up 5s of CPU |
22 | | - Set 40s CPU limit (inner limit) |
23 | | - Infinite loop |
24 | | The inner loop's limit won't even be reached here. After the inner loops |
25 | | runs for 25 seconds, the outer loop's 30s limit is reached. This causes |
26 | | both the inner and the other limit's cpu_limit_exceeded() to return TRUE. |
27 | | It's expected that the inner execution stops and returns back to the outer |
28 | | execution, which notices that the outer execution has also reached the limit. |
29 | | |
30 | | Another example where the inner limit is reached: |
31 | | - Set 30s CPU limit (outer limit) |
32 | | - Use up 5s of CPU |
33 | | - Set 10s CPU limit (inner limit) |
34 | | - Infinite loop |
35 | | Here the inner 10s limit is reached, and the inner execution stops. The |
36 | | outer execution could still run for another 15 seconds. |
37 | | |
38 | | Example usage: |
39 | | |
40 | | bool limit_reached = FALSE; |
41 | | limit = cpu_limit_init(5, CPU_LIMIT_TYPE_ALL); |
42 | | while (long_operation_iterate_once()) { |
43 | | if (cpu_limit_exceeded(limit)) { |
44 | | limit_reached = TRUE; // operation took >=5 secs |
45 | | break; |
46 | | } |
47 | | } |
48 | | cpu_limit_deinit(&limit); |
49 | | */ |
50 | | struct cpu_limit * |
51 | | cpu_limit_init(unsigned int cpu_limit_secs, enum cpu_limit_type type); |
52 | | void cpu_limit_deinit(struct cpu_limit **_climit); |
53 | | |
54 | | /* Returns TRUE if the CPU limit has been exceeded for this limit or any of its |
55 | | parents. */ |
56 | | bool cpu_limit_exceeded(struct cpu_limit *climit); |
57 | | |
58 | | unsigned int cpu_limit_get_usage_msecs(struct cpu_limit *climit, |
59 | | enum cpu_limit_type type); |
60 | | |
61 | | static inline unsigned int |
62 | | cpu_limit_get_usage_secs(struct cpu_limit *climit, enum cpu_limit_type type) |
63 | 0 | { |
64 | 0 | return cpu_limit_get_usage_msecs(climit, type) / 1000; |
65 | 0 | } Unexecuted instantiation: sieve-interpreter.c:cpu_limit_get_usage_secs Unexecuted instantiation: cpu-limit.c:cpu_limit_get_usage_secs |
66 | | |
67 | | #endif |