Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.93k stars 549 forks source link

accept leaks memory #4742

Closed p5pRT closed 20 years ago

p5pRT commented 22 years ago

Migrated from rt.perl.org#8120 (status was 'resolved')

Searchable as RT8120$

p5pRT commented 22 years ago

From root@schmorp.de

Created by root@cerebro.laendle

At least on my system\, each successful accept leaks memory. If I change the code in pp_accept from​:

  IoIFP(nstio) = PerlIO_fdopen(fd\, "r");   IoOFP(nstio) = PerlIO_fdopen(fd\, "w");

to​:

  IoIFP(nstio) = PerlIO_fdopen(fd\, "r");   IoOFP(nstio) = PerlIO_fdopen(dup(fd)\, "w");

then "everything works fine"\, in the sense that it doesn't leak anymore (but of course it's not a correct fix). I tried to debug this problem\, but as soon as I found out that PerlIO_fdopen calls PerlIO_openn which in turn calls PerlIO_fdopen my brain went into an endless loop and I gave up understanding how perlio works ;->

Perl Info ``` Flags: category=core severity=medium Site configuration information for perl v5.7.2: Configured by root at Mon Dec 17 04:14:59 CET 2001. Summary of my perl5 (revision 5.0 version 7 subversion 2 patch 13722) configuration: Platform: osname=linux, osvers=2.4, archname=i686-linux uname='linux cerebro 2.4.8-ac9 #7 smp thu aug 30 00:15:46 cest 2001 i686 unknown ' config_args='' hint=previous, useposix=true, d_sigaction=define usethreads=undef use5005threads=undef useithreads=undef usemultiplicity=undef useperlio=define d_sfio=undef uselargefiles=define usesocks=undef use64bitint=undef use64bitall=undef uselongdouble=undef usemymalloc=y, bincompat5005=undef Compiler: cc='gcc-2.95.4', ccflags ='-fno-strict-aliasing -I/usr/local/include -I/opt/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64', optimize='-g -Os -march=pentium -mcpu=pentium -funroll-loops', cppflags='-fno-strict-aliasing -I/usr/local/include -I/opt/include -fno-strict-aliasing -I/usr/local/include -I/opt/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-strict-aliasing -I/usr/local/include -I/opt/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64' ccversion='', gccversion='2.95.4 20010319 (prerelease)', 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-2.95.4', ldflags ='-L/usr/local/lib -L/opt/lib' libpth=/usr/local/lib /lib /usr/lib /opt/lib libs=-ldl -lm -lc -lcrypt perllibs=-ldl -lm -lc -lcrypt libc=/lib/libc-2.2.4.so, so=so, useshrplib=false, libperl=libperl.a Dynamic Linking: dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-rdynamic' cccdlflags='-fpic', lddlflags='-shared -L/usr/local/lib -L/opt/lib' Locally applied patches: DEVEL13686 @INC for perl v5.7.2: /opt/perl/lib/perl5 /opt/perl/lib/perl5 /opt/perl/lib/perl5 /opt/perl/lib/perl5 . Environment for perl v5.7.2: HOME=/root LANG (unset) LANGUAGE (unset) LC_CTYPE=de_DE LD_LIBRARY_PATH (unset) LOGDIR (unset) PATH=/root/s2:/root/s:/opt/qt/bin:/bin:/usr/bin:/usr/app/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/app/bin:/usr/app/sbin:/usr/X11/bin:/opt/jdk118/bin:/opt/bin:/opt/sbin:.:/root/cc/dejagnu/bin PERLDB_OPTS=ornaments=0 PERL_BADLANG (unset) SHELL=/bin/bash ```
p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

Marc Lehmann \pcg@​goof\.com writes​:

This is a bug report for perl from root@​cerebro.laendle\, generated with the help of perlbug 1.33 running under perl v5.7.2.

----------------------------------------------------------------- [Please enter your report here]

At least on my system\, each successful accept leaks memory. If I change the code in pp_accept from​:

IoIFP(nstio) = PerlIO_fdopen(fd\, "r"); IoOFP(nstio) = PerlIO_fdopen(fd\, "w");

to​:

IoIFP(nstio) = PerlIO_fdopen(fd\, "r"); IoOFP(nstio) = PerlIO_fdopen(dup(fd)\, "w");

then "everything works fine"\, in the sense that it doesn't leak anymore (but of course it's not a correct fix).

You are of course correct now I investigate it. We have two FILE * in the :stdio layer for the fd of the accepted socket. The fd refcounting inhibits the fclose() of one of the FILE * so we leak FILE * structures.

I tried to debug this problem\, but as soon as I found out that PerlIO_fdopen calls PerlIO_openn which in turn calls PerlIO_fdopen

No it doesn't ;-) Either PerlIO_openn() calls PerlIO_fdopen (-Uuseperlio - i.e. really fdopen()) PerlIO_fdopen() calls PerlIO_openn() (-Duseperlio).

my brain went into an endless loop and I gave up understanding how perlio works ;->

[Please do not change anything below this line] ----------------------------------------------------------------- --- Flags​: category=core severity=medium --- Site configuration information for perl v5.7.2​:

Configured by root at Mon Dec 17 04​:14​:59 CET 2001.

Summary of my perl5 (revision 5.0 version 7 subversion 2 patch 13722) configuration​: Platform​: osname=linux\, osvers=2.4\, archname=i686-linux uname='linux cerebro 2.4.8-ac9 #7 smp thu aug 30 00​:15​:46 cest 2001 i686 unknown ' config_args='' hint=previous\, useposix=true\, d_sigaction=define usethreads=undef use5005threads=undef useithreads=undef usemultiplicity=undef useperlio=define d_sfio=undef uselargefiles=define usesocks=undef use64bitint=undef use64bitall=undef uselongdouble=undef usemymalloc=y\, bincompat5005=undef Compiler​: cc='gcc-2.95.4'\, ccflags ='-fno-strict-aliasing -I/usr/local/include -I/opt/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'\, optimize='-g -Os -march=pentium -mcpu=pentium -funroll-loops'\, cppflags='-fno-strict-aliasing -I/usr/local/include -I/opt/include -fno-strict-aliasing -I/usr/local/include -I/opt/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-strict-aliasing -I/usr/local/include -I/opt/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64' ccversion=''\, gccversion='2.95.4 20010319 (prerelease)'\, 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-2.95.4'\, ldflags ='-L/usr/local/lib -L/opt/lib' libpth=/usr/local/lib /lib /usr/lib /opt/lib libs=-ldl -lm -lc -lcrypt perllibs=-ldl -lm -lc -lcrypt libc=/lib/libc-2.2.4.so\, so=so\, useshrplib=false\, libperl=libperl.a Dynamic Linking​: dlsrc=dl_dlopen.xs\, dlext=so\, d_dlsymun=undef\, ccdlflags='-rdynamic' cccdlflags='-fpic'\, lddlflags='-shared -L/usr/local/lib -L/opt/lib'

Locally applied patches​: DEVEL13686

--- @​INC for perl v5.7.2​: /opt/perl/lib/perl5 /opt/perl/lib/perl5 /opt/perl/lib/perl5 /opt/perl/lib/perl5 .

--- Environment for perl v5.7.2​: HOME=/root LANG (unset) LANGUAGE (unset) LC_CTYPE=de_DE LD_LIBRARY_PATH (unset) LOGDIR (unset) PATH=/root/s2​:/root/s​:/opt/qt/bin​:/bin​:/usr/bin​:/usr/app/bin​:/bin​:/sbin​:/usr/bin​:/usr/sbin​:/usr/local/bin​:/usr/local/sbin​:/usr/app/bin​:/usr/app/sbin​:/usr/X11/bin​:/opt/jdk118/bin​:/opt/bin​:/opt/sbin​:.​:/root/cc/dejagnu/bin PERLDB_OPTS=ornaments=0 PERL_BADLANG (unset) SHELL=/bin/bash -- Nick Ing-Simmons http​://www.ni-s.u-net.com/

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

Nick Ing-Simmons \nick@​ing\-simmons\.net writes​:

Marc Lehmann \pcg@​goof\.com writes​:

This is a bug report for perl from root@​cerebro.laendle\, generated with the help of perlbug 1.33 running under perl v5.7.2.

----------------------------------------------------------------- [Please enter your report here]

At least on my system\, each successful accept leaks memory. If I change the code in pp_accept from​:

IoIFP(nstio) = PerlIO_fdopen(fd\, "r"); IoOFP(nstio) = PerlIO_fdopen(fd\, "w");

to​:

IoIFP(nstio) = PerlIO_fdopen(fd\, "r"); IoOFP(nstio) = PerlIO_fdopen(dup(fd)\, "w");

then "everything works fine"\, in the sense that it doesn't leak anymore (but of course it's not a correct fix).

You are of course correct now I investigate it. We have two FILE * in the :stdio layer for the fd of the accepted socket. The fd refcounting inhibits the fclose() of one of the FILE * so we leak FILE * structures.

After trying a couple of other fixes and finding other problems with them //depot/perlio/...@​13923 does the dup as above (using PerlLIO_dup() though).

Far from convinced this is right long term fix but accept() is important in server apps and we cannot have it leaking.

FWIW I believe the PERLIO=perlio would not suffer the problem ;-)

-- Nick Ing-Simmons http​://www.ni-s.u-net.com/

p5pRT commented 22 years ago

From @nwc10

On Sat\, Dec 29\, 2001 at 04​:16​:57PM +0000\, Nick Ing-Simmons wrote​:

Nick Ing-Simmons \nick@​ing\-simmons\.net writes​:

Marc Lehmann \pcg@​goof\.com writes​:

[Please enter your report here]

At least on my system\, each successful accept leaks memory. If I change the code in pp_accept from​:

IoIFP(nstio) = PerlIO_fdopen(fd\, "r"); IoOFP(nstio) = PerlIO_fdopen(fd\, "w");

to​:

IoIFP(nstio) = PerlIO_fdopen(fd\, "r"); IoOFP(nstio) = PerlIO_fdopen(dup(fd)\, "w");

then "everything works fine"\, in the sense that it doesn't leak anymore (but of course it's not a correct fix).

You are of course correct now I investigate it. We have two FILE * in the :stdio layer for the fd of the accepted socket. The fd refcounting inhibits the fclose() of one of the FILE * so we leak FILE * structures.

After trying a couple of other fixes and finding other problems with them //depot/perlio/...@​13923 does the dup as above (using PerlLIO_dup() though).

Far from convinced this is right long term fix but accept() is

Nor am I. Any XS extension that does fdopen() via perlio is going to cause leaks in exactly the same way\, isn't it?

important in server apps and we cannot have it leaking.

I had a think about this previously but didn't think it worth mentioning. I don't actually see a problem with doing this even w.r.t. fileno and select. Even if the IoIFP and IoOFP have different numeric file descriptors\, as both descriptors are dup()s of each other\, both will be ready to read\, write or have urgent data read at the same time. [or your OS is wonky]

Nicholas Clark

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

Nicholas Clark \nick@​unfortu\.net writes​:

After trying a couple of other fixes and finding other problems with them //depot/perlio/...@​13923 does the dup as above (using PerlLIO_dup() though).

Far from convinced this is right long term fix but accept() is

Nor am I. Any XS extension that does fdopen() via perlio is going to cause leaks in exactly the same way\, isn't it?

Yes - any XS code which PerlIO_fdopen's the _same_ fd more than once is going to leak.

I had a "better" fix which had Stdio_close do

if (refcnt > 1) {   int copy = dup(fd);   fclose(stdio);   dup2(copy\,fd); }

But​: A. It did not work (it broke a test as it closed STDERR   on open(STDERR\,">&=STDOUT);   This seems to be due to (ab)use of refcnt to avoid closing   the standard handles - if it really does the fclose it really fcloses   stderr. B. It seems overly heavy on system calls when we are almost certainly   going to close both IoIFP and IoOFP of a socket

important in server apps and we cannot have it leaking.

I had a think about this previously but didn't think it worth mentioning. I don't actually see a problem with doing this even w.r.t. fileno and select. Even if the IoIFP and IoOFP have different numeric file descriptors\, as both descriptors are dup()s of each other\, both will be ready to read\, write or have urgent data read at the same time. [or your OS is wonky]

Agreed - the dup() is a sufficent fix but is messy.

Nicholas Clark -- Nick Ing-Simmons http​://www.ni-s.u-net.com/

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

On Sat\, Dec 29\, 2001 at 04​:16​:57PM +0000\, Nick Ing-Simmons \nick@​ing\-simmons\.net wrote​:

After trying a couple of other fixes and finding other problems with them //depot/perlio/...@​13923 does the dup as above (using PerlLIO_dup() though).

Far from convinced this is right long term fix

what does fileno do? And no\, my webserver isn't amused that now the number of filehandles is removed ;)

What about disabling refcounting (my webserver works fine since a few days with this\, and this refcounting sure looks like undocumented non-unix semantics)\, and what about the other patch I sent that gets rid of this magic fd limit that I already hit with my websevrer?

FWIW I believe the PERLIO=perlio would not suffer the problem ;-)

(what does PERLIO=perlio do? ;)

--   -----==- |   ----==-- _ |   ---==---(_)__ __ ____ __ Marc Lehmann +--   --==---/ / _ \/ // /\ \/ / pcg@​goof.com |e|   -=====/_/_//_/\_\,_/ /_/\_\ XX11-RIPE --+   The choice of a GNU generation |   |

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

\ writes​:

On Sat\, Dec 29\, 2001 at 04​:16​:57PM +0000\, Nick Ing-Simmons \nick@​ing\-simmons\.net wrote​:

After trying a couple of other fixes and finding other problems with them //depot/perlio/...@​13923 does the dup as above (using PerlLIO_dup() though).

Far from convinced this is right long term fix

what does fileno do?

fileno returns the fd number of IoIFP i.e. the accept return not the dup().

And no\, my webserver isn't amused that now the number of filehandles is removed ;)

I understand not sentence that ;-)

What about disabling refcounting (my webserver works fine since a few days with this\, and this refcounting sure looks like undocumented non-unix semantics)\,

It is undocumented threads semantics\, it ONLY works on UNIX right now as threads on non-UNIX are poorly. We could disable refcounting if you don't have threads enabled I guess\, but then we have to rework some things. Also threads and web servers should be useful together when they work right.

and what about the other patch I sent that gets rid of this magic fd limit that I already hit with my websevrer?

FWIW I believe the PERLIO=perlio would not suffer the problem ;-)

(what does PERLIO=perlio do? ;)

Having PERLIO=perlio in your enviroment Avoids stdio and hence leaks of FILE *

-- Nick Ing-Simmons http​://www.ni-s.u-net.com/

p5pRT commented 22 years ago

From @nwc10

On Sun\, Dec 30\, 2001 at 03​:52​:24PM +0000\, Nick Ing-Simmons wrote​:

\ writes​:

What about disabling refcounting (my webserver works fine since a few days with this\, and this refcounting sure looks like undocumented non-unix semantics)\,

It is undocumented threads semantics\, it ONLY works on UNIX right now as threads on non-UNIX are poorly. We could disable refcounting if you don't have threads enabled I guess\, but then we have to rework some things. Also threads and web servers should be useful together when they work right.

and what about the other patch I sent that gets rid of this magic fd limit that I already hit with my websevrer?

FWIW I believe the PERLIO=perlio would not suffer the problem ;-)

(what does PERLIO=perlio do? ;)

Having PERLIO=perlio in your enviroment Avoids stdio and hence leaks of FILE *

OK. I confess to doing something dangerous (thinking)

What stops us being able to build the windows pseudo threads on Unix? For debugging purposes. For whatever platforms it is easy to make work (eg just linux\, or just solaris\, or whatever). That way anyone without windows would able to break^Wtest their patches against pseudo-processes\, rather than dumping them all hoping that someone else (ie Arthur who is already too busy) will pick them up?

Or at least allow bits of windows pseudo fork on unix\, enough to test the per-thread malloc which appears to be one of the current causes of problems.

Meanwhile\, on the thought of refcounting file descriptors​:

I've deleted the message where I think this is written\, so it's from memory. Sorry for any errors.

IIRC under pseudo-fork all mallocs have to be per interpreter. Refcounting needs a global table that doesn't get implicitly free()ed\, so it can't be malloc()ed - if it were\, should the interpreter it happened to be allocated from terminate\, poof\, memory disappears. Hence it's staticly allocated.

Why does it need to be?

a​: Is symbol hiding and munching really so complete on Win32 that it's   impossible to access global malloc via any means? If not\, surely   PerlIO could use some suitable qualified name to allocate from global   malloc for its global tables

b​: If it is impossible to access global malloc\, would it instead be possible   to allocate the refcount table from a thread\, with an exit handler on that   thread. (I assume we must have some level of thread is exiting callback.   Is that rash?) If PerlIO's exit handler is called for the thread that   "owns" the global PerlIO table\, then is it possible for PerlIO to   1​: pick another thread and get that thread's data (enough to malloc)   2​: malloc a new buffer in this lucky thread   3​: copy the refcount table into the new buffer\, and change global pointers   to point into this buffer   4​: free the old refcount buffer in the about-to-exit thread.

  I believe that that fakes PerlIO a "global" alloction that will survive   even in a serial forking scenario. {fork and exit while 1} # Don't test this

Nicholas Clark

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

Nicholas Clark \nick@​unfortu\.net writes​:

It is undocumented threads semantics\, it ONLY works on UNIX right now as threads on non-UNIX are poorly. We could disable refcounting if you don't have threads enabled I guess\, but then we have to rework some things. Also threads and web servers should be useful together when they work right.

and what about the other patch I sent that gets rid of this magic fd limit that I already hit with my websevrer?

FWIW I believe the PERLIO=perlio would not suffer the problem ;-)

(what does PERLIO=perlio do? ;)

Having PERLIO=perlio in your enviroment Avoids stdio and hence leaks of FILE *

OK. I confess to doing something dangerous (thinking)

What stops us being able to build the windows pseudo threads on Unix?

They are real threads but pseudo-fork.

You could have pseudo-fork on Unix\, but it would not be windows pseudo fork - see below.

I think it would be a good idea to have way to try pseudo threads on UNIX.

The snag is that pseudo fork is entangled with other Win32 port issues. In particular the per-thread-malloc scheme relies on iperlsys.h re-directing all the calls to a "perl host". A "perl host" is a C++ object defined in win32/perlhost.h. Sadly perlhost.h is not just a declaration of the interface but also the implementation. Implementation is riddled with either Win32-isms (Direct calls to Win32 API\, or calls to win32_xxxx() wrappers defined in win32/win32.c.)

It does not have to be that way - but abstracting out the interface(s) so that we could provide a Unix implementation is a non-trivial - if worthwhile - exercise.

For debugging purposes. For whatever platforms it is easy to make work (eg just linux\, or just solaris\, or whatever). That way anyone without windows would able to break^Wtest their patches against pseudo-processes\, rather than dumping them all hoping that someone else (ie Arthur who is already too busy) will pick them up?

Or at least allow bits of windows pseudo fork on unix\, enough to test the per-thread malloc which appears to be one of the current causes of problems.

per-thread malloc is implemented by creating a new Vmem object for each thread. win32/vmem.h is - again! :-( - both definition an implementation. It is implemented in terms of Win32's HeapCreate and uses Win32's CRITICAL_SECTION for locking (of the shared heap(s)).

Regardless of the coding issues a Unix pseudo-thread scheme would need a way to implement multiple heaps and free memory back to OS by "destroying" the heap. (It it does not do that but really uses one big sbrk() slab of memory it is not going to find the bugs).

If I was going to do that I would try perl's malloc.c + a get-chunk-via-mmap() scheme. munmap() has approximately the same semantic as HeapFree(). There is a minor boot-strapping issue getting the threads thread struct malloced out of its own heap.

Meanwhile\, on the thought of refcounting file descriptors​:

I've deleted the message where I think this is written\, so it's from memory. Sorry for any errors.

IIRC under pseudo-fork all mallocs have to be per interpreter.

All malloc()'s are per-interpreter\, but not all memory allocation. There should still be PerlMemShared_malloc() and PerlMemShared_free() etc. defined or stubbed in iperlsys.h

The snag is that shared heap stuff seems to be buggy. The thread​::shared tests core-dump in the heap routines.

Refcounting needs a global table that doesn't get implicitly free()ed\, so it can't be malloc()ed - if it were\, should the interpreter it happened to be allocated from terminate\, poof\, memory disappears. Hence it's staticly allocated.

Why does it need to be?

a​: Is symbol hiding and munching really so complete on Win32 that it's impossible to access global malloc via any means?

Not at all. There are issues with shared address space becoming fragmented as heaps come and go but I think a small-ish global heap and per-thread heaps should co-exist fine.

If not\, surely PerlIO could use some suitable qualified name to allocate from global malloc for its global tables

That was/is the plan.

b​: If it is impossible to access global malloc\, would it instead be possible to allocate the refcount table from a thread\, with an exit handler on that thread. (I assume we must have some level of thread is exiting callback. Is that rash?)

If all is going to plan we have END blocks and perl level at-exit stuff. The worry is when things are not going according to plan - e.g. some(one|thing) does kill -9-oid TerminateThread() - possibly as a result of memory access violation.

If PerlIO's exit handler is called for the thread that "owns" the global PerlIO table\, then is it possible for PerlIO to 1​: pick another thread and get that thread's data (enough to malloc) 2​: malloc a new buffer in this lucky thread 3​: copy the refcount table into the new buffer\, and change global pointers to point into this buffer 4​: free the old refcount buffer in the about-to-exit thread.

You have the trick of coming up with cures that IMHO are worse than the disease.

The static 2048 limit is a transitional one.   - If we get shared-malloc debugged then we can just use that.   Awaiting Arthur or Sarathy to debug it.   - If not we can use malloc() on Unix and static table on Win32.   Win32 is unlikely to exceed 2048 fd's per-process and   I have a medium term plan for a :win32 layer which will   use Handle's directly avoing fd's altogether.

I believe that that fakes PerlIO a "global" alloction that will survive even in a serial forking scenario. {fork and exit while 1} # Don't test this

Nicholas Clark -- Nick Ing-Simmons http​://www.ni-s.u-net.com/

p5pRT commented 22 years ago

From @nwc10

On Thu\, Jan 10\, 2002 at 09​:00​:08AM +0000\, Nick Ing-Simmons wrote​:

Nicholas Clark \nick@​unfortu\.net writes​:

Or at least allow bits of windows pseudo fork on unix\, enough to test the per-thread malloc which appears to be one of the current causes of problems.

If I was going to do that I would try perl's malloc.c + a get-chunk-via-mmap() scheme. munmap() has approximately the same semantic as HeapFree(). There is a minor boot-strapping issue getting the threads thread struct malloced out of its own heap.

Related to this\, why does perl recommend not used perl's malloc on Linux?

If all is going to plan we have END blocks and perl level at-exit stuff. The worry is when things are not going according to plan - e.g. some(one|thing) does kill -9-oid TerminateThread() - possibly as a result of memory access violation.

Ah.

If PerlIO's exit handler is called for the thread that "owns" the global PerlIO table\, then is it possible for PerlIO to 1​: pick another thread and get that thread's data (enough to malloc) 2​: malloc a new buffer in this lucky thread 3​: copy the refcount table into the new buffer\, and change global pointers to point into this buffer 4​: free the old refcount buffer in the about-to-exit thread.

You have the trick of coming up with cures that IMHO are worse than the disease.

The static 2048 limit is a transitional one. - If we get shared-malloc debugged then we can just use that. Awaiting Arthur or Sarathy to debug it. - If not we can use malloc() on Unix and static table on Win32. Win32 is unlikely to exceed 2048 fd's per-process and I have a medium term plan for a :win32 layer which will use Handle's directly avoing fd's altogether.

Ah. The alarm/fork/whataver thoughts for win32 being another one. Maybe if you keep saying why my suggestions are very sick I might get better at suggesting the right thing earlier. Or maybe not.

Is "Win32 is unlikely to exceed 2048 fd's per-process" a bit like "640K should be enough for anyone"?

One truly lovely piece of software I had the pleasure to work with (or was that against?) was InterWorld Commerce exchange\, which was an e-commerce server originally implemented on NT\, then ported to Unix. It was multithreaded rather than multiprocess\, written in C++\, and liked to use over 256 file handles (which on Solaris confused Oracle because the Oracle libraries were using stdio in C\, which meant they couldn't open the tnsnames file after 255 file descriptors were busy). Oh\, the important bit of this ramble - I got the impression that on NT the process could be quite happy with the idea of having over 3000 file handles open across its threads.

Do people write very parallel threaded servers in perl on Windows?

Nicholas Clark

PS The joys of InterWorld remind me - it's checkout time from the CFT club​: -- ENOJOB http​://www.ccl4.org/~nick/CV.html

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

On Thursday\, January 10\, 2002\, at 12​:29 PM\, Nicholas Clark wrote​:

Or at least allow bits of windows pseudo fork on unix\, enough to test the per-thread malloc which appears to be one of the current causes of problems.

If I was going to do that I would try perl's malloc.c + a get-chunk-via-mmap() scheme. munmap() has approximately the same semantic as HeapFree(). There is a minor boot-strapping issue getting the threads thread struct malloced out of its own heap.

Related to this\, why does perl recommend not used perl's malloc on Linux?

The problems with per-thread malloc won't happen on unix. The problem resides in the lack of sense in win32/vmem.h

I am trying to solve the problem by making sure I always dealloc in the same thread I alloc. However XS writers will need to do that manually.

Or even\, you need to alloc/dealloc in the same perl_context\, as the memory system lives with the perl interpreter.

Arthur

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

Nicholas Clark \nick@​unfortu\.net writes​:

If I was going to do that I would try perl's malloc.c + a get-chunk-via-mmap() scheme. munmap() has approximately the same semantic as HeapFree(). There is a minor boot-strapping issue getting the threads thread struct malloced out of its own heap.

Related to this\, why does perl recommend not used perl's malloc on Linux?

Pass. I tend not to use perl's malloc for historical reasons to do with embedding - perl's malloc round-up-to-2**N scheme was a killer.

Ah. The alarm/fork/whataver thoughts for win32 being another one. Maybe if you keep saying why my suggestions are very sick I might get better at suggesting the right thing earlier. Or maybe not.

Well in this case I think there are easier ways of faking global malloc.

Is "Win32 is unlikely to exceed 2048 fd's per-process" a bit like "640K should be enough for anyone"?

It is my fundamental lack of trust in MS's C runtime DLL.

Numeric fd is faked on Win32 by the runtime which builds a table mapping fd to Handle. You can have lots of handles\, but I don't trust C runtime to have a grow-able table - I have not looked at the code in a while though so I may be doing it an injustice.

One truly lovely piece of software I had the pleasure to work with (or was that against?) was InterWorld Commerce exchange\, which was an e-commerce server originally implemented on NT\, then ported to Unix. It was multithreaded rather than multiprocess\, written in C++\, and liked to use over 256 file handles (which on Solaris confused Oracle because the Oracle libraries were using stdio in C\, which meant they couldn't open the tnsnames file after 255 file descriptors were busy). Oh\, the important bit of this ramble - I got the impression that on NT the process could be quite happy with the idea of having over 3000 file handles open across its threads.

Do people write very parallel threaded servers in perl on Windows?

Not with bleadperl :-(

Nicholas Clark

PS The joys of InterWorld remind me - it's checkout time from the CFT club​: -- Nick Ing-Simmons http​://www.ni-s.u-net.com/

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

Arthur Bergman \arthur@​contiller\.se writes​:

Related to this\, why does perl recommend not used perl's malloc on Linux?

The problems with per-thread malloc won't happen on unix. The problem resides in the lack of sense in win32/vmem.h

It isn't "lack of sense" to have separate Heap for each thread it is a deliberate design decision​:   - avoids need to MUXTEX lock every malloc/free   - allows all memory used by thread to be returned to OS even if   application forgets to free() things.

What is far less clear is why there is a Vmem layer on top of HeapXxxx() routines. Are HeapXxxxx too slow for direct use?

I am trying to solve the problem by making sure I always dealloc in the same thread I alloc. However XS writers will need to do that manually.

Or even\, you need to alloc/dealloc in the same perl_context\, as the memory system lives with the perl interpreter.

Given that we could should be able to have Perl_malloc_for(his_perl\,size) if it was easy to get a 'his_perl' (rather than 'my_perl') given a thread.

Arthur -- Nick Ing-Simmons http​://www.ni-s.u-net.com/

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

On Thursday\, January 10\, 2002\, at 01​:00 PM\, Nick Ing-Simmons wrote​:

From​: Nick Ing-Simmons \nick\.ing\-simmons@​elixent\.com Date​: Thu Jan 10\, 2002 01​:00​:33 PM Europe/Stockholm To​: arthur@​contiller.se Cc​: Nicholas Clark \nick@​unfortu\.net\, gsar@​activestate.com\, Nick Ing-Simmons \nick\.ing\-simmons@​elixent\.com\, Nick Ing-Simmons
\nick@​ing\-simmons\.net\, perl5-porters@​perl.org Subject​: Re​: [ID 20011223.001] accept leaks memory Reply-To​: Nick Ing-Simmons \nick\.ing\-simmons@​elixent\.com

Arthur Bergman \arthur@​contiller\.se writes​:

Related to this\, why does perl recommend not used perl's malloc on Linux?

The problems with per-thread malloc won't happen on unix. The problem resides in the lack of sense in win32/vmem.h

It isn't "lack of sense" to have separate Heap for each thread it is a deliberate design decision​: - avoids need to MUXTEX lock every malloc/free - allows all memory used by thread to be returned to OS even if application forgets to free() things.

What is far less clear is why there is a Vmem layer on top of HeapXxxx() routines. Are HeapXxxxx too slow for direct use?

Sorry I was unclear\, yes I agree that a heap/perlinterpreter is a good idea and what I meant the muddled access to the vmem layer\, and also the so called shared vmem heap with mutex functions which never are called as far as I can tell.

I am trying to solve the problem by making sure I always dealloc in the same thread I alloc. However XS writers will need to do that manually.

Or even\, you need to alloc/dealloc in the same perl_context\, as the memory system lives with the perl interpreter.

Given that we could should be able to have Perl_malloc_for(his_perl\,size) if it was easy to get a 'his_perl' (rather than 'my_perl') given a thread.

There isn't a one-one mapping of perl interpreter - thread. We also don't know what perl interpreter a SV (for example) belongs to.

Arthur

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

Arthur Bergman \arthur@​contiller\.se writes​:

What is far less clear is why there is a Vmem layer on top of HeapXxxx() routines. Are HeapXxxxx too slow for direct use?

Sorry I was unclear\, yes I agree that a heap/perlinterpreter is a good idea and what I meant the muddled access to the vmem layer\, and also the so called shared vmem heap with mutex functions which never are called as far as I can tell.

perlio.c used the shared heap for a while - and it was me that added (access to) its mutexes. It basically works.

It would be the thing to use for the fd refcount table.

There isn't a one-one mapping of perl interpreter - thread.

I thought that was the _entire_ point of ithreads that thread === interpreter.

We also don't know what perl interpreter a SV (for example) belongs to.

But we could (expensively) find out by

foreach thread { foreach arena   return thread if sv in arena }

Arthur -- Nick Ing-Simmons http​://www.ni-s.u-net.com/

p5pRT commented 22 years ago

From @jhi

On Thu\, Jan 10\, 2002 at 11​:52​:57AM +0000\, Nick Ing-Simmons wrote​:

Nicholas Clark \nick@​unfortu\.net writes​:

If I was going to do that I would try perl's malloc.c + a get-chunk-via-mmap() scheme. munmap() has approximately the same semantic as HeapFree(). There is a minor boot-strapping issue getting the threads thread struct malloced out of its own heap.

Related to this\, why does perl recommend not used perl's malloc on Linux?

I do not remember the reason either\, I think the choice has been there for a while\, anyway.

-- $jhi++; # http​://www.iki.fi/jhi/   # There is this special biologist word we use for 'stable'.   # It is 'dead'. -- Jack Cohen

p5pRT commented 22 years ago

From @doughera88

On Thu\, 10 Jan 2002\, Nicholas Clark wrote​:

Related to this\, why does perl recommend not used perl's malloc on Linux?

What\, you mean my comment

  # Explanation?   usemymalloc='n'

in hints/linux.sh doesn't give you enough information? :-)

That's the typical comment I put into a hint file when I couldn't figure out why the original platform porter made that particular choice. The intent was that the original porter would follow up with more details\, but such porters are often quite busy with other things and happy simply to have gotten anything that worked.

If I recall correctly\, the claim was made at the time (199[45]-ish) that Linux's malloc was actually faster\, and definitely was more frugal.
Since then\, Ilya did wonders tuning perl's malloc to be optimized for the actual allocation patterns encountered\, and made it both faster and more frugal. These days\, the two versions appear to be about the same in terms of both space and speed. (which is faster seems to be application-specific\, and may also be hardware-specific (e.g. cache size issues) but any differences I've been able to measure have all been small.)

I left usemymalloc='n' in anyway partly out of inertia and partly because it made dealing with malloc()-ed allocations from third-party extensions and libraries a little easier.

Here's a patch for hints/linux.sh that updates the comments slightly. While I was editing\, I deleted some old notes that are no longer relevant.

Inline Patch ```diff diff -r -u perl-current/hints/linux.sh perl-andy/hints/linux.sh --- perl-current/hints/linux.sh Fri Dec 7 10:41:37 2001 +++ perl-andy/hints/linux.sh Thu Jan 10 10:02:36 2002 @@ -6,11 +6,11 @@ # Additional info from Nigel Head # and Kenneth Albanowski # -# Consolidated by Andy Dougherty +# Consolidated by Andy Dougherty # # Updated Thu Feb 8 11:56:10 EST 1996 -# Updated Thu May 30 10:50:22 EDT 1996 by +# Updated Thu May 30 10:50:22 EDT 1996 by # Updated Fri Jun 21 11:07:54 EDT 1996 # NDBM support for ELF renabled by @@ -39,35 +39,6 @@ # do the implicit mapping. ignore_versioned_solibs='y' -# perl goes into the /usr tree. See the Filesystem Standard -# available via anonymous FTP at tsx-11.mit.edu in -# /pub/linux/docs/linux-standards/fsstnd. -# Allow a command line override, e.g. Configure -Dprefix=/foo/bar -# -# Addendum for 5.005_57 and beyond: -# -# However, most Linux users probably already have a /usr/bin/perl. -# We can't know whether the current user is intending to *replace* -# that /usr/bin/perl or whether the user is intending to install -# a *different* installation. -# -# Here is what we used to do: -# Allow a command line override, e.g. Configure -Dprefix=/foo/bar -# case "$prefix" in -# '') prefix='/usr' ;; -# esac -# -# For now, let's assume that most Linux users get their /usr/bin/perl -# from some packaging system, so that those compiling from source are -# probably the more experimental folks and hence probably aren't -# intending to replace /usr/bin/perl (at least just yet). -# This change makes linux consistent with most other unix platforms -# in having a default of prefix=/usr/local. -# These notes can probably safely be removed in 5.005_50 and beyond. -# -# 9 April 1999 Andy Dougherty -# - # BSD compatability library no longer needed # 'kaffe' has a /usr/lib/libnet.so which is not at all relevent for perl. set `echo X "$libswanted "| sed -e 's/ bsd / /' -e 's/ net / /'` @@ -77,8 +48,6 @@ # If you have glibc, then report the version for ./myconfig bug reporting. # (Configure doesn't need to know the specific version since it just uses # gcc to load the library for all tests.) -# Is this sufficiently robust for libc5 systems as well as -# glibc-2.1.x systems? # We don't use __GLIBC__ and __GLIBC_MINOR__ because they # are insufficiently precise to distinguish things like # libc-2.0.6 and libc-2.0.7. @@ -91,7 +60,9 @@ # function in . d_lstat=define -# Explanation? +# The system malloc() is about as fast and as frugal as perl's. +# Since the system malloc() has been the default since at least +# 5.001, we might as well leave it that way. --AD 10 Jan 2002 case "$usemymalloc" in '') usemymalloc='n' ;; esac @@ -137,10 +108,6 @@ You appear to have ELF support. I'll try to use it for dynamic loading. If dynamic loading doesn't work, read hints/linux.sh for further information. EOM - -#For RedHat Linux 3.0.3, you may need to fetch -# ftp://ftp.redhat.com/pub/redhat-3.0.3/i386/updates/RPMS/ld.so-1.7.14-3.i386.rpm -# else cat <<'EOM' >&4 -- ```

  Andy Dougherty doughera@​lafayette.edu   Dept. of Physics   Lafayette College\, Easton PA 18042

p5pRT commented 22 years ago

From @jhi

Here's a patch for hints/linux.sh that updates the comments slightly. While I was editing\, I deleted some old notes that are no longer relevant.

Thanks\, applied.

-- $jhi++; # http​://www.iki.fi/jhi/   # There is this special biologist word we use for 'stable'.   # It is 'dead'. -- Jack Cohen

p5pRT commented 22 years ago

From @andk

On Thu\, 10 Jan 2002 10​:13​:07 -0500 (EST)\, Andy Dougherty \doughera@&#8203;lafayette\.edu said​:

  > -# Explanation?   > +# The system malloc() is about as fast and as frugal as perl's.   > +# Since the system malloc() has been the default since at least   > +# 5.001\, we might as well leave it that way. --AD 10 Jan 2002

I found my posting http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2000-07/msg00018.html again.

It contains a small demo that shows that perl's malloc is bad at providing large amounts of memory. Apart from that I've been running with perl's malloc for many years without problems until I encountered this memory shortage. Since I've started processing large images with Image​::Magick I switched to usemymalloc=n.

I just retried the demo with a recent bleadperl and still see the same behaviour.

-- andreas

p5pRT commented 22 years ago

From @gsar

On Thu\, 10 Jan 2002 09​:00​:08 GMT\, Nick Ing-Simmons wrote​:

The snag is that shared heap stuff seems to be buggy. The thread​::shared tests core-dump in the heap routines.

Doug Lankshear contributed a patch to make vmem.h use the CRT's malloc(). I've checked it in as change#14175. Perhaps this will help in your hunt for what's wrong in the shared heap code.

Sarathy gsar@​ActiveState.com

p5pRT commented 22 years ago

From @gsar

On Thu\, 10 Jan 2002 12​:00​:33 GMT\, Nick Ing-Simmons wrote​:

What is far less clear is why there is a Vmem layer on top of HeapXxxx() routines. Are HeapXxxxx too slow for direct use?

It is "just" an internal abstraction that allows you to try other allocation schemes\, like the one I just checked in.

I'm not a big fan of C++\, so if you want to turn it into a pure C abstraction that uses macros and/or function tables\, feel free to do so.

I am trying to solve the problem by making sure I always dealloc in the same thread I alloc. However XS writers will need to do that manually.

Or even\, you need to alloc/dealloc in the same perl_context\, as the memory system lives with the perl interpreter.

Given that we could should be able to have Perl_malloc_for(his_perl\,size) if it was easy to get a 'his_perl' (rather than 'my_perl') given a thread.

If you're executing in the thread already\, PERL_GET_CONTEXT is what you want. If not\, I suspect you'll need to track which thread currently "owns" the interpreter in a separate data structure which gets updated by PERL_SET_CONTEXT().

Sarathy gsar@​ActiveState.com

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

Gurusamy Sarathy \gsar@&#8203;ActiveState\.com writes​:

On Thu\, 10 Jan 2002 09​:00​:08 GMT\, Nick Ing-Simmons wrote​:

The snag is that shared heap stuff seems to be buggy. The thread​::shared tests core-dump in the heap routines.

Doug Lankshear contributed a patch to make vmem.h use the CRT's malloc(). I've checked it in as change#14175. Perhaps this will help in your hunt for what's wrong in the shared heap code.

As far as I can tell something like this is occuring somewhere​:

SomeFunc(...) { dTHX;

}

OtherFunc(pTHX_ ...) {   SomeFunc() }

OtherFunc(his_perl\,...)

That is at top of call tree someone is being clever and passing a PerlInterpteter * to a function which takes pTHX on assumption that will be used to access "another" thread's interpteter.

But possibly hidden behind a macro forest the alleged pTHX aware function calls something (e.g. one of win32_xxxx()) which does not get a pTHX and fishes "my_perl" out of TLS and uses that instead of "his_perl".

So the "his_perl" call is a mixture...

-- Nick Ing-Simmons http​://www.ni-s.u-net.com/

p5pRT commented 22 years ago

From @gsar

On Fri\, 11 Jan 2002 23​:14​:21 GMT\, Nick Ing-Simmons wrote​:

Gurusamy Sarathy \gsar@&#8203;ActiveState\.com writes​:

On Thu\, 10 Jan 2002 09​:00​:08 GMT\, Nick Ing-Simmons wrote​:

The snag is that shared heap stuff seems to be buggy. The thread​::shared tests core-dump in the heap routines.

Doug Lankshear contributed a patch to make vmem.h use the CRT's malloc(). I've checked it in as change#14175. Perhaps this will help in your hunt for what's wrong in the shared heap code.

As far as I can tell something like this is occuring somewhere​:

SomeFunc(...) { dTHX;

}

OtherFunc(pTHX_ ...) { SomeFunc() }

OtherFunc(his_perl\,...)

That is at top of call tree someone is being clever and passing a PerlInterpteter * to a function which takes pTHX on assumption that will be used to access "another" thread's interpteter.

But possibly hidden behind a macro forest the alleged pTHX aware function calls something (e.g. one of win32_xxxx()) which does not get a pTHX and fishes "my_perl" out of TLS and uses that instead of "his_perl".

So the "his_perl" call is a mixture...

Whatever calls OtherFunc() had better do a PERL_SET_CONTEXT(his_perl). If it doesn't\, then there's your bug.

Sarathy gsar@​ActiveState.com

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

Gurusamy Sarathy \gsar@&#8203;ActiveState\.com writes​:

That is at top of call tree someone is being clever and passing a PerlInterpteter * to a function which takes pTHX on assumption that will be used to access "another" thread's interpteter.

But possibly hidden behind a macro forest the alleged pTHX aware function calls something (e.g. one of win32_xxxx()) which does not get a pTHX and fishes "my_perl" out of TLS and uses that instead of "his_perl".

So the "his_perl" call is a mixture...

Whatever calls OtherFunc() had better do a PERL_SET_CONTEXT(his_perl). If it doesn't\, then there's your bug.

Agreed. But the above does not seem to occur very often. I have a hacked perlhost.h and perllib.c which checks for the oddity in the mapping macros (slows it down so just for probing). More news when there is some.

Sarathy gsar@​ActiveState.com -- Nick Ing-Simmons http​://www.ni-s.u-net.com/

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

Win32 ithread perl "segfaults" in vmem.h running one of the tests​:

if (eval q{$pid = fork}) {   eval q{ die "parent died" };   print $@​; } else {   eval q{ die "child died" };   print $@​; }

The fail is in VMem​::Free freeing one of the SVs in the SvPADLIST of a CV.

I suspect the CV is that of the first eval q{$pid = fork}.

It seems that as child "returns" from that eval it will be last one out and so the one to free the optree built for the eval "" But it will free OP etc.to its heap\, and they were created in parents heap. Does that guess make any sense?

-- Nick Ing-Simmons http​://www.ni-s.u-net.com/

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

Nick Ing-Simmons \nick@&#8203;ing\-simmons\.net writes​:

Win32 ithread perl "segfaults" in vmem.h running one of the tests​:

if (eval q{$pid = fork}) { eval q{ die "parent died" }; print $@​; } else { eval q{ die "child died" }; print $@​; }

The fail is in VMem​::Free freeing one of the SVs in the SvPADLIST of a CV.

I suspect the CV is that of the first eval q{$pid = fork}.

It seems that as child "returns" from that eval it will be last one out and so the one to free the optree built for the eval "" But it will free OP etc.to its heap\, and they were created in parents heap. Does that guess make any sense?

With some hacking to vmem.h to add an owner field to the link-list used to wrap system malloc() I can confirm that something like that is happening​:

VMem​::Free(VMem * const 0x00000021\, void * 0x015fdebc) line 210 PerlMemFree(IPerlMem * 0x015fe984\, void * 0x015fdebc) line 305 Perl_safesysfree(void * 0x015fdebc) line 151 + 11 bytes S_cop_free(interpreter * 0x015ee20c\, cop * 0x015fed4c) line 888 Perl_op_free(interpreter * 0x015ee20c\, op * 0x015fed4c) line 735 + 10 bytes Perl_op_free(interpreter * 0x015ee20c\, op * 0x015fed0c) line 725 + 10 bytes Perl_op_free(interpreter * 0x015ee20c\, op * 0x015fecdc) line 725 + 10 bytes Perl_leave_scope(interpreter * 0x015ee20c\, long 3) line 812 Perl_pop_scope(interpreter * 0x015ee20c) line 129 + 12 bytes Perl_pp_leaveeval(interpreter * 0x065ee20c) line 3364 Perl_runops_debug(interpreter * 0x015ee20c) line 1392 + 7 bytes win32_start_child(void * 0x015ee20c) line 1740 + 7 bytes

-- Nick Ing-Simmons http​://www.ni-s.u-net.com/

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

Nick Ing-Simmons \nick@&#8203;ing\-simmons\.net writes​:

Nick Ing-Simmons \nick@&#8203;ing\-simmons\.net writes​:

Win32 ithread perl "segfaults" in vmem.h running one of the tests​:

if (eval q{$pid = fork}) { eval q{ die "parent died" }; print $@​; } else { eval q{ die "child died" }; print $@​; }

With some hacking to vmem.h to add an owner field to the link-list used to wrap system malloc() I can confirm that something like that is happening​:

VMem​::Free(VMem * const 0x00000021\, void * 0x015fdebc) line 210 PerlMemFree(IPerlMem * 0x015fe984\, void * 0x015fdebc) line 305 Perl_safesysfree(void * 0x015fdebc) line 151 + 11 bytes S_cop_free(interpreter * 0x015ee20c\, cop * 0x015fed4c) line 888 Perl_op_free(interpreter * 0x015ee20c\, op * 0x015fed4c) line 735 + 10 bytes Perl_op_free(interpreter * 0x015ee20c\, op * 0x015fed0c) line 725 + 10 bytes Perl_op_free(interpreter * 0x015ee20c\, op * 0x015fecdc) line 725 + 10 bytes Perl_leave_scope(interpreter * 0x015ee20c\, long 3) line 812 Perl_pop_scope(interpreter * 0x015ee20c) line 129 + 12 bytes Perl_pp_leaveeval(interpreter * 0x065ee20c) line 3364 Perl_runops_debug(interpreter * 0x015ee20c) line 1392 + 7 bytes win32_start_child(void * 0x015ee20c) line 1740 + 7 bytes

Further hacking of vmem.h to call owner's Free - and of course adding MUXEX locks round all New/Free/Realloc so it can do that even if owner is busy too - makes the test pass.

However this is nearly the worst of all possible worlds​: - we have MUTEX on every malloc and every free - we have linked-list overhead of tracking - we are at mercy of system's malloc()

So - assuming malloc already does the lock Doug's other scheme to just use system malloc() would seem to be a win.

Presumably the other option is to use the special Parse or Shared heap for the ops.

-- Nick Ing-Simmons http​://www.ni-s.u-net.com/

p5pRT commented 22 years ago

From @gsar

On Sat\, 12 Jan 2002 11​:51​:52 GMT\, Nick Ing-Simmons wrote​:

Win32 ithread perl "segfaults" in vmem.h running one of the tests​:

if (eval q{$pid = fork}) { eval q{ die "parent died" }; print $@​; } else { eval q{ die "child died" }; print $@​; }

The fail is in VMem​::Free freeing one of the SVs in the SvPADLIST of a CV.

I suspect the CV is that of the first eval q{$pid = fork}.

It seems that as child "returns" from that eval it will be last one out and so the one to free the optree built for the eval "" But it will free OP etc.to its heap\, and they were created in parents heap. Does that guess make any sense?

Yes it does.

As (erm) "designed"\, the op tree allocations were supposed to be managed by PerlMemParse_*() functions (which are like the PerlMemShared_*() ones in that they're shared across all the threads\, but the bookkeeping may be more optimized for OPs). But the PerlMemParse_*() interfaces were never actually implemented since it is always the case that the parent pseudo-process is the one that goes away last and hence takes op tree with it. Except of course in the case of eval"" op trees shared between parent and child (which I had previously deluded myself as a "could not happen" without really thinking about the eval "...fork()..." case).

I think the best fix here would be to implement the PerlMemParse_*() stuff and do all OP allocations with that. The implementation may be akin to your PL_OP_SLAB_ALLOC scheme if that idea still has merit\, or same as/similar to how PerlMemShared_*() stuff is done.

Sarathy gsar@​ActiveState.com

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

Gurusamy Sarathy \gsar@&#8203;ActiveState\.com writes​:

It seems that as child "returns" from that eval it will be last one out and so the one to free the optree built for the eval "" But it will free OP etc.to its heap\, and they were created in parents heap. Does that guess make any sense?

Yes it does.

As (erm) "designed"\, the op tree allocations were supposed to be managed by PerlMemParse_*() functions (which are like the PerlMemShared_*() ones in that they're shared across all the threads\, but the bookkeeping may be more optimized for OPs). But the PerlMemParse_*() interfaces were never actually implemented since it is always the case that the parent pseudo-process is the one that goes away last and hence takes op tree with it. Except of course in the case of eval"" op trees shared between parent and child (which I had previously deluded myself as a "could not happen" without really thinking about the eval "...fork()..." case).

I think the best fix here would be to implement the PerlMemParse_*() stuff and do all OP allocations with that.

Right ho - in progress in perlio branch.

Any particular reason why PerlMemParse is distinct from PerlMemShared ?

The implementation may be akin to your PL_OP_SLAB_ALLOC scheme

Well that needed finishing before we could use it as it never free'd. Now done and tested on Linux.

//depot/perlio/...@​14250

Has it implemented (and enabled by default - at top of perl.h - so that it can be shaken down across platforms).

if that idea still has merit\,

It is ideal for the Win32 case in hand as it reduces the number of malloc calls and hence MUTEX lock overheads.

or same as/similar to how PerlMemShared_*() stuff is done.

Sarathy gsar@​ActiveState.com -- Nick Ing-Simmons http​://www.ni-s.u-net.com/

p5pRT commented 22 years ago

From @gsar

On Mon\, 14 Jan 2002 00​:25​:52 GMT\, Nick Ing-Simmons wrote​:

Gurusamy Sarathy \gsar@&#8203;ActiveState\.com writes​:

As (erm) "designed"\, the op tree allocations were supposed to be managed by PerlMemParse_*() functions (which are like the PerlMemShared_*() ones in that they're shared across all the threads\, but the bookkeeping may be more optimized for OPs). [...] [...] Any particular reason why PerlMemParse is distinct from PerlMemShared ?

Aside from allowing potential optimizations of how OP memory is allocated that I mentioned above\, no.

Thanks\,

Sarathy gsar@​ActiveState.com

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

Gurusamy Sarathy \gsar@&#8203;ActiveState\.com writes​:

On Mon\, 14 Jan 2002 00​:25​:52 GMT\, Nick Ing-Simmons wrote​:

Gurusamy Sarathy \gsar@&#8203;ActiveState\.com writes​:

As (erm) "designed"\, the op tree allocations were supposed to be managed by PerlMemParse_*() functions (which are like the PerlMemShared_*() ones in that they're shared across all the threads\, but the bookkeeping may be more optimized for OPs). [...] [...] Any particular reason why PerlMemParse is distinct from PerlMemShared ?

Aside from allowing potential optimizations of how OP memory is allocated that I mentioned above\, no.

Okay turning that on in Win32 and turning off the "forward Free to correct heap" and replacing it with an assert yields​:

VMem​::Free(VMem * const 0x015ff7c8\, void * 0x015fd02c) line 207 PerlMemFree(IPerlMem * 0x015fecb4\, void * 0x015fd02c) line 303 Perl_safesysfree(void * 0x015fd02c) line 151 + 11 bytes S_cop_free(interpreter * 0x015ee21c\, cop * 0x01b82b74) line 919 Perl_op_free(interpreter * 0x015ee21c\, op * 0x01b82b74) line 773 + 7 bytes Perl_op_free(interpreter * 0x015ee21c\, op * 0x01b82b50) line 763 + 7 bytes Perl_op_free(interpreter * 0x015ee21c\, op * 0x01b82b30) line 763 + 7 bytes Perl_leave_scope(interpreter * 0x015ee21c\, long 0x00000003) line 812 Perl_pop_scope(interpreter * 0x015ee21c) line 129 + 12 bytes Perl_pp_leaveeval(interpreter * 0x065ee21c) line 3364 Perl_runops_debug(interpreter * 0x015ee21c) line 1392 + 7 bytes win32_start_child(void * 0x015ee21c) line 1738 + 7 bytes

STATIC void S_cop_free(pTHX_ COP* cop) {   Safefree(cop->cop_label); #ifdef USE_ITHREADS   Safefree(CopFILE(cop)); /* XXX share in a pvtable? */   Safefree(CopSTASHPV(cop)); /* XXX share in a pvtable? */   ^^^^^^^^^^^^^^^^^^^^^^^^^

That is attempting to Free something already Free'd. Will allow that for now ...

Thanks\,

Sarathy gsar@​ActiveState.com -- Nick Ing-Simmons http​://www.ni-s.u-net.com/

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

Nick Ing-Simmons \nick\.ing\-simmons@&#8203;elixent\.com writes​:

VMem​::Free(VMem * const 0x015ff7c8\, void * 0x015fd02c) line 207 PerlMemFree(IPerlMem * 0x015fecb4\, void * 0x015fd02c) line 303 Perl_safesysfree(void * 0x015fd02c) line 151 + 11 bytes S_cop_free(interpreter * 0x015ee21c\, cop * 0x01b82b74) line 919 Perl_op_free(interpreter * 0x015ee21c\, op * 0x01b82b74) line 773 + 7 bytes Perl_op_free(interpreter * 0x015ee21c\, op * 0x01b82b50) line 763 + 7 bytes Perl_op_free(interpreter * 0x015ee21c\, op * 0x01b82b30) line 763 + 7 bytes Perl_leave_scope(interpreter * 0x015ee21c\, long 0x00000003) line 812 Perl_pop_scope(interpreter * 0x015ee21c) line 129 + 12 bytes Perl_pp_leaveeval(interpreter * 0x065ee21c) line 3364 Perl_runops_debug(interpreter * 0x015ee21c) line 1392 + 7 bytes win32_start_child(void * 0x015ee21c) line 1738 + 7 bytes

STATIC void S_cop_free(pTHX_ COP* cop) { Safefree(cop->cop_label); #ifdef USE_ITHREADS Safefree(CopFILE(cop)); /* XXX share in a pvtable? */ Safefree(CopSTASHPV(cop)); /* XXX share in a pvtable? */ ^^^^^^^^^^^^^^^^^^^^^^^^^

Seems that the CopXXXX abstraction needed some work. I have added CopFILE_free() and CopSTASH_free() to the abstraction and hence removed a few #ifdef USE_ ITHREADS

from .c files.

It seems to me (as hinted at by (Sarathy's?) comments above) - that if 'sharepvn' produced a shared pv (radical eh?) then

Which gets me a whole 3 lines futher to the SvREFCNT_dec(c->cop_io) (Which is an issue in general case\, but in this case seems to be uninit or trashed ->cop_io ...)

That is attempting to Free something already Free'd. Will allow that for now ...

Thanks\,

Sarathy gsar@​ActiveState.com -- Nick Ing-Simmons http​://www.ni-s.u-net.com/

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

Nick Ing-Simmons \nick\.ing\-simmons@&#8203;elixent\.com writes​:

Seems that the CopXXXX abstraction needed some work.

That is attempting to Free something already Free'd. Will allow that for now ...

That seems to be an interesting race condition which only seems to be triggered using a debugger on it ... What happens is that two threads are both in cleanup at same time and both spot that an op needs freeing one does the free\, then when otherone gets a timeslot it finds the thing it started freeing is now free... I am going to duck that one for now. We _may_ need a 5005-threads-like MUTEX that gives access to the op-tree.

Anyway - with current bleadperl fork and simple threads tests are passing. The threads​::shared tests are another story. There are at least two fail signatures\, but I think both are due to missing PERL_SET_CONTEXT.

Now for an idea which may help...

Currently we have Vmem object which have Lock/Unlock methods and have Add/Release to increment a refcount. But Alloc/Free don't use locks by default (left to higher level code).

Radical idea - we have object(s) - why not use OO design !

That is have Vmem class automatically use Lock/Unlock round its alloc/free iff refcount > 1.

Idea here is that _the_ shared pool starts life as just another pool. So that initial stages when there is only one thread it need do no locking. But as soon as another thread is ->Add-ed to it it starts locking.

The other OO concept we could use is inheritance (single should suffice). If we made the various implementations of Vmem derived classes then the #if copse (not yet a forest) in Vmem.h could be replaced by Vmem.h as just the interface and VmemHeap.cpp\, VmemMalloc.cpp and we just choose which we compile/link.

-- Nick Ing-Simmons http​://www.ni-s.u-net.com/

p5pRT commented 22 years ago

From [Unknown Contact. See original ticket]

On Wednesday\, January 16\, 2002\, at 04​:21 PM\, Nick Ing-Simmons wrote​:

That seems to be an interesting race condition which only seems to be triggered using a debugger on it ... What happens is that two threads are both in cleanup at same time and both spot that an op needs freeing one does the free\, then when otherone gets a timeslot it finds the thing it started freeing is now free... I am going to duck that one for now. We _may_ need a 5005-threads-like MUTEX that gives access to the op-tree.

You might want to use perlvars.h​:39

Gop_mutex\, perl_mutex\, mutex for op refcounting

Arthur