[Sheepdog] [PATCH v3 06/13] trace: low-level trace infrastructure proper

MORITA Kazutaka morita.kazutaka at gmail.com
Mon Apr 9 04:47:08 CEST 2012


On Mon, Apr 9, 2012 at 10:28 AM, Liu Yuan <namei.unix at gmail.com> wrote:
> On 04/06/2012 12:09 AM, MORITA Kazutaka wrote:
>
>> At Thu,  1 Mar 2012 10:20:18 +0800,
>> Liu Yuan wrote:
>>>
>>> +}
>>> +
>>> +notrace struct caller *trace_lookup_ip(unsigned long ip, int create)
>>> +{
>>> +    int h = trace_hash(ip);
>>> +    struct hlist_head *head = trace_hashtable + h;
>>> +    struct hlist_node *node;
>>> +    struct ipinfo info;
>>> +    struct caller *new = NULL;
>>> +
>>> +    pthread_mutex_lock(&trace_lock);
>>> +    if (hlist_empty(head))
>>
>> hlist_empty() calls trace_lookup_ip() again if it is not inlined, and
>> it results in a deadlock.
>>
>> How about preventing a recursive call of trace_lookup_ip()?
>>
>> E.g.:
>>
>> notrace struct caller *trace_lookup_ip(unsigned long ip, int create)
>> {
>>         int h;
>>         struct hlist_head *head;
>>         struct hlist_node *node;
>>         struct ipinfo info;
>>         struct caller *new = NULL;
>>         static __thread int looking_up_ip;
>>
>>         if (looking_up_ip)
>>                 return NULL;
>>
>>         looking_up_ip = 1;
>>
>>         pthread_mutex_lock(&trace_lock);
>>
>>         ...
>>
>>         pthread_mutex_unlock(&trace_lock);
>>
>>         looking_up_ip = 0;
>>         return new;
>> }
>>
>
>
> Nope, this bring more problems than it resolves:
>
> 1) return NULL while there entry does exist will break current trace logic

Is it difficult to change the logic?

> 2) __thread variable doesn't make any effect to exclude concurrent access

Concurrent access is excluded by pthread_mutex_lock().  The __thread
variable just prevents the same thread from re-entering the core of
trace_lookup_ip code.

> 3) one line function of hlist_empty() will be inline for any sane
> compiler if it supports it.

If we add --enable-debug to configure options, the function is not
inlined.

>
>
>>
>>> +            goto not_found;
>>> +
>>> +    hlist_for_each_entry(new, node, head, hash) {
>>> +            if (new->mcount == ip)
>>> +                    goto out;
>>> +    }
>>> +not_found:
>>> +    if (get_ipinfo(ip, &info) < 0) {
>>> +            dprintf("ip: %lx not found\n", ip);
>>> +            new = NULL;
>>> +            goto out;
>>> +    }
>>> +    if (create) {
>>> +            /* unlock to avoid deadlock */
>>> +            pthread_mutex_unlock(&trace_lock);
>>
>> I think we don't need unlock here if we prevent recursion.
>>
>>
>>> +            new = xzalloc(sizeof(*new));
>>> +            pthread_mutex_lock(&trace_lock);

IIUC, you call pthread_mutex_unlock()/lock() here because xzalloc()
will call another trace_lookup_ip() and it results in deadlock, yes?

I think this code is really hard to maintain because we cannot call
other functions which wouldn't be inlined.  In addition, it smells
like a race condition since other function can enter the core of
trace_lookup_ip() just after we release the lock here.

Thanks,

Kazutaka



More information about the sheepdog mailing list