History

posix-cpu-timers: Move state tracking to struct posix_cputimers

Put it where it belongs and clean up the ifdeffery in fork completely.

Thomas Gleixner committed 7 years ago

Commit 244d49e1 parent 8991afe6 files · +54 −50Browse files

Unified · Split

6 files
  1. include/linux/posix-timers.h +8 −0
  2. include/linux/sched/cputime.h +6 −3
  3. include/linux/sched/signal.h +0 −6
  4. init/init_task.c +0 −2
  5. kernel/fork.c +0 −6
  6. kernel/time/posix-cpu-timers.c +40 −33
include/linux/posix-timers.h+8−0
@@ -77,15 +77,23 @@ struct posix_cputimer_base { · 76 unmodified lines
7777 /**
7878 * posix_cputimers - Container for posix CPU timer related data
7979 * @bases: Base container for posix CPU clocks
80+ * @timers_active: Timers are queued.
81+ * @expiry_active: Timer expiry is active. Used for
82+ * process wide timers to avoid multiple
83+ * task trying to handle expiry concurrently
8084 *
8185 * Used in task_struct and signal_struct
8286 */
8387 struct posix_cputimers {
8488 struct posix_cputimer_base bases[CPUCLOCK_MAX];
89+ unsigned int timers_active;
90+ unsigned int expiry_active;
8591 };
8692
8793 static inline void posix_cputimers_init(struct posix_cputimers *pct)
8894 {
95+ pct->timers_active = 0;
96+ pct->expiry_active = 0;
8997 pct->bases[0].nextevt = U64_MAX;
9098 pct->bases[1].nextevt = U64_MAX;
9199 pct->bases[2].nextevt = U64_MAX;
include/linux/sched/cputime.h+6−3
@@ -70,7 +70,7 @@ void thread_group_sample_cputime(struct task_struct *tsk, u64 *samples); · 69 unmodified lines
7070 */
7171
7272 /**
73− * get_running_cputimer - return &tsk->signal->cputimer if cputimer is running
73+ * get_running_cputimer - return &tsk->signal->cputimer if cputimers are active
7474 *
7575 * @tsk: Pointer to target task.
7676 */
@@ -80,8 +80,11 @@ struct thread_group_cputimer *get_running_cputimer(struct task_struct *tsk) · 3 unmodified lines
8080 {
8181 struct thread_group_cputimer *cputimer = &tsk->signal->cputimer;
8282
83− /* Check if cputimer isn't running. This is accessed without locking. */
84− if (!READ_ONCE(cputimer->running))
83+ /*
84+ * Check whether posix CPU timers are active. If not the thread
85+ * group accounting is not active either. Lockless check.
86+ */
87+ if (!READ_ONCE(tsk->signal->posix_cputimers.timers_active))
8588 return NULL;
8689
8790 /*
include/linux/sched/signal.h+0−6
@@ -57,18 +57,12 @@ struct task_cputime_atomic { · 56 unmodified lines
5757 /**
5858 * struct thread_group_cputimer - thread group interval timer counts
5959 * @cputime_atomic: atomic thread group interval timers.
60− * @running: true when there are timers running and
61− * @cputime_atomic receives updates.
62− * @checking_timer: true when a thread in the group is in the
63− * process of checking for thread group timers.
6460 *
6561 * This structure contains the version of task_cputime, above, that is
6662 * used for thread group CPU timer calculations.
6763 */
6864 struct thread_group_cputimer {
6965 struct task_cputime_atomic cputime_atomic;
70− bool running;
71− bool checking_timer;
7266 };
7367
7468 struct multiprocess_signals {
init/init_task.c+0−2
@@ -30,8 +30,6 @@ static struct signal_struct init_signals = { · 29 unmodified lines
3030 .posix_timers = LIST_HEAD_INIT(init_signals.posix_timers),
3131 .cputimer = {
3232 .cputime_atomic = INIT_CPUTIME_ATOMIC,
33− .running = false,
34− .checking_timer = false,
3533 },
3634 #endif
3735 INIT_CPU_TIMERS(init_signals)
kernel/fork.c+0−6
@@ -1517,7 +1517,6 @@ void __cleanup_sighand(struct sighand_struct *sighand) · 1516 unmodified lines
15171517 }
15181518 }
15191519
1520−#ifdef CONFIG_POSIX_TIMERS
15211520 /*
15221521 * Initialize POSIX timer handling for a thread group.
15231522 */
@@ -1528,12 +1527,7 @@ static void posix_cpu_timers_init_group(struct signal_struct *sig) · 4 unmodified lines
15281527
15291528 cpu_limit = READ_ONCE(sig->rlim[RLIMIT_CPU].rlim_cur);
15301529 posix_cputimers_group_init(pct, cpu_limit);
1531− if (cpu_limit != RLIM_INFINITY)
1532− sig->cputimer.running = true;
15331530 }
1534−#else
1535−static inline void posix_cpu_timers_init_group(struct signal_struct *sig) { }
1536−#endif
15371531
15381532 static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
15391533 {
kernel/time/posix-cpu-timers.c+40−33
@@ -23,8 +23,10 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer); · 22 unmodified lines
2323 void posix_cputimers_group_init(struct posix_cputimers *pct, u64 cpu_limit)
2424 {
2525 posix_cputimers_init(pct);
26− if (cpu_limit != RLIM_INFINITY)
26+ if (cpu_limit != RLIM_INFINITY) {
2727 pct->bases[CPUCLOCK_PROF].nextevt = cpu_limit * NSEC_PER_SEC;
28+ pct->timers_active = true;
29+ }
2830 }
2931
3032 /*
@@ -248,8 +250,9 @@ static void update_gt_cputime(struct task_cputime_atomic *cputime_atomic, · 217 unmodified lines
248250 void thread_group_sample_cputime(struct task_struct *tsk, u64 *samples)
249251 {
250252 struct thread_group_cputimer *cputimer = &tsk->signal->cputimer;
253+ struct posix_cputimers *pct = &tsk->signal->posix_cputimers;
251254
252− WARN_ON_ONCE(!cputimer->running);
255+ WARN_ON_ONCE(!pct->timers_active);
253256
254257 proc_sample_cputime_atomic(&cputimer->cputime_atomic, samples);
255258 }
@@ -269,9 +272,10 @@ void thread_group_sample_cputime(struct task_struct *tsk, u64 *samples) · 13 unmodified lines
269272 static void thread_group_start_cputime(struct task_struct *tsk, u64 *samples)
270273 {
271274 struct thread_group_cputimer *cputimer = &tsk->signal->cputimer;
275+ struct posix_cputimers *pct = &tsk->signal->posix_cputimers;
272276
273277 /* Check if cputimer isn't running. This is accessed without locking. */
274− if (!READ_ONCE(cputimer->running)) {
278+ if (!READ_ONCE(pct->timers_active)) {
275279 struct task_cputime sum;
276280
277281 /*
@@ -283,13 +287,13 @@ static void thread_group_start_cputime(struct task_struct *tsk, u64 *samples) · 5 unmodified lines
283287 update_gt_cputime(&cputimer->cputime_atomic, &sum);
284288
285289 /*
286− * We're setting cputimer->running without a lock. Ensure
287− * this only gets written to in one operation. We set
288− * running after update_gt_cputime() as a small optimization,
289− * but barriers are not required because update_gt_cputime()
290+ * We're setting timers_active without a lock. Ensure this
291+ * only gets written to in one operation. We set it after
292+ * update_gt_cputime() as a small optimization, but
293+ * barriers are not required because update_gt_cputime()
290294 * can handle concurrent updates.
291295 */
292− WRITE_ONCE(cputimer->running, true);
296+ WRITE_ONCE(pct->timers_active, true);
293297 }
294298 proc_sample_cputime_atomic(&cputimer->cputime_atomic, samples);
295299 }
@@ -313,9 +317,10 @@ static u64 cpu_clock_sample_group(const clockid_t clkid, struct task_struct *p, · 17 unmodified lines
313317 bool start)
314318 {
315319 struct thread_group_cputimer *cputimer = &p->signal->cputimer;
320+ struct posix_cputimers *pct = &p->signal->posix_cputimers;
316321 u64 samples[CPUCLOCK_MAX];
317322
318− if (!READ_ONCE(cputimer->running)) {
323+ if (!READ_ONCE(pct->timers_active)) {
319324 if (start)
320325 thread_group_start_cputime(p, samples);
321326 else
@@ -834,10 +839,10 @@ static void check_thread_timers(struct task_struct *tsk, · 512 unmodified lines
834839
835840 static inline void stop_process_timers(struct signal_struct *sig)
836841 {
837− struct thread_group_cputimer *cputimer = &sig->cputimer;
842+ struct posix_cputimers *pct = &sig->posix_cputimers;
838843
839− /* Turn off cputimer->running. This is done without locking. */
840− WRITE_ONCE(cputimer->running, false);
844+ /* Turn off the active flag. This is done without locking. */
845+ WRITE_ONCE(pct->timers_active, false);
841846 tick_dep_clear_signal(sig, TICK_DEP_BIT_POSIX_TIMER);
842847 }
843848
@@ -877,17 +882,17 @@ static void check_process_timers(struct task_struct *tsk, · 33 unmodified lines
877882 unsigned long soft;
878883
879884 /*
880− * If cputimer is not running, then there are no active
881− * process wide timers (POSIX 1.b, itimers, RLIMIT_CPU).
885+ * If there are no active process wide timers (POSIX 1.b, itimers,
886+ * RLIMIT_CPU) nothing to check.
882887 */
883− if (!READ_ONCE(sig->cputimer.running))
888+ if (!READ_ONCE(pct->timers_active))
884889 return;
885890
886891 /*
887892 * Signify that a thread is checking for process timers.
888893 * Write access to this field is protected by the sighand lock.
889894 */
890− sig->cputimer.checking_timer = true;
895+ pct->timers_active = true;
891896
892897 /*
893898 * Collect the current process totals. Group accounting is active
@@ -933,7 +938,7 @@ static void check_process_timers(struct task_struct *tsk, · 39 unmodified lines
933938 if (expiry_cache_is_inactive(pct))
934939 stop_process_timers(sig);
935940
936− sig->cputimer.checking_timer = false;
941+ pct->expiry_active = false;
937942 }
938943
939944 /*
@@ -1027,39 +1032,41 @@ task_cputimers_expired(const u64 *sample, struct posix_cputimers *pct) · 87 unmodified lines
10271032 */
10281033 static inline bool fastpath_timer_check(struct task_struct *tsk)
10291034 {
1035+ struct posix_cputimers *pct = &tsk->posix_cputimers;
10301036 struct signal_struct *sig;
10311037
1032− if (!expiry_cache_is_inactive(&tsk->posix_cputimers)) {
1038+ if (!expiry_cache_is_inactive(pct)) {
10331039 u64 samples[CPUCLOCK_MAX];
10341040
10351041 task_sample_cputime(tsk, samples);
1036− if (task_cputimers_expired(samples, &tsk->posix_cputimers))
1042+ if (task_cputimers_expired(samples, pct))
10371043 return true;
10381044 }
10391045
10401046 sig = tsk->signal;
1047+ pct = &sig->posix_cputimers;
10411048 /*
1042− * Check if thread group timers expired when the cputimer is
1043− * running and no other thread in the group is already checking
1044− * for thread group cputimers. These fields are read without the
1045− * sighand lock. However, this is fine because this is meant to
1046− * be a fastpath heuristic to determine whether we should try to
1047− * acquire the sighand lock to check/handle timers.
1049+ * Check if thread group timers expired when timers are active and
1050+ * no other thread in the group is already handling expiry for
1051+ * thread group cputimers. These fields are read without the
1052+ * sighand lock. However, this is fine because this is meant to be
1053+ * a fastpath heuristic to determine whether we should try to
1054+ * acquire the sighand lock to handle timer expiry.
10481055 *
1049− * In the worst case scenario, if 'running' or 'checking_timer' gets
1050− * set but the current thread doesn't see the change yet, we'll wait
1051− * until the next thread in the group gets a scheduler interrupt to
1052− * handle the timer. This isn't an issue in practice because these
1053− * types of delays with signals actually getting sent are expected.
1056+ * In the worst case scenario, if concurrently timers_active is set
1057+ * or expiry_active is cleared, but the current thread doesn't see
1058+ * the change yet, the timer checks are delayed until the next
1059+ * thread in the group gets a scheduler interrupt to handle the
1060+ * timer. This isn't an issue in practice because these types of
1061+ * delays with signals actually getting sent are expected.
10541062 */
1055− if (READ_ONCE(sig->cputimer.running) &&
1056− !READ_ONCE(sig->cputimer.checking_timer)) {
1063+ if (READ_ONCE(pct->timers_active) && !READ_ONCE(pct->expiry_active)) {
10571064 u64 samples[CPUCLOCK_MAX];
10581065
10591066 proc_sample_cputime_atomic(&sig->cputimer.cputime_atomic,
10601067 samples);
10611068
1062− if (task_cputimers_expired(samples, &sig->posix_cputimers))
1069+ if (task_cputimers_expired(samples, pct))
10631070 return true;
10641071 }
10651072

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t