bdwgc: Update library to version 7.6.8.

libatomic_ops is updated accordingly to version 7.6.6.
    Fixes build failures on android.
This commit is contained in:
Marius Gerbershagen 2018-11-03 21:04:55 +01:00
parent 089d30260c
commit 736f50b864
268 changed files with 50728 additions and 14692 deletions

View file

@ -51,6 +51,7 @@
passed empty environment is used
- compiler: when gcc fails ecl prints the failing command output
- ASDF has been updated to 3.1.8.8
- The Boehm-Demers-Weiser garbage collector has been updated to version 7.6.8
- package local nicknames has been implemented (after SBCL)
- hash table extensions are documented in newdoc
- various cleanups performed in the compiler

View file

@ -2,6 +2,8 @@ This is an attempt to acknowledge contributions to the garbage collector.
Early contributions also mentioned (duplicated) in ChangeLog file; details of
later ones should be in "git log".
Currently maintained by Ivan Maidanski.
HISTORY -
Early versions of this collector were developed as a part of research
@ -21,11 +23,14 @@ Other contributors (my apologies for any omissions):
Adam Megacz <adam@megac.com>
Adnan Ali
Adrian Bunk <bunk@fs.tum.de>
Adrian Pop <adrian.pop@liu.se>
Akira Tagoh <tagoh@redhat.com>
Alain Novak <alain.novak@hermes.si>
Alan Dosser <dosser@src.dec.com>
Alan J. Demers <ademers@cs.cornell.edu>
Aleksey Demakov <ademakov@gmail.com>
Alessandro Bruni <alessandro.bruni@gmail.com>
Alex Ronne Petersen <alexrp@xamarin.com>
Alexander Belchenko <bialix@ukr.net>
Alexander Gavrilov <angavrilov@gmail.com>
Alexander Herz <alexander.herz@mytum.de>
@ -36,10 +41,11 @@ Alistair G. Crooks <agc@uts.amdahl.com>
Allan Hsu <allan@counterpop.net>
Andre Leiradella <andre@leiradella.com>
Andreas Jaeger <aj@suse.de>
Andreas Tobler <a.tobler@schweiz.org>
Andreas Tobler <andreastt@gmail.com>
Andrei Polushin <polushin@gmail.com>
Andrej Cedilnik <acedil1@csee.umbc.edu>
Andrew Begel <abegel@eecs.berkeley.edu>
Andrew Buss <abuss@ucsd.edu>
Andrew Gray <andrew.gray@anu.edu.au>
Andrew Haley <aph@redhat.com>
Andrew Horton <andrew.j.horton@gmail.com>
@ -47,6 +53,7 @@ Andrew McKinlay <mckinlay@axonsoft.com>
Andrew Pinski <pinskia@physics.uc.edu>
Andrew Stitcher <astitcher@redhat.com>
Andrew Stone <andrew@stone.com>
Andy Li <andy@onthewings.net>
Andy Wingo <wingo@pobox.com>
Anselm Baird-Smith <Anselm.BairdSmith@inria.fr>
Anthony Green <green@redhat.com>
@ -63,6 +70,7 @@ Ben Hutchings <ben@decadentplace.org.uk>
Ben Maurer <benm@mono-cvs.ximian.com>
Benjamin Lerman <Benjamin.Lerman@ambre.net>
Bernd Edlinger <bernd.edlinger@hotmail.de>
Bernd Kuhls <bernd.kuhls@t-online.de>
Bernie Solomon <bernard@mono-cvs.ximian.com>
Bill Janssen <janssen@parc.xerox.com>
Bo Thorsen <bo@berlioz.suse.de>
@ -80,11 +88,14 @@ Bruce Mitchener <bruce.mitchener@gmail.com>
Bruno Haible <bruno@clisp.org>
Bryce McKinlay <mckinlay@redhat.com>
Burkhard Linke <blinke@cebitec.uni-bielefeld.de>
Calvin Hill <calvin@hakobaito.co.uk>
Carlos J. Puga Medina <cpm@fbsd.es>
Cesar Eduardo Barros <cesarb@nitnet.com.br>
Charles Fiterman <cef@geode.geodesic.com>
Charles Mills <boson@cyberspace.org>
Chris Dodd <chrisd@reservoir.com>
Chris Lingard <chris@highludworth.freeserve.co.uk>
Chris Metcalf <cmetcalf@mellanox.com>
Christian Joensson <christian.joensson@gmail.com>
Christian Limpach <chris@pin.lu>
Christian Thalinger <twisti@complang.tuwien.ac.at>
@ -115,6 +126,8 @@ David Mossberger
David Peroutka <djp@volny.cz>
David Pickens <dsp@rci.rutgers.edu>
David Stes <stes@d5e02b1d.kabel.telenet.be>
David Terei <d@davidterei.com>
David Van Horn <dvanhorn@ccs.neu.edu>
Davide Angelocola <davide.angelocola@tiscali.it>
Dick Porter <dick@acm.org>
Dietmar Planitzer <dave.pl@ping.at>
@ -124,33 +137,39 @@ Djamel Magri <djamel.magri@googlemail.com>
Doug Kaufman <dkaufman@rahul.net>
Doug Moen <doug@moens.org>
Douglas Steel <doug@wg.icl.co.uk>
Eli Barzilay <eli@racket-lang.org>
Elijah Taylor <elijahtaylor@google.com>
Elvenlord Elrond <elrond@samba-tng.org>
Emmanual Stumpf
Eric Benson <eb@kaleida.com>
Eric Holk <eric.holk@gmail.com>
Erik M. Bray <erik.bray@lri.fr>
Fabian Thylman
Fergus Henderson <fjh@cs.mu.oz.au>
Franklin Chen <chen@adi.com>
Fred Gilham <gilham@csl.sri.com>
Fred Stearns
Friedrich Dominicus <friedrichdominicus@googlemail.com>
Gabor Drescher <gabor.drescher@cs.fau.de>
Gary Leavens <leavens@eecs.ucf.edu>
Geoff Norton <grompf@sublimeintervention.com>
George Talbot <Gtalbot@ansarisbio.com>
Gerard A Allan
Glauco Masotti <glauco.masotti@libero.it>
Grzegorz Jakacki <jakacki@acm.org>
Gustavo Giraldez <ggiraldez@manas.com.ar>
Gustavo Rodriguez-Rivera <grr@cs.purdue.edu>
H.J. Lu <hjl.tools@gmail.com>
Hamayama <hamay1010@gmail.com>
Hannes Mehnert <hannes@mehnert.org>
Hanno Boeck <hanno@gentoo.org>
Hans Boehm <boehm@acm.org>
Hans-Peter Nilsson <hp@gcc.gnu.org>
Hans-Peter Nilsson <hp@axis.com>
Henning Makholm <Henning@octoshape.com>
Henrik Theiling <theiling@absint.com>
Hironori Sakamoto <hsaka@mth.biglobe.ne.jp>
Hiroshi Kawashima <kei@arch.sony.co.jp>
Hiroshi Yokota <yokota@netlab.cs.tsukuba.ac.jp>
Hubert Garavel <Hubert.Garavel@imag.fr>
Iain Sandoe <developer@sandoe-acoustics.co.uk>
Ian Piumarta <piumarta@prof.inria.fr>
@ -167,6 +186,8 @@ James Dominy
Jan Alexander Steffens <jan.steffens@gmail.com>
Jan Wielemaker <J.Wielemaker@cs.vu.nl>
Jani Kajala <jani@sumea.com>
Jared McNeill <jmcneill@NetBSD.org>
Jay Krell <jaykrell@microsoft.com>
Jean-Baptiste Nivois
Jean-Claude Beaudoin <jean.claude.beaudoin@gmail.com>
Jean-Daniel Fekete <fekete@cs.umd.edu>
@ -182,6 +203,7 @@ Ji-Yong Chung
Jie Liu <lj8175@gmail.com>
Jim Marshall <jim.marshall@wbemsolutions.com>
Jim Meyering <jim@meyering.net>
Joao Abecasis <joao@abecasis.name>
Joerg Sonnenberger <joerg@britannica.bec.de>
Johannes Schmidt <jschmidt@avtrex.com>
Johannes Totz <jtotz@ic.ac.uk>
@ -190,22 +212,27 @@ John Clements <clements@brinkerhoff.org>
John Ellis <ellis@xerox.parc.com>
John Merryweather Cooper <jmerry@mono-cvs.ximian.com>
Jon Moore <jonm@apache.org>
Jonas Echterhoff <jonas@unity3d.com>
Jonathan Bachrach <jonathan@harlequin.com>
Jonathan Chambers <jonathan@unity3d.com>
Jonathan Clark
Jonathan Pryor <jpryor@novell.com>
Josh Peterson <petersonjm1@gmail.com>
Joshua Richardson <jric@chegg.com>
Juan Jose Garcia-Ripoll <juanjose.garciaripoll@googlemail.com>
Kai Tietz <ktietz70@googlemail.com>
Kaz Kojima <kkojima@rr.iij4u.or.jp>
Kazu Hirata <kazu@codesourcery.com>
Kazuhiro Inaoka <inaoka.kazuhiro@renesas.com>
Keith Seitz <keiths@redhat.com>
Kenjiro Taura <tau@eidos.ic.i.u-tokyo.ac.jp>
Kenneth Schalk <schalk@cadtls.hlo.dec.com>
Kevin Kenny <kenny@m.cs.uiuc.edu>
Kevin Tew <tewk@racket-lang.org>
Kevin Warne <kevinw@direct.ca>
Kjetil S. Matheussen <ksvalast@ifi.uio.no>
Kjetil Matheussen <k.s.matheussen@notam02.no>
Klaus Treichel <ktreichel@web.de>
Klemens Zwischenbrugger <ka7@la-evento.com>
Knut Tvedten <knuttv@ifi.uio.no>
Krister Walfridsson <cato@df.lth.se>
Kristian Kristensen <kk@cs.aau.dk>
@ -213,9 +240,11 @@ Kumar Srikantan
Kurt Miller <kurt@intricatesoftware.com>
Lars Farm <lars.farm@ite.mh.se>
Laurent Morichetti <l_m@pacbell.net>
Leonardo Taccari <iamleot@gmail.com>
Linas Vepstas <linasvepstas@gmail.com>
Loren J. Rittle <rittle@latour.labs.mot.com>
Louis Zhuang <louis.zhuang@acm.org>
Lucas Meijer <lucas@unity3d.com>
Ludovic Courtes <ludo@gnu.org>
Maarten Thibaut <mthibaut@cisco.com>
Manuel A. Fernandez Montecelo <manuel.montezelo@gmail.com>
@ -224,6 +253,7 @@ Marc Recht <recht@netbsd.org>
Marco Maggi <marco.maggi-ipsu@poste.it>
Marcos Dione <Marcos_David.Dione@sophia.inria.fr>
Marcus Herbert
Marek Vasut <marex@denx.de>
Margaret Fleck <mfleck@illinois.edu>
Mark Boulter <mboulter@vnet.ibm.com>
Mark Mitchell <mark@codesourcery.com>
@ -237,17 +267,23 @@ Matthew Flatt <mflatt@plt-scheme.org>
Matthias Andree <matthias.andree@gmx.de>
Matthias Drochner <M.Drochner@fz-juelich.de>
Maurizio Vairani <maurizio.vairani@cloverinformatica.it>
Max Mouratov <mmouratov@gmail.com>
Melissa O'Neill <oneill@cs.sfu.ca>
Michael Arnoldus <chime@proinf.dk>
Michael Fox <mfox@cavium.com>
Michael Smith <msmith@spinnakernet.com>
Michael Spertus <mps@geodesic.com>
Michel Schinz <schinz@alphanet.ch>
Miguel de Icaza <miguel@gnome.org>
Mikael Djurfeldt <mikael@djurfeldt.com>
Mike Frysinger <vapier@gentoo.org>
Mike Gran <spk121@yahoo.com>
Mike McGaughey <mmcg@cs.monash.edu.au>
Mike Stump <mrs@windriver.com>
Mitch Harris <maharri@uiuc.edu>
Mohan Embar <gnustuff@thisiscool.com>
Naoyuki Sawa <sawa_naoyuki-1@yahoo.co.jp>
Natanael Copa <ncopa@alpinelinux.org>
Nathanael Nerode <neroden@twcny.rr.com>
Neale Ferguson <neale@mono-cvs.ximian.com>
Neil Sharman <neil@cs.mu.oz.au>
@ -263,6 +299,7 @@ Parag Patel <parag@netcom.com>
Patrick Bridges <bridges@cs.arizona.edu>
Patrick C. Beard <beard@netscape.com>
Patrick Doyle <doylep@eecg.toronto.edu>
Paul Bone <paul@bone.id.au>
Paul Brook <paul@codesourcery.com>
Paul Graham
Paul Nash <paulnash@wildseed.com>
@ -300,13 +337,17 @@ Richard Henderson <rth@redhat.com>
Richard Sandiford <rsandifo@nildram.co.uk>
Rob Haack <rhaack@polaris.unm.edu>
Robert Brazile <brazile@diamond.bbn.com>
Rodrigo Kumpera <kumpera@gmail.com>
Roger Sayle <roger@eyesopen.com>
Roland McGrath <roland@redhat.com>
Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
Romain Naour <romain.naour@gmail.com>
Romano Paolo Tenca <rotenca@telvia.it>
Rutger Ovidius <ovidr@users.sourceforge.net>
Ryan Gonzalez <rymg19@gmail.com>
Ryan Murray <rmurray@debian.org>
Salvador Eduardo Tropea <salvador@inti.gov.ar>
Samuel Martin <s.martin49@gmail.com>
Samuel Thibault <samuel.thibault@gnu.org>
Scott Ananian <cananian@lesser-magoo.lcs.mit.edu>
Scott Schwartz <schwartz@groucho.cse.psu.edu>
@ -323,10 +364,13 @@ Sven Hartrumpf <Sven.Hartrumpf@fernuni-hagen.de>
Sven Verdoolaege <skimo@kotnet.org>
Takis Psarogiannakopoulos <takis@xfree86.org>
Tatsuya Bizenn <bizenn@visha.org>
Terrell Russell <terrellrussell@gmail.com>
Thiemo Seufer <ths@networkno.de>
Thomas Funke <thf@zelator.in-berlin.de>
Thomas Klausner <tk@giga.or.at>
Thomas Linder Puls <thomas_linder_puls@hotmail.com>
Thomas Maier <Thomas.Maier@uni-kassel.de>
Thomas Schwinge <thomas@codesourcery.com>
Thorsten Glaser <tg@debian.org>
Tilman Vogel <Tilman.Vogel@web.de>
Tim Bingham <tjb@zko.dec.com>
@ -354,6 +398,7 @@ Xi Wang <xi.wang@gmail.com>
Xiaokun Zhu <xiaokun@aero.gla.ac.uk>
Yann Dirson <dirson@debian.org>
Yannis Bres <Yannis@bres.name>
Yuki Okumura <mjt@cltn.org>
Yusuke Suzuki <utatane.tea@gmail.com>
Yvan Roux <yvan.roux@linaro.org>
Zach Saw <zach.saw@gmail.com>

View file

@ -1,21 +1,19 @@
# Makefile for Borland C++ 5.5 on NT
# If you have the Borland assembler, remove "-DUSE_GENERIC"
#
bc= c:\Borland\BCC55
bcbin= $(bc)\bin
bclib= $(bc)\lib
bcinclude= $(bc)\include
gcinclude1 = $(bc)\gc6.2\include
gcinclude2 = $(bc)\gc6.2\cord
gcinclude1 = .\include
cc= $(bcbin)\bcc32
rc= $(bcbin)\brc32
lib= $(bcbin)\tlib
link= $(bcbin)\ilink32
cflags= -O2 -R -v- -vi -H -H=gc.csm -I$(bcinclude);$(gcinclude1);$(gcinclude2) -L$(bclib) \
-w-pro -w-aus -w-par -w-ccc -w-rch -a4
defines= -DALL_INTERIOR_POINTERS -DUSE_GENERIC -DNO_GETENV -DJAVA_FINALIZATION -DGC_OPERATOR_NEW_ARRAY
cflags= -O2 -R -v- -vi -H -H=gc.csm -I$(bcinclude);$(gcinclude1) -L$(bclib) \
-w-pro -w-aus -w-par -w-ccc -w-inl -w-rch -a4
defines= -DALL_INTERIOR_POINTERS -DNO_GETENV -DJAVA_FINALIZATION -DGC_OPERATOR_NEW_ARRAY
.c.obj:
$(cc) @&&|
@ -28,7 +26,7 @@ defines= -DALL_INTERIOR_POINTERS -DUSE_GENERIC -DNO_GETENV -DJAVA_FINALIZATION -
|
.rc.res:
$(rc) -i$(bcinclude) -r -fo$* $*.rc
$(rc) -i$(bcinclude) -r -fo$* $*.rc
XXXOBJS= XXXalloc.obj XXXreclaim.obj XXXallchblk.obj XXXmisc.obj \
XXXmach_dep.obj XXXos_dep.obj XXXmark_rts.obj XXXheaders.obj XXXmark.obj \
@ -44,13 +42,13 @@ all: gctest.exe cord\de.exe test_cpp.exe
$(OBJS) test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h MAKEFILE
gc.lib: $(OBJS)
del gc.lib
-del gc.lib
$(lib) $* @&&|
$(XXXOBJS:XXX=+)
|
gctest.exe: tests\test.obj gc.lib
$(cc) @&&|
$(cc) @&&|
$(cflags) -W -e$* tests\test.obj gc.lib
|
@ -63,25 +61,19 @@ cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj \
$(cflags) -W -e$* cord\cordbscs.obj cord\cordxtra.obj \
cord\tests\de.obj cord\tests\de_win.obj gc.lib
|
$(rc) cord\tests\de_win.res cord\de.exe
$(rc) cord\tests\de_win.res cord\de.exe
gc_cpp.obj: include\gc_cpp.h include\gc.h
gc_cpp.cpp: gc_cpp.cc
copy gc_cpp.cc gc_cpp.cpp
gc_cpp.obj: gc_cpp.cc include\gc_cpp.h include\gc.h
test_cpp.cpp: tests\test_cpp.cc
copy tests\test_cpp.cc test_cpp.cpp
test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc.lib
$(cc) @&&|
$(cc) @&&|
$(cflags) -W -e$* test_cpp.obj gc.lib
|
scratch:
-del *.obj *.res *.exe *.csm cord\*.obj cord\*.res cord\*.exe cord\*.csm
clean:
del gc.lib
del *.obj
del tests\test.obj
-del *.obj *.res *.exe *.csm cord\*.obj cord\*.res cord\*.exe cord\*.csm
-del cord\*.tds cord\tests\*.obj cord\tests\*.res
-del *.log *.tds gc.lib tests\test.obj "gc.#0*"

View file

@ -25,6 +25,8 @@ SET(CMAKE_LEGACY_CYGWIN_WIN32 0) # Remove when CMake >= 2.8.4 is required
PROJECT(gc)
INCLUDE(CTest)
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
ADD_DEFINITIONS("-D_CRT_SECURE_NO_DEPRECATE
@ -49,8 +51,7 @@ INCLUDE_DIRECTORIES(libatomic_ops/src)
SET(SRC alloc.c reclaim.c allchblk.c misc.c mach_dep.c os_dep.c
mark_rts.c headers.c mark.c obj_map.c blacklst.c finalize.c
new_hblk.c dbg_mlc.c malloc.c stubborn.c dyn_load.c
typd_mlc.c ptr_chck.c gc_cpp.cc mallocx.c checksums.c
thread_local_alloc.c)
typd_mlc.c ptr_chck.c mallocx.c gc_cpp.cc)
SET(LIBS)
OPTION(enable_threads "TODO" NO)
IF(enable_threads)
@ -69,6 +70,7 @@ OPTION(enable_parallel_mark "Parallelize marking and free list construction" NO)
#ENDIF(Threads_FOUND)
IF(enable_parallel_mark)
ADD_DEFINITIONS("-DPARALLEL_MARK")
ENDIF(enable_parallel_mark)
OPTION(enable_cplusplus "install C++ support" NO)
@ -82,66 +84,61 @@ MESSAGE("HOST = ${HOST}")
#TODO check cmake detection
IF(CMAKE_USE_PTHREADS_INIT)
SET(SRC ${SRC} pthread_start.c pthread_support.c pthread_stop_world.c)
IF( "HOST" MATCHES x86-.*-linux.*|ia64-.*-linux.*|i586-.*-linux.*|i686-.*-linux.*|x86_64-.*-linux.*|alpha-.*-linux.*|sparc.*-.*-linux.*)
IF( HOST MATCHES x86-.*-linux.*|ia64-.*-linux.*|i586-.*-linux.*|i686-.*-linux.*|x86_64-.*-linux.*|alpha-.*-linux.*|sparc.*-.*-linux.*)
ADD_DEFINITIONS("-DGC_LINUX_THREADS")
ADD_DEFINITIONS("-D_REENTRANT")
IF (${enable_parallel_mark})
ADD_DEFINITIONS("-DPARALLEL_MARK")
ENDIF()
ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
SET(SRC ${SRC} thread_local_alloc.c)
MESSAGE("Explicit GC_INIT() calls may be required.")
ENDIF()
IF ( "HOST" MATCHES .*-.*-linux.*)
IF ( HOST MATCHES .*-.*-linux.*)
ADD_DEFINITIONS("-DGC_LINUX_THREADS")
ADD_DEFINITIONS("-D_REENTRANT")
ENDIF()
IF ( "HOST" MATCHES .*-.*-aix.*)
IF ( HOST MATCHES .*-.*-aix.*)
ADD_DEFINITIONS("-DGC_AIX_THREADS")
ADD_DEFINITIONS("-D_REENTRANT")
ENDIF()
IF ( "HOST" MATCHES .*-.*-hpux11.*)
IF ( HOST MATCHES .*-.*-hpux11.*)
MESSAGE("Only HP/UX 11 POSIX threads are supported.")
ADD_DEFINITIONS("-DGC_HPUX_THREADS")
ADD_DEFINITIONS("-D_POSIX_C_SOURCE=199506L") #TODO test -DVAR=value. Alternative is COMPILE_DEFINITIONS property
IF (${enable_parallel_mark})
ADD_DEFINITIONS("-DPARALLEL_MARK")
ENDIF()
MESSAGE("Explicit GC_INIT() calls may be required.")
ADD_DEFINITIONS("-D_REENTRANT") #TODO
ENDIF()
IF ( "HOST" MATCHES .*-.*-hpux10.*)
IF ( HOST MATCHES .*-.*-hpux10.*)
MESSAGE("Only HP/UX 11 POSIX threads are supported.")
ENDIF()
IF ( "HOST" MATCHES .*-.*-openbsd.*)
IF ( HOST MATCHES .*-.*-openbsd.*)
ADD_DEFINITIONS("-DGC_OPENBSD_THREADS")
ENDIF()
IF ( "HOST" MATCHES .*-.*-freebsd.*)
IF ( HOST MATCHES .*-.*-freebsd.*)
MESSAGE("FreeBSD does not yet fully support threads with Boehm GC.")
ADD_DEFINITIONS("-DGC_FREEBSD_THREADS")
ENDIF()
IF ( "HOST" MATCHES .*-.*-kfreebsd.*-gnu)
IF ( HOST MATCHES .*-.*-kfreebsd.*-gnu)
ADD_DEFINITIONS("-DGC_FREEBSD_THREADS")
ADD_DEFINITIONS("-D_REENTRANT")
IF (${enable_parallel_mark})
ADD_DEFINITIONS("-DPARALLEL_MARK")
ENDIF()
ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
ADD_DEFINITIONS("-DUSE_COMPILER_TLS")
SET(SRC ${SRC} thread_local_alloc.c)
ENDIF()
IF ( "HOST" MATCHES .*-.*-gnu.*)
IF ( HOST MATCHES .*-.*-gnu.*)
ADD_DEFINITIONS("-DGC_GNU_THREADS")
ADD_DEFINITIONS("-D_REENTRANT")
ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
SET(SRC ${SRC} thread_local_alloc.c)
ENDIF()
IF ( "HOST" MATCHES .*-.*-netbsd.*)
IF ( HOST MATCHES .*-.*-netbsd.*)
MESSAGE("Only on NetBSD 2.0 or later.")
ADD_DEFINITIONS("-DGC_NETBSD_THREADS")
ADD_DEFINITIONS("-D_REENTRANT")
ADD_DEFINITIONS("-D_PTHREADS")
ENDIF()
IF ( "HOST" MATCHES .*-.*-solaris.*)
IF ( HOST MATCHES .*-.*-solaris.*)
ADD_DEFINITIONS("-DGC_SOLARIS_THREADS")
ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
SET(SRC ${SRC} thread_local_alloc.c)
#TODO
# if test "$GCC" != yes; then
# CFLAGS="$CFLAGS -O"
@ -149,41 +146,33 @@ IF(CMAKE_USE_PTHREADS_INIT)
# fi
ENDIF()
IF ( "HOST" MATCHES .*-.*-irix.*)
IF ( HOST MATCHES .*-.*-irix.*)
ADD_DEFINITIONS("-DGC_IRIX_THREADS")
ENDIF()
IF ( "HOST" MATCHES .*-.*-cygwin.*)
IF ( HOST MATCHES .*-.*-cygwin.*)
ADD_DEFINITIONS("-DGC_THREADS")
IF (${enable_parallel_mark})
ADD_DEFINITIONS("-DPARALLEL_MARK")
ENDIF()
ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
#TODO
# win32_threads=true
SET(SRC ${SRC} thread_local_alloc.c win32_threads.c)
ENDIF()
IF ( "HOST" MATCHES .*-.*-darwin.*)
IF ( HOST MATCHES .*-.*-darwin.*)
ADD_DEFINITIONS("-DGC_DARWIN_THREADS")
ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
MESSAGE("Explicit GC_INIT() calls may be required.")
SET(SRC ${SRC} darwin_stop_world.c)
IF (${enable_parallel_mark})
ADD_DEFINITIONS("-DPARALLEL_MARK")
ENDIF()
SET(SRC ${SRC} darwin_stop_world.c thread_local_alloc.c)
#TODO
#darwin_threads=true
ENDIF()
IF ( "HOST" MATCHES .*-.*-osf*)
IF ( HOST MATCHES .*-.*-osf.*)
ADD_DEFINITIONS("-DGC_OSF1_THREADS")
IF (${enable_parallel_mark})
ADD_DEFINITIONS("-DPARALLEL_MARK")
IF(enable_parallel_mark)
ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
SET(SRC ${SRC} thread_local_alloc.c)
MESSAGE("Explicit GC_INIT() calls may be required.")
# May want to enable it in other cases, too.
# Measurements haven't yet been done.
ENDIF()
ENDIF()
IF ( "HOST" MATCHES .*-.*-linux.*)
IF ( HOST MATCHES .*-.*-linux.*)
ADD_DEFINITIONS("-DGC_LINUX_THREADS")
ADD_DEFINITIONS("-D_REENTRANT")
ENDIF()
@ -191,10 +180,9 @@ ENDIF(CMAKE_USE_PTHREADS_INIT)
IF(CMAKE_USE_WIN32_THREADS_INIT)
ADD_DEFINITIONS("-DGC_THREADS")
#win32_threads=true TODO
IF (${enable_parallel_mark})
ADD_DEFINITIONS("-DPARALLEL_MARK")
IF(enable_parallel_mark)
ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
SET(SRC ${SRC} thread_local_alloc.c)
ENDIF()
ADD_DEFINITIONS("-DEMPTY_GETENV_RESULTS") #TODO test
SET(SRC ${SRC} win32_threads.c)
@ -203,6 +191,10 @@ ENDIF(CMAKE_USE_WIN32_THREADS_INIT)
OPTION(enable_gcj_support "Support for gcj" NO)
IF(enable_gcj_support)
ADD_DEFINITIONS("-DGC_GCJ_SUPPORT")
IF(enable_threads)
ADD_DEFINITIONS("-DGC_ENABLE_SUSPEND_THREAD")
ENDIF(enable_threads)
SET(SRC ${SRC} gcj_mlc.c)
ENDIF(enable_gcj_support)

File diff suppressed because it is too large Load diff

View file

@ -11,6 +11,12 @@
## Process this file with automake to produce Makefile.in.
# Info (current:revision:age) for the Libtool versioning system.
# These numbers should be updated at most once just before the release,
# and, optionally, at most once during the development (after the release).
LIBGC_VER_INFO = 4:4:3
LIBGCCPP_VER_INFO = 4:2:3
## FIXME: `make distcheck' in this directory will not currently work.
## This is most likely to the explicit flags passed to submakes.
@ -18,7 +24,7 @@
# use the internal version. This is done since libatomic_ops doesn't
# use libtool, since it has no real use for it. But that seems to make
# it hard to use either the resulting object files or libraries.
# Thus there seems too be no real reason to recursively build in the
# Thus there seems to be no real reason to recursively build in the
# libatomic_ops directory.
# if USE_INTERNAL_LIBATOMICS_OPS
# SUBDIRS = @maybe_libatomic_ops@
@ -32,7 +38,7 @@ AM_CPPFLAGS = \
-I$(top_builddir)/include -I$(top_srcdir)/include \
$(ATOMIC_OPS_CFLAGS)
# Initialize variables so that we can declare files locally.
## Initialize variables so that we can declare files locally.
EXTRA_DIST =
lib_LTLIBRARIES =
include_HEADERS =
@ -49,25 +55,35 @@ pkgconfig_DATA = bdw-gc.pc
# ---------
lib_LTLIBRARIES += libgc.la
if SINGLE_GC_OBJ
libgc_la_SOURCES = extra/gc.c
if PTHREAD_START_STANDALONE
AM_CPPFLAGS += -DGC_PTHREAD_START_STANDALONE
libgc_la_SOURCES += pthread_start.c
endif
else
EXTRA_DIST += extra/gc.c
libgc_la_SOURCES = \
allchblk.c alloc.c blacklst.c checksums.c dbg_mlc.c \
dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c \
mach_dep.c malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
obj_map.c os_dep.c pcr_interface.c ptr_chck.c real_malloc.c reclaim.c \
specific.c stubborn.c thread_local_alloc.c typd_mlc.c
specific.c stubborn.c typd_mlc.c
# C Library: Architecture Dependent
# ---------------------------------
if WIN32_THREADS
libgc_la_SOURCES += win32_threads.c
libgc_la_SOURCES += thread_local_alloc.c win32_threads.c
else
if PTHREADS
libgc_la_SOURCES += pthread_start.c pthread_support.c
# Not Cygwin or MinGW.
libgc_la_SOURCES += pthread_start.c pthread_support.c thread_local_alloc.c
if DARWIN_THREADS
libgc_la_SOURCES += darwin_stop_world.c
else
@ -84,6 +100,7 @@ if ENABLE_DISCLAIM
libgc_la_SOURCES += fnlz_mlc.c
endif
## End of !SINGLE_GC_OBJ
endif
if USE_INTERNAL_LIBATOMIC_OPS
@ -98,27 +115,26 @@ endif
# linuxthread semaphore functions get linked:
libgc_la_LIBADD = @addobjs@ $(THREADDLLIBS) $(UNWINDLIBS) $(ATOMIC_OPS_LIBS)
libgc_la_DEPENDENCIES = @addobjs@
libgc_la_LDFLAGS = $(extra_ldflags_libgc) -version-info 1:3:0 -no-undefined
libgc_la_LDFLAGS = $(extra_ldflags_libgc) -version-info $(LIBGC_VER_INFO) \
-no-undefined
EXTRA_libgc_la_SOURCES = ia64_save_regs_in_stack.s sparc_mach_dep.S \
sparc_netbsd_mach_dep.s sparc_sunos4_mach_dep.s
if CPLUSPLUS
# C++ Interface
# -------------
if CPLUSPLUS
lib_LTLIBRARIES += libgccpp.la
pkginclude_HEADERS += include/gc_cpp.h
include_HEADERS += include/extra/gc_cpp.h
libgccpp_la_SOURCES = gc_cpp.cc
libgccpp_la_LIBADD = ./libgc.la
libgccpp_la_LDFLAGS = -version-info 1:3:0 -no-undefined
libgccpp_la_LDFLAGS = -version-info $(LIBGCCPP_VER_INFO) -no-undefined
endif
# FIXME: If Visual C++ users use Makefile.am, this should go into
# pkginclude_HEADERS with proper AM_CONDITIONALization. Otherwise
# delete this comment.
## FIXME: If Visual C++ users use Makefile.am, this should go into
## pkginclude_HEADERS with proper AM_CONDITIONALization. Otherwise
## delete this comment.
EXTRA_DIST += gc_cpp.cpp
@ -126,7 +142,10 @@ EXTRA_DIST += gc_cpp.cpp
# ----
AM_CXXFLAGS = @GC_CFLAGS@
AM_CFLAGS = @GC_CFLAGS@
AM_CFLAGS = $(WERROR_CFLAGS) @GC_CFLAGS@
CFLAGS += $(CFLAGS_EXTRA)
CXXFLAGS += $(CFLAGS_EXTRA)
## FIXME: relies on internal code generated by automake.
## FIXME: ./configure --enable-dependency-tracking should be used
@ -165,15 +184,14 @@ CCASFLAGS += $(DEFS)
# documentation which is not installed
#
EXTRA_DIST += README.QUICK TODO
EXTRA_DIST += README.QUICK
# other makefiles
# :GOTCHA: deliberately we do not include 'Makefile'
EXTRA_DIST += BCC_MAKEFILE NT_MAKEFILE \
OS2_MAKEFILE PCR-Makefile digimars.mak EMX_MAKEFILE \
Makefile.direct SMakefile.amiga WCC_MAKEFILE autogen.sh \
NT_STATIC_THREADS_MAKEFILE NT_X64_STATIC_THREADS_MAKEFILE \
NT_X64_THREADS_MAKEFILE CMakeLists.txt tests/CMakeLists.txt
CMakeLists.txt tests/CMakeLists.txt
# files used by makefiles other than Makefile.am
#
@ -197,5 +215,5 @@ include include/include.am
include cord/cord.am
include tests/tests.am
include doc/doc.am
# Putting these at the top causes cord to be built first, and not find libgc.a
# on HP/UX. There may be a better fix.
## Putting these at the top causes cord to be built first, and not find
## libgc.a on HP/UX. There may be a better fix.

View file

@ -5,9 +5,10 @@
# gc.a - builds basic library
# c++ - adds C++ interface to library
# cords - adds cords (heavyweight strings) to library
# test - prints porting information, then builds basic version of gc.a,
# and runs some tests of collector and cords. Does not add cords or
# c++ interface to gc.a
# check - prints porting information, then builds basic version of gc.a,
# and runs some tests of collector and cords. Does not add cords or
# c++ interface to gc.a
# check-cpp - runs C++ test without adding C++ (and cords) interface to gc.a
# cord/de - builds dumb editor based on cords.
ABI_FLAG=
@ -21,10 +22,17 @@ AS_ABI_FLAG=$(ABI_FLAG)
# executables.
CC=cc $(ABI_FLAG)
CXX=g++ $(ABI_FLAG)
# Needed only for "make c++", which adds the c++ interface.
AS=as $(AS_ABI_FLAG)
# The above doesn't work with gas, which doesn't run cpp.
# Define AS as `gcc -c -x assembler-with-cpp' instead.
# The above doesn't work with gas, which doesn't run cpp.
# Define AS as `gcc -c -x assembler-with-cpp' instead.
# Under Irix 6, you have to specify the ABI (-o32, -n32, or -64)
# if you use something other than the default ABI on your machine.
LD=ld
# Redefining srcdir allows object code for the nonPCR version of the collector
# to be generated in different directories.
@ -36,17 +44,20 @@ AO_SRC_DIR=$(srcdir)/libatomic_ops
CFLAGS_EXTRA=
CFLAGS= -O -I$(srcdir)/include -I$(AO_SRC_DIR)/src \
-DATOMIC_UNCOLLECTABLE -DNO_EXECUTE_PERMISSION -DALL_INTERIOR_POINTERS \
-DGC_ATOMIC_UNCOLLECTABLE -DNO_EXECUTE_PERMISSION -DALL_INTERIOR_POINTERS \
$(CFLAGS_EXTRA)
# To build the parallel collector on Linux, add to the above:
# -DGC_LINUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC
# To build the collector with threads support, add to the above:
# -DGC_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC
#
# To build the thread-capable preload library that intercepts
# malloc, add -DGC_USE_DLOPEN_WRAP -DREDIRECT_MALLOC=GC_malloc -fpic
#
# To build the parallel collector in a static library on HP/UX,
# add to the above:
# -DGC_HPUX_THREADS -DTHREAD_LOCAL_ALLOC -D_POSIX_C_SOURCE=199506L -mt
# FIXME: PARALLEL_MARK currently broken on HP/UX.
#
# To build the thread-safe collector on Tru64, add to the above:
# -pthread -DGC_OSF1_THREADS
@ -111,7 +122,7 @@ SRCS= $(CSRCS) \
ia64_save_regs_in_stack.s sparc_mach_dep.S \
sparc_netbsd_mach_dep.s sparc_sunos4_mach_dep.s $(CORD_SRCS)
DOC_FILES= README.QUICK TODO doc/README.Mac doc/README.OS2 \
DOC_FILES= doc/README.Mac doc/README.OS2 \
doc/README.amiga doc/README.cords doc/debugging.html \
doc/finalization.html doc/porting.html doc/overview.html \
doc/README.hp doc/README.linux doc/README.rs6000 \
@ -136,11 +147,10 @@ GNU_BUILD_FILES= configure.ac Makefile.am configure install-sh Makefile.in \
OTHER_MAKEFILES= OS2_MAKEFILE NT_MAKEFILE gc.mak \
BCC_MAKEFILE EMX_MAKEFILE WCC_MAKEFILE PCR-Makefile SMakefile.amiga \
digimars.mak Makefile.direct NT_STATIC_THREADS_MAKEFILE \
NT_X64_STATIC_THREADS_MAKEFILE NT_X64_THREADS_MAKEFILE
digimars.mak Makefile.direct
OTHER_FILES= tools/setjmp_t.c tools/callprocs.sh extra/MacOS.c \
extra/Mac_files/datastart.c extra/Mac_files/dataend.c \
OTHER_FILES= README.QUICK tools/setjmp_t.c tools/callprocs.sh \
extra/MacOS.c extra/Mac_files/datastart.c extra/Mac_files/dataend.c \
extra/Mac_files/MacOS_config.h tools/add_gc_prefix.c gc_cpp.cpp \
extra/symbian/global_end.cpp extra/symbian/global_start.cpp \
extra/symbian/init_global_static_roots.cpp extra/symbian.cpp \
@ -154,33 +164,35 @@ CORD_INCLUDE_FILES= $(srcdir)/include/gc.h $(srcdir)/include/cord.h \
UTILS= if_mach if_not_there threadlibs
# Libraries needed for curses applications. Only needed for de.
CURSES= -lcurses -ltermlib
# It might also require -ltermlib on some targets.
CURSES= -lcurses
# The following is irrelevant on most systems. But a few
# versions of make otherwise fork the shell specified in
# the SHELL environment variable.
SHELL= /bin/sh
SPECIALCFLAGS = -I$(srcdir)/include -I$(AO_SRC_DIR)/src
SPECIALCFLAGS= -I$(srcdir)/include -I$(AO_SRC_DIR)/src
# Alternative flags to the C compiler for mach_dep.c.
# Mach_dep.c often doesn't like optimization, and it's
# not time-critical anyway.
# Set SPECIALCFLAGS to -q nodirect_code on Encore.
all: gc.a gctest
all: base_lib gctest
atomic_ops.o: $(AO_SRC_DIR)/src/atomic_ops.c
$(CC) $(CFLAGS) -c -o $@ $<
$(CC) $(CFLAGS) -c -o $@ $(AO_SRC_DIR)/src/atomic_ops.c
# For some reason, Solaris make does not handle "$<" properly.
atomic_ops_sysdeps.o: $(AO_SRC_DIR)/src/atomic_ops_sysdeps.S
$(CC) $(CFLAGS) -c -o $@ $<
$(CC) $(CFLAGS) -c -o $@ $(AO_SRC_DIR)/src/atomic_ops_sysdeps.S
LEAKFLAGS=$(CFLAGS) -DFIND_LEAK
LEAKFLAGS= $(CFLAGS) -DFIND_LEAK
BSD-pkg-all: bsd-libgc.a bsd-libleak.a
bsd-libgc.a:
$(MAKE) CFLAGS="$(CFLAGS)" clean c++-t
$(MAKE) -f Makefile.direct CFLAGS="$(CFLAGS)" clean c++-t
mv gc.a bsd-libgc.a
bsd-libleak.a:
@ -200,18 +212,18 @@ mach_dep.o $(SRCS)
$(MAKE) -f PCR-Makefile
$(OBJS) tests/test.o dyn_load.o dyn_load_sunos53.o: \
$(srcdir)/include/private/gc_priv.h \
$(srcdir)/include/private/gc_hdrs.h $(srcdir)/include/private/gc_locks.h \
$(srcdir)/include/gc.h $(srcdir)/include/gc_pthread_redirects.h \
$(srcdir)/include/private/gcconfig.h $(srcdir)/include/gc_typed.h \
$(srcdir)/include/gc_config_macros.h
$(srcdir)/include/private/gc_priv.h \
$(srcdir)/include/private/gc_hdrs.h $(srcdir)/include/private/gc_locks.h \
$(srcdir)/include/gc.h $(srcdir)/include/gc_pthread_redirects.h \
$(srcdir)/include/private/gcconfig.h $(srcdir)/include/gc_typed.h \
$(srcdir)/include/gc_config_macros.h
mark.o typd_mlc.o finalize.o ptr_chck.o: $(srcdir)/include/gc_mark.h \
$(srcdir)/include/private/gc_pmark.h
specific.o pthread_support.o thread_local_alloc.o win32_threads.o: \
$(srcdir)/include/private/specific.h $(srcdir)/include/gc_inline.h \
$(srcdir)/include/private/thread_local_alloc.h
$(srcdir)/include/private/specific.h $(srcdir)/include/gc_inline.h \
$(srcdir)/include/private/thread_local_alloc.h
dbg_mlc.o gcj_mlc.o: $(srcdir)/include/private/dbg_mlc.h
@ -223,7 +235,6 @@ tests:
mkdir tests
base_lib gc.a: $(OBJS) dyn_load.o $(UTILS)
echo > base_lib
rm -f dont_ar_1
./if_mach SPARC SOLARIS touch dont_ar_1
./if_mach SPARC SOLARIS $(AR) rus gc.a $(OBJS) dyn_load.o
@ -231,9 +242,11 @@ base_lib gc.a: $(OBJS) dyn_load.o $(UTILS)
./if_mach M68K AMIGA $(AR) -vrus gc.a $(OBJS) dyn_load.o
./if_not_there dont_ar_1 $(AR) ru gc.a $(OBJS) dyn_load.o
./if_not_there dont_ar_1 $(RANLIB) gc.a || cat /dev/null
# ignore ranlib failure; that usually means it doesn't exist, and isn't needed
echo > base_lib
# Ignore ranlib failure; that usually means it doesn't exist, and
# isn't needed.
cords: $(CORD_OBJS) cord/cordtest $(UTILS)
cords: $(CORD_OBJS) cord/cordtest $(UTILS) base_lib
rm -f dont_ar_3
./if_mach SPARC SOLARIS touch dont_ar_3
./if_mach SPARC SOLARIS $(AR) rus gc.a $(CORD_OBJS)
@ -241,23 +254,27 @@ cords: $(CORD_OBJS) cord/cordtest $(UTILS)
./if_mach M68K AMIGA $(AR) -vrus gc.a $(CORD_OBJS)
./if_not_there dont_ar_3 $(AR) ru gc.a $(CORD_OBJS)
./if_not_there dont_ar_3 $(RANLIB) gc.a || cat /dev/null
echo > cords
gc_cpp.o: $(srcdir)/gc_cpp.cc $(srcdir)/include/gc_cpp.h $(srcdir)/include/gc.h
$(CXX) -c $(CXXFLAGS) $(srcdir)/gc_cpp.cc
test_cpp: $(srcdir)/tests/test_cpp.cc $(srcdir)/include/gc_cpp.h gc_cpp.o $(srcdir)/include/gc.h \
base_lib $(UTILS)
test_cpp: $(srcdir)/tests/test_cpp.cc $(srcdir)/include/gc_cpp.h $(srcdir)/include/gc.h \
gc_cpp.o base_lib $(UTILS)
rm -f test_cpp
./if_mach HP_PA HPUX $(CXX) $(CXXFLAGS) -o test_cpp $(srcdir)/tests/test_cpp.cc gc_cpp.o gc.a -ldld `./threadlibs`
./if_not_there test_cpp $(CXX) $(CXXFLAGS) -o test_cpp $(srcdir)/tests/test_cpp.cc gc_cpp.o gc.a `./threadlibs`
c++-t: c++
check-cpp: test_cpp
./test_cpp
c++-t: c++ test_cpp
./test_cpp 1
c++-nt: c++
@echo "Use ./test_cpp 1 to test the leak library"
c++: gc_cpp.o $(srcdir)/include/gc_cpp.h test_cpp
c++: gc_cpp.o $(srcdir)/include/gc_cpp.h base_lib
rm -f dont_ar_4
./if_mach SPARC SOLARIS touch dont_ar_4
./if_mach SPARC SOLARIS $(AR) rus gc.a gc_cpp.o
@ -265,7 +282,6 @@ c++: gc_cpp.o $(srcdir)/include/gc_cpp.h test_cpp
./if_mach M68K AMIGA $(AR) -vrus gc.a gc_cpp.o
./if_not_there dont_ar_4 $(AR) ru gc.a gc_cpp.o
./if_not_there dont_ar_4 $(RANLIB) gc.a || cat /dev/null
./test_cpp 1
echo > c++
dyn_load_sunos53.o: dyn_load.c
@ -278,12 +294,12 @@ sunos5gc.so: $(OBJS) dyn_load_sunos53.o
# Alpha/OSF shared library version of the collector
libalphagc.so: $(OBJS)
ld -shared -o libalphagc.so $(OBJS) dyn_load.o -lc
$(LD) -shared -o libalphagc.so $(OBJS) dyn_load.o -lc
ln libalphagc.so libgc.so
# IRIX shared library version of the collector
libirixgc.so: $(OBJS) dyn_load.o
ld -shared $(ABI_FLAG) -o libirixgc.so $(OBJS) dyn_load.o -lc
$(LD) -shared $(ABI_FLAG) -o libirixgc.so $(OBJS) dyn_load.o -lc
ln libirixgc.so libgc.so
# Linux shared library version of the collector
@ -303,33 +319,37 @@ dyn_test:
#.SUFFIXES: .lo $(SUFFIXES)
#
#.c.lo:
# $(CC) $(CFLAGS) $(CPPFLAGS) -fPIC -c $< -o $@
# $(CC) $(CFLAGS) $(CPPFLAGS) -fPIC -c $< -o $@
#
# liblinuxgc.so: $(LIBOBJS) dyn_load.lo
# gcc -shared -Wl,-soname=libgc.so.0 -o libgc.so.0 $(LIBOBJS) dyn_load.lo
# touch liblinuxgc.so
mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/sparc_mach_dep.S \
$(srcdir)/sparc_sunos4_mach_dep.s \
$(srcdir)/ia64_save_regs_in_stack.s \
$(srcdir)/sparc_netbsd_mach_dep.s $(UTILS)
$(srcdir)/sparc_sunos4_mach_dep.s \
$(srcdir)/ia64_save_regs_in_stack.s \
$(srcdir)/sparc_netbsd_mach_dep.s $(UTILS)
rm -f mach_dep.o
./if_mach SPARC SOLARIS $(CC) -c -o mach_dep2.o $(srcdir)/sparc_mach_dep.S
./if_mach SPARC OPENBSD $(AS) -o mach_dep2.o $(srcdir)/sparc_sunos4_mach_dep.s
./if_mach SPARC NETBSD $(AS) -o mach_dep2.o $(srcdir)/sparc_netbsd_mach_dep.s
./if_mach SPARC "" $(CC) -c -o mach_dep1.o $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
./if_mach SPARC "" ld -r -o mach_dep.o mach_dep1.o mach_dep2.o
./if_mach IA64 "" as $(AS_ABI_FLAG) -o ia64_save_regs_in_stack.o $(srcdir)/ia64_save_regs_in_stack.s
./if_mach SPARC "" $(LD) -r -o mach_dep.o mach_dep1.o mach_dep2.o
./if_mach IA64 "" $(AS) -o ia64_save_regs_in_stack.o $(srcdir)/ia64_save_regs_in_stack.s
./if_mach IA64 "" $(CC) -c -o mach_dep1.o $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
./if_mach IA64 "" ld -r -o mach_dep.o mach_dep1.o ia64_save_regs_in_stack.o
./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
./if_mach IA64 "" $(LD) -r -o mach_dep.o mach_dep1.o ia64_save_regs_in_stack.o
-./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
-./if_not_there mach_dep.o `cygpath -w /bin/sh` $(CC) -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
-./if_not_there mach_dep.o /bin/sh $(CC) -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
mark_rts.o: $(srcdir)/mark_rts.c $(UTILS)
rm -f mark_rts.o
-./if_mach ALPHA OSF1 $(CC) -c $(CFLAGS) -Wo,-notail $(srcdir)/mark_rts.c
./if_not_there mark_rts.o $(CC) -c $(CFLAGS) $(srcdir)/mark_rts.c
# Work-around for DEC optimizer tail recursion elimination bug.
# The ALPHA-specific line should be removed if gcc is used.
-./if_not_there mark_rts.o $(CC) -c $(CFLAGS) $(srcdir)/mark_rts.c
-./if_not_there mark_rts.o `cygpath -w /bin/sh` $(CC) -c $(CFLAGS) $(srcdir)/mark_rts.c
-./if_not_there mark_rts.o /bin/sh $(CC) -c $(CFLAGS) $(srcdir)/mark_rts.c
# Work-around for DEC optimizer tail recursion elimination bug.
# The ALPHA-specific line should be removed if gcc is used.
alloc.o: include/gc_version.h
@ -349,17 +369,18 @@ cord/cordprnt.o: cord $(srcdir)/cord/cordprnt.c $(CORD_INCLUDE_FILES)
$(CC) $(CFLAGS) -c -I$(srcdir) $(srcdir)/cord/cordprnt.c
mv cordprnt.o cord/cordprnt.o
cord/cordtest: $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) gc.a $(UTILS)
cord/cordtest: $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) base_lib $(UTILS)
rm -f cord/cordtest
./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) gc.a -lucb
./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) gc.a -ldld `./threadlibs`
./if_mach M68K AMIGA $(CC) $(CFLAGS) -UGC_AMIGA_MAKINGLIB -o cord/cordtest $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) gc.a `./threadlibs`
./if_not_there cord/cordtest $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) gc.a `./threadlibs`
cord/de: $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(UTILS)
cord/de: $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o base_lib \
$(UTILS)
rm -f cord/de
./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lucb `./threadlibs`
./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -ldld `./threadlibs`
./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses -ltermlib -lucb `./threadlibs`
./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses -ltermlib -ldld `./threadlibs`
./if_mach POWERPC AIX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
./if_mach POWERPC DARWIN $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a
./if_mach I386 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
@ -378,12 +399,13 @@ if_not_there: $(srcdir)/tools/if_not_there.c
$(HOSTCC) $(HOSTCFLAGS) -o if_not_there $(srcdir)/tools/if_not_there.c
clean:
rm -f gc.a *.o *.exe tests/*.o gctest gctest_dyn_link test_cpp \
setjmp_test mon.out gmon.out a.out core if_not_there if_mach \
base_lib c++ threadlibs $(CORD_OBJS) cord/cordtest cord/de
rm -f gc.a *.i *.o *.exe tests/*.o gctest gctest_dyn_link test_cpp \
setjmp_test mon.out gmon.out a.out core if_not_there if_mach \
base_lib c++ $(CORD_OBJS) cord/cordtest cord/de cords \
dont_ar_* threadlibs
-rm -f *~
gctest: tests/test.o gc.a $(UTILS)
gctest: tests/test.o base_lib $(UTILS)
rm -f gctest
./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o gctest tests/test.o gc.a -lucb
./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o gctest tests/test.o gc.a -ldld `./threadlibs`
@ -396,7 +418,7 @@ gctest: tests/test.o gc.a $(UTILS)
setjmp_test: $(srcdir)/tools/setjmp_t.c $(srcdir)/include/gc.h $(UTILS)
$(CC) $(CFLAGS) -o setjmp_test $(srcdir)/tools/setjmp_t.c
test: KandRtest cord/cordtest
check: KandRtest cord/cordtest
cord/cordtest
# Those tests that work even with a K&R C compiler:
@ -404,13 +426,16 @@ KandRtest: setjmp_test gctest
./setjmp_test
./gctest
# A synonym to "check" (for compatibility with older GC versions).
test: check
add_gc_prefix: $(srcdir)/tools/add_gc_prefix.c $(srcdir)/include/gc_version.h
$(CC) -o add_gc_prefix $(srcdir)/tools/add_gc_prefix.c
gcname: $(srcdir)/tools/gcname.c $(srcdir)/include/gc_version.h
$(CC) -o gcname $(srcdir)/tools/gcname.c
#We assume this is being done from source directory.
# We assume this is being done from source directory.
dist gc.tar: $(SRCS) $(DOC_FILES) $(OTHER_FILES) add_gc_prefix gcname
rm -f `./gcname`
ln -s . `./gcname`
@ -432,7 +457,7 @@ lint: $(CSRCS) tests/test.c
# BTL: added to test shared library version of collector.
# Currently works only under SunOS5. Requires GC_INIT call from statically
# loaded client code.
ABSDIR = `pwd`
ABSDIR= `pwd`
gctest_dyn_link: tests/test.o libgc.so
$(CC) -L$(ABSDIR) -R$(ABSDIR) -o gctest_dyn_link tests/test.o -lgc -ldl -lthread

View file

@ -136,51 +136,50 @@ check_PROGRAMS = cordtest$(EXEEXT) gctest$(EXEEXT) leaktest$(EXEEXT) \
middletest$(EXEEXT) smashtest$(EXEEXT) hugetest$(EXEEXT) \
realloc_test$(EXEEXT) staticrootstest$(EXEEXT) $(am__EXEEXT_1) \
$(am__EXEEXT_2) $(am__EXEEXT_3) $(am__EXEEXT_4)
TESTS = cordtest$(EXEEXT) gctest$(EXEEXT) leaktest$(EXEEXT) \
middletest$(EXEEXT) smashtest$(EXEEXT) hugetest$(EXEEXT) \
realloc_test$(EXEEXT) staticrootstest$(EXEEXT) \
$(am__append_12) $(am__append_14) $(am__append_16) \
$(am__EXEEXT_4)
@SINGLE_GC_OBJ_FALSE@am__append_1 = extra/gc.c
@PTHREAD_START_STANDALONE_TRUE@@SINGLE_GC_OBJ_TRUE@am__append_1 = -DGC_PTHREAD_START_STANDALONE
@PTHREAD_START_STANDALONE_TRUE@@SINGLE_GC_OBJ_TRUE@am__append_2 = pthread_start.c
@SINGLE_GC_OBJ_FALSE@am__append_3 = extra/gc.c
# C Library: Architecture Dependent
# ---------------------------------
@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_TRUE@am__append_2 = win32_threads.c
@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@am__append_3 = pthread_start.c pthread_support.c
@DARWIN_THREADS_TRUE@@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@am__append_4 = darwin_stop_world.c
@DARWIN_THREADS_FALSE@@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@am__append_5 = pthread_stop_world.c
@MAKE_BACK_GRAPH_TRUE@@SINGLE_GC_OBJ_FALSE@am__append_6 = backgraph.c
@ENABLE_DISCLAIM_TRUE@@SINGLE_GC_OBJ_FALSE@am__append_7 = fnlz_mlc.c
@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_TRUE@am__append_4 = thread_local_alloc.c win32_threads.c
# Not Cygwin or MinGW.
@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@am__append_5 = pthread_start.c pthread_support.c thread_local_alloc.c
@DARWIN_THREADS_TRUE@@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@am__append_6 = darwin_stop_world.c
@DARWIN_THREADS_FALSE@@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@am__append_7 = pthread_stop_world.c
@MAKE_BACK_GRAPH_TRUE@@SINGLE_GC_OBJ_FALSE@am__append_8 = backgraph.c
@ENABLE_DISCLAIM_TRUE@@SINGLE_GC_OBJ_FALSE@am__append_9 = fnlz_mlc.c
# C++ Interface
# -------------
@CPLUSPLUS_TRUE@am__append_8 = libgccpp.la
@CPLUSPLUS_TRUE@am__append_9 = include/gc_cpp.h
@CPLUSPLUS_TRUE@am__append_10 = include/extra/gc_cpp.h
@THREADS_TRUE@am__append_11 = $(THREADDLLIBS)
@KEEP_BACK_PTRS_TRUE@am__append_12 = tracetest$(EXEEXT)
@KEEP_BACK_PTRS_TRUE@am__append_13 = tracetest
@THREADS_TRUE@am__append_14 = threadleaktest$(EXEEXT) \
@CPLUSPLUS_TRUE@am__append_10 = libgccpp.la
@CPLUSPLUS_TRUE@am__append_11 = include/gc_cpp.h
@CPLUSPLUS_TRUE@am__append_12 = include/extra/gc_cpp.h
@THREADS_TRUE@am__append_13 = $(THREADDLLIBS)
@KEEP_BACK_PTRS_TRUE@am__append_14 = tracetest$(EXEEXT)
@KEEP_BACK_PTRS_TRUE@am__append_15 = tracetest
@THREADS_TRUE@am__append_16 = threadleaktest$(EXEEXT) \
@THREADS_TRUE@ threadkey_test$(EXEEXT) \
@THREADS_TRUE@ subthreadcreate_test$(EXEEXT) \
@THREADS_TRUE@ initsecondarythread_test$(EXEEXT)
@THREADS_TRUE@am__append_15 = threadleaktest threadkey_test \
@THREADS_TRUE@am__append_17 = threadleaktest threadkey_test \
@THREADS_TRUE@ subthreadcreate_test initsecondarythread_test
@CPLUSPLUS_TRUE@am__append_16 = test_cpp$(EXEEXT)
@CPLUSPLUS_TRUE@am__append_17 = test_cpp
@ENABLE_DISCLAIM_TRUE@am__append_18 = disclaim_test disclaim_bench
@ENABLE_DISCLAIM_TRUE@am__append_19 = disclaim_test disclaim_bench
@ENABLE_DISCLAIM_TRUE@@THREADS_TRUE@am__append_20 = $(THREADDLLIBS)
@CPLUSPLUS_TRUE@am__append_18 = test_cpp$(EXEEXT)
@CPLUSPLUS_TRUE@am__append_19 = test_cpp
@ENABLE_DISCLAIM_TRUE@am__append_20 = disclaim_test$(EXEEXT) \
@ENABLE_DISCLAIM_TRUE@ disclaim_bench$(EXEEXT)
@ENABLE_DISCLAIM_TRUE@am__append_21 = disclaim_test disclaim_bench
@ENABLE_DISCLAIM_TRUE@@THREADS_TRUE@am__append_22 = $(THREADDLLIBS)
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
$(top_srcdir)/configure.ac
am__aclocal_m4_deps = $(top_srcdir)/m4/gc_set_version.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
$(am__configure_deps) $(dist_pkgdata_DATA) \
$(am__configure_deps) $(am__dist_doc_DATA_DIST) \
$(dist_noinst_HEADERS) $(am__include_HEADERS_DIST) \
$(am__pkginclude_HEADERS_DIST) $(am__DIST_COMMON)
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
@ -216,9 +215,9 @@ am__uninstall_files_from_dir = { \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgdatadir)" \
"$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(includedir)" \
"$(DESTDIR)$(pkgincludedir)"
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(man3dir)" \
"$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgconfigdir)" \
"$(DESTDIR)$(includedir)" "$(DESTDIR)$(pkgincludedir)"
LTLIBRARIES = $(lib_LTLIBRARIES)
libcord_la_DEPENDENCIES = $(top_builddir)/libgc.la
am__dirstamp = $(am__leading_dot)dirstamp
@ -238,19 +237,21 @@ am__libgc_la_SOURCES_DIST = allchblk.c alloc.c blacklst.c checksums.c \
headers.c mach_dep.c malloc.c mallocx.c mark.c mark_rts.c \
misc.c new_hblk.c obj_map.c os_dep.c pcr_interface.c \
ptr_chck.c real_malloc.c reclaim.c specific.c stubborn.c \
thread_local_alloc.c typd_mlc.c win32_threads.c \
typd_mlc.c thread_local_alloc.c win32_threads.c \
pthread_start.c pthread_support.c darwin_stop_world.c \
pthread_stop_world.c backgraph.c fnlz_mlc.c extra/gc.c
@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_TRUE@am__objects_1 = \
@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_TRUE@am__objects_1 = thread_local_alloc.lo \
@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_TRUE@ win32_threads.lo
@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@am__objects_2 = pthread_start.lo \
@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@ pthread_support.lo
@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@ pthread_support.lo \
@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@ thread_local_alloc.lo
@DARWIN_THREADS_TRUE@@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@am__objects_3 = darwin_stop_world.lo
@DARWIN_THREADS_FALSE@@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@am__objects_4 = pthread_stop_world.lo
@MAKE_BACK_GRAPH_TRUE@@SINGLE_GC_OBJ_FALSE@am__objects_5 = \
@MAKE_BACK_GRAPH_TRUE@@SINGLE_GC_OBJ_FALSE@ backgraph.lo
@ENABLE_DISCLAIM_TRUE@@SINGLE_GC_OBJ_FALSE@am__objects_6 = \
@ENABLE_DISCLAIM_TRUE@@SINGLE_GC_OBJ_FALSE@ fnlz_mlc.lo
@PTHREAD_START_STANDALONE_TRUE@@SINGLE_GC_OBJ_TRUE@am__objects_7 = pthread_start.lo
@SINGLE_GC_OBJ_FALSE@am_libgc_la_OBJECTS = allchblk.lo alloc.lo \
@SINGLE_GC_OBJ_FALSE@ blacklst.lo checksums.lo dbg_mlc.lo \
@SINGLE_GC_OBJ_FALSE@ dyn_load.lo finalize.lo gc_dlopen.lo \
@ -259,15 +260,14 @@ am__libgc_la_SOURCES_DIST = allchblk.c alloc.c blacklst.c checksums.c \
@SINGLE_GC_OBJ_FALSE@ misc.lo new_hblk.lo obj_map.lo os_dep.lo \
@SINGLE_GC_OBJ_FALSE@ pcr_interface.lo ptr_chck.lo \
@SINGLE_GC_OBJ_FALSE@ real_malloc.lo reclaim.lo specific.lo \
@SINGLE_GC_OBJ_FALSE@ stubborn.lo thread_local_alloc.lo \
@SINGLE_GC_OBJ_FALSE@ typd_mlc.lo $(am__objects_1) \
@SINGLE_GC_OBJ_FALSE@ stubborn.lo typd_mlc.lo $(am__objects_1) \
@SINGLE_GC_OBJ_FALSE@ $(am__objects_2) $(am__objects_3) \
@SINGLE_GC_OBJ_FALSE@ $(am__objects_4) $(am__objects_5) \
@SINGLE_GC_OBJ_FALSE@ $(am__objects_6)
@SINGLE_GC_OBJ_TRUE@am_libgc_la_OBJECTS = extra/gc.lo $(am__objects_1) \
@SINGLE_GC_OBJ_TRUE@ $(am__objects_2) $(am__objects_3) \
@SINGLE_GC_OBJ_TRUE@ $(am__objects_4) $(am__objects_5) \
@SINGLE_GC_OBJ_TRUE@ $(am__objects_6)
@SINGLE_GC_OBJ_TRUE@am_libgc_la_OBJECTS = extra/gc.lo $(am__objects_7) \
@SINGLE_GC_OBJ_TRUE@ $(am__objects_1) $(am__objects_2) \
@SINGLE_GC_OBJ_TRUE@ $(am__objects_3) $(am__objects_4) \
@SINGLE_GC_OBJ_TRUE@ $(am__objects_5) $(am__objects_6)
@NEED_ATOMIC_OPS_ASM_FALSE@@USE_INTERNAL_LIBATOMIC_OPS_TRUE@nodist_libgc_la_OBJECTS = libatomic_ops/src/atomic_ops.lo
@NEED_ATOMIC_OPS_ASM_TRUE@nodist_libgc_la_OBJECTS = libatomic_ops/src/atomic_ops_sysdeps.lo
libgc_la_OBJECTS = $(am_libgc_la_OBJECTS) $(nodist_libgc_la_OBJECTS)
@ -505,7 +505,21 @@ am__can_run_installinfo = \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
DATA = $(dist_pkgdata_DATA) $(pkgconfig_DATA)
man3dir = $(mandir)/man3
NROFF = nroff
MANS = $(dist_man3_MANS)
am__dist_doc_DATA_DIST = AUTHORS README.md doc/README.DGUX386 \
doc/README.Mac doc/README.OS2 doc/README.amiga \
doc/README.arm.cross doc/README.autoconf doc/README.cmake \
doc/README.cords doc/README.darwin doc/README.environment \
doc/README.ews4800 doc/README.hp doc/README.linux \
doc/README.macros doc/README.rs6000 doc/README.sgi \
doc/README.solaris2 doc/README.symbian doc/README.uts \
doc/README.win32 doc/README.win64 doc/debugging.html \
doc/finalization.html doc/gcdescr.html doc/gcinterface.html \
doc/leak.html doc/overview.html doc/porting.html \
doc/scale.html doc/simple_example.html doc/tree.html
DATA = $(dist_doc_DATA) $(pkgconfig_DATA)
am__include_HEADERS_DIST = include/extra/gc_cpp.h include/extra/gc.h
am__pkginclude_HEADERS_DIST = include/gc_cpp.h include/gc.h \
include/gc_allocator.h include/gc_backptr.h \
@ -722,12 +736,12 @@ TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
$(TEST_LOG_FLAGS)
DIST_SUBDIRS = $(SUBDIRS)
am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/bdw-gc.pc.in \
$(srcdir)/cord/cord.am $(srcdir)/doc/doc.am \
$(srcdir)/include/include.am $(srcdir)/tests/tests.am \
$(top_srcdir)/include/config.h.in AUTHORS ChangeLog TODO \
compile config.guess config.sub depcomp install-sh ltmain.sh \
missing test-driver
am__DIST_COMMON = $(dist_man3_MANS) $(srcdir)/Makefile.in \
$(srcdir)/bdw-gc.pc.in $(srcdir)/cord/cord.am \
$(srcdir)/doc/doc.am $(srcdir)/include/include.am \
$(srcdir)/tests/tests.am $(top_srcdir)/include/config.h.in \
AUTHORS ChangeLog compile config.guess config.sub depcomp \
install-sh ltmain.sh missing test-driver
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir)
@ -763,20 +777,18 @@ am__relativize = \
dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
done; \
reldir="$$dir2"
DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.bz2
DIST_ARCHIVES = $(distdir).tar.gz
GZIP_ENV = --best
DIST_TARGETS = dist-bzip2 dist-gzip
DIST_TARGETS = dist-gzip
distuninstallcheck_listfiles = find . -type f -print
am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
| sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
distcleancheck_listfiles = find . -type f -print
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_CFLAGS = @GC_CFLAGS@
AM_CPPFLAGS = \
-I$(top_builddir)/include -I$(top_srcdir)/include \
$(ATOMIC_OPS_CFLAGS)
AM_CFLAGS = $(WERROR_CFLAGS) @GC_CFLAGS@
AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include \
$(ATOMIC_OPS_CFLAGS) $(am__append_1)
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
ATOMIC_OPS_CFLAGS = @ATOMIC_OPS_CFLAGS@
@ -790,13 +802,14 @@ CCAS = @CCAS@
CCASDEPMODE = @CCASDEPMODE@
CCASFLAGS = @CCASFLAGS@ $(DEFS)
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CFLAGS = @CFLAGS@ $(CFLAGS_EXTRA)
CFLAGS_EXTRA = @CFLAGS_EXTRA@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CXXFLAGS = @CXXFLAGS@ $(CFLAGS_EXTRA)
CXXLIBS = @CXXLIBS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
@ -857,6 +870,7 @@ STRIP = @STRIP@
THREADDLLIBS = @THREADDLLIBS@
UNWINDLIBS = @UNWINDLIBS@
VERSION = @VERSION@
WERROR_CFLAGS = @WERROR_CFLAGS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
@ -920,11 +934,17 @@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
# Info (current:revision:age) for the Libtool versioning system.
# These numbers should be updated at most once just before the release,
# and, optionally, at most once during the development (after the release).
LIBGC_VER_INFO = 4:4:3
LIBGCCPP_VER_INFO = 4:2:3
# We currently use the source files directly from libatomic_ops, if we
# use the internal version. This is done since libatomic_ops doesn't
# use libtool, since it has no real use for it. But that seems to make
# it hard to use either the resulting object files or libraries.
# Thus there seems too be no real reason to recursively build in the
# Thus there seems to be no real reason to recursively build in the
# libatomic_ops directory.
# if USE_INTERNAL_LIBATOMICS_OPS
# SUBDIRS = @maybe_libatomic_ops@
@ -934,12 +954,6 @@ top_srcdir = @top_srcdir@
SUBDIRS =
ACLOCAL_AMFLAGS = -I m4
# Initialize variables so that we can declare files locally.
# FIXME: If Visual C++ users use Makefile.am, this should go into
# pkginclude_HEADERS with proper AM_CONDITIONALization. Otherwise
# delete this comment.
# headers which are not installed
# (see include/include.am for more)
#
@ -952,16 +966,14 @@ ACLOCAL_AMFLAGS = -I m4
# files used by makefiles other than Makefile.am
#
EXTRA_DIST = $(am__append_1) gc_cpp.cpp README.QUICK TODO BCC_MAKEFILE \
EXTRA_DIST = $(am__append_3) gc_cpp.cpp README.QUICK BCC_MAKEFILE \
NT_MAKEFILE OS2_MAKEFILE PCR-Makefile digimars.mak \
EMX_MAKEFILE Makefile.direct SMakefile.amiga WCC_MAKEFILE \
autogen.sh NT_STATIC_THREADS_MAKEFILE \
NT_X64_STATIC_THREADS_MAKEFILE NT_X64_THREADS_MAKEFILE \
CMakeLists.txt tests/CMakeLists.txt tools/add_gc_prefix.c \
tools/gcname.c tools/if_mach.c tools/if_not_there.c \
tools/setjmp_t.c tools/threadlibs.c gc.mak extra/MacOS.c \
extra/AmigaOS.c extra/symbian/global_end.cpp \
extra/symbian/global_start.cpp \
autogen.sh CMakeLists.txt tests/CMakeLists.txt \
tools/add_gc_prefix.c tools/gcname.c tools/if_mach.c \
tools/if_not_there.c tools/setjmp_t.c tools/threadlibs.c \
gc.mak extra/MacOS.c extra/AmigaOS.c \
extra/symbian/global_end.cpp extra/symbian/global_start.cpp \
extra/symbian/init_global_static_roots.cpp extra/symbian.cpp \
build/s60v3/bld.inf build/s60v3/libgc.mmp \
extra/Mac_files/datastart.c extra/Mac_files/dataend.c \
@ -972,14 +984,14 @@ EXTRA_DIST = $(am__append_1) gc_cpp.cpp README.QUICK TODO BCC_MAKEFILE \
# C Library
# ---------
lib_LTLIBRARIES = libgc.la $(am__append_8) libcord.la
lib_LTLIBRARIES = libgc.la $(am__append_10) libcord.la
# unprefixed header
include_HEADERS = $(am__append_10) include/extra/gc.h
include_HEADERS = $(am__append_12) include/extra/gc.h
# installed headers
#
pkginclude_HEADERS = $(am__append_9) include/gc.h \
pkginclude_HEADERS = $(am__append_11) include/gc.h \
include/gc_allocator.h include/gc_backptr.h \
include/gc_config_macros.h include/gc_disclaim.h \
include/gc_gcj.h include/gc_inline.h include/gc_mark.h \
@ -1001,6 +1013,11 @@ dist_noinst_HEADERS = include/cord.h include/cord_pos.h include/ec.h \
include/private/thread_local_alloc.h
check_LTLIBRARIES = libstaticrootslib_test.la \
libstaticrootslib2_test.la
TESTS = cordtest$(EXEEXT) gctest$(EXEEXT) leaktest$(EXEEXT) \
middletest$(EXEEXT) smashtest$(EXEEXT) hugetest$(EXEEXT) \
realloc_test$(EXEEXT) staticrootstest$(EXEEXT) \
$(am__append_14) $(am__append_16) $(am__append_18) \
$(am__append_20)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = bdw-gc.pc
@SINGLE_GC_OBJ_FALSE@libgc_la_SOURCES = allchblk.c alloc.c blacklst.c \
@ -1010,15 +1027,14 @@ pkgconfig_DATA = bdw-gc.pc
@SINGLE_GC_OBJ_FALSE@ mark.c mark_rts.c misc.c new_hblk.c \
@SINGLE_GC_OBJ_FALSE@ obj_map.c os_dep.c pcr_interface.c \
@SINGLE_GC_OBJ_FALSE@ ptr_chck.c real_malloc.c reclaim.c \
@SINGLE_GC_OBJ_FALSE@ specific.c stubborn.c \
@SINGLE_GC_OBJ_FALSE@ thread_local_alloc.c typd_mlc.c \
@SINGLE_GC_OBJ_FALSE@ $(am__append_2) $(am__append_3) \
@SINGLE_GC_OBJ_FALSE@ specific.c stubborn.c typd_mlc.c \
@SINGLE_GC_OBJ_FALSE@ $(am__append_4) $(am__append_5) \
@SINGLE_GC_OBJ_FALSE@ $(am__append_6) $(am__append_7)
@SINGLE_GC_OBJ_FALSE@ $(am__append_6) $(am__append_7) \
@SINGLE_GC_OBJ_FALSE@ $(am__append_8) $(am__append_9)
@SINGLE_GC_OBJ_TRUE@libgc_la_SOURCES = extra/gc.c $(am__append_2) \
@SINGLE_GC_OBJ_TRUE@ $(am__append_3) $(am__append_4) \
@SINGLE_GC_OBJ_TRUE@ $(am__append_5) $(am__append_6) \
@SINGLE_GC_OBJ_TRUE@ $(am__append_7)
@SINGLE_GC_OBJ_TRUE@ $(am__append_4) $(am__append_5) \
@SINGLE_GC_OBJ_TRUE@ $(am__append_6) $(am__append_7) \
@SINGLE_GC_OBJ_TRUE@ $(am__append_8) $(am__append_9)
@NEED_ATOMIC_OPS_ASM_TRUE@nodist_libgc_la_SOURCES = libatomic_ops/src/atomic_ops_sysdeps.S
@USE_INTERNAL_LIBATOMIC_OPS_TRUE@nodist_libgc_la_SOURCES = libatomic_ops/src/atomic_ops.c
@ -1026,13 +1042,15 @@ pkgconfig_DATA = bdw-gc.pc
# linuxthread semaphore functions get linked:
libgc_la_LIBADD = @addobjs@ $(THREADDLLIBS) $(UNWINDLIBS) $(ATOMIC_OPS_LIBS)
libgc_la_DEPENDENCIES = @addobjs@
libgc_la_LDFLAGS = $(extra_ldflags_libgc) -version-info 1:3:0 -no-undefined
libgc_la_LDFLAGS = $(extra_ldflags_libgc) -version-info $(LIBGC_VER_INFO) \
-no-undefined
EXTRA_libgc_la_SOURCES = ia64_save_regs_in_stack.s sparc_mach_dep.S \
sparc_netbsd_mach_dep.s sparc_sunos4_mach_dep.s
@CPLUSPLUS_TRUE@libgccpp_la_SOURCES = gc_cpp.cc
@CPLUSPLUS_TRUE@libgccpp_la_LIBADD = ./libgc.la
@CPLUSPLUS_TRUE@libgccpp_la_LDFLAGS = -version-info 1:3:0 -no-undefined
@CPLUSPLUS_TRUE@libgccpp_la_LDFLAGS = -version-info $(LIBGCCPP_VER_INFO) -no-undefined
# Misc
# ----
@ -1047,8 +1065,13 @@ AM_CXXFLAGS = @GC_CFLAGS@
#include/private/pthread_stop_world.h \
#include/gc_mark.h @addincludes@
@ASM_WITH_CPP_UNSUPPORTED_TRUE@ASM_CPP_OPTIONS =
# Info (current:revision:age) for the Libtool versioning system.
# These numbers should be updated at most once just before the release,
# and, optionally, at most once during the development (after the release).
LIBCORD_VER_INFO = 4:1:3
libcord_la_LIBADD = $(top_builddir)/libgc.la
libcord_la_LDFLAGS = -version-info 1:3:0 -no-undefined
libcord_la_LDFLAGS = -version-info $(LIBCORD_VER_INFO) -no-undefined
libcord_la_CPPFLAGS = $(AM_CPPFLAGS)
libcord_la_SOURCES = \
cord/cordbscs.c \
@ -1061,7 +1084,7 @@ cordtest_LDADD = $(top_builddir)/libgc.la $(top_builddir)/libcord.la
# Common libs to _LDADD for all tests.
test_ldadd = $(top_builddir)/libgc.la $(EXTRA_TEST_LIBS)
gctest_SOURCES = tests/test.c
gctest_LDADD = $(test_ldadd) $(am__append_11)
gctest_LDADD = $(test_ldadd) $(am__append_13)
gctest_DEPENDENCIES = $(top_builddir)/libgc.la
leaktest_SOURCES = tests/leak_test.c
leaktest_LDADD = $(test_ldadd)
@ -1105,48 +1128,47 @@ libstaticrootslib2_test_la_LDFLAGS = -version-info 1:3:0 -no-undefined \
@AVOID_CPP_LIB_TRUE@@CPLUSPLUS_TRUE@test_cpp_LDADD = gc_cpp.o $(test_ldadd) $(CXXLIBS)
@ENABLE_DISCLAIM_TRUE@disclaim_test_SOURCES = tests/disclaim_test.c
@ENABLE_DISCLAIM_TRUE@disclaim_test_LDADD = $(test_ldadd) \
@ENABLE_DISCLAIM_TRUE@ $(am__append_20)
@ENABLE_DISCLAIM_TRUE@ $(am__append_22)
@ENABLE_DISCLAIM_TRUE@disclaim_bench_SOURCES = tests/disclaim_bench.c
@ENABLE_DISCLAIM_TRUE@disclaim_bench_LDADD = $(test_ldadd)
# installed documentation
#
dist_pkgdata_DATA = \
AUTHORS \
README.md \
doc/README.DGUX386 \
doc/README.Mac \
doc/README.OS2 \
doc/README.amiga \
doc/README.arm.cross \
doc/README.autoconf \
doc/README.cmake \
doc/README.cords \
doc/README.darwin \
doc/README.environment \
doc/README.ews4800 \
doc/README.hp \
doc/README.linux \
doc/README.macros \
doc/README.rs6000 \
doc/README.sgi \
doc/README.solaris2 \
doc/README.symbian \
doc/README.uts \
doc/README.win32 \
doc/README.win64 \
doc/debugging.html \
doc/finalization.html \
doc/gc.man \
doc/gcdescr.html \
doc/gcinterface.html \
doc/leak.html \
doc/overview.html \
doc/porting.html \
doc/scale.html \
doc/simple_example.html \
doc/tree.html
@ENABLE_DOCS_TRUE@dist_doc_DATA = \
@ENABLE_DOCS_TRUE@ AUTHORS \
@ENABLE_DOCS_TRUE@ README.md \
@ENABLE_DOCS_TRUE@ doc/README.DGUX386 \
@ENABLE_DOCS_TRUE@ doc/README.Mac \
@ENABLE_DOCS_TRUE@ doc/README.OS2 \
@ENABLE_DOCS_TRUE@ doc/README.amiga \
@ENABLE_DOCS_TRUE@ doc/README.arm.cross \
@ENABLE_DOCS_TRUE@ doc/README.autoconf \
@ENABLE_DOCS_TRUE@ doc/README.cmake \
@ENABLE_DOCS_TRUE@ doc/README.cords \
@ENABLE_DOCS_TRUE@ doc/README.darwin \
@ENABLE_DOCS_TRUE@ doc/README.environment \
@ENABLE_DOCS_TRUE@ doc/README.ews4800 \
@ENABLE_DOCS_TRUE@ doc/README.hp \
@ENABLE_DOCS_TRUE@ doc/README.linux \
@ENABLE_DOCS_TRUE@ doc/README.macros \
@ENABLE_DOCS_TRUE@ doc/README.rs6000 \
@ENABLE_DOCS_TRUE@ doc/README.sgi \
@ENABLE_DOCS_TRUE@ doc/README.solaris2 \
@ENABLE_DOCS_TRUE@ doc/README.symbian \
@ENABLE_DOCS_TRUE@ doc/README.uts \
@ENABLE_DOCS_TRUE@ doc/README.win32 \
@ENABLE_DOCS_TRUE@ doc/README.win64 \
@ENABLE_DOCS_TRUE@ doc/debugging.html \
@ENABLE_DOCS_TRUE@ doc/finalization.html \
@ENABLE_DOCS_TRUE@ doc/gcdescr.html \
@ENABLE_DOCS_TRUE@ doc/gcinterface.html \
@ENABLE_DOCS_TRUE@ doc/leak.html \
@ENABLE_DOCS_TRUE@ doc/overview.html \
@ENABLE_DOCS_TRUE@ doc/porting.html \
@ENABLE_DOCS_TRUE@ doc/scale.html \
@ENABLE_DOCS_TRUE@ doc/simple_example.html \
@ENABLE_DOCS_TRUE@ doc/tree.html
@ENABLE_DOCS_TRUE@dist_man3_MANS = doc/gc.man
all: all-recursive
.SUFFIXES:
@ -1615,27 +1637,68 @@ clean-libtool:
distclean-libtool:
-rm -f libtool config.lt
install-dist_pkgdataDATA: $(dist_pkgdata_DATA)
install-man3: $(dist_man3_MANS)
@$(NORMAL_INSTALL)
@list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \
@list1='$(dist_man3_MANS)'; \
list2=''; \
test -n "$(man3dir)" \
&& test -n "`echo $$list1$$list2`" \
|| exit 0; \
echo " $(MKDIR_P) '$(DESTDIR)$(man3dir)'"; \
$(MKDIR_P) "$(DESTDIR)$(man3dir)" || exit 1; \
{ for i in $$list1; do echo "$$i"; done; \
if test -n "$$list2"; then \
for i in $$list2; do echo "$$i"; done \
| sed -n '/\.3[a-z]*$$/p'; \
fi; \
} | while read p; do \
if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; echo "$$p"; \
done | \
sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
sed 'N;N;s,\n, ,g' | { \
list=; while read file base inst; do \
if test "$$base" = "$$inst"; then list="$$list $$file"; else \
echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \
$(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \
fi; \
done; \
for i in $$list; do echo "$$i"; done | $(am__base_list) | \
while read files; do \
test -z "$$files" || { \
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \
$(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \
done; }
uninstall-man3:
@$(NORMAL_UNINSTALL)
@list='$(dist_man3_MANS)'; test -n "$(man3dir)" || exit 0; \
files=`{ for i in $$list; do echo "$$i"; done; \
} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
dir='$(DESTDIR)$(man3dir)'; $(am__uninstall_files_from_dir)
install-dist_docDATA: $(dist_doc_DATA)
@$(NORMAL_INSTALL)
@list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkgdatadir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkgdatadir)" || exit 1; \
echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgdatadir)'"; \
$(INSTALL_DATA) $$files "$(DESTDIR)$(pkgdatadir)" || exit $$?; \
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \
$(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \
done
uninstall-dist_pkgdataDATA:
uninstall-dist_docDATA:
@$(NORMAL_UNINSTALL)
@list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \
@list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(pkgdatadir)'; $(am__uninstall_files_from_dir)
dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir)
install-pkgconfigDATA: $(pkgconfig_DATA)
@$(NORMAL_INSTALL)
@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
@ -2141,6 +2204,7 @@ distdir: $(DISTFILES)
dist-gzip: distdir
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
$(am__post_remove_distdir)
dist-bzip2: distdir
tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
$(am__post_remove_distdir)
@ -2265,10 +2329,10 @@ check-am: all-am
$(MAKE) $(AM_MAKEFLAGS) $(check_LTLIBRARIES) $(check_PROGRAMS)
$(MAKE) $(AM_MAKEFLAGS) check-TESTS
check: check-recursive
all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS)
all-am: Makefile $(LTLIBRARIES) $(MANS) $(DATA) $(HEADERS)
installdirs: installdirs-recursive
installdirs-am:
for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgdatadir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(includedir)" "$(DESTDIR)$(pkgincludedir)"; do \
for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(includedir)" "$(DESTDIR)$(pkgincludedir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-recursive
@ -2338,8 +2402,8 @@ info: info-recursive
info-am:
install-data-am: install-dist_pkgdataDATA install-includeHEADERS \
install-pkgconfigDATA install-pkgincludeHEADERS
install-data-am: install-dist_docDATA install-includeHEADERS \
install-man install-pkgconfigDATA install-pkgincludeHEADERS
install-dvi: install-dvi-recursive
@ -2355,7 +2419,7 @@ install-info: install-info-recursive
install-info-am:
install-man:
install-man: install-man3
install-pdf: install-pdf-recursive
@ -2387,10 +2451,12 @@ ps: ps-recursive
ps-am:
uninstall-am: uninstall-dist_pkgdataDATA uninstall-includeHEADERS \
uninstall-libLTLIBRARIES uninstall-pkgconfigDATA \
uninstall-am: uninstall-dist_docDATA uninstall-includeHEADERS \
uninstall-libLTLIBRARIES uninstall-man uninstall-pkgconfigDATA \
uninstall-pkgincludeHEADERS
uninstall-man: uninstall-man3
.MAKE: $(am__recursive_targets) check-am install-am install-strip
.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
@ -2403,19 +2469,19 @@ uninstall-am: uninstall-dist_pkgdataDATA uninstall-includeHEADERS \
distclean-hdr distclean-libtool distclean-tags distcleancheck \
distdir distuninstallcheck dvi dvi-am html html-am info \
info-am install install-am install-data install-data-am \
install-dist_pkgdataDATA install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-dist_docDATA install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am \
install-includeHEADERS install-info install-info-am \
install-libLTLIBRARIES install-man install-pdf install-pdf-am \
install-pkgconfigDATA install-pkgincludeHEADERS install-ps \
install-ps-am install-strip installcheck installcheck-am \
installdirs installdirs-am maintainer-clean \
install-libLTLIBRARIES install-man install-man3 install-pdf \
install-pdf-am install-pkgconfigDATA install-pkgincludeHEADERS \
install-ps install-ps-am install-strip installcheck \
installcheck-am installdirs installdirs-am maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
recheck tags tags-am uninstall uninstall-am \
uninstall-dist_pkgdataDATA uninstall-includeHEADERS \
uninstall-libLTLIBRARIES uninstall-pkgconfigDATA \
uninstall-pkgincludeHEADERS
uninstall-dist_docDATA uninstall-includeHEADERS \
uninstall-libLTLIBRARIES uninstall-man uninstall-man3 \
uninstall-pkgconfigDATA uninstall-pkgincludeHEADERS
.PRECIOUS: Makefile
@ -2432,9 +2498,6 @@ uninstall-am: uninstall-dist_pkgdataDATA uninstall-includeHEADERS \
.S.s:
if $(CPP) $< >$@ ; then :; else rm -f $@; fi
# Putting these at the top causes cord to be built first, and not find libgc.a
# on HP/UX. There may be a better fix.
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View file

@ -1,61 +1,135 @@
# Makefile for Windows NT. Assumes Microsoft compiler, and a single thread.
# Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor.
# Makefile for Windows NT. Assumes Microsoft compiler.
# Should be invoked as "nmake -f NT_MAKEFILE [<args>]"; the optional arguments
# are: "cpu=AMD64" - to target x64, "cpu=i386" - to target x86,
# "make_as_lib=1" - to build it as a static library, "nodebug=1" - to produce
# the release variant of the library, "nothreads=1" - to build the library and
# the tests without threads support.
MY_CPU=X86
CPU=$(MY_CPU)
!include <ntwin32.mak>
cc = cl
link = link
rc = rc
!IF !DEFINED(CPU) || "$(CPU)" == ""
CPU = $(PROCESSOR_ARCHITECTURE)
!ENDIF
!IF "$(CPU)" == "I386" || "$(CPU)" == "X86" || "$(CPU)" == "x86"
CPU = i386
!ELSEIF "$(CPU)" == "X64" || "$(CPU)" == "x64" || "$(CPU)" == "amd64"
CPU = AMD64
!ENDIF
!IF !DEFINED(NMAKE_WINVER)
NMAKE_WINVER = 0x0600
!ENDIF
cflags = $(cflags) -c -DCRTAPI1=_cdecl -DCRTAPI2=_cdecl -GS -D_WINNT -W4
!IF "$(CPU)" == "i386"
cflags = $(cflags) -D_X86_=1 -DWIN32 -D_WIN32
!ELSEIF "$(CPU)" == "AMD64"
cflags = $(cflags) -D_AMD64_=1 -DWIN64 -D_WIN64 -DWIN32 -D_WIN32
!ENDIF
cflags = $(cflags) -D_WIN32_WINNT=$(NMAKE_WINVER) -DWINVER=$(NMAKE_WINVER)
!IFDEF NODEBUG
cvarsmt = -D_MT -MT
cdebug = -Ox -DNDEBUG
rcvars = -DWIN32 -D_WIN32 -DWINVER=$(NMAKE_WINVER)
ldebug = /RELEASE
!ELSE
cvarsmt = -D_MT -MTd
cdebug = -Zi -Od -DDEBUG
rcvars = -DWIN32 -D_WIN32 -DWINVER=$(NMAKE_WINVER) -DDEBUG -D_DEBUG
ldebug = /DEBUG /DEBUGTYPE:cv
!ENDIF
!IF "$(CPU)" == "i386"
CVTRES_CPU=X86
!ELSEIF "$(CPU)" == "AMD64"
CVTRES_CPU=X64
!ENDIF
!IFNDEF NOTHREADS
CFLAGS_MT=$(cvarsmt) -DGC_THREADS -DTHREAD_LOCAL_ALLOC -DPARALLEL_MARK
!ENDIF
!IFDEF MAKE_AS_LIB
CFLAGS_GCDLL=-DGC_NOT_DLL
GC_LIB=gc.lib
LINK_GC=lib /out:$(GC_LIB)
!ELSE
CFLAGS_GCDLL=-DGC_DLL
!IF "$(CPU)" == "AMD64"
GC_DLL=gc64.dll
GC_LIB=gc64_dll.lib
!ELSE
GC_DLL=gc.dll
GC_LIB=gc_dll.lib
!ENDIF
LINK_DLL_FLAGS=kernel32.lib user32.lib /subsystem:windows /dll \
/INCREMENTAL:NO /pdb:"gc.pdb" /out:$(GC_DLL) /implib:$(GC_LIB)
LINK_GC=$(link) $(ldebug) $(LINK_DLL_FLAGS)
!ENDIF
CFLAGS_SPECIFIC=$(CFLAGS_GCDLL) $(CFLAGS_MT)
# Make sure that .cc is not viewed as a suffix. It is for VC++2005, but
# not earlier versions. We can deal with either, but not inconsistency.
.SUFFIXES:
.SUFFIXES: .obj .cpp .c
OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj fnlz_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj extra\msvc_dbg.obj
# Atomic_ops installation directory. For win32, the source directory
# should do, since we only need the headers.
# We assume this was manually unpacked.
AO_SRC_DIR=libatomic_ops/src
AO_INCLUDE_DIR=$(AO_SRC_DIR)
OBJS= misc.obj win32_threads.obj alloc.obj reclaim.obj allchblk.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj fnlz_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj extra\msvc_dbg.obj thread_local_alloc.obj
all: gctest.exe cord\de.exe test_cpp.exe
.c.obj:
$(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -D_CRT_SECURE_NO_DEPRECATE $*.c /Fo$*.obj
$(cc) $(cdebug) $(cflags) $(CFLAGS_SPECIFIC) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DCORD_NOT_DLL -D_CRT_SECURE_NO_DEPRECATE $*.c /Fo$*.obj /wd4100 /wd4127 /wd4701
# Disable crt security warnings, since unfortunately they warn about all sorts
# of safe uses of strncpy. It would be nice to leave the rest enabled.
.cpp.obj:
$(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -D_CRT_SECURE_NO_DEPRECATE $*.cpp /Fo$*.obj
$(cc) $(cdebug) $(cflags) $(CFLAGS_SPECIFIC) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -D_CRT_SECURE_NO_DEPRECATE $*.cpp /Fo$*.obj
$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\gc_disclaim.h include\private\msvc_dbg.h
gc.lib: $(OBJS)
lib /MACHINE:i386 /out:gc.lib $(OBJS)
# The original NT SDK used lib32 instead of lib
$(GC_LIB): $(OBJS)
$(LINK_GC) /MACHINE:$(CPU) $(OBJS)
gctest.exe: tests\test.obj gc.lib
# The following works for win32 debugging. For win32s debugging use debugtype:coff
# and add mapsympe line.
# This produces a "GUI" applications that opens no windows and writes to the log file
# "gctest.gc.log". This is done to make the result runnable under win32s.
$(link) -debug -debugtype:cv $(guiflags) -stack:131072 -out:$*.exe tests\test.obj $(guilibs) gc.lib
gctest.exe: $(GC_LIB) tests\test.obj
$(link) /MACHINE:$(CPU) /INCREMENTAL:NO $(ldebug) $(lflags) user32.lib -out:$*.exe tests\test.obj $(GC_LIB)
# mapsympe -n -o gctest.sym gctest.exe
# This produces a GUI app that opens no window and writes to gctest.gc.log.
cord\de_win.rbj: cord\de_win.res
cvtres /MACHINE:$(MY_CPU) /OUT:cord\de_win.rbj cord\de_win.res
cord\tests\de_win.rbj: cord\tests\de_win.res
cvtres /MACHINE:$(CVTRES_CPU) /OUT:cord\tests\de_win.rbj cord\tests\de_win.res
cord\tests\de.obj cord\tests\de_win.obj: include\cord.h include\cord_pos.h cord\tests\de_win.h cord\tests\de_cmds.h
cord\de_win.res: cord\tests\de_win.rc cord\tests\de_win.h cord\tests\de_cmds.h
$(rc) $(rcvars) -r -fo cord\de_win.res cord\tests\de_win.rc
cord\tests\de_win.res: cord\tests\de_win.rc cord\tests\de_win.h cord\tests\de_cmds.h
$(rc) $(rcvars) -r -fo cord\tests\de_win.res cord\tests\de_win.rc
# Cord/de is a real win32 gui application.
cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\de_win.rbj gc.lib
$(link) -debug -debugtype:cv $(guiflags) -stack:16384 -out:cord\de.exe cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\de_win.rbj gc.lib $(guilibs)
# Cord/de is a real win32 GUI app.
cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\tests\de_win.rbj $(GC_LIB)
$(link) /MACHINE:$(CPU) /INCREMENTAL:NO $(ldebug) $(lflags) -out:cord\de.exe cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\tests\de_win.rbj $(GC_LIB) gdi32.lib user32.lib
gc_cpp.obj: include\gc_cpp.h include\gc.h
gc_cpp.cpp: gc_cpp.cc
# copy gc_cpp.cc gc_cpp.cpp
gc_cpp.obj: gc_cpp.cc include\gc_cpp.h include\gc.h
test_cpp.cpp: tests\test_cpp.cc
copy tests\test_cpp.cc test_cpp.cpp
# This generates the C++ test executable. The executable expects
# a single numeric argument, which is the number of iterations.
# The output appears in the file "test_cpp.gc.log".
test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc.lib
$(link) -debug -debugtype:cv $(guiflags) -stack:16384 -out:test_cpp.exe test_cpp.obj gc.lib $(guilibs)
# The output appears in test_cpp.gc.log file.
test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h $(GC_LIB)
$(link) /MACHINE:$(CPU) /INCREMENTAL:NO $(ldebug) $(lflags) user32.lib -out:test_cpp.exe test_cpp.obj $(GC_LIB)
$(AO_SRC_DIR):
tar xvfz $(AO_SRC_DIR).tar.gz
clean:
del *.exe *.log *.obj *.pdb cord\*.exe cord\*.exp cord\*.lib cord\*.obj cord\*.pdb cord\tests\*.rbj cord\tests\*.res cord\tests\*.obj extra\*.obj gc*.lib gc*.dll gc*.exp test_cpp.cpp tests\*.obj 2> nul

View file

@ -1,71 +0,0 @@
# Makefile for Windows NT. Assumes Microsoft compiler.
# Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor.
MY_CPU=X86
CPU=$(MY_CPU)
!include <ntwin32.mak>
# Make sure that .cc is not viewed as a suffix. It is for VC++2005, but
# not earlier versions. We can deal with either, but not inconsistency.
.SUFFIXES:
.SUFFIXES: .obj .cpp .c
# Atomic_ops installation directory. For win32, the source directory
# should do, since we only need the headers.
# We assume this was manually unpacked, since I'm not sure there is
# a Windows standard command line tool to do this.
AO_SRC_DIR=libatomic_ops/src
AO_INCLUDE_DIR=$(AO_SRC_DIR)
OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj fnlz_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj win32_threads.obj extra\msvc_dbg.obj thread_local_alloc.obj
all: gctest.exe cord\de.exe test_cpp.exe
.c.obj:
$(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -DGC_THREADS -DTHREAD_LOCAL_ALLOC -DPARALLEL_MARK -D_CRT_SECURE_NO_DEPRECATE $*.c /Fo$*.obj
.cpp.obj:
$(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -DGC_THREADS -DTHREAD_LOCAL_ALLOC -D_CRT_SECURE_NO_DEPRECATE $*.cpp /Fo$*.obj
$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\gc_disclaim.h include\private\msvc_dbg.h
gc.lib: $(OBJS)
lib /MACHINE:i386 /out:gc.lib $(OBJS)
# The original NT SDK used lib32 instead of lib
gctest.exe: tests\test.obj gc.lib
# The following works for win32 debugging. For win32s debugging use debugtype:coff
# and add mapsympe line.
# This produces a "GUI" applications that opens no windows and writes to the log file
# "gctest.gc.log". This is done to make the result runnable under win32s.
$(link) -debug -debugtype:cv $(guiflags) -stack:262144 -out:$*.exe tests\test.obj $(guilibs) gc.lib
# mapsympe -n -o gctest.sym gctest.exe
cord\de_win.rbj: cord\de_win.res
cvtres /MACHINE:$(MY_CPU) /OUT:cord\de_win.rbj cord\de_win.res
cord\tests\de.obj cord\tests\de_win.obj: include\cord.h include\cord_pos.h cord\tests\de_win.h cord\tests\de_cmds.h
cord\de_win.res: cord\tests\de_win.rc cord\tests\de_win.h cord\tests\de_cmds.h
$(rc) $(rcvars) -r -fo cord\de_win.res cord\tests\de_win.rc
# Cord/de is a real win32 gui application.
cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\de_win.rbj gc.lib
$(link) -debug -debugtype:cv $(guiflags) -stack:16384 -out:cord\de.exe cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\de_win.rbj gc.lib $(guilibs)
gc_cpp.obj: include\gc_cpp.h include\gc.h
gc_cpp.cpp: gc_cpp.cc
# copy gc_cpp.cc gc_cpp.cpp
test_cpp.cpp: tests\test_cpp.cc
copy tests\test_cpp.cc test_cpp.cpp
# This generates the C++ test executable. The executable expects
# a single numeric argument, which is the number of iterations.
# The output appears in the file "test_cpp.gc.log".
test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc.lib
$(link) -debug -debugtype:cv $(guiflags) -stack:16384 -out:test_cpp.exe test_cpp.obj gc.lib $(guilibs)
AO_SCR_DIR:
tar xvfz $(AO_SRC_DIR).tar.gz;

View file

@ -1,70 +0,0 @@
# Makefile for Windows NT. Assumes Microsoft compiler.
# Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor.
MY_CPU=AMD64
CPU=$(MY_CPU)
!include <ntwin32.mak>
# Make sure that .cc is not viewed as a suffix. It is for VC++2005, but
# not earlier versions. We can deal with either, but not inconsistency.
.SUFFIXES:
.SUFFIXES: .obj .cpp .c
# Atomic_ops installation directory. For win32, the source directory
# should do, since we only need the headers.
# We assume this was manually unpacked, since I'm not sure there is
# a Windows standard command line tool to do this.
AO_SRC_DIR=libatomic_ops/src
AO_INCLUDE_DIR=$(AO_SRC_DIR)
OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj fnlz_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj win32_threads.obj extra\msvc_dbg.obj thread_local_alloc.obj
all: gctest.exe cord\de.exe test_cpp.exe
.c.obj:
$(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -DGC_THREADS -DTHREAD_LOCAL_ALLOC -D_CRT_SECURE_NO_DEPRECATE $*.c /Fo$*.obj /wd4701
# Disable "may not be initialized" warnings. They're too approximate.
# Disable crt security warnings, since unfortunately they warn about all sorts
# of safe uses of strncpy. It would be nice to leave the rest enabled.
.cpp.obj:
$(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -DGC_THREADS -DTHREAD_LOCAL_ALLOC -D_CRT_SECURE_NO_DEPRECATE $*.cpp /Fo$*.obj
$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\gc_disclaim.h include\private\msvc_dbg.h
gc.lib: $(OBJS)
lib /MACHINE:X64 /out:gc.lib $(OBJS)
gctest.exe: tests\test.obj gc.lib
# This produces a "GUI" applications that opens no windows and writes to
# the log file "gctest.gc.log".
$(link) $(ldebug) $(guiflags) -out:$*.exe tests\test.obj $(guilibs) gc.lib
cord\de_win.rbj: cord\de_win.res
cvtres /MACHINE:$(MY_CPU) /OUT:cord\de_win.rbj cord\de_win.res
cord\tests\de.obj cord\tests\de_win.obj: include\cord.h include\cord_pos.h cord\tests\de_win.h cord\tests\de_cmds.h
cord\de_win.res: cord\tests\de_win.rc cord\tests\de_win.h cord\tests\de_cmds.h
$(rc) $(rcvars) -r -fo cord\de_win.res cord\tests\de_win.rc
# Cord/de is a real win32 gui application.
cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\de_win.rbj gc.lib
$(link) $(ldebug) $(guiflags) -stack:16384 -out:cord\de.exe cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\de_win.rbj gc.lib $(guilibs)
gc_cpp.obj: include\gc_cpp.h include\gc.h
gc_cpp.cpp: gc_cpp.cc
# copy gc_cpp.cc gc_cpp.cpp
test_cpp.cpp: tests\test_cpp.cc
copy tests\test_cpp.cc test_cpp.cpp
# This generates the C++ test executable. The executable expects
# a single numeric argument, which is the number of iterations.
# The output appears in the file "test_cpp.gc.log".
test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc.lib
$(link) $(ldebug) $(guiflags) -stack:16384 -out:test_cpp.exe test_cpp.obj gc.lib $(guilibs)
AO_SCR_DIR:
tar xvfz $(AO_SRC_DIR).tar.gz;

View file

@ -1,87 +0,0 @@
# Makefile for Windows NT. Assumes Microsoft compiler.
# modified 2007 August by Friedrich Dominicus:
# - copied from NT_X64_STATIC_THREADS_MAKEFILES
# - checked agaist gc.mak (NT_THREADS_MAKEFILE)
# - added changes to integrate the tools
# - currently just with debug information
# problems can be sent to
# frido at q-software-solutions.de
#
# or the mailing list
MY_CPU=AMD64
CPU=$(MY_CPU)
!include <ntwin32.mak>
# Make sure that .cc is not viewed as a suffix. It is for VC++2005, but # not earlier versions. We can deal with either, but not inconsistency.
.SUFFIXES:
.SUFFIXES: .obj .cpp .c
# Atomic_ops installation directory. For win32, the source directory
# should do, since we only need the headers.
# We assume this was manually unpacked, since I'm not sure there is
# a Windows standard command line tool to do this.
AO_SRC_DIR=libatomic_ops/src
AO_INCLUDE_DIR=$(AO_SRC_DIR)
OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj fnlz_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj win32_threads.obj extra\msvc_dbg.obj thread_local_alloc.obj
all: gc64.dll gctest.exe cord\de.exe test_cpp.exe
.c.obj:
$(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_DLL -DGC_THREADS -D_CRT_SECURE_NO_DEPRECATE $*.c /Fo$*.obj /wd4701
# Disable "may not be initialized" warnings. They're too approximate.
# Disable crt security warnings, since unfortunately they warn about all sorts # of safe uses of strncpy. It would be nice to leave the rest enabled.
.cpp.obj:
$(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_DLL -DGC_THREADS -D_CRT_SECURE_NO_DEPRECATE $*.cpp /Fo$*.obj
$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\gc_disclaim.h include\private\msvc_dbg.h
LINK64=link.exe
LINK64_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib \
shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo \
/subsystem:windows /dll /incremental:no /pdb:"gc.pdb" /machine:X64 /out:"gc64.dll" \
/implib:"gc64_dll.lib"
gc64.dll : $(OBJS)
$(LINK64) $(ldebug) $(LINK64_FLAGS) $(OBJS)
gctest.exe: tests\test.obj gc64_dll.lib
# This produces a "GUI" applications that opens no windows and writes to
# the log file "gctest.gc.log".
$(link) $(ldebug) $(guiflags) -out:$*.exe tests\test.obj $(guilibs) gc64_dll.lib
cord\de_win.rbj: cord\de_win.res
cvtres /MACHINE:$(MY_CPU) /OUT:cord\de_win.rbj cord\de_win.res
cord\tests\de.obj cord\tests\de_win.obj: include\cord.h include\cord_pos.h cord\tests\de_win.h cord\tests\de_cmds.h
cord\de_win.res: cord\tests\de_win.rc cord\tests\de_win.h cord\tests\de_cmds.h
$(rc) $(rcvars) -r -fo cord\de_win.res cord\tests\de_win.rc
# Cord/de is a real win32 gui application.
cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\de_win.rbj gc64_dll.lib
$(link) $(ldebug) $(guiflags) -stack:16384 -out:cord\de.exe cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\de_win.rbj gc64_dll.lib $(guilibs)
gc_cpp.obj: include\gc_cpp.h include\gc.h
gc_cpp.cpp: gc_cpp.cc
# copy gc_cpp.cc gc_cpp.cpp
test_cpp.cpp: tests\test_cpp.cc
copy tests\test_cpp.cc test_cpp.cpp
# This generates the C++ test executable. The executable expects # a single numeric argument, which is the number of iterations.
# The output appears in the file "test_cpp.gc.log".
test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc64_dll.lib
$(link) $(ldebug) $(guiflags) -stack:16384 -out:test_cpp.exe test_cpp.obj gc64_dll.lib $(guilibs)
AO_SCR_DIR:
tar xvfz $(AO_SRC_DIR).tar.gz;
clean:
del *.obj gc64_dll.lib gc64.dll

View file

@ -32,9 +32,9 @@ LDFLAGS = $(CONFIG_LDFLAGS)
# Fix to point to local pcr installation directory.
PCRDIR= ..
COBJ= alloc.o reclaim.o allchblk.o misc.o os_dep.o mark_rts.o headers.o mark.o obj_map.o pcr_interface.o blacklst.o finalize.o new_hblk.o real_malloc.o dyn_load.o dbg_mlc.o fnlz_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o typd_mlc.o ptr_chck.o mallocx.o
COBJ= alloc.o reclaim.o allchblk.o misc.o os_dep.o mark_rts.o headers.o mark.o obj_map.o pcr_interface.o blacklst.o finalize.o new_hblk.o real_malloc.o dyn_load.o dbg_mlc.o fnlz_mlc.o malloc.o stubborn.o checksums.o typd_mlc.o ptr_chck.o mallocx.o
CSRC= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c fnlz_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c typd_mlc.c ptr_chck.c mallocx.c
CSRC= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c fnlz_mlc.c malloc.c stubborn.c checksums.c typd_mlc.c ptr_chck.c mallocx.c
SHELL= /bin/sh

View file

@ -2,6 +2,7 @@ Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
Copyright (c) 1999-2001 by Hewlett-Packard. All rights reserved.
Copyright (c) 2009-2018 Ivan Maidanski
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@ -26,10 +27,8 @@ For the version number, see README.md or include/gc_version.h files.
INSTALLATION:
Under UN*X, Linux:
Alternative 1 (the old way): type "make test" in this directory.
Link against gc.a. With the most recent GC distributions
you may have to type "make -f Makefile.direct test" or
copy Makefile.direct to Makefile first.
Alternative 1 (the old way): type "make -f Makefile.direct check".
Link against gc.a.
Alternative 2 (the new way): type
"./configure --prefix=<dir>; make; make check; make install".
@ -48,7 +47,7 @@ as described in doc/README.macros, or possibly use
--enable-threads=posix when running the configure script.
If you wish to use the cord (structured string) library with the stand-alone
Makefile.direct, type "make cords", after copying to "Makefile".
Makefile.direct, type "make -f Makefile.direct cords".
(This requires an ANSI C compiler. You may
need to redefine CC in the Makefile. The CORD_printf implementation in
cordprnt.c is known to be less than perfectly portable. The rest of the

View file

@ -1,11 +1,17 @@
# Boehm-Demers-Weiser Garbage Collector
This is version 7.5.0 (next release development) of a conservative garbage
This is version 7.6.8 of a conservative garbage
collector for C and C++.
You might find a more recent version
[here](http://www.hboehm.info/gc/), or
[here](https://github.com/ivmai/bdwgc).
## Download
You might find a more recent/stable version on the
[Download](https://github.com/ivmai/bdwgc/wiki/Download) page, or
[BDWGC site](http://www.hboehm.info/gc/).
Also, the latest bug fixes and new features are available in the
[development repository](https://github.com/ivmai/bdwgc).
## Overview
@ -63,7 +69,7 @@ collector. (See doc/README.cords and H.-J. Boehm, R. Atkinson, and M. Plass,
in Xerox Cedar, or the "rope" package in the SGI STL or the g++ distribution.)
Further collector documentation can be found
[here](http://www.hboehm.info/gc/).
in [overview.html](doc/overview.html).
## General Description
@ -174,14 +180,17 @@ libatomic_ops source repository as well) could look like:
git clone git://github.com/ivmai/bdwgc.git
cd bdwgc
git clone git://github.com/ivmai/libatomic_ops.git
autoreconf -vif
automake --add-missing
./autogen.sh
./configure
make
make -j
make check
If you are getting "syntax error near unexpected token ATOMIC_OPS" during
configure execution, this means pkg.m4 cannot be found, most probably
you should run `pkg-config` once before running `./autogen.sh` (autoreconf).
Below we focus on the collector build using classic makefile.
For the Makefile.direct-based process, typing `make test` instead of `make`
For the Makefile.direct-based process, typing `make check` instead of `make`
will automatically build the collector and then run `setjmp_test` and `gctest`.
`Setjmp_test` will give you information about configuring the collector, which is
useful primarily if you have a machine that's not already supported. Gctest is
@ -453,7 +462,7 @@ equivalents. (`GC_REGISTER_FINALIZER` is necessary, since pointers to
objects with debugging information are really pointers to a displacement
of 16 bytes form the object beginning, and some translation is necessary
when finalization routines are invoked. For details, about what's stored
in the header, see the definition of the type oh in debug_malloc.c)
in the header, see the definition of the type oh in dbg_mlc.c file.)
## Incremental/Generational Collection
@ -534,9 +543,30 @@ per MB of accessible memory that needs to be scanned and processor.
Your mileage may vary.) The incremental/generational collection facility
may help in some cases.
Please address bug reports [here](mailto:bdwgc@lists.opendylan.org).
If you are contemplating a major addition, you might also send mail to ask
whether it's already been done (or whether we tried and discarded it).
## Feedback, Contribution, Questions and Notifications
Please address bug reports and new feature ideas to
[GitHub issues](https://github.com/ivmai/bdwgc/issues). Before the
submission please check that it has not been done yet by someone else.
If you want to contribute, submit
a [pull request](https://github.com/ivmai/bdwgc/pulls) to GitHub.
If you need help, use
[Stack Overflow](https://stackoverflow.com/questions/tagged/boehm-gc).
Older technical discussions are available in `bdwgc` mailing list archive - it
can be downloaded as a
[compressed file](https://github.com/ivmai/bdwgc/files/1038163/bdwgc-mailing-list-archive-2017_04.tar.gz)
or browsed at [Narkive](http://bdwgc.opendylan.narkive.com).
To get new release announcements, subscribe to
[RSS feed](https://github.com/ivmai/bdwgc/releases.atom).
(To receive the notifications by email, a 3rd-party free service like
[IFTTT RSS Feed](https://ifttt.com/feed) can be setup.)
To be notified on all issues, please
[watch](https://github.com/ivmai/bdwgc/watchers) the project on
GitHub.
## Copyright & Warranty
@ -545,21 +575,31 @@ whether it's already been done (or whether we tried and discarded it).
* Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
* Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
* Copyright (c) 1999-2011 by Hewlett-Packard Development Company.
* Copyright (c) 2008-2018 Ivan Maidanski
The file linux_threads.c is also
The files pthread_stop_world.c, pthread_support.c and some others are also
* Copyright (c) 1998 by Fergus Henderson. All rights reserved.
The files Makefile.am, and configure.in are
The file gc.h is also
* Copyright (c) 2001 by Red Hat Inc. All rights reserved.
* Copyright (c) 2007 Free Software Foundation, Inc
The files Makefile.am and configure.ac are
* Copyright (c) 2001 by Red Hat Inc. All rights reserved.
The files msvc_dbg.c and msvc_dbg.h are
* Copyright (c) 2004-2005 Andrei Polushin
The file initsecondarythread.c is
* Copyright (c) 2011 Ludovic Courtes
Several files supporting GNU-style builds are copyrighted by the Free
Software Foundation, and carry a different license from that given
below. The files included in the libatomic_ops distribution (included
here) use either the license below, or a similar MIT-style license,
or, for some files not actually used by the garbage-collector library, the
GPL.
below.
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@ -575,8 +615,3 @@ slightly different licenses, though they are all similar in spirit. A few
are GPL'ed, but with an exception that should cover all uses in the
collector. (If you are concerned about such things, I recommend you look
at the notice in config.guess or ltmain.sh.)
The atomic_ops library contains some code that is covered by the GNU General
Public License, but is not needed by, nor linked into the collector library.
It is included here only because the atomic_ops distribution is, for
simplicity, included in its entirety.

View file

@ -1,6 +1,6 @@
# Rewritten smakefile for amiga / sas/c. -Kjetil M.
# Dont use the cord-package if you define parm=both or parm=reg.
# Don't use the cord-package if you define parm=both or parm=reg.
#----------------TOOLS--------------------------------
@ -32,7 +32,7 @@ DEFINE __USE_SYSBASE
SOPT= $(OPT) $(IGNORE) \
DEFINE AMIGA_SKIP_SEG \
DEFINE ATOMIC_UNCOLLECTABLE \
DEFINE GC_ATOMIC_UNCOLLECTABLE \
DEFINE GC_AMIGA_FASTALLOC \
DEFINE GC_AMIGA_RETRY \
DEFINE GC_AMIGA_PRINTSTATS \

View file

@ -1,93 +0,0 @@
== TODO tasks ==
tests/CMakeLists.txt: Add more executables (see tests.am).
Use C++0x ATM (atomic memory operations) if available (either from the
compiler runtime, provided it is reliable, or from the future libatomic_ops).
Add a test for libatomic_ops minimal version required (at compile time).
windows-untested: Remove if CMake can generate MS Visual Studio 6.0, 7.0, 8.0
project files.
BCC_MAKEFILE: Remove if CMake can generate Makefile for this compiler.
(Same for WCC_MAKEFILE, OS2_MAKEFILE, NT_MAKEFILE, NT_STATIC_THREADS_MAKEFILE,
NT_X64_STATIC_THREADS_MAKEFILE, NT_X64_THREADS_MAKEFILE, digimars.mak,
gc.mak.)
BCC_MAKEFILE, EMX_MAKEFILE, OS2_MAKEFILE, PCR-Makefile, WCC_MAKEFILE,
SMakefile.amiga, digimars.mak: move to "build" folder.
Do type-punning via union (instead of pointer type cast) to enable safe
'-fstrict-aliasing' compiler optimization option.
Support CAN_HANDLE_FORK if USE_WINALLOC for Cygwin.
Use madvise() on Unix/Cygwin.
Use Linux VM pressure notifications to force GC and unmapping.
Filter overlaps in GC_add_roots for Unix (same as for Win32).
Do not resume parallel markers if only 1 core is active at GC mark start.
Enable GC_set_handle_fork(1) for Darwin with GC_dirty_maintained on (both
single and multi-threaded modes).
Add more fields to GC_prof_stats_s (potential candidates are:
requested_heapsize, max_large_allocd_bytes, large_allocd_bytes, bytes_dropped,
bytes_finalized, bytes_freed, finalizer_bytes_freed, composite_in_use,
atomic_in_use, GC_n_heap_sects, GC_n_memory, GC_black_list_spacing,
GC_root_size, GC_max_root_size, n_root_sets, GC_total_stacksize,
GC_collect_at_heapsize, GC_fail_count, GC_mark_stack_size, last_fo_entries,
last_bytes_finalized, last_finalizer_notification_no, GC_dl_entries,
GC_old_dl_entries, GC_used_heap_size_after_full, GC_total_stack_black_listed,
signed_log_dl_table_size, GC_n_rescuing_pages, signed_log_fo_table_size,
GC_excl_table_entries, GC_stack_last_cleared, GC_bytes_allocd_at_reset,
GC_n_heap_bases, registered_threads_cnt, GC_max_thread_index, GC_block_count,
GC_unlocked_count, GC_hdr_cache_hits, GC_hdr_cache_misses, GC_spin_count).
Support musl libc (on sabotage linux).
== FIXME tasks ==
Solaris + GCC: make check fails with the message:
libc.so.1: gctest: fatal: libgcc_s.so.1: open failed: No such file or directory
Solaris/x86[_64]: gctest fails if PROC_VDB.
Sun C++ 5.11: test_cpp.cc:237: Error: Too few arguments in call to
"operator delete(void*, GCPlacement, extern "C" void(*)(void*,void*), void*)".
Darwin/x86_64: deadlock might occur between:
dlclose() -> GC_dyld_image_remove() -> GC_lock() and
GC_inner_start_routine()+LOCK -> dyld_stub_binder_().
HP-UX 11.00 with the vendor cc fails:
Perhaps GC_push_regs was configured incorrectly? FAIL: gctest.
Linux/mips64el (N32): threadleaktest crashes once every 3-4 runs (SIGSEGV in
GC_delete_gc_thread(t=0) called from GC_pthread_join) if configured with
--disable-shared.
FreeBSD 9.0/x86_64 (gcc-4.2.1-20070831): gctest segfaults sometimes in
GC_typed_mark_proc if configured with --enable-threads=pthreads.
OpenBSD 5.1/i386: leaktest fails rarely (unless logging redirected to file):
cannot write to stderr from GC_gcollect invoked from 'atexit' hook.
NetBSD 5.1/x86: threadkey_test hangs sometimes.
Cygwin: subthread_create: exception STATUS_ACCESS_VIOLATION.
Cygwin: gctest: assertion failure at UNLOCK in GC_fork_parent_proc.
Mingw-w32: gctest: "SuspendThread failed" sometimes occurs (if
GC_DLL+GC_THREADS+GC_ASSERTIONS).
Mingw: gctest (compiled with PARALLEL_MARK): launched in gdb with breakpoint
at GC_mark_local, after several breakpoint hits, crashes with the messages
"Caught ACCESS_VIOLATION in marker; memory mapping disappeared" and
"Tried to start parallel mark in bad state", or enters deadlock.
Mingw: test_cpp: crashes at some iteration if big argument (e.g., 1000) given.

View file

@ -1,7 +1,7 @@
# Makefile for Watcom C/C++ 10.5, 10.6, 11.0 on NT, OS2 and DOS4GW.
# May work with Watcom 10.0.
# Uncoment one of the lines below for cross compilation.
# Uncomment one of the lines below for cross compilation.
SYSTEM=MSWIN32
#SYSTEM=DOS4GW
#SYSTEM=OS2
@ -25,7 +25,7 @@ CPU=5
OPTIM=-oneatx -s
#OPTIM=-ohneatx -s
DEFS=-DALL_INTERIOR_POINTERS #-DSMALL_CONFIG #-DGC_DEBUG
DEFS=-DALL_INTERIOR_POINTERS #-DSMALL_CONFIG
#####
@ -66,11 +66,10 @@ TEST_DLLFLAG=
CC=wcc386
CXX=wpp386
# -DUSE_GENERIC is required !
CFLAGS=-$(CPU)$(CALLING) $(OPTIM) -zp4 -zc $(SYSFLAG) $(DLLFLAG) -DUSE_GENERIC $(DEFS)
CXXFLAGS= $(CFLAGS)
TEST_CFLAGS=-$(CPU)$(CALLING) $(OPTIM) -zp4 -zc $(SYSFLAG) $(TEST_DLLFLAG) $(DEFS)
TEST_CXXFLAGS= $(TEST_CFLAGS)
CFLAGS=-$(CPU)$(CALLING) $(OPTIM) -iinclude -zp4 -zc $(SYSFLAG) $(DLLFLAG) $(DEFS)
CXXFLAGS= $(CFLAGS) -xs
TEST_CFLAGS=-$(CPU)$(CALLING) $(OPTIM) -iinclude -zp4 -zc $(SYSFLAG) $(TEST_DLLFLAG) $(DEFS)
TEST_CXXFLAGS= $(TEST_CFLAGS) -xs
OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj &
mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj &
@ -96,23 +95,12 @@ gc.dll: $(OBJS) .AUTODEPEND
!endif
@%append $*.lnk name $*
@for %i in ($(OBJS)) do @%append $*.lnk file '%i'
!ifeq CALLING s
@%append $*.lnk export GC_is_marked
@%append $*.lnk export GC_incr_bytes_allocd
@%append $*.lnk export GC_incr_bytes_freed
@%append $*.lnk export GC_generic_malloc_words_small
!else
@%append $*.lnk export GC_is_marked_
@%append $*.lnk export GC_incr_bytes_allocd_
@%append $*.lnk export GC_incr_bytes_freed_
@%append $*.lnk export GC_generic_malloc_words_small_
!endif
*wlink @$*.lnk
!else
gc.lib: $(OBJS) gc_cpp.obj
@%create $*.lb1
@for %i in ($(OBJS)) do @%append $*.lb1 +'%i'
@%append $*.lb1 +'gc_cpp.obj'
@%append $*.lb1 +'gc_cpp.obj'
*wlib -b -c -n -p=512 $@ @$*.lb1
!endif
@ -132,13 +120,6 @@ gctest.exe: test.obj gc.lib
@%append $*.lnk name $*
@%append $*.lnk file test.obj
@%append $*.lnk library gc.lib
!ifdef MAKE_AS_DLL
!ifeq CALLING s
@%append $*.lnk import GC_is_marked gc
!else
@%append $*.lnk import GC_is_marked_ gc
!endif
!endif
*wlink @$*.lnk
test_cpp.exe: test_cpp.obj gc.lib
%create $*.lnk
@ -154,26 +135,14 @@ test_cpp.exe: test_cpp.obj gc.lib
@%append $*.lnk name $*
@%append $*.lnk file test_cpp.obj
@%append $*.lnk library gc.lib
!ifdef MAKE_AS_DLL
!ifeq CALLING s
@%append $*.lnk import GC_incr_bytes_allocd gc
@%append $*.lnk import GC_incr_bytes_freed gc
@%append $*.lnk import GC_generic_malloc_words_small gc
!else
@%append $*.lnk import GC_incr_bytes_allocd_ gc
@%append $*.lnk import GC_incr_bytes_freed_ gc
@%append $*.lnk import GC_generic_malloc_words_small_ gc
!endif
!endif
*wlink @$*.lnk
gc_cpp.obj: gc_cpp.cc .AUTODEPEND
$(CXX) $(TEST_CXXFLAGS) -iinclude $*.cc
$(CXX) $(TEST_CXXFLAGS) $*.cc
test.obj: tests\test.c .AUTODEPEND
$(CC) $(TEST_CFLAGS) $*.c
$(CC) $(TEST_CFLAGS) tests\test.c
test_cpp.obj: tests\test_cpp.cc .AUTODEPEND
$(CXX) $(TEST_CXXFLAGS) -iinclude $*.cc
$(CXX) $(TEST_CXXFLAGS) tests\test_cpp.cc
.c.obj: .AUTODEPEND
$(CC) $(CFLAGS) $*.c

218
src/bdwgc/aclocal.m4 vendored
View file

@ -20,32 +20,63 @@ You have another version of autoconf. It may work, but is not guaranteed to.
If you have problems, you may need to regenerate the build system entirely.
To do so, use the procedure documented by the package, typically 'autoreconf'.])])
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
# serial 1 (pkg-config-0.24)
#
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
# serial 12 (pkg-config-0.29.2)
# PKG_PROG_PKG_CONFIG([MIN-VERSION])
# ----------------------------------
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
dnl
dnl This program is free software; you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation; either version 2 of the License, or
dnl (at your option) any later version.
dnl
dnl This program is distributed in the hope that it will be useful, but
dnl WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
dnl General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with this program; if not, write to the Free Software
dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
dnl 02111-1307, USA.
dnl
dnl As a special exception to the GNU General Public License, if you
dnl distribute this file as part of a program that contains a
dnl configuration script generated by Autoconf, you may include it under
dnl the same distribution terms that you use for the rest of that
dnl program.
dnl PKG_PREREQ(MIN-VERSION)
dnl -----------------------
dnl Since: 0.29
dnl
dnl Verify that the version of the pkg-config macros are at least
dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
dnl installed version of pkg-config, this checks the developer's version
dnl of pkg.m4 when generating configure.
dnl
dnl To ensure that this macro is defined, also add:
dnl m4_ifndef([PKG_PREREQ],
dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
dnl
dnl See the "Since" comment for each macro you use to see what version
dnl of the macros you require.
m4_defun([PKG_PREREQ],
[m4_define([PKG_MACROS_VERSION], [0.29.2])
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
])dnl PKG_PREREQ
dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
dnl ----------------------------------
dnl Since: 0.16
dnl
dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
dnl first found in the path. Checks that the version of pkg-config found
dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
dnl used since that's the first version where most current features of
dnl pkg-config existed.
AC_DEFUN([PKG_PROG_PKG_CONFIG],
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
@ -67,18 +98,19 @@ if test -n "$PKG_CONFIG"; then
PKG_CONFIG=""
fi
fi[]dnl
])# PKG_PROG_PKG_CONFIG
])dnl PKG_PROG_PKG_CONFIG
# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
#
# Check to see whether a particular set of modules exists. Similar
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
#
# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
# only at the first occurence in configure.ac, so if the first place
# it's called might be skipped (such as if it is within an "if", you
# have to call PKG_CHECK_EXISTS manually
# --------------------------------------------------------------
dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl -------------------------------------------------------------------
dnl Since: 0.18
dnl
dnl Check to see whether a particular set of modules exists. Similar to
dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
dnl
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
dnl only at the first occurence in configure.ac, so if the first place
dnl it's called might be skipped (such as if it is within an "if", you
dnl have to call PKG_CHECK_EXISTS manually
AC_DEFUN([PKG_CHECK_EXISTS],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
if test -n "$PKG_CONFIG" && \
@ -88,8 +120,10 @@ m4_ifvaln([$3], [else
$3])dnl
fi])
# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
# ---------------------------------------------
dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
dnl ---------------------------------------------
dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
dnl pkg_failed based on the result.
m4_define([_PKG_CONFIG],
[if test -n "$$1"; then
pkg_cv_[]$1="$$1"
@ -101,10 +135,11 @@ m4_define([_PKG_CONFIG],
else
pkg_failed=untried
fi[]dnl
])# _PKG_CONFIG
])dnl _PKG_CONFIG
# _PKG_SHORT_ERRORS_SUPPORTED
# -----------------------------
dnl _PKG_SHORT_ERRORS_SUPPORTED
dnl ---------------------------
dnl Internal check to see if pkg-config supports short errors.
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@ -112,26 +147,24 @@ if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
else
_pkg_short_errors_supported=no
fi[]dnl
])# _PKG_SHORT_ERRORS_SUPPORTED
])dnl _PKG_SHORT_ERRORS_SUPPORTED
# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
# [ACTION-IF-NOT-FOUND])
#
#
# Note that if there is a possibility the first call to
# PKG_CHECK_MODULES might not happen, you should be sure to include an
# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
#
#
# --------------------------------------------------------------
dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
dnl [ACTION-IF-NOT-FOUND])
dnl --------------------------------------------------------------
dnl Since: 0.4.0
dnl
dnl Note that if there is a possibility the first call to
dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
AC_DEFUN([PKG_CHECK_MODULES],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
pkg_failed=no
AC_MSG_CHECKING([for $1])
AC_MSG_CHECKING([for $2])
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
@ -141,11 +174,11 @@ and $1[]_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.])
if test $pkg_failed = yes; then
AC_MSG_RESULT([no])
AC_MSG_RESULT([no])
_PKG_SHORT_ERRORS_SUPPORTED
if test $_pkg_short_errors_supported = yes; then
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
else
else
$1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
@ -162,7 +195,7 @@ installed software in a non-standard prefix.
_PKG_TEXT])[]dnl
])
elif test $pkg_failed = untried; then
AC_MSG_RESULT([no])
AC_MSG_RESULT([no])
m4_default([$4], [AC_MSG_FAILURE(
[The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
@ -178,16 +211,40 @@ else
AC_MSG_RESULT([yes])
$3
fi[]dnl
])# PKG_CHECK_MODULES
])dnl PKG_CHECK_MODULES
# PKG_INSTALLDIR(DIRECTORY)
# -------------------------
# Substitutes the variable pkgconfigdir as the location where a module
# should install pkg-config .pc files. By default the directory is
# $libdir/pkgconfig, but the default can be changed by passing
# DIRECTORY. The user can override through the --with-pkgconfigdir
# parameter.
dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
dnl [ACTION-IF-NOT-FOUND])
dnl ---------------------------------------------------------------------
dnl Since: 0.29
dnl
dnl Checks for existence of MODULES and gathers its build flags with
dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
dnl and VARIABLE-PREFIX_LIBS from --libs.
dnl
dnl Note that if there is a possibility the first call to
dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
dnl configure.ac.
AC_DEFUN([PKG_CHECK_MODULES_STATIC],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
_save_PKG_CONFIG=$PKG_CONFIG
PKG_CONFIG="$PKG_CONFIG --static"
PKG_CHECK_MODULES($@)
PKG_CONFIG=$_save_PKG_CONFIG[]dnl
])dnl PKG_CHECK_MODULES_STATIC
dnl PKG_INSTALLDIR([DIRECTORY])
dnl -------------------------
dnl Since: 0.27
dnl
dnl Substitutes the variable pkgconfigdir as the location where a module
dnl should install pkg-config .pc files. By default the directory is
dnl $libdir/pkgconfig, but the default can be changed by passing
dnl DIRECTORY. The user can override through the --with-pkgconfigdir
dnl parameter.
AC_DEFUN([PKG_INSTALLDIR],
[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
m4_pushdef([pkg_description],
@ -198,16 +255,18 @@ AC_ARG_WITH([pkgconfigdir],
AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
m4_popdef([pkg_default])
m4_popdef([pkg_description])
]) dnl PKG_INSTALLDIR
])dnl PKG_INSTALLDIR
# PKG_NOARCH_INSTALLDIR(DIRECTORY)
# -------------------------
# Substitutes the variable noarch_pkgconfigdir as the location where a
# module should install arch-independent pkg-config .pc files. By
# default the directory is $datadir/pkgconfig, but the default can be
# changed by passing DIRECTORY. The user can override through the
# --with-noarch-pkgconfigdir parameter.
dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
dnl --------------------------------
dnl Since: 0.27
dnl
dnl Substitutes the variable noarch_pkgconfigdir as the location where a
dnl module should install arch-independent pkg-config .pc files. By
dnl default the directory is $datadir/pkgconfig, but the default can be
dnl changed by passing DIRECTORY. The user can override through the
dnl --with-noarch-pkgconfigdir parameter.
AC_DEFUN([PKG_NOARCH_INSTALLDIR],
[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
m4_pushdef([pkg_description],
@ -218,13 +277,15 @@ AC_ARG_WITH([noarch-pkgconfigdir],
AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
m4_popdef([pkg_default])
m4_popdef([pkg_description])
]) dnl PKG_NOARCH_INSTALLDIR
])dnl PKG_NOARCH_INSTALLDIR
# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
# -------------------------------------------
# Retrieves the value of the pkg-config variable for the given module.
dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl -------------------------------------------
dnl Since: 0.28
dnl
dnl Retrieves the value of the pkg-config variable for the given module.
AC_DEFUN([PKG_CHECK_VAR],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
@ -233,7 +294,7 @@ _PKG_CONFIG([$1], [variable="][$3]["], [$2])
AS_VAR_COPY([$1], [pkg_cv_][$1])
AS_VAR_IF([$1], [""], [$5], [$4])dnl
])# PKG_CHECK_VAR
])dnl PKG_CHECK_VAR
# Copyright (C) 2002-2014 Free Software Foundation, Inc.
#
@ -1421,6 +1482,7 @@ AC_SUBST([am__tar])
AC_SUBST([am__untar])
]) # _AM_PROG_TAR
m4_include([m4/gc_set_version.m4])
m4_include([m4/libtool.m4])
m4_include([m4/ltoptions.m4])
m4_include([m4/ltsugar.m4])

View file

@ -103,12 +103,13 @@ STATIC int GC_hblk_fl_from_blocks(word blocks_needed)
/* Should return the same value as GC_large_free_bytes. */
GC_INNER word GC_compute_large_free_bytes(void)
{
struct hblk * h;
hdr * hhdr;
word total_free = 0;
unsigned i;
for (i = 0; i <= N_HBLK_FLS; ++i) {
struct hblk * h;
hdr * hhdr;
for (h = GC_hblkfreelist[i]; h != 0; h = hhdr->hb_next) {
hhdr = HDR(h);
total_free += hhdr->hb_sz;
@ -121,17 +122,17 @@ STATIC int GC_hblk_fl_from_blocks(word blocks_needed)
# if !defined(NO_DEBUGGING)
void GC_print_hblkfreelist(void)
{
struct hblk * h;
hdr * hhdr;
unsigned i;
word total;
for (i = 0; i <= N_HBLK_FLS; ++i) {
h = GC_hblkfreelist[i];
struct hblk * h = GC_hblkfreelist[i];
if (0 != h) GC_printf("Free list %u (total size %lu):\n",
i, (unsigned long)GC_free_bytes[i]);
while (h != 0) {
hhdr = HDR(h);
hdr * hhdr = HDR(h);
GC_printf("\t%p size %lu %s black listed\n",
(void *)h, (unsigned long) hhdr -> hb_sz,
GC_is_black_listed(h, HBLKSIZE) != 0 ? "start" :
@ -152,42 +153,42 @@ void GC_print_hblkfreelist(void)
/* appears, or -1 if it appears nowhere. */
static int free_list_index_of(hdr *wanted)
{
struct hblk * h;
hdr * hhdr;
int i;
for (i = 0; i <= N_HBLK_FLS; ++i) {
h = GC_hblkfreelist[i];
while (h != 0) {
struct hblk * h;
hdr * hhdr;
for (h = GC_hblkfreelist[i]; h != 0; h = hhdr -> hb_next) {
hhdr = HDR(h);
if (hhdr == wanted) return i;
h = hhdr -> hb_next;
}
}
return -1;
}
void GC_dump_regions(void)
GC_API void GC_CALL GC_dump_regions(void)
{
unsigned i;
ptr_t start, end;
ptr_t p;
size_t bytes;
hdr *hhdr;
for (i = 0; i < GC_n_heap_sects; ++i) {
start = GC_heap_sects[i].hs_start;
bytes = GC_heap_sects[i].hs_bytes;
end = start + bytes;
ptr_t start = GC_heap_sects[i].hs_start;
size_t bytes = GC_heap_sects[i].hs_bytes;
ptr_t end = start + bytes;
ptr_t p;
/* Merge in contiguous sections. */
while (i+1 < GC_n_heap_sects && GC_heap_sects[i+1].hs_start == end) {
++i;
end = GC_heap_sects[i].hs_start + GC_heap_sects[i].hs_bytes;
}
GC_printf("***Section from %p to %p\n", start, end);
GC_printf("***Section from %p to %p\n", (void *)start, (void *)end);
for (p = start; (word)p < (word)end; ) {
hhdr = HDR(p);
hdr *hhdr = HDR(p);
if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
GC_printf("\t%p Missing header!!(%p)\n", p, (void *)hhdr);
GC_printf("\t%p Missing header!!(%p)\n",
(void *)p, (void *)hhdr);
p += HBLKSIZE;
continue;
}
@ -196,8 +197,8 @@ void GC_dump_regions(void)
divHBLKSZ(hhdr -> hb_sz));
int actual_index;
GC_printf("\t%p\tfree block of size 0x%lx bytes%s\n", p,
(unsigned long)(hhdr -> hb_sz),
GC_printf("\t%p\tfree block of size 0x%lx bytes%s\n",
(void *)p, (unsigned long)(hhdr -> hb_sz),
IS_MAPPED(hhdr) ? "" : " (unmapped)");
actual_index = free_list_index_of(hhdr);
if (-1 == actual_index) {
@ -209,8 +210,8 @@ void GC_dump_regions(void)
}
p += hhdr -> hb_sz;
} else {
GC_printf("\t%p\tused for blocks of size 0x%lx bytes\n", p,
(unsigned long)(hhdr -> hb_sz));
GC_printf("\t%p\tused for blocks of size 0x%lx bytes\n",
(void *)p, (unsigned long)(hhdr -> hb_sz));
p += HBLKSIZE * OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
}
}
@ -226,9 +227,8 @@ static GC_bool setup_header(hdr * hhdr, struct hblk *block, size_t byte_sz,
int kind, unsigned flags)
{
word descr;
# ifdef MARK_BIT_PER_GRANULE
size_t granules;
# ifdef MARK_BIT_PER_GRANULE
if (byte_sz > MAXOBJBYTES)
flags |= LARGE_BLOCK;
# endif
@ -250,7 +250,7 @@ static GC_bool setup_header(hdr * hhdr, struct hblk *block, size_t byte_sz,
# ifdef MARK_BIT_PER_OBJ
/* Set hb_inv_sz as portably as possible. */
/* We set it to the smallest value such that sz * inv_sz > 2**32 */
/* We set it to the smallest value such that sz * inv_sz >= 2**32 */
/* This may be more precision than necessary. */
if (byte_sz > MAXOBJBYTES) {
hhdr -> hb_inv_sz = LARGE_INV_SZ;
@ -265,11 +265,16 @@ static GC_bool setup_header(hdr * hhdr, struct hblk *block, size_t byte_sz,
inv_sz = ((unsigned)1 << 31)/byte_sz;
inv_sz *= 2;
while (inv_sz*byte_sz > byte_sz) ++inv_sz;
# endif
# ifdef INV_SZ_COMPUTATION_CHECK
GC_ASSERT(((1ULL << 32) + byte_sz - 1) / byte_sz == inv_sz);
# endif
hhdr -> hb_inv_sz = inv_sz;
}
# else /* MARK_BIT_PER_GRANULE */
granules = BYTES_TO_GRANULES(byte_sz);
{
size_t granules = BYTES_TO_GRANULES(byte_sz);
if (EXPECT(!GC_add_map_entry(granules), FALSE)) {
/* Make it look like a valid block. */
hhdr -> hb_sz = HBLKSIZE;
@ -280,6 +285,7 @@ static GC_bool setup_header(hdr * hhdr, struct hblk *block, size_t byte_sz,
}
hhdr -> hb_map = GC_obj_map[(hhdr -> hb_flags & LARGE_BLOCK) != 0 ?
0 : granules];
}
# endif /* MARK_BIT_PER_GRANULE */
/* Clear mark bits */
@ -353,19 +359,18 @@ STATIC void GC_add_to_fl(struct hblk *h, hdr *hhdr)
{
int index = GC_hblk_fl_from_blocks(divHBLKSZ(hhdr -> hb_sz));
struct hblk *second = GC_hblkfreelist[index];
hdr * second_hdr;
# if defined(GC_ASSERTIONS) && !defined(USE_MUNMAP)
struct hblk *next = (struct hblk *)((word)h + hhdr -> hb_sz);
hdr * nexthdr = HDR(next);
struct hblk *prev = GC_free_block_ending_at(h);
hdr * prevhdr = HDR(prev);
GC_ASSERT(nexthdr == 0 || !HBLK_IS_FREE(nexthdr)
|| (signed_word)GC_heapsize < 0);
|| (GC_heapsize & SIGNB) != 0);
/* In the last case, blocks may be too large to merge. */
GC_ASSERT(prev == 0 || !HBLK_IS_FREE(prevhdr)
|| (signed_word)GC_heapsize < 0);
|| (GC_heapsize & SIGNB) != 0);
# endif
GC_ASSERT(((hhdr -> hb_sz) & (HBLKSIZE-1)) == 0);
GC_hblkfreelist[index] = h;
GC_free_bytes[index] += hhdr -> hb_sz;
@ -373,6 +378,8 @@ STATIC void GC_add_to_fl(struct hblk *h, hdr *hhdr)
hhdr -> hb_next = second;
hhdr -> hb_prev = 0;
if (0 != second) {
hdr * second_hdr;
GET_HDR(second, second_hdr);
second_hdr -> hb_prev = h;
}
@ -391,19 +398,22 @@ GC_INNER int GC_unmap_threshold = MUNMAP_THRESHOLD;
/* way blocks are ever unmapped. */
GC_INNER void GC_unmap_old(void)
{
struct hblk * h;
hdr * hhdr;
int i;
if (GC_unmap_threshold == 0)
return; /* unmapping disabled */
for (i = 0; i <= N_HBLK_FLS; ++i) {
struct hblk * h;
hdr * hhdr;
for (h = GC_hblkfreelist[i]; 0 != h; h = hhdr -> hb_next) {
hhdr = HDR(h);
if (!IS_MAPPED(hhdr)) continue;
if ((unsigned short)GC_gc_no - hhdr -> hb_last_reclaimed >
/* Check that the interval is larger than the threshold (the */
/* truncated counter value wrapping is handled correctly). */
if ((unsigned short)(GC_gc_no - hhdr->hb_last_reclaimed) >
(unsigned short)GC_unmap_threshold) {
GC_unmap((ptr_t)h, hhdr -> hb_sz);
hhdr -> hb_flags |= WAS_UNMAPPED;
@ -417,14 +427,16 @@ GC_INNER void GC_unmap_old(void)
/* fully mapped or fully unmapped. */
GC_INNER void GC_merge_unmapped(void)
{
struct hblk * h, *next;
hdr * hhdr, *nexthdr;
word size, nextsize;
int i;
for (i = 0; i <= N_HBLK_FLS; ++i) {
h = GC_hblkfreelist[i];
struct hblk *h = GC_hblkfreelist[i];
while (h != 0) {
struct hblk *next;
hdr *hhdr, *nexthdr;
word size, nextsize;
GET_HDR(h, hhdr);
size = hhdr->hb_sz;
next = (struct hblk *)((word)h + size);
@ -500,7 +512,7 @@ STATIC struct hblk * GC_get_first_part(struct hblk *h, hdr *hhdr,
rest_hdr = GC_install_header(rest);
if (0 == rest_hdr) {
/* FIXME: This is likely to be very bad news ... */
WARN("Header allocation failed: Dropping block.\n", 0);
WARN("Header allocation failed: dropping block\n", 0);
return(0);
}
rest_hdr -> hb_sz = total_size - bytes;
@ -583,7 +595,7 @@ GC_allochblk(size_t sz, int kind, unsigned flags/* IGNORE_OFF_PAGE or 0 */)
/* split. */
GC_ASSERT((sz & (GRANULE_BYTES - 1)) == 0);
blocks = OBJ_SZ_TO_BLOCKS(sz);
blocks = OBJ_SZ_TO_BLOCKS_CHECKED(sz);
if ((signed_word)(blocks * HBLKSIZE) < 0) {
return 0;
}
@ -643,26 +655,26 @@ GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n, int may_split)
hdr * hhdr; /* Header corr. to hbp */
struct hblk *thishbp;
hdr * thishdr; /* Header corr. to thishbp */
signed_word size_needed; /* number of bytes in requested objects */
signed_word size_avail; /* bytes available in this block */
size_needed = HBLKSIZE * OBJ_SZ_TO_BLOCKS(sz);
signed_word size_needed = HBLKSIZE * OBJ_SZ_TO_BLOCKS_CHECKED(sz);
/* number of bytes in requested objects */
/* search for a big enough block in free list */
for (hbp = GC_hblkfreelist[n];; hbp = hhdr -> hb_next) {
signed_word size_avail; /* bytes available in this block */
if (NULL == hbp) return NULL;
GET_HDR(hbp, hhdr); /* set hhdr value */
size_avail = hhdr->hb_sz;
if (size_avail < size_needed) continue;
if (size_avail != size_needed) {
signed_word next_size;
if (!may_split) continue;
/* If the next heap block is obviously better, go on. */
/* This prevents us from disassembling a single large */
/* block to get tiny blocks. */
thishbp = hhdr -> hb_next;
if (thishbp != 0) {
signed_word next_size;
GET_HDR(thishbp, thishdr);
next_size = (signed_word)(thishdr -> hb_sz);
if (next_size < size_avail
@ -721,12 +733,13 @@ GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n, int may_split)
>= GC_large_alloc_warn_interval) {
WARN("Repeated allocation of very large block "
"(appr. size %" WARN_PRIdPTR "):\n"
"\tMay lead to memory leak and poor performance.\n",
"\tMay lead to memory leak and poor performance\n",
size_needed);
GC_large_alloc_warn_suppressed = 0;
}
size_avail = orig_avail;
} else if (size_avail == 0 && size_needed == HBLKSIZE
} else if (size_avail == 0
&& size_needed == (signed_word)HBLKSIZE
&& IS_MAPPED(hhdr)) {
if (!GC_find_leak) {
static unsigned count = 0;

View file

@ -3,6 +3,7 @@
* Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
* Copyright (c) 1998 by Silicon Graphics. All rights reserved.
* Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
* Copyright (c) 2008-2018 Ivan Maidanski
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@ -64,21 +65,21 @@ word GC_non_gc_bytes = 0; /* Number of bytes not intended to be collected */
word GC_gc_no = 0;
#ifndef GC_DISABLE_INCREMENTAL
GC_INNER int GC_incremental = 0; /* By default, stop the world. */
GC_INNER GC_bool GC_incremental = FALSE; /* By default, stop the world. */
#endif
#ifdef THREADS
int GC_parallel = FALSE; /* By default, parallel GC is off. */
#endif
#ifndef GC_FULL_FREQ
# define GC_FULL_FREQ 19 /* Every 20th collection is a full */
#if defined(GC_FULL_FREQ) && !defined(CPPCHECK)
int GC_full_freq = GC_FULL_FREQ;
#else
int GC_full_freq = 19; /* Every 20th collection is a full */
/* collection, whether we need it */
/* or not. */
#endif
int GC_full_freq = GC_FULL_FREQ;
STATIC GC_bool GC_need_full_gc = FALSE;
/* Need full GC do to heap growth. */
@ -90,10 +91,11 @@ STATIC word GC_used_heap_size_after_full = 0;
/* GC_copyright symbol is externally visible. */
char * const GC_copyright[] =
{"Copyright 1988,1989 Hans-J. Boehm and Alan J. Demers ",
{"Copyright 1988, 1989 Hans-J. Boehm and Alan J. Demers ",
"Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. ",
"Copyright (c) 1996-1998 by Silicon Graphics. All rights reserved. ",
"Copyright (c) 1999-2009 by Hewlett-Packard Company. All rights reserved. ",
"Copyright (c) 2008-2018 Ivan Maidanski ",
"THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY",
" EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.",
"See source code for details." };
@ -119,24 +121,25 @@ GC_API unsigned GC_CALL GC_get_version(void)
int GC_dont_expand = FALSE;
#endif
#ifndef GC_FREE_SPACE_DIVISOR
# define GC_FREE_SPACE_DIVISOR 3 /* must be > 0 */
#if defined(GC_FREE_SPACE_DIVISOR) && !defined(CPPCHECK)
word GC_free_space_divisor = GC_FREE_SPACE_DIVISOR; /* must be > 0 */
#else
word GC_free_space_divisor = 3;
#endif
word GC_free_space_divisor = GC_FREE_SPACE_DIVISOR;
GC_INNER int GC_CALLBACK GC_never_stop_func(void)
{
return(0);
}
#ifndef GC_TIME_LIMIT
# define GC_TIME_LIMIT 50 /* We try to keep pause times from exceeding */
#if defined(GC_TIME_LIMIT) && !defined(CPPCHECK)
unsigned long GC_time_limit = GC_TIME_LIMIT;
/* We try to keep pause times from exceeding */
/* this by much. In milliseconds. */
#else
unsigned long GC_time_limit = 50;
#endif
unsigned long GC_time_limit = GC_TIME_LIMIT;
#ifndef NO_CLOCK
STATIC CLOCK_TYPE GC_start_time = 0;
/* Time at which we stopped world. */
@ -152,7 +155,7 @@ STATIC GC_stop_func GC_default_stop_func = GC_never_stop_func;
GC_API void GC_CALL GC_set_stop_func(GC_stop_func stop_func)
{
DCL_LOCK_STATE;
GC_ASSERT(stop_func != 0);
GC_ASSERT(NONNULL_ARG_NOT_NULL(stop_func));
LOCK();
GC_default_stop_func = stop_func;
UNLOCK();
@ -202,15 +205,7 @@ GC_API GC_stop_func GC_CALL GC_get_stop_func(void)
static word min_bytes_allocd(void)
{
word result;
# ifdef STACK_NOT_SCANNED
word stack_size = 0;
# elif defined(STACK_GROWS_UP)
word stack_size = GC_approx_sp() - GC_stackbottom;
/* GC_stackbottom is used only for a single-threaded case. */
# else
word stack_size = GC_stackbottom - GC_approx_sp();
# endif
word stack_size;
word total_root_size; /* includes double stack size, */
/* since the stack is expensive */
/* to scan. */
@ -226,8 +221,17 @@ static word min_bytes_allocd(void)
GC_log_printf("Total stacks size: %lu\n",
(unsigned long)stack_size);
# endif
}
} else
# endif
/* else*/ {
# ifdef STACK_NOT_SCANNED
stack_size = 0;
# elif defined(STACK_GROWS_UP)
stack_size = GC_approx_sp() - GC_stackbottom;
# else
stack_size = GC_stackbottom - GC_approx_sp();
# endif
}
total_root_size = 2 * stack_size + GC_root_size;
scan_size = 2 * GC_composite_in_use + GC_atomic_in_use / 4
@ -355,11 +359,11 @@ STATIC void GC_finish_collection(void);
*/
STATIC void GC_maybe_gc(void)
{
static int n_partial_gcs = 0;
GC_ASSERT(I_HOLD_LOCK());
ASSERT_CANCEL_DISABLED();
if (GC_should_collect()) {
static int n_partial_gcs = 0;
if (!GC_incremental) {
/* FIXME: If possible, GC_default_stop_func should be used here */
GC_try_to_collect_inner(GC_never_stop_func);
@ -386,7 +390,7 @@ STATIC void GC_maybe_gc(void)
}
/* We try to mark with the world stopped. */
/* If we run out of time, this turns into */
/* incremental marking. */
/* incremental marking. */
# ifndef NO_CLOCK
if (GC_time_limit != GC_TIME_UNLIMITED) { GET_TIME(GC_start_time); }
# endif
@ -407,26 +411,50 @@ STATIC void GC_maybe_gc(void)
}
}
STATIC GC_on_collection_event_proc GC_on_collection_event = 0;
/*
* Stop the world garbage collection. Assumes lock held. If stop_func is
* not GC_never_stop_func then abort if stop_func returns TRUE.
* Return TRUE if we successfully completed the collection.
*/
GC_API void GC_CALL GC_set_on_collection_event(GC_on_collection_event_proc fn)
{
/* fn may be 0 (means no event notifier). */
DCL_LOCK_STATE;
LOCK();
GC_on_collection_event = fn;
UNLOCK();
}
GC_API GC_on_collection_event_proc GC_CALL GC_get_on_collection_event(void)
{
GC_on_collection_event_proc fn;
DCL_LOCK_STATE;
LOCK();
fn = GC_on_collection_event;
UNLOCK();
return fn;
}
/* Stop the world garbage collection. If stop_func is not */
/* GC_never_stop_func then abort if stop_func returns TRUE. */
/* Return TRUE if we successfully completed the collection. */
GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func)
{
# ifndef SMALL_CONFIG
CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */
CLOCK_TYPE current_time;
# endif
ASSERT_CANCEL_DISABLED();
GC_ASSERT(I_HOLD_LOCK());
if (GC_dont_gc || (*stop_func)()) return FALSE;
if (GC_on_collection_event)
GC_on_collection_event(GC_EVENT_START);
if (GC_incremental && GC_collection_in_progress()) {
GC_COND_LOG_PRINTF(
"GC_try_to_collect_inner: finishing collection in progress\n");
/* Just finish collection already in progress. */
while(GC_collection_in_progress()) {
if ((*stop_func)()) return(FALSE);
if ((*stop_func)()) {
/* TODO: Notify GC_EVENT_ABANDON */
return(FALSE);
}
GC_collect_a_little_inner(1);
}
}
@ -450,6 +478,7 @@ GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func)
if ((GC_find_leak || stop_func != GC_never_stop_func)
&& !GC_reclaim_all(stop_func, FALSE)) {
/* Aborted. So far everything is still consistent. */
/* TODO: Notify GC_EVENT_ABANDON */
return(FALSE);
}
GC_invalidate_mark_state(); /* Flush mark stack. */
@ -467,16 +496,21 @@ GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func)
GC_unpromote_black_lists();
} /* else we claim the world is already still consistent. We'll */
/* finish incrementally. */
/* TODO: Notify GC_EVENT_ABANDON */
return(FALSE);
}
GC_finish_collection();
# ifndef SMALL_CONFIG
if (GC_print_stats) {
CLOCK_TYPE current_time;
GET_TIME(current_time);
GC_log_printf("Complete collection took %lu msecs\n",
MS_TIME_DIFF(current_time,start_time));
}
# endif
if (GC_on_collection_event)
GC_on_collection_event(GC_EVENT_END);
return(TRUE);
}
@ -503,12 +537,13 @@ STATIC int GC_deficit = 0;/* The number of extra calls to GC_mark_some */
GC_INNER void GC_collect_a_little_inner(int n)
{
int i;
IF_CANCEL(int cancel_state;)
if (GC_dont_gc) return;
DISABLE_CANCEL(cancel_state);
if (GC_incremental && GC_collection_in_progress()) {
int i;
for (i = GC_deficit; i < GC_RATE*n; i++) {
if (GC_mark_some((ptr_t)0)) {
/* Need to finish a collection */
@ -593,7 +628,6 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
unsigned i;
# ifndef SMALL_CONFIG
CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */
CLOCK_TYPE current_time;
# endif
# if !defined(REDIRECT_MALLOC) && defined(USE_WINALLOC)
@ -608,7 +642,19 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
GET_TIME(start_time);
# endif
# if !defined(GC_NO_FINALIZATION) && !defined(GC_TOGGLE_REFS_NOT_NEEDED)
GC_process_togglerefs();
# endif
# ifdef THREADS
if (GC_on_collection_event)
GC_on_collection_event(GC_EVENT_PRE_STOP_WORLD);
# endif
STOP_WORLD();
# ifdef THREADS
if (GC_on_collection_event)
GC_on_collection_event(GC_EVENT_POST_STOP_WORLD);
# endif
# ifdef THREAD_LOCAL_ALLOC
GC_world_stopped = TRUE;
# endif
@ -623,6 +669,9 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
# endif
/* Mark from all roots. */
if (GC_on_collection_event)
GC_on_collection_event(GC_EVENT_MARK_START);
/* Minimize junk left in my registers and on the stack */
GC_clear_a_few_frames();
GC_noop6(0,0,0,0,0,0);
@ -636,7 +685,20 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
# ifdef THREAD_LOCAL_ALLOC
GC_world_stopped = FALSE;
# endif
# ifdef THREADS
if (GC_on_collection_event)
GC_on_collection_event(GC_EVENT_PRE_START_WORLD);
# endif
START_WORLD();
# ifdef THREADS
if (GC_on_collection_event)
GC_on_collection_event(GC_EVENT_POST_START_WORLD);
# endif
/* TODO: Notify GC_EVENT_MARK_ABANDON */
return(FALSE);
}
if (GC_mark_some(GC_approx_sp())) break;
@ -653,15 +715,31 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
if (GC_debugging_started) {
(*GC_check_heap)();
}
if (GC_on_collection_event)
GC_on_collection_event(GC_EVENT_MARK_END);
# ifdef THREAD_LOCAL_ALLOC
GC_world_stopped = FALSE;
# endif
# ifdef THREADS
if (GC_on_collection_event)
GC_on_collection_event(GC_EVENT_PRE_START_WORLD);
# endif
START_WORLD();
# ifdef THREADS
if (GC_on_collection_event)
GC_on_collection_event(GC_EVENT_POST_START_WORLD);
# endif
# ifndef SMALL_CONFIG
if (GC_PRINT_STATS_FLAG) {
unsigned long time_diff;
unsigned total_time, divisor;
CLOCK_TYPE current_time;
GET_TIME(current_time);
time_diff = MS_TIME_DIFF(current_time,start_time);
@ -691,19 +769,15 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
/* Set all mark bits for the free list whose first entry is q */
GC_INNER void GC_set_fl_marks(ptr_t q)
{
struct hblk *h, *last_h;
hdr *hhdr;
IF_PER_OBJ(size_t sz;)
unsigned bit_no;
if (q != NULL) {
struct hblk *h = HBLKPTR(q);
struct hblk *last_h = h;
hdr *hhdr = HDR(h);
IF_PER_OBJ(size_t sz = hhdr->hb_sz;)
if (q != NULL) {
h = HBLKPTR(q);
last_h = h;
hhdr = HDR(h);
IF_PER_OBJ(sz = hhdr->hb_sz;)
for (;;) {
unsigned bit_no = MARK_BIT_NO((ptr_t)q - (ptr_t)h, sz);
for (;;) {
bit_no = MARK_BIT_NO((ptr_t)q - (ptr_t)h, sz);
if (!mark_bit_from_hdr(hhdr, bit_no)) {
set_mark_bit_from_hdr(hhdr, bit_no);
++hhdr -> hb_n_marks;
@ -719,8 +793,8 @@ GC_INNER void GC_set_fl_marks(ptr_t q)
hhdr = HDR(h);
IF_PER_OBJ(sz = hhdr->hb_sz;)
}
}
}
}
}
}
#if defined(GC_ASSERTIONS) && defined(THREADS) && defined(THREAD_LOCAL_ALLOC)
@ -769,22 +843,21 @@ GC_INNER void GC_set_fl_marks(ptr_t q)
/* Decrement GC_bytes_found by number of bytes on free list. */
STATIC void GC_clear_fl_marks(ptr_t q)
{
struct hblk *h, *last_h;
hdr *hhdr;
size_t sz;
unsigned bit_no;
if (q != NULL) {
struct hblk *h = HBLKPTR(q);
struct hblk *last_h = h;
hdr *hhdr = HDR(h);
size_t sz = hhdr->hb_sz; /* Normally set only once. */
if (q != NULL) {
h = HBLKPTR(q);
last_h = h;
hhdr = HDR(h);
sz = hhdr->hb_sz; /* Normally set only once. */
for (;;) {
unsigned bit_no = MARK_BIT_NO((ptr_t)q - (ptr_t)h, sz);
for (;;) {
bit_no = MARK_BIT_NO((ptr_t)q - (ptr_t)h, sz);
if (mark_bit_from_hdr(hhdr, bit_no)) {
size_t n_marks = hhdr -> hb_n_marks - 1;
size_t n_marks = hhdr -> hb_n_marks;
GC_ASSERT(n_marks != 0);
clear_mark_bit_from_hdr(hhdr, bit_no);
n_marks--;
# ifdef PARALLEL_MARK
/* Appr. count, don't decrement to zero! */
if (0 != n_marks || !GC_parallel) {
@ -806,8 +879,8 @@ STATIC void GC_clear_fl_marks(ptr_t q)
hhdr = HDR(h);
sz = hhdr->hb_sz;
}
}
}
}
}
}
#if defined(GC_ASSERTIONS) && defined(THREADS) && defined(THREAD_LOCAL_ALLOC)
@ -832,7 +905,6 @@ STATIC void GC_finish_collection(void)
# ifndef SMALL_CONFIG
CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */
CLOCK_TYPE finalize_time = 0;
CLOCK_TYPE done_time;
# endif
# if defined(GC_ASSERTIONS) && defined(THREADS) \
@ -846,6 +918,8 @@ STATIC void GC_finish_collection(void)
if (GC_print_stats)
GET_TIME(start_time);
# endif
if (GC_on_collection_event)
GC_on_collection_event(GC_EVENT_RECLAIM_START);
# ifndef GC_GET_HEAP_USAGE_NOT_NEEDED
if (GC_bytes_found > 0)
@ -951,8 +1025,12 @@ STATIC void GC_finish_collection(void)
IF_USE_MUNMAP(GC_unmap_old());
if (GC_on_collection_event)
GC_on_collection_event(GC_EVENT_RECLAIM_END);
# ifndef SMALL_CONFIG
if (GC_print_stats) {
CLOCK_TYPE done_time;
GET_TIME(done_time);
# ifndef GC_NO_FINALIZATION
/* A convenient place to output finalization statistics. */
@ -1004,7 +1082,7 @@ STATIC GC_bool GC_try_to_collect_general(GC_stop_func stop_func,
/* Externally callable routines to invoke full, stop-the-world collection. */
GC_API int GC_CALL GC_try_to_collect(GC_stop_func stop_func)
{
GC_ASSERT(stop_func != 0);
GC_ASSERT(NONNULL_ARG_NOT_NULL(stop_func));
return (int)GC_try_to_collect_general(stop_func, FALSE);
}
@ -1130,9 +1208,9 @@ GC_INNER void GC_add_to_heap(struct hblk *p, size_t bytes)
for (h = (struct hblk *)start; (word)h < (word)(start + len); h++) {
if (GC_is_black_listed(h, HBLKSIZE)) nbl++;
}
GC_printf("Section %d from %p to %p %lu/%lu blacklisted\n",
i, start, start + len,
(unsigned long)nbl, (unsigned long)(len/HBLKSIZE));
GC_printf("Section %d from %p to %p %u/%lu blacklisted\n",
i, (void *)start, (void *)&start[len],
nbl, (unsigned long)divHBLKSZ(len));
}
}
#endif
@ -1165,25 +1243,28 @@ GC_word GC_max_retries = 0;
/* Returns FALSE on failure. */
GC_INNER GC_bool GC_expand_hp_inner(word n)
{
word bytes;
size_t bytes;
struct hblk * space;
word expansion_slop; /* Number of bytes by which we expect the */
/* heap to expand soon. */
if (n < MINHINCR) n = MINHINCR;
bytes = ROUNDUP_PAGESIZE(n * HBLKSIZE);
if (GC_max_heapsize != 0 && GC_heapsize + bytes > GC_max_heapsize) {
bytes = ROUNDUP_PAGESIZE((size_t)n * HBLKSIZE);
if (GC_max_heapsize != 0
&& (GC_max_heapsize < (word)bytes
|| GC_heapsize > GC_max_heapsize - (word)bytes)) {
/* Exceeded self-imposed limit */
return(FALSE);
}
space = GET_MEM(bytes);
GC_add_to_our_memory((ptr_t)space, bytes);
if (space == 0) {
WARN("Failed to expand heap by %" WARN_PRIdPTR " bytes\n", bytes);
WARN("Failed to expand heap by %" WARN_PRIdPTR " bytes\n",
(word)bytes);
return(FALSE);
}
GC_INFOLOG_PRINTF("Grow heap to %lu KiB after %lu bytes allocated\n",
TO_KiB_UL(GC_heapsize + bytes),
TO_KiB_UL(GC_heapsize + (word)bytes),
(unsigned long)GC_bytes_allocd);
/* Adjust heap limits generously for blacklisting to work better. */
/* GC_add_to_heap performs minimal adjustment needed for */
@ -1193,7 +1274,7 @@ GC_INNER GC_bool GC_expand_hp_inner(word n)
|| (GC_last_heap_addr != 0
&& (word)GC_last_heap_addr < (word)space)) {
/* Assume the heap is growing up */
word new_limit = (word)space + bytes + expansion_slop;
word new_limit = (word)space + (word)bytes + expansion_slop;
if (new_limit > (word)space) {
GC_greatest_plausible_heap_addr =
(void *)GC_max((word)GC_greatest_plausible_heap_addr,
@ -1229,8 +1310,8 @@ GC_API int GC_CALL GC_expand_hp(size_t bytes)
int result;
DCL_LOCK_STATE;
LOCK();
if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
LOCK();
result = (int)GC_expand_hp_inner(divHBLKSZ((word)bytes));
if (result) GC_requested_heapsize += bytes;
UNLOCK();
@ -1246,6 +1327,8 @@ GC_INNER unsigned GC_fail_count = 0;
static word last_fo_entries = 0;
static word last_bytes_finalized = 0;
#define GC_WORD_MAX (~(word)0)
/* Collect or expand heap in an attempt make the indicated number of */
/* free blocks available. Should be called until the blocks are */
/* available (setting retry value to TRUE unless this is the first call */
@ -1300,6 +1383,8 @@ GC_INNER GC_bool GC_collect_or_expand(word needed_blocks,
} else {
blocks_to_get = MAXHINCR;
}
if (blocks_to_get > divHBLKSZ(GC_WORD_MAX))
blocks_to_get = divHBLKSZ(GC_WORD_MAX);
}
if (!GC_expand_hp_inner(blocks_to_get)
@ -1310,7 +1395,7 @@ GC_INNER GC_bool GC_collect_or_expand(word needed_blocks,
GC_gcollect_inner();
GC_ASSERT(GC_bytes_allocd == 0);
} else if (GC_fail_count++ < GC_max_retries) {
WARN("Out of Memory! Trying to continue ...\n", 0);
WARN("Out of Memory! Trying to continue...\n", 0);
GC_gcollect_inner();
} else {
# if !defined(AMIGA) || !defined(GC_AMIGA_FASTALLOC)

View file

@ -86,13 +86,13 @@ static back_edges *avail_back_edges = 0;
static back_edges * new_back_edges(void)
{
if (0 == back_edge_space) {
back_edge_space = (back_edges *)GET_MEM(
ROUNDUP_PAGESIZE_IF_MMAP(MAX_BACK_EDGE_STRUCTS
* sizeof(back_edges)));
size_t bytes_to_get = ROUNDUP_PAGESIZE_IF_MMAP(MAX_BACK_EDGE_STRUCTS
* sizeof(back_edges));
back_edge_space = (back_edges *)GET_MEM(bytes_to_get);
if (NULL == back_edge_space)
ABORT("Insufficient memory for back edges");
GC_add_to_our_memory((ptr_t)back_edge_space,
MAX_BACK_EDGE_STRUCTS*sizeof(back_edges));
GC_add_to_our_memory((ptr_t)back_edge_space, bytes_to_get);
}
if (0 != avail_back_edges) {
back_edges * result = avail_back_edges;
@ -129,26 +129,32 @@ static size_t n_in_progress = 0;
static void push_in_progress(ptr_t p)
{
if (n_in_progress >= in_progress_size) {
if (in_progress_size == 0) {
ptr_t * new_in_progress_space;
if (NULL == in_progress_space) {
in_progress_size = ROUNDUP_PAGESIZE_IF_MMAP(INITIAL_IN_PROGRESS
* sizeof(ptr_t))
/ sizeof(ptr_t);
in_progress_space = (ptr_t *)GET_MEM(in_progress_size * sizeof(ptr_t));
GC_add_to_our_memory((ptr_t)in_progress_space,
in_progress_size * sizeof(ptr_t));
new_in_progress_space =
(ptr_t *)GET_MEM(in_progress_size * sizeof(ptr_t));
} else {
ptr_t * new_in_progress_space;
in_progress_size *= 2;
new_in_progress_space = (ptr_t *)
GET_MEM(in_progress_size * sizeof(ptr_t));
GC_add_to_our_memory((ptr_t)new_in_progress_space,
in_progress_size * sizeof(ptr_t));
if (new_in_progress_space != NULL)
BCOPY(in_progress_space, new_in_progress_space,
n_in_progress * sizeof(ptr_t));
in_progress_space = new_in_progress_space;
/* FIXME: This just drops the old space. */
}
GC_add_to_our_memory((ptr_t)new_in_progress_space,
in_progress_size * sizeof(ptr_t));
# ifndef GWW_VDB
GC_scratch_recycle_no_gww(in_progress_space,
n_in_progress * sizeof(ptr_t));
# elif defined(LINT2)
/* TODO: implement GWW-aware recycling as in alloc_mark_stack */
GC_noop1((word)in_progress_space);
# endif
in_progress_space = new_in_progress_space;
}
if (in_progress_space == 0)
ABORT("MAKE_BACK_GRAPH: Out of in-progress space: "
@ -227,13 +233,6 @@ static void add_edge(ptr_t p, ptr_t q)
ptr_t old_back_ptr = GET_OH_BG_PTR(q);
back_edges * be, *be_cont;
word i;
static unsigned random_number = 13;
# define GOT_LUCKY_NUMBER (((++random_number) & 0x7f) == 0)
/* A not very random number we use to occasionally allocate a */
/* back_edges structure even for a single backward edge. This */
/* prevents us from repeatedly tracing back through very long */
/* chains, since we will have some place to store height and */
/* in_progress flags along the way. */
GC_ASSERT(p == GC_base(p) && q == GC_base(q));
if (!GC_HAS_DEBUG_INFO(q) || !GC_HAS_DEBUG_INFO(p)) {
@ -242,6 +241,14 @@ static void add_edge(ptr_t p, ptr_t q)
return;
}
if (0 == old_back_ptr) {
static unsigned random_number = 13;
# define GOT_LUCKY_NUMBER (((++random_number) & 0x7f) == 0)
/* A not very random number we use to occasionally allocate a */
/* back_edges structure even for a single backward edge. This */
/* prevents us from repeatedly tracing back through very long */
/* chains, since we will have some place to store height and */
/* in_progress flags along the way. */
SET_OH_BG_PTR(q, p);
if (GOT_LUCKY_NUMBER) ensure_struct(q);
return;
@ -382,7 +389,8 @@ static word backwards_height(ptr_t p)
FOR_EACH_PRED(q, p, {
word this_height;
if (GC_is_marked(q) && !(FLAG_MANY & (word)GET_OH_BG_PTR(p))) {
GC_COND_LOG_PRINTF("Found bogus pointer from %p to %p\n", q, p);
GC_COND_LOG_PRINTF("Found bogus pointer from %p to %p\n",
(void *)q, (void *)p);
/* Reachable object "points to" unreachable one. */
/* Could be caused by our lax treatment of GC descriptors. */
this_height = 1;
@ -463,14 +471,19 @@ GC_INNER void GC_traverse_back_graph(void)
void GC_print_back_graph_stats(void)
{
GC_ASSERT(I_HOLD_LOCK());
GC_printf("Maximum backwards height of reachable objects at GC %lu is %lu\n",
(unsigned long) GC_gc_no, (unsigned long)GC_max_height);
if (GC_max_height > GC_max_max_height) {
ptr_t obj = GC_deepest_obj;
GC_max_max_height = GC_max_height;
UNLOCK();
GC_err_printf(
"The following unreachable object is last in a longest chain "
"of unreachable objects:\n");
GC_print_heap_obj(GC_deepest_obj);
GC_print_heap_obj(obj);
LOCK();
}
GC_COND_LOG_PRINTF("Needed max total of %d back-edge structs\n",
GC_n_back_edge_structs);

View file

@ -60,7 +60,7 @@ GC_INNER void GC_default_print_heap_obj_proc(ptr_t p)
int kind = HDR(base)->hb_obj_kind;
GC_err_printf("object at %p of appr. %lu bytes (%s)\n",
base, (unsigned long)GC_size(base),
(void *)base, (unsigned long)GC_size(base),
kind == PTRFREE ? "atomic" :
IS_UNCOLLECTABLE(kind) ? "uncollectable" : "composite");
}
@ -75,7 +75,7 @@ GC_INNER void (*GC_print_heap_obj)(ptr_t p) = GC_default_print_heap_obj_proc;
if (0 == base) {
GC_err_printf("Black listing (%s) %p referenced from %p in %s\n",
kind_str, (ptr_t)p, source,
kind_str, (void *)p, (void *)source,
NULL != source ? "root set" : "register");
} else {
/* FIXME: We can't call the debug version of GC_print_heap_obj */
@ -83,8 +83,8 @@ GC_INNER void (*GC_print_heap_obj)(ptr_t p) = GC_default_print_heap_obj_proc;
/* the world is stopped. */
GC_err_printf("Black listing (%s) %p referenced from %p in"
" object at %p of appr. %lu bytes\n",
kind_str, (ptr_t)p, source,
base, (unsigned long)GC_size(base));
kind_str, (void *)p, (void *)source,
(void *)base, (unsigned long)GC_size(base));
}
}
#endif /* PRINT_BLACK_LIST */
@ -109,6 +109,7 @@ GC_INNER void GC_bl_init(void)
if (!GC_all_interior_pointers) {
GC_bl_init_no_interiors();
}
GC_ASSERT(NULL == GC_old_stack_bl && NULL == GC_incomplete_stack_bl);
GC_old_stack_bl = (word *)GC_scratch_alloc(sizeof(page_hash_table));
GC_incomplete_stack_bl = (word *)GC_scratch_alloc(sizeof(page_hash_table));
if (GC_old_stack_bl == 0 || GC_incomplete_stack_bl == 0) {
@ -281,7 +282,7 @@ static word total_stack_black_listed(void)
for (i = 0; i < GC_n_heap_sects; i++) {
struct hblk * start = (struct hblk *) GC_heap_sects[i].hs_start;
struct hblk * endp1 = start + GC_heap_sects[i].hs_bytes/HBLKSIZE;
struct hblk * endp1 = start + divHBLKSZ(GC_heap_sects[i].hs_bytes);
total += GC_number_stack_black_listed(start, endp1);
}

View file

@ -39,18 +39,21 @@ STATIC word GC_faulted[NSUMS] = { 0 };
STATIC size_t GC_n_faulted = 0;
void GC_record_fault(struct hblk * h)
{
word page = ROUNDUP_PAGESIZE((word)h);
#if defined(MPROTECT_VDB) && !defined(DARWIN)
void GC_record_fault(struct hblk * h)
{
word page = (word)h & ~(GC_page_size - 1);
GC_ASSERT(GC_page_size != 0);
if (GC_n_faulted >= NSUMS) ABORT("write fault log overflowed");
GC_faulted[GC_n_faulted++] = page;
}
}
#endif
STATIC GC_bool GC_was_faulted(struct hblk *h)
{
size_t i;
word page = ROUNDUP_PAGESIZE((word)h);
word page = (word)h & ~(GC_page_size - 1);
for (i = 0; i < GC_n_faulted; ++i) {
if (GC_faulted[i] == page) return TRUE;
@ -90,8 +93,8 @@ STATIC word GC_checksum(struct hblk *h)
int GC_n_dirty_errors = 0;
int GC_n_faulted_dirty_errors = 0;
int GC_n_changed_errors = 0;
int GC_n_clean = 0;
int GC_n_dirty = 0;
unsigned long GC_n_clean = 0;
unsigned long GC_n_dirty = 0;
STATIC void GC_update_check_page(struct hblk *h, int index)
{
@ -196,14 +199,13 @@ void GC_check_dirty(void)
}
out:
GC_COND_LOG_PRINTF("Checked %lu clean and %lu dirty pages\n",
(unsigned long)GC_n_clean, (unsigned long)GC_n_dirty);
GC_n_clean, GC_n_dirty);
if (GC_n_dirty_errors > 0) {
GC_err_printf("Found %d dirty bit errors (%d were faulted)\n",
GC_n_dirty_errors, GC_n_faulted_dirty_errors);
}
if (GC_n_changed_errors > 0) {
GC_err_printf("Found %lu changed bit errors\n",
(unsigned long)GC_n_changed_errors);
GC_err_printf("Found %d changed bit errors\n", GC_n_changed_errors);
GC_err_printf(
"These may be benign (provoked by nonpointer changes)\n");
# ifdef THREADS

409
src/bdwgc/configure vendored
View file

@ -1,8 +1,8 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for gc 7.5.0.
# Generated by GNU Autoconf 2.69 for gc 7.6.8.
#
# Report bugs to <bdwgc@lists.opendylan.org>.
# Report bugs to <https://github.com/ivmai/bdwgc/issues>.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@ -275,10 +275,10 @@ fi
$as_echo "$0: be upgraded to zsh 4.3.4 or later."
else
$as_echo "$0: Please tell bug-autoconf@gnu.org and
$0: bdwgc@lists.opendylan.org about your system, including
$0: any error possibly output before this message. Then
$0: install a modern shell, or manually run the script
$0: under such a shell if you do have one."
$0: https://github.com/ivmai/bdwgc/issues about your
$0: system, including any error possibly output before this
$0: message. Then install a modern shell, or manually run
$0: the script under such a shell if you do have one."
fi
exit 1
fi
@ -590,9 +590,9 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='gc'
PACKAGE_TARNAME='gc'
PACKAGE_VERSION='7.5.0'
PACKAGE_STRING='gc 7.5.0'
PACKAGE_BUGREPORT='bdwgc@lists.opendylan.org'
PACKAGE_VERSION='7.6.8'
PACKAGE_STRING='gc 7.6.8'
PACKAGE_BUGREPORT='https://github.com/ivmai/bdwgc/issues'
PACKAGE_URL=''
ac_unique_file="gcj_mlc.c"
@ -647,8 +647,11 @@ ATOMIC_OPS_CFLAGS
PKG_CONFIG_LIBDIR
PKG_CONFIG_PATH
PKG_CONFIG
ENABLE_DOCS_FALSE
ENABLE_DOCS_TRUE
SINGLE_GC_OBJ_FALSE
SINGLE_GC_OBJ_TRUE
WERROR_CFLAGS
USE_LIBDIR_FALSE
USE_LIBDIR_TRUE
UNWINDLIBS
@ -672,6 +675,8 @@ AVOID_CPP_LIB_FALSE
AVOID_CPP_LIB_TRUE
ASM_WITH_CPP_UNSUPPORTED_FALSE
ASM_WITH_CPP_UNSUPPORTED_TRUE
PTHREAD_START_STANDALONE_FALSE
PTHREAD_START_STANDALONE_TRUE
WIN32_THREADS_FALSE
WIN32_THREADS_TRUE
DARWIN_THREADS_FALSE
@ -681,6 +686,7 @@ PTHREADS_TRUE
THREADS_FALSE
THREADS_TRUE
THREADDLLIBS
CFLAGS_EXTRA
GC_CFLAGS
CXXCPP
CPP
@ -846,7 +852,10 @@ enable_large_config
enable_handle_fork
enable_gc_assertions
enable_munmap
enable_werror
enable_single_obj_compilation
enable_gcov
enable_docs
with_libatomic_ops
'
ac_precious_vars='build_alias
@ -1410,7 +1419,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures gc 7.5.0 to adapt to many kinds of systems.
\`configure' configures gc 7.6.8 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1481,7 +1490,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of gc 7.5.0:";;
short | recursive ) echo "Configuration of gc 7.6.8:";;
esac
cat <<\_ACEOF
@ -1506,25 +1515,28 @@ Optional Features:
--enable-threads=TYPE choose threading package
--enable-parallel-mark parallelize marking and free list construction
--enable-cplusplus install C++ support
--disable-gcj-support Disable support for gcj.
--enable-sigrt-signals Force GC to use SIGRTMIN-based signals for thread
--disable-gcj-support disable support for gcj
--enable-sigrt-signals force GC to use SIGRTMIN-based signals for thread
suspend/resume
--enable-gc-debug include full support for pointer backtracing etc.
--disable-java-finalization
Disable support for java finalization.
disable support for java finalization
--disable-atomic-uncollectible
Disable support for atomic uncollectible allocation.
disable support for atomic uncollectible allocation
--enable-redirect-malloc
Redirect malloc and friends to GC routines
--disable-disclaim Disable alternative (more efficient) finalization
interface.
--enable-large-config Optimize for large (> 100 MB) heap or root set
--enable-handle-fork Attempt to ensure a usable collector after fork() in
multi-threaded programs.
redirect malloc and friends to GC routines
--disable-disclaim disable alternative (more efficient) finalization
interface
--enable-large-config optimize for large (> 100 MB) heap or root set
--enable-handle-fork attempt to ensure a usable collector after fork() in
multi-threaded programs
--enable-gc-assertions collector-internal assertion checking
--enable-munmap=N return page to the os if empty for N collections
--enable-werror pass -Werror to the C compiler
--enable-single-obj-compilation
Compile all library .c files into single .o
compile all libgc source files into single .o
--enable-gcov turn on code coverage analysis
--disable-docs do not build and install documentation
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
@ -1542,7 +1554,7 @@ Optional Packages:
configuring with a cross compiler
--with-cross-host=HOST configuring with a cross compiler
--with-libatomic-ops=yes|no|check
Use a external libatomic_ops? (default: check)
Use an external libatomic_ops? (default: check)
Some influential environment variables:
CC C compiler command
@ -1573,7 +1585,7 @@ Some influential environment variables:
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
Report bugs to <bdwgc@lists.opendylan.org>.
Report bugs to <https://github.com/ivmai/bdwgc/issues>.
_ACEOF
ac_status=$?
fi
@ -1636,7 +1648,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
gc configure 7.5.0
gc configure 7.6.8
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -2102,9 +2114,9 @@ $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
( $as_echo "## ---------------------------------------- ##
## Report this to bdwgc@lists.opendylan.org ##
## ---------------------------------------- ##"
( $as_echo "## ---------------------------------------------------- ##
## Report this to https://github.com/ivmai/bdwgc/issues ##
## ---------------------------------------------------- ##"
) | sed "s/^/$as_me: WARNING: /" >&2
;;
esac
@ -2126,7 +2138,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by gc $as_me 7.5.0, which was
It was created by gc $as_me 7.6.8, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@ -2474,7 +2486,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
ac_compiler_gnu=$ac_cv_c_compiler_gnu
## version must conform to [0-9]+[.][0-9]+[.][0-9]+
ac_aux_dir=
@ -2617,7 +2629,42 @@ test -n "$target_alias" &&
NONENONEs,x,x, &&
program_prefix=${target_alias}-
GC_SET_VERSION
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking GC version numbers" >&5
$as_echo_n "checking GC version numbers... " >&6; }
GC_VERSION_MAJOR=`echo $PACKAGE_VERSION | sed 's/^\([0-9][0-9]*\)[.].*$/\1/g'`
GC_VERSION_MINOR=`echo $PACKAGE_VERSION | sed 's/^[^.]*[.]\([0-9][0-9]*\).*$/\1/g'`
GC_VERSION_MICRO=`echo $PACKAGE_VERSION | sed 's/^[^.]*[.][^.]*[.]\([0-9][0-9]*\)$/\1/g'`
if test :$GC_VERSION_MAJOR: = :: \
-o :$GC_VERSION_MINOR: = :: \
-o :$GC_VERSION_MICRO: = :: ;
then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: invalid" >&5
$as_echo "invalid" >&6; }
as_fn_error $? "nonconforming PACKAGE_VERSION='$PACKAGE_VERSION'" "$LINENO" 5
fi
cat >>confdefs.h <<_ACEOF
#define GC_VERSION_MAJOR $GC_VERSION_MAJOR
_ACEOF
cat >>confdefs.h <<_ACEOF
#define GC_VERSION_MINOR $GC_VERSION_MINOR
_ACEOF
cat >>confdefs.h <<_ACEOF
#define GC_VERSION_MICRO $GC_VERSION_MICRO
_ACEOF
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: major=$GC_VERSION_MAJOR minor=$GC_VERSION_MINOR \
micro=$GC_VERSION_MICRO" >&5
$as_echo "major=$GC_VERSION_MAJOR minor=$GC_VERSION_MINOR \
micro=$GC_VERSION_MICRO" >&6; }
am__api_version='1.15'
# Find a good install program. We prefer a C program (faster),
@ -3104,7 +3151,7 @@ fi
# Define the identity of the package.
PACKAGE='gc'
VERSION='7.5.0'
VERSION='7.6.8'
cat >>confdefs.h <<_ACEOF
@ -16098,8 +16145,6 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
# Only expand once:
# Note: If Autoconf reports that LIBTOOL (or AC_ENABLE_SHARED, or
# AC_PROG_LIBTOOL) is undefined, Libtool installation should be checked.
# Special CFLAGS to use when building
gc_cflags=""
@ -16118,7 +16163,7 @@ else
if test :$GCC: != :"yes": ; then
gc_cflags="${gc_flags} +ESdbgasm"
fi
# :TODO: actaully we should check using Autoconf if
# :TODO: actually we should check using Autoconf if
# the compiler supports this option.
;;
esac
@ -16157,6 +16202,8 @@ esac
GC_CFLAGS=${gc_cflags}
# Check whether --enable-threads was given.
if test "${enable_threads+set}" = set; then :
enableval=$enable_threads; THREADS=$enableval
@ -16227,6 +16274,9 @@ fi
old_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $CFLAGS_EXTRA"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
$as_echo_n "checking for inline... " >&6; }
if ${ac_cv_c_inline+:} false; then :
@ -16269,10 +16319,11 @@ _ACEOF
;;
esac
CFLAGS="$old_CFLAGS"
THREADDLLIBS=
need_atomic_ops_asm=false
## Libraries needed to support dynamic loading and/or threads.
# Libraries needed to support dynamic loading and/or threads.
case "$THREADS" in
no | none | single)
THREADS=none
@ -16333,9 +16384,9 @@ fi
$as_echo "#define THREAD_LOCAL_ALLOC 1" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&5
$as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;};
$as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;}
;;
*-*-linux*)
*-*-*linux* | *-*-nacl*)
$as_echo "#define GC_LINUX_THREADS 1" >>confdefs.h
$as_echo "#define _REENTRANT 1" >>confdefs.h
@ -16346,6 +16397,12 @@ $as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;};
$as_echo "#define _REENTRANT 1" >>confdefs.h
;;
*-*-haiku*)
$as_echo "#define GC_HAIKU_THREADS 1" >>confdefs.h
$as_echo "#define _REENTRANT 1" >>confdefs.h
;;
*-*-hpux11*)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"Only HP/UX 11 POSIX threads are supported.\"" >&5
@ -16361,7 +16418,7 @@ $as_echo "$as_me: WARNING: \"Only HP/UX 11 POSIX threads are supported.\"" >&2;}
$as_echo "#define THREAD_LOCAL_ALLOC 1" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&5
$as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;};
$as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;}
THREADDLLIBS="-lpthread -lrt"
# HPUX needs REENTRANT for the _r calls.
@ -16378,7 +16435,7 @@ $as_echo "$as_me: WARNING: \"Only HP-UX 11 POSIX threads are supported.\"" >&2;}
THREADDLLIBS=-pthread
AM_CFLAGS="$AM_CFLAGS -pthread"
;;
*-*-freebsd*)
*-*-dragonfly* | *-*-freebsd*)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"FreeBSD does not yet fully support threads with Boehm GC.\"" >&5
$as_echo "$as_me: WARNING: \"FreeBSD does not yet fully support threads with Boehm GC.\"" >&2;}
$as_echo "#define GC_FREEBSD_THREADS 1" >>confdefs.h
@ -16402,8 +16459,12 @@ $as_echo "$as_me: WARNING: \"FreeBSD does not yet fully support threads with Boe
$as_echo "#define PARALLEL_MARK 1" >>confdefs.h
fi
$as_echo "#define THREAD_LOCAL_ALLOC 1" >>confdefs.h
# FIXME: For a reason, gctest hangs up on kFreeBSD if both of
# THREAD_LOCAL_ALLOC and GC_ENABLE_SUSPEND_THREAD are defined.
if test x"$enable_gcj_support" = xno; then
$as_echo "#define THREAD_LOCAL_ALLOC 1" >>confdefs.h
fi
$as_echo "#define USE_COMPILER_TLS 1" >>confdefs.h
;;
@ -16476,7 +16537,7 @@ $as_echo "$as_me: WARNING: \"Only on NetBSD 2.0 or later.\"" >&2;}
$as_echo "#define GC_DARWIN_THREADS 1" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&5
$as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;};
$as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;}
# Parallel-mark is not well-tested on Darwin
if test "${enable_parallel_mark}" != no; then
$as_echo "#define PARALLEL_MARK 1" >>confdefs.h
@ -16552,7 +16613,7 @@ $as_echo "$THREADDLLIBS" >&6; }
$as_echo "#define THREAD_LOCAL_ALLOC 1" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&5
$as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;};
$as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;}
$as_echo "#define GC_DGUX386_THREADS 1" >>confdefs.h
@ -16619,18 +16680,25 @@ fi
compiler_suncc=no
pthread_start_standalone=no
case "$host" in
powerpc-*-darwin*)
*-*-*linux*)
# Turn on the workaround described in pthread_start.c.
if test "$THREADS" = posix; then :
pthread_start_standalone=yes
fi
;;
powerpc-*-darwin*)
powerpc_darwin=true
;;
*-*-solaris*)
*-*-solaris*)
if test "$GCC" != yes; then
# Solaris SunCC
compiler_suncc=yes
CFLAGS="-O $CFLAGS"
fi
;;
*-*-wince*)
*-*-wince*)
if test "$enable_gc_debug" != "no"; then
$as_echo "#define GC_READ_ENV_FILE 1" >>confdefs.h
@ -16638,11 +16706,19 @@ $as_echo "#define GC_READ_ENV_FILE 1" >>confdefs.h
fi
;;
esac
if test x$pthread_start_standalone = xyes; then
PTHREAD_START_STANDALONE_TRUE=
PTHREAD_START_STANDALONE_FALSE='#'
else
PTHREAD_START_STANDALONE_TRUE='#'
PTHREAD_START_STANDALONE_FALSE=
fi
if test "$GCC" = yes; then
# Output all warnings.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc -Wextra" >&5
$as_echo_n "checking for gcc -Wextra... " >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -Wextra" >&5
$as_echo_n "checking whether compiler supports -Wextra... " >&6; }
old_CFLAGS="$CFLAGS"
CFLAGS="-Wextra $CFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@ -16670,7 +16746,36 @@ $as_echo "$ac_cv_cc_wextra" >&6; }
else
WEXTRA="-W"
fi
CFLAGS="-Wall $WEXTRA $CFLAGS"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -Wpedantic" >&5
$as_echo_n "checking whether compiler supports -Wpedantic... " >&6; }
CFLAGS="-Wpedantic -Wno-long-long $CFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
main ()
{
extern int quiet;
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_cc_pedantic=yes
else
ac_cv_cc_pedantic=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CFLAGS="$old_CFLAGS"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_pedantic" >&5
$as_echo "$ac_cv_cc_pedantic" >&6; }
WPEDANTIC=
if test "$ac_cv_cc_pedantic" = yes; then :
WPEDANTIC="-Wpedantic -Wno-long-long"
fi
CFLAGS="-Wall $WEXTRA $WPEDANTIC $CFLAGS"
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for xlc" >&5
@ -16718,8 +16823,8 @@ fi
if test "$GCC" = yes; then
# Disable aliasing optimization unless forced to.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gcc supports -fno-strict-aliasing" >&5
$as_echo_n "checking whether gcc supports -fno-strict-aliasing... " >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -fno-strict-aliasing" >&5
$as_echo_n "checking whether compiler supports -fno-strict-aliasing... " >&6; }
ac_cv_fno_strict_aliasing=no
for cflag in $CFLAGS; do
case "$cflag" in
@ -16757,6 +16862,42 @@ fi
$as_echo "$ac_cv_fno_strict_aliasing" >&6; }
fi
# Check for getcontext (uClibc can be configured without it, for example)
for ac_func in getcontext
do :
ac_fn_c_check_func "$LINENO" "getcontext" "ac_cv_func_getcontext"
if test "x$ac_cv_func_getcontext" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_GETCONTEXT 1
_ACEOF
fi
done
if test "$ac_cv_func_getcontext" = "no"; then
$as_echo "#define NO_GETCONTEXT 1" >>confdefs.h
fi
# Check whether dl_iterate_phdr exists (as a strong symbol).
for ac_func in dl_iterate_phdr
do :
ac_fn_c_check_func "$LINENO" "dl_iterate_phdr" "ac_cv_func_dl_iterate_phdr"
if test "x$ac_cv_func_dl_iterate_phdr" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_DL_ITERATE_PHDR 1
_ACEOF
fi
done
if test "$ac_cv_func_dl_iterate_phdr" = "yes"; then
$as_echo "#define HAVE_DL_ITERATE_PHDR 1" >>confdefs.h
fi
case "$host" in
# While IRIX 6 has libdl for the O32 and N32 ABIs, it's missing for N64
# and unnecessary everywhere.
@ -16825,6 +16966,25 @@ else
fi
# Check for various headers.
for ac_header in execinfo.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default"
if test "x$ac_cv_header_execinfo_h" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_EXECINFO_H 1
_ACEOF
fi
done
if test "$ac_cv_header_execinfo_h" != "yes"; then
$as_echo "#define GC_MISSING_EXECINFO_H 1" >>confdefs.h
fi
# extra LD Flags which are required for targets
case "${host}" in
*-*-darwin*)
@ -16948,8 +17108,8 @@ if test "${enable_shared}" = yes; then
if test "$GCC" = yes; then
# Pass -fvisibility=hidden option if supported
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gcc supports -fvisibility" >&5
$as_echo_n "checking whether gcc supports -fvisibility... " >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -fvisibility" >&5
$as_echo_n "checking whether compiler supports -fvisibility... " >&6; }
old_CFLAGS="$CFLAGS"
CFLAGS="-Werror -fvisibility=hidden $CFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@ -16972,6 +17132,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CFLAGS="$old_CFLAGS"
if test "$ac_cv_fvisibility_hidden" = yes; then :
CFLAGS="-DGC_VISIBILITY_HIDDEN_SET -fvisibility=hidden $CFLAGS"
else
CFLAGS="-DGC_NO_VISIBILITY $CFLAGS"
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_fvisibility_hidden" >&5
$as_echo "$ac_cv_fvisibility_hidden" >&6; }
@ -17016,6 +17178,10 @@ $as_echo "#define SUNOS53_SHARED_LIB 1" >>confdefs.h
;;
ia64-*-*)
machdep="ia64_save_regs_in_stack.lo"
;;
*-*-nacl*)
$as_echo "#define NO_EXECUTE_PERMISSION 1" >>confdefs.h
;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $machdep" >&5
@ -17039,14 +17205,8 @@ if test "${with_cross_host+set}" = set; then :
fi
# automake wants to see AC_EXEEXT. But we don't need it. And having
# it is actually a problem, because the compiler we're passed can't
# necessarily do a full link. So we fool automake here.
if false; then
# autoconf 2.50 runs AC_EXEEXT by default, and the macro expands
# to nothing, so nothing would remain between `then' and `fi' if it
# were not for the `:' below.
:
:
fi
@ -17094,6 +17254,9 @@ if test x"$enable_gcj_support" != xno; then
$as_echo "#define GC_GCJ_SUPPORT 1" >>confdefs.h
$as_echo "#define GC_ENABLE_SUSPEND_THREAD 1" >>confdefs.h
fi
# Check whether --enable-sigrt-signals was given.
@ -17217,6 +17380,8 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dladdr" >&5
$as_echo_n "checking for dladdr... " >&6; }
have_dladdr=no
old_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $CFLAGS_EXTRA"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@ -17237,6 +17402,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
have_dladdr=yes
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CFLAGS="$old_CFLAGS"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_dladdr" >&5
$as_echo "$have_dladdr" >&6; }
if test x"$have_dladdr" = xyes; then
@ -17254,7 +17420,6 @@ fi
## :GOTCHA: we do not check anything but sys/dg_sys_info.h
if test $ac_is_dgux = yes; then
dgux_spec_opts="-DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
CFLAGS="$dgux_spec_opts $CFLAGS"
@ -17285,7 +17450,7 @@ fi
if test x"$enable_atomic_uncollectible" != x"no"; then
$as_echo "#define ATOMIC_UNCOLLECTABLE 1" >>confdefs.h
$as_echo "#define GC_ATOMIC_UNCOLLECTABLE 1" >>confdefs.h
fi
@ -17339,7 +17504,6 @@ if test "${enable_large_config+set}" = set; then :
enableval=$enable_large_config;
fi
if test "${enable_large_config}" = yes; then
$as_echo "#define LARGE_CONFIG 1" >>confdefs.h
@ -17351,7 +17515,6 @@ if test "${enable_handle_fork+set}" = set; then :
enableval=$enable_handle_fork;
fi
if test "${enable_handle_fork}" = yes; then
$as_echo "#define HANDLE_FORK 1" >>confdefs.h
@ -17395,18 +17558,11 @@ if test "${enable_munmap+set}" = set; then :
enableval=$enable_munmap; MUNMAP_THRESHOLD=$enableval
fi
if test "${enable_munmap}" != ""; then
if test x$enable_munmap != x -a x$enable_munmap != xno; then
$as_echo "#define USE_MMAP 1" >>confdefs.h
case "$host" in
*-*-cygwin*)
# Workaround for Cygwin: use VirtualAlloc since mmap(PROT_NONE) fails
$as_echo "#define USE_WINALLOC 1" >>confdefs.h
;;
esac
$as_echo "#define USE_MUNMAP 1" >>confdefs.h
@ -17435,6 +17591,24 @@ else
fi
# Check whether --enable-werror was given.
if test "${enable_werror+set}" = set; then :
enableval=$enable_werror; werror_flag=$enableval
else
werror_flag=no
fi
if test x$werror_flag = xyes; then
WERROR_CFLAGS="-Werror"
case "$host" in
# _dyld_bind_fully_image_containing_address is deprecated in OS X 10.5+
*-*-darwin*)
WERROR_CFLAGS="$WERROR_CFLAGS -Wno-deprecated-declarations"
;;
esac
fi
# Check whether --enable-single-obj-compilation was given.
if test "${enable_single_obj_compilation+set}" = set; then :
enableval=$enable_single_obj_compilation; single_obj_compilation=yes
@ -17449,6 +17623,37 @@ else
fi
# Check whether --enable-gcov was given.
if test "${enable_gcov+set}" = set; then :
enableval=$enable_gcov;
fi
if test "$enable_gcov" = "yes"; then
CFLAGS="$CFLAGS --coverage"
if test "${enable_shared}" = no; then
# FIXME: As of g++-4.8.4/x86_64, in case of shared library build, test_cpp
# linkage fails with "hidden symbol atexit is referenced by DSO" message.
CXXFLAGS="$CXXFLAGS --coverage"
fi
# Turn off optimization to get accurate line numbers.
CFLAGS=`echo "$CFLAGS" | sed -e 's/-O\(1\|2\|3\|4\|s\|fast\)\?//g'`
CXXFLAGS=`echo "$CXXFLAGS" | sed -e 's/-O\(1\|2\|3\|4\|s\|fast\)\?//g'`
fi
# Check whether --enable-docs was given.
if test "${enable_docs+set}" = set; then :
enableval=$enable_docs;
fi
if test x$enable_docs != xno; then
ENABLE_DOCS_TRUE=
ENABLE_DOCS_FALSE='#'
else
ENABLE_DOCS_TRUE='#'
ENABLE_DOCS_FALSE=
fi
# Atomic Ops
# ----------
@ -17463,11 +17668,14 @@ else
fi
# Check for an external libatomic_ops if the answer was yes or check. If not
# found, fail on yes, and convert check to no.
# Note: "syntax error near unexpected token ATOMIC_OPS" reported by configure
# means Autotools pkg.m4 file was not found during aclocal.m4 generation.
# Check for an external libatomic_ops if the above answer is "yes" or "check".
# If not found, fail on "yes", and convert "check" to "no".
# First, check that libatomic_ops usage is not disabled explicitly.
missing_libatomic_ops=false
if test x"$with_libatomic_ops" != xno -a x"$THREADS" != xnone; then :
missing_libatomic_ops=true
fi
@ -17588,11 +17796,11 @@ $as_echo "no" >&6; }
PKG_CONFIG=""
fi
fi
if test x"$with_libatomic_ops" != xno; then :
if test x$missing_libatomic_ops = xtrue; then :
pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ATOMIC_OPS" >&5
$as_echo_n "checking for ATOMIC_OPS... " >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for atomic_ops" >&5
$as_echo_n "checking for atomic_ops... " >&6; }
if test -n "$ATOMIC_OPS_CFLAGS"; then
pkg_cv_ATOMIC_OPS_CFLAGS="$ATOMIC_OPS_CFLAGS"
@ -17632,7 +17840,7 @@ fi
if test $pkg_failed = yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@ -17648,20 +17856,29 @@ fi
# Put the nasty error message in config.log where it belongs
echo "$ATOMIC_OPS_PKG_ERRORS" >&5
missing_libatomic_ops=true
elif test $pkg_failed = untried; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
missing_libatomic_ops=true
else
ATOMIC_OPS_CFLAGS=$pkg_cv_ATOMIC_OPS_CFLAGS
ATOMIC_OPS_LIBS=$pkg_cv_ATOMIC_OPS_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
missing_libatomic_ops=false
fi
fi
if test x$missing_libatomic_ops = xtrue; then :
ac_fn_c_check_header_mongrel "$LINENO" "atomic_ops.h" "ac_cv_header_atomic_ops_h" "$ac_includes_default"
if test "x$ac_cv_header_atomic_ops_h" = xyes; then :
missing_libatomic_ops=false
fi
fi
fi
if test x$missing_libatomic_ops = xtrue ; then :
if test x$missing_libatomic_ops = xtrue; then :
if test x"$with_libatomic_ops" != xcheck; then :
as_fn_error $? "An external libatomic_ops was not found" "$LINENO" 5
fi
@ -17670,7 +17887,8 @@ fi
# If we have neither an external or an internal version, offer a useful hint
# and exit.
if test x"$with_libatomic_ops" = xno -a ! -e "$srcdir/libatomic_ops"; then :
if test x"$with_libatomic_ops" = xno \
-a ! -e "$srcdir/libatomic_ops/src/atomic_ops.h"; then :
as_fn_error $? "libatomic_ops is required. You can either install it on
your system, or fetch and unpack a recent version into the
source directory and link or rename it to libatomic_ops." "$LINENO" 5
@ -17682,8 +17900,13 @@ $as_echo_n "checking which libatomic_ops to use... " >&6; }
if test x"$with_libatomic_ops" != xno; then :
if test x"$THREADS" != xnone; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: external" >&5
$as_echo "external" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
$as_echo "none" >&6; }
fi
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: internal" >&5
$as_echo "internal" >&6; }
@ -17879,6 +18102,10 @@ if test -z "${WIN32_THREADS_TRUE}" && test -z "${WIN32_THREADS_FALSE}"; then
as_fn_error $? "conditional \"WIN32_THREADS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${PTHREAD_START_STANDALONE_TRUE}" && test -z "${PTHREAD_START_STANDALONE_FALSE}"; then
as_fn_error $? "conditional \"PTHREAD_START_STANDALONE\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${ASM_WITH_CPP_UNSUPPORTED_TRUE}" && test -z "${ASM_WITH_CPP_UNSUPPORTED_FALSE}"; then
as_fn_error $? "conditional \"ASM_WITH_CPP_UNSUPPORTED\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
@ -17911,6 +18138,10 @@ if test -z "${SINGLE_GC_OBJ_TRUE}" && test -z "${SINGLE_GC_OBJ_FALSE}"; then
as_fn_error $? "conditional \"SINGLE_GC_OBJ\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${ENABLE_DOCS_TRUE}" && test -z "${ENABLE_DOCS_FALSE}"; then
as_fn_error $? "conditional \"ENABLE_DOCS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${USE_INTERNAL_LIBATOMIC_OPS_TRUE}" && test -z "${USE_INTERNAL_LIBATOMIC_OPS_FALSE}"; then
as_fn_error $? "conditional \"USE_INTERNAL_LIBATOMIC_OPS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
@ -18316,7 +18547,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by gc $as_me 7.5.0, which was
This file was extended by gc $as_me 7.6.8, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -18376,13 +18607,13 @@ $config_headers
Configuration commands:
$config_commands
Report bugs to <bdwgc@lists.opendylan.org>."
Report bugs to <https://github.com/ivmai/bdwgc/issues>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
gc config.status 7.5.0
gc config.status 7.6.8
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

View file

@ -1,4 +1,6 @@
# Copyright (c) 1999-2001 by Red Hat, Inc. All rights reserved.
# Copyright (c) 2005-2009 Hewlett-Packard Development Company, L.P.
# Copyright (c) 2009-2018 Ivan Maidanski
#
# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@ -11,15 +13,16 @@
dnl Process this file with autoconf to produce configure.
# Initialization
AC_INIT(gc,7.5.0,bdwgc@lists.opendylan.org)
## version must conform to [0-9]+[.][0-9]+[.][0-9]+
dnl Initialization.
AC_INIT(gc,7.6.8,https://github.com/ivmai/bdwgc/issues)
dnl Version must conform to: [0-9]+[.][0-9]+[.][0-9]+
AC_CONFIG_SRCDIR(gcj_mlc.c)
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_TARGET
AC_PREREQ(2.61)
GC_SET_VERSION
AM_INIT_AUTOMAKE([foreign dist-bzip2 nostdinc subdir-objects])
AM_INIT_AUTOMAKE([foreign nostdinc subdir-objects])
AC_CONFIG_HEADERS([include/config.h])
AM_MAINTAINER_MODE
@ -31,8 +34,8 @@ AC_PROG_CXX
AM_PROG_AS
AC_PROG_INSTALL
LT_INIT
# Note: If Autoconf reports that LIBTOOL (or AC_ENABLE_SHARED, or
# AC_PROG_LIBTOOL) is undefined, Libtool installation should be checked.
dnl Note: If Autoconf reports that LIBTOOL (or AC_ENABLE_SHARED, or
dnl AC_PROG_LIBTOOL) is undefined, Libtool installation should be checked.
# Special CFLAGS to use when building
gc_cflags=""
@ -51,7 +54,7 @@ else
if test :$GCC: != :"yes": ; then
gc_cflags="${gc_flags} +ESdbgasm"
fi
# :TODO: actaully we should check using Autoconf if
# :TODO: actually we should check using Autoconf if
# the compiler supports this option.
;;
esac
@ -90,6 +93,9 @@ esac
GC_CFLAGS=${gc_cflags}
AC_SUBST(GC_CFLAGS)
dnl Extra user-defined flags to pass both to C and C++ compilers.
AC_SUBST([CFLAGS_EXTRA])
AC_ARG_ENABLE(threads,
[AC_HELP_STRING([--enable-threads=TYPE], [choose threading package])],
THREADS=$enableval,
@ -137,6 +143,7 @@ AH_TEMPLATE([GC_AIX_THREADS], [Define to support IBM AIX threads.])
AH_TEMPLATE([GC_DARWIN_THREADS], [Define to support Darwin pthreads.])
AH_TEMPLATE([GC_FREEBSD_THREADS], [Define to support FreeBSD pthreads.])
AH_TEMPLATE([GC_GNU_THREADS], [Define to support GNU pthreads.])
AH_TEMPLATE([GC_HAIKU_THREADS], [Define to support Haiku pthreads.])
AH_TEMPLATE([GC_HPUX_THREADS], [Define to support HP/UX 11 pthreads.])
AH_TEMPLATE([GC_IRIX_THREADS], [Define to support Irix pthreads.])
AH_TEMPLATE([GC_LINUX_THREADS], [Define to support pthreads on Linux.])
@ -164,11 +171,14 @@ AH_TEMPLATE([GC_DLL],
[Define to build dynamic libraries with only API symbols exposed.])
dnl Check for a flavor of supported inline keyword.
old_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $CFLAGS_EXTRA"
AC_C_INLINE
CFLAGS="$old_CFLAGS"
THREADDLLIBS=
need_atomic_ops_asm=false
## Libraries needed to support dynamic loading and/or threads.
# Libraries needed to support dynamic loading and/or threads.
case "$THREADS" in
no | none | single)
THREADS=none
@ -185,9 +195,9 @@ case "$THREADS" in
AC_DEFINE(PARALLEL_MARK)
fi
AC_DEFINE(THREAD_LOCAL_ALLOC)
AC_MSG_WARN("Explicit GC_INIT() calls may be required.");
AC_MSG_WARN("Explicit GC_INIT() calls may be required.")
;;
*-*-linux*)
*-*-*linux* | *-*-nacl*)
AC_DEFINE(GC_LINUX_THREADS)
AC_DEFINE(_REENTRANT)
;;
@ -195,6 +205,10 @@ case "$THREADS" in
AC_DEFINE(GC_AIX_THREADS)
AC_DEFINE(_REENTRANT)
;;
*-*-haiku*)
AC_DEFINE(GC_HAIKU_THREADS)
AC_DEFINE(_REENTRANT)
;;
*-*-hpux11*)
AC_MSG_WARN("Only HP/UX 11 POSIX threads are supported.")
AC_DEFINE(GC_HPUX_THREADS)
@ -203,7 +217,7 @@ case "$THREADS" in
AC_DEFINE(PARALLEL_MARK)
fi
AC_DEFINE(THREAD_LOCAL_ALLOC)
AC_MSG_WARN("Explicit GC_INIT() calls may be required.");
AC_MSG_WARN("Explicit GC_INIT() calls may be required.")
THREADDLLIBS="-lpthread -lrt"
# HPUX needs REENTRANT for the _r calls.
AC_DEFINE(_REENTRANT, 1, [Required define if using POSIX threads.])
@ -216,7 +230,7 @@ case "$THREADS" in
THREADDLLIBS=-pthread
AM_CFLAGS="$AM_CFLAGS -pthread"
;;
*-*-freebsd*)
*-*-dragonfly* | *-*-freebsd*)
AC_MSG_WARN("FreeBSD does not yet fully support threads with Boehm GC.")
AC_DEFINE(GC_FREEBSD_THREADS)
AM_CFLAGS="$AM_CFLAGS -pthread"
@ -233,7 +247,11 @@ case "$THREADS" in
if test "${enable_parallel_mark}" = yes; then
AC_DEFINE(PARALLEL_MARK)
fi
AC_DEFINE(THREAD_LOCAL_ALLOC)
# FIXME: For a reason, gctest hangs up on kFreeBSD if both of
# THREAD_LOCAL_ALLOC and GC_ENABLE_SUSPEND_THREAD are defined.
if test x"$enable_gcj_support" = xno; then
AC_DEFINE(THREAD_LOCAL_ALLOC)
fi
AC_DEFINE(USE_COMPILER_TLS)
;;
*-*-gnu*)
@ -286,7 +304,7 @@ case "$THREADS" in
;;
*-*-darwin*)
AC_DEFINE(GC_DARWIN_THREADS)
AC_MSG_WARN("Explicit GC_INIT() calls may be required.");
AC_MSG_WARN("Explicit GC_INIT() calls may be required.")
# Parallel-mark is not well-tested on Darwin
if test "${enable_parallel_mark}" != no; then
AC_DEFINE(PARALLEL_MARK)
@ -346,7 +364,7 @@ case "$THREADS" in
AC_DEFINE(PARALLEL_MARK)
fi
AC_DEFINE(THREAD_LOCAL_ALLOC)
AC_MSG_WARN("Explicit GC_INIT() calls may be required.");
AC_MSG_WARN("Explicit GC_INIT() calls may be required.")
AC_DEFINE([GC_DGUX386_THREADS], 1,
[Define to enable support for DB/UX threads on i386.])
AC_DEFINE([DGUX_THREADS], 1,
@ -379,35 +397,52 @@ AM_CONDITIONAL(DARWIN_THREADS, test x$darwin_threads = xtrue)
AM_CONDITIONAL(WIN32_THREADS, test x$win32_threads = xtrue)
compiler_suncc=no
pthread_start_standalone=no
case "$host" in
powerpc-*-darwin*)
*-*-*linux*)
# Turn on the workaround described in pthread_start.c.
AS_IF([test "$THREADS" = posix], [pthread_start_standalone=yes])
;;
powerpc-*-darwin*)
powerpc_darwin=true
;;
*-*-solaris*)
*-*-solaris*)
if test "$GCC" != yes; then
# Solaris SunCC
compiler_suncc=yes
CFLAGS="-O $CFLAGS"
fi
;;
*-*-wince*)
*-*-wince*)
if test "$enable_gc_debug" != "no"; then
AC_DEFINE([GC_READ_ENV_FILE], 1,
[Read environment variables from the GC 'env' file.])
fi
;;
esac
AM_CONDITIONAL(PTHREAD_START_STANDALONE,
test x$pthread_start_standalone = xyes)
if test "$GCC" = yes; then
# Output all warnings.
AC_MSG_CHECKING(for gcc -Wextra)
AC_MSG_CHECKING([whether compiler supports -Wextra])
old_CFLAGS="$CFLAGS"
CFLAGS="-Wextra $CFLAGS"
AC_TRY_COMPILE([],[], [ac_cv_cc_wextra=yes], [ac_cv_cc_wextra=no])
CFLAGS="$old_CFLAGS"
AC_MSG_RESULT($ac_cv_cc_wextra)
AS_IF([test "$ac_cv_cc_wextra" = yes], [WEXTRA="-Wextra"], [WEXTRA="-W"])
CFLAGS="-Wall $WEXTRA $CFLAGS"
AC_MSG_CHECKING([whether compiler supports -Wpedantic])
CFLAGS="-Wpedantic -Wno-long-long $CFLAGS"
AC_TRY_COMPILE([],[
extern int quiet;
], [ac_cv_cc_pedantic=yes], [ac_cv_cc_pedantic=no])
CFLAGS="$old_CFLAGS"
AC_MSG_RESULT($ac_cv_cc_pedantic)
WPEDANTIC=
AS_IF([test "$ac_cv_cc_pedantic" = yes],
[WPEDANTIC="-Wpedantic -Wno-long-long"])
CFLAGS="-Wall $WEXTRA $WPEDANTIC $CFLAGS"
fi
AC_MSG_CHECKING(for xlc)
@ -429,7 +464,7 @@ AM_CONDITIONAL([ASM_WITH_CPP_UNSUPPORTED],
if test "$GCC" = yes; then
# Disable aliasing optimization unless forced to.
AC_MSG_CHECKING([whether gcc supports -fno-strict-aliasing])
AC_MSG_CHECKING([whether compiler supports -fno-strict-aliasing])
ac_cv_fno_strict_aliasing=no
for cflag in $CFLAGS; do
case "$cflag" in
@ -451,6 +486,19 @@ if test "$GCC" = yes; then
AC_MSG_RESULT($ac_cv_fno_strict_aliasing)
fi
# Check for getcontext (uClibc can be configured without it, for example)
AC_CHECK_FUNCS([getcontext])
if test "$ac_cv_func_getcontext" = "no"; then
AC_DEFINE([NO_GETCONTEXT], [1], [Missing getcontext function.])
fi
# Check whether dl_iterate_phdr exists (as a strong symbol).
AC_CHECK_FUNCS([dl_iterate_phdr])
if test "$ac_cv_func_dl_iterate_phdr" = "yes"; then
AC_DEFINE([HAVE_DL_ITERATE_PHDR], [1],
[Define if 'dl_iterate_phdr' function is available.])
fi
case "$host" in
# While IRIX 6 has libdl for the O32 and N32 ABIs, it's missing for N64
# and unnecessary everywhere.
@ -473,6 +521,12 @@ case "$host" in
esac
AM_CONDITIONAL(AVOID_CPP_LIB,test $avoid_cpp_lib = yes)
# Check for various headers.
AC_CHECK_HEADERS([execinfo.h])
if test "$ac_cv_header_execinfo_h" != "yes"; then
AC_DEFINE([GC_MISSING_EXECINFO_H], [1], [Missing execinfo.h header.])
fi
# extra LD Flags which are required for targets
case "${host}" in
*-*-darwin*)
@ -555,14 +609,15 @@ if test "${enable_shared}" = yes; then
AC_DEFINE(GC_DLL)
if test "$GCC" = yes; then
# Pass -fvisibility=hidden option if supported
AC_MSG_CHECKING([whether gcc supports -fvisibility])
AC_MSG_CHECKING([whether compiler supports -fvisibility])
old_CFLAGS="$CFLAGS"
CFLAGS="-Werror -fvisibility=hidden $CFLAGS"
AC_TRY_COMPILE([],[], [ac_cv_fvisibility_hidden=yes],
[ac_cv_fvisibility_hidden=no])
CFLAGS="$old_CFLAGS"
AS_IF([test "$ac_cv_fvisibility_hidden" = yes],
[CFLAGS="-DGC_VISIBILITY_HIDDEN_SET -fvisibility=hidden $CFLAGS"])
[CFLAGS="-DGC_VISIBILITY_HIDDEN_SET -fvisibility=hidden $CFLAGS"],
[CFLAGS="-DGC_NO_VISIBILITY $CFLAGS"])
AC_MSG_RESULT($ac_cv_fvisibility_hidden)
fi
fi
@ -606,6 +661,9 @@ case "$host" in
ia64-*-*)
machdep="ia64_save_regs_in_stack.lo"
;;
*-*-nacl*)
AC_DEFINE(NO_EXECUTE_PERMISSION)
;;
esac
AC_MSG_RESULT($machdep)
addobjs="$addobjs $machdep"
@ -621,13 +679,13 @@ AC_ARG_WITH(target-subdir,
AC_ARG_WITH(cross-host,
[ --with-cross-host=HOST configuring with a cross compiler])
# automake wants to see AC_EXEEXT. But we don't need it. And having
# it is actually a problem, because the compiler we're passed can't
# necessarily do a full link. So we fool automake here.
dnl automake wants to see AC_EXEEXT. But we don't need it. And having
dnl it is actually a problem, because the compiler we're passed can't
dnl necessarily do a full link. So we fool automake here.
if false; then
# autoconf 2.50 runs AC_EXEEXT by default, and the macro expands
# to nothing, so nothing would remain between `then' and `fi' if it
# were not for the `:' below.
dnl autoconf 2.50 runs AC_EXEEXT by default, and the macro expands
dnl to nothing, so nothing would remain between `then' and `fi' if it
dnl were not for the `:' below.
:
AC_EXEEXT
fi
@ -674,16 +732,17 @@ dnl
dnl By default, make the library as general as possible.
dnl enable_gcj_support=no
AC_ARG_ENABLE(gcj-support,
[AC_HELP_STRING([--disable-gcj-support],
[Disable support for gcj.])])
[AC_HELP_STRING([--disable-gcj-support], [disable support for gcj])])
if test x"$enable_gcj_support" != xno; then
AC_DEFINE(GC_GCJ_SUPPORT, 1, [Define to include support for gcj.])
AC_DEFINE([GC_ENABLE_SUSPEND_THREAD], 1,
[Define to turn on GC_suspend_thread support.])
fi
dnl Interaction with other programs that might use signals.
AC_ARG_ENABLE(sigrt-signals,
[AC_HELP_STRING([--enable-sigrt-signals],
[Force GC to use SIGRTMIN-based signals for thread suspend/resume])])
[force GC to use SIGRTMIN-based signals for thread suspend/resume])])
if test x"${enable_sigrt_signals}" = xyes; then
AC_DEFINE([GC_USESIGRT_SIGNALS], 1,
[Force the GC to use signals based on SIGRTMIN+k.])
@ -740,12 +799,15 @@ AM_CONDITIONAL([KEEP_BACK_PTRS], [test x"$keep_back_ptrs" = xtrue])
# Check for dladdr (used for debugging).
AC_MSG_CHECKING(for dladdr)
have_dladdr=no
old_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $CFLAGS_EXTRA"
AC_TRY_COMPILE([
#define _GNU_SOURCE 1
#include <dlfcn.h>], [{
Dl_info info;
(void)dladdr("", &info);
}], [ have_dladdr=yes ])
CFLAGS="$old_CFLAGS"
AC_MSG_RESULT($have_dladdr)
if test x"$have_dladdr" = xyes; then
AC_DEFINE([HAVE_DLADDR], 1, [Define to use 'dladdr' function.])
@ -756,7 +818,7 @@ ac_is_dgux=no
AC_CHECK_HEADER(sys/dg_sys_info.h,
[ac_is_dgux=yes;])
## :GOTCHA: we do not check anything but sys/dg_sys_info.h
dnl :GOTCHA: we do not check anything but sys/dg_sys_info.h
if test $ac_is_dgux = yes; then
dgux_spec_opts="-DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
CFLAGS="$dgux_spec_opts $CFLAGS"
@ -771,22 +833,22 @@ fi
AC_ARG_ENABLE(java-finalization,
[AC_HELP_STRING([--disable-java-finalization],
[Disable support for java finalization.])])
[disable support for java finalization])])
if test x"$enable_java_finalization" != xno; then
AC_DEFINE([JAVA_FINALIZATION], 1, [See doc/README.macros.])
fi
AC_ARG_ENABLE(atomic-uncollectable,
[AC_HELP_STRING([--disable-atomic-uncollectible],
[Disable support for atomic uncollectible allocation.])])
[disable support for atomic uncollectible allocation])])
if test x"$enable_atomic_uncollectible" != x"no"; then
AC_DEFINE(ATOMIC_UNCOLLECTABLE, 1,
AC_DEFINE([GC_ATOMIC_UNCOLLECTABLE], 1,
[Define to enable atomic uncollectible allocation.])
fi
AC_ARG_ENABLE(redirect-malloc,
[AC_HELP_STRING([--enable-redirect-malloc],
[Redirect malloc and friends to GC routines])])
[redirect malloc and friends to GC routines])])
if test "${enable_redirect_malloc}" = yes; then
if test "${enable_gc_debug}" = yes; then
@ -804,7 +866,7 @@ fi
AC_ARG_ENABLE(disclaim,
[AC_HELP_STRING([--disable-disclaim],
[Disable alternative (more efficient) finalization interface.])])
[disable alternative (more efficient) finalization interface])])
if test x"$enable_disclaim" != xno; then
AC_DEFINE(ENABLE_DISCLAIM, 1,
[Define to enable alternative finalization interface.])
@ -814,17 +876,16 @@ AM_CONDITIONAL(ENABLE_DISCLAIM,
AC_ARG_ENABLE(large-config,
[AC_HELP_STRING([--enable-large-config],
[Optimize for large (> 100 MB) heap or root set])])
[optimize for large (> 100 MB) heap or root set])])
if test "${enable_large_config}" = yes; then
AC_DEFINE(LARGE_CONFIG, 1, [Define to optimize for large heaps or root sets.])
AC_DEFINE(LARGE_CONFIG, 1,
[Define to optimize for large heaps or root sets.])
fi
AC_ARG_ENABLE(handle-fork,
[AC_HELP_STRING([--enable-handle-fork],
[Attempt to ensure a usable collector after fork() in multi-threaded
programs.])])
[attempt to ensure a usable collector after fork() in multi-threaded
programs])])
if test "${enable_handle_fork}" = yes; then
AC_DEFINE(HANDLE_FORK, 1,
[Define to install pthread_atfork() handlers by default.])
@ -835,7 +896,7 @@ fi
dnl This is something of a hack. When cross-compiling we turn off
dnl some functionality. We also enable the "small" configuration.
dnl These is only correct when targetting an embedded system. FIXME.
dnl These is only correct when targeting an embedded system. FIXME.
if test -n "${with_cross_host}"; then
AC_DEFINE([NO_CLOCK], 1, [Define to not use system clock (cross compiling).])
AC_DEFINE([SMALL_CONFIG], 1,
@ -853,24 +914,20 @@ AC_ARG_ENABLE(gc-assertions,
[AC_HELP_STRING([--enable-gc-assertions],
[collector-internal assertion checking])])
if test "${enable_gc_assertions}" = yes; then
AC_DEFINE([GC_ASSERTIONS], 1, [Define to enable internal debug assertions.])
AC_DEFINE([GC_ASSERTIONS], 1,
[Define to enable internal debug assertions.])
fi
AC_ARG_ENABLE(munmap,
[AC_HELP_STRING([--enable-munmap=N],
[return page to the os if empty for N collections])],
MUNMAP_THRESHOLD=$enableval)
if test "${enable_munmap}" != ""; then
if test x$enable_munmap != x -a x$enable_munmap != xno; then
AC_DEFINE([USE_MMAP], 1,
[Define to use mmap instead of sbrk to expand the heap.])
case "$host" in
*-*-cygwin*)
# Workaround for Cygwin: use VirtualAlloc since mmap(PROT_NONE) fails
AC_DEFINE([USE_WINALLOC], 1,
AH_TEMPLATE([USE_WINALLOC],
[Define to use Win32 VirtualAlloc (instead of sbrk or
mmap) to expand the heap.])
;;
esac
AC_DEFINE([USE_MUNMAP], 1,
[Define to return memory to OS with munmap calls
(see doc/README.macros).])
@ -888,12 +945,45 @@ fi
AM_CONDITIONAL(USE_LIBDIR, test -z "$with_cross_host")
AC_ARG_ENABLE(werror,
[AS_HELP_STRING([--enable-werror], [pass -Werror to the C compiler])],
werror_flag=$enableval, werror_flag=no)
if test x$werror_flag = xyes; then
WERROR_CFLAGS="-Werror"
case "$host" in
# _dyld_bind_fully_image_containing_address is deprecated in OS X 10.5+
*-*-darwin*)
WERROR_CFLAGS="$WERROR_CFLAGS -Wno-deprecated-declarations"
;;
esac
fi
AC_SUBST([WERROR_CFLAGS])
AC_ARG_ENABLE(single-obj-compilation,
[AC_HELP_STRING([--enable-single-obj-compilation],
[Compile all library .c files into single .o])],
[compile all libgc source files into single .o])],
[single_obj_compilation=yes])
AM_CONDITIONAL([SINGLE_GC_OBJ], [test "$single_obj_compilation" = "yes"])
AC_ARG_ENABLE(gcov,
[AC_HELP_STRING([--enable-gcov], [turn on code coverage analysis])])
if test "$enable_gcov" = "yes"; then
CFLAGS="$CFLAGS --coverage"
if test "${enable_shared}" = no; then
# FIXME: As of g++-4.8.4/x86_64, in case of shared library build, test_cpp
# linkage fails with "hidden symbol atexit is referenced by DSO" message.
CXXFLAGS="$CXXFLAGS --coverage"
fi
# Turn off optimization to get accurate line numbers.
CFLAGS=`echo "$CFLAGS" | sed -e 's/-O\(1\|2\|3\|4\|s\|fast\)\?//g'`
CXXFLAGS=`echo "$CXXFLAGS" | sed -e 's/-O\(1\|2\|3\|4\|s\|fast\)\?//g'`
fi
AC_ARG_ENABLE(docs,
[AC_HELP_STRING([--disable-docs],
[do not build and install documentation])])
AM_CONDITIONAL(ENABLE_DOCS, test x$enable_docs != xno)
# Atomic Ops
# ----------
@ -901,25 +991,36 @@ AM_CONDITIONAL([SINGLE_GC_OBJ], [test "$single_obj_compilation" = "yes"])
# found.
AC_ARG_WITH([libatomic-ops],
[AS_HELP_STRING([--with-libatomic-ops[=yes|no|check]],
[Use a external libatomic_ops? (default: check)])],
[Use an external libatomic_ops? (default: check)])],
[], [with_libatomic_ops=check])
# Check for an external libatomic_ops if the answer was yes or check. If not
# found, fail on yes, and convert check to no.
# Note: "syntax error near unexpected token ATOMIC_OPS" reported by configure
# means Autotools pkg.m4 file was not found during aclocal.m4 generation.
# Check for an external libatomic_ops if the above answer is "yes" or "check".
# If not found, fail on "yes", and convert "check" to "no".
# First, check that libatomic_ops usage is not disabled explicitly.
missing_libatomic_ops=false
AS_IF([test x"$with_libatomic_ops" != xno],
[ PKG_CHECK_MODULES([ATOMIC_OPS], [atomic_ops], [],
[ missing_libatomic_ops=true ]) ])
AS_IF([test x$missing_libatomic_ops = xtrue ],
AS_IF([test x"$with_libatomic_ops" != xno -a x"$THREADS" != xnone],
[ missing_libatomic_ops=true ])
dnl Note: "syntax error near unexpected token ATOMIC_OPS" reported by configure
dnl means Autotools pkg.m4 file was not found during aclocal.m4 generation;
dnl in this case, most probably, you should run pkg-config once before running
dnl autogen.sh (autoreconf); alternatively, comment out the following 3 lines.
AS_IF([test x$missing_libatomic_ops = xtrue],
[ PKG_CHECK_MODULES([ATOMIC_OPS], [atomic_ops],
[ missing_libatomic_ops=false ], [ [] ]) ])
dnl Retry with AC_CHECK_HEADER if PKG_CHECK_MODULES failed.
AS_IF([test x$missing_libatomic_ops = xtrue],
[ AC_CHECK_HEADER([atomic_ops.h], [missing_libatomic_ops=false]) ])
AS_IF([test x$missing_libatomic_ops = xtrue],
[ AS_IF([test x"$with_libatomic_ops" != xcheck],
[ AC_MSG_ERROR([An external libatomic_ops was not found]) ])
with_libatomic_ops=no ])
# If we have neither an external or an internal version, offer a useful hint
# and exit.
AS_IF([test x"$with_libatomic_ops" = xno -a ! -e "$srcdir/libatomic_ops"],
AS_IF([test x"$with_libatomic_ops" = xno \
-a ! -e "$srcdir/libatomic_ops/src/atomic_ops.h"],
[ AC_MSG_ERROR([libatomic_ops is required. You can either install it on
your system, or fetch and unpack a recent version into the
source directory and link or rename it to libatomic_ops.]) ])
@ -927,7 +1028,8 @@ AS_IF([test x"$with_libatomic_ops" = xno -a ! -e "$srcdir/libatomic_ops"],
# Finally, emit the definitions for bundled or external AO.
AC_MSG_CHECKING([which libatomic_ops to use])
AS_IF([test x"$with_libatomic_ops" != xno],
[ AC_MSG_RESULT([external]) ],
[ AS_IF([test x"$THREADS" != xnone],
[ AC_MSG_RESULT([external]) ], [ AC_MSG_RESULT([none]) ]) ],
[ AC_MSG_RESULT([internal])
ATOMIC_OPS_CFLAGS='-I$(top_builddir)/libatomic_ops/src -I$(top_srcdir)/libatomic_ops/src'
ATOMIC_OPS_LIBS=""

View file

@ -1,8 +1,14 @@
## This file is processed with automake.
# Info (current:revision:age) for the Libtool versioning system.
# These numbers should be updated at most once just before the release,
# and, optionally, at most once during the development (after the release).
LIBCORD_VER_INFO = 4:1:3
lib_LTLIBRARIES += libcord.la
libcord_la_LIBADD = $(top_builddir)/libgc.la
libcord_la_LDFLAGS = -version-info 1:3:0 -no-undefined
libcord_la_LDFLAGS = -version-info $(LIBCORD_VER_INFO) -no-undefined
libcord_la_CPPFLAGS = $(AM_CPPFLAGS)
libcord_la_SOURCES = \

View file

@ -37,7 +37,7 @@ typedef void (* oom_fn)(void);
oom_fn CORD_oom_fn = (oom_fn) 0;
# define OUT_OF_MEMORY { if (CORD_oom_fn != (oom_fn) 0) (*CORD_oom_fn)(); \
ABORT("Out of memory\n"); }
ABORT("Out of memory"); }
# define ABORT(msg) { fprintf(stderr, "%s\n", msg); abort(); }
typedef unsigned long word;
@ -126,14 +126,14 @@ void CORD_dump_inner(CORD x, unsigned n)
register struct Concatenation * conc =
&(((CordRep *)x) -> concatenation);
printf("Concatenation: %p (len: %d, depth: %d)\n",
x, (int)(conc -> len), (int)(conc -> depth));
(void *)x, (int)(conc -> len), (int)(conc -> depth));
CORD_dump_inner(conc -> left, n+1);
CORD_dump_inner(conc -> right, n+1);
} else /* function */{
register struct Function * func =
&(((CordRep *)x) -> function);
if (IS_SUBSTR(x)) printf("(Substring) ");
printf("Function: %p (len: %d): ", x, (int)(func -> len));
printf("Function: %p (len: %d): ", (void *)x, (int)(func -> len));
for (i = 0; i < 20 && i < func -> len; i++) {
putchar((*(func -> fn))(i, func -> client_data));
}
@ -175,13 +175,14 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
register CORD right;
register CORD left;
register char * new_right;
register size_t right_len;
lenx = LEN(x);
if (leny <= SHORT_LIMIT/2
&& IS_CONCATENATION(x)
&& CORD_IS_STRING(right = ((CordRep *)x) -> concatenation.right)) {
size_t right_len;
/* Merge y into right part of x. */
if (!CORD_IS_STRING(left = ((CordRep *)x) -> concatenation.left)) {
right_len = lenx - LEN(left);
@ -220,11 +221,15 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
result = GC_NEW(struct Concatenation);
if (result == 0) OUT_OF_MEMORY;
result->header = CONCAT_HDR;
result->depth = depth;
if (lenx <= MAX_LEFT_LEN) result->left_len = lenx;
result->len = result_len;
result->depth = (char)depth;
if (lenx <= MAX_LEFT_LEN)
result->left_len = (unsigned char)lenx;
result->len = (word)result_len;
result->left = x;
result->right = y;
GC_END_STUBBORN_CHANGE(result);
GC_reachable_here(x);
GC_reachable_here(y);
if (depth >= MAX_DEPTH) {
return(CORD_balance((CORD)result));
} else {
@ -261,11 +266,15 @@ CORD CORD_cat(CORD x, CORD y)
result = GC_NEW(struct Concatenation);
if (result == 0) OUT_OF_MEMORY;
result->header = CONCAT_HDR;
result->depth = depth;
if (lenx <= MAX_LEFT_LEN) result->left_len = lenx;
result->len = result_len;
result->depth = (char)depth;
if (lenx <= MAX_LEFT_LEN)
result->left_len = (unsigned char)lenx;
result->len = (word)result_len;
result->left = x;
result->right = y;
GC_END_STUBBORN_CHANGE(result);
GC_reachable_here(x);
GC_reachable_here(y);
if (depth >= MAX_DEPTH) {
return(CORD_balance((CORD)result));
} else {
@ -275,18 +284,17 @@ CORD CORD_cat(CORD x, CORD y)
}
CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len)
static CordRep *CORD_from_fn_inner(CORD_fn fn, void * client_data, size_t len)
{
if (len <= 0) return(0);
if (len == 0) return(0);
if (len <= SHORT_LIMIT) {
register char * result;
register size_t i;
char buf[SHORT_LIMIT+1];
register char c;
for (i = 0; i < len; i++) {
c = (*fn)(i, client_data);
char c = (*fn)(i, client_data);
if (c == '\0') goto gen_case;
buf[i] = c;
}
@ -295,7 +303,7 @@ CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len)
if (result == 0) OUT_OF_MEMORY;
memcpy(result, buf, len);
result[len] = '\0';
return((CORD) result);
return (CordRep *)result;
}
gen_case:
{
@ -305,13 +313,20 @@ CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len)
if (result == 0) OUT_OF_MEMORY;
result->header = FN_HDR;
/* depth is already 0 */
result->len = len;
result->len = (word)len;
result->fn = fn;
result->client_data = client_data;
return((CORD) result);
GC_END_STUBBORN_CHANGE(result);
GC_reachable_here(client_data);
return (CordRep *)result;
}
}
CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len)
{
return (/* const */ CORD) CORD_from_fn_inner(fn, client_data, len);
}
size_t CORD_len(CORD x)
{
if (x == 0) {
@ -348,15 +363,17 @@ char CORD_apply_access_fn(size_t i, void * client_data)
CORD CORD_substr_closure(CORD x, size_t i, size_t n, CORD_fn f)
{
register struct substr_args * sa = GC_NEW(struct substr_args);
CORD result;
CordRep * result;
if (sa == 0) OUT_OF_MEMORY;
sa->sa_cord = (CordRep *)x;
sa->sa_index = i;
result = CORD_from_fn(f, (void *)sa, n);
if (result == CORD_EMPTY) return CORD_EMPTY; /* n == 0 */
((CordRep *)result) -> function.header = SUBSTR_HDR;
return (result);
GC_END_STUBBORN_CHANGE(sa);
GC_reachable_here(x);
result = CORD_from_fn_inner(f, (void *)sa, n);
if ((CORD)result != CORD_EMPTY && 0 == result -> function.null)
result -> function.header = SUBSTR_HDR;
return (CORD)result;
}
# define SUBSTR_LIMIT (10 * SHORT_LIMIT)
@ -430,12 +447,12 @@ CORD CORD_substr_checked(CORD x, size_t i, size_t n)
register struct Function * f = &(((CordRep *)x) -> function);
char buf[SUBSTR_LIMIT+1];
register char * p = buf;
register char c;
register int j;
register int lim = i + n;
register size_t j;
register size_t lim = i + n;
for (j = i; j < lim; j++) {
c = (*(f -> fn))(j, f -> client_data);
char c = (*(f -> fn))(j, f -> client_data);
if (c == '\0') {
return(CORD_substr_closure(x, i, n, CORD_apply_access_fn));
}
@ -454,9 +471,7 @@ CORD CORD_substr(CORD x, size_t i, size_t n)
{
register size_t len = CORD_len(x);
if (i >= len || n <= 0) return(0);
/* n < 0 is impossible in a correct C implementation, but */
/* quite possible under SunOS 4.X. */
if (i >= len || n == 0) return(0);
if (i + n > len) n = len - i;
return(CORD_substr_checked(x, i, n));
}
@ -521,10 +536,10 @@ int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data)
if (x == 0) return(0);
if (CORD_IS_STRING(x)) {
register const char *p = x + i;
register char c;
for(;;) {
c = *p;
char c = *p;
if (c == '\0') ABORT("2nd arg to CORD_riter4 too big");
if ((*f1)(c, client_data)) return(1);
if (p == x) break;
@ -601,18 +616,19 @@ typedef ForestElement Forest [ MAX_DEPTH ];
void CORD_init_min_len(void)
{
register int i;
register size_t last, previous, current;
size_t last, previous;
min_len[0] = previous = 1;
min_len[1] = last = 2;
for (i = 2; i < MAX_DEPTH; i++) {
current = last + previous;
size_t current = last + previous;
if (current < last) /* overflow */ current = last;
min_len[i] = current;
previous = last;
last = current;
}
CORD_max_len = last - 1;
CORD_max_len = (int)last - 1;
min_len_init = 1;
}
@ -869,7 +885,7 @@ void CORD__prev(register CORD_pos p)
char CORD_pos_fetch(register CORD_pos p)
{
if (p[0].cur_start <= p[0].cur_pos && p[0].cur_pos < p[0].cur_end) {
if (p[0].cur_end != 0) {
return(p[0].cur_leaf[p[0].cur_pos - p[0].cur_start]);
} else {
return(CORD__pos_fetch(p));
@ -878,7 +894,7 @@ char CORD_pos_fetch(register CORD_pos p)
void CORD_next(CORD_pos p)
{
if (p[0].cur_pos < p[0].cur_end - 1) {
if (p[0].cur_pos + 1 < p[0].cur_end) {
p[0].cur_pos++;
} else {
CORD__next(p);

View file

@ -30,9 +30,12 @@
#include "cord.h"
#include "ec.h"
#include <stdio.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gc.h"
#define CONV_SPEC_LEN 50 /* Maximum length of a single */
@ -41,6 +44,11 @@
/* conversion with default */
/* width and prec. */
#define OUT_OF_MEMORY do { \
if (CORD_oom_fn != 0) (*CORD_oom_fn)(); \
fprintf(stderr, "Out of memory\n"); \
abort(); \
} while (0)
static int ec_len(CORD_ec x)
{
@ -84,7 +92,9 @@ static int extract_conv_spec(CORD_pos source, char *buf,
if (!saw_number) {
/* Zero fill flag; ignore */
break;
} /* otherwise fall through: */
}
current_number *= 10;
break;
case '1':
case '2':
case '3':
@ -164,6 +174,20 @@ static int extract_conv_spec(CORD_pos source, char *buf,
return(result);
}
#if defined(DJGPP) || defined(__STRICT_ANSI__)
/* vsnprintf is missing in DJGPP (v2.0.3) */
# define GC_VSNPRINTF(buf, bufsz, format, args) vsprintf(buf, format, args)
#elif defined(_MSC_VER)
# ifdef MSWINCE
/* _vsnprintf is deprecated in WinCE */
# define GC_VSNPRINTF StringCchVPrintfA
# else
# define GC_VSNPRINTF _vsnprintf
# endif
#else
# define GC_VSNPRINTF vsnprintf
#endif
int CORD_vsprintf(CORD * out, CORD format, va_list args)
{
CORD_ec result;
@ -220,11 +244,12 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
if (prec != NONE && len > (size_t)prec) {
if (prec < 0) return(-1);
arg = CORD_substr(arg, 0, prec);
len = prec;
len = (unsigned)prec;
}
if (width != NONE && len < (size_t)width) {
char * blanks = GC_MALLOC_ATOMIC(width-len+1);
if (NULL == blanks) OUT_OF_MEMORY;
memset(blanks, ' ', width-len);
blanks[width-len] = '\0';
if (left_adj) {
@ -249,7 +274,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
char * str = va_arg(args, char *);
register char c;
while ((c = *str++)) {
while ((c = *str++) != '\0') {
CORD_ec_append(result, c);
}
goto done;
@ -263,16 +288,17 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
register char * buf;
va_list vsprintf_args;
int max_size = 0;
int res;
# ifdef __va_copy
int res = 0;
# if defined(CPPCHECK)
va_copy(vsprintf_args, args);
# elif defined(__va_copy)
__va_copy(vsprintf_args, args);
# else
# if defined(__GNUC__) && !defined(__DJGPP__) \
# elif defined(__GNUC__) && !defined(__DJGPP__) \
&& !defined(__EMX__) /* and probably in other cases */
va_copy(vsprintf_args, args);
# else
vsprintf_args = args;
# endif
va_copy(vsprintf_args, args);
# else
vsprintf_args = args;
# endif
if (width == VARIABLE) width = va_arg(args, int);
if (prec == VARIABLE) prec = va_arg(args, int);
@ -281,6 +307,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
max_size += CONV_RESULT_LEN;
if (max_size >= CORD_BUFSZ) {
buf = GC_MALLOC_ATOMIC(max_size + 1);
if (NULL == buf) OUT_OF_MEMORY;
} else {
if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
< max_size) {
@ -298,7 +325,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
case 'c':
if (long_arg <= 0) {
(void) va_arg(args, int);
} else if (long_arg > 0) {
} else /* long_arg > 0 */ {
(void) va_arg(args, long);
}
break;
@ -314,15 +341,12 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
(void) va_arg(args, double);
break;
default:
# if defined(__va_copy) \
|| (defined(__GNUC__) && !defined(__DJGPP__) \
&& !defined(__EMX__))
va_end(vsprintf_args);
# endif
return(-1);
res = -1;
}
res = vsprintf(buf, conv_spec, vsprintf_args);
# if defined(__va_copy) \
if (0 == res)
res = GC_VSNPRINTF(buf, max_size + 1, conv_spec,
vsprintf_args);
# if defined(CPPCHECK) || defined(__va_copy) \
|| (defined(__GNUC__) && !defined(__DJGPP__) \
&& !defined(__EMX__))
va_end(vsprintf_args);
@ -337,7 +361,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
if (buf != result[0].ec_bufptr) {
register char c;
while ((c = *buf++)) {
while ((c = *buf++) != '\0') {
CORD_ec_append(result, c);
}
} else {

View file

@ -59,8 +59,8 @@
typedef void (* oom_fn)(void);
# define OUT_OF_MEMORY { if (CORD_oom_fn != (oom_fn) 0) (*CORD_oom_fn)(); \
ABORT("Out of memory\n"); }
# define OUT_OF_MEMORY { if (CORD_oom_fn != (oom_fn) 0) (*CORD_oom_fn)(); \
ABORT("Out of memory"); }
# define ABORT(msg) { fprintf(stderr, "%s\n", msg); abort(); }
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
@ -136,22 +136,23 @@ int CORD_batched_fill_proc(const char * s, void * client_data)
}
/* Fill buf with len characters starting at i. */
/* Assumes len characters are available. */
void CORD_fill_buf(CORD x, size_t i, size_t len, char * buf)
/* Assumes len characters are available in buf. */
/* Return 1 if buf is filled fully (and len is */
/* non-zero), 0 otherwise. */
int CORD_fill_buf(CORD x, size_t i, size_t len, char * buf)
{
CORD_fill_data fd;
fd.len = len;
fd.buf = buf;
fd.count = 0;
(void)CORD_iter5(x, i, CORD_fill_proc, CORD_batched_fill_proc, &fd);
return CORD_iter5(x, i, CORD_fill_proc, CORD_batched_fill_proc, &fd);
}
int CORD_cmp(CORD x, CORD y)
{
CORD_pos xpos;
CORD_pos ypos;
register size_t avail, yavail;
if (y == CORD_EMPTY) return(x != CORD_EMPTY);
if (x == CORD_EMPTY) return(-1);
@ -159,6 +160,8 @@ int CORD_cmp(CORD x, CORD y)
CORD_set_pos(xpos, x, 0);
CORD_set_pos(ypos, y, 0);
for(;;) {
size_t avail, yavail;
if (!CORD_pos_valid(xpos)) {
if (CORD_pos_valid(ypos)) {
return(-1);
@ -169,8 +172,9 @@ int CORD_cmp(CORD x, CORD y)
if (!CORD_pos_valid(ypos)) {
return(1);
}
if ((avail = CORD_pos_chars_left(xpos)) <= 0
|| (yavail = CORD_pos_chars_left(ypos)) <= 0) {
avail = CORD_pos_chars_left(xpos);
if (avail == 0
|| (yavail = CORD_pos_chars_left(ypos)) == 0) {
register char xcurrent = CORD_pos_fetch(xpos);
register char ycurrent = CORD_pos_fetch(ypos);
if (xcurrent != ycurrent) return(xcurrent - ycurrent);
@ -195,11 +199,12 @@ int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, size_t len)
CORD_pos xpos;
CORD_pos ypos;
register size_t count;
register long avail, yavail;
CORD_set_pos(xpos, x, x_start);
CORD_set_pos(ypos, y, y_start);
for(count = 0; count < len;) {
long avail, yavail;
if (!CORD_pos_valid(xpos)) {
if (CORD_pos_valid(ypos)) {
return(-1);
@ -224,7 +229,8 @@ int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, size_t len)
if (avail > yavail) avail = yavail;
count += avail;
if (count > len) avail -= (count - len);
if (count > len)
avail -= (long)(count - len);
result = strncmp(CORD_pos_cur_char_addr(xpos),
CORD_pos_cur_char_addr(ypos), (size_t)avail);
if (result != 0) return(result);
@ -241,7 +247,8 @@ char * CORD_to_char_star(CORD x)
char * result = GC_MALLOC_ATOMIC(len + 1);
if (result == 0) OUT_OF_MEMORY;
CORD_fill_buf(x, 0, len, result);
if (len > 0 && CORD_fill_buf(x, 0, len, result) != 1)
ABORT("CORD_fill_buf malfunction");
result[len] = '\0';
return(result);
}
@ -341,7 +348,7 @@ size_t CORD_chr(CORD x, size_t i, int c)
chr_data d;
d.pos = i;
d.target = c;
d.target = (char)c;
if (CORD_iter5(x, i, CORD_chr_proc, CORD_batched_chr_proc, &d)) {
return(d.pos);
} else {
@ -354,7 +361,7 @@ size_t CORD_rchr(CORD x, size_t i, int c)
chr_data d;
d.pos = i;
d.target = c;
d.target = (char)c;
if (CORD_riter4(x, i, CORD_rchr_proc, &d)) {
return(d.pos);
} else {
@ -428,6 +435,7 @@ void CORD_ec_flush_buf(CORD_ec x)
if (len == 0) return;
s = GC_MALLOC_ATOMIC(len+1);
if (NULL == s) OUT_OF_MEMORY;
memcpy(s, x[0].ec_buf, len);
s[len] = '\0';
x[0].ec_cord = CORD_cat_char_star(x[0].ec_cord, s, len);
@ -442,23 +450,22 @@ void CORD_ec_append_cord(CORD_ec x, CORD s)
char CORD_nul_func(size_t i CORD_ATTR_UNUSED, void * client_data)
{
return((char)(unsigned long)client_data);
return (char)(GC_word)client_data;
}
CORD CORD_chars(char c, size_t i)
{
return(CORD_from_fn(CORD_nul_func, (void *)(unsigned long)c, i));
return CORD_from_fn(CORD_nul_func, (void *)(GC_word)(unsigned char)c, i);
}
CORD CORD_from_file_eager(FILE * f)
{
register int c;
CORD_ec ecord;
CORD_ec_init(ecord);
for(;;) {
c = getc(f);
int c = getc(f);
if (c == 0) {
/* Append the right number of NULs */
/* Note that any string of NULs is represented in 4 words, */
@ -470,7 +477,7 @@ CORD CORD_from_file_eager(FILE * f)
ecord[0].ec_cord = CORD_cat(ecord[0].ec_cord, CORD_nul(count));
}
if (c == EOF) break;
CORD_ec_append(ecord, c);
CORD_ec_append(ecord, (char)c);
}
(void) fclose(f);
return(CORD_balance(CORD_ec_to_cord(ecord)));
@ -519,17 +526,17 @@ typedef struct {
} refill_data;
/* Executed with allocation lock. */
static char refill_cache(refill_data * client_data)
static void * GC_CALLBACK refill_cache(void * client_data)
{
register lf_state * state = client_data -> state;
register size_t file_pos = client_data -> file_pos;
register lf_state * state = ((refill_data *)client_data) -> state;
register size_t file_pos = ((refill_data *)client_data) -> file_pos;
FILE *f = state -> lf_file;
size_t line_start = LINE_START(file_pos);
size_t line_no = DIV_LINE_SZ(MOD_CACHE_SZ(file_pos));
cache_line * new_cache = client_data -> new_cache;
cache_line * new_cache = ((refill_data *)client_data) -> new_cache;
if (line_start != state -> lf_current
&& fseek(f, line_start, SEEK_SET) != 0) {
&& fseek(f, (long)line_start, SEEK_SET) != 0) {
ABORT("fseek failed");
}
if (fread(new_cache -> data, sizeof(char), LINE_SZ, f)
@ -539,8 +546,10 @@ static char refill_cache(refill_data * client_data)
new_cache -> tag = DIV_LINE_SZ(file_pos);
/* Store barrier goes here. */
ATOMIC_WRITE(state -> lf_cache[line_no], new_cache);
GC_END_STUBBORN_CHANGE((/* no volatile */ void *)(state -> lf_cache
+ line_no));
state -> lf_current = line_start + LINE_SZ;
return(new_cache->data[MOD_LINE_SZ(file_pos)]);
return (void *)((GC_word)new_cache->data[MOD_LINE_SZ(file_pos)]);
}
char CORD_lf_func(size_t i, void * client_data)
@ -558,8 +567,7 @@ char CORD_lf_func(size_t i, void * client_data)
rd.file_pos = i;
rd.new_cache = GC_NEW_ATOMIC(cache_line);
if (rd.new_cache == 0) OUT_OF_MEMORY;
return((char)(GC_word)
GC_call_with_alloc_lock((GC_fn_type) refill_cache, &rd));
return (char)((GC_word)GC_call_with_alloc_lock(refill_cache, &rd));
}
return(cl -> data[MOD_LINE_SZ(i)]);
}
@ -585,11 +593,10 @@ CORD CORD_from_file_lazy_inner(FILE * f, size_t len)
/* world is multi-threaded. */
char buf[1];
if (fread(buf, 1, 1, f) > 1) {
/* Just to suppress "unused result" compiler warning. */
ABORT("fread unexpected result");
if (fread(buf, 1, 1, f) > 1
|| fseek(f, 0l, SEEK_SET) != 0) {
ABORT("Bad f argument or I/O failure");
}
rewind(f);
}
state -> lf_file = f;
for (i = 0; i < CACHE_SZ/LINE_SZ; i++) {
@ -604,13 +611,11 @@ CORD CORD_from_file_lazy(FILE * f)
{
register long len;
if (fseek(f, 0l, SEEK_END) != 0) {
ABORT("Bad fd argument - fseek failed");
if (fseek(f, 0l, SEEK_END) != 0
|| (len = ftell(f)) < 0
|| fseek(f, 0l, SEEK_SET) != 0) {
ABORT("Bad f argument or I/O failure");
}
if ((len = ftell(f)) < 0) {
ABORT("Bad fd argument - ftell failed");
}
rewind(f);
return(CORD_from_file_lazy_inner(f, (size_t)len));
}
@ -620,13 +625,11 @@ CORD CORD_from_file(FILE * f)
{
register long len;
if (fseek(f, 0l, SEEK_END) != 0) {
ABORT("Bad fd argument - fseek failed");
if (fseek(f, 0l, SEEK_END) != 0
|| (len = ftell(f)) < 0
|| fseek(f, 0l, SEEK_SET) != 0) {
ABORT("Bad f argument or I/O failure");
}
if ((len = ftell(f)) < 0) {
ABORT("Bad fd argument - ftell failed");
}
rewind(f);
if (len < LAZY_THRESHOLD) {
return(CORD_from_file_eager(f));
} else {

View file

@ -13,15 +13,28 @@
# include "gc.h" /* For GC_INIT() only */
# include "cord.h"
# include <stdarg.h>
# include <string.h>
# include <stdio.h>
# include <stdlib.h>
/* This is a very incomplete test of the cord package. It knows about */
/* a few internals of the package (e.g. when C strings are returned) */
/* that real clients shouldn't rely on. */
/* that real clients shouldn't rely on. */
# define ABORT(string) \
{ int x = 0; fprintf(stderr, "FAILED: %s\n", string); x = 1 / x; abort(); }
{ fprintf(stderr, "FAILED: %s\n", string); abort(); }
#if defined(CPPCHECK)
# undef CORD_iter
# undef CORD_next
# undef CORD_pos_fetch
# undef CORD_pos_to_cord
# undef CORD_pos_to_index
# undef CORD_pos_valid
# undef CORD_prev
#endif
int count;
@ -53,7 +66,6 @@ void test_basics(void)
{
CORD x = CORD_from_char_star("ab");
register int i;
char c;
CORD y;
CORD_pos p;
@ -114,11 +126,22 @@ void test_basics(void)
i = 0;
CORD_set_pos(p, y, i);
while(CORD_pos_valid(p)) {
c = CORD_pos_fetch(p);
char c = CORD_pos_fetch(p);
if(c != i) ABORT("Traversal of function node failed");
CORD_next(p); i++;
CORD_next(p);
i++;
}
if (i != 13) ABORT("Bad apparent length for function node");
# if defined(CPPCHECK)
/* TODO: Actually test these functions. */
CORD_prev(p);
(void)CORD_pos_to_cord(p);
(void)CORD_pos_to_index(p);
(void)CORD_iter(CORD_EMPTY, test_fn, NULL);
(void)CORD_riter(CORD_EMPTY, test_fn, NULL);
CORD_dump(y);
# endif
}
void test_extras(void)
@ -128,7 +151,7 @@ void test_extras(void)
register int i;
CORD y = "abcdefghijklmnopqrstuvwxyz0123456789";
CORD x = "{}";
CORD w, z;
CORD u, w, z;
FILE *f;
FILE *f1a, *f1b, *f2;
@ -180,7 +203,9 @@ void test_extras(void)
ABORT("file substr wrong");
if (strcmp(CORD_to_char_star(CORD_substr(w, 1000*36, 36)), y) != 0)
ABORT("char * file substr wrong");
if (strcmp(CORD_substr(w, 1000*36, 2), "ab") != 0)
u = CORD_substr(w, 1000*36, 2);
if (!u) ABORT("CORD_substr returned NULL");
if (strcmp(u, "ab") != 0)
ABORT("short file substr wrong");
if (CORD_str(x,1,"9a") != 35) ABORT("CORD_str failed 1");
if (CORD_str(x,0,"9abcdefghijk") != 35) ABORT("CORD_str failed 2");
@ -197,13 +222,35 @@ void test_extras(void)
if (remove(FNAME1) != 0) {
/* On some systems, e.g. OS2, this may fail if f1 is still open. */
/* But we cannot call fclose as it might lead to double close. */
fprintf(stderr, "WARNING: remove(FNAME1) failed\n");
fprintf(stderr, "WARNING: remove failed: " FNAME1 "\n");
}
if (remove(FNAME2) != 0) {
fprintf(stderr, "WARNING: remove(FNAME2) failed\n");
fprintf(stderr, "WARNING: remove failed: " FNAME2 "\n");
}
}
int wrap_vprintf(CORD format, ...)
{
va_list args;
int result;
va_start(args, format);
result = CORD_vprintf(format, args);
va_end(args);
return result;
}
int wrap_vfprintf(FILE * f, CORD format, ...)
{
va_list args;
int result;
va_start(args, format);
result = CORD_vfprintf(f, format, args);
va_end(args);
return result;
}
#if defined(__DJGPP__) || defined(__STRICT_ANSI__)
/* snprintf is missing in DJGPP (v2.0.3) */
#else
@ -249,6 +296,10 @@ void test_printf(void)
# endif
result2[sizeof(result2) - 1] = '\0';
if (CORD_cmp(result, result2) != 0)ABORT("CORD_sprintf goofed 5");
/* TODO: Better test CORD_[v][f]printf. */
(void)CORD_printf(CORD_EMPTY);
(void)wrap_vfprintf(stdout, CORD_EMPTY);
(void)wrap_vprintf(CORD_EMPTY);
}
int main(void)

View file

@ -27,13 +27,15 @@
*/
#include <stdio.h>
#include <stdlib.h> /* for exit() */
#include "gc.h"
#include "cord.h"
#ifdef THINK_C
#define MACINTOSH
#include <ctype.h>
#endif
#include <ctype.h>
#if (defined(__BORLANDC__) || defined(__CYGWIN__)) && !defined(WIN32)
/* If this is DOS or win16, we'll fail anyway. */
@ -63,10 +65,16 @@
# define COLS 80
#else
# include <curses.h>
# include <unistd.h> /* for sleep() */
# define de_error(s) { fprintf(stderr, s); sleep(2); }
#endif
#include "de_cmds.h"
#define OUT_OF_MEMORY do { \
fprintf(stderr, "Out of memory\n"); \
exit(3); \
} while (0)
/* List of line number to position mappings, in descending order. */
/* There may be holes. */
typedef struct LineMapRep {
@ -125,21 +133,30 @@ void prune_map(void)
do {
current_map_size++;
if (map -> line < start_line - LINES && map -> previous != 0) {
map -> previous = map -> previous -> previous;
line_map pred = map -> previous -> previous;
map -> previous = pred;
GC_END_STUBBORN_CHANGE(map);
GC_reachable_here(pred);
}
map = map -> previous;
} while (map != 0);
}
/* Add mapping entry */
void add_map(int line, size_t pos)
void add_map(int line_arg, size_t pos)
{
line_map new_map = GC_NEW(struct LineMapRep);
line_map cur_map;
if (NULL == new_map) OUT_OF_MEMORY;
if (current_map_size >= MAX_MAP_SIZE) prune_map();
new_map -> line = line;
new_map -> line = line_arg;
new_map -> pos = pos;
new_map -> previous = current_map;
cur_map = current_map;
new_map -> previous = cur_map;
GC_END_STUBBORN_CHANGE(new_map);
GC_reachable_here(cur_map);
current_map = new_map;
current_map_size++;
}
@ -155,7 +172,6 @@ size_t line_pos(int i, int *c)
{
int j;
size_t cur;
size_t next;
line_map map = current_map;
while (map -> line > i) map = map -> previous;
@ -167,10 +183,11 @@ size_t line_pos(int i, int *c)
if (++j > current_map -> line) add_map(j, cur);
}
if (c != 0) {
next = CORD_chr(current, cur, '\n');
size_t next = CORD_chr(current, cur, '\n');
if (next == CORD_NOT_FOUND) next = current_len - 1;
if (next < cur + *c) {
*c = next - cur;
*c = (int)(next - cur);
}
cur += *c;
}
@ -181,10 +198,15 @@ void add_hist(CORD s)
{
history new_file = GC_NEW(struct HistoryRep);
if (NULL == new_file) OUT_OF_MEMORY;
new_file -> file_contents = current = s;
current_len = CORD_len(s);
new_file -> previous = now;
if (now != 0) now -> map = current_map;
GC_END_STUBBORN_CHANGE(new_file);
if (now != NULL) {
now -> map = current_map;
GC_END_STUBBORN_CHANGE(now);
}
now = new_file;
}
@ -206,7 +228,6 @@ int screen_size = 0;
/* terribly appropriate for tabs. */
void replace_line(int i, CORD s)
{
register int c;
CORD_pos p;
# if !defined(MACINTOSH)
size_t len = CORD_len(s);
@ -215,10 +236,11 @@ void replace_line(int i, CORD s)
if (screen == 0 || LINES > screen_size) {
screen_size = LINES;
screen = (CORD *)GC_MALLOC(screen_size * sizeof(CORD));
if (NULL == screen) OUT_OF_MEMORY;
}
# if !defined(MACINTOSH)
/* A gross workaround for an apparent curses bug: */
if (i == LINES-1 && len == COLS) {
if (i == LINES-1 && len == (unsigned)COLS) {
s = CORD_substr(s, 0, len - 1);
}
# endif
@ -226,7 +248,8 @@ void replace_line(int i, CORD s)
move(i, 0); clrtoeol(); move(i,0);
CORD_FOR (p, s) {
c = CORD_pos_fetch(p) & 0x7f;
int c = CORD_pos_fetch(p) & 0x7f;
if (iscntrl(c)) {
standout(); addch(c + 0x40); standend();
} else {
@ -234,6 +257,8 @@ void replace_line(int i, CORD s)
}
}
screen[i] = s;
GC_END_STUBBORN_CHANGE(screen + i);
GC_reachable_here(s);
}
}
#else
@ -336,7 +361,8 @@ void fix_pos(void)
{
int my_col = col;
if ((size_t)line > current_len) line = current_len;
if ((size_t)line > current_len)
line = (int)current_len;
file_pos = line_pos(line, &my_col);
if (file_pos == CORD_NOT_FOUND) {
for (line = current_map -> line, file_pos = current_map -> pos;
@ -417,7 +443,7 @@ void do_command(int c)
if (file_pos > new_pos) break;
line++;
}
col = new_pos - line_pos(line, 0);
col = (int)(new_pos - line_pos(line, 0));
file_pos = new_pos;
fix_cursor();
} else {
@ -448,7 +474,8 @@ void do_command(int c)
locate_mode = 1;
break;
case TOP:
line = col = file_pos = 0;
line = col = 0;
file_pos = 0;
break;
case UP:
if (line != 0) {
@ -479,7 +506,7 @@ void do_command(int c)
break;
}
col--; file_pos--;
/* fall through: */
/* FALLTHRU */
case DEL:
if (file_pos == current_len-1) break;
/* Can't delete trailing newline */
@ -541,9 +568,11 @@ void generic_init(void)
if ((f = fopen(arg_file_name, "rb")) == NULL) {
initial = "\n";
} else {
size_t len;
initial = CORD_from_file(f);
if (initial == CORD_EMPTY
|| CORD_fetch(initial, CORD_len(initial)-1) != '\n') {
len = CORD_len(initial);
if (0 == len || CORD_fetch(initial, len - 1) != '\n') {
initial = CORD_cat(initial, "\n");
}
}
@ -551,50 +580,51 @@ void generic_init(void)
add_hist(initial);
now -> map = current_map;
now -> previous = now; /* Can't back up further: beginning of the world */
GC_END_STUBBORN_CHANGE(now);
need_redisplay = ALL;
fix_cursor();
}
#ifndef WIN32
main(argc, argv)
int argc;
char ** argv;
int main(int argc, char **argv)
{
int c;
void *buf;
#if defined(MACINTOSH)
# if defined(MACINTOSH)
console_options.title = "\pDumb Editor";
cshow(stdout);
argc = ccommand(&argv);
#endif
# endif
GC_INIT();
if (argc != 2) goto usage;
if (argc != 2) {
fprintf(stderr, "Usage: %s file\n", argv[0]);
fprintf(stderr, "Cursor keys: ^B(left) ^F(right) ^P(up) ^N(down)\n");
fprintf(stderr, "Undo: ^U Write to <file>.new: ^W");
fprintf(stderr, "Quit:^D Repeat count: ^R[n]\n");
fprintf(stderr, "Top: ^T Locate (search, find): ^L text ^L\n");
exit(1);
}
arg_file_name = argv[1];
setvbuf(stdout, GC_MALLOC_ATOMIC(8192), _IOFBF, 8192);
buf = GC_MALLOC_ATOMIC(8192);
if (NULL == buf) OUT_OF_MEMORY;
setvbuf(stdout, buf, _IOFBF, 8192);
initscr();
noecho(); nonl(); cbreak();
generic_init();
while ((c = getchar()) != QUIT) {
if (c == EOF) break;
do_command(c);
if (c == EOF) break;
do_command(c);
}
done:
move(LINES-1, 0);
clrtoeol();
refresh();
nl();
echo();
endwin();
exit(0);
usage:
fprintf(stderr, "Usage: %s file\n", argv[0]);
fprintf(stderr, "Cursor keys: ^B(left) ^F(right) ^P(up) ^N(down)\n");
fprintf(stderr, "Undo: ^U Write to <file>.new: ^W");
fprintf(stderr, "Quit:^D Repeat count: ^R[n]\n");
fprintf(stderr, "Top: ^T Locate (search, find): ^L text ^L\n");
exit(1);
return 0;
}
#endif /* !WIN32 */

View file

@ -46,9 +46,9 @@ int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
WNDCLASS wndclass;
HANDLE hAccel;
# ifdef THREAD_LOCAL_ALLOC
GC_INIT(); /* Required if GC is built with THREAD_LOCAL_ALLOC */
/* Always safe, but this is used as a GC test. */
GC_INIT();
# if defined(CPPCHECK)
GC_noop1((GC_word)&WinMain);
# endif
if (!hPrevInstance)
@ -65,11 +65,7 @@ int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
wndclass.lpszClassName = szAppName;
if (RegisterClass (&wndclass) == 0) {
char buf[50];
sprintf(buf, "RegisterClass: error code: 0x%X",
(unsigned)GetLastError());
de_error(buf);
de_error("RegisterClass error");
return(0);
}
}
@ -102,11 +98,7 @@ int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
NULL, /* Window class menu */
hInstance, NULL);
if (hwnd == NULL) {
char buf[50];
sprintf(buf, "CreateWindow: error code: 0x%X",
(unsigned)GetLastError());
de_error(buf);
de_error("CreateWindow error");
return(0);
}
@ -122,7 +114,7 @@ int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
DispatchMessage (&msg);
}
}
return msg.wParam;
return (int)msg.wParam;
}
/* Return the argument with all control characters replaced by blanks. */
@ -131,6 +123,7 @@ char * plain_chars(char * text, size_t len)
char * result = GC_MALLOC_ATOMIC(len + 1);
register size_t i;
if (NULL == result) return NULL;
for (i = 0; i < len; i++) {
if (iscntrl(((unsigned char *)text)[i])) {
result[i] = ' ';
@ -149,6 +142,7 @@ char * control_chars(char * text, size_t len)
char * result = GC_MALLOC_ATOMIC(len + 1);
register size_t i;
if (NULL == result) return NULL;
for (i = 0; i < len; i++) {
if (iscntrl(((unsigned char *)text)[i])) {
result[i] = text[i] + 0x40;
@ -163,9 +157,9 @@ char * control_chars(char * text, size_t len)
int char_width;
int char_height;
void get_line_rect(int line, int win_width, RECT * rectp)
void get_line_rect(int line_arg, int win_width, RECT * rectp)
{
rectp -> top = line * char_height;
rectp -> top = line_arg * (LONG)char_height;
rectp -> bottom = rectp->top + char_height;
rectp -> left = 0;
rectp -> right = win_width;
@ -204,7 +198,7 @@ INT_PTR CALLBACK AboutBoxCallback( HWND hDlg, UINT message,
return FALSE;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
LRESULT CALLBACK WndProc (HWND hwnd_arg, UINT message,
WPARAM wParam, LPARAM lParam)
{
static HANDLE hInstance;
@ -221,13 +215,13 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
{
case WM_CREATE:
hInstance = ( (LPCREATESTRUCT) lParam)->hInstance;
dc = GetDC(hwnd);
dc = GetDC(hwnd_arg);
SelectObject(dc, GetStockObject(SYSTEM_FIXED_FONT));
GetTextMetrics(dc, &tm);
ReleaseDC(hwnd, dc);
ReleaseDC(hwnd_arg, dc);
char_width = tm.tmAveCharWidth;
char_height = tm.tmHeight + tm.tmExternalLeading;
GetClientRect(hwnd, &client_area);
GetClientRect(hwnd_arg, &client_area);
COLS = (client_area.right - client_area.left)/char_width;
LINES = (client_area.bottom - client_area.top)/char_height;
generic_init();
@ -235,21 +229,21 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
case WM_CHAR:
if (wParam == QUIT) {
SendMessage( hwnd, WM_CLOSE, 0, 0L );
SendMessage(hwnd_arg, WM_CLOSE, 0, 0L);
} else {
do_command((int)wParam);
}
return(0);
case WM_SETFOCUS:
CreateCaret(hwnd, NULL, char_width, char_height);
ShowCaret(hwnd);
CreateCaret(hwnd_arg, NULL, char_width, char_height);
ShowCaret(hwnd_arg);
caret_visible = 1;
update_cursor();
return(0);
case WM_KILLFOCUS:
HideCaret(hwnd);
HideCaret(hwnd_arg);
DestroyCaret();
caret_visible = 0;
return(0);
@ -273,13 +267,13 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
} else {
switch(id) {
case IDM_FILEEXIT:
SendMessage( hwnd, WM_CLOSE, 0, 0L );
SendMessage(hwnd_arg, WM_CLOSE, 0, 0L);
return( 0 );
case IDM_HELPABOUT:
if( DialogBox( hInstance, TEXT("ABOUTBOX"),
hwnd, AboutBoxCallback ) )
InvalidateRect( hwnd, NULL, TRUE );
hwnd_arg, AboutBoxCallback ) )
InvalidateRect(hwnd_arg, NULL, TRUE);
return( 0 );
case IDM_HELPCONTENTS:
de_error(
@ -292,7 +286,7 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
break;
case WM_CLOSE:
DestroyWindow( hwnd );
DestroyWindow(hwnd_arg);
return 0;
case WM_DESTROY:
@ -301,8 +295,8 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
return 0;
case WM_PAINT:
dc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &client_area);
dc = BeginPaint(hwnd_arg, &ps);
GetClientRect(hwnd_arg, &client_area);
COLS = (client_area.right - client_area.left)/char_width;
LINES = (client_area.bottom - client_area.top)/char_height;
SelectObject(dc, GetStockObject(SYSTEM_FIXED_FONT));
@ -317,27 +311,32 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
char * blanks = CORD_to_char_star(CORD_chars(' ',
COLS - len));
char * control = control_chars(text, len);
if (NULL == plain || NULL == control)
de_error("Out of memory!");
# define RED RGB(255,0,0)
SetBkMode(dc, OPAQUE);
SetTextColor(dc, GetSysColor(COLOR_WINDOWTEXT));
TextOutA(dc, this_line.left, this_line.top,
plain, (int)len);
if (plain != NULL)
TextOutA(dc, this_line.left, this_line.top,
plain, (int)len);
TextOutA(dc, this_line.left + (int)len * char_width,
this_line.top,
blanks, (int)(COLS - len));
SetBkMode(dc, TRANSPARENT);
SetTextColor(dc, RED);
TextOutA(dc, this_line.left, this_line.top,
control, (int)strlen(control));
if (control != NULL)
TextOutA(dc, this_line.left, this_line.top,
control, (int)strlen(control));
}
}
EndPaint(hwnd, &ps);
EndPaint(hwnd_arg, &ps);
screen_was_painted = 1;
return 0;
}
return DefWindowProc (hwnd, message, wParam, lParam);
return DefWindowProc(hwnd_arg, message, wParam, lParam);
}
int last_col;
@ -359,11 +358,11 @@ void update_cursor(void)
void invalidate_line(int i)
{
RECT line;
RECT line_r;
if (!screen_was_painted) return;
/* Invalidating a rectangle before painting seems result in a */
/* major performance problem. */
get_line_rect(i, COLS*char_width, &line);
InvalidateRect(hwnd, &line, FALSE);
get_line_rect(i, COLS*char_width, &line_r);
InvalidateRect(hwnd, &line_r, FALSE);
}

View file

@ -44,11 +44,7 @@
/* Windows UI stuff */
LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
UINT wParam, LONG lParam);
LRESULT CALLBACK AboutBox( HWND hDlg, UINT message,
UINT wParam, LONG lParam );
WPARAM wParam, LPARAM lParam);
/* Screen dimensions. Maintained by de_win.c. */
extern int LINES;

View file

@ -12,52 +12,49 @@
#include "de_cmds.h"
#include "de_win.h"
ABOUTBOX DIALOG 19, 21, 163, 47
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About Demonstration Text Editor"
BEGIN
/* ICON "DE", -1, 8, 8, 13, 13, WS_CHILD | WS_VISIBLE */
LTEXT "Demonstration Text Editor", -1, 44, 8, 118, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
LTEXT "Version 4.1", -1, 44, 16, 60, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
PUSHBUTTON "OK", IDOK, 118, 27, 24, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
/* ICON "DE", -1, 8, 8, 13, 13, WS_CHILD | WS_VISIBLE */
LTEXT "Demonstration Text Editor", -1, 44, 8, 118, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
LTEXT "Version 4.1", -1, 44, 16, 60, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
PUSHBUTTON "OK", IDOK, 118, 27, 24, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
END
DE MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&Save\t^W", IDM_FILESAVE
MENUITEM "E&xit\t^D", IDM_FILEEXIT
END
POPUP "&File"
BEGIN
MENUITEM "&Save\t^W", IDM_FILESAVE
MENUITEM "E&xit\t^D", IDM_FILEEXIT
END
POPUP "&Edit"
BEGIN
MENUITEM "Page &Down\t^R^N", IDM_EDITPDOWN
MENUITEM "Page &Up\t^R^P", IDM_EDITPUP
MENUITEM "U&ndo\t^U", IDM_EDITUNDO
MENUITEM "&Locate\t^L ... ^L", IDM_EDITLOCATE
MENUITEM "D&own\t^N", IDM_EDITDOWN
MENUITEM "U&p\t^P", IDM_EDITUP
MENUITEM "Le&ft\t^B", IDM_EDITLEFT
MENUITEM "&Right\t^F", IDM_EDITRIGHT
MENUITEM "Delete &Backward\tBS", IDM_EDITBS
MENUITEM "Delete F&orward\tDEL", IDM_EDITDEL
MENUITEM "&Top\t^T", IDM_EDITTOP
END
POPUP "&Edit"
BEGIN
MENUITEM "Page &Down\t^R^N", IDM_EDITPDOWN
MENUITEM "Page &Up\t^R^P", IDM_EDITPUP
MENUITEM "U&ndo\t^U", IDM_EDITUNDO
MENUITEM "&Locate\t^L ... ^L", IDM_EDITLOCATE
MENUITEM "D&own\t^N", IDM_EDITDOWN
MENUITEM "U&p\t^P", IDM_EDITUP
MENUITEM "Le&ft\t^B", IDM_EDITLEFT
MENUITEM "&Right\t^F", IDM_EDITRIGHT
MENUITEM "Delete &Backward\tBS", IDM_EDITBS
MENUITEM "Delete F&orward\tDEL", IDM_EDITDEL
MENUITEM "&Top\t^T", IDM_EDITTOP
END
POPUP "&Help"
BEGIN
MENUITEM "&Contents", IDM_HELPCONTENTS
MENUITEM "&About...", IDM_HELPABOUT
END
POPUP "&Help"
BEGIN
MENUITEM "&Contents", IDM_HELPCONTENTS
MENUITEM "&About...", IDM_HELPABOUT
END
MENUITEM "Page_&Down", IDM_EDITPDOWN
MENUITEM "Page_&Up", IDM_EDITPUP
MENUITEM "Page_&Down", IDM_EDITPDOWN
MENUITEM "Page_&Up", IDM_EDITPUP
END
DE ACCELERATORS
BEGIN
"^R", IDM_EDITREPEAT
@ -67,9 +64,8 @@ BEGIN
"^B", IDM_EDITLEFT
"^F", IDM_EDITRIGHT
"^T", IDM_EDITTOP
VK_DELETE, IDM_EDITDEL, VIRTKEY
VK_BACK, IDM_EDITBS, VIRTKEY
VK_DELETE, IDM_EDITDEL, VIRTKEY
VK_BACK, IDM_EDITBS, VIRTKEY
END
/* DE ICON cord\de_win.ICO */

View file

@ -73,7 +73,7 @@ GC_INNER ptr_t GC_FindTopOfStack(unsigned long stack_start)
}
# ifdef DEBUG_THREADS_EXTRA
GC_log_printf("FindTopOfStack start at sp = %p\n", frame);
GC_log_printf("FindTopOfStack start at sp = %p\n", (void *)frame);
# endif
while (frame->savedSP != 0) {
/* if there are no more stack frames, stop */
@ -83,11 +83,11 @@ GC_INNER ptr_t GC_FindTopOfStack(unsigned long stack_start)
/* we do these next two checks after going to the next frame
because the LR for the first stack frame in the loop
is not set up on purpose, so we shouldn't check it. */
if ((frame->savedLR & ~0x3) == 0 || (frame->savedLR & ~0x3) == ~0x3U)
if ((frame->savedLR & ~0x3) == 0 || (frame->savedLR & ~0x3) == ~0x3UL)
break; /* if the next LR is bogus, stop */
}
# ifdef DEBUG_THREADS_EXTRA
GC_log_printf("FindTopOfStack finish at sp = %p\n", frame);
GC_log_printf("FindTopOfStack finish at sp = %p\n", (void *)frame);
# endif
return (ptr_t)frame;
}
@ -129,7 +129,9 @@ GC_API void GC_CALL GC_use_threads_discovery(void)
/* Evaluates the stack range for a given thread. Returns the lower */
/* bound and sets *phi to the upper one. */
STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p,
GC_bool thread_blocked, mach_port_t my_thread)
GC_bool thread_blocked, mach_port_t my_thread,
ptr_t *paltstack_lo,
ptr_t *paltstack_hi GC_ATTR_UNUSED)
{
ptr_t lo;
if (thread == my_thread) {
@ -140,6 +142,9 @@ STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p,
# endif
} else if (thread_blocked) {
# if defined(CPPCHECK)
if (NULL == p) ABORT("Invalid GC_thread passed to GC_stack_range_for");
# endif
lo = p->stop_info.stack_ptr;
# ifndef DARWIN_DONT_PARSE_STACK
*phi = p->topOfStack;
@ -167,14 +172,20 @@ STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p,
arm_unified_thread_state_t unified_state;
mach_msg_type_number_t unified_thread_state_count
= ARM_UNIFIED_THREAD_STATE_COUNT;
kern_result = thread_get_state(thread, ARM_UNIFIED_THREAD_STATE,
# if defined(CPPCHECK)
# define GC_ARM_UNIFIED_THREAD_STATE 1
# else
# define GC_ARM_UNIFIED_THREAD_STATE ARM_UNIFIED_THREAD_STATE
# endif
kern_result = thread_get_state(thread, GC_ARM_UNIFIED_THREAD_STATE,
(natural_t *)&unified_state,
&unified_thread_state_count);
if (unified_state.ash.flavor != ARM_THREAD_STATE32) {
ABORT("unified_state flavor should be ARM_THREAD_STATE32");
}
state = unified_state.ts_32;
# if !defined(CPPCHECK)
if (unified_state.ash.flavor != ARM_THREAD_STATE32) {
ABORT("unified_state flavor should be ARM_THREAD_STATE32");
}
# endif
state = unified_state;
} else
# endif
/* else */ {
@ -293,6 +304,8 @@ STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p,
GC_push_one(state.THREAD_FLD(fp));
GC_push_one(state.THREAD_FLD(lr));
# elif defined(CPPCHECK)
lo = NULL;
# else
# error FIXME for non-x86 || ppc || arm architectures
# endif
@ -302,17 +315,30 @@ STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p,
/* p is guaranteed to be non-NULL regardless of GC_query_task_threads. */
*phi = (p->flags & MAIN_THREAD) != 0 ? GC_stackbottom : p->stack_end;
# endif
/* TODO: Determine p and handle altstack if !DARWIN_DONT_PARSE_STACK */
# ifdef DARWIN_DONT_PARSE_STACK
if (p->altstack != NULL && (word)p->altstack <= (word)lo
&& (word)lo <= (word)p->altstack + p->altstack_size) {
*paltstack_lo = lo;
*paltstack_hi = p->altstack + p->altstack_size;
lo = p->stack;
*phi = p->stack + p->stack_size;
} else
# endif
/* else */ {
*paltstack_lo = NULL;
}
# ifdef DEBUG_THREADS
GC_log_printf("Darwin: Stack for thread %p = [%p,%p)\n",
(void *)thread, lo, *phi);
(void *)(word)thread, (void *)lo, (void *)(*phi));
# endif
return lo;
}
GC_INNER void GC_push_all_stacks(void)
{
int i;
ptr_t lo, hi;
ptr_t hi, altstack_lo, altstack_hi;
task_t my_task = current_task();
mach_port_t my_thread = mach_thread_self();
GC_bool found_me = FALSE;
@ -324,6 +350,7 @@ GC_INNER void GC_push_all_stacks(void)
# ifndef DARWIN_DONT_PARSE_STACK
if (GC_query_task_threads) {
int i;
kern_return_t kern_result;
thread_act_array_t act_list = 0;
@ -334,10 +361,15 @@ GC_INNER void GC_push_all_stacks(void)
for (i = 0; i < (int)listcount; i++) {
thread_act_t thread = act_list[i];
lo = GC_stack_range_for(&hi, thread, NULL, FALSE, my_thread);
GC_ASSERT((word)lo <= (word)hi);
total_size += hi - lo;
GC_push_all_stack(lo, hi);
ptr_t lo = GC_stack_range_for(&hi, thread, NULL, FALSE, my_thread,
&altstack_lo, &altstack_hi);
if (lo) {
GC_ASSERT((word)lo <= (word)hi);
total_size += hi - lo;
GC_push_all_stack(lo, hi);
}
/* TODO: Handle altstack */
nthreads++;
if (thread == my_thread)
found_me = TRUE;
@ -349,16 +381,28 @@ GC_INNER void GC_push_all_stacks(void)
} else
# endif /* !DARWIN_DONT_PARSE_STACK */
/* else */ {
int i;
for (i = 0; i < (int)listcount; i++) {
GC_thread p;
for (p = GC_threads[i]; p != NULL; p = p->next)
if ((p->flags & FINISHED) == 0) {
thread_act_t thread = (thread_act_t)p->stop_info.mach_thread;
lo = GC_stack_range_for(&hi, thread, p, (GC_bool)p->thread_blocked,
my_thread);
GC_ASSERT((word)lo <= (word)hi);
total_size += hi - lo;
GC_push_all_stack_sections(lo, hi, p->traced_stack_sect);
ptr_t lo = GC_stack_range_for(&hi, thread, p,
(GC_bool)p->thread_blocked,
my_thread, &altstack_lo,
&altstack_hi);
if (lo) {
GC_ASSERT((word)lo <= (word)hi);
total_size += hi - lo;
GC_push_all_stack_sections(lo, hi, p->traced_stack_sect);
}
if (altstack_lo) {
total_size += altstack_hi - altstack_lo;
GC_push_all_stack(altstack_lo, altstack_hi);
}
nthreads++;
if (thread == my_thread)
found_me = TRUE;
@ -429,7 +473,8 @@ STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
# endif
# ifdef DEBUG_THREADS
GC_log_printf("Attempting to suspend thread %p\n", (void *)thread);
GC_log_printf("Attempting to suspend thread %p\n",
(void *)(word)thread);
# endif
/* find the current thread in the old list */
found = FALSE;
@ -473,7 +518,8 @@ STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
continue;
}
# ifdef DEBUG_THREADS
GC_log_printf("Thread state for %p = %d\n", (void *)thread, info.run_state);
GC_log_printf("Thread state for %p = %d\n", (void *)(word)thread,
info.run_state);
# endif
if (info.suspend_count != 0) {
/* thread is already suspended. */
@ -483,9 +529,11 @@ STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
}
# ifdef DEBUG_THREADS
GC_log_printf("Suspending %p\n", (void *)thread);
GC_log_printf("Suspending %p\n", (void *)(word)thread);
# endif
kern_result = thread_suspend(thread);
do {
kern_result = thread_suspend(thread);
} while (kern_result == KERN_ABORTED);
if (kern_result != KERN_SUCCESS) {
/* The thread may have quit since the thread_threads() call we */
/* mark already suspended so it's not dealt with anymore later. */
@ -495,6 +543,8 @@ STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
}
if (!found)
GC_mach_threads_count++;
if (GC_on_thread_event)
GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED, (void *)(word)thread);
}
return changed;
}
@ -504,13 +554,13 @@ STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
/* Caller holds allocation lock. */
GC_INNER void GC_stop_world(void)
{
unsigned i;
task_t my_task = current_task();
mach_port_t my_thread = mach_thread_self();
kern_return_t kern_result;
# ifdef DEBUG_THREADS
GC_log_printf("Stopping the world from thread %p\n", (void *)my_thread);
GC_log_printf("Stopping the world from thread %p\n",
(void *)(word)my_thread);
# endif
# ifdef PARALLEL_MARK
if (GC_parallel) {
@ -526,6 +576,7 @@ GC_INNER void GC_stop_world(void)
if (GC_query_task_threads) {
# ifndef GC_NO_THREADS_DISCOVERY
unsigned i;
GC_bool changed;
thread_act_array_t act_list, prev_list;
mach_msg_type_number_t listcount, prevcount;
@ -573,6 +624,8 @@ GC_INNER void GC_stop_world(void)
# endif /* !GC_NO_THREADS_DISCOVERY */
} else {
unsigned i;
for (i = 0; i < THREAD_TABLE_SZ; i++) {
GC_thread p;
@ -580,9 +633,14 @@ GC_INNER void GC_stop_world(void)
if ((p->flags & FINISHED) == 0 && !p->thread_blocked &&
p->stop_info.mach_thread != my_thread) {
kern_result = thread_suspend(p->stop_info.mach_thread);
do {
kern_result = thread_suspend(p->stop_info.mach_thread);
} while (kern_result == KERN_ABORTED);
if (kern_result != KERN_SUCCESS)
ABORT("thread_suspend failed");
if (GC_on_thread_event)
GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED,
(void *)(word)p->stop_info.mach_thread);
}
}
}
@ -599,7 +657,7 @@ GC_INNER void GC_stop_world(void)
# endif
# ifdef DEBUG_THREADS
GC_log_printf("World stopped from %p\n", (void *)my_thread);
GC_log_printf("World stopped from %p\n", (void *)(word)my_thread);
# endif
mach_port_deallocate(my_task, my_thread);
}
@ -616,13 +674,15 @@ GC_INLINE void GC_thread_resume(thread_act_t thread)
ABORT("thread_info failed");
# endif
# ifdef DEBUG_THREADS
GC_log_printf("Resuming thread %p with state %d\n", (void *)thread,
GC_log_printf("Resuming thread %p with state %d\n", (void *)(word)thread,
info.run_state);
# endif
/* Resume the thread */
kern_result = thread_resume(thread);
if (kern_result != KERN_SUCCESS)
ABORT("thread_resume failed");
if (GC_on_thread_event)
GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, (void *)(word)thread);
}
/* Caller holds allocation lock, and has held it continuously since */
@ -630,7 +690,6 @@ GC_INLINE void GC_thread_resume(thread_act_t thread)
GC_INNER void GC_start_world(void)
{
task_t my_task = current_task();
int i;
# ifdef DEBUG_THREADS
GC_log_printf("World starting\n");
# endif
@ -642,6 +701,7 @@ GC_INNER void GC_start_world(void)
if (GC_query_task_threads) {
# ifndef GC_NO_THREADS_DISCOVERY
int i;
int j = GC_mach_threads_count;
kern_return_t kern_result;
thread_act_array_t act_list;
@ -675,7 +735,7 @@ GC_INNER void GC_start_world(void)
if (GC_mach_threads[j].already_suspended) {
# ifdef DEBUG_THREADS
GC_log_printf("Not resuming already suspended thread %p\n",
(void *)thread);
(void *)(word)thread);
# endif
} else {
GC_thread_resume(thread);
@ -689,6 +749,7 @@ GC_INNER void GC_start_world(void)
# endif /* !GC_NO_THREADS_DISCOVERY */
} else {
int i;
mach_port_t my_thread = mach_thread_self();
for (i = 0; i < THREAD_TABLE_SZ; i++) {

View file

@ -54,9 +54,24 @@
}
#endif /* !SHORT_DBG_HDRS */
#ifdef LINT2
long GC_random(void)
{
static unsigned seed = 1; /* not thread-safe */
/* Linear congruential pseudo-random numbers generator. */
seed = (seed * 1103515245U + 12345) & GC_RAND_MAX; /* overflow is ok */
return (long)seed;
}
#endif
#ifdef KEEP_BACK_PTRS
#ifdef LINT2
# define RANDOM() GC_random()
#else
# include <stdlib.h>
# define GC_RAND_MAX RAND_MAX
# if defined(__GLIBC__) || defined(SOLARIS) \
|| defined(HPUX) || defined(IRIX5) || defined(OSF1)
@ -64,6 +79,7 @@
# else
# define RANDOM() (long)rand()
# endif
#endif /* !LINT2 */
/* Store back pointer to source in dest, if that appears to be possible. */
/* This is not completely safe, since we may mistakenly conclude that */
@ -142,11 +158,10 @@
GC_API void * GC_CALL GC_generate_random_heap_address(void)
{
size_t i;
size_t size;
word heap_offset = RANDOM();
if (GC_heapsize > RAND_MAX) {
heap_offset *= RAND_MAX;
if (GC_heapsize > GC_RAND_MAX) {
heap_offset *= GC_RAND_MAX;
heap_offset += RANDOM();
}
heap_offset %= GC_heapsize;
@ -154,6 +169,8 @@
/* e.g. RAND_MAX = 1.5* GC_heapsize. But for typical cases, */
/* it's not too bad. */
for (i = 0;; ++i) {
size_t size;
if (i >= GC_n_heap_sects)
ABORT("GC_generate_random_heap_address: size inconsistency");
@ -250,15 +267,13 @@
# define CROSSES_HBLK(p, sz) \
(((word)((p) + sizeof(oh) + (sz) - 1) ^ (word)(p)) >= HBLKSIZE)
/* Store debugging info into p. Return displaced pointer. */
/* This version assumes we do hold the allocation lock. */
STATIC ptr_t GC_store_debug_info_inner(ptr_t p, word sz GC_ATTR_UNUSED,
const char *string, int linenum)
GC_INNER void *GC_store_debug_info_inner(void *p, word sz GC_ATTR_UNUSED,
const char *string, int linenum)
{
word * result = (word *)((oh *)p + 1);
GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK(p, sz)));
GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK((ptr_t)p, sz)));
# ifdef KEEP_BACK_PTRS
((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
# endif
@ -276,14 +291,24 @@ STATIC ptr_t GC_store_debug_info_inner(ptr_t p, word sz GC_ATTR_UNUSED,
return((ptr_t)result);
}
GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *string,
int linenum)
/* Check the allocation is successful, store debugging info into p, */
/* start the debugging mode (if not yet), and return displaced pointer. */
static void *store_debug_info(void *p, size_t lb,
const char *fn, GC_EXTRA_PARAMS)
{
ptr_t result;
void *result;
DCL_LOCK_STATE;
if (NULL == p) {
GC_err_printf("%s(%lu) returning NULL (%s:%d)\n",
fn, (unsigned long)lb, s, i);
return NULL;
}
LOCK();
result = GC_store_debug_info_inner(p, sz, string, linenum);
if (!GC_debugging_started)
GC_start_debugging_inner();
ADD_CALL_CHAIN(p, ra);
result = GC_store_debug_info_inner(p, (word)lb, s, i);
UNLOCK();
return result;
}
@ -370,7 +395,7 @@ STATIC void GC_print_obj(ptr_t p)
case UNCOLLECTABLE:
kind_str = "UNCOLLECTABLE";
break;
# ifdef ATOMIC_UNCOLLECTABLE
# ifdef GC_ATOMIC_UNCOLLECTABLE
case AUNCOLLECTABLE:
kind_str = "ATOMIC_UNCOLLECTABLE";
break;
@ -387,13 +412,14 @@ STATIC void GC_print_obj(ptr_t p)
if (NULL != kind_str) {
GC_err_printf("%p (%s:%d," IF_NOT_SHORTDBG_HDRS(" sz=%lu,") " %s)\n",
(ptr_t)ohdr + sizeof(oh),
(void *)((ptr_t)ohdr + sizeof(oh)),
ohdr->oh_string, GET_OH_LINENUM(ohdr) /*, */
COMMA_IFNOT_SHORTDBG_HDRS((unsigned long)ohdr->oh_sz),
kind_str);
} else {
GC_err_printf("%p (%s:%d," IF_NOT_SHORTDBG_HDRS(" sz=%lu,")
" kind=%d descr=0x%lx)\n", (ptr_t)ohdr + sizeof(oh),
" kind=%d descr=0x%lx)\n",
(void *)((ptr_t)ohdr + sizeof(oh)),
ohdr->oh_string, GET_OH_LINENUM(ohdr) /*, */
COMMA_IFNOT_SHORTDBG_HDRS((unsigned long)ohdr->oh_sz),
kind, (unsigned long)hhdr->hb_descr);
@ -428,11 +454,11 @@ STATIC void GC_debug_print_heap_obj_proc(ptr_t p)
|| ohdr -> oh_string == 0) {
GC_err_printf(
"%s %p in or near object at %p(<smashed>, appr. sz = %lu)\n",
msg, clobbered_addr, p,
msg, (void *)clobbered_addr, (void *)p,
(unsigned long)(GC_size((ptr_t)ohdr) - DEBUG_BYTES));
} else {
GC_err_printf("%s %p in or near object at %p (%s:%d, sz=%lu)\n",
msg, clobbered_addr, p,
msg, (void *)clobbered_addr, (void *)p,
(word)(ohdr -> oh_string) < HBLKSIZE ? "(smashed string)" :
ohdr -> oh_string[0] == '\0' ? "EMPTY(smashed?)" :
ohdr -> oh_string,
@ -440,16 +466,14 @@ STATIC void GC_debug_print_heap_obj_proc(ptr_t p)
PRINT_CALL_CHAIN(ohdr);
}
}
#endif
#ifndef SHORT_DBG_HDRS
STATIC void GC_check_heap_proc (void);
STATIC void GC_print_all_smashed_proc (void);
#else
STATIC void GC_do_nothing(void) {}
#endif
STATIC void GC_start_debugging_inner(void)
GC_INNER void GC_start_debugging_inner(void)
{
GC_ASSERT(I_HOLD_LOCK());
# ifndef SHORT_DBG_HDRS
@ -464,15 +488,6 @@ STATIC void GC_start_debugging_inner(void)
GC_register_displacement_inner((word)sizeof(oh));
}
GC_INNER void GC_start_debugging(void)
{
DCL_LOCK_STATE;
LOCK();
GC_start_debugging_inner();
UNLOCK();
}
size_t GC_debug_header_size = sizeof(oh);
GC_API void GC_CALL GC_debug_register_displacement(size_t offset)
@ -486,7 +501,7 @@ GC_API void GC_CALL GC_debug_register_displacement(size_t offset)
}
#ifdef GC_ADD_CALLER
# if defined(HAVE_DLADDR) && defined(GC_RETURN_ADDR_PARENT)
# if defined(HAVE_DLADDR) && defined(GC_HAVE_RETURN_ADDR_PARENT)
# include <dlfcn.h>
STATIC void GC_caller_func_offset(word ad, const char **symp, int *offp)
@ -514,84 +529,52 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_malloc(size_t lb,
/* Note that according to malloc() specification, if size is 0 then */
/* malloc() returns either NULL, or a unique pointer value that can */
/* later be successfully passed to free(). We always do the latter. */
result = GC_malloc(lb + DEBUG_BYTES);
result = GC_malloc(SIZET_SAT_ADD(lb, DEBUG_BYTES));
# ifdef GC_ADD_CALLER
if (s == NULL) {
GC_caller_func_offset(ra, &s, &i);
}
# endif
if (result == 0) {
GC_err_printf("GC_debug_malloc(%lu) returning NULL (%s:%d)\n",
(unsigned long)lb, s, i);
return(0);
}
if (!GC_debugging_started) {
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
return (GC_store_debug_info(result, (word)lb, s, i));
return store_debug_info(result, lb, "GC_debug_malloc", OPT_RA s, i);
}
GC_API GC_ATTR_MALLOC void * GC_CALL
GC_debug_malloc_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
{
void * result = GC_malloc_ignore_off_page(lb + DEBUG_BYTES);
void * result = GC_malloc_ignore_off_page(SIZET_SAT_ADD(lb, DEBUG_BYTES));
if (result == 0) {
GC_err_printf("GC_debug_malloc_ignore_off_page(%lu)"
" returning NULL (%s:%d)\n", (unsigned long)lb, s, i);
return(0);
}
if (!GC_debugging_started) {
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
return (GC_store_debug_info(result, (word)lb, s, i));
return store_debug_info(result, lb, "GC_debug_malloc_ignore_off_page",
OPT_RA s, i);
}
GC_API GC_ATTR_MALLOC void * GC_CALL
GC_debug_malloc_atomic_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
{
void * result = GC_malloc_atomic_ignore_off_page(lb + DEBUG_BYTES);
void * result = GC_malloc_atomic_ignore_off_page(
SIZET_SAT_ADD(lb, DEBUG_BYTES));
if (result == 0) {
GC_err_printf("GC_debug_malloc_atomic_ignore_off_page(%lu)"
" returning NULL (%s:%d)\n", (unsigned long)lb, s, i);
return(0);
}
if (!GC_debugging_started) {
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
return (GC_store_debug_info(result, (word)lb, s, i));
return store_debug_info(result, lb,
"GC_debug_malloc_atomic_ignore_off_page",
OPT_RA s, i);
}
STATIC void * GC_debug_generic_malloc(size_t lb, int knd, GC_EXTRA_PARAMS)
{
void * result = GC_generic_malloc(lb + DEBUG_BYTES, knd);
void * result = GC_generic_malloc(SIZET_SAT_ADD(lb, DEBUG_BYTES), knd);
if (NULL == result) {
GC_err_printf(
"GC_debug_generic_malloc(%lu, %d) returning NULL (%s:%d)\n",
(unsigned long)lb, knd, s, i);
return NULL;
}
if (!GC_debugging_started) {
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
return GC_store_debug_info(result, (word)lb, s, i);
return store_debug_info(result, lb, "GC_debug_generic_malloc",
OPT_RA s, i);
}
#ifdef DBG_HDRS_ALL
/* An allocation function for internal use. Normally internally */
/* allocated objects do not have debug information. But in this */
/* case, we need to make sure that all objects have debug headers. */
/* We assume debugging was started in collector initialization, and */
/* we already hold the GC lock. */
/* We assume we already hold the GC lock. */
GC_INNER void * GC_debug_generic_malloc_inner(size_t lb, int k)
{
void * result = GC_generic_malloc_inner(lb + DEBUG_BYTES, k);
void * result = GC_generic_malloc_inner(
SIZET_SAT_ADD(lb, DEBUG_BYTES), k);
if (result == 0) {
GC_err_printf("GC internal allocation (%lu bytes) returning NULL\n",
@ -609,7 +592,7 @@ STATIC void * GC_debug_generic_malloc(size_t lb, int knd, GC_EXTRA_PARAMS)
int k)
{
void * result = GC_generic_malloc_inner_ignore_off_page(
lb + DEBUG_BYTES, k);
SIZET_SAT_ADD(lb, DEBUG_BYTES), k);
if (result == 0) {
GC_err_printf("GC internal allocation (%lu bytes) returning NULL\n",
@ -628,18 +611,10 @@ STATIC void * GC_debug_generic_malloc(size_t lb, int knd, GC_EXTRA_PARAMS)
GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_malloc_stubborn(size_t lb,
GC_EXTRA_PARAMS)
{
void * result = GC_malloc_stubborn(lb + DEBUG_BYTES);
void * result = GC_malloc_stubborn(SIZET_SAT_ADD(lb, DEBUG_BYTES));
if (result == 0) {
GC_err_printf("GC_debug_malloc_stubborn(%lu)"
" returning NULL (%s:%d)\n", (unsigned long)lb, s, i);
return(0);
}
if (!GC_debugging_started) {
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
return (GC_store_debug_info(result, (word)lb, s, i));
return store_debug_info(result, lb, "GC_debug_malloc_stubborn",
OPT_RA s, i);
}
GC_API void GC_CALL GC_debug_change_stubborn(const void *p)
@ -657,22 +632,6 @@ STATIC void * GC_debug_generic_malloc(size_t lb, int knd, GC_EXTRA_PARAMS)
GC_change_stubborn(q);
}
GC_API void GC_CALL GC_debug_end_stubborn_change(const void *p)
{
const void * q = GC_base_C(p);
hdr * hhdr;
if (q == 0) {
ABORT_ARG1("GC_debug_end_stubborn_change: bad arg", ": %p", p);
}
hhdr = HDR(q);
if (hhdr -> hb_obj_kind != STUBBORN) {
ABORT_ARG1("GC_debug_end_stubborn_change: arg not stubborn",
": %p", p);
}
GC_end_stubborn_change(q);
}
#else /* !STUBBORN_ALLOC */
GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_malloc_stubborn(size_t lb,
@ -683,26 +642,30 @@ STATIC void * GC_debug_generic_malloc(size_t lb, int knd, GC_EXTRA_PARAMS)
GC_API void GC_CALL GC_debug_change_stubborn(
const void * p GC_ATTR_UNUSED) {}
GC_API void GC_CALL GC_debug_end_stubborn_change(
const void * p GC_ATTR_UNUSED) {}
#endif /* !STUBBORN_ALLOC */
GC_API void GC_CALL GC_debug_end_stubborn_change(const void *p)
{
const void * q = GC_base_C(p);
if (NULL == q) {
ABORT_ARG1("GC_debug_end_stubborn_change: bad arg", ": %p", p);
}
# ifdef STUBBORN_ALLOC
if (HDR(q) -> hb_obj_kind != STUBBORN)
ABORT_ARG1("GC_debug_end_stubborn_change: arg not stubborn",
": %p", p);
# endif
GC_end_stubborn_change(q);
}
GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_malloc_atomic(size_t lb,
GC_EXTRA_PARAMS)
{
void * result = GC_malloc_atomic(lb + DEBUG_BYTES);
void * result = GC_malloc_atomic(SIZET_SAT_ADD(lb, DEBUG_BYTES));
if (result == 0) {
GC_err_printf("GC_debug_malloc_atomic(%lu) returning NULL (%s:%d)\n",
(unsigned long)lb, s, i);
return(0);
}
if (!GC_debugging_started) {
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
return (GC_store_debug_info(result, (word)lb, s, i));
return store_debug_info(result, lb, "GC_debug_malloc_atomic",
OPT_RA s, i);
}
GC_API GC_ATTR_MALLOC char * GC_CALL GC_debug_strdup(const char *str,
@ -769,39 +732,25 @@ GC_API GC_ATTR_MALLOC char * GC_CALL GC_debug_strndup(const char *str,
GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_malloc_uncollectable(size_t lb,
GC_EXTRA_PARAMS)
{
void * result = GC_malloc_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
void * result = GC_malloc_uncollectable(
SIZET_SAT_ADD(lb, UNCOLLECTABLE_DEBUG_BYTES));
if (result == 0) {
GC_err_printf("GC_debug_malloc_uncollectable(%lu)"
" returning NULL (%s:%d)\n", (unsigned long)lb, s, i);
return(0);
}
if (!GC_debugging_started) {
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
return (GC_store_debug_info(result, (word)lb, s, i));
return store_debug_info(result, lb, "GC_debug_malloc_uncollectable",
OPT_RA s, i);
}
#ifdef ATOMIC_UNCOLLECTABLE
#ifdef GC_ATOMIC_UNCOLLECTABLE
GC_API GC_ATTR_MALLOC void * GC_CALL
GC_debug_malloc_atomic_uncollectable(size_t lb, GC_EXTRA_PARAMS)
{
void * result =
GC_malloc_atomic_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
void * result = GC_malloc_atomic_uncollectable(
SIZET_SAT_ADD(lb, UNCOLLECTABLE_DEBUG_BYTES));
if (result == 0) {
GC_err_printf("GC_debug_malloc_atomic_uncollectable(%lu)"
" returning NULL (%s:%d)\n", (unsigned long)lb, s, i);
return(0);
}
if (!GC_debugging_started) {
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
return (GC_store_debug_info(result, (word)lb, s, i));
return store_debug_info(result, lb,
"GC_debug_malloc_atomic_uncollectable",
OPT_RA s, i);
}
#endif /* ATOMIC_UNCOLLECTABLE */
#endif /* GC_ATOMIC_UNCOLLECTABLE */
#ifndef GC_FREED_MEM_MARKER
# if CPP_WORDSZ == 32
@ -818,6 +767,14 @@ GC_API void GC_CALL GC_debug_free(void * p)
base = GC_base(p);
if (base == 0) {
# if defined(REDIRECT_MALLOC) \
&& ((defined(NEED_CALLINFO) && defined(GC_HAVE_BUILTIN_BACKTRACE)) \
|| defined(GC_LINUX_THREADS) || defined(GC_SOLARIS_THREADS) \
|| defined(MSWIN32))
/* In some cases, we should ignore objects that do not belong */
/* to the GC heap. See the comment in GC_free. */
if (!GC_is_heap_ptr(p)) return;
# endif
ABORT_ARG1("Invalid pointer passed to free()", ": %p", p);
}
if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
@ -852,7 +809,7 @@ GC_API void GC_CALL GC_debug_free(void * p)
} else {
hdr * hhdr = HDR(p);
if (hhdr -> hb_obj_kind == UNCOLLECTABLE
# ifdef ATOMIC_UNCOLLECTABLE
# ifdef GC_ATOMIC_UNCOLLECTABLE
|| hhdr -> hb_obj_kind == AUNCOLLECTABLE
# endif
) {
@ -894,6 +851,11 @@ GC_API void * GC_CALL GC_debug_realloc(void * p, size_t lb, GC_EXTRA_PARAMS)
if (p == 0) {
return GC_debug_malloc(lb, OPT_RA s, i);
}
if (0 == lb) /* and p != NULL */ {
GC_debug_free(p);
return NULL;
}
# ifdef GC_ADD_CALLER
if (s == NULL) {
GC_caller_func_offset(ra, &s, &i);
@ -924,7 +886,7 @@ GC_API void * GC_CALL GC_debug_realloc(void * p, size_t lb, GC_EXTRA_PARAMS)
case UNCOLLECTABLE:
result = GC_debug_malloc_uncollectable(lb, OPT_RA s, i);
break;
# ifdef ATOMIC_UNCOLLECTABLE
# ifdef GC_ATOMIC_UNCOLLECTABLE
case AUNCOLLECTABLE:
result = GC_debug_malloc_atomic_uncollectable(lb, OPT_RA s, i);
break;
@ -961,7 +923,7 @@ GC_API GC_ATTR_MALLOC void * GC_CALL
return GC_debug_malloc(lb, OPT_RA s, i);
case UNCOLLECTABLE:
return GC_debug_malloc_uncollectable(lb, OPT_RA s, i);
# ifdef ATOMIC_UNCOLLECTABLE
# ifdef GC_ATOMIC_UNCOLLECTABLE
case AUNCOLLECTABLE:
return GC_debug_malloc_atomic_uncollectable(lb, OPT_RA s, i);
# endif
@ -1109,7 +1071,7 @@ STATIC void GC_CALLBACK GC_debug_invoke_finalizer(void * obj, void * data)
}
/* Special finalizer_proc value to detect GC_register_finalizer() failure. */
#define OFN_UNSET (GC_finalization_proc)(signed_word)-1
#define OFN_UNSET ((GC_finalization_proc)~(signed_word)0)
/* Set ofn and ocd to reflect the values we got back. */
static void store_old(void *obj, GC_finalization_proc my_old_fn,

View file

@ -2,9 +2,8 @@
# compiler from www.digitalmars.com
# Written by Walter Bright
DEFINES=-DNDEBUG -D_WINDOWS -DGC_DLL -DALL_INTERIOR_POINTERS -DWIN32_THREADS
CFLAGS=-Iinclude $(DEFINES) -wx -g
DEFINES=-D_WINDOWS -DGC_DLL -DGC_THREADS -DGC_DISCOVER_TASK_THREADS -DALL_INTERIOR_POINTERS
CFLAGS=-Iinclude -Ilibatomic_ops\src $(DEFINES) -wx -g
LFLAGS=/ma/implib/co
CC=sc
@ -40,31 +39,35 @@ OBJS= \
typd_mlc.obj\
win32_threads.obj
targets: gc.dll gc.lib gctest.exe
targets: gc.dll gc.lib gctest.exe test_cpp.exe
gc.dll: $(OBJS) gc.def digimars.mak
sc -ogc.dll $(OBJS) -L$(LFLAGS) gc.def kernel32.lib user32.lib
$(CC) -ogc.dll $(OBJS) -L$(LFLAGS) gc.def kernel32.lib user32.lib
gc.def: digimars.mak
echo LIBRARY GC >gc.def
echo DESCRIPTION "Hans Boehm Garbage Collector" >>gc.def
echo DESCRIPTION "Boehm-Demers-Weiser Garbage Collector" >>gc.def
echo EXETYPE NT >>gc.def
echo EXPORTS >>gc.def
echo GC_is_visible_print_proc >>gc.def
echo GC_is_valid_displacement_print_proc >>gc.def
clean:
del gc.def
del *.log gc.def gc.dll gc.lib gc.map gctest.map test_cpp.map
del tests\test.obj gctest.exe tests\test_cpp.obj test_cpp.exe
del $(OBJS)
gctest.exe: gc.lib tests\test.obj
$(CC) -ogctest.exe tests\test.obj gc.lib
gctest.exe : gc.lib tests\test.obj
sc -ogctest.exe tests\test.obj gc.lib
tests\test.obj: tests\test.c
$(CC) -c $(CFLAGS) tests\test.c -otests\test.obj
tests\test.obj : tests\test.c
$(CC) -c -g -DNDEBUG -D_WINDOWS -DGC_DLL \
-DALL_INTERIOR_POINTERS -DWIN32_THREADS \
-Iinclude tests\test.c -otests\test.obj
test_cpp.exe: gc.lib tests\test_cpp.obj
$(CC) -otest_cpp.exe tests\test_cpp.obj gc.lib
tests\test_cpp.obj: tests\test_cpp.cc
$(CC) -c $(CFLAGS) -cpp tests\test_cpp.cc -otests\test_cpp.obj
allchblk.obj: allchblk.c
alloc.obj: alloc.c
@ -74,7 +77,7 @@ dbg_mlc.obj: dbg_mlc.c
dyn_load.obj: dyn_load.c
finalize.obj: finalize.c
fnlz_mlc.obj: fnlz_mlc.c
gc_cpp.obj: gc_cpp.cpp
gc_cpp.obj: gc_cpp.cc gc_cpp.cpp
headers.obj: headers.c
mach_dep.obj: mach_dep.c
malloc.obj: malloc.c

View file

@ -1,4 +1,4 @@
Garbage Collector (parallel iversion) for ix86 DG/UX Release R4.20MU07
Garbage Collector (parallel version) for x86 DG/UX Release R4.20MU07
*READ* the file README.QUICK.
@ -7,7 +7,7 @@
This compiler has the new "dgux386" threads package implemented.
It also supports the switch "-pthread" needed to link correctly
the DG/UX's -lrte -lthread with -lgcc and the system's -lc.
Finally we support parralleli-mark for the SMP DG/UX machines.
Finally, we support parallel mark for the SMP DG/UX machines.
To build the garbage collector do:
./configure --enable-parallel-mark
@ -24,13 +24,7 @@
To enable debugging messages please do:
1) Add the "--enable-gc-debug" flag during configuration.
2) Edit the file linux-threads.c and uncomment the line:
/* #define DEBUG_THREADS 1 */ to --->
#define DEBUG_THREADS 1
Then give "make" as usual.
2) Pass "CFLAGS=-DDEBUG_THREADS" to "make".
In a machine with 4 CPUs (my own machine) the option parallel
mark (aka --enable-parallel-mark) makes a BIG difference.

View file

@ -126,7 +126,7 @@ o 68K Linker
Prefix Files to configure the GC sources
----------------------------------------
The Codewarrior equivalent of commandline compilers -DNAME=X is to use
The Codewarrior equivalent of command-line compilers -DNAME=X is to use
prefix-files. A TEXT file that is automatically #included before the first byte
of every source file. I used these:
@ -161,7 +161,7 @@ of every source file. I used these:
#define ALL_INTERIOR_POINTERS // follows interior pointers.
//#define DONT_ADD_BYTE_AT_END // disables the padding if defined.
//#define SMALL_CONFIG // whether to use a smaller heap.
#define ATOMIC_UNCOLLECTABLE // GC_malloc_atomic_uncollectable()
#define GC_ATOMIC_UNCOLLECTABLE // GC_malloc_atomic_uncollectable()
// define either or none as per personal preference
// used in malloc.c
@ -271,7 +271,7 @@ action! malloc will call GC_malloc and free GC_free, new/delete too. You
don't have to call free or delete. You may have to be a bit cautious about
delete if you're freeing other resources than RAM. See gc_cpp.h. You can
also keep coding as always with delete/free. That works too. If you want,
"include <gc.h> and tweak it's use a bit.
include "gc.h" and tweak its use a bit.
== Symantec SPM ==

View file

@ -48,7 +48,7 @@ WHATS NEW:
It is also the most important flag to set to prevent
GC from returning chip-mem. Beware that it slows down a lot
when a program is rapidly allocating/deallocating when
theres either very little fast-memory left or verly little
there's either very little fast-memory left or very little
chip-memory left. Its not a very common situation, but gctest
sometimes (very rare) use many minutes because of this.
@ -62,7 +62,7 @@ WHATS NEW:
program, and prints out the info when the atexit-handler
is called.
My reccomendation is to set all this flags, except GC_AMIGA_PRINTSTATS and
My recommendation is to set all this flags, except GC_AMIGA_PRINTSTATS and
GC_AMIGA_ONLYFAST.
If your program demands high response-time, you should
@ -70,7 +70,7 @@ WHATS NEW:
GC_AMIGA_RETRY does not seem to slow down much.
Also, when compiling up programs, and GC_AMIGA_FASTALLOC was not defined when
compilling gc, you can define GC_AMIGA_MAKINGLIB to avoid having these allocation-
compiling gc, you can define GC_AMIGA_MAKINGLIB to avoid having these allocation-
functions wrapped. (see gc.h)
Note that GC_realloc must not be called before any of
@ -249,7 +249,7 @@ will not behave well with Amiga specific code. Especially not inter-
process comms via messages, and setting up public structures like
Intuition objects or anything else in the system lists. For the
time being the use of this library is limited to single threaded
ANSI/POSIX compliant or near-complient code. (ie. Stick to stdio
ANSI/POSIX compliant or near-compliant code. (ie. Stick to stdio
for now). Given this limitation there is currently no mechanism for
allocating "CHIP" or "PUBLIC" memory under the garbage collector.
I'll add this after giving it considerable thought. The major
@ -260,7 +260,7 @@ If you allocate your own stack in client code, you will have to
assign the pointer plus stack size to GC_stackbottom.
The initial stack size of the target program can be compiled in by
setting the __stack symbol (see SAS documentaion). It can be over-
setting the __stack symbol (see SAS documentation). It can be over-
ridden from the CLI by running the AmigaDOS "stack" program, or from
the WorkBench by setting the stack size in the tool types window.
@ -282,7 +282,7 @@ The library as it stands is compatible with the GigaMem commercial
virtual memory software, and probably similar PD software.
The performance of "gctest" on an Amiga 2630 (68030 @ 25Mhz)
compares favourably with an HP9000 with similar architecture (a 325
compares favorably with an HP9000 with similar architecture (a 325
with a 68030 I think).
-----------------------------------------------------------------------

View file

@ -9,8 +9,6 @@ Permission to modify the code and to distribute modified code is granted,
provided the above notices are retained, and a notice that the code was
modified is included with the above copyright notice.
Please send bug reports to Hans-J. Boehm.
This is a string packages that uses a tree-based representation.
See cord.h for a description of the functions provided. Ec.h describes
"extensible cords", which are essentially output streams that write
@ -43,7 +41,7 @@ To build the editor, type "make cord/de" in the gc directory.
This package assumes an ANSI C compiler such as gcc. It will
not compile with an old-style K&R compiler.
Note that CORD_printf iand friends use C functions with variable numbers
Note that CORD_printf and friends use C functions with variable numbers
of arguments in non-standard-conforming ways. This code is known to
break on some platforms, notably PowerPC. It should be possible to
build the remainder of the library (everything but cordprnt.c) on

View file

@ -21,7 +21,7 @@ cannot call GC_init() before your libraries' static initializers have
run and perhaps called GC_malloc(), create an initialization routine
for each library to call GC_init():
#include <gc/gc.h>
#include "gc.h"
extern "C" void my_library_init() { GC_init(); }
Compile this code into a my_library_init.o, and link it into your

View file

@ -97,7 +97,7 @@ GC_PRINT_BACK_HEIGHT - Print max length of chain through unreachable objects
(http://www.hpl.hp.com/techreports/2001/HPL-2001-251.html).
GC_RETRY_SIGNALS, GC_NO_RETRY_SIGNALS - Try to compensate for lost
thread suspend signals in linux_threads.c. On by
thread suspend signals (Pthreads only). On by
default for GC_OSF1_THREADS, off otherwise. Note
that this does not work around a possible loss of
thread restart signals. This seems to be necessary for

View file

@ -2,27 +2,28 @@ GC on EWS4800
-------------
1. About EWS4800
EWS4800 is 32bit/64bit workstation.
Vender: NEC Corporation
EWS4800 is a 32/64-bit workstation.
Vendor: NEC Corporation
OS: UX/4800 R9.* - R13.* (SystemV R4.2)
CPU: R4000, R4400, R10000 (MIPS)
2. Compiler
32bit:
32-bit:
Use ANSI C compiler.
CC = /usr/abiccs/bin/cc
64bit:
Use 64bit ANSI C compiler.
64-bit:
Use the 64-bit ANSI C compiler.
CC = /usr/ccs64/bin/cc
AR = /usr/ccs64/bin/ar
3. ELF file format
*** Caution: The following infomation is empirical. ***
*** Caution: The following information is empirical. ***
32bit:
32-bit:
ELF file has an unique format. (See a.out(4) and end(3C).)
&_start
@ -57,7 +58,7 @@ GC on EWS4800
&edata and DATASTART2. The global symbol &_DYNAMIC_LINKING is used
for the detection.
64bit:
64-bit:
ELF file has a simple format. (See end(3C).)
_ftext
@ -76,5 +77,5 @@ Hironori SAKAMOTO
When using the new "configure; make" build process, please
run configure with the --disable-shared option. "Make check" does not
yet pass with dynamic libraries. Ther reasons for that are not yet
yet pass with dynamic libraries. The reasons for that are not yet
understood. (HB, paraphrasing message from Hironori SAKAMOTO.)

View file

@ -8,7 +8,7 @@ The collector should compile with either plain cc or cc -Ae. Cc -Aa
fails to define _HPUX_SOURCE and thus will not configure the collector
correctly.
Incremental collection support was reccently added, and should now work.
Incremental collection support was added recently, and should now work.
In spite of past claims, pthread support under HP/UX 11 should now work.
Define GC_HPUX_THREADS for the build. Incremental collection still does not

View file

@ -8,8 +8,7 @@ See below for M68K specific notes.
Incremental GC is generally supported.
Dynamic libraries are supported on an ELF system. A static executable
should be linked with the gcc option "-Wl,-defsym,_DYNAMIC=0".
Dynamic libraries are supported on an ELF system.
The collector appears to work reliably with Linux threads, but beware
of older versions of glibc and gdb.

View file

@ -43,6 +43,10 @@ GC_NO_THREAD_REDIRECTS Tested by gc.h. Prevents redirection of thread
GC_NO_THREAD_DECLS Tested by gc.h. MS Windows only. Do not declare
Windows thread creation routines and do not include windows.h.
GC_DONT_INCLUDE_WINDOWS_H Tested by gc.h. MS Windows only. Do not include
windows.h from gc.h (but Windows-specific thread creation
routines are declared).
GC_UNDERSCORE_STDCALL Tested by gc.h. Explicitly prefix exported/imported
WINAPI (__stdcall) symbols with '_' (underscore). Could be
used with MinGW (for x86) compiler (in conjunction with
@ -107,10 +111,6 @@ SUNOS5SIGS Solaris-like signal handling. This is probably misnamed,
PCR Set if the collector is being built as part of the Xerox Portable
Common Runtime.
USE_COMPILER_TLS Assume the existence of __thread-style thread-local storage.
Set automatically for thread-local allocation with the HP/UX vendor
compiler. Usable with gcc on sufficiently up-to-date ELF platforms.
IMPORTANT: Any of the _THREADS options must normally also be defined in
the client before including gc.h. This redefines thread primitives to
invoke the GC_ versions instead. Alternatively, linker-based symbol
@ -257,9 +257,11 @@ FINALIZE_ON_DEMAND Causes finalizers to be run only in response
In 5.0 this became runtime adjustable, and this only determines the
initial value of GC_finalize_on_demand.
GC_NO_FINALIZATION Exclude finalization support (for smaller code size)
GC_NO_FINALIZATION Exclude finalization support (for smaller code size).
ATOMIC_UNCOLLECTABLE Includes code for GC_malloc_atomic_uncollectable.
GC_TOGGLE_REFS_NOT_NEEDED Exclude toggle-refs support.
GC_ATOMIC_UNCOLLECTABLE Includes code for GC_malloc_atomic_uncollectable.
This is useful if either the vendor malloc implementation is poor,
or if REDIRECT_MALLOC is used.
@ -392,12 +394,18 @@ USE_COMPILER_TLS Causes thread local allocation to use
default in HP/UX. It may help performance on recent Linux installations.
(It failed for me on RedHat 8, but appears to work on RedHat 9.)
GC_ATTR_TLS_FAST Use specific attributes for GC_thread_key like
__attribute__((tls_model("local-exec"))).
PARALLEL_MARK Allows the marker to run in multiple threads. Recommended
for multiprocessors.
GC_ALWAYS_MULTITHREADED Force multi-threaded mode at GC initialization.
(Turns GC_allow_register_threads into a no-op routine.)
GC_ENABLE_SUSPEND_THREAD (Linux only) Turn on thread suspend/resume API
support.
GC_WINMAIN_REDIRECT (Win32 only) Redirect (rename) an application
WinMain to GC_WinMain; implement the "real" WinMain which starts a new
thread to call GC_WinMain after initializing the GC. Useful for WinCE.
@ -557,7 +565,7 @@ GC_FULL_FREQ=<value> Set alternate default number of partial collections
NO_CANCEL_SAFE (Posix platforms with threads only) Don't bother trying
to make the collector safe for thread cancellation; cancellation is not
used. (Note that if cancellation is used anyway, threads may end up
getting cancelled in unexpected places.) Even without this option,
getting canceled in unexpected places.) Even without this option,
PTHREAD_CANCEL_ASYNCHRONOUS is never safe with the collector. (We could
argue about its safety without the collector.)

View file

@ -26,8 +26,8 @@ will run on other pthreads platforms. But please tell me if it does.)
include gc.h. Gc.h redefines some of the pthread primitives as macros which
also provide the collector with information it requires.
4) pthread_cond_wait and pthread_cond_timed_wait should be prepared for
premature wakeups. (I believe the pthreads and realted standards require this
4) pthread_cond_wait and pthread_cond_timedwait should be prepared for
premature wakeups. (I believe the pthreads and related standards require this
anyway. Irix pthreads often terminate a wait if a signal arrives.
The garbage collector uses signals to stop threads.)

View file

@ -60,7 +60,7 @@ have it invoke the garbage-collector's allocators only after main has started.
(Note that the latter requires a moderately expensive test in operator
delete.)
I encountered "symbol <unknown>: offet .... is non-aligned" errors. These
I encountered "symbol <unknown>: offset .... is non-aligned" errors. These
appear to be traceable to the use of the GNU assembler with the Sun linker.
The former appears to generate a relocation not understood by the latter.
The fix appears to be to use a consistent tool chain. (As a non-Solaris-expert

View file

@ -1,6 +1,6 @@
The collector has at various times been compiled under Windows 95 & later, NT,
and XP, with the original Microsoft SDK, with Visual C++ 2.0, 4.0, and 6, with
the GNU win32 tools, with Borland 4.5, with Watcom C, and recently
the GNU win32 tools, with Borland C++ Builder, with Watcom C, and
with the Digital Mars compiler. It is likely that some of these have been
broken in the meantime. Patches are appreciated.
@ -41,10 +41,13 @@ in 6.1alpha4, since we now separate heap sections with an unused page.)
Microsoft Tools
---------------
For Microsoft development tools, rename NT_MAKEFILE as
MAKEFILE. (Make sure that the CPU environment variable is defined
to be i386.) In order to use the gc_cpp.h C++ interface, all
client code should include gc_cpp.h.
For Microsoft development tools, type
"nmake -f NT_MAKEFILE cpu=i386 make_as_lib=1 nothreads=1 nodebug=1"
to build the release variant of the collector as a static library without
threads support.
In order to use the gc_cpp.h C++ interface, all client code should include
gc_cpp.h.
For historical reasons,
the collector test program "gctest" is linked as a GUI application,
@ -93,10 +96,8 @@ I expect that -a1 introduces major performance penalties on a
486 or Pentium.) Note that this changes structure layouts. (As a last
resort, gcconfig.h can be changed to allow 1 byte alignment. But
this has significant negative performance implications.)
The Makefile is set up to assume Borland 4.5. If you have another
version, change the line near the top. By default, it does not
require the assembler. If you do have the assembler, I recommend
removing the -DUSE_GENERIC.
The Makefile is set up to assume Borland 5.5. If you have another
version, change the line near the top.
Digital Mars compiler
---------------------
@ -180,10 +181,15 @@ to the collector DLL still exists, but requires that both
We generally recommend avoiding this if possible, since it seems to
be less than 100% reliable.
Use gc.mak (a.k.a NT_THREADS_MAKEFILE) instead of NT_MAKEFILE
to build a version that supports both kinds of thread tracking.
To build the garbage collector
test with VC++ from the command line, use
To build the collector as a dynamic library which handles threads similarly
to other platforms, type "nmake -f NT_MAKEFILE". If automatic tracking of
threads attached to the collector DLL (i.e. support of both kinds of thread
tracking) is needed then delete "-DTHREAD_LOCAL_ALLOC" from NT_MAKEFILE
manually before the build.
The alternate way (not well tested) to build the dynamic library that supports
both kinds of thread tracking is to use gc.mak instead of NT_MAKEFILE.
To build the garbage collector test with VC++ from the command line, use
nmake /F ".\gc.mak" CFG="gctest - Win32 Release"
@ -194,10 +200,9 @@ This version currently supports incremental collection only if it is
enabled before any additional threads are created.
Since 6.3alpha2, threads are also better supported in static library builds
with Microsoft tools (use NT_STATIC_THREADS_MAKEFILE) and with the GNU
tools. The collector must be built with GC_THREADS defined.
(NT_STATIC_THREADS_MAKEFILE does this implicitly. Under Cygwin,
./configure --enable-threads=posix should be used.)
with Microsoft tools (e.g., NT_MAKEFILE) and with the GNU
tools. The collector must be built with GC_THREADS defined (this is the
default in NT_MAKEFILE, ./configure and CMakeLists.txt).
For the normal, non-dll-based thread tracking to work properly,
threads should be created with GC_CreateThread or GC_beginthreadex,

View file

@ -1,26 +1,27 @@
64-bit Windows on AMD64/Intel EM64T is somewhat supported in the 7.0
and later release. A collector can be built with Microsoft Visual C++ 2005
or with mingw-w64 gcc.
More testing would clearly be helpful.
NT_X64_STATIC_THREADS_MAKEFILE has been used in
this environment. Copy this file to MAKEFILE, and then type "nmake"
in a Visual C++ command line window to build the static library
and the usual test programs. To verify that the collector is
at least somewhat functional, run gctest.exe. This should create
gctest.gc.log after a few seconds.
NT_MAKEFILE has been used in this environment. Type
"nmake -f NT_MAKEFILE cpu=AMD64 nodebug=1" in a Visual C++ command line
window to build the release variant of the dynamic library with threads
support and the usual test programs.
To verify that the collector is at least somewhat functional, run gctest.exe.
This should create gctest.gc.log after a few seconds.
This process is completely analogous to NT_STATIC_THREADS_MAKEFILE
for the 32-bit version.
Test_cpp.exe might not run correctly in case of dynamic GC linking. (It seems
that we're getting wrong instances of operator new/delete in some cases.)
A similar procedure using NT_X64_THREADS_MAKEFILE should be usable to
build the dynamic library. Test_cpp.exe did not seem to run correctly this
way. It seems that we're getting the wrong instances of operator new/delete
in some cases. The C tests seemed OK.
This process is completely analogous to NT_MAKEFILE usage
for the 32-bit library version.
Note that currently a few warnings are still generated by default,
and a number of others have been explicitly turned off in the makefile.
A similar procedure using NT_MAKEFILE is applicable to build the static
library - just pass "make_as_lib=1" as an extra argument to nmake.
If needed, it is also possible to build the library without threads
support - this could be done by passing "nothreads=1" argument to nmake.
VC++ note: to suppress warnings use -D_CRT_SECURE_NO_DEPRECATE.
Note that some warnings have been explicitly turned off in the makefile.
VC++ note: to suppress warnings -D_CRT_SECURE_NO_DEPRECATE is used.
gcc note: -fno-strict-aliasing should be used if optimizing.

View file

@ -160,7 +160,7 @@ before including <TT>gc.h</tt> and allocating with <TT>GC_MALLOC</tt>),
so that objects will be identified by their allocation site,
<LI> Running the application long enough so
that most of the heap is composed of "leaked" memory, and
<LI> Then calling <TT>GC_generate_random_backtrace()</tt> from backptr.h
<LI> Then calling <TT>GC_generate_random_backtrace()</tt> from gc_backptr.h
a few times to determine why some randomly sampled objects in the heap are
being retained.
</ol>
@ -285,7 +285,7 @@ collector's layout description for <TT>s</tt> is such that the pointer field
will be scanned. Call <TT>*GC_find_header(s)</tt> to look at the descriptor
for the heap chunk. The <TT>hb_descr</tt> field specifies the layout
of objects in that chunk. See gc_mark.h for the meaning of the descriptor.
(If it's low order 2 bits are zero, then it is just the length of the
(If its low order 2 bits are zero, then it is just the length of the
object prefix to be scanned. This form is always used for objects allocated
with <TT>GC_malloc</tt> or <TT>GC_malloc_atomic</tt>.)
<LI> If the failure is not deterministic, you may still be able to apply some

View file

@ -11,8 +11,8 @@
## Process this file with automake to produce Makefile.in.
# installed documentation
#
dist_pkgdata_DATA = \
if ENABLE_DOCS
dist_doc_DATA = \
AUTHORS \
README.md \
doc/README.DGUX386 \
@ -38,7 +38,6 @@ dist_pkgdata_DATA = \
doc/README.win64 \
doc/debugging.html \
doc/finalization.html \
doc/gc.man \
doc/gcdescr.html \
doc/gcinterface.html \
doc/leak.html \
@ -47,3 +46,6 @@ dist_pkgdata_DATA = \
doc/scale.html \
doc/simple_example.html \
doc/tree.html
dist_man3_MANS = doc/gc.man
endif

View file

@ -1,4 +1,4 @@
.TH GC_MALLOC 1L "2 October 2003"
.TH BDWGC 3 "22 July 2018"
.SH NAME
GC_malloc, GC_malloc_atomic, GC_free, GC_realloc, GC_enable_incremental, GC_register_finalizer, GC_malloc_ignore_off_page, GC_malloc_atomic_ignore_off_page, GC_set_warn_proc \- Garbage collecting malloc replacement
.SH SYNOPSIS
@ -11,7 +11,7 @@ void GC_free(void *ptr);
void * GC_realloc(void *ptr, size_t size);
.br
.sp
cc ... gc.a
cc ... -lgc
.LP
.SH DESCRIPTION
.I GC_malloc
@ -91,7 +91,7 @@ Other facilities not discussed here include limited facilities to support increm
.SH "SEE ALSO"
The README and gc.h files in the distribution. More detailed definitions of the functions exported by the collector are given there. (The above list is not complete.)
.LP
The web site at http://www.hboehm.info/gc/ .
The web site at http://www.hboehm.info/gc/ (or https://github.com/ivmai/bdwgc/).
.LP
Boehm, H., and M. Weiser, "Garbage Collection in an Uncooperative Environment",
"Software Practice & Experience", September 1988, pp. 807-820.
@ -100,4 +100,4 @@ The malloc(3) man page.
.LP
.SH AUTHOR
Hans-J. Boehm (boehm@acm.org).
Some of the code was written by others, most notably Alan Demers.
Some of the code was written by others (see the AUTHORS file for the details), most notably by Alan Demers, and, recently, Ivan Maidanski.

View file

@ -92,8 +92,8 @@ One (<TT>STUBBORN</tt>) is immutable without special precautions.
In spite of that, it is very likely that most C clients of the
collector currently
use at most two kinds: <TT>NORMAL</tt> and <TT>PTRFREE</tt> objects.
The <A HREF="http://gcc.gnu.org/java">gcj</a> runtime also makes
heavy use of a kind (allocated with GC_gcj_malloc) that stores
The <A HREF="https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcj/">GCJ</a> runtime
also makes heavy use of a kind (allocated with GC_gcj_malloc) that stores
type information at a known offset in method tables.
<P>
The collector uses a two level allocator. A large block is defined to
@ -133,7 +133,7 @@ large block free list.
<P>
In order to avoid allocating blocks for too many distinct object sizes,
the collector normally does not directly allocate objects of every possible
request size. Instead request are rounded up to one of a smaller number
request size. Instead, the request is rounded up to one of a smaller number
of allocated sizes, for which free lists are maintained. The exact
allocated sizes are computed on demand, but subject to the constraint
that they increase roughly in geometric progression. Thus objects
@ -230,7 +230,7 @@ At the beginning of the mark phase, all root segments
(as described above) are pushed on the
stack by <TT>GC_push_roots</tt>. (Registers and eagerly processed
stack sections are processed by pushing the referenced objects instead
of the stack section itself.) If <TT>ALL_INTERIOR_PTRS</tt> is not
of the stack section itself.) If <TT>ALL_INTERIOR_POINTERS</tt> is not
defined, then stack roots require special treatment. In this case, the
normal marking code ignores interior pointers, but <TT>GC_push_all_stack</tt>
explicitly checks for interior pointers and pushes descriptors for target
@ -272,7 +272,7 @@ each call, so that it can also be used by the incremental collector.
It is fairly carefully tuned, since it usually consumes a large majority
of the garbage collection time.
<P>
The fact that it perform a only a small amount of work per call also
The fact that it performs only a small amount of work per call also
allows it to be used as the core routine of the parallel marker. In that
case it is normally invoked on thread-private mark stacks instead of the
global mark stack. More details can be found in
@ -471,6 +471,9 @@ catching write faults. This is
implemented for many Unix-like systems and for win32. It is not possible
in a few environments.
<LI>
(<TT>GWW_VDB</tt>) By using the Win32 GetWriteWatch function to read dirty
bits.
<LI>
(<TT>PROC_VDB</tt>) By retrieving dirty bit information from /proc.
(Currently only Sun's
Solaris supports this. Though this is considerably cleaner, performance
@ -489,9 +492,9 @@ the vast majority of objects use <TT>GC_malloc_stubborn</tt>.
The collector implements <I>black-listing</i> of pages, as described
in
<A HREF="http://www.acm.org/pubs/citations/proceedings/pldi/155090/p197-boehm/">
<A HREF="http://dl.acm.org/citation.cfm?doid=155090.155109">
Boehm, ``Space Efficient Conservative Collection'', PLDI '93</a>, also available
<A HREF="papers/pldi93.ps.Z">here</a>.
<A HREF="https://www.cs.rice.edu/~javaplt/311/Readings/pldi93.pdf">here</a>.
<P>
During the mark phase, the collector tracks ``near misses'', i.e. attempts
to follow a ``pointer'' to just outside the garbage-collected heap, or
@ -534,23 +537,16 @@ common Pthreads implementations.
In particular, it is very difficult for the collector to stop all other
threads in the system and examine the register contents. This is currently
accomplished with very different mechanisms for some Pthreads
implementations. The Solaris implementation temporarily disables much
of the user-level threads implementation by stopping kernel-level threads
("lwp"s). The Linux/HPUX/OSF1 and Irix implementations sends signals to
implementations. For Linux/HPUX/OSF1, Solaris and Irix it sends signals to
individual Pthreads and has them wait in the signal handler.
<P>
The Linux and Irix implementations use
only documented Pthreads calls, but rely on extensions to their semantics.
The Linux implementation <TT>linux_threads.c</tt> relies on only very
The Linux implementation <TT>pthread_stop_world.c</tt> relies on only very
mild extensions to the pthreads semantics, and already supports a large number
of other Unix-like pthreads implementations. Our goal is to make this the
only pthread support in the collector.
<P>
(The Irix implementation is separate only for historical reasons and should
clearly be merged. The current Solaris implementation probably performs
better in the uniprocessor case, but does not support thread operations in the
collector. Hence it cannot support the parallel marker.)
<P>
All implementations must
intercept thread creation and a few other thread-specific calls to allow
enumeration of threads and location of thread stacks. This is current
@ -617,12 +613,5 @@ For some more details see <A HREF="scale.html">here</a>, and the
technical report entitled
<A HREF="http://www.hpl.hp.com/techreports/2000/HPL-2000-165.html">
"Fast Multiprocessor Memory Allocation and Garbage Collection"</a>
<P>
<HR>
<P>
Comments are appreciated. Please send mail to
<A HREF="mailto:bdwgc@lists.opendylan.org"><tt>bdwgc@lists.opendylan.org</tt></a>
(GC mailing list) or
<A HREF="mailto:boehm@acm.org"><TT>boehm@acm.org</tt></a>
</body>
</html>

View file

@ -129,7 +129,7 @@ allocation is used (see
<A type="text/plain" HREF="../include/gc.h">gc.h</a>).
On many platforms this interacts poorly with system calls
that write to the garbage collected heap.
<DT> <B> GC_warn_proc GC_set_warn_proc(GC_warn_proc <I>p</i>) </b>
<DT> <B> void GC_set_warn_proc(GC_warn_proc <I>p</i>) </b>
<DD>
Replace the default procedure used by the collector to print warnings.
The collector

View file

@ -68,7 +68,7 @@ at least the file name and line number at the allocation point to
be saved as part of the object. Leak reports will then also include
this information.
<P>
Many collector features (<I>e.g</i> stubborn objects, finalization,
Many collector features (<I>e.g.</i> stubborn objects, finalization,
and disappearing links) are less useful in this context, and are not
fully supported. Their use will usually generate additional bogus
leak reports, since the collector itself drops some associated objects.

View file

@ -7,7 +7,7 @@
<td><a href="http://www.hboehm.info/gc/04tutorial.pdf">Tutorial Slides</a></td>
<td><a href="http://www.hboehm.info/gc/faq.html">FAQ</a></td>
<td><a href="simple_example.html">Example</a></td>
<td><a href="http://www.hboehm.info/gc/gc_source/">Download</a></td>
<td><a href="https://github.com/ivmai/bdwgc/wiki/Download">Download</a></td>
<td><a href="http://www.hboehm.info/gc/license.txt">License</a></td>
</tr>
</tbody></table>
@ -27,11 +27,10 @@
before that at
<tt>http://reality.sgi.com/boehm/gc.html</tt>
and before that at
<a href="ftp://ftp.parc.xerox.com/pub/gc/gc.html">
<tt>ftp://ftp.parc.xerox.com/pub/gc/gc.html</tt></a>. ]
<tt>ftp://ftp.parc.xerox.com/pub/gc/gc.html</tt>. ]
<p>
The <a href="http://www.hboehm.info">Boehm</a>-<a href="http://www.cs.cornell.edu/annual_report/00-01/bios.htm#demers">Demers</a>-<a href="http://www-sul.stanford.edu/weiser/">Weiser</a>
conservative garbage collector can
The <a href="http://www.hboehm.info">Boehm</a>-<a href="http://www.cs.cornell.edu/annual_report/00-01/bios.htm#demers">Demers</a>-<a href="http://www.ubiq.com/hypertext/weiser/weiser.html">Weiser</a>
conservative Garbage Collector (<b>BDWGC</b>) can
be used as a garbage collecting
replacement for C <tt>malloc</tt> or C++ <tt>new</tt>.
It allows you to allocate memory basically as you normally would,
@ -52,23 +51,14 @@ Alternatively, the garbage collector may be used as
a <a href="leak.html">leak detector</a>
for C or C++ programs, though that is not its primary goal.
</p><p>
Typically several versions will be available.
Usually you should first try to use
<a href="http://www.hboehm.info/gc/gc_source/gc.tar.gz"><tt>gc_source/gc.tar.gz</tt></a>,
which is normally an older, more stable version.
</p><p>
If that fails, try the latest explicitly numbered version
in <a href="http://www.hboehm.info/gc/gc_source/">
<tt>gc_source/</tt></a>.
Later versions may contain additional features, platform support,
or bug fixes, but are likely to be less well tested.
</p><p>
A slightly older version of the garbage collector is now also
included as part of the
<a href="http://gcc.gnu.org/">GNU compiler</a>
distribution. The source
code for that version is available for browsing
<a href="http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/boehm-gc/">here</a>.
Typically several versions are offered for
<a href="https://github.com/ivmai/bdwgc/wiki/Download">downloading</a>:
preview, stable, legacy.
Usually you should use the one marked as the <i>latest stable</i> release.
Preview versions may contain additional features, platform support,
but are likely to be less well tested.
The list of changes for each version is specified on the
<a href="https://github.com/ivmai/bdwgc/releases">releases</a> page.
</p><p>
The arguments for and against conservative garbage collection
in C and C++ are briefly
@ -110,8 +100,7 @@ HP/UX 11 pthreads, Tru64 pthreads, and MacOS X threads are supported
in recent versions.
</p><h3>Separately distributed ports</h3>
For MacOS 9/Classic use, Patrick Beard's latest port is available from
<a href="http://homepage.mac.com/pcbeard/gc/">
<tt>http://homepage.mac.com/pcbeard/gc/</tt></a>.
<tt>http://homepage.mac.com/pcbeard/gc/</tt>.
(Unfortunately, that's now quite dated.
I'm not in a position to test under MacOS. Although I try to
incorporate changes, it is impossible for
@ -124,7 +113,7 @@ Precompiled versions of the collector for NetBSD are available
versions of the collector.
</p><h2><a name="multiprocessors">Scalable multiprocessor versions</a></h2>
Kenjiro Taura, Toshio Endo, and Akinori Yonezawa have made available
a <a href="http://web.yl.is.s.u-tokyo.ac.jp/gc/">parallel collector</a>
a <a href="http://ieeexplore.ieee.org/abstract/document/1592629/">parallel collector</a>
based on this one. Their collector takes advantage of multiple processors
during a collection. Starting with collector version 6.0alpha1
we also do this, though with more modest processor scalability goals.
@ -265,7 +254,7 @@ Proceedings of the ACM SIGPLAN '96 Conference on Programming Language Design
and Implementation.
</p><p>
Boehm, H., and D. Chase, <a href="http://www.hboehm.info/gc/papers/boecha.ps.gz">"A Proposal for Garbage-Collector-Safe C Compilation"</a>,
<i>Journal of C Language Translation 4</i>, 2 (Decemeber 1992), pp. 126-141.
<i>Journal of C Language Translation 4</i>, 2 (December 1992), pp. 126-141.
</p><p>
<b>Other related information: </b>
</p><p>
@ -275,7 +264,9 @@ using programs written for malloc/free.
</p><p>
Joel Bartlett's <a href="ftp://gatekeeper.dec.com/pub/compaq/WRL/research-reports/WRL-TN-12.ps">mostly copying conservative garbage collector for C++</a>.
</p><p>
John Ellis and David Detlef's <a href="ftp://ftp.parc.xerox.com/pub/ellis/gc/gc.ps">Safe Efficient Garbage Collection for C++</a> proposal.
John Ellis and David Detlef's
<a href="http://dl.acm.org/citation.cfm?id=1267983">Safe Efficient Garbage Collection for C++</a>
proposal.
</p><p>
Henry Baker's <a href="http://home.pipeline.com/%7Ehbaker1/">paper collection</a>.
</p><p>
@ -283,7 +274,8 @@ Slides for Hans Boehm's <a href="http://www.hboehm.info/gc/myths.ps">Allocation
</p><h1><a name="users">Current users:</a></h1>
Known current users of some variant of this collector include:
<p>
The runtime system for <a href="http://gcc.gnu.org/java">GCJ</a>,
The runtime system for
<a href="https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcj/">GCJ</a>,
the static GNU java compiler.
</p><p>
<a href="http://w3m.sourceforge.net/">W3m</a>, a text-based web browser.
@ -335,11 +327,11 @@ research in algebraic geometry and commutative algebra.
The <a href="http://www.vestasys.org/">Vesta</a> configuration management
system.
</p><p>
<a href="http://www.visual-prolog.com/vip6">Visual Prolog 6</a>.
<a href="http://www.visual-prolog.com/">Visual Prolog 6</a>.
</p><p>
<a href="http://asymptote.sf.net/">Asymptote LaTeX-compatible
vector graphics language.</a>
</p><h1><a name="collector">More collector information at this site</a></h1>
</p><h1><a name="collector">More information on the BDWGC primary site</a></h1>
<a href="simple_example.html">A simple illustration of how to build and
use the collector</a>.
<p>
@ -362,8 +354,12 @@ garbage collector.</a>
</p><p>
<a href="scale.html">Scalability of the collector to multiprocessors.</a>
</p><p>
<a href="http://www.hboehm.info/gc/gc_source/">Directory containing garbage collector source</a>.
</p><h1><a name="background">More background information at this site</a></h1>
<a href="http://www.hboehm.info/gc/gc_source/">Directory</a> containing
the distribution files of all garbage collector releases.
It duplicates
<a href="https://github.com/ivmai/bdwgc/wiki/Download">Download</a> page on
GitHub.
</p><h1><a name="background">More background information</a></h1>
<a href="http://www.hboehm.info/gc/bounds.html">An attempt to establish a bound on space usage of
conservative garbage collectors</a>.
<p>
@ -398,37 +394,38 @@ Technical Report version</a>).
<a href="http://www.hboehm.info/gc/gctalk.ps">Slides for OOPSLA 98 garbage collection talk</a>.
</p><p>
<a href="http://www.hboehm.info/gc/papers/">Related papers</a>.
</p><h1><a name="contacts">Contacts and Mailing List</a></h1>
<a>We have recently set up two mailing list for collector announcements
and discussions:
</a><ul>
<li><a href="mailto:bdwgc-announce@lists.opendylan.org">bdwgc-announce@lists.opendylan.org</a>
is used for announcements of new versions. Postings are restricted.
We expect this to always remain a very low volume list.
</li><li><a href="mailto:bdwgc@lists.opendylan.org">bdwgc@lists.opendylan.org</a>
is used for discussions, bug reports, and the like. Subscribers may post.
On-topic posts by nonsubscribers will usually also be accepted, but
it may take some time to review them.
</li></ul>
To subscribe to these lists, please visit
<a href="https://lists.opendylan.org/mailman/listinfo/bdwgc-announce">lists.opendylan.org/mailman/listinfo/bdwgc-announce</a>
and
<a href="https://lists.opendylan.org/mailman/listinfo/bdwgc">lists.opendylan.org/mailman/listinfo/bdwgc</a>,
respectively.
</p><h1><a name="contacts">Contacts and new release announcements</a></h1>
GitHub and Stack Overflow are the major two places for communication.
<p>
The archives for these lists appear
<a href="https://lists.opendylan.org/pipermail/bdwgc-announce/">here</a> and
<a href="https://lists.opendylan.org/pipermail/bdwgc/">here</a>,
respectively.
Technical questions (how to, how does it work, etc.) should be posted to
<a href="https://stackoverflow.com/questions/tagged/boehm-gc">Stack Overflow</a>
with "boehm-gc" tag.
</p><p>
To contribute, please rebase your code to the latest
<a href="https://github.com/ivmai/bdwgc/tree/master/">master</a> and submit
a <a href="https://github.com/ivmai/bdwgc/pulls">pull request</a> to GitHub.
</p><p>
To report a bug, or propose (request) a new feature, create
a <a href="https://github.com/ivmai/bdwgc/issues">GitHub issue</a>.
Please make sure it has not been reported yet by someone else.
</p><p>
To receive notifications on every release, please subscribe to
<a href="https://github.com/ivmai/bdwgc/releases.atom">Releases RSS feed</a>.
Notifications on all issues and pull requests are available by
<a href="https://github.com/ivmai/bdwgc/watchers">watching</a> the project.
</p><p>
Mailing lists (bdwgc-announce@lists.opendylan.org, bdwgc@lists.opendylan.org,
and the former gc-announce@linux.hpl.hp.com and gc@linux.hpl.hp.com) are not
used at this moment. Their content is available in
<a href="https://github.com/ivmai/bdwgc/files/1037650/bdwgc-announce-mailing-list-archive-2014_02.tar.gz">bdwgc-announce</a>
and
<a href="https://github.com/ivmai/bdwgc/files/1038163/bdwgc-mailing-list-archive-2017_04.tar.gz">bdwgc</a>
archive files, respectively.
The gc list archive may also be read at
<a href="http://dir.gmane.org/gmane.comp.programming.garbage-collection.boehmgc">gmane.org</a>.
<a href="http://bdwgc.opendylan.narkive.com">Narkive</a>.
</p><p>
Some prior discussion of the collector has taken place on the gcc
java mailing list, whose archives appear
<a href="http://gcc.gnu.org/ml/java/">here</a>, and also on
<a href="http://lists.tunes.org/mailman/listinfo/gclist">gclist@iecc.com</a>.
</p><p>
Comments and bug reports may also be sent to
(<a href="mailto:boehm@acm.org">boehm@acm.org</a>), but the gc
mailing list is usually preferred.
</p></body></html>

View file

@ -131,7 +131,7 @@ should be defined to the limits of the second main data segment.
<DD>
Should be defined if the stack (or thread stacks) grow towards higher
addresses. (This appears to be true only on PA-RISC. If your architecture
has more than one stack per thread, and is not already supported, you will
has more than one stack per thread, and is not supported yet, you will
need to do more work. Grep for "IA64" in the source for an example.)
<DT><TT>STACKBOTTOM</tt>
<DD>
@ -166,7 +166,7 @@ The cold end of the stack is determined by taking an address inside
GC_init's frame, incrementing it repeatedly
in small steps (decrement if <TT>STACK_GROWS_UP</tt>), and reading the value
at each location. We remember the value when the first
Segmentation violation or Bus error is signalled, round that
Segmentation violation or Bus error is signaled, round that
to the nearest plausible page boundary, and use that as the
stack base.
<DT><TT>DYNAMIC_LOADING</tt>
@ -181,7 +181,7 @@ allows incremental/generational garbage collection.
<TT>MPROTECT_VDB</tt> identifies modified pages by
write protecting the heap and catching faults.
<TT>PROC_VDB</tt> uses the /proc primitives to read dirty bits.
<DT><TT>PREFETCH, PREFETCH_FOR_WRITE</tt>
<DT><TT>PREFETCH, GC_PREFETCH_FOR_WRITE</tt>
<DD>
The collector uses <TT>PREFETCH</tt>(<I>x</i>) to preload the cache
with *<I>x</i>.
@ -196,12 +196,6 @@ word stores of 0 are used instead.
<DD>
<TT>HEAP_START</tt> may be defined as the initial address hint for mmap-based
allocation.
<DT><TT>ALIGN_DOUBLE</tt>
<DD>
Should be defined if the architecture requires double-word alignment
of <TT>GC_malloc</tt>ed memory, e.g. 8-byte alignment with a
32-bit ABI. Most modern machines are likely to require this.
This is no longer needed for GC7 and later.
</dl>
<H2>Additional requirements for a basic port</h2>
In some cases, you may have to add additional platform-specific code
@ -214,7 +208,7 @@ tweaking of conditional compilation tests.
<P>
For GC7, if your platform supports <TT>getcontext()</tt>, then defining
the macro <TT>UNIX_LIKE</tt> for your OS in <TT>gcconfig.h</tt>
(if it isn't defined there already) is likely to solve the problem.
(if it isn't defined there yet) is likely to solve the problem.
otherwise, if you are using gcc, <TT>_builtin_unwind_init()</tt>
will be used, and should work fine. If that is not applicable either,
the implementation will try to use <TT>setjmp()</tt>. This will work if your

View file

@ -64,23 +64,12 @@ locking. The thread-local free lists are refilled using
<TT>GC_malloc_many</tt>.
<P>
An important side effect of this flag is to replace the default
spin-then-sleep lock to be replace by a spin-then-queue based implementation.
spin-then-sleep lock to be replaced by a spin-then-queue based implementation.
This <I>reduces performance</i> for the standard allocation functions,
though it usually improves performance when thread-local allocation is
used heavily, and thus the number of short-duration lock acquisitions
is greatly reduced.
</ul>
<P>
The easiest way to switch an application to thread-local allocation
in a pre-version-7.0 collector was to
<OL>
<LI> Define the macro <TT>GC_REDIRECT_TO_LOCAL</tt>,
and then include the <TT>gc.h</tt>
header in each client source file.
<LI> Invoke <TT>GC_thr_init()</tt> before any allocation.
<LI> Allocate using <TT>GC_MALLOC</tt>, <TT>GC_MALLOC_ATOMIC</tt>,
and/or <TT>GC_GCJ_MALLOC</tt>.
</ol>
<H2>The Parallel Marking Algorithm</h2>
We use an algorithm similar to
<A HREF="http://www.yl.is.s.u-tokyo.ac.jp/gc/">that developed by
@ -145,7 +134,7 @@ Running with a thread-unsafe collector, the benchmark ran in 9
seconds. With the simple thread-safe collector,
built with <TT>-DLINUX_THREADS</tt>, the execution time
increased to 10.3 seconds, or 23.5 elapsed seconds with two clients.
(The times for the <TT>malloc</tt>/i<TT>free</tt> version
(The times for the <TT>malloc</tt>/<TT>free</tt> version
with glibc <TT>malloc</tt>
are 10.51 (standard library, pthreads not linked),
20.90 (one thread, pthreads linked),
@ -167,7 +156,7 @@ avoided in time-critical code.
directly for allocation locking would have been worse still, at
least for older versions of linuxthreads.
With THREAD_LOCAL_ALLOC, we first repeatedly try to acquire the
lock with pthread_mutex_try_lock(), busy_waiting between attempts.
lock with pthread_mutex_try_lock(), busy-waiting between attempts.
After a fixed number of attempts, we use pthread_mutex_lock().)
<P>
These measurements do not use incremental collection, nor was prefetching

View file

@ -12,7 +12,7 @@ a single-threaded application. <FONT COLOR=green>The green
text contains information about other platforms or scenarios.
It can be skipped, especially on first reading</font>.
<H2>Building the collector</h2>
If you haven't already so, unpack the collector and enter
If you have not so yet, unpack the collector and enter
the newly created directory with
<PRE>
tar xvfz gc&lt;version&gt;.tar.gz
@ -55,7 +55,7 @@ strong preference of the would-be maintainer of those project files.)
If you need thread support, configure the collector with
</font>
<PRE style="color:green">
--enable-threads=posix --enable-thread-local-alloc --enable-parallel-mark
--enable-threads=posix --enable-parallel-mark
</pre>
<FONT COLOR=green>
instead of
@ -143,22 +143,6 @@ should first define the macro <TT>GC_THREADS</tt>, and then
include <TT>"gc.h"</tt>. On some platforms this will redefine some
threads primitives, e.g. to let the collector keep track of thread creation.
</font>
<LI>
<FONT COLOR=green>
To take advantage of fast thread-local allocation in versions before 7.0,
use the following instead
of including <TT>gc.h</tt>:
</font>
<PRE style="color:green">
#define GC_REDIRECT_TO_LOCAL
#include "gc_local_alloc.h"
</pre>
<FONT COLOR=green>
This will cause GC_MALLOC and GC_MALLOC_ATOMIC to keep per-thread allocation
caches, and greatly reduce the number of lock acquisitions during allocation.
For versions after 7.0, this happens implicitly if the collector is built
with thread-local allocation enabled.
</font>
</ul>
<H3><FONT COLOR=green>C++</font></h3>

View file

@ -185,7 +185,7 @@ freed; free lists are used (e.g. alloc_hdr). HBLK's below are collected.
HBLKSIZE | |--------------- | (words)
(bytes) | | v MAX_OFFSET
| + - - - - - - - - - - -+ --- (bytes)
| | | !All_INTERIOR_PTRS ^ |
| | | !ALL_INTERIOR_POINTERS ^ |
| | | sets j only for hb_sz |
| | Object N | valid object offsets. | |
v | | All objects WORDSZ v v

View file

@ -52,18 +52,18 @@ STATIC GC_has_static_roots_func GC_has_static_roots = 0;
#if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
|| defined(CYGWIN32)) && !defined(PCR)
#if !defined(SOLARISDL) && !defined(IRIX5) && \
!defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) && \
!(defined(ALPHA) && defined(OSF1)) && \
!defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
!defined(AIX) && !defined(SCO_ELF) && !defined(DGUX) && \
!(defined(FREEBSD) && defined(__ELF__)) && \
!(defined(OPENBSD) && (defined(__ELF__) || defined(M68K))) && \
!(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) && \
!defined(DARWIN) && !defined(CYGWIN32)
--> We only know how to find data segments of dynamic libraries for the
--> above. Additional SVR4 variants might not be too
--> hard to add.
#if !defined(DARWIN) && !defined(SCO_ELF) && !defined(SOLARISDL) \
&& !defined(AIX) && !defined(DGUX) && !defined(IRIX5) && !defined(HPUX) \
&& !defined(CYGWIN32) && !defined(MSWIN32) && !defined(MSWINCE) \
&& !(defined(ALPHA) && defined(OSF1)) \
&& !(defined(FREEBSD) && defined(__ELF__)) \
&& !((defined(LINUX) || defined(NACL)) && defined(__ELF__)) \
&& !(defined(NETBSD) && defined(__ELF__)) \
&& !defined(HAIKU) && !defined(HURD) \
&& !(defined(OPENBSD) && (defined(__ELF__) || defined(M68K))) \
&& !defined(CPPCHECK)
# error We only know how to find data segments of dynamic libraries for above.
# error Additional SVR4 variants might not be too hard to add.
#endif
#include <stdio.h>
@ -82,14 +82,15 @@ STATIC GC_has_static_roots_func GC_has_static_roots = 0;
#if defined(OPENBSD)
# include <sys/param.h>
# if OpenBSD >= 200519
# if (OpenBSD >= 200519) && !defined(HAVE_DL_ITERATE_PHDR)
# define HAVE_DL_ITERATE_PHDR
# endif
#endif /* OPENBSD */
#if defined(SCO_ELF) || defined(DGUX) || defined(HURD) \
|| (defined(__ELF__) && (defined(LINUX) || defined(FREEBSD) \
|| defined(NETBSD) || defined(OPENBSD)))
|| defined(NACL) || defined(NETBSD) \
|| defined(OPENBSD)))
# include <stddef.h>
# if !defined(OPENBSD) && !defined(PLATFORM_ANDROID)
/* OpenBSD does not have elf.h file; link.h below is sufficient. */
@ -109,9 +110,9 @@ STATIC GC_has_static_roots_func GC_has_static_roots = 0;
# undef EM_ALPHA
# endif
# include <link.h>
# if !defined(GC_DONT_DEFINE_LINK_MAP)
/* link_map and r_debug should be defined explicitly, */
/* as only bionic/linker/linker.h defines them but the header */
# if !defined(GC_DONT_DEFINE_LINK_MAP) && !(__ANDROID_API__ >= 21)
/* link_map and r_debug are defined in link.h of NDK r10+. */
/* bionic/linker/linker.h defines them too but the header */
/* itself is a C++ one starting from Android 4.3. */
struct link_map {
uintptr_t l_addr;
@ -179,23 +180,26 @@ GC_FirstDLOpenedLinkMap(void)
/* at program startup. */
if( dynStructureAddr == 0 ) {
void* startupSyms = dlopen(0, RTLD_LAZY);
dynStructureAddr = (ElfW(Dyn)*)dlsym(startupSyms, "_DYNAMIC");
dynStructureAddr = (ElfW(Dyn)*)(word)dlsym(startupSyms, "_DYNAMIC");
}
# else
dynStructureAddr = &_DYNAMIC;
# endif
if (dynStructureAddr == 0) {
if (0 == COVERT_DATAFLOW(dynStructureAddr)) {
/* _DYNAMIC symbol not resolved. */
return(0);
}
if( cachedResult == 0 ) {
if (cachedResult == 0) {
int tag;
for( dp = ((ElfW(Dyn) *)(&_DYNAMIC)); (tag = dp->d_tag) != 0; dp++ ) {
if( tag == DT_DEBUG ) {
struct link_map *lm
= ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
if( lm != 0 ) cachedResult = lm->l_next; /* might be NULL */
if (tag == DT_DEBUG) {
struct r_debug *rd = (struct r_debug *)dp->d_un.d_ptr;
if (rd != NULL) {
struct link_map *lm = rd->r_map;
if (lm != NULL)
cachedResult = lm->l_next; /* might be NULL */
}
break;
}
}
@ -213,8 +217,9 @@ GC_FirstDLOpenedLinkMap(void)
# if defined(SOLARISDL)
/* Add dynamic library data sections to the root set. */
# if !defined(PCR) && !defined(GC_SOLARIS_THREADS) && defined(THREADS)
--> fix mutual exclusion with dlopen
# if !defined(PCR) && !defined(GC_SOLARIS_THREADS) && defined(THREADS) \
&& !defined(CPPCHECK)
# error Fix mutual exclusion with dlopen
# endif
# ifndef USE_PROC_FOR_LIBRARIES
@ -257,7 +262,8 @@ GC_INNER void GC_register_dynamic_libraries(void)
#if defined(SCO_ELF) || defined(DGUX) || defined(HURD) \
|| (defined(__ELF__) && (defined(LINUX) || defined(FREEBSD) \
|| defined(NETBSD) || defined(OPENBSD)))
|| defined(NACL) || defined(NETBSD) \
|| defined(OPENBSD)))
#ifdef USE_PROC_FOR_LIBRARIES
@ -279,9 +285,10 @@ static void sort_heap_sects(struct HeapSect *base, size_t number_of_elements)
{
signed_word n = (signed_word)number_of_elements;
signed_word nsorted = 1;
signed_word i;
while (nsorted < n) {
signed_word i;
while (nsorted < n &&
(word)base[nsorted-1].hs_start < (word)base[nsorted].hs_start)
++nsorted;
@ -299,7 +306,7 @@ static void sort_heap_sects(struct HeapSect *base, size_t number_of_elements)
}
}
STATIC word GC_register_map_entries(char *maps)
STATIC void GC_register_map_entries(char *maps)
{
char *prot;
char *buf_ptr = maps;
@ -307,19 +314,6 @@ STATIC word GC_register_map_entries(char *maps)
unsigned int maj_dev;
ptr_t least_ha, greatest_ha;
unsigned i;
ptr_t datastart;
# ifdef DATASTART_IS_FUNC
static ptr_t datastart_cached = (ptr_t)(word)-1;
/* Evaluate DATASTART only once. */
if (datastart_cached == (ptr_t)(word)-1) {
datastart_cached = (ptr_t)(DATASTART);
}
datastart = datastart_cached;
# else
datastart = (ptr_t)(DATASTART);
# endif
GC_ASSERT(I_HOLD_LOCK());
sort_heap_sects(GC_our_memory, GC_n_memory);
@ -330,7 +324,8 @@ STATIC word GC_register_map_entries(char *maps)
for (;;) {
buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, &prot,
&maj_dev, 0);
if (buf_ptr == NULL) return 1;
if (NULL == buf_ptr)
break;
if (prot[1] == 'w') {
/* This is a writable mapping. Add it to */
/* the root set unless it is already otherwise */
@ -395,15 +390,21 @@ STATIC word GC_register_map_entries(char *maps)
}
if ((word)start < (word)end)
GC_add_roots_inner((char *)start, (char *)end, TRUE);
} else if (prot[0] == '-' && prot[1] == '-' && prot[2] == '-') {
/* Even roots added statically might disappear partially */
/* (e.g. the roots added by INCLUDE_LINUX_THREAD_DESCR). */
GC_remove_roots_subregion(start, end);
}
}
return 1;
}
GC_INNER void GC_register_dynamic_libraries(void)
{
if (!GC_register_map_entries(GC_get_maps()))
char *maps = GC_get_maps();
if (NULL == maps)
ABORT("Failed to read /proc for library registration");
GC_register_map_entries(maps);
}
/* We now take care of the main data segment ourselves: */
@ -423,23 +424,28 @@ GC_INNER GC_bool GC_register_main_static_data(void)
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
|| (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)) \
|| defined(PLATFORM_ANDROID) /* Are others OK here, too? */
/* We have the header files for a glibc that includes dl_iterate_phdr. */
/* It may still not be available in the library on the target system. */
/* Thus we also treat it as a weak symbol. */
# define HAVE_DL_ITERATE_PHDR
# ifndef HAVE_DL_ITERATE_PHDR
# define HAVE_DL_ITERATE_PHDR
# endif
# ifdef PLATFORM_ANDROID
/* Android headers might have no such definition for some targets. */
int dl_iterate_phdr(int (*cb)(struct dl_phdr_info *, size_t, void *),
void *data);
# endif
# pragma weak dl_iterate_phdr
#endif
#endif /* __GLIBC__ >= 2 || PLATFORM_ANDROID */
#if (defined(FREEBSD) && __FreeBSD__ >= 7)
#if (defined(FREEBSD) && __FreeBSD__ >= 7) || defined(__DragonFly__)
/* On the FreeBSD system, any target system at major version 7 shall */
/* have dl_iterate_phdr; therefore, we need not make it weak as above. */
# define HAVE_DL_ITERATE_PHDR
/* have dl_iterate_phdr; therefore, we need not make it weak as below. */
# ifndef HAVE_DL_ITERATE_PHDR
# define HAVE_DL_ITERATE_PHDR
# endif
# define DL_ITERATE_PHDR_STRONG
#elif defined(HAVE_DL_ITERATE_PHDR)
/* We have the header files for a glibc that includes dl_iterate_phdr.*/
/* It may still not be available in the library on the target system. */
/* Thus we also treat it as a weak symbol. */
# pragma weak dl_iterate_phdr
#endif
#if defined(HAVE_DL_ITERATE_PHDR)
@ -464,6 +470,7 @@ GC_INNER GC_bool GC_register_main_static_data(void)
} load_segs[MAX_LOAD_SEGS];
static int n_load_segs;
static GC_bool load_segs_overflow;
# endif /* PT_GNU_RELRO */
STATIC int GC_register_dynlib_callback(struct dl_phdr_info * info,
@ -479,75 +486,80 @@ STATIC int GC_register_dynlib_callback(struct dl_phdr_info * info,
return -1;
p = info->dlpi_phdr;
for( i = 0; i < (int)info->dlpi_phnum; i++, p++ ) {
switch( p->p_type ) {
for (i = 0; i < (int)info->dlpi_phnum; i++, p++) {
if (p->p_type == PT_LOAD) {
GC_has_static_roots_func callback = GC_has_static_roots;
if ((p->p_flags & PF_W) == 0) continue;
start = (ptr_t)p->p_vaddr + info->dlpi_addr;
end = start + p->p_memsz;
if (callback != 0 && !callback(info->dlpi_name, start, p->p_memsz))
continue;
# ifdef PT_GNU_RELRO
case PT_GNU_RELRO:
/* This entry is known to be constant and will eventually be remapped
read-only. However, the address range covered by this entry is
typically a subset of a previously encountered "LOAD" segment, so
we need to exclude it. */
{
int j;
start = ((ptr_t)(p->p_vaddr)) + info->dlpi_addr;
end = start + p->p_memsz;
for (j = n_load_segs; --j >= 0; ) {
if ((word)start >= (word)load_segs[j].start
&& (word)start < (word)load_segs[j].end) {
if (load_segs[j].start2 != 0) {
WARN("More than one GNU_RELRO segment per load seg\n",0);
} else {
GC_ASSERT((word)end <= (word)load_segs[j].end);
/* Remove from the existing load segment */
load_segs[j].end2 = load_segs[j].end;
load_segs[j].end = start;
load_segs[j].start2 = end;
}
break;
}
if (j == 0) WARN("Failed to find PT_GNU_RELRO segment"
" inside PT_LOAD region", 0);
}
# if CPP_WORDSZ == 64
/* TODO: GC_push_all eventually does the correct */
/* rounding to the next multiple of ALIGNMENT, so, most */
/* probably, we should remove the corresponding assertion */
/* check in GC_add_roots_inner along with this code line. */
/* start pointer value may require aligning. */
start = (ptr_t)((word)start & ~(word)(sizeof(word) - 1));
# endif
if (n_load_segs >= MAX_LOAD_SEGS) {
if (!load_segs_overflow) {
WARN("Too many PT_LOAD segments;"
" registering as roots directly...\n", 0);
load_segs_overflow = TRUE;
}
GC_add_roots_inner(start, end, TRUE);
} else {
load_segs[n_load_segs].start = start;
load_segs[n_load_segs].end = end;
load_segs[n_load_segs].start2 = 0;
load_segs[n_load_segs].end2 = 0;
++n_load_segs;
}
break;
# endif
case PT_LOAD:
{
GC_has_static_roots_func callback = GC_has_static_roots;
if( !(p->p_flags & PF_W) ) break;
start = ((char *)(p->p_vaddr)) + info->dlpi_addr;
end = start + p->p_memsz;
if (callback != 0 && !callback(info->dlpi_name, start, p->p_memsz))
break;
# ifdef PT_GNU_RELRO
if (n_load_segs >= MAX_LOAD_SEGS) ABORT("Too many PT_LOAD segs");
# if CPP_WORDSZ == 64
/* FIXME: GC_push_all eventually does the correct */
/* rounding to the next multiple of ALIGNMENT, so, most */
/* probably, we should remove the corresponding assertion */
/* check in GC_add_roots_inner along with this code line. */
/* start pointer value may require aligning */
start = (ptr_t)((word)start & ~(sizeof(word) - 1));
# endif
load_segs[n_load_segs].start = start;
load_segs[n_load_segs].end = end;
load_segs[n_load_segs].start2 = 0;
load_segs[n_load_segs].end2 = 0;
++n_load_segs;
# else
GC_add_roots_inner(start, end, TRUE);
# endif /* PT_GNU_RELRO */
}
break;
default:
break;
# else
GC_add_roots_inner(start, end, TRUE);
# endif /* !PT_GNU_RELRO */
}
}
# ifdef PT_GNU_RELRO
p = info->dlpi_phdr;
for (i = 0; i < (int)info->dlpi_phnum; i++, p++) {
if (p->p_type == PT_GNU_RELRO) {
/* This entry is known to be constant and will eventually be */
/* remapped as read-only. However, the address range covered */
/* by this entry is typically a subset of a previously */
/* encountered "LOAD" segment, so we need to exclude it. */
int j;
start = (ptr_t)p->p_vaddr + info->dlpi_addr;
end = start + p->p_memsz;
for (j = n_load_segs; --j >= 0; ) {
if ((word)start >= (word)load_segs[j].start
&& (word)start < (word)load_segs[j].end) {
if (load_segs[j].start2 != 0) {
WARN("More than one GNU_RELRO segment per load one\n",0);
} else {
GC_ASSERT((word)end <= (word)load_segs[j].end);
/* Remove from the existing load segment */
load_segs[j].end2 = load_segs[j].end;
load_segs[j].end = start;
load_segs[j].start2 = end;
}
break;
}
if (0 == j && 0 == GC_has_static_roots)
WARN("Failed to find PT_GNU_RELRO segment"
" inside PT_LOAD region\n", 0);
/* No warning reported in case of the callback is present */
/* because most likely the segment has been excluded. */
}
}
}
# endif
*(int *)ptr = 1; /* Signal that we were called */
return 0;
}
@ -560,7 +572,7 @@ GC_INNER GC_bool GC_register_main_static_data(void)
/* zero (otherwise a compiler might issue a warning). */
return FALSE;
# else
return (dl_iterate_phdr == 0); /* implicit conversion to function ptr */
return 0 == COVERT_DATAFLOW(dl_iterate_phdr);
# endif
}
@ -575,6 +587,7 @@ STATIC GC_bool GC_register_dynamic_libraries_dl_iterate_phdr(void)
{
static GC_bool excluded_segs = FALSE;
n_load_segs = 0;
load_segs_overflow = FALSE;
if (!EXPECT(excluded_segs, TRUE)) {
GC_exclude_static_roots_inner((ptr_t)load_segs,
(ptr_t)load_segs + sizeof(load_segs));
@ -606,7 +619,7 @@ STATIC GC_bool GC_register_dynamic_libraries_dl_iterate_phdr(void)
/* Evaluate DATASTART only once. */
if (datastart_cached == (ptr_t)(word)-1) {
datastart_cached = (ptr_t)(DATASTART);
datastart_cached = DATASTART;
}
datastart = (char *)datastart_cached;
# else
@ -617,19 +630,29 @@ STATIC GC_bool GC_register_dynamic_libraries_dl_iterate_phdr(void)
static ptr_t dataend_cached = 0;
/* Evaluate DATAEND only once. */
if (dataend_cached == 0) {
dataend_cached = (ptr_t)(DATAEND);
dataend_cached = DATAEND;
}
dataend = (char *)dataend_cached;
}
# else
dataend = DATAEND;
# endif
if (NULL == *(char * volatile *)&datastart
|| (word)datastart > (word)dataend)
ABORT_ARG2("Wrong DATASTART/END pair",
": %p .. %p", (void *)datastart, (void *)dataend);
/* dl_iterate_phdr may forget the static data segment in */
/* statically linked executables. */
GC_add_roots_inner(datastart, dataend, TRUE);
# if defined(DATASTART2)
GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), TRUE);
# ifdef GC_HAVE_DATAREGION2
if ((word)DATASTART2 - 1U >= (word)DATAEND2) {
/* Subtract one to check also for NULL */
/* without a compiler warning. */
ABORT_ARG2("Wrong DATASTART/END2 pair",
": %p .. %p", (void *)DATASTART2, (void *)DATAEND2);
}
GC_add_roots_inner(DATASTART2, DATAEND2, TRUE);
# endif
}
return TRUE;
@ -677,17 +700,21 @@ extern ElfW(Dyn) _DYNAMIC[];
STATIC struct link_map *
GC_FirstDLOpenedLinkMap(void)
{
ElfW(Dyn) *dp;
static struct link_map *cachedResult = 0;
if (0 == (ptr_t)_DYNAMIC) {
if (0 == COVERT_DATAFLOW(_DYNAMIC)) {
/* _DYNAMIC symbol not resolved. */
return(0);
}
if( cachedResult == 0 ) {
# if defined(NETBSD) && defined(RTLD_DI_LINKMAP)
# if defined(CPPCHECK)
# define GC_RTLD_DI_LINKMAP 2
# else
# define GC_RTLD_DI_LINKMAP RTLD_DI_LINKMAP
# endif
struct link_map *lm = NULL;
if (!dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &lm) && lm != NULL) {
if (!dlinfo(RTLD_SELF, GC_RTLD_DI_LINKMAP, &lm) && lm != NULL) {
/* Now lm points link_map object of libgc. Since it */
/* might not be the first dynamically linked object, */
/* try to find it (object next to the main object). */
@ -697,12 +724,18 @@ GC_FirstDLOpenedLinkMap(void)
cachedResult = lm->l_next;
}
# else
ElfW(Dyn) *dp;
int tag;
for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
if( tag == DT_DEBUG ) {
struct link_map *lm
= ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
if( lm != 0 ) cachedResult = lm->l_next; /* might be NULL */
if (tag == DT_DEBUG) {
struct r_debug *rd = (struct r_debug *)dp->d_un.d_ptr;
/* d_ptr could be null if libs are linked statically. */
if (rd != NULL) {
struct link_map *lm = rd->r_map;
if (lm != NULL)
cachedResult = lm->l_next; /* might be NULL */
}
break;
}
}
@ -776,7 +809,7 @@ GC_INNER void GC_register_dynamic_libraries(void)
char buf[30];
static prmap_t * addr_map = 0;
static int current_sz = 0; /* Number of records currently in addr_map */
static int needed_sz; /* Required size of addr_map */
int needed_sz = 0; /* Required size of addr_map */
int i;
long flags;
ptr_t start;
@ -803,17 +836,19 @@ GC_INNER void GC_register_dynamic_libraries(void)
": fd = %d, errno = %d", fd, errno);
}
if (needed_sz >= current_sz) {
GC_scratch_recycle_no_gww(addr_map,
(size_t)current_sz * sizeof(prmap_t));
current_sz = needed_sz * 2 + 1;
/* Expansion, plus room for 0 record */
addr_map = (prmap_t *)GC_scratch_alloc(
(word)current_sz * sizeof(prmap_t));
(size_t)current_sz * sizeof(prmap_t));
if (addr_map == NULL)
ABORT("Insufficient memory for address map");
}
if (ioctl(fd, PIOCMAP, addr_map) < 0) {
ABORT_ARG3("/proc PIOCMAP ioctl failed",
": errcode= %d, needed_sz= %d, addr_map= %p",
errno, needed_sz, addr_map);
errno, needed_sz, (void *)addr_map);
};
if (GC_n_heap_sects > 0) {
heap_end = GC_heap_sects[GC_n_heap_sects-1].hs_start
@ -913,7 +948,7 @@ GC_INNER void GC_register_dynamic_libraries(void)
# else
char * stack_top
= (char *)((word)GC_approx_sp() &
~(GC_sysinfo.dwAllocationGranularity - 1));
~(word)(GC_sysinfo.dwAllocationGranularity - 1));
if (base == limit) return;
if ((word)limit > (word)stack_top
@ -964,7 +999,6 @@ GC_INNER void GC_register_dynamic_libraries(void)
GC_INNER void GC_register_dynamic_libraries(void)
{
MEMORY_BASIC_INFORMATION buf;
size_t result;
DWORD protect;
LPVOID p;
char * base;
@ -975,7 +1009,8 @@ GC_INNER void GC_register_dynamic_libraries(void)
# endif
base = limit = p = GC_sysinfo.lpMinimumApplicationAddress;
while ((word)p < (word)GC_sysinfo.lpMaximumApplicationAddress) {
result = VirtualQuery(p, &buf, sizeof(buf));
size_t result = VirtualQuery(p, &buf, sizeof(buf));
# ifdef MSWINCE
if (result == 0) {
/* Page is free; advance to the next possible allocation base */
@ -992,7 +1027,9 @@ GC_INNER void GC_register_dynamic_libraries(void)
protect = buf.Protect;
if (buf.State == MEM_COMMIT
&& (protect == PAGE_EXECUTE_READWRITE
|| protect == PAGE_READWRITE)
|| protect == PAGE_EXECUTE_WRITECOPY
|| protect == PAGE_READWRITE
|| protect == PAGE_WRITECOPY)
&& (buf.Type == MEM_IMAGE
# ifdef GC_REGISTER_MEM_PRIVATE
|| (protect == PAGE_READWRITE && buf.Type == MEM_PRIVATE)
@ -1033,29 +1070,18 @@ extern int errno;
GC_INNER void GC_register_dynamic_libraries(void)
{
int status;
ldr_process_t mypid;
/* module */
ldr_module_t moduleid = LDR_NULL_MODULE;
ldr_module_info_t moduleinfo;
size_t moduleinfosize = sizeof(moduleinfo);
size_t modulereturnsize;
/* region */
ldr_region_t region;
ldr_region_info_t regioninfo;
size_t regioninfosize = sizeof(regioninfo);
size_t regionreturnsize;
/* Obtain id of this process */
mypid = ldr_my_process();
ldr_module_t moduleid = LDR_NULL_MODULE;
ldr_process_t mypid = ldr_my_process(); /* obtain id of this process */
/* For each module */
while (TRUE) {
/* Get the next (first) module */
status = ldr_next_module(mypid, &moduleid);
ldr_module_info_t moduleinfo;
size_t modulereturnsize;
ldr_region_t region;
ldr_region_info_t regioninfo;
size_t regionreturnsize;
int status = ldr_next_module(mypid, &moduleid);
/* Get the next (first) module */
/* Any more modules? */
if (moduleid == LDR_NULL_MODULE)
@ -1071,7 +1097,7 @@ GC_INNER void GC_register_dynamic_libraries(void)
/* Get the module information */
status = ldr_inq_module(mypid, moduleid, &moduleinfo,
moduleinfosize, &modulereturnsize);
sizeof(moduleinfo), &modulereturnsize);
if (status != 0 )
ABORT("ldr_inq_module failed");
@ -1091,7 +1117,7 @@ GC_INNER void GC_register_dynamic_libraries(void)
for (region = 0; region < moduleinfo.lmi_nregion; region++) {
/* Get the region information */
status = ldr_inq_region(mypid, moduleid, region, &regioninfo,
regioninfosize, &regionreturnsize);
sizeof(regioninfo), &regionreturnsize);
if (status != 0 )
ABORT("ldr_inq_region failed");
@ -1131,15 +1157,13 @@ extern int sys_nerr;
GC_INNER void GC_register_dynamic_libraries(void)
{
int status;
int index = 1; /* Ordinal position in shared library search list */
struct shl_descriptor *shl_desc; /* Shared library info, see dl.h */
/* For each dynamic library loaded */
while (TRUE) {
/* Get info about next shared library */
status = shl_get(index, &shl_desc);
struct shl_descriptor *shl_desc; /* Shared library info, see dl.h */
int status = shl_get(index, &shl_desc);
/* Get info about next shared library */
/* Check if this is the end of the list or if some error occurred */
if (status != 0) {
@ -1186,18 +1210,24 @@ GC_INNER void GC_register_dynamic_libraries(void)
# include <sys/errno.h>
GC_INNER void GC_register_dynamic_libraries(void)
{
int ldibuflen = 8192;
for (;;) {
int len;
char *ldibuf;
int ldibuflen;
struct ld_info *ldi;
# if defined(CPPCHECK)
char ldibuf[ldibuflen];
# else
char *ldibuf = alloca(ldibuflen);
# endif
ldibuf = alloca(ldibuflen = 8192);
while ( (len = loadquery(L_GETINFO,ldibuf,ldibuflen)) < 0) {
len = loadquery(L_GETINFO, ldibuf, ldibuflen);
if (len < 0) {
if (errno != ENOMEM) {
ABORT("loadquery failed");
}
ldibuf = alloca(ldibuflen *= 2);
ldibuflen *= 2;
continue;
}
ldi = (struct ld_info *)ldibuf;
@ -1210,6 +1240,8 @@ GC_INNER void GC_register_dynamic_libraries(void)
TRUE);
ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
}
break;
}
}
#endif /* AIX */
@ -1282,8 +1314,6 @@ STATIC void GC_dyld_image_add(const struct GC_MACH_HEADER *hdr,
const struct GC_MACH_SECTION *sec;
const char *name;
GC_has_static_roots_func callback = GC_has_static_roots;
char secnam[16];
const char *fmt;
DCL_LOCK_STATE;
if (GC_no_dls) return;
@ -1315,9 +1345,12 @@ STATIC void GC_dyld_image_add(const struct GC_MACH_HEADER *hdr,
/* Sections constructed on demand. */
for (j = 0; j < sizeof(GC_dyld_add_sect_fmts) / sizeof(char *); j++) {
fmt = GC_dyld_add_sect_fmts[j];
const char *fmt = GC_dyld_add_sect_fmts[j];
/* Add our manufactured aligned BSS sections. */
for (i = 0; i <= L2_MAX_OFILE_ALIGNMENT; i++) {
char secnam[16];
(void)snprintf(secnam, sizeof(secnam), fmt, (unsigned)i);
secnam[sizeof(secnam) - 1] = '\0';
sec = GC_GETSECTBYNAME(hdr, SEG_DATA, secnam);
@ -1347,8 +1380,6 @@ STATIC void GC_dyld_image_remove(const struct GC_MACH_HEADER *hdr,
unsigned long start, end;
unsigned i, j;
const struct GC_MACH_SECTION *sec;
char secnam[16];
const char *fmt;
for (i = 0; i < sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]); i++) {
sec = GC_GETSECTBYNAME(hdr, GC_dyld_sections[i].seg,
@ -1368,8 +1399,11 @@ STATIC void GC_dyld_image_remove(const struct GC_MACH_HEADER *hdr,
/* Remove our on-demand sections. */
for (j = 0; j < sizeof(GC_dyld_add_sect_fmts) / sizeof(char *); j++) {
fmt = GC_dyld_add_sect_fmts[j];
const char *fmt = GC_dyld_add_sect_fmts[j];
for (i = 0; i <= L2_MAX_OFILE_ALIGNMENT; i++) {
char secnam[16];
(void)snprintf(secnam, sizeof(secnam), fmt, (unsigned)i);
secnam[sizeof(secnam) - 1] = '\0';
sec = GC_GETSECTBYNAME(hdr, SEG_DATA, secnam);
@ -1424,12 +1458,13 @@ GC_INNER void GC_init_dyld(void)
This WILL properly register already linked libraries and libraries
linked in the future.
*/
_dyld_register_func_for_add_image(GC_dyld_image_add);
_dyld_register_func_for_remove_image(GC_dyld_image_remove);
/* Ignore 2 compiler warnings here: passing argument 1 of */
/* '_dyld_register_func_for_add/remove_image' from incompatible */
/* pointer type. */
_dyld_register_func_for_add_image(
(void (*)(const struct mach_header*, intptr_t))GC_dyld_image_add);
_dyld_register_func_for_remove_image(
(void (*)(const struct mach_header*, intptr_t))GC_dyld_image_remove);
/* Structure mach_header64 has the same fields */
/* as mach_header except for the reserved one */
/* at the end, so these casts are OK. */
/* Set this early to avoid reentrancy issues. */
initialized = TRUE;
@ -1465,6 +1500,21 @@ GC_INNER GC_bool GC_register_main_static_data(void)
#endif /* DARWIN */
#if defined(HAIKU)
# include <kernel/image.h>
GC_INNER void GC_register_dynamic_libraries(void)
{
image_info info;
int32 cookie = 0;
while (get_next_image_info(0, &cookie, &info) == B_OK) {
ptr_t data = (ptr_t)info.data;
GC_add_roots_inner(data, data + info.data_size, TRUE);
}
}
#endif /* HAIKU */
#elif defined(PCR)
# include "il/PCR_IL.h"

View file

@ -9,7 +9,7 @@
#if !defined(GC_AMIGA_DEF) && !defined(GC_AMIGA_SB) && !defined(GC_AMIGA_DS) && !defined(GC_AMIGA_AM)
# include "gc_priv.h"
# include "private/gc_priv.h"
# include <stdio.h>
# include <signal.h>
# define GC_AMIGA_DEF
@ -40,7 +40,7 @@
Find the base of the stack.
******************************************************************/
ptr_t GC_get_main_stack_base()
ptr_t GC_get_main_stack_base(void)
{
struct Process *proc = (struct Process*)SysBase->ThisTask;
@ -65,16 +65,13 @@ ptr_t GC_get_main_stack_base()
Register data segments.
******************************************************************/
void GC_register_data_segments()
void GC_register_data_segments(void)
{
struct Process *proc;
struct CommandLineInterface *cli;
BPTR myseglist;
ULONG *data;
int num;
# ifdef __GNUC__
ULONG dataSegSize;
GC_bool found_segment = FALSE;
@ -90,10 +87,9 @@ ptr_t GC_get_main_stack_base()
/* Reference: Amiga Guru Book Pages: 538ff,565,573
and XOper.asm */
myseglist = proc->pr_SegList;
if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS) {
if (proc->pr_CLI == NULL) {
myseglist = proc->pr_SegList;
} else {
if (proc->pr_CLI != NULL) {
/* ProcLoaded 'Loaded as a command: '*/
cli = BADDR(proc->pr_CLI);
myseglist = cli->cli_Module;
@ -108,11 +104,11 @@ ptr_t GC_get_main_stack_base()
/* xoper hunks Shell Process */
num=0;
for (data = (ULONG *)BADDR(myseglist); data != NULL;
data = (ULONG *)BADDR(data[0])) {
if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) ||
((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) {
if ((ULONG)GC_register_data_segments < (ULONG)(&data[1])
|| (ULONG)GC_register_data_segments > (ULONG)(&data[1])
+ data[-1]) {
# ifdef __GNUC__
if (dataSegSize == data[-1]) {
found_segment = TRUE;
@ -121,7 +117,6 @@ ptr_t GC_get_main_stack_base()
GC_add_roots_inner((char *)&data[1],
((char *)&data[1]) + data[-1], FALSE);
}
++num;
} /* for */
# ifdef __GNUC__
if (!found_segment) {
@ -213,7 +208,6 @@ int ncur151=0;
void GC_amiga_free_all_mem(void){
struct GC_Amiga_AllocedMemoryHeader *gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(GC_AMIGAMEM));
struct GC_Amiga_AllocedMemoryHeader *temp;
#ifdef GC_AMIGA_PRINTSTATS
printf("\n\n"
@ -228,11 +222,11 @@ void GC_amiga_free_all_mem(void){
printf("GC_gcollect was called %d times to avoid returning NULL or start allocating with the MEMF_ANY flag.\n",numcollects);
printf("%d of them was a success. (the others had to use allocation from the OS.)\n",nullretries);
printf("\n");
printf("Succeded forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",succ,succ2);
printf("Succeeded forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",succ,succ2);
printf("Failed forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",nsucc,nsucc2);
printf("\n");
printf(
"Number of retries before succeding a chip->fast force:\n"
"Number of retries before succeeding a chip->fast force:\n"
"0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n",
cur0,cur1,cur10,cur50,cur150,cur151
);
@ -244,7 +238,7 @@ void GC_amiga_free_all_mem(void){
#endif
while(gc_am!=NULL){
temp=gc_am->next;
struct GC_Amiga_AllocedMemoryHeader *temp = gc_am->next;
FreeMem(gc_am,gc_am->size);
gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(temp));
}
@ -267,6 +261,8 @@ size_t latestsize;
#endif
#ifdef GC_AMIGA_FASTALLOC
/*
* The actual function that is called with the GET_MEM macro.
*
@ -277,11 +273,10 @@ void *GC_amiga_get_mem(size_t size){
#ifndef GC_AMIGA_ONLYFAST
if(GC_amiga_dontalloc==TRUE){
// printf("rejected, size: %d, latestsize: %d\n",size,latestsize);
return NULL;
}
// We really don't want to use chip-mem, but if we must, then as little as possible.
/* We really don't want to use chip-mem, but if we must, then as little as possible. */
if(GC_AMIGA_MEMF==(MEMF_ANY|MEMF_CLEAR) && size>100000 && latestsize<50000) return NULL;
#endif
@ -292,8 +287,6 @@ void *GC_amiga_get_mem(size_t size){
gc_am->size=size + sizeof(struct GC_Amiga_AllocedMemoryHeader);
GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(gc_am));
// printf("Allocated %d (%d) bytes at address: %x. Latest: %d\n",size,tot,gc_am,latestsize);
#ifdef GC_AMIGA_PRINTSTATS
if((char *)gc_am<chipmax){
allochip+=size;
@ -306,7 +299,7 @@ void *GC_amiga_get_mem(size_t size){
}
#endif
#ifndef GC_AMIGA_ONLYFAST
@ -348,7 +341,6 @@ void *GC_amiga_rec_alloc(size_t size,void *(*AllocFunction)(size_t size2),const
if (((char *)ret)<=chipmax && ret!=NULL && (rec<(size>500000?9:size/5000))){
ret=GC_amiga_rec_alloc(size,AllocFunction,rec+1);
// GC_free(ret2);
}
return ret;
@ -362,16 +354,16 @@ void *GC_amiga_rec_alloc(size_t size,void *(*AllocFunction)(size_t size2),const
void *GC_amiga_allocwrapper_any(size_t size,void *(*AllocFunction)(size_t size2)){
void *ret,*ret2;
void *ret;
GC_amiga_dontalloc=TRUE; // Pretty tough thing to do, but its indeed necessary.
GC_amiga_dontalloc=TRUE; /* Pretty tough thing to do, but its indeed necessary. */
latestsize=size;
ret=(*AllocFunction)(size);
if(((char *)ret) <= chipmax){
if(ret==NULL){
//Give GC access to allocate memory.
/* Give GC access to allocate memory. */
#ifdef GC_AMIGA_GC
if(!GC_dont_gc){
GC_gcollect();
@ -380,8 +372,9 @@ void *GC_amiga_allocwrapper_any(size_t size,void *(*AllocFunction)(size_t size2)
#endif
ret=(*AllocFunction)(size);
}
if(ret==NULL)
#endif
if(ret==NULL){
{
GC_amiga_dontalloc=FALSE;
ret=(*AllocFunction)(size);
if(ret==NULL){
@ -397,13 +390,13 @@ void *GC_amiga_allocwrapper_any(size_t size,void *(*AllocFunction)(size_t size2)
}
#ifdef GC_AMIGA_RETRY
else{
void *ret2;
/* We got chip-mem. Better try again and again and again etc., we might get fast-mem sooner or later... */
/* Using gctest to check the effectiveness of doing this, does seldom give a very good result. */
/* However, real programs doesn't normally rapidly allocate and deallocate. */
// printf("trying to force... %d bytes... ",size);
if(
AllocFunction!=GC_malloc_uncollectable
#ifdef ATOMIC_UNCOLLECTABLE
#ifdef GC_ATOMIC_UNCOLLECTABLE
&& AllocFunction!=GC_malloc_atomic_uncollectable
#endif
){
@ -423,12 +416,10 @@ void *GC_amiga_allocwrapper_any(size_t size,void *(*AllocFunction)(size_t size2)
#endif
}
if(((char *)ret2)>chipmax){
// printf("Succeeded.\n");
GC_free(ret);
ret=ret2;
}else{
GC_free(ret2);
// printf("But did not succeed.\n");
}
}
#endif
@ -447,7 +438,7 @@ void GC_amiga_set_toany(void (*func)(void)){
GC_amiga_toany=func;
}
#endif // !GC_AMIGA_ONLYFAST
#endif /* !GC_AMIGA_ONLYFAST */
void *GC_amiga_allocwrapper_fast(size_t size,void *(*AllocFunction)(size_t size2)){
@ -456,8 +447,7 @@ void *GC_amiga_allocwrapper_fast(size_t size,void *(*AllocFunction)(size_t size2
ret=(*AllocFunction)(size);
if(ret==NULL){
// Enable chip-mem allocation.
// printf("ret==NULL\n");
/* Enable chip-mem allocation. */
#ifdef GC_AMIGA_GC
if(!GC_dont_gc){
GC_gcollect();
@ -466,8 +456,9 @@ void *GC_amiga_allocwrapper_fast(size_t size,void *(*AllocFunction)(size_t size2
#endif
ret=(*AllocFunction)(size);
}
if(ret==NULL)
#endif
if(ret==NULL){
{
#ifndef GC_AMIGA_ONLYFAST
GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR;
if(GC_amiga_toany!=NULL) (*GC_amiga_toany)();
@ -487,13 +478,13 @@ void *GC_amiga_allocwrapper_fast(size_t size,void *(*AllocFunction)(size_t size2
void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2)){
atexit(&GC_amiga_free_all_mem);
chipmax=(char *)SysBase->MaxLocMem; // For people still having SysBase in chip-mem, this might speed up a bit.
chipmax=(char *)SysBase->MaxLocMem; /* For people still having SysBase in chip-mem, this might speed up a bit. */
GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_fast;
return GC_amiga_allocwrapper_fast(size,AllocFunction);
}
#endif //GC_AMIGA_FASTALLOC
#endif /* GC_AMIGA_FASTALLOC */
@ -508,7 +499,8 @@ void *GC_amiga_realloc(void *old_object,size_t new_size_in_bytes){
void *ret;
latestsize=new_size_in_bytes;
ret=GC_realloc(old_object,new_size_in_bytes);
if(ret==NULL && GC_AMIGA_MEMF==(MEMF_FAST | MEMF_CLEAR)){
if(ret==NULL && new_size_in_bytes != 0
&& GC_AMIGA_MEMF==(MEMF_FAST | MEMF_CLEAR)){
/* Out of fast-mem. */
#ifdef GC_AMIGA_GC
if(!GC_dont_gc){
@ -518,8 +510,9 @@ void *GC_amiga_realloc(void *old_object,size_t new_size_in_bytes){
#endif
ret=GC_realloc(old_object,new_size_in_bytes);
}
if(ret==NULL)
#endif
if(ret==NULL){
{
#ifndef GC_AMIGA_ONLYFAST
GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR;
if(GC_amiga_toany!=NULL) (*GC_amiga_toany)();
@ -533,7 +526,7 @@ void *GC_amiga_realloc(void *old_object,size_t new_size_in_bytes){
}
#endif
}
if(ret==NULL){
if(ret==NULL && new_size_in_bytes != 0){
WARN("Out of Memory! Returning NIL!\n", 0);
}
#ifdef GC_AMIGA_PRINTSTATS
@ -545,4 +538,4 @@ void *GC_amiga_realloc(void *old_object,size_t new_size_in_bytes){
#endif
}
#endif //GC_AMIGA_AM
#endif /* GC_AMIGA_AM */

View file

@ -24,9 +24,9 @@ unloading shared library.
#define GC_BUILD
#include "gc.h"
#include "gc_priv.h"
#include "private/gc_priv.h"
// use 'CODE' resource 0 to get exact location of the beginning of global space.
/* use 'CODE' resource 0 to get exact location of the beginning of global space. */
typedef struct {
unsigned long aboveA5;
@ -35,7 +35,7 @@ typedef struct {
unsigned long JTOffset;
} *CodeZeroPtr, **CodeZeroHandle;
void* GC_MacGetDataStart()
void* GC_MacGetDataStart(void)
{
CodeZeroHandle code0 = (CodeZeroHandle)GetResource('CODE', 0);
if (code0) {
@ -48,6 +48,8 @@ void* GC_MacGetDataStart()
return 0;
}
#ifdef USE_TEMPORARY_MEMORY
/* track the use of temporary memory so it can be freed all at once. */
typedef struct TemporaryMemoryBlock TemporaryMemoryBlock, **TemporaryMemoryHandle;
@ -58,13 +60,14 @@ struct TemporaryMemoryBlock {
};
static TemporaryMemoryHandle theTemporaryMemory = NULL;
static Boolean firstTime = true;
void GC_MacFreeTemporaryMemory(void);
Ptr GC_MacTemporaryNewPtr(size_t size, Boolean clearMemory)
{
# if !defined(SHARED_LIBRARY_BUILD)
static Boolean firstTime = true;
# endif
OSErr result;
TemporaryMemoryHandle tempMemBlock;
Ptr tempPtr = nil;
@ -76,13 +79,13 @@ Ptr GC_MacTemporaryNewPtr(size_t size, Boolean clearMemory)
if (clearMemory) memset(tempPtr, 0, size);
tempPtr = StripAddress(tempPtr);
// keep track of the allocated blocks.
/* keep track of the allocated blocks. */
(**tempMemBlock).nextBlock = theTemporaryMemory;
theTemporaryMemory = tempMemBlock;
}
# if !defined(SHARED_LIBRARY_BUILD)
// install an exit routine to clean up the memory used at the end.
/* install an exit routine to clean up the memory used at the end. */
if (firstTime) {
atexit(&GC_MacFreeTemporaryMemory);
firstTime = false;
@ -94,7 +97,7 @@ Ptr GC_MacTemporaryNewPtr(size_t size, Boolean clearMemory)
extern word GC_fo_entries;
static void perform_final_collection()
static void perform_final_collection(void)
{
unsigned i;
word last_fo_entries = 0;
@ -111,7 +114,7 @@ static void perform_final_collection()
}
void GC_MacFreeTemporaryMemory()
void GC_MacFreeTemporaryMemory(void)
{
# if defined(SHARED_LIBRARY_BUILD)
/* if possible, collect all memory, and invoke all finalizers. */
@ -119,11 +122,15 @@ void GC_MacFreeTemporaryMemory()
# endif
if (theTemporaryMemory != NULL) {
# if !defined(SHARED_LIBRARY_BUILD)
long totalMemoryUsed = 0;
# endif
TemporaryMemoryHandle tempMemBlock = theTemporaryMemory;
while (tempMemBlock != NULL) {
TemporaryMemoryHandle nextBlock = (**tempMemBlock).nextBlock;
# if !defined(SHARED_LIBRARY_BUILD)
totalMemoryUsed += GetHandleSize((Handle)tempMemBlock);
# endif
DisposeHandle((Handle)tempMemBlock);
tempMemBlock = nextBlock;
}
@ -132,16 +139,19 @@ void GC_MacFreeTemporaryMemory()
# if !defined(SHARED_LIBRARY_BUILD)
if (GC_print_stats) {
fprintf(stdout, "[total memory used: %ld bytes.]\n",
totalMemoryUsed);
fprintf(stdout, "[total collections: %ld.]\n", GC_gc_no);
totalMemoryUsed);
fprintf(stdout, "[total collections: %lu]\n",
(unsigned long)GC_gc_no);
}
# endif
}
}
#endif /* USE_TEMPORARY_MEMORY */
#if __option(far_data)
void* GC_MacGetDataEnd()
void* GC_MacGetDataEnd(void)
{
CodeZeroHandle code0 = (CodeZeroHandle)GetResource('CODE', 0);
if (code0) {

View file

@ -12,17 +12,16 @@
/* Boehm, November 17, 1995 12:10 pm PST */
#ifdef __MWERKS__
// for CodeWarrior Pro with Metrowerks Standard Library (MSL).
// #define MSL_USE_PRECOMPILED_HEADERS 0
/* for CodeWarrior Pro with Metrowerks Standard Library (MSL). */
/* #define MSL_USE_PRECOMPILED_HEADERS 0 */
#include <ansi_prefix.mac.h>
#endif /* __MWERKS__ */
// these are defined again in gc_priv.h.
/* these are defined again in gc_priv.h. */
#undef TRUE
#undef FALSE
#define ALL_INTERIOR_POINTERS // follows interior pointers.
//#define DONT_ADD_BYTE_AT_END // no padding.
//#define SMALL_CONFIG // whether to use a smaller heap.
#define USE_TEMPORARY_MEMORY // use Macintosh temporary memory.
#define ALL_INTERIOR_POINTERS /* follows interior pointers. */
/* #define DONT_ADD_BYTE_AT_END */ /* no padding. */
/* #define SMALL_CONFIG */ /* whether to use a smaller heap. */
#define USE_TEMPORARY_MEMORY /* use Macintosh temporary memory. */

View file

@ -4,6 +4,7 @@
* Copyright (c) 1998 by Fergus Henderson. All rights reserved.
* Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
* All rights reserved.
* Copyright (c) 2009-2018 Ivan Maidanski
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.

View file

@ -47,7 +47,7 @@ typedef GC_word word;
typedef ULONG ULONG_ADDR;
#endif
static HANDLE GetSymHandle()
static HANDLE GetSymHandle(void)
{
static HANDLE symHandle = NULL;
if (!symHandle) {
@ -158,8 +158,8 @@ size_t GetStackFramesFromContext(HANDLE hProcess, HANDLE hThread,
#elif defined(_M_ALPHA64)
machineType = IMAGE_FILE_MACHINE_ALPHA64;
stackFrame.AddrPC.Offset = context->Fir;
#else
#error Unknown CPU
#elif !defined(CPPCHECK)
# error Unknown CPU
#endif
for (frameIndex = 0; frameIndex < maxFrames; ) {
BOOL bRet = StackWalk(machineType, hProcess, hThread, &stackFrame,
@ -308,7 +308,6 @@ size_t GetDescriptionFromAddress(void* address, const char* format,
char*const begin = buffer;
char*const end = buffer + size;
size_t line_number = 0;
char str[128];
if (size) {
*buffer = 0;
@ -317,7 +316,9 @@ size_t GetDescriptionFromAddress(void* address, const char* format,
size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer;
if (line_number) {
wsprintf(str, "(%d) : ", line_number);
char str[128];
wsprintf(str, "(%d) : ", (int)line_number);
if (size) {
strncpy(buffer, str, size)[size - 1] = 0;
}
@ -341,8 +342,6 @@ size_t GetDescriptionFromAddress(void* address, const char* format,
size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer;
buffer += GetModuleNameFromAddress(address, buffer, size);
size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer;
return buffer - begin;
}
@ -354,12 +353,15 @@ size_t GetDescriptionFromStack(void* const frames[], size_t count,
char*const end = begin + size;
char* buffer = begin + (count + 1) * sizeof(char*);
size_t i;
(void)format;
for (i = 0; i < count; ++i) {
if (description) description[i] = buffer;
if (size)
description[i] = buffer;
size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer;
buffer += 1 + GetDescriptionFromAddress(frames[i], NULL, buffer, size);
}
if (description) description[count] = NULL;
if (size)
description[count] = NULL;
return buffer - begin;
}
@ -374,8 +376,14 @@ char** backtrace_symbols(void*const* addresses, int count)
{
size_t size = GetDescriptionFromStack(addresses, count, NULL, NULL, 0);
char** symbols = (char**)malloc(size);
GetDescriptionFromStack(addresses, count, NULL, symbols, size);
if (symbols != NULL)
GetDescriptionFromStack(addresses, count, NULL, symbols, size);
return symbols;
}
#endif /* !_M_AMD64 */
#else
extern int GC_quiet;
/* ANSI C does not allow translation units to be empty. */
#endif /* _M_AMD64 */

View file

@ -45,7 +45,8 @@ char* GC_get_private_path_and_zero_file()
size_t size = path8.Length() + 1;
char* copyChar = (char*) malloc( size );
memcpy( copyChar, path8.PtrZ(), size );
if (copyChar)
memcpy( copyChar, path8.PtrZ(), size );
return copyChar; // ownership passed
}

View file

@ -26,7 +26,7 @@ typedef void (* finalization_mark_proc)(ptr_t /* finalizable_obj_ptr */);
#define HASH3(addr,size,log_size) \
((((word)(addr) >> 3) ^ ((word)(addr) >> (3 + (log_size)))) \
& ((size) - 1))
#define HASH2(addr,log_size) HASH3(addr, 1 << (log_size), log_size)
#define HASH2(addr,log_size) HASH3(addr, (word)1 << (log_size), log_size)
struct hash_chain_entry {
word hidden_key;
@ -55,7 +55,7 @@ STATIC struct dl_hashtbl_s GC_dl_hashtbl = {
STATIC struct dl_hashtbl_s GC_ll_hashtbl = { NULL, -1, 0 };
#endif
STATIC struct finalizable_object {
struct finalizable_object {
struct hash_chain_entry prolog;
# define fo_hidden_base prolog.hidden_key
/* Pointer to object base. */
@ -67,50 +67,68 @@ STATIC struct finalizable_object {
ptr_t fo_client_data;
word fo_object_size; /* In bytes. */
finalization_mark_proc fo_mark_proc; /* Mark-through procedure */
} **GC_fo_head = 0;
STATIC struct finalizable_object * GC_finalize_now = 0;
/* List of objects that should be finalized now. */
};
static signed_word log_fo_table_size = -1;
GC_INNER void GC_push_finalizer_structures(void)
STATIC struct {
struct finalizable_object **fo_head;
/* List of objects that should be finalized now: */
struct finalizable_object *finalize_now;
} GC_fnlz_roots = { NULL, NULL };
GC_API void GC_CALL GC_push_finalizer_structures(void)
{
GC_ASSERT((word)&GC_dl_hashtbl.head % sizeof(word) == 0);
GC_ASSERT((word)&GC_fo_head % sizeof(word) == 0);
GC_ASSERT((word)&GC_finalize_now % sizeof(word) == 0);
GC_ASSERT((word)(&GC_dl_hashtbl.head) % sizeof(word) == 0);
GC_ASSERT((word)(&GC_fnlz_roots) % sizeof(word) == 0);
# ifndef GC_LONG_REFS_NOT_NEEDED
GC_ASSERT((word)&GC_ll_hashtbl.head % sizeof(word) == 0);
GC_push_all((ptr_t)(&GC_ll_hashtbl.head),
(ptr_t)(&GC_ll_hashtbl.head) + sizeof(word));
GC_ASSERT((word)(&GC_ll_hashtbl.head) % sizeof(word) == 0);
GC_PUSH_ALL_SYM(GC_ll_hashtbl.head);
# endif
GC_push_all((ptr_t)(&GC_dl_hashtbl.head),
(ptr_t)(&GC_dl_hashtbl.head) + sizeof(word));
GC_push_all((ptr_t)(&GC_fo_head), (ptr_t)(&GC_fo_head) + sizeof(word));
GC_push_all((ptr_t)(&GC_finalize_now),
(ptr_t)(&GC_finalize_now) + sizeof(word));
GC_PUSH_ALL_SYM(GC_dl_hashtbl.head);
GC_PUSH_ALL_SYM(GC_fnlz_roots);
}
/* Double the size of a hash table. *size_ptr is the log of its current */
/* size. May be a no-op. */
/* Threshold of log_size to initiate full collection before growing */
/* a hash table. */
#ifndef GC_ON_GROW_LOG_SIZE_MIN
# define GC_ON_GROW_LOG_SIZE_MIN CPP_LOG_HBLKSIZE
#endif
/* Double the size of a hash table. *log_size_ptr is the log of its */
/* current size. May be a no-op. */
/* *table is a pointer to an array of hash headers. If we succeed, we */
/* update both *table and *log_size_ptr. Lock is held. */
STATIC void GC_grow_table(struct hash_chain_entry ***table,
signed_word *log_size_ptr)
signed_word *log_size_ptr, word *entries_ptr)
{
register word i;
register struct hash_chain_entry *p;
signed_word log_old_size = *log_size_ptr;
signed_word log_new_size = log_old_size + 1;
word old_size = ((log_old_size == -1)? 0: (1 << log_old_size));
word old_size = log_old_size == -1 ? 0 : (word)1 << log_old_size;
word new_size = (word)1 << log_new_size;
/* FIXME: Power of 2 size often gets rounded up to one more page. */
struct hash_chain_entry **new_table = (struct hash_chain_entry **)
GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
(size_t)new_size * sizeof(struct hash_chain_entry *), NORMAL);
struct hash_chain_entry **new_table;
GC_ASSERT(I_HOLD_LOCK());
/* Avoid growing the table in case of at least 25% of entries can */
/* be deleted by enforcing a collection. Ignored for small tables. */
if (log_old_size >= GC_ON_GROW_LOG_SIZE_MIN) {
IF_CANCEL(int cancel_state;)
DISABLE_CANCEL(cancel_state);
(void)GC_try_to_collect_inner(GC_never_stop_func);
RESTORE_CANCEL(cancel_state);
/* GC_finalize might decrease entries value. */
if (*entries_ptr < ((word)1 << log_old_size) - (*entries_ptr >> 2))
return;
}
new_table = (struct hash_chain_entry **)
GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
(size_t)new_size * sizeof(struct hash_chain_entry *),
NORMAL);
if (new_table == 0) {
if (*table == 0) {
ABORT("Insufficient space for initial table allocation");
@ -126,12 +144,14 @@ STATIC void GC_grow_table(struct hash_chain_entry ***table,
size_t new_hash = HASH3(real_key, new_size, log_new_size);
p -> next = new_table[new_hash];
GC_dirty(p);
new_table[new_hash] = p;
p = next;
}
}
*log_size_ptr = log_new_size;
*table = new_table;
GC_dirty(new_table); /* entire object */
}
GC_API int GC_CALL GC_register_disappearing_link(void * * link)
@ -146,20 +166,24 @@ GC_API int GC_CALL GC_register_disappearing_link(void * * link)
STATIC int GC_register_disappearing_link_inner(
struct dl_hashtbl_s *dl_hashtbl, void **link,
const void *obj)
const void *obj, const char *tbl_log_name)
{
struct disappearing_link *curr_dl;
size_t index;
struct disappearing_link * new_dl;
DCL_LOCK_STATE;
if (EXPECT(GC_find_leak, FALSE)) return GC_UNIMPLEMENTED;
LOCK();
GC_ASSERT(obj != NULL && GC_base_C(obj) == obj);
if (dl_hashtbl -> log_size == -1
|| dl_hashtbl -> entries > ((word)1 << dl_hashtbl -> log_size)) {
GC_grow_table((struct hash_chain_entry ***)&dl_hashtbl -> head,
&dl_hashtbl -> log_size);
GC_COND_LOG_PRINTF("Grew dl table to %u entries\n",
&dl_hashtbl -> log_size, &dl_hashtbl -> entries);
# ifdef LINT2
if (dl_hashtbl->log_size < 0) ABORT("log_size is negative");
# endif
GC_COND_LOG_PRINTF("Grew %s table to %u entries\n", tbl_log_name,
1 << (unsigned)dl_hashtbl -> log_size);
}
index = HASH2(link, dl_hashtbl -> log_size);
@ -202,8 +226,10 @@ STATIC int GC_register_disappearing_link_inner(
new_dl -> dl_hidden_obj = GC_HIDE_POINTER(obj);
new_dl -> dl_hidden_link = GC_HIDE_POINTER(link);
dl_set_next(new_dl, dl_hashtbl -> head[index]);
GC_dirty(new_dl);
dl_hashtbl -> head[index] = new_dl;
dl_hashtbl -> entries++;
GC_dirty(dl_hashtbl->head + index);
UNLOCK();
return GC_SUCCESS;
}
@ -211,9 +237,10 @@ STATIC int GC_register_disappearing_link_inner(
GC_API int GC_CALL GC_general_register_disappearing_link(void * * link,
const void * obj)
{
if (((word)link & (ALIGNMENT-1)) != 0 || NULL == link)
if (((word)link & (ALIGNMENT-1)) != 0 || !NONNULL_ARG_NOT_NULL(link))
ABORT("Bad arg to GC_general_register_disappearing_link");
return GC_register_disappearing_link_inner(&GC_dl_hashtbl, link, obj);
return GC_register_disappearing_link_inner(&GC_dl_hashtbl, link, obj,
"dl");
}
#ifdef DBG_HDRS_ALL
@ -229,16 +256,22 @@ GC_INLINE struct disappearing_link *GC_unregister_disappearing_link_inner(
{
struct disappearing_link *curr_dl;
struct disappearing_link *prev_dl = NULL;
size_t index = HASH2(link, dl_hashtbl->log_size);
size_t index;
if (dl_hashtbl->log_size == -1)
return NULL; /* prevent integer shift by a negative amount */
index = HASH2(link, dl_hashtbl->log_size);
for (curr_dl = dl_hashtbl -> head[index]; curr_dl;
curr_dl = dl_next(curr_dl)) {
if (curr_dl -> dl_hidden_link == GC_HIDE_POINTER(link)) {
/* Remove found entry from the table. */
if (NULL == prev_dl) {
dl_hashtbl -> head[index] = dl_next(curr_dl);
GC_dirty(dl_hashtbl->head + index);
} else {
dl_set_next(prev_dl, dl_next(curr_dl));
GC_dirty(prev_dl);
}
dl_hashtbl -> entries--;
break;
@ -263,12 +296,213 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
return 1;
}
/* Toggle-ref support. */
#ifndef GC_TOGGLE_REFS_NOT_NEEDED
typedef union {
/* Lowest bit is used to distinguish between choices. */
void *strong_ref;
GC_hidden_pointer weak_ref;
} GCToggleRef;
STATIC GC_toggleref_func GC_toggleref_callback = 0;
STATIC GCToggleRef *GC_toggleref_arr = NULL;
STATIC int GC_toggleref_array_size = 0;
STATIC int GC_toggleref_array_capacity = 0;
GC_INNER void GC_process_togglerefs(void)
{
int i;
int new_size = 0;
GC_bool needs_barrier = FALSE;
GC_ASSERT(I_HOLD_LOCK());
for (i = 0; i < GC_toggleref_array_size; ++i) {
GCToggleRef r = GC_toggleref_arr[i];
void *obj = r.strong_ref;
if (((word)obj & 1) != 0) {
obj = GC_REVEAL_POINTER(r.weak_ref);
}
if (NULL == obj) {
continue;
}
switch (GC_toggleref_callback(obj)) {
case GC_TOGGLE_REF_DROP:
break;
case GC_TOGGLE_REF_STRONG:
GC_toggleref_arr[new_size++].strong_ref = obj;
needs_barrier = TRUE;
break;
case GC_TOGGLE_REF_WEAK:
GC_toggleref_arr[new_size++].weak_ref = GC_HIDE_POINTER(obj);
break;
default:
ABORT("Bad toggle-ref status returned by callback");
}
}
if (new_size < GC_toggleref_array_size) {
BZERO(&GC_toggleref_arr[new_size],
(GC_toggleref_array_size - new_size) * sizeof(GCToggleRef));
GC_toggleref_array_size = new_size;
}
if (needs_barrier)
GC_dirty(GC_toggleref_arr); /* entire object */
}
STATIC void GC_normal_finalize_mark_proc(ptr_t);
static void push_and_mark_object(void *p)
{
GC_normal_finalize_mark_proc(p);
while (!GC_mark_stack_empty()) {
MARK_FROM_MARK_STACK();
}
GC_set_mark_bit(p);
if (GC_mark_state != MS_NONE) {
while (!GC_mark_some(0)) {
/* Empty. */
}
}
}
STATIC void GC_mark_togglerefs(void)
{
int i;
if (NULL == GC_toggleref_arr)
return;
/* TODO: Hide GC_toggleref_arr to avoid its marking from roots. */
GC_set_mark_bit(GC_toggleref_arr);
for (i = 0; i < GC_toggleref_array_size; ++i) {
void *obj = GC_toggleref_arr[i].strong_ref;
if (obj != NULL && ((word)obj & 1) == 0) {
push_and_mark_object(obj);
}
}
}
STATIC void GC_clear_togglerefs(void)
{
int i;
for (i = 0; i < GC_toggleref_array_size; ++i) {
if ((GC_toggleref_arr[i].weak_ref & 1) != 0) {
if (!GC_is_marked(GC_REVEAL_POINTER(GC_toggleref_arr[i].weak_ref))) {
GC_toggleref_arr[i].weak_ref = 0;
} else {
/* No need to copy, BDWGC is a non-moving collector. */
}
}
}
}
GC_API void GC_CALL GC_set_toggleref_func(GC_toggleref_func fn)
{
DCL_LOCK_STATE;
LOCK();
GC_toggleref_callback = fn;
UNLOCK();
}
GC_API GC_toggleref_func GC_CALL GC_get_toggleref_func(void)
{
GC_toggleref_func fn;
DCL_LOCK_STATE;
LOCK();
fn = GC_toggleref_callback;
UNLOCK();
return fn;
}
static GC_bool ensure_toggleref_capacity(int capacity_inc)
{
GC_ASSERT(capacity_inc >= 0);
if (NULL == GC_toggleref_arr) {
GC_toggleref_array_capacity = 32; /* initial capacity */
GC_toggleref_arr = GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
GC_toggleref_array_capacity * sizeof(GCToggleRef),
NORMAL);
if (NULL == GC_toggleref_arr)
return FALSE;
}
if ((unsigned)GC_toggleref_array_size + (unsigned)capacity_inc
>= (unsigned)GC_toggleref_array_capacity) {
GCToggleRef *new_array;
while ((unsigned)GC_toggleref_array_capacity
< (unsigned)GC_toggleref_array_size + (unsigned)capacity_inc) {
GC_toggleref_array_capacity *= 2;
if (GC_toggleref_array_capacity < 0) /* overflow */
return FALSE;
}
new_array = GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
GC_toggleref_array_capacity * sizeof(GCToggleRef),
NORMAL);
if (NULL == new_array)
return FALSE;
BCOPY(GC_toggleref_arr, new_array,
GC_toggleref_array_size * sizeof(GCToggleRef));
GC_INTERNAL_FREE(GC_toggleref_arr);
GC_toggleref_arr = new_array;
}
return TRUE;
}
GC_API int GC_CALL GC_toggleref_add(void *obj, int is_strong_ref)
{
int res = GC_SUCCESS;
DCL_LOCK_STATE;
GC_ASSERT(NONNULL_ARG_NOT_NULL(obj));
LOCK();
if (GC_toggleref_callback != 0) {
if (!ensure_toggleref_capacity(1)) {
res = GC_NO_MEMORY;
} else {
GC_toggleref_arr[GC_toggleref_array_size].strong_ref =
is_strong_ref ? obj : (void *)GC_HIDE_POINTER(obj);
if (is_strong_ref)
GC_dirty(GC_toggleref_arr + GC_toggleref_array_size);
GC_toggleref_array_size++;
}
}
UNLOCK();
return res;
}
#endif /* !GC_TOGGLE_REFS_NOT_NEEDED */
/* Finalizer callback support. */
STATIC GC_await_finalize_proc GC_object_finalized_proc = 0;
GC_API void GC_CALL GC_set_await_finalize_proc(GC_await_finalize_proc fn)
{
DCL_LOCK_STATE;
LOCK();
GC_object_finalized_proc = fn;
UNLOCK();
}
GC_API GC_await_finalize_proc GC_CALL GC_get_await_finalize_proc(void)
{
GC_await_finalize_proc fn;
DCL_LOCK_STATE;
LOCK();
fn = GC_object_finalized_proc;
UNLOCK();
return fn;
}
#ifndef GC_LONG_REFS_NOT_NEEDED
GC_API int GC_CALL GC_register_long_link(void * * link, const void * obj)
{
if (((word)link & (ALIGNMENT-1)) != 0 || NULL == link)
if (((word)link & (ALIGNMENT-1)) != 0 || !NONNULL_ARG_NOT_NULL(link))
ABORT("Bad arg to GC_register_long_link");
return GC_register_disappearing_link_inner(&GC_ll_hashtbl, link, obj);
return GC_register_disappearing_link_inner(&GC_ll_hashtbl, link, obj,
"long dl");
}
GC_API int GC_CALL GC_unregister_long_link(void * * link)
@ -298,6 +532,9 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
word curr_hidden_link;
word new_hidden_link;
if (dl_hashtbl->log_size == -1)
return GC_NOT_FOUND; /* prevent integer shift by a negative amount */
/* Find current link. */
curr_index = HASH2(link, dl_hashtbl -> log_size);
curr_hidden_link = GC_HIDE_POINTER(link);
@ -333,10 +570,13 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
dl_hashtbl -> head[curr_index] = dl_next(curr_dl);
} else {
dl_set_next(prev_dl, dl_next(curr_dl));
GC_dirty(prev_dl);
}
curr_dl -> dl_hidden_link = new_hidden_link;
dl_set_next(curr_dl, dl_hashtbl -> head[new_index]);
dl_hashtbl -> head[new_index] = curr_dl;
GC_dirty(curr_dl);
GC_dirty(dl_hashtbl->head); /* entire object */
return GC_SUCCESS;
}
@ -345,7 +585,8 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
int result;
DCL_LOCK_STATE;
if (((word)new_link & (ALIGNMENT-1)) != 0 || new_link == NULL)
if (((word)new_link & (ALIGNMENT-1)) != 0
|| !NONNULL_ARG_NOT_NULL(new_link))
ABORT("Bad new_link arg to GC_move_disappearing_link");
if (((word)link & (ALIGNMENT-1)) != 0)
return GC_NOT_FOUND; /* Nothing to do. */
@ -362,8 +603,9 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
int result;
DCL_LOCK_STATE;
if (((word)new_link & (ALIGNMENT-1)) != 0 || new_link == NULL)
ABORT("Bad new_link arg to GC_move_disappearing_link");
if (((word)new_link & (ALIGNMENT-1)) != 0
|| !NONNULL_ARG_NOT_NULL(new_link))
ABORT("Bad new_link arg to GC_move_long_link");
if (((word)link & (ALIGNMENT-1)) != 0)
return GC_NOT_FOUND; /* Nothing to do. */
@ -393,7 +635,6 @@ STATIC void GC_ignore_self_finalize_mark_proc(ptr_t p)
hdr * hhdr = HDR(p);
word descr = hhdr -> hb_descr;
ptr_t q;
word r;
ptr_t scan_limit;
ptr_t target_limit = p + hhdr -> hb_sz - 1;
@ -403,7 +644,8 @@ STATIC void GC_ignore_self_finalize_mark_proc(ptr_t p)
scan_limit = target_limit + 1 - sizeof(word);
}
for (q = p; (word)q <= (word)scan_limit; q += ALIGNMENT) {
r = *(word *)q;
word r = *(word *)q;
if (r < (word)p || r > (word)target_limit) {
GC_PUSH_ONE_HEAP(r, q, GC_mark_stack_top);
}
@ -435,41 +677,45 @@ STATIC void GC_register_finalizer_inner(void * obj,
GC_finalization_proc *ofn, void **ocd,
finalization_mark_proc mp)
{
ptr_t base;
struct finalizable_object * curr_fo, * prev_fo;
struct finalizable_object * curr_fo;
size_t index;
struct finalizable_object *new_fo = 0;
hdr *hhdr = NULL; /* initialized to prevent warning. */
GC_oom_func oom_fn;
DCL_LOCK_STATE;
if (EXPECT(GC_find_leak, FALSE)) return;
LOCK();
if (log_fo_table_size == -1
|| GC_fo_entries > ((word)1 << log_fo_table_size)) {
GC_grow_table((struct hash_chain_entry ***)&GC_fo_head,
&log_fo_table_size);
GC_grow_table((struct hash_chain_entry ***)&GC_fnlz_roots.fo_head,
&log_fo_table_size, &GC_fo_entries);
# ifdef LINT2
if (log_fo_table_size < 0) ABORT("log_size is negative");
# endif
GC_COND_LOG_PRINTF("Grew fo table to %u entries\n",
1 << (unsigned)log_fo_table_size);
}
/* in the THREADS case we hold allocation lock. */
base = (ptr_t)obj;
for (;;) {
index = HASH2(base, log_fo_table_size);
prev_fo = 0;
curr_fo = GC_fo_head[index];
struct finalizable_object *prev_fo = NULL;
GC_oom_func oom_fn;
index = HASH2(obj, log_fo_table_size);
curr_fo = GC_fnlz_roots.fo_head[index];
while (curr_fo != 0) {
GC_ASSERT(GC_size(curr_fo) >= sizeof(struct finalizable_object));
if (curr_fo -> fo_hidden_base == GC_HIDE_POINTER(base)) {
if (curr_fo -> fo_hidden_base == GC_HIDE_POINTER(obj)) {
/* Interruption by a signal in the middle of this */
/* should be safe. The client may see only *ocd */
/* updated, but we'll declare that to be his problem. */
if (ocd) *ocd = (void *) (curr_fo -> fo_client_data);
if (ofn) *ofn = curr_fo -> fo_fn;
/* Delete the structure for base. */
/* Delete the structure for obj. */
if (prev_fo == 0) {
GC_fo_head[index] = fo_next(curr_fo);
GC_fnlz_roots.fo_head[index] = fo_next(curr_fo);
} else {
fo_set_next(prev_fo, fo_next(curr_fo));
GC_dirty(prev_fo);
}
if (fn == 0) {
GC_fo_entries--;
@ -483,14 +729,18 @@ STATIC void GC_register_finalizer_inner(void * obj,
curr_fo -> fo_fn = fn;
curr_fo -> fo_client_data = (ptr_t)cd;
curr_fo -> fo_mark_proc = mp;
GC_dirty(curr_fo);
/* Reinsert it. We deleted it first to maintain */
/* consistency in the event of a signal. */
if (prev_fo == 0) {
GC_fo_head[index] = curr_fo;
GC_fnlz_roots.fo_head[index] = curr_fo;
} else {
fo_set_next(prev_fo, curr_fo);
GC_dirty(prev_fo);
}
}
if (NULL == prev_fo)
GC_dirty(GC_fnlz_roots.fo_head + index);
UNLOCK();
# ifndef DBG_HDRS_ALL
if (EXPECT(new_fo != 0, FALSE)) {
@ -504,7 +754,11 @@ STATIC void GC_register_finalizer_inner(void * obj,
curr_fo = fo_next(curr_fo);
}
if (EXPECT(new_fo != 0, FALSE)) {
/* new_fo is returned by GC_oom_fn(), so fn != 0 and hhdr != 0. */
/* new_fo is returned by GC_oom_fn(). */
GC_ASSERT(fn != 0);
# ifdef LINT2
if (NULL == hhdr) ABORT("Bad hhdr in GC_register_finalizer_inner");
# endif
break;
}
if (fn == 0) {
@ -513,7 +767,7 @@ STATIC void GC_register_finalizer_inner(void * obj,
UNLOCK();
return;
}
GET_HDR(base, hhdr);
GET_HDR(obj, hhdr);
if (EXPECT(0 == hhdr, FALSE)) {
/* We won't collect it, hence finalizer wouldn't be run. */
if (ocd) *ocd = 0;
@ -541,14 +795,16 @@ STATIC void GC_register_finalizer_inner(void * obj,
GC_ASSERT(GC_size(new_fo) >= sizeof(struct finalizable_object));
if (ocd) *ocd = 0;
if (ofn) *ofn = 0;
new_fo -> fo_hidden_base = GC_HIDE_POINTER(base);
new_fo -> fo_hidden_base = GC_HIDE_POINTER(obj);
new_fo -> fo_fn = fn;
new_fo -> fo_client_data = (ptr_t)cd;
new_fo -> fo_object_size = hhdr -> hb_sz;
new_fo -> fo_mark_proc = mp;
fo_set_next(new_fo, GC_fo_head[index]);
fo_set_next(new_fo, GC_fnlz_roots.fo_head[index]);
GC_dirty(new_fo);
GC_fo_entries++;
GC_fo_head[index] = new_fo;
GC_fnlz_roots.fo_head[index] = new_fo;
GC_dirty(GC_fnlz_roots.fo_head + index);
UNLOCK();
}
@ -593,27 +849,29 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
STATIC void GC_dump_finalization_links(
const struct dl_hashtbl_s *dl_hashtbl)
{
struct disappearing_link *curr_dl;
ptr_t real_ptr, real_link;
size_t dl_size = dl_hashtbl->log_size == -1 ? 0 :
1 << dl_hashtbl->log_size;
(size_t)1 << dl_hashtbl->log_size;
size_t i;
for (i = 0; i < dl_size; i++) {
struct disappearing_link *curr_dl;
for (curr_dl = dl_hashtbl -> head[i]; curr_dl != 0;
curr_dl = dl_next(curr_dl)) {
real_ptr = GC_REVEAL_POINTER(curr_dl -> dl_hidden_obj);
real_link = GC_REVEAL_POINTER(curr_dl -> dl_hidden_link);
GC_printf("Object: %p, link: %p\n", real_ptr, real_link);
ptr_t real_ptr = GC_REVEAL_POINTER(curr_dl -> dl_hidden_obj);
ptr_t real_link = GC_REVEAL_POINTER(curr_dl -> dl_hidden_link);
GC_printf("Object: %p, link: %p\n",
(void *)real_ptr, (void *)real_link);
}
}
}
void GC_dump_finalization(void)
GC_API void GC_CALL GC_dump_finalization(void)
{
struct finalizable_object * curr_fo;
size_t fo_size = log_fo_table_size == -1 ? 0 : 1 << log_fo_table_size;
ptr_t real_ptr;
size_t fo_size = log_fo_table_size == -1 ? 0 :
(size_t)1 << log_fo_table_size;
size_t i;
GC_printf("Disappearing (short) links:\n");
@ -624,10 +882,11 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
# endif
GC_printf("Finalizers:\n");
for (i = 0; i < fo_size; i++) {
for (curr_fo = GC_fo_head[i]; curr_fo != 0;
curr_fo = fo_next(curr_fo)) {
real_ptr = GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
GC_printf("Finalizable object: %p\n", real_ptr);
for (curr_fo = GC_fnlz_roots.fo_head[i];
curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
ptr_t real_ptr = GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
GC_printf("Finalizable object: %p\n", (void *)real_ptr);
}
}
}
@ -672,10 +931,11 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
{ \
size_t i; \
size_t dl_size = dl_hashtbl->log_size == -1 ? 0 : \
1 << dl_hashtbl->log_size; \
(size_t)1 << dl_hashtbl->log_size; \
GC_bool needs_barrier = FALSE; \
for (i = 0; i < dl_size; i++) { \
struct disappearing_link *prev_dl = NULL; \
curr_dl = dl_hashtbl -> head[i]; \
prev_dl = NULL; \
while (curr_dl) {
#define ITERATE_DL_HASHTBL_END(curr_dl, prev_dl) \
@ -683,6 +943,8 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
curr_dl = dl_next(curr_dl); \
} \
} \
if (needs_barrier) \
GC_dirty(dl_hashtbl -> head); /* entire object */ \
}
#define DELETE_DL_HASHTBL_ENTRY(dl_hashtbl, curr_dl, prev_dl, next_dl) \
@ -690,8 +952,10 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
next_dl = dl_next(curr_dl); \
if (NULL == prev_dl) { \
dl_hashtbl -> head[i] = next_dl; \
needs_barrier = TRUE; \
} else { \
dl_set_next(prev_dl, next_dl); \
GC_dirty(prev_dl); \
} \
GC_clear_mark_bit(curr_dl); \
dl_hashtbl -> entries--; \
@ -702,15 +966,14 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
GC_INLINE void GC_make_disappearing_links_disappear(
struct dl_hashtbl_s* dl_hashtbl)
{
struct disappearing_link *curr, *prev, *next;
ptr_t real_ptr, real_link;
struct disappearing_link *curr, *next;
ITERATE_DL_HASHTBL_BEGIN(dl_hashtbl, curr, prev)
real_ptr = GC_REVEAL_POINTER(curr -> dl_hidden_obj);
real_link = GC_REVEAL_POINTER(curr -> dl_hidden_link);
ptr_t real_ptr = GC_REVEAL_POINTER(curr -> dl_hidden_obj);
ptr_t real_link = GC_REVEAL_POINTER(curr -> dl_hidden_link);
if (!GC_is_marked(real_ptr)) {
*(word *)real_link = 0;
GC_clear_mark_bit(curr);
DELETE_DL_HASHTBL_ENTRY(dl_hashtbl, curr, prev, next);
}
ITERATE_DL_HASHTBL_END(curr, prev)
@ -719,13 +982,12 @@ GC_INLINE void GC_make_disappearing_links_disappear(
GC_INLINE void GC_remove_dangling_disappearing_links(
struct dl_hashtbl_s* dl_hashtbl)
{
struct disappearing_link *curr, *prev, *next;
ptr_t real_link;
struct disappearing_link *curr, *next;
ITERATE_DL_HASHTBL_BEGIN(dl_hashtbl, curr, prev)
real_link = GC_base(GC_REVEAL_POINTER(curr -> dl_hidden_link));
ptr_t real_link = GC_base(GC_REVEAL_POINTER(curr -> dl_hidden_link));
if (NULL != real_link && !GC_is_marked(real_link)) {
GC_clear_mark_bit(curr);
DELETE_DL_HASHTBL_ENTRY(dl_hashtbl, curr, prev, next);
}
ITERATE_DL_HASHTBL_END(curr, prev)
@ -739,7 +1001,9 @@ GC_INNER void GC_finalize(void)
struct finalizable_object * curr_fo, * prev_fo, * next_fo;
ptr_t real_ptr;
size_t i;
size_t fo_size = log_fo_table_size == -1 ? 0 : 1 << log_fo_table_size;
size_t fo_size = log_fo_table_size == -1 ? 0 :
(size_t)1 << log_fo_table_size;
GC_bool needs_barrier = FALSE;
# ifndef SMALL_CONFIG
/* Save current GC_[dl/ll]_entries value for stats printing */
@ -749,14 +1013,17 @@ GC_INNER void GC_finalize(void)
# endif
# endif
# ifndef GC_TOGGLE_REFS_NOT_NEEDED
GC_mark_togglerefs();
# endif
GC_make_disappearing_links_disappear(&GC_dl_hashtbl);
/* Mark all objects reachable via chains of 1 or more pointers */
/* from finalizable objects. */
GC_ASSERT(GC_mark_state == MS_NONE);
for (i = 0; i < fo_size; i++) {
for (curr_fo = GC_fo_head[i]; curr_fo != 0;
curr_fo = fo_next(curr_fo)) {
for (curr_fo = GC_fnlz_roots.fo_head[i];
curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
GC_ASSERT(GC_size(curr_fo) >= sizeof(struct finalizable_object));
real_ptr = GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
if (!GC_is_marked(real_ptr)) {
@ -772,7 +1039,7 @@ GC_INNER void GC_finalize(void)
/* unreachable. */
GC_bytes_finalized = 0;
for (i = 0; i < fo_size; i++) {
curr_fo = GC_fo_head[i];
curr_fo = GC_fnlz_roots.fo_head[i];
prev_fo = 0;
while (curr_fo != 0) {
real_ptr = GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
@ -782,15 +1049,25 @@ GC_INNER void GC_finalize(void)
}
/* Delete from hash table */
next_fo = fo_next(curr_fo);
if (prev_fo == 0) {
GC_fo_head[i] = next_fo;
if (NULL == prev_fo) {
GC_fnlz_roots.fo_head[i] = next_fo;
if (GC_object_finalized_proc) {
GC_dirty(GC_fnlz_roots.fo_head + i);
} else {
needs_barrier = TRUE;
}
} else {
fo_set_next(prev_fo, next_fo);
GC_dirty(prev_fo);
}
GC_fo_entries--;
if (GC_object_finalized_proc)
GC_object_finalized_proc(real_ptr);
/* Add to list of objects awaiting finalization. */
fo_set_next(curr_fo, GC_finalize_now);
GC_finalize_now = curr_fo;
fo_set_next(curr_fo, GC_fnlz_roots.finalize_now);
GC_dirty(curr_fo);
GC_fnlz_roots.finalize_now = curr_fo;
/* unhide object pointer so any future collections will */
/* see it. */
curr_fo -> fo_hidden_base =
@ -810,8 +1087,8 @@ GC_INNER void GC_finalize(void)
if (GC_java_finalization) {
/* make sure we mark everything reachable from objects finalized
using the no_order mark_proc */
for (curr_fo = GC_finalize_now;
curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
for (curr_fo = GC_fnlz_roots.finalize_now;
curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
if (!GC_is_marked(real_ptr)) {
if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
@ -826,30 +1103,37 @@ GC_INNER void GC_finalize(void)
/* now revive finalize-when-unreachable objects reachable from
other finalizable objects */
if (need_unreachable_finalization) {
curr_fo = GC_finalize_now;
prev_fo = 0;
while (curr_fo != 0) {
curr_fo = GC_fnlz_roots.finalize_now;
# if defined(GC_ASSERTIONS) || defined(LINT2)
if (curr_fo != NULL && log_fo_table_size < 0)
ABORT("log_size is negative");
# endif
prev_fo = NULL;
while (curr_fo != NULL) {
next_fo = fo_next(curr_fo);
if (curr_fo -> fo_mark_proc == GC_unreachable_finalize_mark_proc) {
real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
if (!GC_is_marked(real_ptr)) {
GC_set_mark_bit(real_ptr);
} else {
if (prev_fo == 0)
GC_finalize_now = next_fo;
else
if (NULL == prev_fo) {
GC_fnlz_roots.finalize_now = next_fo;
} else {
fo_set_next(prev_fo, next_fo);
GC_dirty(prev_fo);
}
curr_fo -> fo_hidden_base =
GC_HIDE_POINTER(curr_fo -> fo_hidden_base);
GC_bytes_finalized -=
curr_fo->fo_object_size + sizeof(struct finalizable_object);
i = HASH2(real_ptr, log_fo_table_size);
fo_set_next (curr_fo, GC_fo_head[i]);
fo_set_next(curr_fo, GC_fnlz_roots.fo_head[i]);
GC_dirty(curr_fo);
GC_fo_entries++;
GC_fo_head[i] = curr_fo;
GC_fnlz_roots.fo_head[i] = curr_fo;
curr_fo = prev_fo;
needs_barrier = TRUE;
}
}
prev_fo = curr_fo;
@ -857,8 +1141,13 @@ GC_INNER void GC_finalize(void)
}
}
}
if (needs_barrier)
GC_dirty(GC_fnlz_roots.fo_head); /* entire object */
GC_remove_dangling_disappearing_links(&GC_dl_hashtbl);
# ifndef GC_TOGGLE_REFS_NOT_NEEDED
GC_clear_togglerefs();
# endif
# ifndef GC_LONG_REFS_NOT_NEEDED
GC_make_disappearing_links_disappear(&GC_ll_hashtbl);
GC_remove_dangling_disappearing_links(&GC_ll_hashtbl);
@ -880,33 +1169,28 @@ GC_INNER void GC_finalize(void)
/* Enqueue all remaining finalizers to be run - Assumes lock is held. */
STATIC void GC_enqueue_all_finalizers(void)
{
struct finalizable_object * curr_fo, * prev_fo, * next_fo;
ptr_t real_ptr;
register int i;
struct finalizable_object * next_fo;
int i;
int fo_size;
fo_size = log_fo_table_size == -1 ? 0 : 1 << log_fo_table_size;
GC_bytes_finalized = 0;
for (i = 0; i < fo_size; i++) {
curr_fo = GC_fo_head[i];
prev_fo = 0;
while (curr_fo != 0) {
real_ptr = GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
struct finalizable_object * curr_fo = GC_fnlz_roots.fo_head[i];
GC_fnlz_roots.fo_head[i] = NULL;
while (curr_fo != NULL) {
ptr_t real_ptr = (ptr_t)GC_REVEAL_POINTER(curr_fo->fo_hidden_base);
GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
GC_set_mark_bit(real_ptr);
/* Delete from hash table */
next_fo = fo_next(curr_fo);
if (prev_fo == 0) {
GC_fo_head[i] = next_fo;
} else {
fo_set_next(prev_fo, next_fo);
}
GC_fo_entries--;
/* Add to list of objects awaiting finalization. */
fo_set_next(curr_fo, GC_finalize_now);
GC_finalize_now = curr_fo;
fo_set_next(curr_fo, GC_fnlz_roots.finalize_now);
GC_dirty(curr_fo);
GC_fnlz_roots.finalize_now = curr_fo;
/* unhide object pointer so any future collections will */
/* see it. */
@ -917,6 +1201,7 @@ GC_INNER void GC_finalize(void)
curr_fo = next_fo;
}
}
GC_fo_entries = 0; /* all entries deleted from the hash table */
}
/* Invoke all remaining finalizers that haven't yet been run.
@ -958,19 +1243,20 @@ GC_INNER void GC_finalize(void)
/* getting into that safe state is expensive.) */
GC_API int GC_CALL GC_should_invoke_finalizers(void)
{
return GC_finalize_now != 0;
return GC_fnlz_roots.finalize_now != NULL;
}
/* Invoke finalizers for all objects that are ready to be finalized. */
/* Should be called without allocation lock. */
GC_API int GC_CALL GC_invoke_finalizers(void)
{
struct finalizable_object * curr_fo;
int count = 0;
word bytes_freed_before = 0; /* initialized to prevent warning. */
DCL_LOCK_STATE;
while (GC_finalize_now != 0) {
while (GC_fnlz_roots.finalize_now != NULL) {
struct finalizable_object * curr_fo;
# ifdef THREADS
LOCK();
# endif
@ -978,25 +1264,22 @@ GC_API int GC_CALL GC_invoke_finalizers(void)
bytes_freed_before = GC_bytes_freed;
/* Don't do this outside, since we need the lock. */
}
curr_fo = GC_finalize_now;
curr_fo = GC_fnlz_roots.finalize_now;
# ifdef THREADS
if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
if (curr_fo != 0) GC_fnlz_roots.finalize_now = fo_next(curr_fo);
UNLOCK();
if (curr_fo == 0) break;
# else
GC_finalize_now = fo_next(curr_fo);
GC_fnlz_roots.finalize_now = fo_next(curr_fo);
# endif
fo_set_next(curr_fo, 0);
(*(curr_fo -> fo_fn))((ptr_t)(curr_fo -> fo_hidden_base),
curr_fo -> fo_client_data);
curr_fo -> fo_client_data = 0;
++count;
# ifdef UNDEFINED
/* This is probably a bad idea. It throws off accounting if */
/* nearly all objects are finalizable. O.w. it shouldn't */
/* matter. */
GC_free((void *)curr_fo);
# endif
/* Explicit freeing of curr_fo is probably a bad idea. */
/* It throws off accounting if nearly all objects are */
/* finalizable. Otherwise it should not matter. */
}
/* bytes_freed_before is initialized whenever count != 0 */
if (count != 0 && bytes_freed_before != GC_bytes_freed) {
@ -1007,7 +1290,7 @@ GC_API int GC_CALL GC_invoke_finalizers(void)
return count;
}
static GC_word last_finalizer_notification = 0;
static word last_finalizer_notification = 0;
GC_INNER void GC_notify_or_invoke_finalizers(void)
{
@ -1020,7 +1303,7 @@ GC_INNER void GC_notify_or_invoke_finalizers(void)
# if defined(THREADS) && !defined(KEEP_BACK_PTRS) \
&& !defined(MAKE_BACK_GRAPH)
/* Quick check (while unlocked) for an empty finalization queue. */
if (GC_finalize_now == 0) return;
if (NULL == GC_fnlz_roots.finalize_now) return;
# endif
LOCK();
@ -1045,14 +1328,12 @@ GC_INNER void GC_notify_or_invoke_finalizers(void)
# endif
# ifdef MAKE_BACK_GRAPH
if (GC_print_back_height) {
UNLOCK();
GC_print_back_graph_stats();
LOCK();
}
# endif
}
# endif
if (GC_finalize_now == 0) {
if (NULL == GC_fnlz_roots.finalize_now) {
UNLOCK();
return;
}
@ -1065,7 +1346,7 @@ GC_INNER void GC_notify_or_invoke_finalizers(void)
(void) GC_invoke_finalizers();
*pnested = 0; /* Reset since no more finalizers. */
# ifndef THREADS
GC_ASSERT(GC_finalize_now == 0);
GC_ASSERT(NULL == GC_fnlz_roots.finalize_now);
# endif /* Otherwise GC can run concurrently and add more */
}
return;
@ -1100,7 +1381,7 @@ GC_INNER void GC_notify_or_invoke_finalizers(void)
(unsigned long)IF_LONG_REFS_PRESENT_ELSE(
GC_ll_hashtbl.entries, 0));
for (fo = GC_finalize_now; 0 != fo; fo = fo_next(fo))
for (fo = GC_fnlz_roots.finalize_now; fo != NULL; fo = fo_next(fo))
++ready;
GC_log_printf("%lu finalization-ready objects;"
" %ld/%ld short/long links cleared\n",

View file

@ -17,29 +17,32 @@
#ifdef ENABLE_DISCLAIM
#include "gc_disclaim.h"
#ifdef THREAD_LOCAL_ALLOC
# include "private/thread_local_alloc.h"
#else
STATIC ptr_t * GC_finalized_objfreelist = NULL;
#endif /* !THREAD_LOCAL_ALLOC */
#include "gc_inline.h" /* for GC_malloc_kind */
STATIC int GC_finalized_kind = 0;
#if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
/* The first bit is already used for a debug purpose. */
# define FINALIZER_CLOSURE_FLAG 0x2
#else
# define FINALIZER_CLOSURE_FLAG 0x1
#endif
STATIC int GC_CALLBACK GC_finalized_disclaim(void *obj)
{
word fc_word = *(word *)obj;
if ((fc_word & 1) != 0) {
if ((fc_word & FINALIZER_CLOSURE_FLAG) != 0) {
/* The disclaim function may be passed fragments from the */
/* free-list, on which it should not run finalization. */
/* To recognize this case, we use the fact that the first word */
/* on such fragments are always even (a link to the next */
/* on such fragments is always multiple of 4 (a link to the next */
/* fragment, or NULL). If it is desirable to have a finalizer */
/* which does not use the first word for storing finalization */
/* info, GC_reclaim_with_finalization must be extended to clear */
/* fragments so that the assumption holds for the selected word. */
const struct GC_finalizer_closure *fc = (void *)(fc_word & ~(word)1);
const struct GC_finalizer_closure *fc
= (void *)(fc_word & ~(word)FINALIZER_CLOSURE_FLAG);
(*fc->proc)((word *)obj + 1, fc->cd);
}
return 0;
@ -66,8 +69,7 @@ GC_API void GC_CALL GC_init_finalized_malloc(void)
/* start of the user region. */
GC_register_displacement_inner(sizeof(word));
GC_finalized_objfreelist = (ptr_t *)GC_new_free_list_inner();
GC_finalized_kind = GC_new_kind_inner((void **)GC_finalized_objfreelist,
GC_finalized_kind = GC_new_kind_inner(GC_new_free_list_inner(),
GC_DS_LENGTH, TRUE, TRUE);
GC_register_disclaim_proc(GC_finalized_kind, GC_finalized_disclaim, TRUE);
UNLOCK();
@ -81,90 +83,17 @@ GC_API void GC_CALL GC_register_disclaim_proc(int kind, GC_disclaim_proc proc,
GC_obj_kinds[kind].ok_mark_unconditionally = (GC_bool)mark_unconditionally;
}
#ifdef THREAD_LOCAL_ALLOC
STATIC void * GC_core_finalized_malloc(size_t lb,
GC_API GC_ATTR_MALLOC void * GC_CALL GC_finalized_malloc(size_t lb,
const struct GC_finalizer_closure *fclos)
#else
GC_API GC_ATTR_MALLOC void * GC_CALL GC_finalized_malloc(size_t lb,
const struct GC_finalizer_closure *fclos)
#endif
{
ptr_t op;
word lg;
DCL_LOCK_STATE;
word *op;
lb += sizeof(word);
GC_ASSERT(done_init);
if (SMALL_OBJ(lb)) {
GC_DBG_COLLECT_AT_MALLOC(lb);
lg = GC_size_map[lb];
LOCK();
op = GC_finalized_objfreelist[lg];
if (EXPECT(0 == op, FALSE)) {
UNLOCK();
op = GC_generic_malloc(lb, GC_finalized_kind);
if (NULL == op)
return NULL;
/* GC_generic_malloc has extended the size map for us. */
lg = GC_size_map[lb];
} else {
GC_finalized_objfreelist[lg] = obj_link(op);
obj_link(op) = 0;
GC_bytes_allocd += GRANULES_TO_BYTES(lg);
UNLOCK();
}
GC_ASSERT(lg > 0);
} else {
op = GC_generic_malloc(lb, GC_finalized_kind);
if (NULL == op)
return NULL;
GC_ASSERT(GC_size(op) >= lb);
}
*(word *)op = (word)fclos | 1;
return GC_clear_stack((word *)op + 1);
op = GC_malloc_kind(SIZET_SAT_ADD(lb, sizeof(word)), GC_finalized_kind);
if (EXPECT(NULL == op, FALSE))
return NULL;
*op = (word)fclos | FINALIZER_CLOSURE_FLAG;
return op + 1;
}
#ifdef THREAD_LOCAL_ALLOC
GC_API GC_ATTR_MALLOC void * GC_CALL GC_finalized_malloc(size_t client_lb,
const struct GC_finalizer_closure *fclos)
{
size_t lb = client_lb + sizeof(word);
size_t lg = ROUNDED_UP_GRANULES(lb);
GC_tlfs tsd;
void *result;
void **tiny_fl, **my_fl, *my_entry;
void *next;
if (EXPECT(lg >= GC_TINY_FREELISTS, FALSE))
return GC_core_finalized_malloc(client_lb, fclos);
tsd = GC_getspecific(GC_thread_key);
tiny_fl = tsd->finalized_freelists;
my_fl = tiny_fl + lg;
my_entry = *my_fl;
while (EXPECT((word)my_entry
<= DIRECT_GRANULES + GC_TINY_FREELISTS + 1, FALSE)) {
if ((word)my_entry - 1 < DIRECT_GRANULES) {
*my_fl = (ptr_t)my_entry + lg + 1;
return GC_core_finalized_malloc(client_lb, fclos);
} else {
GC_generic_malloc_many(GC_RAW_BYTES_FROM_INDEX(lg),
GC_finalized_kind, my_fl);
my_entry = *my_fl;
if (my_entry == 0) {
return (*GC_get_oom_fn())(lb);
}
}
}
next = obj_link(my_entry);
result = (void *)my_entry;
*my_fl = next;
obj_link(result) = 0;
*(word *)result = (word)fclos | 1;
PREFETCH_FOR_WRITE(next);
return (word *)result + 1;
}
#endif /* THREAD_LOCAL_ALLOC */
#endif /* ENABLE_DISCLAIM */

View file

@ -7,7 +7,7 @@
!IF "$(CFG)" == ""
CFG=gctest - Win32 Release
!MESSAGE No configuration specified. Defaulting to cord - Win32 Debug.
!MESSAGE No configuration specified. Defaulting to gctest - Win32 Release.
!ENDIF
!IF "$(CFG)" != "gc - Win32 Release" && "$(CFG)" != "gc - Win32 Debug" &&\
@ -110,8 +110,9 @@ CLEAN :
-@erase ".\Release\typd_mlc.sbr"
-@erase ".\Release\win32_threads.obj"
-@erase ".\Release\win32_threads.sbr"
-@erase ".\Release\msvc_dbg.obj"
-@erase ".\Release\msvc_dbg.sbr"
-@erase ".\Release\msvc_dbg.copied.obj"
-@erase ".\Release\msvc_dbg.copied.sbr"
-@erase ".\msvc_dbg.copied.c"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
@ -119,10 +120,10 @@ CLEAN :
CPP=cl.exe
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "GC_THREADS" /FR /YX /c
CPP_PROJ=/nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D\
"WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "GC_THREADS" \
/FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch" \
/I./libatomic_ops/src /YX /Fo"$(INTDIR)/" /c
CPP_PROJ=/nologo /MD /W3 /EHsc /O2 /I include /D "NDEBUG" /D "WIN32"\
/D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "GC_THREADS" /D "_CRT_SECURE_NO_DEPRECATE"\
/FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch"\
/I./libatomic_ops/src /Fo"$(INTDIR)/" /c
CPP_OBJS=.\Release/
CPP_SBRS=.\Release/
@ -155,31 +156,31 @@ BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/gc.bsc"
BSC32_SBRS= \
".\Release\allchblk.sbr" \
".\Release\alloc.sbr" \
".\Release\blacklst.sbr" \
".\Release\checksums.sbr" \
".\Release\dbg_mlc.sbr" \
".\Release\dyn_load.sbr" \
".\Release\finalize.sbr" \
".\Release\fnlz_mlc.sbr" \
".\Release\gc_cpp.sbr" \
".\Release\headers.sbr" \
".\Release\mach_dep.sbr" \
".\Release\malloc.sbr" \
".\Release\mallocx.sbr" \
".\Release\mark.sbr" \
".\Release\mark_rts.sbr" \
".\Release\misc.sbr" \
".\Release\new_hblk.sbr" \
".\Release\obj_map.sbr" \
".\Release\os_dep.sbr" \
".\Release\ptr_chck.sbr" \
".\Release\reclaim.sbr" \
".\Release\stubborn.sbr" \
".\Release\typd_mlc.sbr" \
".\Release\msvc_dbg.sbr" \
BSC32_SBRS=\
".\Release\allchblk.sbr"\
".\Release\alloc.sbr"\
".\Release\blacklst.sbr"\
".\Release\checksums.sbr"\
".\Release\dbg_mlc.sbr"\
".\Release\dyn_load.sbr"\
".\Release\finalize.sbr"\
".\Release\fnlz_mlc.sbr"\
".\Release\gc_cpp.sbr"\
".\Release\headers.sbr"\
".\Release\mach_dep.sbr"\
".\Release\malloc.sbr"\
".\Release\mallocx.sbr"\
".\Release\mark.sbr"\
".\Release\mark_rts.sbr"\
".\Release\misc.sbr"\
".\Release\new_hblk.sbr"\
".\Release\obj_map.sbr"\
".\Release\os_dep.sbr"\
".\Release\ptr_chck.sbr"\
".\Release\reclaim.sbr"\
".\Release\stubborn.sbr"\
".\Release\typd_mlc.sbr"\
".\Release\msvc_dbg.copied.sbr"\
".\Release\win32_threads.sbr"
".\Release\gc.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
@ -195,31 +196,31 @@ LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
odbccp32.lib /nologo /subsystem:windows /dll /incremental:no\
/pdb:"$(OUTDIR)/gc.pdb" /machine:I386 /out:"$(OUTDIR)/gc.dll"\
/implib:"$(OUTDIR)/gc.lib"
LINK32_OBJS= \
".\Release\allchblk.obj" \
".\Release\alloc.obj" \
".\Release\blacklst.obj" \
".\Release\checksums.obj" \
".\Release\dbg_mlc.obj" \
".\Release\dyn_load.obj" \
".\Release\finalize.obj" \
".\Release\fnlz_mlc.obj" \
".\Release\gc_cpp.obj" \
".\Release\headers.obj" \
".\Release\mach_dep.obj" \
".\Release\malloc.obj" \
".\Release\mallocx.obj" \
".\Release\mark.obj" \
".\Release\mark_rts.obj" \
".\Release\misc.obj" \
".\Release\new_hblk.obj" \
".\Release\obj_map.obj" \
".\Release\os_dep.obj" \
".\Release\ptr_chck.obj" \
".\Release\reclaim.obj" \
".\Release\stubborn.obj" \
".\Release\typd_mlc.obj" \
".\Release\msvc_dbg.obj" \
LINK32_OBJS=\
".\Release\allchblk.obj"\
".\Release\alloc.obj"\
".\Release\blacklst.obj"\
".\Release\checksums.obj"\
".\Release\dbg_mlc.obj"\
".\Release\dyn_load.obj"\
".\Release\finalize.obj"\
".\Release\fnlz_mlc.obj"\
".\Release\gc_cpp.obj"\
".\Release\headers.obj"\
".\Release\mach_dep.obj"\
".\Release\malloc.obj"\
".\Release\mallocx.obj"\
".\Release\mark.obj"\
".\Release\mark_rts.obj"\
".\Release\misc.obj"\
".\Release\new_hblk.obj"\
".\Release\obj_map.obj"\
".\Release\os_dep.obj"\
".\Release\ptr_chck.obj"\
".\Release\reclaim.obj"\
".\Release\stubborn.obj"\
".\Release\typd_mlc.obj"\
".\Release\msvc_dbg.copied.obj"\
".\Release\win32_threads.obj"
".\Release\gc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
@ -301,8 +302,9 @@ CLEAN :
-@erase ".\Debug\vc40.pdb"
-@erase ".\Debug\win32_threads.obj"
-@erase ".\Debug\win32_threads.sbr"
-@erase ".\Debug\msvc_dbg.obj"
-@erase ".\Debug\msvc_dbg.sbr"
-@erase ".\Debug\msvc_dbg.copied.obj"
-@erase ".\Debug\msvc_dbg.copied.sbr"
-@erase ".\msvc_dbg.copied.c"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
@ -310,10 +312,10 @@ CLEAN :
CPP=cl.exe
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "GC_THREADS" /FR /YX /c
CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG"\
/D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" \
/D "GC_ASSERTIONS" /D "GC_THREADS" \
/FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch" /YX /Fo"$(INTDIR)/"\
CPP_PROJ=/nologo /MDd /W3 /Gm /EHsc /Zi /Od /I include /D "_DEBUG"\
/D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS"\
/D "GC_ASSERTIONS" /D "GC_THREADS" /D "_CRT_SECURE_NO_DEPRECATE"\
/FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch" /Fo"$(INTDIR)/"\
/I./libatomic_ops/src /Fd"$(INTDIR)/" /c
CPP_OBJS=.\Debug/
CPP_SBRS=.\Debug/
@ -347,31 +349,31 @@ BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/gc.bsc"
BSC32_SBRS= \
".\Debug\allchblk.sbr" \
".\Debug\alloc.sbr" \
".\Debug\blacklst.sbr" \
".\Debug\checksums.sbr" \
".\Debug\dbg_mlc.sbr" \
".\Debug\dyn_load.sbr" \
".\Debug\finalize.sbr" \
".\Debug\fnlz_mlc.sbr" \
".\Debug\gc_cpp.sbr" \
".\Debug\headers.sbr" \
".\Debug\mach_dep.sbr" \
".\Debug\malloc.sbr" \
".\Debug\mallocx.sbr" \
".\Debug\mark.sbr" \
".\Debug\mark_rts.sbr" \
".\Debug\misc.sbr" \
".\Debug\new_hblk.sbr" \
".\Debug\obj_map.sbr" \
".\Debug\os_dep.sbr" \
".\Debug\ptr_chck.sbr" \
".\Debug\reclaim.sbr" \
".\Debug\stubborn.sbr" \
".\Debug\typd_mlc.sbr" \
".\Debug\msvc_dbg.sbr" \
BSC32_SBRS=\
".\Debug\allchblk.sbr"\
".\Debug\alloc.sbr"\
".\Debug\blacklst.sbr"\
".\Debug\checksums.sbr"\
".\Debug\dbg_mlc.sbr"\
".\Debug\dyn_load.sbr"\
".\Debug\finalize.sbr"\
".\Debug\fnlz_mlc.sbr"\
".\Debug\gc_cpp.sbr"\
".\Debug\headers.sbr"\
".\Debug\mach_dep.sbr"\
".\Debug\malloc.sbr"\
".\Debug\mallocx.sbr"\
".\Debug\mark.sbr"\
".\Debug\mark_rts.sbr"\
".\Debug\misc.sbr"\
".\Debug\new_hblk.sbr"\
".\Debug\obj_map.sbr"\
".\Debug\os_dep.sbr"\
".\Debug\ptr_chck.sbr"\
".\Debug\reclaim.sbr"\
".\Debug\stubborn.sbr"\
".\Debug\typd_mlc.sbr"\
".\Debug\msvc_dbg.copied.sbr"\
".\Debug\win32_threads.sbr"
".\Debug\gc.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
@ -387,31 +389,31 @@ LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
odbccp32.lib /nologo /subsystem:windows /dll /incremental:no\
/pdb:"$(OUTDIR)/gc.pdb" /map:"$(INTDIR)/gc.map" /debug /machine:I386\
/out:"$(OUTDIR)/gc.dll" /implib:"$(OUTDIR)/gc.lib"
LINK32_OBJS= \
".\Debug\allchblk.obj" \
".\Debug\alloc.obj" \
".\Debug\blacklst.obj" \
".\Debug\checksums.obj" \
".\Debug\dbg_mlc.obj" \
".\Debug\dyn_load.obj" \
".\Debug\finalize.obj" \
".\Debug\fnlz_mlc.obj" \
".\Debug\gc_cpp.obj" \
".\Debug\headers.obj" \
".\Debug\mach_dep.obj" \
".\Debug\malloc.obj" \
".\Debug\mallocx.obj" \
".\Debug\mark.obj" \
".\Debug\mark_rts.obj" \
".\Debug\misc.obj" \
".\Debug\new_hblk.obj" \
".\Debug\obj_map.obj" \
".\Debug\os_dep.obj" \
".\Debug\ptr_chck.obj" \
".\Debug\reclaim.obj" \
".\Debug\stubborn.obj" \
".\Debug\typd_mlc.obj" \
".\Debug\msvc_dbg.obj" \
LINK32_OBJS=\
".\Debug\allchblk.obj"\
".\Debug\alloc.obj"\
".\Debug\blacklst.obj"\
".\Debug\checksums.obj"\
".\Debug\dbg_mlc.obj"\
".\Debug\dyn_load.obj"\
".\Debug\finalize.obj"\
".\Debug\fnlz_mlc.obj"\
".\Debug\gc_cpp.obj"\
".\Debug\headers.obj"\
".\Debug\mach_dep.obj"\
".\Debug\malloc.obj"\
".\Debug\mallocx.obj"\
".\Debug\mark.obj"\
".\Debug\mark_rts.obj"\
".\Debug\misc.obj"\
".\Debug\new_hblk.obj"\
".\Debug\obj_map.obj"\
".\Debug\os_dep.obj"\
".\Debug\ptr_chck.obj"\
".\Debug\reclaim.obj"\
".\Debug\stubborn.obj"\
".\Debug\typd_mlc.obj"\
".\Debug\msvc_dbg.copied.obj"\
".\Debug\win32_threads.obj"
".\Debug\gc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
@ -437,22 +439,23 @@ INTDIR=.\gctest\Release
ALL : "gc - Win32 Release" ".\Release\gctest.exe"
CLEAN :
-@erase ".\gctest\Release\test.obj"
-@erase ".\gctest\Release\test.copied.obj"
-@erase ".\test.copied.c"
-@erase ".\Release\gctest.exe"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
test.c : tests\test.c
copy tests\test.c test.c
test.copied.c : tests\test.c
copy tests\test.c test.copied.c
CPP=cl.exe
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "GC_THREADS" /YX /c
CPP_PROJ=/nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D\
"ALL_INTERIOR_POINTERS" /D "GC_THREADS" \
/I./libatomic_ops/src /Fp"$(INTDIR)/gctest.pch" \
/YX /Fo"$(INTDIR)/" /c
CPP_PROJ=/nologo /MD /W3 /EHsc /O2 /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS"\
/D "ALL_INTERIOR_POINTERS" /D "GC_THREADS" /D "_CRT_SECURE_NO_DEPRECATE"\
/I./libatomic_ops/src /Fp"$(INTDIR)/gctest.pch"\
/Fo"$(INTDIR)/" /c
CPP_OBJS=.\gctest\Release/
CPP_SBRS=.\.
@ -485,7 +488,7 @@ BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/gctest.bsc"
BSC32_SBRS= \
BSC32_SBRS=\
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
@ -494,8 +497,8 @@ LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:windows /incremental:no\
/pdb:"$(OUTDIR)/gctest.pdb" /machine:I386 /out:"Release/gctest.exe"
LINK32_OBJS= \
".\gctest\Release\test.obj" \
LINK32_OBJS=\
".\gctest\Release\test.copied.obj"\
".\Release\gc.lib"
".\Release\gctest.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
@ -525,8 +528,9 @@ CLEAN :
-@erase ".\gctest\Debug\gctest.bsc"
-@erase ".\gctest\Debug\gctest.map"
-@erase ".\gctest\Debug\gctest.pdb"
-@erase ".\gctest\Debug\test.obj"
-@erase ".\gctest\Debug\test.sbr"
-@erase ".\gctest\Debug\test.copied.obj"
-@erase ".\gctest\Debug\test.copied.sbr"
-@erase ".\test.copied.c"
-@erase ".\gctest\Debug\vc40.idb"
-@erase ".\gctest\Debug\vc40.pdb"
@ -536,9 +540,9 @@ CLEAN :
CPP=cl.exe
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "GC_THREADS" /FR /YX /c
CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "WIN32" /D "_WINDOWS"\
/D "ALL_INTERIOR_POINTERS" /D "GC_THREADS" /FR"$(INTDIR)/"\
/I./libatomic_ops/src /Fp"$(INTDIR)/gctest.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
CPP_PROJ=/nologo /MDd /W3 /Gm /EHsc /Zi /Od /I include /D "_DEBUG" /D "WIN32" /D "_WINDOWS"\
/D "ALL_INTERIOR_POINTERS" /D "GC_THREADS" /D "_CRT_SECURE_NO_DEPRECATE" /FR"$(INTDIR)/"\
/I./libatomic_ops/src /Fp"$(INTDIR)/gctest.pch" /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
CPP_OBJS=.\gctest\Debug/
CPP_SBRS=.\gctest\Debug/
@ -571,8 +575,8 @@ BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/gctest.bsc"
BSC32_SBRS= \
".\gctest\Debug\test.sbr"
BSC32_SBRS=\
".\gctest\Debug\test.copied.sbr"
".\gctest\Debug\gctest.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
$(BSC32) @<<
@ -587,9 +591,9 @@ LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
odbccp32.lib /nologo /subsystem:windows /incremental:no\
/pdb:"$(OUTDIR)/gctest.pdb" /map:"$(INTDIR)/gctest.map" /debug /machine:I386\
/out:"Debug/gctest.exe"
LINK32_OBJS= \
".\Debug\gc.lib" \
".\gctest\Debug\test.obj"
LINK32_OBJS=\
".\Debug\gc.lib"\
".\gctest\Debug\test.copied.obj"
".\Debug\gctest.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
@ -627,8 +631,8 @@ CLEAN :
CPP=cl.exe
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /YX /c
CPP_PROJ=/nologo /MD /W3 /GX /O2 /I "." /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D\
/I./libatomic_ops/src "ALL_INTERIOR_POINTERS" /Fp"$(INTDIR)/cord.pch" /YX /Fo"$(INTDIR)/" /c
CPP_PROJ=/nologo /MD /W3 /EHsc /O2 /I "." /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS"\
/D "ALL_INTERIOR_POINTERS" /I./libatomic_ops/src /Fp"$(INTDIR)/cord.pch" /Fo"$(INTDIR)/" /c
CPP_OBJS=.\cord\Release/
CPP_SBRS=.\.
@ -662,7 +666,7 @@ BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/cord.bsc"
BSC32_SBRS= \
BSC32_SBRS=\
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
@ -671,12 +675,12 @@ LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:windows /incremental:no /pdb:"$(OUTDIR)/de.pdb"\
/machine:I386 /out:"Release/de.exe"
LINK32_OBJS= \
".\cord\Release\cordbscs.obj" \
".\cord\Release\cordxtra.obj" \
".\cord\Release\de.obj" \
".\cord\Release\de_win.obj" \
".\cord\Release\de_win.res" \
LINK32_OBJS=\
".\cord\Release\cordbscs.obj"\
".\cord\Release\cordxtra.obj"\
".\cord\Release\de.obj"\
".\cord\Release\de_win.obj"\
".\cord\Release\de_win.res"\
".\Release\gc.lib"
".\Release\de.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
@ -719,8 +723,8 @@ CLEAN :
CPP=cl.exe
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "." /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /YX /c
CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I "." /I include /D "_DEBUG" /D "WIN32" /D\
"_WINDOWS" /D "ALL_INTERIOR_POINTERS" /Fp"$(INTDIR)/cord.pch" /YX\
CPP_PROJ=/nologo /MDd /W3 /Gm /EHsc /Zi /Od /I "." /I include /D "_DEBUG" /D "WIN32" /D "_WINDOWS"\
/D "ALL_INTERIOR_POINTERS" /Fp"$(INTDIR)/cord.pch"\
/I./libatomic_ops/src /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
CPP_OBJS=.\cord\Debug/
CPP_SBRS=.\.
@ -755,7 +759,7 @@ BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
BSC32_FLAGS=/nologo /o"$(OUTDIR)/cord.bsc"
BSC32_SBRS= \
BSC32_SBRS=\
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
@ -764,12 +768,12 @@ LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:windows /incremental:yes\
/pdb:"$(OUTDIR)/de.pdb" /debug /machine:I386 /out:"Debug/de.exe"
LINK32_OBJS= \
".\cord\Debug\cordbscs.obj" \
".\cord\Debug\cordxtra.obj" \
".\cord\Debug\de.obj" \
".\cord\Debug\de_win.obj" \
".\cord\Debug\de_win.res" \
LINK32_OBJS=\
".\cord\Debug\cordbscs.obj"\
".\cord\Debug\cordxtra.obj"\
".\cord\Debug\de.obj"\
".\cord\Debug\de_win.obj"\
".\cord\Debug\de_win.res"\
".\Debug\gc.lib"
".\Debug\de.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
@ -1945,6 +1949,9 @@ NODEP_CPP_WIN32=\
SOURCE=.\extra\msvc_dbg.c
msvc_dbg.copied.c : extra\msvc_dbg.c
copy extra\msvc_dbg.c msvc_dbg.copied.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_WIN32=\
@ -1961,9 +1968,9 @@ NODEP_CPP_WIN32=\
".\th\PCR_ThCtl.h"\
".\Release\msvc_dbg.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
".\Release\msvc_dbg.copied.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
".\Release\msvc_dbg.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
".\Release\msvc_dbg.copied.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
@ -1982,9 +1989,9 @@ NODEP_CPP_WIN32=\
".\th\PCR_ThCtl.h"\
".\Debug\msvc_dbg.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
".\Debug\msvc_dbg.copied.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
".\Debug\msvc_dbg.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
".\Debug\msvc_dbg.copied.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
!ENDIF
@ -2090,15 +2097,15 @@ NODEP_CPP_TEST_=\
!IF "$(CFG)" == "gctest - Win32 Release"
".\gctest\Release\test.obj" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
".\gctest\Release\test.copied.obj" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
!ELSEIF "$(CFG)" == "gctest - Win32 Debug"
".\gctest\Debug\test.obj" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
".\gctest\Debug\test.copied.obj" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
".\gctest\Debug\test.sbr" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
".\gctest\Debug\test.copied.sbr" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
!ENDIF

View file

@ -27,62 +27,73 @@ built-in "new" and "delete".
# define GC_BUILD
#endif
#include "gc_cpp.h"
#include "gc.h"
#if !defined(GC_NEW_DELETE_NEED_THROW) && defined(__GNUC__) \
&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
# define GC_NEW_DELETE_NEED_THROW
#include <new> // for bad_alloc, precedes include of gc_cpp.h
#include "gc_cpp.h" // for GC_OPERATOR_NEW_ARRAY, GC_DECL_DELETE_THROW
#if defined(GC_NEW_ABORTS_ON_OOM) || defined(_LIBCPP_NO_EXCEPTIONS)
# define GC_ALLOCATOR_THROW_OR_ABORT() GC_abort_on_oom()
#else
# define GC_ALLOCATOR_THROW_OR_ABORT() throw std::bad_alloc()
#endif
#ifdef GC_NEW_DELETE_NEED_THROW
# include <new> /* for std::bad_alloc */
# define GC_DECL_NEW_THROW throw(std::bad_alloc)
# define GC_DECL_DELETE_THROW throw()
#else
# define GC_DECL_NEW_THROW /* empty */
# define GC_DECL_DELETE_THROW /* empty */
#endif /* !GC_NEW_DELETE_NEED_THROW */
void* operator new( size_t size ) GC_DECL_NEW_THROW {
return GC_MALLOC_UNCOLLECTABLE(size);
GC_API void GC_CALL GC_throw_bad_alloc() {
GC_ALLOCATOR_THROW_OR_ABORT();
}
#if !defined(__CYGWIN__)
void operator delete( void* obj ) GC_DECL_DELETE_THROW {
GC_FREE(obj);
}
#endif /* !__CYGWIN__ */
#if !defined(_MSC_VER) && !defined(__DMC__)
#ifdef GC_OPERATOR_NEW_ARRAY
void* operator new[]( size_t size ) GC_DECL_NEW_THROW {
return GC_MALLOC_UNCOLLECTABLE(size);
}
void operator delete[]( void* obj ) GC_DECL_DELETE_THROW {
GC_FREE(obj);
}
#endif /* GC_OPERATOR_NEW_ARRAY */
#ifdef _MSC_VER
// This new operator is used by VC++ in case of Debug builds!
void* operator new( size_t size, int /* nBlockUse */,
const char * szFileName, int nLine ) GC_DECL_NEW_THROW
{
# ifndef GC_DEBUG
return GC_malloc_uncollectable(size);
# else
return GC_debug_malloc_uncollectable(size, szFileName, nLine);
# endif
}
# if _MSC_VER > 1020
// This new operator is used by VC++ 7.0 and later in Debug builds.
void* operator new[]( size_t size, int nBlockUse,
const char* szFileName, int nLine ) GC_DECL_NEW_THROW
{
return operator new(size, nBlockUse, szFileName, nLine);
}
# if !defined(GC_NEW_DELETE_THROW_NOT_NEEDED) \
&& !defined(GC_NEW_DELETE_NEED_THROW) \
&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) \
&& (__cplusplus < 201103L || defined(__clang__))
# define GC_NEW_DELETE_NEED_THROW
# endif
#endif /* _MSC_VER */
# ifdef GC_NEW_DELETE_NEED_THROW
# define GC_DECL_NEW_THROW throw(std::bad_alloc)
# else
# define GC_DECL_NEW_THROW /* empty */
# endif
void* operator new(size_t size) GC_DECL_NEW_THROW {
void* obj = GC_MALLOC_UNCOLLECTABLE(size);
if (0 == obj)
GC_ALLOCATOR_THROW_OR_ABORT();
return obj;
}
void operator delete(void* obj) GC_DECL_DELETE_THROW {
GC_FREE(obj);
}
# if defined(GC_OPERATOR_NEW_ARRAY) && !defined(CPPCHECK)
void* operator new[](size_t size) GC_DECL_NEW_THROW {
void* obj = GC_MALLOC_UNCOLLECTABLE(size);
if (0 == obj)
GC_ALLOCATOR_THROW_OR_ABORT();
return obj;
}
void operator delete[](void* obj) GC_DECL_DELETE_THROW {
GC_FREE(obj);
}
# endif // GC_OPERATOR_NEW_ARRAY
# if __cplusplus > 201103L // C++14
void operator delete(void* obj, size_t size) GC_DECL_DELETE_THROW {
(void)size; // size is ignored
GC_FREE(obj);
}
# if defined(GC_OPERATOR_NEW_ARRAY) && !defined(CPPCHECK)
void operator delete[](void* obj, size_t size) GC_DECL_DELETE_THROW {
(void)size;
GC_FREE(obj);
}
# endif
# endif // C++14
#endif // !_MSC_VER

View file

@ -54,8 +54,6 @@ int GC_gcj_debug_kind = 0;
GC_INNER ptr_t * GC_gcjobjfreelist = NULL;
STATIC ptr_t * GC_gcjdebugobjfreelist = NULL;
STATIC struct GC_ms_entry * GC_gcj_fake_mark_proc(word * addr GC_ATTR_UNUSED,
struct GC_ms_entry *mark_stack_ptr,
struct GC_ms_entry * mark_stack_limit GC_ATTR_UNUSED,
@ -69,7 +67,9 @@ STATIC struct GC_ms_entry * GC_gcj_fake_mark_proc(word * addr GC_ATTR_UNUSED,
GC_API void GC_CALL GC_init_gcj_malloc(int mp_index,
void * /* really GC_mark_proc */mp)
{
GC_bool ignore_gcj_info;
# ifndef GC_IGNORE_GCJ_INFO
GC_bool ignore_gcj_info;
# endif
DCL_LOCK_STATE;
if (mp == 0) /* In case GC_DS_PROC is unused. */
@ -84,7 +84,7 @@ GC_API void GC_CALL GC_init_gcj_malloc(int mp_index,
GC_gcj_malloc_initialized = TRUE;
# ifdef GC_IGNORE_GCJ_INFO
/* This is useful for debugging on platforms with missing getenv(). */
ignore_gcj_info = 1;
# define ignore_gcj_info TRUE
# else
ignore_gcj_info = (0 != GETENV("GC_IGNORE_GCJ_INFO"));
# endif
@ -101,7 +101,7 @@ GC_API void GC_CALL GC_init_gcj_malloc(int mp_index,
/* Use a simple length-based descriptor, thus forcing a fully */
/* conservative scan. */
GC_gcj_kind = GC_new_kind_inner((void **)GC_gcjobjfreelist,
(0 | GC_DS_LENGTH),
/* 0 | */ GC_DS_LENGTH,
TRUE, TRUE);
} else {
GC_gcj_kind = GC_new_kind_inner(
@ -114,16 +114,14 @@ GC_API void GC_CALL GC_init_gcj_malloc(int mp_index,
/* Set up object kind for objects that require mark proc call. */
if (ignore_gcj_info) {
GC_gcj_debug_kind = GC_gcj_kind;
GC_gcjdebugobjfreelist = GC_gcjobjfreelist;
} else {
GC_gcjdebugobjfreelist = (ptr_t *)GC_new_free_list_inner();
GC_gcj_debug_kind = GC_new_kind_inner(
(void **)GC_gcjdebugobjfreelist,
GC_gcj_debug_kind = GC_new_kind_inner(GC_new_free_list_inner(),
GC_MAKE_PROC(mp_index,
1 /* allocated with debug info */),
FALSE, TRUE);
}
UNLOCK();
# undef ignore_gcj_info
}
#define GENERAL_MALLOC_INNER(lb,k) \
@ -164,12 +162,12 @@ static void maybe_finalize(void)
#endif
{
ptr_t op;
word lg;
DCL_LOCK_STATE;
GC_DBG_COLLECT_AT_MALLOC(lb);
if(SMALL_OBJ(lb)) {
lg = GC_size_map[lb];
word lg = GC_size_map[lb];
LOCK();
op = GC_gcjobjfreelist[lg];
if(EXPECT(0 == op, FALSE)) {
@ -182,11 +180,9 @@ static void maybe_finalize(void)
}
} else {
GC_gcjobjfreelist[lg] = obj_link(op);
GC_bytes_allocd += GRANULES_TO_BYTES(lg);
GC_bytes_allocd += GRANULES_TO_BYTES((word)lg);
}
*(void **)op = ptr_to_struct_containing_descr;
GC_ASSERT(((void **)op)[1] == 0);
UNLOCK();
} else {
LOCK();
maybe_finalize();
@ -196,10 +192,12 @@ static void maybe_finalize(void)
UNLOCK();
return((*oom_fn)(lb));
}
*(void **)op = ptr_to_struct_containing_descr;
UNLOCK();
}
return((void *) op);
*(void **)op = ptr_to_struct_containing_descr;
UNLOCK();
GC_dirty(op);
REACHABLE_AFTER_DIRTY(ptr_to_struct_containing_descr);
return (void *)op;
}
/* Similar to GC_gcj_malloc, but add debug info. This is allocated */
@ -214,7 +212,8 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_gcj_malloc(size_t lb,
/* confuse the backtrace. */
LOCK();
maybe_finalize();
result = GC_generic_malloc_inner(lb + DEBUG_BYTES, GC_gcj_debug_kind);
result = GC_generic_malloc_inner(SIZET_SAT_ADD(lb, DEBUG_BYTES),
GC_gcj_debug_kind);
if (result == 0) {
GC_oom_func oom_fn = GC_oom_fn;
UNLOCK();
@ -223,12 +222,15 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_gcj_malloc(size_t lb,
return((*oom_fn)(lb));
}
*((void **)((ptr_t)result + sizeof(oh))) = ptr_to_struct_containing_descr;
UNLOCK();
if (!GC_debugging_started) {
GC_start_debugging();
GC_start_debugging_inner();
}
ADD_CALL_CHAIN(result, ra);
return (GC_store_debug_info(result, (word)lb, s, i));
result = GC_store_debug_info_inner(result, (word)lb, s, i);
UNLOCK();
GC_dirty(result);
REACHABLE_AFTER_DIRTY(ptr_to_struct_containing_descr);
return result;
}
/* There is no THREAD_LOCAL_ALLOC for GC_gcj_malloc_ignore_off_page(). */
@ -236,12 +238,12 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_gcj_malloc_ignore_off_page(size_t lb,
void * ptr_to_struct_containing_descr)
{
ptr_t op;
word lg;
DCL_LOCK_STATE;
GC_DBG_COLLECT_AT_MALLOC(lb);
if(SMALL_OBJ(lb)) {
lg = GC_size_map[lb];
word lg = GC_size_map[lb];
LOCK();
op = GC_gcjobjfreelist[lg];
if (EXPECT(0 == op, FALSE)) {
@ -254,7 +256,7 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_gcj_malloc_ignore_off_page(size_t lb,
}
} else {
GC_gcjobjfreelist[lg] = obj_link(op);
GC_bytes_allocd += GRANULES_TO_BYTES(lg);
GC_bytes_allocd += GRANULES_TO_BYTES((word)lg);
}
} else {
LOCK();
@ -268,7 +270,9 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_gcj_malloc_ignore_off_page(size_t lb,
}
*(void **)op = ptr_to_struct_containing_descr;
UNLOCK();
return((void *) op);
GC_dirty(op);
REACHABLE_AFTER_DIRTY(ptr_to_struct_containing_descr);
return (void *)op;
}
#endif /* GC_GCJ_SUPPORT */

View file

@ -118,7 +118,7 @@ static ptr_t scratch_free_ptr = 0;
GC_INNER ptr_t GC_scratch_alloc(size_t bytes)
{
ptr_t result = scratch_free_ptr;
word bytes_to_get;
size_t bytes_to_get;
bytes = ROUNDUP_GRANULE_SIZE(bytes);
for (;;) {
@ -170,7 +170,7 @@ static hdr * alloc_hdr(void)
register hdr * result;
if (hdr_free_list == 0) {
result = (hdr *) GC_scratch_alloc((word)(sizeof(hdr)));
result = (hdr *)GC_scratch_alloc(sizeof(hdr));
} else {
result = hdr_free_list;
hdr_free_list = (hdr *) (result -> hb_next);
@ -194,7 +194,7 @@ GC_INNER void GC_init_headers(void)
{
register unsigned i;
GC_all_nils = (bottom_index *)GC_scratch_alloc((word)sizeof(bottom_index));
GC_all_nils = (bottom_index *)GC_scratch_alloc(sizeof(bottom_index));
if (GC_all_nils == NULL) {
GC_err_printf("Insufficient memory for GC_all_nils\n");
EXIT();
@ -224,14 +224,14 @@ static GC_bool get_index(word addr)
if (p -> key == hi) return(TRUE);
p = p -> hash_link;
}
r = (bottom_index*)GC_scratch_alloc((word)(sizeof (bottom_index)));
r = (bottom_index *)GC_scratch_alloc(sizeof(bottom_index));
if (r == 0) return(FALSE);
BZERO(r, sizeof (bottom_index));
r -> hash_link = old;
GC_top_index[i] = r;
# else
if (GC_top_index[hi] != GC_all_nils) return(TRUE);
r = (bottom_index*)GC_scratch_alloc((word)(sizeof (bottom_index)));
r = (bottom_index *)GC_scratch_alloc(sizeof(bottom_index));
if (r == 0) return(FALSE);
GC_top_index[hi] = r;
BZERO(r, sizeof (bottom_index));
@ -277,14 +277,14 @@ GC_INNER struct hblkhdr * GC_install_header(struct hblk *h)
GC_INNER GC_bool GC_install_counts(struct hblk *h, size_t sz/* bytes */)
{
struct hblk * hbp;
word i;
for (hbp = h; (word)hbp < (word)h + sz; hbp += BOTTOM_SZ) {
if (!get_index((word) hbp)) return(FALSE);
}
if (!get_index((word)h + sz - 1)) return(FALSE);
for (hbp = h + 1; (word)hbp < (word)h + sz; hbp += 1) {
i = HBLK_PTR_DIFF(hbp, h);
word i = HBLK_PTR_DIFF(hbp, h);
SET_HDR(hbp, (hdr *)(i > MAX_JUMP? MAX_JUMP : i));
}
return(TRUE);

View file

@ -3,9 +3,6 @@
/* Define to recognise all pointers to the interior of objects. */
#undef ALL_INTERIOR_POINTERS
/* Define to enable atomic uncollectible allocation. */
#undef ATOMIC_UNCOLLECTABLE
/* See doc/README.macros. */
#undef DARWIN_DONT_PARSE_STACK
@ -30,6 +27,9 @@
/* Define to enable internal debug assertions. */
#undef GC_ASSERTIONS
/* Define to enable atomic uncollectible allocation. */
#undef GC_ATOMIC_UNCOLLECTABLE
/* Define to support Darwin pthreads. */
#undef GC_DARWIN_THREADS
@ -39,6 +39,9 @@
/* Define to build dynamic libraries with only API symbols exposed. */
#undef GC_DLL
/* Define to turn on GC_suspend_thread support. */
#undef GC_ENABLE_SUSPEND_THREAD
/* Define to support FreeBSD pthreads. */
#undef GC_FREEBSD_THREADS
@ -48,6 +51,9 @@
/* Define to support GNU pthreads. */
#undef GC_GNU_THREADS
/* Define to support Haiku pthreads. */
#undef GC_HAIKU_THREADS
/* Define if backtrace information is supported. */
#undef GC_HAVE_BUILTIN_BACKTRACE
@ -63,6 +69,9 @@
/* Define to support pthreads on Linux. */
#undef GC_LINUX_THREADS
/* Missing execinfo.h header. */
#undef GC_MISSING_EXECINFO_H
/* Define to support NetBSD pthreads. */
#undef GC_NETBSD_THREADS
@ -93,6 +102,15 @@
/* See doc/README.macros. */
#undef GC_USE_DLOPEN_WRAP
/* The major version number of this GC release. */
#undef GC_VERSION_MAJOR
/* The micro version number of this GC release. */
#undef GC_VERSION_MICRO
/* The minor version number of this GC release. */
#undef GC_VERSION_MINOR
/* Define to support pthreads-win32 or winpthreads. */
#undef GC_WIN32_PTHREADS
@ -108,6 +126,15 @@
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define if 'dl_iterate_phdr' function is available. */
#undef HAVE_DL_ITERATE_PHDR
/* Define to 1 if you have the <execinfo.h> header file. */
#undef HAVE_EXECINFO_H
/* Define to 1 if you have the `getcontext' function. */
#undef HAVE_GETCONTEXT
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
@ -162,6 +189,9 @@
/* Define to make the collector not allocate executable memory by default. */
#undef NO_EXECUTE_PERMISSION
/* Missing getcontext function. */
#undef NO_GETCONTEXT
/* Prohibit installation of pthread_atfork() handlers. */
#undef NO_HANDLE_FORK

View file

@ -58,7 +58,7 @@
#include <stddef.h>
#include <stdio.h>
#ifdef GC_DLL
#if defined(GC_DLL) && !defined(CORD_NOT_DLL)
/* Same as for GC_API in gc_config_macros.h. */
# ifdef CORD_BUILD
# if defined(__MINGW32__) || defined(__CEGCC__)
@ -66,8 +66,8 @@
# elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \
|| defined(__CYGWIN__) || defined(__WATCOMC__)
# define CORD_API extern __declspec(dllexport)
# elif defined(__GNUC__) && (__GNUC__ >= 4 \
|| defined(GC_VISIBILITY_HIDDEN_SET))
# elif defined(__GNUC__) && !defined(GC_NO_VISIBILITY) \
&& (__GNUC__ >= 4 || defined(GC_VISIBILITY_HIDDEN_SET))
/* Only matters if used in conjunction with -fvisibility=hidden option. */
# define CORD_API extern __attribute__((__visibility__("default")))
# endif

View file

@ -43,7 +43,7 @@ typedef struct CORD_ec_struct {
/* This structure represents the concatenation of ec_cord with */
/* ec_buf[0 ... (ec_bufptr-ec_buf-1)] */
/* Flush the buffer part of the extended chord into ec_cord. */
/* Flush the buffer part of the extended cord into ec_cord. */
/* Note that this is almost the only real function, and it is */
/* implemented in 6 lines in cordxtra.c */
void CORD_ec_flush_buf(CORD_ec x);

View file

@ -5,6 +5,7 @@
* Copyright 1999 by Hewlett-Packard Company. All rights reserved.
* Copyright (C) 2007 Free Software Foundation, Inc
* Copyright (c) 2000-2011 by Hewlett-Packard Development Company.
* Copyright (c) 2009-2018 Ivan Maidanski
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@ -31,6 +32,11 @@
#ifndef GC_H
#define GC_H
/* Help debug mixed up preprocessor symbols. */
#if (defined(WIN64) && !defined(_WIN64)) && defined(_MSC_VER)
#pragma message("Warning: Expecting _WIN64 for x64 targets! Notice the leading underscore!")
#endif
#include "gc_version.h"
/* Define version numbers here to allow test on build machine */
/* for cross-builds. Note that this defines the header */
@ -54,7 +60,7 @@ typedef void * GC_PTR; /* preserved only for backward compatibility */
/* better choices. But those had incorrect definitions on some older */
/* systems. Notably "typedef int size_t" is WRONG. */
#ifdef _WIN64
# ifdef __int64
# if defined(__int64) && !defined(CPPCHECK)
typedef unsigned __int64 GC_word;
typedef __int64 GC_signed_word;
# else
@ -129,10 +135,50 @@ GC_API GC_on_heap_resize_proc GC_CALL GC_get_on_heap_resize(void);
/* Both the supplied setter and the getter */
/* acquire the GC lock (to avoid data races). */
typedef enum {
GC_EVENT_START /* COLLECTION */,
GC_EVENT_MARK_START,
GC_EVENT_MARK_END,
GC_EVENT_RECLAIM_START,
GC_EVENT_RECLAIM_END,
GC_EVENT_END /* COLLECTION */,
GC_EVENT_PRE_STOP_WORLD /* STOPWORLD_BEGIN */,
GC_EVENT_POST_STOP_WORLD /* STOPWORLD_END */,
GC_EVENT_PRE_START_WORLD /* STARTWORLD_BEGIN */,
GC_EVENT_POST_START_WORLD /* STARTWORLD_END */,
GC_EVENT_THREAD_SUSPENDED,
GC_EVENT_THREAD_UNSUSPENDED
} GC_EventType;
typedef void (GC_CALLBACK * GC_on_collection_event_proc)(GC_EventType);
/* Invoked to indicate progress through the */
/* collection process. Not used for thread */
/* suspend/resume notifications. Called with */
/* the GC lock held (or, even, the world */
/* stopped). May be 0 (means no notifier). */
GC_API void GC_CALL GC_set_on_collection_event(GC_on_collection_event_proc);
GC_API GC_on_collection_event_proc GC_CALL GC_get_on_collection_event(void);
/* Both the supplied setter and the getter */
/* acquire the GC lock (to avoid data races). */
#ifdef GC_THREADS
typedef void (GC_CALLBACK * GC_on_thread_event_proc)(GC_EventType,
void * /* thread_id */);
/* Invoked when a thread is suspended or */
/* resumed during collection. Called with the */
/* GC lock held (and the world stopped */
/* partially). May be 0 (means no notifier). */
GC_API void GC_CALL GC_set_on_thread_event(GC_on_thread_event_proc);
GC_API GC_on_thread_event_proc GC_CALL GC_get_on_thread_event(void);
/* Both the supplied setter and the getter */
/* acquire the GC lock (to avoid data races). */
#endif
GC_API GC_ATTR_DEPRECATED int GC_find_leak;
/* Do not actually garbage collect, but simply */
/* Set to true to turn on the leak-finding mode */
/* (do not actually garbage collect, but simply */
/* report inaccessible memory that was not */
/* deallocated with GC_free. Initial value */
/* deallocated with GC_FREE). Initial value */
/* is determined by FIND_LEAK macro. */
/* The value should not typically be modified */
/* after GC initialization (and, thus, it does */
@ -274,7 +320,7 @@ GC_API GC_ATTR_DEPRECATED GC_word GC_free_space_divisor;
/* bytes (bytes in "atomic" objects), plus */
/* a rough estimate of the root set size. */
/* N approximates GC tracing work per GC. */
/* Initially, GC_free_space_divisor = 3. */
/* The initial value is GC_FREE_SPACE_DIVISOR. */
/* Increasing its value will use less space */
/* but more collection time. Decreasing it */
/* will appreciably decrease collection time */
@ -283,6 +329,8 @@ GC_API GC_ATTR_DEPRECATED GC_word GC_free_space_divisor;
/* GC_call_with_alloc_lock() is required to */
/* avoid data races (if the value is modified */
/* after the GC is put to multi-threaded mode). */
/* In version 7.1 (and before), the setter */
/* returned the old value. */
GC_API void GC_CALL GC_set_free_space_divisor(GC_word);
GC_API GC_word GC_CALL GC_get_free_space_divisor(void);
@ -395,6 +443,10 @@ GC_API void GC_CALL GC_atfork_child(void);
/* from the main program instead. */
GC_API void GC_CALL GC_init(void);
/* Returns non-zero (TRUE) if and only if the collector is initialized */
/* (or, at least, the initialization is in progress). */
GC_API int GC_CALL GC_is_init_called(void);
/* General purpose allocation routines, with roughly malloc calling */
/* conv. The atomic versions promise that no relevant pointers are */
/* contained in the object. The non-atomic versions guarantee that the */
@ -482,7 +534,20 @@ GC_API size_t GC_CALL GC_size(const void * /* obj_addr */) GC_ATTR_NONNULL(1);
/* The resulting object has the same kind as the original. */
/* If the argument is stubborn, the result will have changes enabled. */
/* It is an error to have changes enabled for the original object. */
/* Follows ANSI conventions for NULL old_object. */
/* It does not change the content of the object from its beginning to */
/* the minimum of old size and new_size_in_bytes; the content above in */
/* case of object size growth is initialized to zero (not guaranteed */
/* for atomic object type). The function follows ANSI conventions for */
/* NULL old_object (i.e., equivalent to GC_malloc regardless of new */
/* size). If new size is zero (and old_object is non-NULL) then the */
/* call is equivalent to GC_free (and NULL is returned). If old_object */
/* is non-NULL, it must have been returned by an earlier call to */
/* GC_malloc* or GC_realloc. In case of the allocation failure, the */
/* memory pointed by old_object is untouched (and not freed). */
/* If the returned pointer is not the same as old_object and both of */
/* them are non-NULL then old_object is freed. Returns either NULL (in */
/* case of the allocation failure or zero new size) or pointer to the */
/* allocated memory. */
GC_API void * GC_CALL GC_realloc(void * /* old_object */,
size_t /* new_size_in_bytes */)
/* 'realloc' attr */ GC_ATTR_ALLOC_SIZE(2);
@ -585,7 +650,7 @@ GC_API GC_stop_func GC_CALL GC_get_stop_func(void);
/* This getter remains lock-free (unsynchronized) for compatibility */
/* reason since some existing clients call it from a GC callback */
/* holding the allocator lock. (This API function and the following */
/* four ones bellow were made thread-safe in GC v7.2alpha1 and */
/* four ones below were made thread-safe in GC v7.2alpha1 and */
/* reverted back in v7.2alpha7 for the reason described.) */
GC_API size_t GC_CALL GC_get_heap_size(void);
@ -680,6 +745,10 @@ GC_API size_t GC_CALL GC_get_prof_stats(struct GC_prof_stats_s *,
size_t /* stats_sz */);
#endif
/* Count total memory use in bytes by all allocated blocks. Acquires */
/* the lock. */
GC_API size_t GC_CALL GC_get_memory_use(void);
/* Disable garbage collection. Even GC_gcollect calls will be */
/* ineffective. */
GC_API void GC_CALL GC_disable(void);
@ -708,7 +777,7 @@ GC_API void GC_CALL GC_enable_incremental(void);
/* Does incremental mode write-protect pages? Returns zero or */
/* more of the following, or'ed together: */
#define GC_PROTECTS_POINTER_HEAP 1 /* May protect non-atomic objs. */
#define GC_PROTECTS_POINTER_HEAP 1 /* May protect non-atomic objects. */
#define GC_PROTECTS_PTRFREE_HEAP 2
#define GC_PROTECTS_STATIC_DATA 4 /* Currently never. */
#define GC_PROTECTS_STACK 8 /* Probably impractical. */
@ -718,7 +787,8 @@ GC_API void GC_CALL GC_enable_incremental(void);
GC_API int GC_CALL GC_incremental_protection_needs(void);
/* Perform some garbage collection work, if appropriate. */
/* Return 0 if there is no more work to be done. */
/* Return 0 if there is no more work to be done (including the */
/* case when garbage collection is not appropriate). */
/* Typically performs an amount of work corresponding roughly */
/* to marking from one page. May do more work if further */
/* progress requires it, e.g. if incremental collection is */
@ -933,6 +1003,7 @@ GC_API void GC_CALL GC_debug_register_finalizer(void * /* obj */,
/* be avoided, or broken by disappearing links. */
/* All but the last finalizer registered for an object */
/* is ignored. */
/* No-op in the leak-finding mode. */
/* Finalization may be removed by passing 0 as fn. */
/* Finalizers are implicitly unregistered when they are */
/* enqueued for finalization (i.e. become ready to be */
@ -1070,6 +1141,7 @@ GC_API int GC_CALL GC_general_register_disappearing_link(void ** /* link */,
/* explicitly deallocate the object containing link. */
/* Explicit deallocation of obj may or may not cause */
/* link to eventually be cleared. */
/* No-op in the leak-finding mode. */
/* This function can be used to implement certain types */
/* of weak pointers. Note, however, this generally */
/* requires that the allocation lock is held (see */
@ -1081,7 +1153,8 @@ GC_API int GC_CALL GC_general_register_disappearing_link(void ** /* link */,
/* succeeded (a new link is registered), GC_DUPLICATE */
/* if link was already registered (with some object), */
/* GC_NO_MEMORY if registration failed for lack of */
/* memory (and GC_oom_fn did not handle the problem). */
/* memory (and GC_oom_fn did not handle the problem), */
/* GC_UNIMPLEMENTED if GC_find_leak is true. */
GC_API int GC_CALL GC_move_disappearing_link(void ** /* link */,
void ** /* new_link */)
@ -1124,7 +1197,54 @@ GC_API int GC_CALL GC_unregister_long_link(void ** /* link */);
/* Similar to GC_unregister_disappearing_link but for a */
/* registration by either of the above two routines. */
/* Support of toggle-ref style of external memory management */
/* without hooking up to the host retain/release machinery. */
/* The idea of toggle-ref is that an external reference to */
/* an object is kept and it can be either a strong or weak */
/* reference; a weak reference is used when the external peer */
/* has no interest in the object, and a strong otherwise. */
typedef enum {
GC_TOGGLE_REF_DROP,
GC_TOGGLE_REF_STRONG,
GC_TOGGLE_REF_WEAK
} GC_ToggleRefStatus;
/* The callback is to decide (return) the new state of a given */
/* object. Invoked by the collector for all objects registered */
/* for toggle-ref processing. Invoked with the allocation lock */
/* held (but the "world" is running). */
typedef GC_ToggleRefStatus (GC_CALLBACK *GC_toggleref_func)(void * /* obj */);
/* Set (register) a callback that decides the state of a given */
/* object (by, probably, inspecting its native state). */
/* The argument may be 0 (means no callback). Both the setter */
/* and the getter acquire the allocation lock (to avoid data */
/* races). */
GC_API void GC_CALL GC_set_toggleref_func(GC_toggleref_func);
GC_API GC_toggleref_func GC_CALL GC_get_toggleref_func(void);
/* Register a given object for toggle-ref processing. It will */
/* be stored internally and the toggle-ref callback will be */
/* invoked on the object until the callback returns */
/* GC_TOGGLE_REF_DROP or the object is collected. If is_strong */
/* is true then the object is registered with a strong ref, */
/* a weak one otherwise. Returns GC_SUCCESS if registration */
/* succeeded (or no callback registered yet), GC_NO_MEMORY if */
/* it failed for lack of memory. */
GC_API int GC_CALL GC_toggleref_add(void * /* obj */, int /* is_strong */)
GC_ATTR_NONNULL(1);
/* Finalizer callback support. Invoked by the collector (with */
/* the allocation lock held) for each unreachable object */
/* enqueued for finalization. */
typedef void (GC_CALLBACK * GC_await_finalize_proc)(void * /* obj */);
GC_API void GC_CALL GC_set_await_finalize_proc(GC_await_finalize_proc);
GC_API GC_await_finalize_proc GC_CALL GC_get_await_finalize_proc(void);
/* Zero means no callback. The setter */
/* and getter acquire the lock too. */
/* Returns !=0 if GC_invoke_finalizers has something to do. */
/* Does not use any synchronization. */
GC_API int GC_CALL GC_should_invoke_finalizers(void);
GC_API int GC_CALL GC_invoke_finalizers(void);
@ -1155,7 +1275,8 @@ GC_API int GC_CALL GC_invoke_finalizers(void);
/* GC_set_warn_proc can be used to redirect or filter warning messages. */
/* p may not be a NULL pointer. msg is printf format string (arg must */
/* match the format). Both the setter and the getter acquire the GC */
/* lock (to avoid data races). */
/* lock (to avoid data races). In version 7.1 (and before), the setter */
/* returned the old warn_proc value. */
typedef void (GC_CALLBACK * GC_warn_proc)(char * /* msg */,
GC_word /* arg */);
GC_API void GC_CALL GC_set_warn_proc(GC_warn_proc /* p */) GC_ATTR_NONNULL(1);
@ -1180,6 +1301,9 @@ typedef void (GC_CALLBACK * GC_abort_func)(const char * /* msg */);
GC_API void GC_CALL GC_set_abort_func(GC_abort_func) GC_ATTR_NONNULL(1);
GC_API GC_abort_func GC_CALL GC_get_abort_func(void);
/* A portable way to abort the application because of not enough memory.*/
GC_API void GC_CALL GC_abort_on_oom(void);
/* The following is intended to be used by a higher level */
/* (e.g. Java-like) finalization facility. It is expected */
/* that finalization code will arrange for hidden pointers to */
@ -1303,6 +1427,7 @@ GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */,
/* latter case, the explicit call is normally required for threads */
/* created by third-party libraries. */
/* A manually registered thread requires manual unregistering. */
/* Returns GC_SUCCESS on success, GC_DUPLICATE if already registered. */
GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *)
GC_ATTR_NONNULL(1);
@ -1310,6 +1435,14 @@ GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */,
/* registered with the garbage collector. */
GC_API int GC_CALL GC_thread_is_registered(void);
/* Notify the collector about the stack and the alt-stack of the */
/* current thread. stack_start/size is used to determine the stack */
/* boundaries when a thread is suspended while it is on an alt-stack. */
GC_API void GC_CALL GC_register_altstack(void * /* stack_start */,
GC_word /* stack_size */,
void * /* altstack_base */,
GC_word /* altstack_size */);
/* Unregister the current thread. Only an explicitly registered */
/* thread (i.e. for which GC_register_my_thread() returns GC_SUCCESS) */
/* is allowed (and required) to call this function. (As a special */
@ -1402,6 +1535,15 @@ GC_API void * GC_CALL GC_is_valid_displacement(void * /* p */);
/* Defined only if the library has been compiled without NO_DEBUGGING. */
GC_API void GC_CALL GC_dump(void);
/* Dump information about each block of every GC memory section. */
/* Defined only if the library has been compiled without NO_DEBUGGING. */
GC_API void GC_CALL GC_dump_regions(void);
/* Dump information about every registered disappearing link and */
/* finalizable object. */
/* Defined only if the library has been compiled without NO_DEBUGGING. */
GC_API void GC_CALL GC_dump_finalization(void);
/* Safer, but slow, pointer addition. Probably useful mainly with */
/* a preprocessor. Useful only for heap pointers. */
/* Only the macros without trailing digits are meant to be used */
@ -1417,10 +1559,10 @@ GC_API void GC_CALL GC_dump(void);
((type_of_result)GC_pre_incr((void **)(&(x)), (n)*sizeof(*x)))
# define GC_POST_INCR3(x, n, type_of_result) \
((type_of_result)GC_post_incr((void **)(&(x)), (n)*sizeof(*x)))
# define GC_PTR_ADD(x, n) GC_PTR_ADD3(x, n, typeof(x))
# define GC_PRE_INCR(x, n) GC_PRE_INCR3(x, n, typeof(x))
# define GC_POST_INCR(x) GC_POST_INCR3(x, 1, typeof(x))
# define GC_POST_DECR(x) GC_POST_INCR3(x, -1, typeof(x))
# define GC_PTR_ADD(x, n) GC_PTR_ADD3(x, n, __typeof__(x))
# define GC_PRE_INCR(x, n) GC_PRE_INCR3(x, n, __typeof__(x))
# define GC_POST_INCR(x) GC_POST_INCR3(x, 1, __typeof__(x))
# define GC_POST_DECR(x) GC_POST_INCR3(x, -1, __typeof__(x))
#else /* !GC_DEBUG || !__GNUC__ */
/* We can't do this right without typeof, which ANSI decided was not */
/* sufficiently useful. Without it we resort to the non-debug version. */
@ -1478,8 +1620,14 @@ typedef int (GC_CALLBACK * GC_has_static_roots_func)(
GC_API void GC_CALL GC_register_has_static_roots_callback(
GC_has_static_roots_func);
#if !defined(CPPCHECK) && !defined(GC_WINDOWS_H_INCLUDED) && defined(WINAPI)
/* windows.h is included before gc.h */
# define GC_WINDOWS_H_INCLUDED
#endif
#if defined(GC_WIN32_THREADS) \
&& (!defined(GC_PTHREADS) || defined(GC_BUILD) || defined(WINAPI))
&& (!defined(GC_PTHREADS) || defined(GC_BUILD) \
|| defined(GC_WINDOWS_H_INCLUDED))
/* Note: for Cygwin and pthreads-win32, this is skipped */
/* unless windows.h is included before gc.h. */
@ -1493,7 +1641,10 @@ GC_API void GC_CALL GC_register_has_static_roots_callback(
# include <process.h> /* For _beginthreadex, _endthreadex */
# endif
# include <windows.h>
# if defined(GC_BUILD) || !defined(GC_DONT_INCLUDE_WINDOWS_H)
# include <windows.h>
# define GC_WINDOWS_H_INCLUDED
# endif
# ifdef __cplusplus
extern "C" {
@ -1506,14 +1657,14 @@ GC_API void GC_CALL GC_register_has_static_roots_callback(
# define GC_ExitThread _GC_ExitThread
# endif
# ifdef GC_INSIDE_DLL
/* Export GC DllMain to be invoked from client DllMain. */
# ifdef GC_UNDERSCORE_STDCALL
# define GC_DllMain _GC_DllMain
# ifndef DECLSPEC_NORETURN
/* Typically defined in winnt.h. */
# ifdef GC_WINDOWS_H_INCLUDED
# define DECLSPEC_NORETURN /* empty */
# else
# define DECLSPEC_NORETURN __declspec(noreturn)
# endif
GC_API BOOL WINAPI GC_DllMain(HINSTANCE /* inst */, ULONG /* reason */,
LPVOID /* reserved */);
# endif /* GC_INSIDE_DLL */
# endif
# if !defined(_UINTPTR_T) && !defined(_UINTPTR_T_DEFINED) \
&& !defined(UINTPTR_MAX)
@ -1521,7 +1672,28 @@ GC_API void GC_CALL GC_register_has_static_roots_callback(
# else
typedef uintptr_t GC_uintptr_t;
# endif
# define GC_WIN32_SIZE_T GC_uintptr_t
# ifdef _WIN64
# define GC_WIN32_SIZE_T GC_uintptr_t
# elif defined(GC_WINDOWS_H_INCLUDED)
# define GC_WIN32_SIZE_T DWORD
# else
# define GC_WIN32_SIZE_T unsigned long
# endif
# ifdef GC_INSIDE_DLL
/* Export GC DllMain to be invoked from client DllMain. */
# ifdef GC_UNDERSCORE_STDCALL
# define GC_DllMain _GC_DllMain
# endif
# ifdef GC_WINDOWS_H_INCLUDED
GC_API BOOL WINAPI GC_DllMain(HINSTANCE /* inst */,
ULONG /* reason */,
LPVOID /* reserved */);
# else
GC_API int __stdcall GC_DllMain(void *, unsigned long, void *);
# endif
# endif /* GC_INSIDE_DLL */
/* All threads must be created using GC_CreateThread or */
/* GC_beginthreadex, or must explicitly call GC_register_my_thread */
@ -1533,20 +1705,24 @@ GC_API void GC_CALL GC_register_has_static_roots_callback(
/* Currently the collector expects all threads to fall through and */
/* terminate normally, or call GC_endthreadex() or GC_ExitThread, */
/* so that the thread is properly unregistered. */
GC_API HANDLE WINAPI GC_CreateThread(
# ifdef GC_WINDOWS_H_INCLUDED
GC_API HANDLE WINAPI GC_CreateThread(
LPSECURITY_ATTRIBUTES /* lpThreadAttributes */,
GC_WIN32_SIZE_T /* dwStackSize */,
LPTHREAD_START_ROUTINE /* lpStartAddress */,
LPVOID /* lpParameter */, DWORD /* dwCreationFlags */,
LPDWORD /* lpThreadId */);
# ifndef DECLSPEC_NORETURN
/* Typically defined in winnt.h. */
# define DECLSPEC_NORETURN /* empty */
# endif
GC_API DECLSPEC_NORETURN void WINAPI GC_ExitThread(
GC_API DECLSPEC_NORETURN void WINAPI GC_ExitThread(
DWORD /* dwExitCode */);
# else
struct _SECURITY_ATTRIBUTES;
GC_API void *__stdcall GC_CreateThread(struct _SECURITY_ATTRIBUTES *,
GC_WIN32_SIZE_T,
unsigned long (__stdcall *)(void *),
void *, unsigned long, unsigned long *);
GC_API DECLSPEC_NORETURN void __stdcall GC_ExitThread(unsigned long);
# endif
# if !defined(_WIN32_WCE) && !defined(__CEGCC__)
GC_API GC_uintptr_t GC_CALL GC_beginthreadex(
@ -1603,11 +1779,21 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
#if defined(__CYGWIN32__) || defined(__CYGWIN__)
/* Similarly gnu-win32 DLLs need explicit initialization from the */
/* main program, as does AIX. */
extern int _data_start__[], _data_end__[], _bss_start__[], _bss_end__[];
# define GC_DATASTART ((GC_word)_data_start__ < (GC_word)_bss_start__ ? \
(void *)_data_start__ : (void *)_bss_start__)
# define GC_DATAEND ((GC_word)_data_end__ > (GC_word)_bss_end__ ? \
(void *)_data_end__ : (void *)_bss_end__)
# ifdef __x86_64__
/* Cygwin/x64 does not add leading underscore to symbols anymore. */
extern int __data_start__[], __data_end__[];
extern int __bss_start__[], __bss_end__[];
# define GC_DATASTART ((GC_word)__data_start__ < (GC_word)__bss_start__ \
? (void *)__data_start__ : (void *)__bss_start__)
# define GC_DATAEND ((GC_word)__data_end__ > (GC_word)__bss_end__ \
? (void *)__data_end__ : (void *)__bss_end__)
# else
extern int _data_start__[], _data_end__[], _bss_start__[], _bss_end__[];
# define GC_DATASTART ((GC_word)_data_start__ < (GC_word)_bss_start__ \
? (void *)_data_start__ : (void *)_bss_start__)
# define GC_DATAEND ((GC_word)_data_end__ > (GC_word)_bss_end__ \
? (void *)_data_end__ : (void *)_bss_end__)
# endif /* !__x86_64__ */
# define GC_INIT_CONF_ROOTS GC_add_roots(GC_DATASTART, GC_DATAEND); \
GC_gcollect() /* For blacklisting. */
/* Required at least if GC is in a DLL. And doesn't hurt. */
@ -1618,23 +1804,29 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
# define GC_INIT_CONF_ROOTS GC_add_roots(GC_DATASTART, GC_DATAEND)
#elif (defined(PLATFORM_ANDROID) || defined(__ANDROID__)) \
&& !defined(GC_NOT_DLL)
# pragma weak __data_start
extern int __data_start[], _end[];
# pragma weak _etext
# pragma weak __data_start
# pragma weak __dso_handle
extern int _etext[], __dso_handle[];
/* Explicitly register caller static data roots (__data_start points */
/* to the beginning typically but NDK "gold" linker could provide it */
/* incorrectly, so the workaround is to check the value and use */
/* __dso_handle as an alternative data start reference if provided). */
/* It also works for Android/x86 target where __data_start is not */
/* defined currently (regardless of linker used). */
extern int _etext[], __data_start[], __dso_handle[];
# pragma weak __end__
extern int __end__[], _end[];
/* Explicitly register caller static data roots. Workaround for */
/* __data_start: NDK "gold" linker might miss it or place it */
/* incorrectly, __dso_handle is an alternative data start reference. */
/* Workaround for _end: NDK Clang 3.5+ does not place it at correct */
/* offset (as of NDK r10e) but "bfd" linker provides __end__ symbol */
/* that could be used instead. */
# define GC_INIT_CONF_ROOTS \
(void)((GC_word)__data_start < (GC_word)_etext \
&& (GC_word)_etext < (GC_word)__dso_handle ? \
(GC_add_roots(__dso_handle, _end), 0) : \
(GC_word)__data_start != 0 ? \
(GC_add_roots(__data_start, _end), 0) : 0)
&& (GC_word)_etext < (GC_word)__dso_handle \
? (__end__ != 0 \
? (GC_add_roots(__dso_handle, __end__), 0) \
: (GC_word)__dso_handle < (GC_word)_end \
? (GC_add_roots(__dso_handle, _end), 0) : 0) \
: __data_start != 0 ? (__end__ != 0 \
? (GC_add_roots(__data_start, __end__), 0) \
: (GC_word)__data_start < (GC_word)_end \
? (GC_add_roots(__data_start, _end), 0) : 0) : 0)
#else
# define GC_INIT_CONF_ROOTS /* empty */
#endif
@ -1658,14 +1850,14 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
/* This is for debugging only (useful if environment variables are */
/* unsupported); cannot call GC_disable as goes before GC_init. */
# define GC_INIT_CONF_MAX_RETRIES (void)(GC_dont_gc = 1)
#elif defined(GC_MAX_RETRIES)
#elif defined(GC_MAX_RETRIES) && !defined(CPPCHECK)
/* Set GC_max_retries to the desired value at start-up */
# define GC_INIT_CONF_MAX_RETRIES GC_set_max_retries(GC_MAX_RETRIES)
#else
# define GC_INIT_CONF_MAX_RETRIES /* empty */
#endif
#ifdef GC_FREE_SPACE_DIVISOR
#if defined(GC_FREE_SPACE_DIVISOR) && !defined(CPPCHECK)
/* Set GC_free_space_divisor to the desired value at start-up */
# define GC_INIT_CONF_FREE_SPACE_DIVISOR \
GC_set_free_space_divisor(GC_FREE_SPACE_DIVISOR)
@ -1673,34 +1865,34 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
# define GC_INIT_CONF_FREE_SPACE_DIVISOR /* empty */
#endif
#ifdef GC_FULL_FREQ
#if defined(GC_FULL_FREQ) && !defined(CPPCHECK)
/* Set GC_full_freq to the desired value at start-up */
# define GC_INIT_CONF_FULL_FREQ GC_set_full_freq(GC_FULL_FREQ)
#else
# define GC_INIT_CONF_FULL_FREQ /* empty */
#endif
#ifdef GC_TIME_LIMIT
#if defined(GC_TIME_LIMIT) && !defined(CPPCHECK)
/* Set GC_time_limit to the desired value at start-up */
# define GC_INIT_CONF_TIME_LIMIT GC_set_time_limit(GC_TIME_LIMIT)
#else
# define GC_INIT_CONF_TIME_LIMIT /* empty */
#endif
#if defined(GC_SIG_SUSPEND) && defined(GC_THREADS)
#if defined(GC_SIG_SUSPEND) && defined(GC_THREADS) && !defined(CPPCHECK)
# define GC_INIT_CONF_SUSPEND_SIGNAL GC_set_suspend_signal(GC_SIG_SUSPEND)
#else
# define GC_INIT_CONF_SUSPEND_SIGNAL /* empty */
#endif
#if defined(GC_SIG_THR_RESTART) && defined(GC_THREADS)
#if defined(GC_SIG_THR_RESTART) && defined(GC_THREADS) && !defined(CPPCHECK)
# define GC_INIT_CONF_THR_RESTART_SIGNAL \
GC_set_thr_restart_signal(GC_SIG_THR_RESTART)
#else
# define GC_INIT_CONF_THR_RESTART_SIGNAL /* empty */
#endif
#ifdef GC_MAXIMUM_HEAP_SIZE
#if defined(GC_MAXIMUM_HEAP_SIZE) && !defined(CPPCHECK)
/* Limit the heap size to the desired value (useful for debugging). */
/* The limit could be overridden either at the program start-up by */
/* the similar environment variable or anytime later by the */
@ -1718,7 +1910,7 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
# define GC_INIT_CONF_IGNORE_WARN /* empty */
#endif
#ifdef GC_INITIAL_HEAP_SIZE
#if defined(GC_INITIAL_HEAP_SIZE) && !defined(CPPCHECK)
/* Set heap size to the desired value at start-up */
# define GC_INIT_CONF_INITIAL_HEAP_SIZE \
{ size_t heap_size = GC_get_heap_size(); \

View file

@ -38,16 +38,23 @@
*/
#ifndef GC_ALLOCATOR_H
#define GC_ALLOCATOR_H
#include "gc.h"
#include <new> // for placement new
#include <new> // for placement new and bad_alloc
#if defined(__GNUC__)
# define GC_ATTR_UNUSED __attribute__((__unused__))
#ifndef GC_ATTR_EXPLICIT
# if (__cplusplus >= 201103L) || defined(CPPCHECK)
# define GC_ATTR_EXPLICIT explicit
# else
# define GC_ATTR_EXPLICIT /* empty */
# endif
#endif
#if defined(GC_NEW_ABORTS_ON_OOM) || defined(_LIBCPP_NO_EXCEPTIONS)
# define GC_ALLOCATOR_THROW_OR_ABORT() GC_abort_on_oom()
#else
# define GC_ATTR_UNUSED
# define GC_ALLOCATOR_THROW_OR_ABORT() throw std::bad_alloc()
#endif
/* First some helpers to allow us to dispatch on whether or not a type
@ -85,15 +92,24 @@ GC_DECLARE_PTRFREE(long double);
// pointer-free object.
template <class GC_Tp>
inline void * GC_selective_alloc(size_t n, GC_Tp, bool ignore_off_page) {
return ignore_off_page?GC_MALLOC_IGNORE_OFF_PAGE(n):GC_MALLOC(n);
void *obj = ignore_off_page ? GC_MALLOC_IGNORE_OFF_PAGE(n) : GC_MALLOC(n);
if (0 == obj)
GC_ALLOCATOR_THROW_OR_ABORT();
return obj;
}
template <>
inline void * GC_selective_alloc<GC_true_type>(size_t n, GC_true_type,
bool ignore_off_page) {
return ignore_off_page? GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(n)
: GC_MALLOC_ATOMIC(n);
}
#if !defined(__WATCOMC__)
/* Note: template-id not supported in this context by Watcom compiler. */
template <>
inline void * GC_selective_alloc<GC_true_type>(size_t n, GC_true_type,
bool ignore_off_page) {
void * obj = ignore_off_page ? GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(n)
: GC_MALLOC_ATOMIC(n);
if (0 == obj)
GC_ALLOCATOR_THROW_OR_ABORT();
return obj;
}
#endif
/* Now the public gc_allocator<T> class:
*/
@ -116,7 +132,8 @@ public:
gc_allocator(const gc_allocator&) throw() {}
# if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
// MSVC++ 6.0 do not support member templates
template <class GC_Tp1> gc_allocator(const gc_allocator<GC_Tp1>&) throw() {}
template <class GC_Tp1> GC_ATTR_EXPLICIT
gc_allocator(const gc_allocator<GC_Tp1>&) throw() {}
# endif
~gc_allocator() throw() {}
@ -133,7 +150,7 @@ public:
}
// __p is not permitted to be a null pointer.
void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n)
void deallocate(pointer __p, size_type /* GC_n */)
{ GC_FREE(__p); }
size_type max_size() const throw()
@ -191,7 +208,7 @@ public:
gc_allocator_ignore_off_page(const gc_allocator_ignore_off_page&) throw() {}
# if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
// MSVC++ 6.0 do not support member templates
template <class GC_Tp1>
template <class GC_Tp1> GC_ATTR_EXPLICIT
gc_allocator_ignore_off_page(const gc_allocator_ignore_off_page<GC_Tp1>&)
throw() {}
# endif
@ -210,7 +227,7 @@ public:
}
// __p is not permitted to be a null pointer.
void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n)
void deallocate(pointer __p, size_type /* GC_n */)
{ GC_FREE(__p); }
size_type max_size() const throw()
@ -271,8 +288,8 @@ public:
traceable_allocator(const traceable_allocator&) throw() {}
# if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
// MSVC++ 6.0 do not support member templates
template <class GC_Tp1> traceable_allocator
(const traceable_allocator<GC_Tp1>&) throw() {}
template <class GC_Tp1> GC_ATTR_EXPLICIT
traceable_allocator(const traceable_allocator<GC_Tp1>&) throw() {}
# endif
~traceable_allocator() throw() {}
@ -282,11 +299,14 @@ public:
// GC_n is permitted to be 0. The C++ standard says nothing about what
// the return value is when GC_n == 0.
GC_Tp* allocate(size_type GC_n, const void* = 0) {
return static_cast<GC_Tp*>(GC_MALLOC_UNCOLLECTABLE(GC_n * sizeof(GC_Tp)));
void * obj = GC_MALLOC_UNCOLLECTABLE(GC_n * sizeof(GC_Tp));
if (0 == obj)
GC_ALLOCATOR_THROW_OR_ABORT();
return static_cast<GC_Tp*>(obj);
}
// __p is not permitted to be a null pointer.
void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n)
void deallocate(pointer __p, size_type /* GC_n */)
{ GC_FREE(__p); }
size_type max_size() const throw()

View file

@ -64,7 +64,8 @@
#if defined(GC_AIX_THREADS) || defined(GC_DARWIN_THREADS) \
|| defined(GC_DGUX386_THREADS) || defined(GC_FREEBSD_THREADS) \
|| defined(GC_GNU_THREADS) || defined(GC_HPUX_THREADS) \
|| defined(GC_GNU_THREADS) \
|| defined(GC_HAIKU_THREADS) || defined(GC_HPUX_THREADS) \
|| defined(GC_IRIX_THREADS) || defined(GC_LINUX_THREADS) \
|| defined(GC_NETBSD_THREADS) || defined(GC_OPENBSD_THREADS) \
|| defined(GC_OSF1_THREADS) || defined(GC_SOLARIS_THREADS) \
@ -88,18 +89,22 @@
# define GC_IRIX_THREADS
# endif
# if defined(__sparc) && !defined(__linux__) \
|| defined(sun) && (defined(i386) || defined(__i386__) \
|| defined(__amd64__))
|| ((defined(sun) || defined(__sun)) \
&& (defined(i386) || defined(__i386__) \
|| defined(__amd64) || defined(__amd64__)))
# define GC_SOLARIS_THREADS
# elif defined(__APPLE__) && defined(__MACH__)
# define GC_DARWIN_THREADS
# elif defined(__HAIKU__)
# define GC_HAIKU_THREADS
# elif defined(__OpenBSD__)
# define GC_OPENBSD_THREADS
# elif !defined(GC_LINUX_THREADS) && !defined(GC_HPUX_THREADS) \
&& !defined(GC_OSF1_THREADS) && !defined(GC_IRIX_THREADS)
/* FIXME: Should we really need for FreeBSD and NetBSD to check */
/* that no other GC_xxx_THREADS macro is set? */
# if defined(__FreeBSD__) || defined(__DragonFly__)
# if defined(__FreeBSD__) || defined(__DragonFly__) \
|| defined(__FreeBSD_kernel__)
# define GC_FREEBSD_THREADS
# elif defined(__NetBSD__)
# define GC_NETBSD_THREADS
@ -172,7 +177,7 @@
#if defined(GC_DLL) && !defined(GC_API)
# if defined(__MINGW32__) || defined(__CEGCC__)
# ifdef GC_BUILD
# if defined(GC_BUILD) || defined(__MINGW32_DELAY_LOAD__)
# define GC_API __declspec(dllexport)
# else
# define GC_API __declspec(dllimport)
@ -202,8 +207,8 @@
# elif defined(__GNUC__)
/* Only matters if used in conjunction with -fvisibility=hidden option. */
# if defined(GC_BUILD) && (__GNUC__ >= 4 \
|| defined(GC_VISIBILITY_HIDDEN_SET))
# if defined(GC_BUILD) && !defined(GC_NO_VISIBILITY) \
&& (__GNUC__ >= 4 || defined(GC_VISIBILITY_HIDDEN_SET))
# define GC_API extern __attribute__((__visibility__("default")))
# endif
# endif
@ -232,7 +237,7 @@
# elif defined(__GNUC__) && (__GNUC__ > 3 \
|| (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
# define GC_ATTR_MALLOC __attribute__((__malloc__))
# elif defined(_MSC_VER) && _MSC_VER >= 14
# elif defined(_MSC_VER) && _MSC_VER >= 1400
# define GC_ATTR_MALLOC __declspec(noalias) __declspec(restrict)
# else
# define GC_ATTR_MALLOC
@ -270,7 +275,7 @@
# define GC_ATTR_DEPRECATED /* empty */
# elif defined(__GNUC__) && __GNUC__ >= 4
# define GC_ATTR_DEPRECATED __attribute__((__deprecated__))
# elif defined(_MSC_VER) && _MSC_VER >= 12
# elif defined(_MSC_VER) && _MSC_VER >= 1200
# define GC_ATTR_DEPRECATED __declspec(deprecated)
# else
# define GC_ATTR_DEPRECATED /* empty */
@ -287,7 +292,8 @@
# include <features.h>
# endif
# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \
&& !defined(__ia64__) && !defined(__UCLIBC__) \
&& !defined(__ia64__) \
&& !defined(GC_MISSING_EXECINFO_H) \
&& !defined(GC_HAVE_BUILTIN_BACKTRACE)
# define GC_HAVE_BUILTIN_BACKTRACE
# endif
@ -319,7 +325,8 @@
/* This may also be desirable if it is possible but expensive to */
/* retrieve the call chain. */
#if (defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) \
|| defined(__FreeBSD__) || defined(__DragonFly__) \
|| defined(__FreeBSD__) || defined(__DragonFly__) || defined(__HAIKU__) \
|| defined(__FreeBSD_kernel__) \
|| defined(PLATFORM_ANDROID) || defined(__ANDROID__)) \
&& !defined(GC_CAN_SAVE_CALL_STACKS)
# define GC_ADD_CALLER
@ -329,6 +336,7 @@
# define GC_RETURN_ADDR (GC_word)__builtin_return_address(0)
# if (__GNUC__ >= 4) && (defined(__i386__) || defined(__amd64__) \
|| defined(__x86_64__) /* and probably others... */)
# define GC_HAVE_RETURN_ADDR_PARENT
# define GC_RETURN_ADDR_PARENT \
(GC_word)__builtin_extract_return_addr(__builtin_return_address(1))
# endif
@ -361,14 +369,16 @@
# ifndef GC_PTHREAD_CREATE_CONST
# define GC_PTHREAD_CREATE_CONST /* empty */
# endif
# ifndef GC_PTHREAD_EXIT_ATTRIBUTE
# ifndef GC_HAVE_PTHREAD_EXIT
# define GC_HAVE_PTHREAD_EXIT
# define GC_PTHREAD_EXIT_ATTRIBUTE /* empty */
# endif
# endif
# if !defined(GC_PTHREAD_EXIT_ATTRIBUTE) \
# if !defined(GC_HAVE_PTHREAD_EXIT) \
&& !defined(PLATFORM_ANDROID) && !defined(__ANDROID__) \
&& (defined(GC_LINUX_THREADS) || defined(GC_SOLARIS_THREADS))
# define GC_HAVE_PTHREAD_EXIT
/* Intercept pthread_exit on Linux and Solaris. */
# if defined(__GNUC__) /* since GCC v2.7 */
# define GC_PTHREAD_EXIT_ATTRIBUTE __attribute__((__noreturn__))
@ -379,7 +389,7 @@
# endif
# endif
# if (!defined(GC_PTHREAD_EXIT_ATTRIBUTE) || defined(__native_client__)) \
# if (!defined(GC_HAVE_PTHREAD_EXIT) || defined(__native_client__)) \
&& !defined(GC_NO_PTHREAD_CANCEL)
/* Either there is no pthread_cancel() or no need to intercept it. */
# define GC_NO_PTHREAD_CANCEL

View file

@ -149,91 +149,125 @@ by UseGC. GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined.
#endif
#ifndef THINK_CPLUS
# define GC_cdecl GC_CALLBACK
# define GC_cdecl GC_CALLBACK
#else
# define GC_cdecl _cdecl
# define GC_cdecl _cdecl
#endif
#if ! defined( GC_NO_OPERATOR_NEW_ARRAY ) \
#if !defined(GC_NO_OPERATOR_NEW_ARRAY) \
&& !defined(_ENABLE_ARRAYNEW) /* Digimars */ \
&& (defined(__BORLANDC__) && (__BORLANDC__ < 0x450) \
|| (defined(__GNUC__) && \
(__GNUC__ < 2 || __GNUC__ == 2 && __GNUC_MINOR__ < 6)) \
|| (defined(_MSC_VER) && _MSC_VER <= 1020) \
|| (defined(__WATCOMC__) && __WATCOMC__ < 1050))
# define GC_NO_OPERATOR_NEW_ARRAY
# define GC_NO_OPERATOR_NEW_ARRAY
#endif
#if !defined(GC_NO_OPERATOR_NEW_ARRAY) && !defined(GC_OPERATOR_NEW_ARRAY)
# define GC_OPERATOR_NEW_ARRAY
# define GC_OPERATOR_NEW_ARRAY
#endif
#if (!defined(__BORLANDC__) || __BORLANDC__ > 0x0620) \
&& ! defined ( __sgi ) && ! defined( __WATCOMC__ ) \
&& ! defined (__sgi) && ! defined(__WATCOMC__) \
&& (!defined(_MSC_VER) || _MSC_VER > 1020)
# define GC_PLACEMENT_DELETE
# define GC_PLACEMENT_DELETE
#endif
#ifndef GC_DECL_DELETE_THROW
# if defined(__DMC__) || (defined(__BORLANDC__) \
&& (defined(_RWSTD_NO_EXCEPTIONS) || defined(_RWSTD_NO_EX_SPEC))) \
|| (defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) \
|| (defined(__WATCOMC__) && !defined(_CPPUNWIND))
# define GC_DECL_DELETE_THROW /* empty */
# ifndef GC_NEW_ABORTS_ON_OOM
# define GC_NEW_ABORTS_ON_OOM
# endif
# else
# define GC_DECL_DELETE_THROW throw()
# endif
#endif // !GC_DECL_DELETE_THROW
#if defined(GC_NEW_ABORTS_ON_OOM) || defined(_LIBCPP_NO_EXCEPTIONS)
# define GC_OP_NEW_OOM_CHECK(obj) \
do { if (!(obj)) GC_abort_on_oom(); } while (0)
#elif defined(GC_INCLUDE_NEW)
# include <new> // for bad_alloc
# define GC_OP_NEW_OOM_CHECK(obj) if (obj) {} else throw std::bad_alloc()
#else
// "new" header is not included, so bad_alloc cannot be thrown directly.
GC_API void GC_CALL GC_throw_bad_alloc();
# define GC_OP_NEW_OOM_CHECK(obj) if (obj) {} else GC_throw_bad_alloc()
#endif // !GC_NEW_ABORTS_ON_OOM && !GC_INCLUDE_NEW
#ifdef GC_NAMESPACE
namespace boehmgc
{
#endif
enum GCPlacement {
enum GCPlacement
{
UseGC,
# ifndef GC_NAME_CONFLICT
GC=UseGC,
GC = UseGC,
# endif
NoGC,
PointerFreeGC
# ifdef GC_ATOMIC_UNCOLLECTABLE
, PointerFreeNoGC
# endif
};
class gc {
public:
inline void* operator new( size_t size );
inline void* operator new( size_t size, GCPlacement gcp );
inline void* operator new( size_t size, void *p );
/* Must be redefined here, since the other overloadings */
/* hide the global definition. */
inline void operator delete( void* obj );
# ifdef GC_PLACEMENT_DELETE
inline void operator delete( void*, GCPlacement );
/* called if construction fails. */
inline void operator delete( void*, void* );
# endif
/**
* Instances of classes derived from "gc" will be allocated in the collected
* heap by default, unless an explicit NoGC placement is specified.
*/
class gc
{
public:
inline void* operator new(size_t size);
inline void* operator new(size_t size, GCPlacement gcp);
inline void* operator new(size_t size, void* p);
// Must be redefined here, since the other overloadings hide
// the global definition.
inline void operator delete(void* obj);
#ifdef GC_OPERATOR_NEW_ARRAY
inline void* operator new[]( size_t size );
inline void* operator new[]( size_t size, GCPlacement gcp );
inline void* operator new[]( size_t size, void *p );
inline void operator delete[]( void* obj );
# ifdef GC_PLACEMENT_DELETE
inline void operator delete(void*, GCPlacement);
// Called if construction fails.
inline void operator delete(void*, void*);
# endif // GC_PLACEMENT_DELETE
# ifdef GC_OPERATOR_NEW_ARRAY
inline void* operator new[](size_t size);
inline void* operator new[](size_t size, GCPlacement gcp);
inline void* operator new[](size_t size, void* p);
inline void operator delete[](void* obj);
# ifdef GC_PLACEMENT_DELETE
inline void operator delete[]( void*, GCPlacement );
inline void operator delete[]( void*, void* );
inline void operator delete[](void*, GCPlacement);
inline void operator delete[](void*, void*);
# endif
#endif /* GC_OPERATOR_NEW_ARRAY */
# endif // GC_OPERATOR_NEW_ARRAY
};
/*
Instances of classes derived from "gc" will be allocated in the
collected heap by default, unless an explicit NoGC placement is
specified. */
class gc_cleanup: virtual public gc {
public:
inline gc_cleanup();
inline virtual ~gc_cleanup();
/**
* Instances of classes derived from "gc_cleanup" will be allocated
* in the collected heap by default. When the collector discovers
* an inaccessible object derived from "gc_cleanup" or containing
* a member derived from "gc_cleanup", its destructors will be invoked.
*/
class gc_cleanup: virtual public gc
{
public:
inline gc_cleanup();
inline virtual ~gc_cleanup();
private:
inline static void GC_cdecl cleanup( void* obj, void* clientData );
inline static void GC_cdecl cleanup(void* obj, void* clientData);
};
/*
Instances of classes derived from "gc_cleanup" will be allocated
in the collected heap by default. When the collector discovers an
inaccessible object derived from "gc_cleanup" or containing a
member derived from "gc_cleanup", its destructors will be
invoked. */
extern "C" {
typedef void (GC_CALLBACK * GCCleanUpFunc)( void* obj, void* clientData );
typedef void (GC_CALLBACK * GCCleanUpFunc)(void* obj, void* clientData);
}
#ifdef GC_NAMESPACE
@ -244,193 +278,268 @@ extern "C" {
// Disable warning that "no matching operator delete found; memory will
// not be freed if initialization throws an exception"
# pragma warning(disable:4291)
// TODO: "non-member operator new or delete may not be declared inline"
// warning is disabled for now.
# pragma warning(disable:4595)
#endif
inline void* operator new( size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
GC_NS_QUALIFY(GCCleanUpFunc) cleanup = 0,
void* clientData = 0 );
/*
Allocates a collectible or uncollectible object, according to the
value of "gcp".
For collectible objects, if "cleanup" is non-null, then when the
allocated object "obj" becomes inaccessible, the collector will
invoke the function "cleanup( obj, clientData )" but will not
invoke the object's destructors. It is an error to explicitly
delete an object allocated with a non-null "cleanup".
It is an error to specify a non-null "cleanup" with NoGC or for
classes derived from "gc_cleanup" or containing members derived
from "gc_cleanup". */
void* clientData = 0);
// Allocates a collectible or uncollectible object, according to the
// value of "gcp".
//
// For collectible objects, if "cleanup" is non-null, then when the
// allocated object "obj" becomes inaccessible, the collector will
// invoke the function "cleanup(obj, clientData)" but will not
// invoke the object's destructors. It is an error to explicitly
// delete an object allocated with a non-null "cleanup".
//
// It is an error to specify a non-null "cleanup" with NoGC or for
// classes derived from "gc_cleanup" or containing members derived
// from "gc_cleanup".
#ifdef GC_PLACEMENT_DELETE
inline void operator delete( void*, GC_NS_QUALIFY(GCPlacement),
GC_NS_QUALIFY(GCCleanUpFunc), void * );
inline void operator delete(void*, GC_NS_QUALIFY(GCPlacement),
GC_NS_QUALIFY(GCCleanUpFunc), void*);
#endif
#ifdef _MSC_VER
/** This ensures that the system default operator new[] doesn't get
* undefined, which is what seems to happen on VC++ 6 for some reason
* if we define a multi-argument operator new[].
* There seems to be no way to redirect new in this environment without
* including this everywhere.
*/
# if _MSC_VER > 1020
void *operator new[]( size_t size );
void operator delete[]( void* obj );
#if defined(_MSC_VER) || defined(__DMC__)
// The following ensures that the system default operator new[] does not
// get undefined, which is what seems to happen on VC++ 6 for some reason
// if we define a multi-argument operator new[].
// There seems to be no way to redirect new in this environment without
// including this everywhere.
// Inlining done to avoid mix up of new and delete operators by VC++ 9 (due
// to arbitrary ordering during linking).
# ifdef GC_OPERATOR_NEW_ARRAY
inline void* operator new[](size_t size)
{
void* obj = GC_MALLOC_UNCOLLECTABLE(size);
GC_OP_NEW_OOM_CHECK(obj);
return obj;
}
inline void operator delete[](void* obj)
{
GC_FREE(obj);
}
# endif
void* operator new( size_t size );
void operator delete( void* obj );
inline void* operator new(size_t size)
{
void* obj = GC_MALLOC_UNCOLLECTABLE(size);
GC_OP_NEW_OOM_CHECK(obj);
return obj;
}
// This new operator is used by VC++ in case of Debug builds !
void* operator new( size_t size, int /* nBlockUse */,
const char * szFileName, int nLine );
#endif /* _MSC_VER */
inline void operator delete(void* obj)
{
GC_FREE(obj);
}
// This new operator is used by VC++ in case of Debug builds:
# ifdef GC_DEBUG
inline void* operator new(size_t size, int /* nBlockUse */,
const char* szFileName, int nLine)
{
void* obj = GC_debug_malloc_uncollectable(size, szFileName, nLine);
GC_OP_NEW_OOM_CHECK(obj);
return obj;
}
# else
inline void* operator new(size_t size, int /* nBlockUse */,
const char* /* szFileName */, int /* nLine */)
{
void* obj = GC_malloc_uncollectable(size);
GC_OP_NEW_OOM_CHECK(obj);
return obj;
}
# endif /* !GC_DEBUG */
# ifdef GC_OPERATOR_NEW_ARRAY
// This new operator is used by VC++ 7+ in Debug builds:
inline void* operator new[](size_t size, int nBlockUse,
const char* szFileName, int nLine)
{
return operator new(size, nBlockUse, szFileName, nLine);
}
# endif
#endif // _MSC_VER
#ifdef GC_OPERATOR_NEW_ARRAY
inline void* operator new[]( size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
// The operator new for arrays, identical to the above.
inline void* operator new[](size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
GC_NS_QUALIFY(GCCleanUpFunc) cleanup = 0,
void* clientData = 0 );
/* The operator new for arrays, identical to the above. */
#endif /* GC_OPERATOR_NEW_ARRAY */
void* clientData = 0);
#endif // GC_OPERATOR_NEW_ARRAY
/****************************************************************************
Inline implementation
****************************************************************************/
/* Inline implementation */
#ifdef GC_NAMESPACE
namespace boehmgc
{
#endif
inline void* gc::operator new( size_t size ) {
return GC_MALLOC( size );
inline void* gc::operator new(size_t size)
{
void* obj = GC_MALLOC(size);
GC_OP_NEW_OOM_CHECK(obj);
return obj;
}
inline void* gc::operator new( size_t size, GCPlacement gcp ) {
if (gcp == UseGC)
return GC_MALLOC( size );
else if (gcp == PointerFreeGC)
return GC_MALLOC_ATOMIC( size );
else
return GC_MALLOC_UNCOLLECTABLE( size );
inline void* gc::operator new(size_t size, GCPlacement gcp)
{
void* obj;
switch (gcp) {
case UseGC:
obj = GC_MALLOC(size);
break;
case PointerFreeGC:
obj = GC_MALLOC_ATOMIC(size);
break;
# ifdef GC_ATOMIC_UNCOLLECTABLE
case PointerFreeNoGC:
obj = GC_MALLOC_ATOMIC_UNCOLLECTABLE(size);
break;
# endif
case NoGC:
default:
obj = GC_MALLOC_UNCOLLECTABLE(size);
}
GC_OP_NEW_OOM_CHECK(obj);
return obj;
}
inline void* gc::operator new( size_t /* size */, void *p ) {
return p;
inline void* gc::operator new(size_t /* size */, void* p)
{
return p;
}
inline void gc::operator delete( void* obj ) {
GC_FREE( obj );
inline void gc::operator delete(void* obj)
{
GC_FREE(obj);
}
#ifdef GC_PLACEMENT_DELETE
inline void gc::operator delete( void*, void* ) {}
inline void gc::operator delete(void*, void*) {}
inline void gc::operator delete( void* p, GCPlacement /* gcp */ ) {
inline void gc::operator delete(void* p, GCPlacement /* gcp */)
{
GC_FREE(p);
}
#endif
#endif // GC_PLACEMENT_DELETE
#ifdef GC_OPERATOR_NEW_ARRAY
inline void* gc::operator new[]( size_t size ) {
return gc::operator new( size );
inline void* gc::operator new[](size_t size)
{
return gc::operator new(size);
}
inline void* gc::operator new[]( size_t size, GCPlacement gcp ) {
return gc::operator new( size, gcp );
inline void* gc::operator new[](size_t size, GCPlacement gcp)
{
return gc::operator new(size, gcp);
}
inline void* gc::operator new[]( size_t /* size */, void *p ) {
inline void* gc::operator new[](size_t /* size */, void* p)
{
return p;
}
inline void gc::operator delete[]( void* obj ) {
gc::operator delete( obj );
inline void gc::operator delete[](void* obj)
{
gc::operator delete(obj);
}
# ifdef GC_PLACEMENT_DELETE
inline void gc::operator delete[]( void*, void* ) {}
inline void gc::operator delete[](void*, void*) {}
inline void gc::operator delete[]( void* p, GCPlacement /* gcp */ ) {
inline void gc::operator delete[](void* p, GCPlacement /* gcp */)
{
gc::operator delete(p);
}
# endif
#endif /* GC_OPERATOR_NEW_ARRAY */
#endif // GC_OPERATOR_NEW_ARRAY
inline gc_cleanup::~gc_cleanup() {
GC_register_finalizer_ignore_self( GC_base(this), 0, 0, 0, 0 );
inline gc_cleanup::~gc_cleanup()
{
void* base = GC_base(this);
if (0 == base) return; // Non-heap object.
GC_register_finalizer_ignore_self(base, 0, 0, 0, 0);
}
inline void GC_CALLBACK gc_cleanup::cleanup( void* obj, void* displ ) {
((gc_cleanup*) ((char*) obj + (ptrdiff_t) displ))->~gc_cleanup();
inline void GC_CALLBACK gc_cleanup::cleanup(void* obj, void* displ)
{
((gc_cleanup*) ((char*) obj + (ptrdiff_t) displ))->~gc_cleanup();
}
inline gc_cleanup::gc_cleanup() {
GC_finalization_proc oldProc;
void* oldData;
void* base = GC_base( (void *) this );
if (0 != base) {
// Don't call the debug version, since this is a real base address.
GC_register_finalizer_ignore_self( base, (GC_finalization_proc)cleanup,
(void*)((char*)this - (char*)base),
&oldProc, &oldData );
if (0 != oldProc) {
GC_register_finalizer_ignore_self( base, oldProc, oldData, 0, 0 );
}
inline gc_cleanup::gc_cleanup()
{
GC_finalization_proc oldProc;
void* oldData;
void* this_ptr = (void*)this;
void* base = GC_base(this_ptr);
if (base != 0) {
// Don't call the debug version, since this is a real base address.
GC_register_finalizer_ignore_self(base, (GC_finalization_proc) cleanup,
(void*)((char*)this_ptr - (char*)base),
&oldProc, &oldData);
if (oldProc != 0) {
GC_register_finalizer_ignore_self(base, oldProc, oldData, 0, 0);
}
}
}
#ifdef GC_NAMESPACE
}
#endif
inline void* operator new( size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
GC_NS_QUALIFY(GCCleanUpFunc) cleanup,
void* clientData )
void* clientData)
{
void* obj;
if (gcp == GC_NS_QUALIFY(UseGC)) {
obj = GC_MALLOC( size );
if (cleanup != 0)
GC_REGISTER_FINALIZER_IGNORE_SELF( obj, cleanup, clientData,
0, 0 );
} else if (gcp == GC_NS_QUALIFY(PointerFreeGC)) {
obj = GC_MALLOC_ATOMIC( size );
} else {
obj = GC_MALLOC_UNCOLLECTABLE( size );
};
return obj;
void* obj;
switch (gcp) {
case GC_NS_QUALIFY(UseGC):
obj = GC_MALLOC(size);
if (cleanup != 0 && obj != 0) {
GC_REGISTER_FINALIZER_IGNORE_SELF(obj, cleanup, clientData, 0, 0);
}
break;
case GC_NS_QUALIFY(PointerFreeGC):
obj = GC_MALLOC_ATOMIC(size);
break;
# ifdef GC_ATOMIC_UNCOLLECTABLE
case GC_NS_QUALIFY(PointerFreeNoGC):
obj = GC_MALLOC_ATOMIC_UNCOLLECTABLE(size);
break;
# endif
case GC_NS_QUALIFY(NoGC):
default:
obj = GC_MALLOC_UNCOLLECTABLE(size);
}
GC_OP_NEW_OOM_CHECK(obj);
return obj;
}
#ifdef GC_PLACEMENT_DELETE
inline void operator delete( void *p, GC_NS_QUALIFY(GCPlacement) /* gcp */,
inline void operator delete(void* p, GC_NS_QUALIFY(GCPlacement) /* gcp */,
GC_NS_QUALIFY(GCCleanUpFunc) /* cleanup */,
void* /* clientData */ )
void* /* clientData */)
{
GC_FREE(p);
}
#endif /* GC_PLACEMENT_DELETE */
#endif // GC_PLACEMENT_DELETE
#ifdef GC_OPERATOR_NEW_ARRAY
inline void* operator new[]( size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
inline void* operator new[](size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
GC_NS_QUALIFY(GCCleanUpFunc) cleanup,
void* clientData )
void* clientData)
{
return ::operator new( size, gcp, cleanup, clientData );
return ::operator new(size, gcp, cleanup, clientData);
}
#endif /* GC_OPERATOR_NEW_ARRAY */
#if defined(__CYGWIN__)
# include <new> // for delete throw()
inline void operator delete(void *p)
{
GC_FREE(p);
}
#endif
#endif // GC_OPERATOR_NEW_ARRAY
#endif /* GC_CPP_H */

View file

@ -48,6 +48,9 @@ struct GC_finalizer_closure {
/* dedicated object kind with a disclaim procedure, and is more */
/* efficient than GC_register_finalizer and friends. */
/* GC_init_finalized_malloc must be called before using this. */
/* Note that GC_size (applied to such allocated object) returns a value */
/* slightly bigger than the specified allocation size, and that GC_base */
/* result points to a word prior to the start of the allocated object. */
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
GC_finalized_malloc(size_t /*size*/,
const struct GC_finalizer_closure * /*fc*/);

View file

@ -42,12 +42,34 @@
# define GC_ASSERT(expr) /* empty */
#endif
#ifndef GC_PREFETCH_FOR_WRITE
# define GC_PREFETCH_FOR_WRITE(x) (void)0
#endif
/* Object kinds; must match PTRFREE, NORMAL in gc_priv.h. */
#define GC_I_PTRFREE 0
#define GC_I_NORMAL 1
/* Store a pointer to a list of newly allocated objects of kind k and */
/* size lb in *result. The caller must make sure that *result is */
/* traced even if objects are ptrfree. */
GC_API void GC_CALL GC_generic_malloc_many(size_t /* lb */, int /* k */,
void ** /* result */);
/* Generalized version of GC_malloc and GC_malloc_atomic. */
/* Uses appropriately the thread-local (if available) or the global */
/* free-list of the specified kind. */
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
GC_malloc_kind(size_t /* lb */, int /* k */);
#ifdef GC_THREADS
/* Same as above but uses only the global free-list. */
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
GC_malloc_kind_global(size_t /* lb */, int /* k */);
#else
# define GC_malloc_kind_global GC_malloc_kind
#endif
/* The ultimately general inline allocation macro. Allocate an object */
/* of size granules, putting the resulting pointer in result. Tiny_fl */
/* is a "tiny" free list array, which will be used first, if the size */
@ -56,17 +78,17 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t /* lb */, int /* k */,
/* GC_generic_malloc_many with the indicated kind. */
/* Tiny_fl should be an array of GC_TINY_FREELISTS void * pointers. */
/* If num_direct is nonzero, and the individual free list pointers */
/* are initialized to (void *)1, then we allocate numdirect granules */
/* directly using gmalloc before putting multiple objects into the */
/* tiny_fl entry. If num_direct is zero, then the free lists may also */
/* be initialized to (void *)0. */
/* are initialized to (void *)1, then we allocate num_direct granules */
/* directly using generic_malloc before putting multiple objects into */
/* the tiny_fl entry. If num_direct is zero, then the free lists may */
/* also be initialized to (void *)0. */
/* Note that we use the zeroth free list to hold objects 1 granule in */
/* size that are used to satisfy size 0 allocation requests. */
/* We rely on much of this hopefully getting optimized away in the */
/* num_direct = 0 case. */
/* Particularly if granules is constant, this should generate a small */
/* amount of code. */
# define GC_FAST_MALLOC_GRANS(result,granules,tiny_fl,num_direct,\
# define GC_FAST_MALLOC_GRANS(result,granules,tiny_fl,num_direct, \
kind,default_expr,init) \
do { \
if (GC_EXPECT((granules) >= GC_TINY_FREELISTS,0)) { \
@ -76,14 +98,31 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t /* lb */, int /* k */,
void *my_entry=*my_fl; \
void *next; \
\
while (GC_EXPECT((GC_word)my_entry \
<= (num_direct) + GC_TINY_FREELISTS + 1, 0)) { \
for (;;) { \
if (GC_EXPECT((GC_word)my_entry \
> (num_direct) + GC_TINY_FREELISTS + 1, 1)) { \
next = *(void **)(my_entry); \
result = (void *)my_entry; \
*my_fl = next; \
init; \
GC_PREFETCH_FOR_WRITE(next); \
if ((kind) != GC_I_PTRFREE) { \
GC_end_stubborn_change(my_fl); \
GC_reachable_here(next); \
} \
GC_ASSERT(GC_size(result) >= (granules)*GC_GRANULE_BYTES); \
GC_ASSERT((kind) == GC_I_PTRFREE \
|| ((GC_word *)result)[1] == 0); \
break; \
} \
/* Entry contains counter or NULL */ \
if ((GC_word)my_entry - 1 < (num_direct)) { \
if ((GC_signed_word)my_entry - (GC_signed_word)(num_direct) <= 0 \
/* (GC_word)my_entry <= (num_direct) */ \
&& my_entry != 0 /* NULL */) { \
/* Small counter value, not NULL */ \
*my_fl = (char *)my_entry + (granules) + 1; \
result = (default_expr); \
goto out; \
break; \
} else { \
/* Large counter or NULL */ \
GC_generic_malloc_many(((granules) == 0? GC_GRANULE_BYTES : \
@ -92,18 +131,10 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t /* lb */, int /* k */,
my_entry = *my_fl; \
if (my_entry == 0) { \
result = (*GC_get_oom_fn())((granules)*GC_GRANULE_BYTES); \
goto out; \
break; \
} \
} \
} \
next = *(void **)(my_entry); \
result = (void *)my_entry; \
*my_fl = next; \
init; \
PREFETCH_FOR_WRITE(next); \
GC_ASSERT(GC_size(result) >= (granules)*GC_GRANULE_BYTES); \
GC_ASSERT((kind) == PTRFREE || ((GC_word *)result)[1] == 0); \
out: ; \
} \
} while (0)
@ -117,30 +148,37 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t /* lb */, int /* k */,
/* the caller is responsible for supplying a cleared tiny_fl */
/* free list array. For single-threaded applications, this may be */
/* a global array. */
# define GC_MALLOC_WORDS_KIND(result,n,tiny_fl,k,init) \
do { \
size_t grans = GC_WORDS_TO_WHOLE_GRANULES(n); \
GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, k, \
GC_malloc_kind(grans * GC_GRANULE_BYTES, k), \
init); \
} while (0)
# define GC_MALLOC_WORDS(result,n,tiny_fl) \
do { \
size_t grans = GC_WORDS_TO_WHOLE_GRANULES(n); \
GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
NORMAL, GC_malloc(grans*GC_GRANULE_BYTES), \
*(void **)(result) = 0); \
} while (0)
GC_MALLOC_WORDS_KIND(result, n, tiny_fl, GC_I_NORMAL, \
*(void **)(result) = 0)
# define GC_MALLOC_ATOMIC_WORDS(result,n,tiny_fl) \
do { \
size_t grans = GC_WORDS_TO_WHOLE_GRANULES(n); \
GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
PTRFREE, GC_malloc_atomic(grans*GC_GRANULE_BYTES), \
(void)0 /* no initialization */); \
} while (0)
GC_MALLOC_WORDS_KIND(result, n, tiny_fl, GC_I_PTRFREE, (void)0)
/* And once more for two word initialized objects: */
# define GC_CONS(result, first, second, tiny_fl) \
do { \
size_t grans = GC_WORDS_TO_WHOLE_GRANULES(2); \
GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
NORMAL, GC_malloc(grans*GC_GRANULE_BYTES), \
*(void **)(result) = (void *)(first)); \
((void **)(result))[1] = (void *)(second); \
} while (0)
do { \
void *l = (void *)(first); \
void *r = (void *)(second); \
GC_MALLOC_WORDS_KIND(result, 2, tiny_fl, GC_I_NORMAL, (void)0); \
if ((result) != 0 /* NULL */) { \
*(void **)(result) = l; \
((void **)(result))[1] = r; \
GC_end_stubborn_change(result); \
GC_reachable_here(l); \
GC_reachable_here(r); \
} \
} while (0)
GC_API void GC_CALL GC_print_free_list(int /* kind */,
size_t /* sz_in_granules */);
#endif /* !GC_INLINE_H */

View file

@ -101,10 +101,10 @@ typedef struct GC_ms_entry * (*GC_mark_proc)(GC_word * /* addr */,
| (proc_index)) << GC_DS_TAG_BITS) | GC_DS_PROC)
#define GC_DS_PER_OBJECT 3 /* The real descriptor is at the */
/* byte displacement from the beginning of the */
/* object given by descr & ~DS_TAGS */
/* object given by descr & ~GC_DS_TAGS. */
/* If the descriptor is negative, the real */
/* descriptor is at (*<object_start>) - */
/* (descr & ~DS_TAGS) - GC_INDIR_PER_OBJ_BIAS */
/* (descr&~GC_DS_TAGS) - GC_INDIR_PER_OBJ_BIAS */
/* The latter alternative can be used if each */
/* object contains a type descriptor in the */
/* first word. */
@ -184,7 +184,7 @@ GC_API unsigned GC_CALL GC_new_proc(GC_mark_proc);
GC_API unsigned GC_CALL GC_new_proc_inner(GC_mark_proc);
/* Allocate an object of a given kind. By default, there are only */
/* a few kinds: composite (pointer-free), atomic, uncollectible, etc. */
/* a few kinds: composite (pointerful), atomic, uncollectible, etc. */
/* We claim it is possible for clever client code that understands the */
/* GC internals to add more, e.g. to communicate object layout */
/* information to the collector. Note that in the multi-threaded */
@ -204,6 +204,11 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
/* first page of the resulting object */
/* are ignored. */
/* Generalized version of GC_malloc_[atomic_]uncollectable. */
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
GC_generic_malloc_uncollectable(
size_t /* lb */, int /* knd */);
/* Same as above but primary for allocating an object of the same kind */
/* as an existing one (kind obtained by GC_get_kind_and_size). */
/* Not suitable for GCJ and typed-malloc kinds. */
@ -274,10 +279,13 @@ GC_API void GC_CALL GC_set_mark_bit(const void *) GC_ATTR_NONNULL(1);
/* Push everything in the given range onto the mark stack. */
/* (GC_push_conditional pushes either all or only dirty pages depending */
/* on the third argument.) */
/* on the third argument.) GC_push_all_eager also ensures that stack */
/* is scanned immediately, not just scheduled for scanning. */
GC_API void GC_CALL GC_push_all(char * /* bottom */, char * /* top */);
GC_API void GC_CALL GC_push_all_eager(char * /* bottom */, char * /* top */);
GC_API void GC_CALL GC_push_conditional(char * /* bottom */, char * /* top */,
int /* bool all */);
GC_API void GC_CALL GC_push_finalizer_structures(void);
/* Set and get the client push-other-roots procedure. A client */
/* supplied procedure should also call the original procedure. */
@ -287,6 +295,21 @@ typedef void (GC_CALLBACK * GC_push_other_roots_proc)(void);
GC_API void GC_CALL GC_set_push_other_roots(GC_push_other_roots_proc);
GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void);
/* Walk the GC heap visiting all reachable objects. Assume the caller */
/* holds the allocation lock. Object base pointer, object size and */
/* client custom data are passed to the callback (holding the lock). */
typedef void (GC_CALLBACK *GC_reachable_object_proc)(void * /* obj */,
size_t /* bytes */,
void * /* client_data */);
GC_API void GC_CALL GC_enumerate_reachable_objects_inner(
GC_reachable_object_proc,
void * /* client_data */) GC_ATTR_NONNULL(1);
GC_API int GC_CALL GC_is_tmp_root(void *);
GC_API void GC_CALL GC_print_trace(GC_word /* gc_no */);
GC_API void GC_CALL GC_print_trace_inner(GC_word /* gc_no */);
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View file

@ -33,15 +33,23 @@
#ifndef GC_PTHREAD_REDIRECTS_ONLY
# include <pthread.h>
# ifndef GC_SUSPEND_THREAD_ID
# define GC_SUSPEND_THREAD_ID pthread_t
# endif
# ifndef GC_NO_DLOPEN
# include <dlfcn.h>
GC_API void *GC_dlopen(const char * /* path */, int /* mode */);
# endif /* !GC_NO_DLOPEN */
# ifndef GC_NO_PTHREAD_SIGMASK
# include <signal.h>
GC_API int GC_pthread_sigmask(int /* how */, const sigset_t *,
sigset_t * /* oset */);
# include <signal.h> /* needed anyway for proper redirection */
# if defined(GC_PTHREAD_SIGMASK_NEEDED) \
|| defined(_BSD_SOURCE) || defined(_GNU_SOURCE) \
|| (_POSIX_C_SOURCE >= 199506L) || (_XOPEN_SOURCE >= 500)
GC_API int GC_pthread_sigmask(int /* how */, const sigset_t *,
sigset_t * /* oset */);
# endif
# endif /* !GC_NO_PTHREAD_SIGMASK */
# ifndef GC_PTHREAD_CREATE_CONST
@ -59,7 +67,7 @@
GC_API int GC_pthread_cancel(pthread_t);
# endif
# if defined(GC_PTHREAD_EXIT_ATTRIBUTE) && !defined(GC_PTHREAD_EXIT_DECLARED)
# if defined(GC_HAVE_PTHREAD_EXIT) && !defined(GC_PTHREAD_EXIT_DECLARED)
# define GC_PTHREAD_EXIT_DECLARED
GC_API void GC_pthread_exit(void *) GC_PTHREAD_EXIT_ATTRIBUTE;
# endif
@ -88,7 +96,7 @@
# undef pthread_cancel
# define pthread_cancel GC_pthread_cancel
# endif
# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
# ifdef GC_HAVE_PTHREAD_EXIT
# undef pthread_exit
# define pthread_exit GC_pthread_exit
# endif

View file

@ -50,7 +50,7 @@ typedef GC_word * GC_bitmap;
typedef GC_word GC_descr;
GC_API GC_descr GC_CALL GC_make_descriptor(const GC_word * /* GC_bitmap bm */,
size_t /* len */);
size_t /* len (number_of_bits_in_bitmap) */);
/* Return a type descriptor for the object whose layout */
/* is described by the argument. */
/* The least significant bit of the first word is one */
@ -81,8 +81,10 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
GC_malloc_explicitly_typed(size_t /* size_in_bytes */,
GC_descr /* d */);
/* Allocate an object whose layout is described by d. */
/* The resulting object MAY NOT BE PASSED TO REALLOC. */
/* The returned object is cleared. */
/* The size may NOT be less than the number of */
/* meaningful bits in the bitmap of d multiplied by */
/* sizeof GC_word. The returned object is cleared. */
/* The returned object may NOT be passed to GC_realloc. */
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
GC_malloc_explicitly_typed_ignore_off_page(size_t /* size_in_bytes */,
@ -97,7 +99,9 @@ GC_API GC_ATTR_MALLOC void * GC_CALL
/* The element size must be a multiple of the byte */
/* alignment required for pointers. E.g. on a 32-bit */
/* machine with 16-bit aligned pointers, size_in_bytes */
/* must be a multiple of 2. */
/* must be a multiple of 2. The element size may NOT */
/* be less than the number of meaningful bits in the */
/* bitmap of d multiplied by sizeof GC_word. */
/* Returned object is cleared. */
#ifdef GC_DEBUG

View file

@ -29,8 +29,8 @@
/* Eventually this one may become unnecessary. For now we need */
/* it to keep the old-style build process working. */
#define GC_TMP_VERSION_MAJOR 7
#define GC_TMP_VERSION_MINOR 5
#define GC_TMP_VERSION_MICRO 0 /* 7.5.0 */
#define GC_TMP_VERSION_MINOR 6
#define GC_TMP_VERSION_MICRO 8 /* 7.6.8 */
#ifdef GC_VERSION_MAJOR
# if GC_TMP_VERSION_MAJOR != GC_VERSION_MAJOR \

View file

@ -33,13 +33,28 @@
* must be prepared to deal with objects that have been finalized in
* spite of the fact that they are still referenced by statically
* allocated pointer variables.
* 1) It may mean that we get stuck in an infinite loop running
* 2) It may mean that we get stuck in an infinite loop running
* finalizers which create new finalizable objects, though that's
* probably unlikely.
* Thus this is not recommended for general use.
*/
GC_API void GC_CALL GC_finalize_all(void);
#ifdef GC_THREADS
/* External thread suspension support. No thread suspension count */
/* (so a thread which has been suspended numerous times will be */
/* resumed with the very first call to GC_resume_thread). */
/* Acquire the allocation lock. Thread should be registered in GC */
/* (otherwise no-op, GC_is_thread_suspended returns false). */
/* Unimplemented on some platforms. Not recommended for general use. */
# ifndef GC_SUSPEND_THREAD_ID
# define GC_SUSPEND_THREAD_ID void*
# endif
GC_API void GC_CALL GC_suspend_thread(GC_SUSPEND_THREAD_ID);
GC_API void GC_CALL GC_resume_thread(GC_SUSPEND_THREAD_ID);
GC_API int GC_CALL GC_is_thread_suspended(GC_SUSPEND_THREAD_ID);
#endif /* GC_THREADS */
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View file

@ -12,15 +12,15 @@
*/
//
// This is a revision of gc_alloc.h for SGI STL versions > 3.0
// Unlike earlier versions, it supplements the standard "alloc.h"
// This is a revision of gc_allocator.h for SGI STL versions > 3.0.
// Unlike earlier versions, it supplements the standard (STL) alloc.h
// instead of replacing it.
//
// This is sloppy about variable names used in header files.
// It also doesn't yet understand the new header file names or
// namespaces.
//
// This assumes the collector has been compiled with -DATOMIC_UNCOLLECTABLE.
// This assumes the collector has been compiled with -DGC_ATOMIC_UNCOLLECTABLE.
// The user should also consider -DREDIRECT_MALLOC=GC_uncollectable_malloc,
// to ensure that object allocated through malloc are traced.
//
@ -85,11 +85,13 @@ extern "C" {
GC_API void GC_CALL GC_incr_bytes_allocd(size_t bytes);
GC_API void GC_CALL GC_incr_bytes_freed(size_t bytes);
GC_API char * GC_CALL GC_generic_malloc_words_small(size_t word, int kind);
/* FIXME: Doesn't exist anymore. */
}
#define GC_generic_malloc_words_small(lw, k) \
GC_generic_malloc((lw) * sizeof(GC_word), k)
#define GC_ALLOCATOR_THROW_OR_ABORT() GC_abort_on_oom()
// Object kinds; must match PTRFREE, NORMAL, UNCOLLECTABLE, and
// AUNCOLLECTABLE in gc_priv.h.
@ -98,11 +100,15 @@ enum { GC_PTRFREE = 0, GC_NORMAL = 1, GC_UNCOLLECTABLE = 2,
enum { GC_max_fast_bytes = 255 };
enum { GC_bytes_per_word = sizeof(char *) };
enum { GC_byte_alignment = 8 };
enum { GC_word_alignment = GC_byte_alignment/GC_bytes_per_word };
#if defined(CPPCHECK)
const unsigned GC_bytes_per_word = sizeof(char *);
const unsigned GC_word_alignment = GC_byte_alignment/GC_bytes_per_word;
#else
enum { GC_bytes_per_word = sizeof(char *) };
enum { GC_word_alignment = GC_byte_alignment/GC_bytes_per_word };
#endif
inline void * &GC_obj_link(void * p)
{ return *reinterpret_cast<void **>(p); }
@ -156,6 +162,10 @@ size_t GC_aux_template<dummy>::GC_uncollectable_bytes_recently_freed = 0;
template <int dummy>
void * GC_aux_template<dummy>::GC_out_of_line_malloc(size_t nwords, int kind)
{
void * op = GC_generic_malloc_words_small(nwords, kind);
if (0 == op)
GC_ALLOCATOR_THROW_OR_ABORT();
GC_bytes_recently_allocd += GC_uncollectable_bytes_recently_allocd;
GC_non_gc_bytes +=
GC_uncollectable_bytes_recently_allocd;
@ -170,8 +180,7 @@ void * GC_aux_template<dummy>::GC_out_of_line_malloc(size_t nwords, int kind)
GC_incr_bytes_freed(GC_bytes_recently_freed);
GC_bytes_recently_freed = 0;
return GC_generic_malloc_words_small(nwords, kind);
return op;
}
typedef GC_aux_template<0> GC_aux;
@ -189,9 +198,15 @@ class single_client_gc_alloc_template {
void ** flh;
void * op;
if (n > GC_max_fast_bytes) return GC_malloc(n);
flh = GC_objfreelist_ptr + nwords;
if (0 == (op = *flh)) {
if (n > GC_max_fast_bytes) {
op = GC_malloc(n);
if (0 == op)
GC_ALLOCATOR_THROW_OR_ABORT();
return op;
}
flh = &GC_objfreelist_ptr[nwords];
op = *flh;
if (0 == op) {
return GC_aux::GC_out_of_line_malloc(nwords, GC_NORMAL);
}
*flh = GC_obj_link(op);
@ -204,9 +219,15 @@ class single_client_gc_alloc_template {
void ** flh;
void * op;
if (n > GC_max_fast_bytes) return GC_malloc_atomic(n);
flh = GC_aobjfreelist_ptr + nwords;
if (0 == (op = *flh)) {
if (n > GC_max_fast_bytes) {
op = GC_malloc_atomic(n);
if (0 == op)
GC_ALLOCATOR_THROW_OR_ABORT();
return op;
}
flh = &GC_aobjfreelist_ptr[nwords];
op = *flh;
if (0 == op) {
return GC_aux::GC_out_of_line_malloc(nwords, GC_PTRFREE);
}
*flh = GC_obj_link(op);
@ -215,13 +236,12 @@ class single_client_gc_alloc_template {
}
static void deallocate(void *p, size_t n)
{
size_t nwords = GC_round_up(n);
void ** flh;
if (n > GC_max_fast_bytes) {
GC_free(p);
} else {
flh = GC_objfreelist_ptr + nwords;
size_t nwords = GC_round_up(n);
void ** flh = &GC_objfreelist_ptr[nwords];
GC_obj_link(p) = *flh;
memset(reinterpret_cast<char *>(p) + GC_bytes_per_word, 0,
GC_bytes_per_word * (nwords - 1));
@ -231,13 +251,12 @@ class single_client_gc_alloc_template {
}
static void ptr_free_deallocate(void *p, size_t n)
{
size_t nwords = GC_round_up(n);
void ** flh;
if (n > GC_max_fast_bytes) {
GC_free(p);
} else {
flh = GC_aobjfreelist_ptr + nwords;
size_t nwords = GC_round_up(n);
void ** flh = &GC_aobjfreelist_ptr[nwords];
GC_obj_link(p) = *flh;
*flh = p;
GC_aux::GC_bytes_recently_freed += nwords * GC_bytes_per_word;
@ -257,9 +276,15 @@ class single_client_traceable_alloc_template {
void ** flh;
void * op;
if (n > GC_max_fast_bytes) return GC_malloc_uncollectable(n);
flh = GC_uobjfreelist_ptr + nwords;
if (0 == (op = *flh)) {
if (n > GC_max_fast_bytes) {
op = GC_malloc_uncollectable(n);
if (0 == op)
GC_ALLOCATOR_THROW_OR_ABORT();
return op;
}
flh = &GC_uobjfreelist_ptr[nwords];
op = *flh;
if (0 == op) {
return GC_aux::GC_out_of_line_malloc(nwords, GC_UNCOLLECTABLE);
}
*flh = GC_obj_link(op);
@ -273,9 +298,15 @@ class single_client_traceable_alloc_template {
void ** flh;
void * op;
if (n > GC_max_fast_bytes) return GC_malloc_atomic_uncollectable(n);
flh = GC_auobjfreelist_ptr + nwords;
if (0 == (op = *flh)) {
if (n > GC_max_fast_bytes) {
op = GC_malloc_atomic_uncollectable(n);
if (0 == op)
GC_ALLOCATOR_THROW_OR_ABORT();
return op;
}
flh = &GC_auobjfreelist_ptr[nwords];
op = *flh;
if (0 == op) {
return GC_aux::GC_out_of_line_malloc(nwords, GC_AUNCOLLECTABLE);
}
*flh = GC_obj_link(op);
@ -285,13 +316,12 @@ class single_client_traceable_alloc_template {
}
static void deallocate(void *p, size_t n)
{
size_t nwords = GC_round_up_uncollectable(n);
void ** flh;
if (n > GC_max_fast_bytes) {
GC_free(p);
} else {
flh = GC_uobjfreelist_ptr + nwords;
size_t nwords = GC_round_up_uncollectable(n);
void ** flh = &GC_uobjfreelist_ptr[nwords];
GC_obj_link(p) = *flh;
*flh = p;
GC_aux::GC_uncollectable_bytes_recently_freed +=
@ -300,13 +330,12 @@ class single_client_traceable_alloc_template {
}
static void ptr_free_deallocate(void *p, size_t n)
{
size_t nwords = GC_round_up_uncollectable(n);
void ** flh;
if (n > GC_max_fast_bytes) {
GC_free(p);
} else {
flh = GC_auobjfreelist_ptr + nwords;
size_t nwords = GC_round_up_uncollectable(n);
void ** flh = &GC_auobjfreelist_ptr[nwords];
GC_obj_link(p) = *flh;
*flh = p;
GC_aux::GC_uncollectable_bytes_recently_freed +=
@ -320,9 +349,18 @@ typedef single_client_traceable_alloc_template<0> single_client_traceable_alloc;
template < int dummy >
class gc_alloc_template {
public:
static void * allocate(size_t n) { return GC_malloc(n); }
static void * ptr_free_allocate(size_t n)
{ return GC_malloc_atomic(n); }
static void * allocate(size_t n) {
void * op = GC_malloc(n);
if (0 == op)
GC_ALLOCATOR_THROW_OR_ABORT();
return op;
}
static void * ptr_free_allocate(size_t n) {
void * op = GC_malloc_atomic(n);
if (0 == op)
GC_ALLOCATOR_THROW_OR_ABORT();
return op;
}
static void deallocate(void *, size_t) { }
static void ptr_free_deallocate(void *, size_t) { }
};
@ -332,9 +370,18 @@ typedef gc_alloc_template < 0 > gc_alloc;
template < int dummy >
class traceable_alloc_template {
public:
static void * allocate(size_t n) { return GC_malloc_uncollectable(n); }
static void * ptr_free_allocate(size_t n)
{ return GC_malloc_atomic_uncollectable(n); }
static void * allocate(size_t n) {
void * op = GC_malloc_uncollectable(n);
if (0 == op)
GC_ALLOCATOR_THROW_OR_ABORT();
return op;
}
static void * ptr_free_allocate(size_t n) {
void * op = GC_malloc_atomic_uncollectable(n);
if (0 == op)
GC_ALLOCATOR_THROW_OR_ABORT();
return op;
}
static void deallocate(void *p, size_t) { GC_free(p); }
static void ptr_free_deallocate(void *p, size_t) { GC_free(p); }
};
@ -351,12 +398,12 @@ typedef traceable_alloc_template < 0 > traceable_alloc;
class simple_alloc<T, alloc> { \
public: \
static T *allocate(size_t n) \
{ return 0 == n? 0 : \
reinterpret_cast<T*>(alloc::ptr_free_allocate(n * sizeof(T))); } \
{ reinterpret_cast<T*>(alloc::ptr_free_allocate(0 == n ? 1 \
: n * sizeof(T))); } \
static T *allocate(void) \
{ return reinterpret_cast<T*>(alloc::ptr_free_allocate(sizeof(T))); } \
static void deallocate(T *p, size_t n) \
{ if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof(T)); } \
{ alloc::ptr_free_deallocate(p, 0 == n ? 1 : n * sizeof(T)); } \
static void deallocate(T *p) \
{ alloc::ptr_free_deallocate(p, sizeof(T)); } \
};

View file

@ -78,7 +78,7 @@ typedef struct {
/* We're careful never to overwrite a value with lsb 0. */
# if ALIGNMENT == 1
/* Fudge back pointer to be even. */
# define HIDE_BACK_PTR(p) GC_HIDE_POINTER(~1 & (GC_word)(p))
# define HIDE_BACK_PTR(p) GC_HIDE_POINTER(~1 & (word)(p))
# else
# define HIDE_BACK_PTR(p) GC_HIDE_POINTER(p)
# endif
@ -121,8 +121,7 @@ typedef struct {
#define SIMPLE_ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1) - 1)
/* ADD_CALL_CHAIN stores a (partial) call chain into an object */
/* header. It may be called with or without the allocation */
/* lock. */
/* header; it should be called with the allocation lock held. */
/* PRINT_CALL_CHAIN prints the call chain stored in an object */
/* to stderr. It requires that we do not hold the lock. */
#if defined(SAVE_CALL_CHAIN)
@ -157,6 +156,10 @@ typedef struct {
#endif
#if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
# ifdef SHORT_DBG_HDRS
# error Non-ptr stored in object results in GC_HAS_DEBUG_INFO malfunction
/* We may mistakenly conclude that p has a debugging wrapper. */
# endif
# define GC_HAS_DEBUG_INFO(p) \
((*((word *)p) & 1) && GC_has_other_debug_info(p) > 0)
#else

View file

@ -18,7 +18,7 @@
typedef struct hblkhdr hdr;
#if CPP_WORDSZ != 32 && CPP_WORDSZ < 36
--> Get a real machine.
# error Get a real machine
#endif
/*
@ -98,22 +98,21 @@ typedef struct hce {
#endif
/* Set hhdr to the header for p. Analogous to GET_HDR below, */
/* except that in the case of large objects, it */
/* gets the header for the object beginning, if GC_all_interior_ptrs */
/* is set. */
/* except that in the case of large objects, it gets the header for */
/* the object beginning if GC_all_interior_pointers is set. */
/* Returns zero if p points to somewhere other than the first page */
/* of an object, and it is not a valid pointer to the object. */
#define HC_GET_HDR(p, hhdr, source, exit_label) \
do { \
#define HC_GET_HDR(p, hhdr, source) \
{ /* cannot use do-while(0) here */ \
hdr_cache_entry * hce = HCE(p); \
if (EXPECT(HCE_VALID_FOR(hce, p), TRUE)) { \
HC_HIT(); \
hhdr = hce -> hce_hdr; \
} else { \
hhdr = HEADER_CACHE_MISS(p, hce, source); \
if (0 == hhdr) goto exit_label; \
if (NULL == hhdr) break; /* go to the enclosing loop end */ \
} \
} while (0)
}
typedef struct bi {
hdr * index[BOTTOM_SZ];

View file

@ -36,8 +36,12 @@
# include <base/PCR_Base.h>
# include <th/PCR_Th.h>
GC_EXTERN PCR_Th_ML GC_allocate_ml;
# define DCL_LOCK_STATE \
# if defined(CPPCHECK)
# define DCL_LOCK_STATE /* empty */
# else
# define DCL_LOCK_STATE \
PCR_ERes GC_fastLockRes; PCR_sigset_t GC_old_sig_mask
# endif
# define UNCOND_LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml)
# define UNCOND_UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
# endif
@ -99,7 +103,7 @@
# define NUMERIC_THREAD_ID_UNIQUE
# endif
# else /* pthreads-win32 */
# define NUMERIC_THREAD_ID(id) ((unsigned long)(id.p))
# define NUMERIC_THREAD_ID(id) ((unsigned long)(word)(id.p))
/* Using documented internal details of pthreads-win32 library. */
/* Faster than pthread_equal(). Should not change with */
/* future versions of pthreads-win32 library. */
@ -133,8 +137,7 @@
AO_CLEAR(&GC_allocate_lock); }
# else
# define UNCOND_LOCK() \
{ GC_ASSERT(I_DONT_HOLD_LOCK()); \
if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_SET) \
{ if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_SET) \
GC_lock(); }
# define UNCOND_UNLOCK() AO_CLEAR(&GC_allocate_lock)
# endif /* !GC_ASSERTIONS */
@ -154,11 +157,7 @@
pthread_mutex_unlock(&GC_allocate_ml); }
# else /* !GC_ASSERTIONS */
# if defined(NO_PTHREAD_TRYLOCK)
# ifdef USE_SPIN_LOCK
# define UNCOND_LOCK() GC_lock()
# else
# define UNCOND_LOCK() pthread_mutex_lock(&GC_allocate_ml)
# endif
# define UNCOND_LOCK() pthread_mutex_lock(&GC_allocate_ml)
# else
# define UNCOND_LOCK() \
{ if (0 != pthread_mutex_trylock(&GC_allocate_ml)) \
@ -183,15 +182,25 @@
|| GC_lock_holder != NUMERIC_THREAD_ID(pthread_self()))
# endif
# endif /* GC_ASSERTIONS */
GC_EXTERN volatile GC_bool GC_collecting;
# define ENTER_GC() GC_collecting = 1;
# define EXIT_GC() GC_collecting = 0;
# ifndef GC_WIN32_THREADS
GC_EXTERN volatile GC_bool GC_collecting;
# define ENTER_GC() (void)(GC_collecting = TRUE)
# define EXIT_GC() (void)(GC_collecting = FALSE)
# endif
GC_INNER void GC_lock(void);
# endif /* GC_PTHREADS with linux_threads.c implementation */
# ifdef GC_ALWAYS_MULTITHREADED
# endif /* GC_PTHREADS */
# if defined(GC_ALWAYS_MULTITHREADED) \
&& (defined(USE_PTHREAD_LOCKS) || defined(USE_SPIN_LOCK))
# define GC_need_to_lock TRUE
# define set_need_to_lock() (void)0
# else
# if defined(GC_ALWAYS_MULTITHREADED) && !defined(CPPCHECK)
# error Runtime initialization of GC lock is needed!
# endif
# undef GC_ALWAYS_MULTITHREADED
GC_EXTERN GC_bool GC_need_to_lock;
# define set_need_to_lock() (void)(GC_need_to_lock = TRUE)
/* We are multi-threaded now. */
# endif
# else /* !THREADS */
@ -207,7 +216,8 @@
# endif /* !THREADS */
#if defined(UNCOND_LOCK) && !defined(LOCK)
# if defined(LINT2) || defined(GC_ALWAYS_MULTITHREADED)
# if (defined(LINT2) && defined(USE_PTHREAD_LOCKS)) \
|| defined(GC_ALWAYS_MULTITHREADED)
/* Instruct code analysis tools not to care about GC_need_to_lock */
/* influence to LOCK/UNLOCK semantic. */
# define LOCK() UNCOND_LOCK()

View file

@ -22,7 +22,7 @@
#ifndef GC_PMARK_H
#define GC_PMARK_H
#ifdef HAVE_CONFIG_H
#if defined(HAVE_CONFIG_H) && !defined(GC_PRIVATE_H)
# include "config.h"
#endif
@ -30,6 +30,12 @@
# define GC_BUILD
#endif
#if (defined(__linux__) || defined(__GLIBC__) || defined(__GNU__)) \
&& !defined(_GNU_SOURCE) && defined(GC_PTHREADS) \
&& !defined(GC_NO_PTHREAD_SIGMASK)
# define _GNU_SOURCE 1
#endif
#if defined(KEEP_BACK_PTRS) || defined(PRINT_BLACK_LIST)
# include "dbg_mlc.h"
#endif
@ -130,57 +136,54 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
/* Push the contents of current onto the mark stack if it is a valid */
/* ptr to a currently unmarked object. Mark it. */
/* If we assumed a standard-conforming compiler, we could probably */
/* generate the exit_label transparently. */
#define PUSH_CONTENTS(current, mark_stack_top, mark_stack_limit, \
source, exit_label) \
#define PUSH_CONTENTS(current, mark_stack_top, mark_stack_limit, source) \
do { \
hdr * my_hhdr; \
HC_GET_HDR(current, my_hhdr, source, exit_label); \
HC_GET_HDR(current, my_hhdr, source); /* contains "break" */ \
PUSH_CONTENTS_HDR(current, mark_stack_top, mark_stack_limit, \
source, exit_label, my_hhdr, TRUE); \
exit_label: ; \
source, my_hhdr, TRUE); \
} while (0)
/* Set mark bit, exit if it was already set. */
/* Set mark bit, exit (using "break" statement) if it is already set. */
#ifdef USE_MARK_BYTES
/* There is a race here, and we may set */
/* the bit twice in the concurrent case. This can result in the */
/* object being pushed twice. But that's only a performance issue. */
# define SET_MARK_BIT_EXIT_IF_SET(hhdr,bit_no,exit_label) \
do { \
# define SET_MARK_BIT_EXIT_IF_SET(hhdr, bit_no) \
{ /* cannot use do-while(0) here */ \
char * mark_byte_addr = (char *)hhdr -> hb_marks + (bit_no); \
if (*mark_byte_addr) goto exit_label; \
if (*mark_byte_addr != 0) break; /* go to the enclosing loop end */ \
*mark_byte_addr = 1; \
} while (0)
}
#else
# ifdef PARALLEL_MARK
/* This is used only if we explicitly set USE_MARK_BITS. */
/* The following may fail to exit even if the bit was already set. */
/* For our uses, that's benign: */
# define OR_WORD_EXIT_IF_SET(addr, bits, exit_label) \
do { \
# define OR_WORD_EXIT_IF_SET(addr, bits) \
{ /* cannot use do-while(0) here */ \
if (!(*(addr) & (bits))) { \
AO_or((volatile AO_t *)(addr), (AO_t)(bits)); \
} else { \
goto exit_label; \
break; /* go to the enclosing loop end */ \
} \
} while (0)
}
# else
# define OR_WORD_EXIT_IF_SET(addr, bits, exit_label) \
do { \
# define OR_WORD_EXIT_IF_SET(addr, bits) \
{ /* cannot use do-while(0) here */ \
word old = *(addr); \
word my_bits = (bits); \
if (old & my_bits) goto exit_label; \
*(addr) = (old | my_bits); \
} while (0)
if ((old & my_bits) != 0) \
break; /* go to the enclosing loop end */ \
*(addr) = old | my_bits; \
}
# endif /* !PARALLEL_MARK */
# define SET_MARK_BIT_EXIT_IF_SET(hhdr,bit_no,exit_label) \
do { \
# define SET_MARK_BIT_EXIT_IF_SET(hhdr, bit_no) \
{ /* cannot use do-while(0) here */ \
word * mark_word_addr = hhdr -> hb_marks + divWORDSZ(bit_no); \
OR_WORD_EXIT_IF_SET(mark_word_addr, (word)1 << modWORDSZ(bit_no), \
exit_label); \
} while (0)
OR_WORD_EXIT_IF_SET(mark_word_addr, \
(word)1 << modWORDSZ(bit_no)); /* contains "break" */ \
}
#endif /* !USE_MARK_BYTES */
#ifdef PARALLEL_MARK
@ -228,7 +231,7 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
/* interior of a large object. */
#ifdef MARK_BIT_PER_GRANULE
# define PUSH_CONTENTS_HDR(current, mark_stack_top, mark_stack_limit, \
source, exit_label, hhdr, do_offset_check) \
source, hhdr, do_offset_check) \
do { \
size_t displ = HBLKDISPL(current); /* Displacement in block; in bytes. */\
/* displ is always within range. If current doesn't point to */ \
@ -252,7 +255,7 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
} else { \
if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
goto exit_label; \
break; /* go to the end of PUSH_CONTENTS_HDR */ \
} \
} \
gran_displ = 0; \
@ -264,7 +267,7 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
+ byte_offset; \
if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
goto exit_label; \
break; \
} \
gran_displ -= gran_offset; \
base -= obj_displ; \
@ -274,31 +277,27 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
GC_ASSERT(gran_displ % BYTES_TO_GRANULES(hhdr -> hb_sz) == 0); \
TRACE(source, GC_log_printf("GC #%u: passed validity tests\n", \
(unsigned)GC_gc_no)); \
SET_MARK_BIT_EXIT_IF_SET(hhdr, gran_displ, exit_label); \
SET_MARK_BIT_EXIT_IF_SET(hhdr, gran_displ); \
TRACE(source, GC_log_printf("GC #%u: previously unmarked\n", \
(unsigned)GC_gc_no)); \
TRACE_TARGET(base, \
GC_log_printf("GC #%u: marking %p from %p instead\n", \
(unsigned)GC_gc_no, base, source)); \
(unsigned)GC_gc_no, (void *)base, (void *)(source))); \
INCR_MARKS(hhdr); \
GC_STORE_BACK_PTR((ptr_t)source, base); \
GC_STORE_BACK_PTR((ptr_t)(source), base); \
PUSH_OBJ(base, hhdr, mark_stack_top, mark_stack_limit); \
} while (0)
#endif /* MARK_BIT_PER_GRANULE */
#ifdef MARK_BIT_PER_OBJ
# define PUSH_CONTENTS_HDR(current, mark_stack_top, mark_stack_limit, \
source, exit_label, hhdr, do_offset_check) \
source, hhdr, do_offset_check) \
do { \
size_t displ = HBLKDISPL(current); /* Displacement in block; in bytes. */\
unsigned32 low_prod, high_prod; \
unsigned32 high_prod; \
unsigned32 inv_sz = hhdr -> hb_inv_sz; \
ptr_t base = current; \
LONG_MULT(high_prod, low_prod, displ, inv_sz); \
/* product is > and within sz_in_bytes of displ * sz_in_bytes * 2**32 */ \
if (EXPECT(low_prod >> 16 != 0, FALSE)) { \
/* FIXME: fails if offset is a multiple of HBLKSIZE which becomes 0 */ \
if (inv_sz == LARGE_INV_SZ) { \
ptr_t base; \
if (EXPECT(inv_sz == LARGE_INV_SZ, FALSE)) { \
size_t obj_displ; \
base = (ptr_t)(hhdr -> hb_block); \
obj_displ = (ptr_t)(current) - base; \
@ -309,19 +308,25 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
} else { \
if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
goto exit_label; \
break; /* go to the end of PUSH_CONTENTS_HDR */ \
} \
} \
GC_ASSERT(hhdr -> hb_sz > HBLKSIZE || \
hhdr -> hb_block == HBLKPTR(current)); \
GC_ASSERT((word)hhdr->hb_block < (word)(current)); \
} else { \
GC_ASSERT((word)(hhdr)->hb_block <= (word)(current)); \
high_prod = 0; \
} else { \
unsigned32 low_prod; \
base = (ptr_t)(current); \
LONG_MULT(high_prod, low_prod, (unsigned32)displ, inv_sz); \
if ((low_prod >> 16) != 0) { \
size_t obj_displ; \
/* Accurate enough if HBLKSIZE <= 2**15. */ \
GC_STATIC_ASSERT(HBLKSIZE <= (1 << 15)); \
size_t obj_displ = (((low_prod >> 16) + 1) * (hhdr->hb_sz)) >> 16; \
obj_displ = (((low_prod >> 16) + 1) * hhdr->hb_sz) >> 16; \
if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
goto exit_label; \
break; \
} \
base -= obj_displ; \
} \
@ -331,14 +336,14 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
GC_ASSERT(high_prod <= HBLK_OBJS(hhdr -> hb_sz)); \
TRACE(source, GC_log_printf("GC #%u: passed validity tests\n", \
(unsigned)GC_gc_no)); \
SET_MARK_BIT_EXIT_IF_SET(hhdr, high_prod, exit_label); \
SET_MARK_BIT_EXIT_IF_SET(hhdr, high_prod); \
TRACE(source, GC_log_printf("GC #%u: previously unmarked\n", \
(unsigned)GC_gc_no)); \
TRACE_TARGET(base, \
GC_log_printf("GC #%u: marking %p from %p instead\n", \
(unsigned)GC_gc_no, base, source)); \
(unsigned)GC_gc_no, (void *)base, (void *)(source))); \
INCR_MARKS(hhdr); \
GC_STORE_BACK_PTR((ptr_t)source, base); \
GC_STORE_BACK_PTR((ptr_t)(source), base); \
PUSH_OBJ(base, hhdr, mark_stack_top, mark_stack_limit); \
} while (0)
#endif /* MARK_BIT_PER_OBJ */
@ -359,7 +364,7 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
* if the mark stack overflows.
*/
#if NEED_FIXUP_POINTER
#ifdef NEED_FIXUP_POINTER
/* Try both the raw version and the fixed up one. */
# define GC_PUSH_ONE_STACK(p, source) \
do { \
@ -439,34 +444,34 @@ typedef int mark_state_t; /* Current state of marking, as follows:*/
/* grungy if it was marked dirty in the */
/* last set of bits we retrieved. */
/* Invariant I: all roots and marked */
/* Invariant "I": all roots and marked */
/* objects p are either dirty, or point */
/* to objects q that are either marked */
/* or a pointer to q appears in a range */
/* on the mark stack. */
#define MS_NONE 0 /* No marking in progress. I holds. */
#define MS_NONE 0 /* No marking in progress. "I" holds. */
/* Mark stack is empty. */
#define MS_PUSH_RESCUERS 1 /* Rescuing objects are currently */
/* being pushed. I holds, except */
/* being pushed. "I" holds, except */
/* that grungy roots may point to */
/* unmarked objects, as may marked */
/* grungy objects above scan_ptr. */
#define MS_PUSH_UNCOLLECTABLE 2 /* I holds, except that marked */
#define MS_PUSH_UNCOLLECTABLE 2 /* "I" holds, except that marked */
/* uncollectible objects above scan_ptr */
/* may point to unmarked objects. */
/* Roots may point to unmarked objects */
#define MS_ROOTS_PUSHED 3 /* I holds, mark stack may be nonempty */
#define MS_ROOTS_PUSHED 3 /* "I" holds, mark stack may be nonempty. */
#define MS_PARTIALLY_INVALID 4 /* I may not hold, e.g. because of M.S. */
/* overflow. However marked heap */
/* objects below scan_ptr point to */
/* marked or stacked objects. */
#define MS_PARTIALLY_INVALID 4 /* "I" may not hold, e.g. because of */
/* the mark stack overflow. However */
/* marked heap objects below scan_ptr */
/* point to marked or stacked objects. */
#define MS_INVALID 5 /* I may not hold. */
#define MS_INVALID 5 /* "I" may not hold. */
GC_EXTERN mark_state_t GC_mark_state;

View file

@ -37,6 +37,12 @@
# define _USING_POSIX4A_DRAFT10 1
#endif
#if defined(__MINGW32__) && !defined(__MINGW_EXCPT_DEFINE_PSDK) \
&& defined(__i386__) && defined(GC_EXTERN) /* defined in gc.c */
/* See the description in mark.c. */
# define __MINGW_EXCPT_DEFINE_PSDK 1
#endif
# if defined(NO_DEBUGGING) && !defined(GC_ASSERTIONS) && !defined(NDEBUG)
/* To turn off assertion checking (in atomic_ops.h). */
# define NDEBUG 1
@ -90,10 +96,30 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
/* byte displacements and which can be used */
/* for address comparisons. */
#ifndef SIZE_MAX
# include <limits.h>
#endif
#if defined(SIZE_MAX) && !defined(CPPCHECK)
# define GC_SIZE_MAX ((size_t)SIZE_MAX)
/* Extra cast to workaround some buggy SIZE_MAX definitions. */
#else
# define GC_SIZE_MAX (~(size_t)0)
#endif
/* Saturated addition of size_t values. Used to avoid value wrap */
/* around on overflow. The arguments should have no side effects. */
#define SIZET_SAT_ADD(a, b) \
((a) < GC_SIZE_MAX - (b) ? (a) + (b) : GC_SIZE_MAX)
#ifndef GCCONFIG_H
# include "gcconfig.h"
#endif
#if !defined(GC_ATOMIC_UNCOLLECTABLE) && defined(ATOMIC_UNCOLLECTABLE)
/* For compatibility with old-style naming. */
# define GC_ATOMIC_UNCOLLECTABLE
#endif
#ifndef GC_INNER
/* This tagging macro must be used at the start of every variable */
/* definition which is declared with GC_EXTERN. Should be also used */
@ -104,7 +130,7 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
/* located in the "extra" folder). */
# if defined(GC_DLL) && defined(__GNUC__) && !defined(MSWIN32) \
&& !defined(MSWINCE) && !defined(CYGWIN32)
# if __GNUC__ >= 4
# if (__GNUC__ >= 4) && !defined(GC_NO_VISIBILITY)
/* See the corresponding GC_API definition. */
# define GC_INNER __attribute__((__visibility__("hidden")))
# else
@ -129,6 +155,26 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
# include "gc_hdrs.h"
#endif
#ifndef GC_ATTR_NO_SANITIZE_ADDR
# ifndef ADDRESS_SANITIZER
# define GC_ATTR_NO_SANITIZE_ADDR /* empty */
# elif __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 8)
# define GC_ATTR_NO_SANITIZE_ADDR __attribute__((no_sanitize("address")))
# else
# define GC_ATTR_NO_SANITIZE_ADDR __attribute__((no_sanitize_address))
# endif
#endif /* !GC_ATTR_NO_SANITIZE_ADDR */
#ifndef GC_ATTR_NO_SANITIZE_MEMORY
# ifndef MEMORY_SANITIZER
# define GC_ATTR_NO_SANITIZE_MEMORY /* empty */
# elif __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 8)
# define GC_ATTR_NO_SANITIZE_MEMORY __attribute__((no_sanitize("memory")))
# else
# define GC_ATTR_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
# endif
#endif /* !GC_ATTR_NO_SANITIZE_MEMORY */
#ifndef GC_ATTR_UNUSED
# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
# define GC_ATTR_UNUSED __attribute__((__unused__))
@ -157,10 +203,20 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
# define GC_INLINE static
#endif
#ifndef GC_ATTR_NOINLINE
# if __GNUC__ >= 4
# define GC_ATTR_NOINLINE __attribute__((__noinline__))
# elif _MSC_VER >= 1400
# define GC_ATTR_NOINLINE __declspec(noinline)
# else
# define GC_ATTR_NOINLINE /* empty */
# endif
#endif
#ifndef GC_API_OSCALL
/* This is used to identify GC routines called by name from OS. */
# if defined(__GNUC__)
# if __GNUC__ >= 4
# if (__GNUC__ >= 4) && !defined(GC_NO_VISIBILITY)
/* Same as GC_API if GC_DLL. */
# define GC_API_OSCALL extern __attribute__((__visibility__("default")))
# else
@ -250,36 +306,39 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
#ifndef GC_NO_FINALIZATION
# define GC_INVOKE_FINALIZERS() GC_notify_or_invoke_finalizers()
GC_INNER void GC_notify_or_invoke_finalizers(void);
# define GC_INVOKE_FINALIZERS() GC_notify_or_invoke_finalizers()
GC_INNER void GC_notify_or_invoke_finalizers(void);
/* If GC_finalize_on_demand is not set, invoke */
/* eligible finalizers. Otherwise: */
/* Call *GC_finalizer_notifier if there are */
/* finalizers to be run, and we haven't called */
/* this procedure yet this GC cycle. */
GC_INNER void GC_push_finalizer_structures(void);
GC_INNER void GC_finalize(void);
GC_INNER void GC_finalize(void);
/* Perform all indicated finalization actions */
/* on unmarked objects. */
/* Unreachable finalizable objects are enqueued */
/* for processing by GC_invoke_finalizers. */
/* Invoked with lock. */
# ifndef SMALL_CONFIG
GC_INNER void GC_print_finalization_stats(void);
# endif
# ifndef GC_TOGGLE_REFS_NOT_NEEDED
GC_INNER void GC_process_togglerefs(void);
/* Process the toggle-refs before GC starts. */
# endif
# ifndef SMALL_CONFIG
GC_INNER void GC_print_finalization_stats(void);
# endif
#else
# define GC_INVOKE_FINALIZERS() (void)0
# define GC_INVOKE_FINALIZERS() (void)0
#endif /* GC_NO_FINALIZATION */
#if !defined(DONT_ADD_BYTE_AT_END)
# ifdef LINT2
/* Explicitly instruct the code analysis tool that */
/* GC_all_interior_pointers is assumed to have only 0 or 1 value. */
# define EXTRA_BYTES (GC_all_interior_pointers? 1 : 0)
# define EXTRA_BYTES ((size_t)(GC_all_interior_pointers? 1 : 0))
# else
# define EXTRA_BYTES GC_all_interior_pointers
# define EXTRA_BYTES (size_t)GC_all_interior_pointers
# endif
# define MAX_EXTRA_BYTES 1
#else
@ -420,7 +479,7 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
# define BCOPY_EXISTS
# endif
# ifndef BCOPY_EXISTS
# if !defined(BCOPY_EXISTS) || defined(CPPCHECK)
# include <string.h>
# define BCOPY(x,y,n) memcpy(y, x, (size_t)(n))
# define BZERO(x,n) memset(x, 0, (size_t)(n))
@ -455,8 +514,19 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
# endif
# endif
#ifdef THREADS
GC_EXTERN GC_on_thread_event_proc GC_on_thread_event;
#endif
/* Abandon ship */
# ifdef PCR
# if defined(SMALL_CONFIG) || defined(PCR)
# define GC_on_abort(msg) (void)0 /* be silent on abort */
# else
GC_API_PRIV GC_abort_func GC_on_abort;
# endif
# if defined(CPPCHECK)
# define ABORT(msg) { GC_on_abort(msg); abort(); }
# elif defined(PCR)
# define ABORT(s) PCR_Base_Panic(s)
# else
# if defined(MSWINCE) && !defined(DebugBreak) \
@ -468,11 +538,6 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
/* instead of defining it as a macro). */
# define DebugBreak() _exit(-1) /* there is no abort() in WinCE */
# endif
# ifdef SMALL_CONFIG
# define GC_on_abort(msg) (void)0 /* be silent on abort */
# else
GC_API_PRIV GC_abort_func GC_on_abort;
# endif /* !SMALL_CONFIG */
# if defined(MSWIN32) && (defined(NO_DEBUGGING) || defined(LINT2))
/* A more user-friendly abort after showing fatal message. */
# define ABORT(msg) (GC_on_abort(msg), _exit(-1))
@ -494,17 +559,18 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
/* should match their format specifiers. */
#define ABORT_ARG1(C_msg, C_fmt, arg1) \
do { \
GC_COND_LOG_PRINTF(C_msg /* + */ C_fmt, arg1); \
GC_INFOLOG_PRINTF(C_msg /* + */ C_fmt "\n", arg1); \
ABORT(C_msg); \
} while (0)
#define ABORT_ARG2(C_msg, C_fmt, arg1, arg2) \
do { \
GC_COND_LOG_PRINTF(C_msg /* + */ C_fmt, arg1, arg2); \
GC_INFOLOG_PRINTF(C_msg /* + */ C_fmt "\n", arg1, arg2); \
ABORT(C_msg); \
} while (0)
#define ABORT_ARG3(C_msg, C_fmt, arg1, arg2, arg3) \
do { \
GC_COND_LOG_PRINTF(C_msg /* + */ C_fmt, arg1, arg2, arg3); \
GC_INFOLOG_PRINTF(C_msg /* + */ C_fmt "\n", \
arg1, arg2, arg3); \
ABORT(C_msg); \
} while (0)
@ -524,7 +590,7 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
/* The argument (if any) format specifier should be: */
/* "%s", "%p" or "%"WARN_PRIdPTR. */
#define WARN(msg, arg) (*GC_current_warn_proc)("GC Warning: " msg, \
(GC_word)(arg))
(word)(arg))
GC_EXTERN GC_warn_proc GC_current_warn_proc;
/* Print format type macro for decimal signed_word value passed WARN(). */
@ -537,11 +603,16 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
# define WARN_PRIdPTR "ld"
#endif
/* A tagging macro (for a code static analyzer) to indicate that the */
/* string obtained from an untrusted source (e.g., argv[], getenv) is */
/* safe to use in a vulnerable operation (e.g., open, exec). */
#define TRUSTED_STRING(s) (char*)COVERT_DATAFLOW(s)
/* Get environment entry */
#ifdef GC_READ_ENV_FILE
GC_INNER char * GC_envfile_getenv(const char *name);
# define GETENV(name) GC_envfile_getenv(name)
#elif defined(NO_GETENV)
#elif defined(NO_GETENV) && !defined(CPPCHECK)
# define GETENV(name) NULL
#elif defined(EMPTY_GETENV_RESULTS)
/* Workaround for a reputed Wine bug. */
@ -586,7 +657,8 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
# define GC_MACH_THREAD_STATE x86_THREAD_STATE64
# define GC_MACH_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
# endif
# elif defined(ARM32) && defined(ARM_UNIFIED_THREAD_STATE)
# elif defined(ARM32) && defined(ARM_UNIFIED_THREAD_STATE) \
&& !defined(CPPCHECK)
# define GC_THREAD_STATE_T arm_unified_thread_state_t
# define GC_MACH_THREAD_STATE ARM_UNIFIED_THREAD_STATE
# define GC_MACH_THREAD_STATE_COUNT ARM_UNIFIED_THREAD_STATE_COUNT
@ -600,7 +672,7 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
# define GC_THREAD_STATE_T arm_thread_state64_t
# define GC_MACH_THREAD_STATE ARM_THREAD_STATE64
# define GC_MACH_THREAD_STATE_COUNT ARM_THREAD_STATE64_COUNT
# else
# elif !defined(CPPCHECK)
# error define GC_THREAD_STATE_T
# endif
# ifndef GC_MACH_THREAD_STATE
@ -624,17 +696,14 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
/* without __, thus hopefully, not breaking any existing */
/* Makefile.direct builds. */
# if __DARWIN_UNIX03
# if defined(ARM32) && defined(ARM_UNIFIED_THREAD_STATE)
# define THREAD_FLD(x) ts_32.__ ## x
# else
# define THREAD_FLD(x) __ ## x
# endif
# define THREAD_FLD_NAME(x) __ ## x
# else
# if defined(ARM32) && defined(ARM_UNIFIED_THREAD_STATE)
# define THREAD_FLD(x) ts_32. ## x
# else
# define THREAD_FLD(x) x
# endif
# define THREAD_FLD_NAME(x) x
# endif
# if defined(ARM32) && defined(ARM_UNIFIED_THREAD_STATE)
# define THREAD_FLD(x) ts_32.THREAD_FLD_NAME(x)
# else
# define THREAD_FLD(x) THREAD_FLD_NAME(x)
# endif
#endif /* DARWIN */
@ -739,7 +808,7 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
# elif HBLKSIZE == 16384
# define CPP_LOG_HBLKSIZE 14
# else
--> fix HBLKSIZE
# error fix HBLKSIZE
# endif
# undef HBLKSIZE
#endif
@ -748,11 +817,11 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
# define LOG_HBLKSIZE ((size_t)CPP_LOG_HBLKSIZE)
# define HBLKSIZE ((size_t)CPP_HBLKSIZE)
#define GC_SQRT_SIZE_MAX ((((size_t)1) << (WORDSZ / 2)) - 1)
/* max size objects supported by freelist (larger objects are */
/* Max size objects supported by freelist (larger objects are */
/* allocated directly with allchblk(), by rounding to the next */
/* multiple of HBLKSIZE. */
/* multiple of HBLKSIZE). */
#define CPP_MAXOBJBYTES (CPP_HBLKSIZE/2)
#define MAXOBJBYTES ((size_t)CPP_MAXOBJBYTES)
#define CPP_MAXOBJWORDS BYTES_TO_WORDS(CPP_MAXOBJBYTES)
@ -772,17 +841,17 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
# define modHBLKSZ(n) ((n) & (HBLKSIZE-1))
# define HBLKPTR(objptr) ((struct hblk *)(((word) (objptr)) & ~(HBLKSIZE-1)))
# define HBLKPTR(objptr) ((struct hblk *)(((word)(objptr)) \
& ~(word)(HBLKSIZE-1)))
# define HBLKDISPL(objptr) (((size_t) (objptr)) & (HBLKSIZE-1))
/* Round up allocation size (in bytes) to a multiple of a granule. */
#define ROUNDUP_GRANULE_SIZE(bytes) \
(((bytes) + (GRANULE_BYTES - 1)) & ~(GRANULE_BYTES - 1))
#define ROUNDUP_GRANULE_SIZE(lb) /* lb should have no side-effect */ \
(SIZET_SAT_ADD(lb, GRANULE_BYTES - 1) & ~(GRANULE_BYTES - 1))
/* Round up byte allocation requests to integral number of words, etc. */
# define ROUNDED_UP_GRANULES(n) \
BYTES_TO_GRANULES((n) + (GRANULE_BYTES - 1 + EXTRA_BYTES))
# define ROUNDED_UP_GRANULES(lb) /* lb should have no side-effect */ \
BYTES_TO_GRANULES(SIZET_SAT_ADD(lb, GRANULE_BYTES - 1 + EXTRA_BYTES))
# if MAX_EXTRA_BYTES == 0
# define SMALL_OBJ(bytes) EXPECT((bytes) <= (MAXOBJBYTES), TRUE)
# else
@ -792,7 +861,8 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
/* This really just tests bytes <= MAXOBJBYTES - EXTRA_BYTES. */
/* But we try to avoid looking up EXTRA_BYTES. */
# endif
# define ADD_SLOP(bytes) ((bytes) + EXTRA_BYTES)
# define ADD_SLOP(lb) /* lb should have no side-effect */ \
SIZET_SAT_ADD(lb, EXTRA_BYTES)
# ifndef MIN_WORDS
# define MIN_WORDS 2 /* FIXME: obsolete */
# endif
@ -943,9 +1013,9 @@ struct hblkhdr {
/* without generating a negative result. We avoid */
/* generating free blocks larger than that. */
word hb_descr; /* object descriptor for marking. See */
/* mark.h. */
/* gc_mark.h. */
# ifdef MARK_BIT_PER_GRANULE
short * hb_map; /* Essentially a table of remainders */
unsigned short * hb_map; /* Essentially a table of remainders */
/* mod BYTES_TO_GRANULES(hb_sz), except */
/* for large blocks. See GC_obj_map. */
# endif
@ -1010,9 +1080,11 @@ struct hblk {
# define HBLK_IS_FREE(hdr) (((hdr) -> hb_flags & FREE_BLK) != 0)
# define OBJ_SZ_TO_BLOCKS(sz) divHBLKSZ((sz) + HBLKSIZE-1)
# define OBJ_SZ_TO_BLOCKS(lb) divHBLKSZ((lb) + HBLKSIZE-1)
# define OBJ_SZ_TO_BLOCKS_CHECKED(lb) /* lb should have no side-effect */ \
divHBLKSZ(SIZET_SAT_ADD(lb, HBLKSIZE - 1))
/* Size of block (in units of HBLKSIZE) needed to hold objects of */
/* given sz (in bytes). */
/* given lb (in bytes). The checked variant prevents wrap around. */
/* Object free list link */
# define obj_link(p) (*(void **)(p))
@ -1206,17 +1278,17 @@ struct _GC_arrays {
/* free list for objects */
# define GC_aobjfreelist GC_arrays._aobjfreelist
void *_aobjfreelist[MAXOBJGRANULES+1];
/* free list for atomic objs */
/* free list for atomic objects */
# endif
void *_uobjfreelist[MAXOBJGRANULES+1];
/* Uncollectible but traced objs */
/* objects on this and auobjfreelist */
/* Uncollectible but traced objects. */
/* Objects on this and _auobjfreelist */
/* are always marked, except during */
/* garbage collections. */
# ifdef ATOMIC_UNCOLLECTABLE
# ifdef GC_ATOMIC_UNCOLLECTABLE
# define GC_auobjfreelist GC_arrays._auobjfreelist
void *_auobjfreelist[MAXOBJGRANULES+1];
/* Atomic uncollectible but traced objs */
/* Atomic uncollectible but traced objects. */
# endif
size_t _size_map[MAXOBJBYTES+1];
/* Number of granules to allocate when asked for a certain */
@ -1228,7 +1300,7 @@ struct _GC_arrays {
# endif
# ifdef MARK_BIT_PER_GRANULE
# define GC_obj_map GC_arrays._obj_map
short * _obj_map[MAXOBJGRANULES+1];
unsigned short * _obj_map[MAXOBJGRANULES + 1];
/* If not NULL, then a pointer to a map of valid */
/* object addresses. */
/* _obj_map[sz_in_granules][i] is */
@ -1266,7 +1338,7 @@ struct _GC_arrays {
volatile page_hash_table _dirty_pages;
/* Pages dirtied since last GC_read_dirty. */
# endif
# if defined(PROC_VDB) || defined(GWW_VDB)
# if (defined(CHECKSUMS) && defined(GWW_VDB)) || defined(PROC_VDB)
# define GC_written_pages GC_arrays._written_pages
page_hash_table _written_pages; /* Pages ever dirtied */
# endif
@ -1335,16 +1407,17 @@ GC_API_PRIV GC_FAR struct _GC_arrays GC_arrays;
#define USED_HEAP_SIZE (GC_heapsize - GC_large_free_bytes)
/* Object kinds: */
#define MAXOBJKINDS 16
#ifndef MAXOBJKINDS
# define MAXOBJKINDS 16
#endif
GC_EXTERN struct obj_kind {
void **ok_freelist; /* Array of free listheaders for this kind of object */
/* Point either to GC_arrays or to storage allocated */
/* with GC_scratch_alloc. */
void **ok_freelist; /* Array of free list headers for this kind of */
/* object. Point either to GC_arrays or to */
/* storage allocated with GC_scratch_alloc. */
struct hblk **ok_reclaim_list;
/* List headers for lists of blocks waiting to be */
/* swept. */
/* Indexed by object size in granules. */
/* List headers for lists of blocks waiting to */
/* be swept. Indexed by object size in */
/* granules. */
word ok_descriptor; /* Descriptor template for objects in this */
/* block. */
GC_bool ok_relocate_descr;
@ -1385,7 +1458,7 @@ GC_EXTERN struct obj_kind {
# define endGC_objfreelist (beginGC_objfreelist + sizeof(GC_objfreelist))
extern ptr_t GC_aobjfreelist[MAXOBJGRANULES+1];
/* free list for atomic (PTRFREE) objs */
/* free list for atomic (PTRFREE) objects */
# define beginGC_aobjfreelist ((ptr_t)(&GC_aobjfreelist))
# define endGC_aobjfreelist (beginGC_aobjfreelist + sizeof(GC_aobjfreelist))
#endif /* SEPARATE_GLOBALS */
@ -1394,7 +1467,7 @@ GC_EXTERN struct obj_kind {
#define PTRFREE 0
#define NORMAL 1
#define UNCOLLECTABLE 2
#ifdef ATOMIC_UNCOLLECTABLE
#ifdef GC_ATOMIC_UNCOLLECTABLE
# define AUNCOLLECTABLE 3
# define STUBBORN 4
# define IS_UNCOLLECTABLE(k) (((k) & ~1) == UNCOLLECTABLE)
@ -1413,18 +1486,18 @@ GC_EXTERN word GC_n_heap_sects; /* Number of separately added heap */
/* sections. */
#endif
GC_EXTERN word GC_page_size;
GC_EXTERN size_t GC_page_size;
/* Round up allocation size to a multiple of a page size. */
/* GC_setpagesize() is assumed to be already invoked. */
#define ROUNDUP_PAGESIZE(bytes) \
(((bytes) + GC_page_size - 1) & ~(GC_page_size - 1))
#define ROUNDUP_PAGESIZE(lb) /* lb should have no side-effect */ \
(SIZET_SAT_ADD(lb, GC_page_size - 1) & ~(GC_page_size - 1))
/* Same as above but used to make GET_MEM() argument safe. */
#ifdef MMAP_SUPPORTED
# define ROUNDUP_PAGESIZE_IF_MMAP(bytes) ROUNDUP_PAGESIZE(bytes)
# define ROUNDUP_PAGESIZE_IF_MMAP(lb) ROUNDUP_PAGESIZE(lb)
#else
# define ROUNDUP_PAGESIZE_IF_MMAP(bytes) (bytes)
# define ROUNDUP_PAGESIZE_IF_MMAP(lb) (lb)
#endif
#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
@ -1451,7 +1524,8 @@ GC_EXTERN word GC_black_list_spacing;
# define TRUE_INCREMENTAL FALSE
#else
GC_EXTERN GC_bool GC_incremental;
/* Using incremental/generational collection. */
/* Using incremental/generational collection. */
/* Assumes dirty bits are being maintained. */
# define TRUE_INCREMENTAL \
(GC_incremental && GC_time_limit != GC_TIME_UNLIMITED)
/* True incremental, not just generational, mode */
@ -1589,23 +1663,12 @@ GC_INNER void GC_initiate_gc(void);
GC_INNER GC_bool GC_collection_in_progress(void);
/* Collection is in progress, or was abandoned. */
#ifndef GC_DISABLE_INCREMENTAL
# define GC_PUSH_CONDITIONAL(b, t, all) \
GC_push_conditional((ptr_t)(b), (ptr_t)(t), all)
/* Do either of GC_push_all or GC_push_selected */
/* depending on the third arg. */
#else
# define GC_PUSH_CONDITIONAL(b, t, all) GC_push_all((ptr_t)(b), (ptr_t)(t))
#endif
#define GC_PUSH_ALL_SYM(sym) \
GC_push_all((ptr_t)&(sym), (ptr_t)&(sym) + sizeof(sym))
GC_INNER void GC_push_all_stack(ptr_t b, ptr_t t);
/* As GC_push_all but consider */
/* interior pointers as valid. */
GC_INNER void GC_push_all_eager(ptr_t b, ptr_t t);
/* Same as GC_push_all_stack, but */
/* ensures that stack is scanned */
/* immediately, not just scheduled */
/* for scanning. */
/* In the threads case, we push part of the current thread stack */
/* with GC_push_all_eager when we push the registers. This gets the */
@ -1634,7 +1697,7 @@ GC_EXTERN void (*GC_push_typed_structures)(void);
/* the typed allocation support if unused. */
GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
ptr_t arg);
volatile ptr_t arg);
#if defined(SPARC) || defined(IA64)
/* Cause all stacked registers to be saved in memory. Return a */
@ -1676,6 +1739,9 @@ GC_INNER void GC_set_fl_marks(ptr_t p);
/* set. Abort if not. */
#endif
void GC_add_roots_inner(ptr_t b, ptr_t e, GC_bool tmp);
#ifdef USE_PROC_FOR_LIBRARIES
GC_INNER void GC_remove_roots_subregion(ptr_t b, ptr_t e);
#endif
GC_INNER void GC_exclude_static_roots_inner(void *start, void *finish);
#if defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
|| defined(CYGWIN32) || defined(PCR)
@ -1748,6 +1814,14 @@ GC_INNER ptr_t GC_scratch_alloc(size_t bytes);
/* small objects. Deallocation is not */
/* possible. May return NULL. */
#ifdef GWW_VDB
/* GC_scratch_recycle_no_gww() not used. */
#else
# define GC_scratch_recycle_no_gww GC_scratch_recycle_inner
#endif
GC_INNER void GC_scratch_recycle_inner(void *ptr, size_t bytes);
/* Reuse the memory region by the heap. */
/* Heap block layout maps: */
GC_INNER GC_bool GC_add_map_entry(size_t sz);
/* Add a heap block map for objects of */
@ -1829,6 +1903,13 @@ GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func f);
#define GC_gcollect_inner() \
(void)GC_try_to_collect_inner(GC_never_stop_func)
#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)
GC_EXTERN GC_bool GC_in_thread_creation;
/* We may currently be in thread creation or destruction. */
/* Only set to TRUE while allocation lock is held. */
/* When set, it is OK to run GC from unknown thread. */
#endif
GC_EXTERN GC_bool GC_is_initialized; /* GC_init() has been run. */
#if defined(MSWIN32) || defined(MSWINCE)
@ -1846,12 +1927,15 @@ GC_INNER void GC_collect_a_little_inner(int n);
GC_INNER void * GC_generic_malloc_inner(size_t lb, int k);
/* Allocate an object of the given */
/* kind but assuming lock already held. */
GC_INNER void * GC_generic_malloc_inner_ignore_off_page(size_t lb, int k);
#if defined(DBG_HDRS_ALL) || defined(GC_GCJ_SUPPORT) \
|| !defined(GC_NO_FINALIZATION)
GC_INNER void * GC_generic_malloc_inner_ignore_off_page(size_t lb, int k);
/* Allocate an object, where */
/* the client guarantees that there */
/* will always be a pointer to the */
/* beginning of the object while the */
/* object is live. */
#endif
GC_INNER ptr_t GC_allocobj(size_t sz, int kind);
/* Make the indicated */
@ -1862,7 +1946,7 @@ GC_INNER ptr_t GC_allocobj(size_t sz, int kind);
/* GC_DBG_EXTRAS is used by GC debug API functions (unlike GC_EXTRAS */
/* used by GC debug API macros) thus GC_RETURN_ADDR_PARENT (pointing */
/* to client caller) should be used if possible. */
# ifdef GC_RETURN_ADDR_PARENT
# ifdef GC_HAVE_RETURN_ADDR_PARENT
# define GC_DBG_EXTRAS GC_RETURN_ADDR_PARENT, NULL, 0
# else
# define GC_DBG_EXTRAS GC_RETURN_ADDR, NULL, 0
@ -1889,13 +1973,9 @@ GC_INNER ptr_t GC_allocobj(size_t sz, int kind);
#endif /* !GC_COLLECT_AT_MALLOC */
/* Allocation routines that bypass the thread local cache. */
#ifdef THREAD_LOCAL_ALLOC
GC_INNER void * GC_core_malloc(size_t);
GC_INNER void * GC_core_malloc_atomic(size_t);
# ifdef GC_GCJ_SUPPORT
#if defined(THREAD_LOCAL_ALLOC) && defined(GC_GCJ_SUPPORT)
GC_INNER void * GC_core_gcj_malloc(size_t, void *);
# endif
#endif /* THREAD_LOCAL_ALLOC */
#endif
GC_INNER void GC_init_headers(void);
GC_INNER struct hblkhdr * GC_install_header(struct hblk *h);
@ -1973,6 +2053,11 @@ GC_EXTERN GC_bool GC_have_errors; /* We saw a smashed or leaked object. */
GC_INNER void GC_generate_random_backtrace_no_gc(void);
#endif
#ifdef LINT2
# define GC_RAND_MAX (~0U >> 1)
GC_API_PRIV long GC_random(void);
#endif
GC_EXTERN GC_bool GC_print_back_height;
#ifdef MAKE_BACK_GRAPH
@ -2037,26 +2122,40 @@ GC_EXTERN GC_bool GC_print_back_height;
#endif
#ifndef GC_DISABLE_INCREMENTAL
GC_EXTERN GC_bool GC_dirty_maintained;
/* Dirty bits are being maintained, */
/* either for incremental collection, */
/* or to limit the root set. */
/* Virtual dirty bit implementation: */
/* Each implementation exports the following: */
GC_INNER void GC_read_dirty(void);
/* Retrieve dirty bits. */
GC_INNER GC_bool GC_page_was_dirty(struct hblk *h);
/* Read retrieved dirty bits. */
GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
GC_bool pointerfree);
/* h is about to be written or allocated. Ensure */
/* that it's not write protected by the virtual */
/* dirty bit implementation. */
/* h is about to be written or allocated. Ensure that */
/* it is not write protected by the virtual dirty bit */
/* implementation. I.e., this is a call that: */
/* - hints that [h, h+nblocks) is about to be written; */
/* - guarantees that protection is removed; */
/* - may speed up some dirty bit implementations; */
/* - may be essential if we need to ensure that */
/* pointer-free system call buffers in the heap are */
/* not protected. */
GC_INNER void GC_dirty_init(void);
GC_INNER GC_bool GC_dirty_init(void);
/* Returns true if dirty bits are maintained (otherwise */
/* it is OK to be called again if the client invokes */
/* GC_enable_incremental once more). */
#endif /* !GC_DISABLE_INCREMENTAL */
#ifdef MANUAL_VDB
GC_INNER void GC_dirty_inner(const void *p); /* does not require locking */
# define GC_dirty(p) (GC_incremental ? GC_dirty_inner(p) : (void)0)
# define REACHABLE_AFTER_DIRTY(p) GC_reachable_here(p)
#else
# define GC_dirty(p) (void)(p)
# define REACHABLE_AFTER_DIRTY(p) (void)(p)
#endif
/* Same as GC_base but excepts and returns a pointer to const object. */
#define GC_base_C(p) ((const void *)GC_base((/* no const */ void *)(p)))
@ -2244,12 +2343,13 @@ GC_INNER void GC_initialize_offsets(void); /* defined in obj_map.c */
GC_INNER void GC_bl_init(void);
GC_INNER void GC_bl_init_no_interiors(void); /* defined in blacklst.c */
GC_INNER void GC_start_debugging(void); /* defined in dbg_mlc.c */
GC_INNER void GC_start_debugging_inner(void); /* defined in dbg_mlc.c. */
/* Should not be called if GC_debugging_started. */
/* Store debugging info into p. Return displaced pointer. */
/* Assumes we don't hold allocation lock. */
GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
int linenum);
/* Assumes we hold the allocation lock. */
GC_INNER void *GC_store_debug_info_inner(void *p, word sz, const char *str,
int linenum);
#ifdef REDIRECT_MALLOC
# ifdef GC_LINUX_THREADS
@ -2350,6 +2450,14 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
# define GC_STATIC_ASSERT(expr) (void)sizeof(char[(expr)? 1 : -1])
#endif
/* Runtime check for an argument declared as non-null is actually not null. */
#if defined(__GNUC__) && __GNUC__ >= 4
/* Workaround tautological-pointer-compare Clang warning. */
# define NONNULL_ARG_NOT_NULL(arg) (*(volatile void **)&(arg) != NULL)
#else
# define NONNULL_ARG_NOT_NULL(arg) (NULL != (arg))
#endif
#define COND_DUMP_CHECKS \
do { \
GC_ASSERT(GC_compute_large_free_bytes() == GC_large_free_bytes); \
@ -2386,12 +2494,13 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
/* GC_notify_all_builder() is called when GC_fl_builder_count */
/* reaches 0. */
GC_INNER void GC_wait_for_markers_init(void);
GC_INNER void GC_acquire_mark_lock(void);
GC_INNER void GC_release_mark_lock(void);
GC_INNER void GC_notify_all_builder(void);
GC_INNER void GC_wait_for_reclaim(void);
GC_EXTERN word GC_fl_builder_count; /* Protected by mark lock. */
GC_EXTERN signed_word GC_fl_builder_count; /* Protected by mark lock. */
GC_INNER void GC_notify_all_marker(void);
GC_INNER void GC_wait_marker(void);
@ -2402,6 +2511,8 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
/* my_mark_no. Returns if the mark cycle finishes or */
/* was already done, or there was nothing to do for */
/* some other reason. */
GC_INNER void GC_start_mark_threads_inner(void);
#endif /* PARALLEL_MARK */
#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) && !defined(NACL) \
@ -2426,7 +2537,7 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
# ifndef GC_OPENBSD_UTHREADS
# define SIG_SUSPEND SIGXFSZ
# endif
# elif defined(_SIGRTMIN)
# elif defined(_SIGRTMIN) && !defined(CPPCHECK)
# define SIG_SUSPEND _SIGRTMIN + 6
# else
# define SIG_SUSPEND SIGRTMIN + 6
@ -2473,18 +2584,19 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
# define NEED_FIND_LIMIT
#endif
#if (defined(SVR4) || defined(AUX) || defined(DGUX) \
#if (defined(SVR4) || defined(AIX) || defined(DGUX) \
|| (defined(LINUX) && defined(SPARC))) && !defined(PCR)
# define NEED_FIND_LIMIT
#endif
#if defined(FREEBSD) && (defined(I386) || defined(X86_64) \
|| defined(powerpc) || defined(__powerpc__))
#if defined(DATASTART_USES_BSDGETDATASTART)
# include <machine/trap.h>
# if !defined(PCR)
# define NEED_FIND_LIMIT
# endif
#endif /* FREEBSD */
GC_INNER ptr_t GC_FreeBSDGetDataStart(size_t, ptr_t);
# define DATASTART_IS_FUNC
#endif /* DATASTART_USES_BSDGETDATASTART */
#if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__) \
&& !defined(NEED_FIND_LIMIT)
@ -2499,10 +2611,10 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
#if defined(NEED_FIND_LIMIT) \
|| (defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS))
JMP_BUF GC_jmp_buf;
GC_EXTERN JMP_BUF GC_jmp_buf;
/* Set up a handler for address faults which will longjmp to */
/* GC_jmp_buf; */
/* GC_jmp_buf. */
GC_INNER void GC_setup_temporary_fault_handler(void);
/* Undo the effect of GC_setup_temporary_fault_handler. */
GC_INNER void GC_reset_fault_handler(void);

File diff suppressed because it is too large Load diff

View file

@ -19,10 +19,10 @@
#define GC_PTHREAD_STOP_WORLD_H
struct thread_stop_info {
# ifndef GC_OPENBSD_UTHREADS
word last_stop_count; /* GC_last_stop_count value when thread */
/* last successfully handled a suspend */
/* signal. */
# if !defined(GC_OPENBSD_UTHREADS) && !defined(NACL)
volatile AO_t last_stop_count;
/* The value of GC_stop_count when the thread */
/* last successfully handled a suspend signal. */
# endif
ptr_t stack_ptr; /* Valid only when stopped. */
@ -34,7 +34,12 @@ struct thread_stop_info {
/* saved registers, they may be pushed to the stack much earlier. */
/* Also, on amd64 'push' puts 8 bytes on the stack even though */
/* our pointers are 4 bytes. */
# define NACL_GC_REG_STORAGE_SIZE 20
# ifdef ARM32
/* Space for r4-r8, r10-r12, r14. */
# define NACL_GC_REG_STORAGE_SIZE 9
# else
# define NACL_GC_REG_STORAGE_SIZE 20
# endif
ptr_t reg_storage[NACL_GC_REG_STORAGE_SIZE];
# endif
};

View file

@ -46,12 +46,17 @@ typedef struct GC_Thread_Rep {
/* guaranteed to be dead, but we may */
/* not yet have registered the join.) */
pthread_t id;
# ifdef PLATFORM_ANDROID
# ifdef USE_TKILL_ON_ANDROID
pid_t kernel_id;
# endif
/* Extra bookkeeping information the stopping code uses */
struct thread_stop_info stop_info;
# if defined(GC_ENABLE_SUSPEND_THREAD) && !defined(GC_DARWIN_THREADS) \
&& !defined(GC_OPENBSD_UTHREADS) && !defined(NACL)
volatile AO_t suspended_ext; /* Thread was suspended externally. */
# endif
unsigned char flags;
# define FINISHED 1 /* Thread has exited. */
# define DETACHED 2 /* Thread is treated as detached. */
@ -62,9 +67,6 @@ typedef struct GC_Thread_Rep {
/* it unregisters itself, since it */
/* may not return a GC pointer. */
# define MAIN_THREAD 4 /* True for the original thread only. */
# define SUSPENDED_EXT 8 /* Thread was suspended externally */
/* (this is not used by the unmodified */
/* GC itself at present). */
# define DISABLED_GC 0x10 /* Collections are disabled while the */
/* thread is exiting. */
@ -86,6 +88,12 @@ typedef struct GC_Thread_Rep {
ptr_t stack_end; /* Cold end of the stack (except for */
/* main thread). */
ptr_t altstack; /* The start of the alt-stack if there */
/* is one, NULL otherwise. */
word altstack_size; /* The size of the alt-stack if exists. */
ptr_t stack; /* The start and size of the normal */
/* stack (set by GC_register_altstack). */
word stack_size;
# if defined(GC_DARWIN_THREADS) && !defined(DARWIN_DONT_PARSE_STACK)
ptr_t topOfStack; /* Result of GC_FindTopOfStack(0); */
/* valid only if the thread is blocked; */
@ -114,18 +122,15 @@ typedef struct GC_Thread_Rep {
# endif
} * GC_thread;
# define THREAD_TABLE_SZ 256 /* Must be power of 2 */
#ifndef THREAD_TABLE_SZ
# define THREAD_TABLE_SZ 256 /* Power of 2 (for speed). */
#endif
GC_EXTERN volatile GC_thread GC_threads[THREAD_TABLE_SZ];
GC_EXTERN GC_bool GC_thr_initialized;
GC_INNER GC_thread GC_lookup_thread(pthread_t id);
GC_EXTERN GC_bool GC_in_thread_creation;
/* We may currently be in thread creation or destruction. */
/* Only set to TRUE while allocation lock is held. */
/* When set, it is OK to run GC from unknown thread. */
#ifdef NACL
GC_EXTERN __thread GC_thread GC_nacl_gc_thread_self;
GC_INNER void GC_nacl_initialize_gc_thread(void);

View file

@ -31,7 +31,7 @@
/* An entry describing a thread-specific value for a given thread. */
/* All such accessible structures preserve the invariant that if either */
/* thread is a valid pthread id or qtid is a valid "quick tread id" */
/* thread is a valid pthread id or qtid is a valid "quick thread id" */
/* for a thread, then value holds the corresponding thread specific */
/* value. This invariant must be preserved at ALL times, since */
/* asynchronous reads are allowed. */
@ -76,7 +76,9 @@ typedef tsd * GC_key_t;
#define GC_key_create(key, d) GC_key_create_inner(key)
GC_INNER int GC_key_create_inner(tsd ** key_ptr);
GC_INNER int GC_setspecific(tsd * key, void * value);
GC_INNER void GC_remove_specific(tsd * key);
#define GC_remove_specific(key) \
GC_remove_specific_after_fork(key, pthread_self())
GC_INNER void GC_remove_specific_after_fork(tsd * key, pthread_t t);
/* An internal version of getspecific that assumes a cache miss. */
GC_INNER void * GC_slow_getspecific(tsd * key, word qtid,

Some files were not shown because too many files have changed in this diff Show more