Commit 85ba2d862e521375a8ee01526c5c46b1f24bb4af

Authored by Roland McGrath
Committed by Linus Torvalds
1 parent 1f5a4ad97a

tracehook: wait_task_inactive

This extends wait_task_inactive() with a new argument so it can be used in
a "soft" mode where it will check for the task changing state unexpectedly
and back off.  There is no change to existing callers.  This lays the
groundwork to allow robust, noninvasive tracing that can try to sample a
blocked thread but back off safely if it wakes up.

Signed-off-by: Roland McGrath <roland@redhat.com>
Cc: Oleg Nesterov <oleg@tv-sign.ru>
Reviewed-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 5 changed files with 37 additions and 8 deletions Side-by-side Diff

arch/ia64/kernel/perfmon.c
... ... @@ -2626,7 +2626,7 @@
2626 2626 /*
2627 2627 * make sure the task is off any CPU
2628 2628 */
2629   - wait_task_inactive(task);
  2629 + wait_task_inactive(task, 0);
2630 2630  
2631 2631 /* more to come... */
2632 2632  
... ... @@ -4774,7 +4774,7 @@
4774 4774  
4775 4775 UNPROTECT_CTX(ctx, flags);
4776 4776  
4777   - wait_task_inactive(task);
  4777 + wait_task_inactive(task, 0);
4778 4778  
4779 4779 PROTECT_CTX(ctx, flags);
4780 4780  
include/linux/sched.h
... ... @@ -1882,9 +1882,13 @@
1882 1882 extern char *get_task_comm(char *to, struct task_struct *tsk);
1883 1883  
1884 1884 #ifdef CONFIG_SMP
1885   -extern void wait_task_inactive(struct task_struct * p);
  1885 +extern unsigned long wait_task_inactive(struct task_struct *, long match_state);
1886 1886 #else
1887   -#define wait_task_inactive(p) do { } while (0)
  1887 +static inline unsigned long wait_task_inactive(struct task_struct *p,
  1888 + long match_state)
  1889 +{
  1890 + return 1;
  1891 +}
1888 1892 #endif
1889 1893  
1890 1894 #define next_task(p) list_entry(rcu_dereference((p)->tasks.next), struct task_struct, tasks)
... ... @@ -176,7 +176,7 @@
176 176 return;
177 177 }
178 178 /* Must have done schedule() in kthread() before we set_task_cpu */
179   - wait_task_inactive(k);
  179 + wait_task_inactive(k, 0);
180 180 set_task_cpu(k, cpu);
181 181 k->cpus_allowed = cpumask_of_cpu(cpu);
182 182 k->rt.nr_cpus_allowed = 1;
... ... @@ -107,7 +107,7 @@
107 107 read_unlock(&tasklist_lock);
108 108  
109 109 if (!ret && !kill)
110   - wait_task_inactive(child);
  110 + ret = wait_task_inactive(child, TASK_TRACED) ? 0 : -ESRCH;
111 111  
112 112 /* All systems go.. */
113 113 return ret;
... ... @@ -1867,16 +1867,24 @@
1867 1867 /*
1868 1868 * wait_task_inactive - wait for a thread to unschedule.
1869 1869 *
  1870 + * If @match_state is nonzero, it's the @p->state value just checked and
  1871 + * not expected to change. If it changes, i.e. @p might have woken up,
  1872 + * then return zero. When we succeed in waiting for @p to be off its CPU,
  1873 + * we return a positive number (its total switch count). If a second call
  1874 + * a short while later returns the same number, the caller can be sure that
  1875 + * @p has remained unscheduled the whole time.
  1876 + *
1870 1877 * The caller must ensure that the task *will* unschedule sometime soon,
1871 1878 * else this function might spin for a *long* time. This function can't
1872 1879 * be called with interrupts off, or it may introduce deadlock with
1873 1880 * smp_call_function() if an IPI is sent by the same process we are
1874 1881 * waiting to become inactive.
1875 1882 */
1876   -void wait_task_inactive(struct task_struct *p)
  1883 +unsigned long wait_task_inactive(struct task_struct *p, long match_state)
1877 1884 {
1878 1885 unsigned long flags;
1879 1886 int running, on_rq;
  1887 + unsigned long ncsw;
1880 1888 struct rq *rq;
1881 1889  
1882 1890 for (;;) {
1883 1891  
... ... @@ -1899,8 +1907,11 @@
1899 1907 * return false if the runqueue has changed and p
1900 1908 * is actually now running somewhere else!
1901 1909 */
1902   - while (task_running(rq, p))
  1910 + while (task_running(rq, p)) {
  1911 + if (match_state && unlikely(p->state != match_state))
  1912 + return 0;
1903 1913 cpu_relax();
  1914 + }
1904 1915  
1905 1916 /*
1906 1917 * Ok, time to look more closely! We need the rq
1907 1918  
... ... @@ -1910,9 +1921,21 @@
1910 1921 rq = task_rq_lock(p, &flags);
1911 1922 running = task_running(rq, p);
1912 1923 on_rq = p->se.on_rq;
  1924 + ncsw = 0;
  1925 + if (!match_state || p->state == match_state) {
  1926 + ncsw = p->nivcsw + p->nvcsw;
  1927 + if (unlikely(!ncsw))
  1928 + ncsw = 1;
  1929 + }
1913 1930 task_rq_unlock(rq, &flags);
1914 1931  
1915 1932 /*
  1933 + * If it changed from the expected state, bail out now.
  1934 + */
  1935 + if (unlikely(!ncsw))
  1936 + break;
  1937 +
  1938 + /*
1916 1939 * Was it really running after all now that we
1917 1940 * checked with the proper locks actually held?
1918 1941 *
... ... @@ -1944,6 +1967,8 @@
1944 1967 */
1945 1968 break;
1946 1969 }
  1970 +
  1971 + return ncsw;
1947 1972 }
1948 1973  
1949 1974 /***