Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cond_signal does not wake up a thread #12316

Closed
p5pRT opened this issue Aug 2, 2012 · 13 comments
Closed

cond_signal does not wake up a thread #12316

p5pRT opened this issue Aug 2, 2012 · 13 comments

Comments

@p5pRT
Copy link

p5pRT commented Aug 2, 2012

Migrated from rt.perl.org#114378 (status was 'rejected')

Searchable as RT114378$

@p5pRT
Copy link
Author

p5pRT commented Aug 2, 2012

From matti.linnanvuori@portalify.com

Created by matti@portalify.com

cond_signal does not wake another thread up even though I think it should.
The same problem appears in perl 5.10.0 in SLES 11 SP1.
The main thread joins the other thread forever​:

8/2/12 12​:19​:01.930 PM aplicom​: Failed to receive data from the socket​: Interrupted system call
8/2/12 12​:19​:01.930 PM aplicom​: Closing the socket
8/2/12 12​:19​:01.930 PM aplicom​: Killing the post thread
8/2/12 12​:19​:01.931 PM aplicom​: Locking to signal termination
8/2/12 12​:19​:01.931 PM aplicom​: Signaling the post thread to terminate
8/2/12 12​:19​:01.931 PM aplicom​: Joining the post thread

sub post {
  $SIG{'TERM'} = \&termination_flag;

  my $ua = LWP​::UserAgent->new;
  $ua->timeout( $configuration->{'timeout'} );

  while ($run) {
  my %post;
  {
  syslog LOG_DEBUG, "Locking to check for new location GeoJSON data";
  lock %location;
  until ( %location or not $run ) {
  syslog LOG_DEBUG, "Waiting for location GeoJSON data";
  cond_wait %location;
  }
  %post = %location;
  }
  if (%post) {
  my %feature;
  while ( my ( $id, $feature ) = each %post ) {
  $feature{$id} = encode_json $feature;
  }
  my $content = '{"type"​:"FeatureCollection","features"​:['
  . join( ',', values %feature ) . ']}';
  syslog LOG_INFO, "Posting location data $content";
  my $response = $ua->post(
  $configuration->{'url'},
  'Content-Type' => 'application/json',
  'Content' => $content
  );

  if ( $response->is_success ) {
  syslog LOG_INFO, $response->as_string;
  syslog LOG_DEBUG, "Locking to delete the posted location data";
  lock %location;
  while ( my ( $id, $feature ) = each %location ) {
  if ( $feature{$id} eq encode_json $feature ) {
  delete $location{$id};
  }
  }
  }
  else {
  syslog LOG_WARNING, $response->as_string;
  sleep $run * $configuration->{'retry'};
  }
  }
  }
  syslog LOG_NOTICE, "The post subroutine terminating";
}

until ( $thread = threads->create('post') or not $run ) {
  syslog LOG_ERR, "Failed to create the post thread​: $!. Retrying";
  sleep $run * $configuration->{'retry'};
}

if ( defined $thread ) {
  syslog LOG_NOTICE, "Killing the post thread";
  $thread->kill('SIGTERM');
}

syslog LOG_NOTICE, "Locking to signal termination";
lock %location;
syslog LOG_NOTICE, "Signaling the post thread to terminate";
cond_signal %location;

if ( defined $thread ) {
  syslog LOG_NOTICE, "Joining the post thread";
  $thread->join();
}

GNU gdb 6.3.50-20050815 (Apple version gdb-1752) (Sat Jan 28 03​:02​:46 UTC 2012)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin".
(gdb) attach 363
NRkm.!28DQ
Attaching to process 363.
Reading symbols for shared libraries . done
Reading symbols for shared libraries ......................................... done
Reading symbols for shared libraries + done
0x00007fff960ffe42 in __semwait_signal ()
(gdb) NRkm.!28DQ
Undefined command​: "NRkm". Try "help".
(gdb) bt
#0 0x00007fff960ffe42 in __semwait_signal ()
#1 0x00007fff93bec97e in pthread_join ()
#2 0x000000010d0f2def in XS_threads_join ()
#3 0x000000010cfe7a9c in Perl_pp_entersub ()
#4 0x000000010cfe5ec8 in Perl_runops_standard ()
#5 0x000000010cf8ce51 in perl_run ()
#6 0x000000010cf74d32 in main ()
(gdb) thread 1
[Switching to thread 1 (process 363), "com.apple.main-thread"]
0x00007fff960ffe42 in __semwait_signal ()
(gdb) bt
#0 0x00007fff960ffe42 in __semwait_signal ()
#1 0x00007fff93bec97e in pthread_join ()
#2 0x000000010d0f2def in XS_threads_join ()
#3 0x000000010cfe7a9c in Perl_pp_entersub ()
#4 0x000000010cfe5ec8 in Perl_runops_standard ()
#5 0x000000010cf8ce51 in perl_run ()
#6 0x000000010cf74d32 in main ()
(gdb) thread 2
[Switching to thread 2 (process 363)]
0x00007fff960ffbca in __psynch_cvwait ()
(gdb) bt
#0 0x00007fff960ffbca in __psynch_cvwait ()
#1 0x00007fff93c3a274 in _pthread_cond_wait ()
#2 0x000000010d23de78 in XS_threads__shared_cond_wait ()
#3 0x000000010cfe7a9c in Perl_pp_entersub ()
#4 0x000000010cfe5ec8 in Perl_runops_standard ()
#5 0x000000010cf8c6af in Perl_call_sv ()
#6 0x000000010d0f512b in ithread_mg_free ()
#7 0x00007fff93c368bf in _pthread_start ()
#8 0x00007fff93c39b75 in thread_start ()
(gdb)

Perl Info

Flags:
    category=library
    severity=medium
    module=threads::shared

Site configuration information for perl 5.12.3:

Configured by _mdnsresponder at Wed May 25 17:39:19 PDT 2011.

Summary of my perl5 (revision 5 version 12 subversion 3) configuration:
   
  Platform:
    osname=darwin, osvers=11.0, archname=darwin-thread-multi-2level
    uname='darwin doublemagnum.apple.com 11.0 darwin kernel version 11.0.0: wed dec 22 11:00:23 pst 2010; root:xnu-1699.18.1~1release_x86_64 x86_64 '
    config_args='-ds -e -Dprefix=/usr -Dccflags=-g  -pipe  -Dldflags= -Dman3ext=3pm -Duseithreads -Duseshrplib -Dinc_version_list=none -Dcc=llvm-gcc-4.2'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=define, usemultiplicity=define
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=define, use64bitall=define, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='llvm-gcc-4.2', ccflags ='-arch x86_64 -arch i386 -g -pipe -fno-common -DPERL_DARWIN -fno-strict-aliasing -fstack-protector -I/usr/local/include',
    optimize='-Os',
    cppflags='-g -pipe -fno-common -DPERL_DARWIN -fno-strict-aliasing -fstack-protector -I/usr/local/include'
    ccversion='', gccversion='4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)', gccosandvers=''
    intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='llvm-gcc-4.2 -mmacosx-version-min=10.7', ldflags ='-arch x86_64 -arch i386 -fstack-protector -L/usr/local/lib'
    libpth=/usr/local/lib /usr/lib
    libs=-ldbm -ldl -lm -lutil -lc
    perllibs=-ldl -lm -lutil -lc
    libc=, so=dylib, useshrplib=true, libperl=libperl.dylib
    gnulibc_version=''
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=bundle, d_dlsymun=undef, ccdlflags=' '
    cccdlflags=' ', lddlflags='-arch x86_64 -arch i386 -bundle -undefined dynamic_lookup -L/usr/local/lib -fstack-protector'

Locally applied patches:
    /Library/Perl/Updates/<version> comes before system perl directories
    installprivlib and installarchlib points to the Updates directory


@INC for perl 5.12.3:
    /Library/Perl/5.12/darwin-thread-multi-2level
    /Library/Perl/5.12
    /Network/Library/Perl/5.12/darwin-thread-multi-2level
    /Network/Library/Perl/5.12
    /Library/Perl/Updates/5.12.3/darwin-thread-multi-2level
    /Library/Perl/Updates/5.12.3
    /System/Library/Perl/5.12/darwin-thread-multi-2level
    /System/Library/Perl/5.12
    /System/Library/Perl/Extras/5.12/darwin-thread-multi-2level
    /System/Library/Perl/Extras/5.12
    .


Environment for perl 5.12.3:
    DYLD_LIBRARY_PATH (unset)
    HOME=/Users/matti
    LANG (unset)
    LANGUAGE (unset)
    LC_CTYPE=UTF-8
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin:/usr/local/git/bin
    PERL_BADLANG (unset)
    SHELL=/bin/bash




@p5pRT
Copy link
Author

p5pRT commented Aug 2, 2012

From mattilinnanvuori@yahoo.com

This a deadlock because the killing thread holds a lock while joining.

@p5pRT
Copy link
Author

p5pRT commented Aug 2, 2012

From [Unknown Contact. See original ticket]

This a deadlock because the killing thread holds a lock while joining.

@p5pRT
Copy link
Author

p5pRT commented Aug 2, 2012

From @iabyn

On Thu, Aug 02, 2012 at 02​:36​:34AM -0700, Matti Linnanvuori wrote​:

cond_signal does not wake another thread up even though I think it should.
The same problem appears in perl 5.10.0 in SLES 11 SP1.
The main thread joins the other thread forever​:

Its difficult to say for certain, since you don't provide complete code,
but it looks like the fault is here​:

lock %location;
syslog LOG_NOTICE, "Signaling the post thread to terminate";
cond_signal %location;

if ( defined $thread ) {
syslog LOG_NOTICE, "Joining the post thread";
$thread->join();
}

You don't unlock %location before trying to join the thread. Note that
cond_signal() itself does not unlock the variable (and so cond_wait()
hangs trying to relock the var).

So you probably need to wrap the lock and cond_signal lines above in a
{... } block, so that the lock is released before attempting to join

As a more general comment, I'd recommend try to avoid using cond_wait and
cond_signal wherever possible. They are a very low-level interface, and
are notoriously hard to get right. Use something higher level​: often
a simple perl-level lock is sufficient (it uses condition variables under
the hood to ensure that a process waiting on a lock gets woken up),
or possibly something like Thread​::Queue.

--
This is a great day for France!
  -- Nixon at Charles De Gaulle's funeral

@p5pRT
Copy link
Author

p5pRT commented Aug 2, 2012

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Aug 3, 2012

From mattilinnanvuori@yahoo.com

The bug was indeed in that the joining thread held the lock while the thread being joined waited
for the same lock in cond_wait. So this is not such a Perl bug, even though the warning that
cond_wait emits when used on an unlocked variable contributed to the bug, so the Perl
specification is partly to blame.

@p5pRT
Copy link
Author

p5pRT commented Aug 3, 2012

From [Unknown Contact. See original ticket]

The bug was indeed in that the joining thread held the lock while the thread being joined waited
for the same lock in cond_wait. So this is not such a Perl bug, even though the warning that
cond_wait emits when used on an unlocked variable contributed to the bug, so the Perl
specification is partly to blame.

@p5pRT
Copy link
Author

p5pRT commented Aug 3, 2012

From mattilinnanvuori@yahoo.com

What I meant that if Perl did not emit a warning when calling cond_signal on an unlocked
variable, I would not have locked the variable and so the bug would not have been written. The
no warnings 'threads' to avoid the warning seems such an unclean hack.

@p5pRT
Copy link
Author

p5pRT commented Aug 3, 2012

From [Unknown Contact. See original ticket]

What I meant that if Perl did not emit a warning when calling cond_signal on an unlocked
variable, I would not have locked the variable and so the bug would not have been written. The
no warnings 'threads' to avoid the warning seems such an unclean hack.

@p5pRT
Copy link
Author

p5pRT commented Aug 3, 2012

From @iabyn

On Thu, Aug 02, 2012 at 10​:21​:24PM -0700, Matti Linnanvuori via RT wrote​:

What I meant that if Perl did not emit a warning when calling cond_signal on an unlocked
variable, I would not have locked the variable and so the bug would not have been written. The
no warnings 'threads' to avoid the warning seems such an unclean hack.

I think you misunderstand. For correct use of cond_signal, you *must* hold
the lock first(*), so perl's warning is correct. Your mistake was in not
subsequently unlocking the var.

* because otherwise you can't be sure that the other thread has yet
reached cond_wait(), so the signal could get lost and deadlock ensue.
Which is another reason why you should avoid cond_wait/signal for most
code. It's too hard to get right.

--
"There's something wrong with our bloody ships today, Chatfield."
  -- Admiral Beatty at the Battle of Jutland, 31st May 1916.

@p5pRT
Copy link
Author

p5pRT commented Sep 21, 2016

From @dcollinsn

On Fri Aug 03 03​:09​:02 2012, davem wrote​:

I think you misunderstand. For correct use of cond_signal, you *must*
hold
the lock first(*), so perl's warning is correct. Your mistake was in
not
subsequently unlocking the var.

Closing as not a bug.

--
Respectfully,
Dan Collins

@p5pRT
Copy link
Author

p5pRT commented Sep 21, 2016

From [Unknown Contact. See original ticket]

On Fri Aug 03 03​:09​:02 2012, davem wrote​:

I think you misunderstand. For correct use of cond_signal, you *must*
hold
the lock first(*), so perl's warning is correct. Your mistake was in
not
subsequently unlocking the var.

Closing as not a bug.

--
Respectfully,
Dan Collins

@p5pRT
Copy link
Author

p5pRT commented Sep 21, 2016

@dcollinsn - Status changed from 'open' to 'rejected'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant