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

GLOB_ERROR shared across threads #6822

Open
p5pRT opened this issue Oct 7, 2003 · 5 comments
Open

GLOB_ERROR shared across threads #6822

p5pRT opened this issue Oct 7, 2003 · 5 comments

Comments

@p5pRT
Copy link

p5pRT commented Oct 7, 2003

Migrated from rt.perl.org#24138 (status was 'open')

Searchable as RT24138$

@p5pRT
Copy link
Author

p5pRT commented Oct 7, 2003

From mjp-perl-ZYsBlwkHGFY@pilcrow.madison.wi.us

Created by perlbuild@box.securepipe.com

Is it just me, or is File​::Glob​::GLOB_ERROR() inappropriately
returning a global, shared value, rather than a thread-specific
one?

  $ cat globbit.pl
  use v5.8.1;
  use threads;
  use File​::Glob '​:glob';
  use strict;
 
  sub e($) {
  my $g = shift;
  my $t = threads->tid;
  print "Thread ", threads->tid, "\n";
  print "\tinitial GLOB_ERROR​: ", &GLOB_ERROR, "\n";
  bsd_glob($g);
  print "\tfinal GLOB_ERROR​: ", &GLOB_ERROR, "\n";
  }
 
  for (qw|/root/eacces* /tmp /*/*/*/*/*/*/*|) {
  threads->create(\&e, $_)->join;
  }
  __END__

  $ perl globbit.pl
  Thread 1
  initial GLOB_ERROR​: 0
  final GLOB_ERROR​: -2
  Thread 2
  initial GLOB_ERROR​: -2
  final GLOB_ERROR​: 0
  Thread 3
  initial GLOB_ERROR​: 0
  final GLOB_ERROR​: -2

Also observed under 5.8.0, FWIW.

Perl Info

Flags:
    category=library
    severity=medium

Site configuration information for perl v5.8.1:

Configured by mjp at Fri Sep 26 09:06:03 CDT 2003.

Summary of my perl5 (revision 5.0 version 8 subversion 1) configuration:
  Platform:
    osname=linux, osvers=2.4.20-19.7, archname=i686-linux-thread-multi
    uname='linux box.securepipe.com 2.4.20-19.7 #1 tue jul 15 13:44:14 edt 2003 i686 unknown '
    config_args='-dse'
    hint=previous, useposix=true, d_sigaction=define
    usethreads=define use5005threads=undef useithreads=define usemultiplicity=define
    useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
    use64bitint=undef use64bitall=undef uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='gcc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/gdbm',
    optimize='-O2',
    cppflags='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -fno-strict-aliasing -I/usr/local/include -I/usr/include/gdbm -D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/gdbm'
    ccversion='', gccversion='2.96 20000731 (Red Hat Linux 7.3 2.96-113)', gccosandvers=''
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=4, prototype=define
  Linker and Libraries:
    ld='gcc', ldflags =' -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib
    libs=-lnsl -lndbm -lgdbm -ldl -lm -lcrypt -lutil -lpthread -lc
    perllibs=-lnsl -ldl -lm -lcrypt -lutil -lpthread -lc
    libc=/lib/libc-2.2.5.so, so=so, useshrplib=true, libperl=libperl.so
    gnulibc_version='2.2.5'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-rdynamic -Wl,-rpath,/home/mjp/opt/lib/perl5/5.8.1/i686-linux-thread-multi/CORE'
    cccdlflags='-fpic', lddlflags='-shared -L/usr/local/lib'

Locally applied patches:
    


@INC for perl v5.8.1:
    /home/mjp/opt/lib/perl5/5.8.1/i686-linux-thread-multi
    /home/mjp/opt/lib/perl5/5.8.1
    /home/mjp/opt/lib/perl5/site_perl/5.8.1/i686-linux-thread-multi
    /home/mjp/opt/lib/perl5/site_perl/5.8.1
    /home/mjp/opt/lib/perl5/site_perl
    .


Environment for perl v5.8.1:
    HOME=/home/mjp
    LANG=en_US.iso885915
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/home/mjp/opt/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/mjp/bin
    PERL_BADLANG (unset)
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Oct 7, 2003

From @rgs

mjp-perl-ZYsBlwkHGFY@​pilcrow.madison.wi.us (via RT) wrote​:

Is it just me, or is File​::Glob​::GLOB_ERROR() inappropriately
returning a global, shared value, rather than a thread-specific
one?

No, GLOB_ERROR is actually stored in a thread specific place.
What happens is that it's not zero'ed again when the new interpreter
for the new thread is cloned. This is considered normal behaviour :
the new thread starts where the one who created it left.

I don't know if it's possible to register code to be called at
interpreter clone time. It so, we could make it reset GLOB_ERROR.

$ cat globbit.pl
use v5.8.1;
use threads;
use File​::Glob '​:glob';
use strict;

sub e($) {
my $g = shift;
my $t = threads->tid;
print "Thread ", threads->tid, "\n";
print "\tinitial GLOB_ERROR​: ", &GLOB_ERROR, "\n";
bsd_glob($g);
print "\tfinal GLOB_ERROR​: ", &GLOB_ERROR, "\n";
}

for (qw|/root/eacces* /tmp /*/*/*/*/*/*/*|) {
threads->create(\&e, $_)->join;
}
__END__

$ perl globbit.pl
Thread 1
initial GLOB_ERROR​: 0
final GLOB_ERROR​: -2
Thread 2
initial GLOB_ERROR​: -2
final GLOB_ERROR​: 0
Thread 3
initial GLOB_ERROR​: 0
final GLOB_ERROR​: -2

@p5pRT
Copy link
Author

p5pRT commented Oct 8, 2003

From mjp-perl@pilcrow.madison.wi.us

[rafael - Tue Oct 7 15​:41​:03 2003]​:

No, GLOB_ERROR is actually stored in a thread specific place.

Hmm -- could you try the following example? For me, Thread #1 changes
the return value of GLOB_ERROR() out from under (the older) Thread #0​:

  $ cat glob2.pl
  use threads;
  use File​::Glob qw|​:glob|;
  use strict;

  sub globerr() {
  print "Thread ", threads->tid, " GLOB_ERROR()​:",
  GLOB_ERROR(), "\n";
  }
 
  sub e($) {
  my $g = shift;
  print "calling glob()\n";
  bsd_glob($g);
  globerr();
  }

  e("/tmp");
  threads->create(\&e, '/root/eacces*')->join;
  globerr()

  $ perl glob2.pl
  Thread 0 calling glob()
  Thread 0 GLOB_ERROR()​:0
  Thread 1 calling glob()
  Thread 1 GLOB_ERROR()​:-2
  Thread 0 GLOB_ERROR()​:-2

Same config as before. It surely looks to me like the value being
returned is shared across threads​: TID 0 glob()s, checks error, spawns
TID 1 to do the same; after TID 1 completes, TID 0 checks error again,
and (voila) it has changed.

I think I understand what the XS is trying to do, I just don't see that
behavior.

I don't know if it's possible to register code to be called at
interpreter clone time. It so, we could make it reset GLOB_ERROR.

ISTM that storing the C return value of glob() in an ordinary, unshared
package lexical, and having GLOB_ERROR() fetch that, would have the
desired effect.

Regards,
Mike
--
Michael J. Pomraning
mjp DASH perl AT pilcrow DOT madison DOT wi DOT us

@p5pRT
Copy link
Author

p5pRT commented Oct 8, 2003

From @rgs

According to Michael J.Pomraning :

No, GLOB_ERROR is actually stored in a thread specific place.

Hmm -- could you try the following example? For me, Thread #1 changes
the return value of GLOB_ERROR() out from under (the older) Thread #0​:

I can see that. I don't know why it behaves that way ; I just
hope this doesn't indicate a bug in the code generated by
ExtUtils​::Constant or in MY_CTX.

$ cat glob2.pl
use threads;
use File​::Glob qw|​:glob|;
use strict;

sub globerr() {
print "Thread ", threads->tid, " GLOB_ERROR()​:",
GLOB_ERROR(), "\n";
}

sub e($) {
my $g = shift;
print "calling glob()\n";
bsd_glob($g);
globerr();
}

e("/tmp");
threads->create(\&e, '/root/eacces*')->join;
globerr()

$ perl glob2.pl
Thread 0 calling glob()
Thread 0 GLOB_ERROR()​:0
Thread 1 calling glob()
Thread 1 GLOB_ERROR()​:-2
Thread 0 GLOB_ERROR()​:-2

Same config as before. It surely looks to me like the value being
returned is shared across threads​: TID 0 glob()s, checks error, spawns
TID 1 to do the same; after TID 1 completes, TID 0 checks error again,
and (voila) it has changed.

I think I understand what the XS is trying to do, I just don't see that
behavior.

I don't know if it's possible to register code to be called at
interpreter clone time. It so, we could make it reset GLOB_ERROR.

ISTM that storing the C return value of glob() in an ordinary, unshared
package lexical, and having GLOB_ERROR() fetch that, would have the
desired effect.

@p5pRT
Copy link
Author

p5pRT commented Oct 8, 2003

From mjp-perl@pilcrow.madison.wi.us

To return briefly to my first example​:

[rafael - Tue Oct 7 15​:41​:03 2003]​:

What happens is that it's not zero'ed again when the new interpreter
for the new thread is cloned. This is considered normal behaviour :
the new thread starts where the one who created it left.

All glob()ing threads were serially spawned and join()ed by the same
thread. So, IIUC, they should all have cloned that thread's
MY_CXT.x_GLOB_ERROR, and therefore all reported the same "initial"
value for GLOB_ERROR()? So, the fact that they didn't do so is
probably evidence of this bug, or a very similar one, yes?

(I don't mean to be pointed, but I'd like to make sure I understand all
the issues, and the mechanics of thread creation are murky to me.)

Thanks for your attention to this! It's been bugging me since Feb.

Regards,
Mike

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

2 participants