Search code examples
cglibc

Where is the logic of comparing '__libc_multiple_threads'?


In analyzing iofclose.c file, I found some strange part of that.

// glibc-2.23.90/libio/iofclose.c:53

 if (fp->_IO_file_flags & _IO_IS_FILEBUF)
    _IO_un_link ((struct _IO_FILE_plus *) fp);

  _IO_acquire_lock (fp); // !!!!! This part !!!!!
 ...

As You see this source, fclose() calls _IO_acquire_lock internally.

And _IO_acquire_lock calls _IO_lock_lock below this.

//glibc-2.23.90/sysdeps/nptl/stdio-lock.h:39

#define _IO_lock_lock(_name) \
  do {                                        \
    void *__self = THREAD_SELF;                           \
    if ((_name).owner != __self)                          \
      {                                       \
    lll_lock ((_name).lock, LLL_PRIVATE);                     \
...

In _IO_lock_lock, void *__self = THREAD_SELF; and if ((_name).owner != __self) logic is appeared like this.

0x7f9a21eca393 <_IO_new_fclose+291>: mov    r8,QWORD PTR fs:0x10
   0x7f9a21eca39c <_IO_new_fclose+300>: cmp    r8,QWORD PTR [rdx+0x8]
   0x7f9a21eca3a0 <_IO_new_fclose+304>: je     0x7f9a21eca3e2 <_IO_new_fclose+370>
   0x7f9a21eca3a2 <_IO_new_fclose+306>: mov    esi,0x1
...

Then, if lll_lock((_name).lock, LLL_PRIVATE); is called after branch command, lll_lock() is proceeded like this.

0x7f9a21eca3a2 <_IO_new_fclose+306>: mov    esi,0x1
   0x7f9a21eca3a7 <_IO_new_fclose+311>: xor    eax,eax
   0x7f9a21eca3a9 <_IO_new_fclose+313>:
    cmp    DWORD PTR [rip+0x35c390],0x0        # 0x7f9a22226740 <__libc_multiple_threads>
   0x7f9a21eca3b0 <_IO_new_fclose+320>: je     0x7f9a21eca3ba <_IO_new_fclose+330>
...

In this assembly, logic of comparing __libc_multiple_threads is being.

But, when I saw lll_lock() code, I can't find that logic...

//glibc-2.23.90/sysdeps/unix/sysv/linux/sparc/lowlevellock.h:51

static inline void
__attribute__ ((always_inline))
__lll_lock (int *futex, int private)
{
  int val = atomic_compare_and_exchange_val_24_acq (futex, 1, 0);

  if (__glibc_unlikely (val != 0))
    {
      if (__builtin_constant_p (private) && private == LLL_PRIVATE)
    __lll_lock_wait_private (futex);
      else
    __lll_lock_wait (futex, private);
    }
}
#define lll_lock(futex, private) __lll_lock (&(futex), private)

How happened this situation?

Where can i find these assembly logic in this c source code?


Solution

  • You're reading the source code for the SPARC locking implementation, but the assembly you've shown is x86. I think the code you want is in sysdeps/unix/sysv/linux/x86/lowlevellock.h. There you'll see it tests if (is_single_thread). This expands to SINGLE_THREAD_P, which is defined in sysdeps/unix/sysv/linux/single-thread.h to expand to __glibc_likely (__libc_multiple_threads == 0).