@@ -11773,7 +11773,8 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer)
1177311773
1177411774 event = container_of (hrtimer , struct perf_event , hw .hrtimer );
1177511775
11776- if (event -> state != PERF_EVENT_STATE_ACTIVE )
11776+ if (event -> state != PERF_EVENT_STATE_ACTIVE ||
11777+ event -> hw .state & PERF_HES_STOPPED )
1177711778 return HRTIMER_NORESTART ;
1177811779
1177911780 event -> pmu -> read (event );
@@ -11819,15 +11820,20 @@ static void perf_swevent_cancel_hrtimer(struct perf_event *event)
1181911820 struct hw_perf_event * hwc = & event -> hw ;
1182011821
1182111822 /*
11822- * The throttle can be triggered in the hrtimer handler.
11823- * The HRTIMER_NORESTART should be used to stop the timer,
11824- * rather than hrtimer_cancel(). See perf_swevent_hrtimer()
11823+ * Careful: this function can be triggered in the hrtimer handler,
11824+ * for cpu-clock events, so hrtimer_cancel() would cause a
11825+ * deadlock.
11826+ *
11827+ * So use hrtimer_try_to_cancel() to try to stop the hrtimer,
11828+ * and the cpu-clock handler also sets the PERF_HES_STOPPED flag,
11829+ * which guarantees that perf_swevent_hrtimer() will stop the
11830+ * hrtimer once it sees the PERF_HES_STOPPED flag.
1182511831 */
1182611832 if (is_sampling_event (event ) && (hwc -> interrupts != MAX_INTERRUPTS )) {
1182711833 ktime_t remaining = hrtimer_get_remaining (& hwc -> hrtimer );
1182811834 local64_set (& hwc -> period_left , ktime_to_ns (remaining ));
1182911835
11830- hrtimer_cancel (& hwc -> hrtimer );
11836+ hrtimer_try_to_cancel (& hwc -> hrtimer );
1183111837 }
1183211838}
1183311839
@@ -11871,12 +11877,14 @@ static void cpu_clock_event_update(struct perf_event *event)
1187111877
1187211878static void cpu_clock_event_start (struct perf_event * event , int flags )
1187311879{
11880+ event -> hw .state = 0 ;
1187411881 local64_set (& event -> hw .prev_count , local_clock ());
1187511882 perf_swevent_start_hrtimer (event );
1187611883}
1187711884
1187811885static void cpu_clock_event_stop (struct perf_event * event , int flags )
1187911886{
11887+ event -> hw .state = PERF_HES_STOPPED ;
1188011888 perf_swevent_cancel_hrtimer (event );
1188111889 if (flags & PERF_EF_UPDATE )
1188211890 cpu_clock_event_update (event );
@@ -11950,12 +11958,14 @@ static void task_clock_event_update(struct perf_event *event, u64 now)
1195011958
1195111959static void task_clock_event_start (struct perf_event * event , int flags )
1195211960{
11961+ event -> hw .state = 0 ;
1195311962 local64_set (& event -> hw .prev_count , event -> ctx -> time );
1195411963 perf_swevent_start_hrtimer (event );
1195511964}
1195611965
1195711966static void task_clock_event_stop (struct perf_event * event , int flags )
1195811967{
11968+ event -> hw .state = PERF_HES_STOPPED ;
1195911969 perf_swevent_cancel_hrtimer (event );
1196011970 if (flags & PERF_EF_UPDATE )
1196111971 task_clock_event_update (event , event -> ctx -> time );
0 commit comments