• Arnaldo Carvalho de Melo's avatar
    perf thread: Allow references to thread objects after machine__exit() · 4c00af0e
    Arnaldo Carvalho de Melo authored
    Threads are created when we either synthesize PERF_RECORD_FORK events
    for pre-existing threads or when we receive PERF_RECORD_FORK events from
    the kernel as new threads get created.
    
    We then keep them in machine->threads[].entries rb trees till when we
    receive a PERF_RECORD_EXIT, i.e. that thread terminated.
    
    The thread object has a reference count that is grabbed when, for
    instance, we keep that thread referenced in struct hist_entry, in 'perf
    report' and 'perf top'.
    
    When we receive a PERF_RECORD_EXIT we remove the thread object from the
    rb tree and move it to the corresponding machine->threads[].dead list,
    then we do a thread__put(), dropping the reference we had for keeping it
    in the rb tree.
    
    In thread__put() we were assuming that when the reference count hit zero
    we should remove it from the dead list by simply doing a
    list_del_init(&thread->node).
    
    That works well when all the thread lifetime is during the machine that
    has the list heads lifetime, since we know that we can do the
    list_del_init() and it will update the 'dead' list_head.
    
    But in 'perf sched lat' we were doing:
    
        machine__new() (via perf_session__new)
    
        process events, grabbing refcounts to keep those thread objects
        in 'perf sched' local data structures.
    
        machine__exit() (via perf_session__delete) which would delete the
        'dead' list heads.
    
        And then doing the final thread__put() for the refcounts 'perf sched'
        rightfully obtained for keeping those thread object references.
    
        b00m, since thread__put() would do the list_del_init() touching
        a dead dead list head.
    
    Fix it by removing all the dead threads from machine->threads[].dead at
    machine__exit(), since whatever is there should have refcounts taken by
    things like 'perf sched lat', and make thread__put() check if the thread
    is in a linked list before removing it from that list.
    Reported-by: default avatarWei Li <liwei391@huawei.com>
    Link: https://lkml.kernel.org/r/20190508143648.8153-1-liwei391@huawei.com
    Cc: Adrian Hunter <adrian.hunter@intel.com>
    Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
    Cc: Jiri Olsa <jolsa@kernel.org>
    Cc: Namhyung Kim <namhyung@kernel.org>
    Cc: Peter Zijlstra <peterz@infradead.org>
    Cc: Zhipeng Xie <xiezhipeng1@huawei.com>
    Link: https://lkml.kernel.org/r/20190704194355.GI10740@kernel.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
    4c00af0e
machine.c 65.3 KB