From 4c166b860de4305989d7cb8bcabb457817ffaaef Mon Sep 17 00:00:00 2001 From: John Pye Date: Thu, 25 Nov 2021 00:10:23 +1100 Subject: [PATCH 01/12] duplicating changes from jdpipe/gs-netstream https://github.com/graphstream/gs-netstream/pull/10 --- graphstream/gs-netstream/c++/.gitignore | 6 + graphstream/gs-netstream/c++/Makefile | 24 +- .../gs-netstream/c++/src/netstream-main.cpp | 71 ++--- .../gs-netstream/c++/src/netstream-sender.cpp | 199 ++++++------- .../gs-netstream/c++/src/netstream-sender.h | 131 ++++----- .../gs-netstream/c++/src/netstream-socket.cpp | 109 ++++---- .../gs-netstream/c++/src/netstream-socket.h | 28 +- .../c++/src/netstream-storage.cpp | 262 ++++++++---------- .../gs-netstream/c++/src/netstream-storage.h | 60 ++-- 9 files changed, 428 insertions(+), 462 deletions(-) create mode 100644 graphstream/gs-netstream/c++/.gitignore diff --git a/graphstream/gs-netstream/c++/.gitignore b/graphstream/gs-netstream/c++/.gitignore new file mode 100644 index 000000000..291ff7f5e --- /dev/null +++ b/graphstream/gs-netstream/c++/.gitignore @@ -0,0 +1,6 @@ +netstream-main +*.exe +*.dll +*.so +*.o +*.a diff --git a/graphstream/gs-netstream/c++/Makefile b/graphstream/gs-netstream/c++/Makefile index 64ae89768..973442b4e 100644 --- a/graphstream/gs-netstream/c++/Makefile +++ b/graphstream/gs-netstream/c++/Makefile @@ -3,7 +3,7 @@ OBJDIR=obj SRCDIR=src INCDIR=include -ifeq (darwin,$(findstring darwin,$(shell $(CC) -v 2>&1 | grep ^Target))) +ifeq ($(shell uname),Darwin) AR=libtool ARFLAGS=-static -o else @@ -11,22 +11,25 @@ else ARFLAGS=rcs endif +CC = g++ CWARN = -W -Wall -Wshadow -Wimplicit -Wreturn-type -Wcomment -Wtrigraphs -Wformat -Wparentheses -Wpointer-arith -Wuninitialized -O CDBG = -g $(CWARN) -fno-inline +CFLAGS = -I$(INCDIR) -O3 DFLAGS = -I$(INCDIR) -g $(CWARN) -fno-inline -DDEBUG=1 -ifeq (MINGW,$(findstring MINGW,$(shell uname))) +# https://stackoverflow.com/questions/714100/os-detecting-makefile +ifeq ($(OS),Windows_NT) SOCKET_LIB = -lwsock32 else - SOCKET_LIB = + SOCKET_LIB = endif CTAG = ctags CTAGFILE = filelist # src, object and bin files -OUT_BINARY := netstream-main +OUT_BINARY := netstream-main OUT_LIBRARY := libnetstream.a HEADERS = $(INCDIR)/global.h @@ -35,22 +38,22 @@ OBJS = \ $(OBJDIR)/netstream-storage.o \ $(OBJDIR)/netstream-socket.o \ $(OBJDIR)/netstream-sender.o \ - $(OBJDIR)/netstream-main.o - + $(OBJDIR)/netstream-main.o + .SECONDARY: #-- Rules all: $(OUT_BINARY) $(OUT_LIBRARY) $(OUT_BINARY): $(OBJS) - $(CXX) $(CFLAGS) -I$(INCDIR) $(OBJS) -o $(OUT_BINARY) $(SOCKET_LIB) + $(CC) $(CFLAGS) $(OBJS) -o $(OUT_BINARY) $(SOCKET_LIB) $(OUT_LIBRARY): $(OBJS) - $(AR) $(ARFLAGS) $(OUT_LIBRARY) $(OBJS) + $(AR) $(ARFLAGS) $(OUT_LIBRARY) $(OBJS) $(OBJDIR)/%.o: $(SRCDIR)/%.cpp mkdir -p $(OBJDIR) - $(CXX) $(CFLAGS) -c $? -o $@ + $(CC) $(CFLAGS) -c $? -o $@ .PHONY: clean depend fresh @@ -64,8 +67,7 @@ clean: -rm -f $(SRCDIR)/*.output $(LEX_C) -rm -f */*~ *~ core -rm -f $(BINDIR)/* - -rm -f $(OUT_BINARY) $(OUT_BINARY).exe + -rm -f $(OUT_BINARY) -rm -f $(OUT_LIBRARY) - -rm -rf $(OBJDIR) fresh: clean all diff --git a/graphstream/gs-netstream/c++/src/netstream-main.cpp b/graphstream/gs-netstream/c++/src/netstream-main.cpp index b99ba7939..303a45352 100644 --- a/graphstream/gs-netstream/c++/src/netstream-main.cpp +++ b/graphstream/gs-netstream/c++/src/netstream-main.cpp @@ -13,8 +13,6 @@ #include #include - -#include "netstream-sizes.h" #include "netstream-storage.h" #include "netstream-socket.h" #include "netstream-constants.h" @@ -38,7 +36,7 @@ int main (int argc, char const *argv[]) void e(){ string source_id="C++_netstream_test"; - GS_LONG time_id=0L; + long time_id=0L; NetStreamSender stream("default","localhost",2001,false); string n1("node"); while(1) { @@ -48,9 +46,12 @@ void e(){ } + + + void example(){ - string source_id("C"); - GS_LONG time_id = 0L; + string source_id("C++_netstream_test"); + long time_id=0L; NetStreamSender stream("default","localhost",2001,false); string style("node{fill-mode:plain;fill-color:#567;size:6px;}"); stream.addGraphAttribute(source_id, time_id++, "stylesheet", style); @@ -58,39 +59,42 @@ void example(){ stream.changeGraphAttribute(source_id, time_id++, "test", "test",false); stream.addGraphAttribute(source_id, time_id++, "ui.antialias", true); stream.addGraphAttribute(source_id, time_id++, "layout.stabilization-limit", 0); - for (int i = 0; i < 10; i++) { + for (int i = 0; i < 500; i++) { stringstream n1; n1< 0) { - stringstream n2; - n2<<(i-1); - stringstream n3; - n3<<(i/2); - stringstream e1; - e1< 0) { + + + stringstream n2; + n2<<(i-1); + + stringstream n3; + n3<<(i/2); + + stringstream e1; + e1< value(v,v+3); @@ -104,12 +108,12 @@ void types_test(){ vector value3(v3,v3+2); stream.addGraphAttribute(source_id, time_id++, "doubleArray", value3); - GS_LONG v4[] = {1776,7,4}; - vector value4(v4,v4+3); + long int v4[] = {1776,7,4}; + vector value4(v4,v4+3); stream.addGraphAttribute(source_id, time_id++, "longArray", value4); - GS_CHAR v5[] = {'0',(GS_CHAR)0,'z'}; - vector value5(v5,v5+3); + char v5[] = {'0',(char)0,'z'}; + vector value5(v5,v5+3); stream.addGraphAttribute(source_id, time_id++, "byteArray",value5 ); bool v6[] = {true,false}; @@ -121,10 +125,9 @@ void types_test(){ void events_test(){ string source_id="C++_netstream_test"; - GS_LONG time_id = 0L; + long time_id=0L; NetStreamSender stream("localhost", 2001); stream.addNode(source_id, time_id++, "node0"); - stream.addNode(source_id, time_id++, "node1"); stream.addEdge(source_id, time_id++, "edge", "node0", "node1", true); stream.addNodeAttribute(source_id, time_id++, "node0","nodeAttribute", 0); stream.changeNodeAttribute(source_id, time_id++, "node0","nodeAttribute",0, 1); diff --git a/graphstream/gs-netstream/c++/src/netstream-sender.cpp b/graphstream/gs-netstream/c++/src/netstream-sender.cpp index 06bc4727b..cd8cc614c 100644 --- a/graphstream/gs-netstream/c++/src/netstream-sender.cpp +++ b/graphstream/gs-netstream/c++/src/netstream-sender.cpp @@ -10,31 +10,27 @@ * @author Yoann Pigné */ -/* include unistd on *nix systems for sleep */ -#if !defined(__MINGW32__) && !defined(_MSC_VER) -#include -#endif #include "netstream-sender.h" namespace netstream{ -NetStreamSender::NetStreamSender(const GS_STRING & host, GS_INT port): +NetStreamSender::NetStreamSender(const string & host, int port): _stream_name("default"),_host(host),_port(port),_stream(),_socket(host,port),debug(false) { init(); } -NetStreamSender::NetStreamSender(GS_INT port): +NetStreamSender::NetStreamSender(int port): _stream_name("default"),_host("localhost"),_port(port),_stream(),_socket("localhost",port),debug(false) { init(); } -NetStreamSender::NetStreamSender(const GS_STRING & stream, const GS_STRING & host, GS_INT port): +NetStreamSender::NetStreamSender(const string & stream, const string & host, int port): _stream_name(stream),_host(host),_port(port),_stream(),_socket(host,port),debug(false) { init(); } -NetStreamSender::NetStreamSender(const GS_STRING & stream, const GS_STRING & host, GS_INT port, GS_BOOL debug): +NetStreamSender::NetStreamSender(const string & stream, const string & host, int port, bool debug): _stream_name(stream),_host(host),_port(port),_stream(),_socket(host,port),debug(debug) { init(); @@ -42,7 +38,7 @@ _stream_name(stream),_host(host),_port(port),_stream(),_socket(host,port),debug( void NetStreamSender::init() -{ +{ _stream.writeString(_stream_name); int wait_for_server = 1; @@ -58,7 +54,11 @@ void NetStreamSender::init() else std::cout<<"."< & object){ +int NetStreamSender::_getType(const vector & object){ if(debug){ - cerr<<"NetStreamSender: _getType : char* "< & object){ +int NetStreamSender::_getType(const vector & object){ if(debug){ - cerr<<"NetStreamSender: _getType : bool*"< & object){ +int NetStreamSender::_getType(const vector & object){ if(debug){ - cerr<<"NetStreamSender: _getType : int*"< & object){ +int NetStreamSender::_getType(const vector & object){ if(debug){ - cerr<<"NetStreamSender: _getType : long*"< & object){ +int NetStreamSender::_getType(const vector & object){ if(debug){ - cerr<<"NetStreamSender: _getType : float*"< & object){ +int NetStreamSender::_getType(const vector & object){ if(debug){ - cerr<<"NetStreamSender: _getType : double*"< & value){ - event.writeInt(value.size()); +void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ + event.writeUnsignedVarint(value.size()); for(vector::const_iterator i = value.begin(); i != value.end(); i++){ event.writeByte((*i)); } } - -void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ - event.writeInt(value.size()); +void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ + event.writeUnsignedVarint(value.size()); for(vector::const_iterator i = value.begin(); i != value.end(); i++){ event.writeByte((*i)); } } - -void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ - event.writeInt(value.size()); +void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ + event.writeUnsignedVarint(value.size()); for(vector::const_iterator i = value.begin(); i != value.end(); i++){ - event.writeInt((*i)); + event.writeVarint((*i)); } } - -void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ - event.writeInt(value.size()); - for(vector::const_iterator i = value.begin(); i != value.end(); i++){ - event.writeLong((*i)); +void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ + event.writeUnsignedVarint(value.size()); + for(vector::const_iterator i = value.begin(); i != value.end(); i++){ + event.writeVarint((*i)); } } - -void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ - event.writeInt(value.size()); - for(vector::const_iterator i = value.begin(); i != value.end(); i++){ +void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ + event.writeUnsignedVarint(value.size()); + for(vector::const_iterator i = value.begin(); i != value.end(); i++){ event.writeFloat((*i)); } } - -void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ - event.writeInt(value.size()); - for(vector::const_iterator i = value.begin(); i != value.end(); i++){ +void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ + event.writeUnsignedVarint(value.size()); + for(vector::const_iterator i = value.begin(); i != value.end(); i++){ event.writeDouble((*i)); } } @@ -224,6 +203,13 @@ void NetStreamSender::_sendEvent(NetStreamStorage & event){ if(debug){ cout< -#if !defined(__MINGW32__) -#include + + +#ifndef WIN32 + #include +#else + #include #endif -#include -#include "netstream-sizes.h" + +#include + #include "netstream-storage.h" #include "netstream-socket.h" #include "netstream-constants.h" @@ -33,39 +37,39 @@ namespace netstream{ class NetStreamSender{ protected: - GS_STRING _stream_name; - GS_STRING _host; - GS_INT _port; + string _stream_name; + string _host; + int _port; NetStreamSocket _socket; NetStreamStorage _stream; - GS_BOOL debug; + bool debug; void init(); template - GS_INT getType(T t) + int getType(T t) { return _getType(t); } template - GS_INT getType(const vector & t) + int getType(const vector & t) { return _getType(t); } - GS_INT _getType(GS_CHAR object); - GS_INT _getType(GS_BOOL object); - GS_INT _getType(GS_INT object); - GS_INT _getType(GS_LONG object); - GS_INT _getType(GS_FLOAT object); - GS_INT _getType(GS_DOUBLE object); - GS_INT _getType(const GS_STRING & object); - GS_INT _getType( const vector & object); - GS_INT _getType( const vector & object); - GS_INT _getType( const vector & object); - GS_INT _getType( const vector & object); - GS_INT _getType( const vector & object); - GS_INT _getType( const vector & object); + int _getType(char object); + int _getType(bool object); + int _getType(int object); + int _getType(long object); + int _getType(float object); + int _getType(double object); + int _getType(const string & object); + int _getType( const vector & object); + int _getType( const vector & object); + int _getType( const vector & object); + int _getType( const vector & object); + int _getType( const vector & object); + int _getType( const vector & object); template void encode(NetStreamStorage & event, const T & value){ @@ -75,20 +79,20 @@ class NetStreamSender{ void encode(NetStreamStorage & event, const vector & value){ _encode(event, value); } - void _encode(NetStreamStorage & event, GS_CHAR value); - void _encode(NetStreamStorage & event, GS_BOOL value); - void _encode(NetStreamStorage & event, GS_INT value); - void _encode(NetStreamStorage & event, GS_LONG value); - void _encode(NetStreamStorage & event, GS_FLOAT value); - void _encode(NetStreamStorage & event, GS_DOUBLE value); - void _encode(NetStreamStorage & event, const GS_STRING & value); + void _encode(NetStreamStorage & event, char value); + void _encode(NetStreamStorage & event, bool value); + void _encode(NetStreamStorage & event, int value); + void _encode(NetStreamStorage & event, long value); + void _encode(NetStreamStorage & event, float value); + void _encode(NetStreamStorage & event, double value); + void _encode(NetStreamStorage & event, const string & value); - void _encode(NetStreamStorage & event, const vector & value); - void _encode(NetStreamStorage & event, const vector & value); - void _encode(NetStreamStorage & event, const vector & value); - void _encode(NetStreamStorage & event, const vector & value); - void _encode(NetStreamStorage & event, const vector & value); - void _encode(NetStreamStorage & event, const vector & value); + void _encode(NetStreamStorage & event, const vector & value); + void _encode(NetStreamStorage & event, const vector & value); + void _encode(NetStreamStorage & event, const vector & value); + void _encode(NetStreamStorage & event, const vector & value); + void _encode(NetStreamStorage & event, const vector & value); + void _encode(NetStreamStorage & event, const vector & value); void _sendEvent(NetStreamStorage &); @@ -98,30 +102,29 @@ class NetStreamSender{ // ================ // = Constructors = // ================ - NetStreamSender(const GS_STRING & host, GS_INT port); - NetStreamSender(GS_INT port); - NetStreamSender(const GS_STRING & stream, const GS_STRING & host, GS_INT port); - NetStreamSender(const GS_STRING & stream, const GS_STRING & host, GS_INT port, GS_BOOL debug); - + NetStreamSender(const string & host, int port); + NetStreamSender(int port); + NetStreamSender(const string & stream, const string & host, int port); + NetStreamSender(const string & stream, const string & host, int port, bool debug); // ================== // = Element events = // ================== - void addNode(const GS_STRING & source_id, GS_LONG time_id, const GS_STRING & node_id); - void removeNode(const GS_STRING & source_id, GS_LONG time_id, const GS_STRING & node_id); - void addEdge(const GS_STRING & source_id, GS_LONG time_id, const GS_STRING & edge_id, const GS_STRING & from_node, const GS_STRING & to_node, GS_BOOL directed); - void removeEdge(const GS_STRING & source_id, GS_LONG time_id, const GS_STRING & edge_id); - void stepBegins(const GS_STRING & source_id, GS_LONG time_id, GS_DOUBLE timestamp); - void graphClear(const GS_STRING & source_id, GS_LONG time_id); + void addNode(const string & source_id, long time_id, const string & node_id); + void removeNode(const string & source_id, long time_id, const string & node_id); + void addEdge(const string & source_id, long time_id, const string & edge_id, const string & from_node, const string & to_node, bool directed); + void removeEdge(const string & source_id, long time_id, const string & edge_id); + void stepBegins(const string & source_id, long time_id, double timestamp); + void graphClear(const string & source_id, long time_id); // ==================== // = Attribute events = // ==================== template - void addGraphAttribute(const GS_STRING & source_id, GS_LONG time_id, const GS_STRING & attribute, T value){ + void addGraphAttribute(const string & source_id, long time_id, const string & attribute, T value){ NetStreamStorage event = NetStreamStorage(); event.writeByte(netstream::EVENT_ADD_GRAPH_ATTR); event.writeString(source_id); - event.writeUnsignedVarInt(time_id); + event.writeUnsignedVarint(time_id); event.writeString(attribute); event.writeByte(getType(value)); encode(event, value); @@ -129,11 +132,11 @@ class NetStreamSender{ } template - void changeGraphAttribute(const GS_STRING & source_id, GS_LONG time_id, const GS_STRING & attribute, const T1 & oldValue, const T2 & newValue){ + void changeGraphAttribute(const string & source_id, long time_id, const string & attribute, const T1 & oldValue, const T2 & newValue){ NetStreamStorage event = NetStreamStorage(); event.writeByte(EVENT_CHG_GRAPH_ATTR); event.writeString(source_id); - event.writeUnsignedVarInt(time_id); + event.writeUnsignedVarint(time_id); event.writeString(attribute); event.writeByte(getType(oldValue)); encode(event, oldValue); @@ -142,14 +145,14 @@ class NetStreamSender{ _sendEvent(event); } - void removeGraphAttribute(const GS_STRING & source_id, GS_LONG time_id, const GS_STRING & attribute); + void removeGraphAttribute(const string & source_id, long time_id, const string & attribute); template - void addNodeAttribute(const GS_STRING & source_id, GS_LONG time_id, const GS_STRING & node_id, const GS_STRING & attribute, const T & value){ + void addNodeAttribute(const string & source_id, long time_id, const string & node_id, const string & attribute, const T & value){ NetStreamStorage event = NetStreamStorage(); event.writeByte(EVENT_ADD_NODE_ATTR); event.writeString(source_id); - event.writeUnsignedVarInt(time_id); + event.writeUnsignedVarint(time_id); event.writeString(node_id); event.writeString(attribute); event.writeByte(getType(value)); @@ -158,11 +161,11 @@ class NetStreamSender{ } template - void changeNodeAttribute(const GS_STRING & source_id, GS_LONG time_id, const GS_STRING & node_id, const GS_STRING & attribute, const T1 & oldValue, const T2 & newValue){ + void changeNodeAttribute(const string & source_id, long time_id, const string & node_id, const string & attribute, const T1 & oldValue, const T2 & newValue){ NetStreamStorage event = NetStreamStorage(); event.writeByte(EVENT_CHG_NODE_ATTR); event.writeString(source_id); - event.writeUnsignedVarInt(time_id); + event.writeUnsignedVarint(time_id); event.writeString(node_id); event.writeString(attribute); event.writeByte(getType(oldValue)); @@ -172,14 +175,14 @@ class NetStreamSender{ _sendEvent(event); } - void removeNodeAttribute(const GS_STRING & source_id, GS_LONG time_id, const GS_STRING & node_id, const GS_STRING & attribute); + void removeNodeAttribute(const string & source_id, long time_id, const string & node_id, const string & attribute); template - void addEdgeAttribute(const GS_STRING & source_id, GS_LONG time_id, const GS_STRING & edge_id, const GS_STRING & attribute, const T & value){ + void addEdgeAttribute(const string & source_id, long time_id, const string & edge_id, const string & attribute, const T & value){ NetStreamStorage event = NetStreamStorage(); event.writeByte(EVENT_ADD_EDGE_ATTR); event.writeString(source_id); - event.writeUnsignedVarInt(time_id); + event.writeUnsignedVarint(time_id); event.writeString(edge_id); event.writeString(attribute); event.writeByte(getType(value)); @@ -189,11 +192,11 @@ class NetStreamSender{ } template - void changeEdgeAttribute(const GS_STRING & source_id, GS_LONG time_id, const GS_STRING & edge_id, const GS_STRING & attribute, const T1 & oldValue, const T2 & newValue){ + void changeEdgeAttribute(const string & source_id, long time_id, const string & edge_id, const string & attribute, const T1 & oldValue, const T2 & newValue){ NetStreamStorage event = NetStreamStorage(); event.writeByte(EVENT_CHG_EDGE_ATTR); event.writeString(source_id); - event.writeUnsignedVarInt(time_id); + event.writeUnsignedVarint(time_id); event.writeString(edge_id); event.writeString(attribute); event.writeByte(getType(oldValue)); @@ -203,9 +206,9 @@ class NetStreamSender{ _sendEvent(event); } - void removeEdgeAttribute(const GS_STRING & source_id, GS_LONG time_id, const GS_STRING & edge_id, const GS_STRING & attribute); + void removeEdgeAttribute(const string & source_id, long time_id, const string & edge_id, const string & attribute); }; } -#endif +#endif \ No newline at end of file diff --git a/graphstream/gs-netstream/c++/src/netstream-socket.cpp b/graphstream/gs-netstream/c++/src/netstream-socket.cpp index aa459e587..f5fa6d9af 100644 --- a/graphstream/gs-netstream/c++/src/netstream-socket.cpp +++ b/graphstream/gs-netstream/c++/src/netstream-socket.cpp @@ -6,7 +6,16 @@ ** file in the root of the Shawn source tree for further details. ** ************************************************************************/ -#if !defined(_WIN32) && !defined(_WIN64) +#ifdef SHAWN + #include + #include +#else + #include "netstream-socket.h" +#endif + + + +#ifndef WIN32 #include #include #include @@ -15,7 +24,7 @@ #include #include #include - #include /* include unistd on *nix systems for close */ + #include #else #ifdef ERROR #undef ERROR @@ -23,21 +32,12 @@ #include -#if !defined(__MINGW32__) #ifndef vsnprintf #define vsnprintf _vsnprintf #endif -#endif #endif -#ifdef SHAWN - #include - #include -#else - #include "netstream-socket.h" -#endif - #include #include #include @@ -67,7 +67,7 @@ namespace netstream // ---------------------------------------------------------------------- NetStreamSocket:: - NetStreamSocket(std::string host, int port) + NetStreamSocket(std::string host, int port) : host_( host ), port_( port ), socket_(-1), @@ -80,7 +80,7 @@ namespace netstream // ---------------------------------------------------------------------- NetStreamSocket:: - NetStreamSocket(int port) + NetStreamSocket(int port) : host_(""), port_( port ), socket_(-1), @@ -131,7 +131,7 @@ namespace netstream } #ifdef WIN32 - if( server_socket_ == -1 && socket_ == -1 + if( server_socket_ == -1 && socket_ == -1 && init_windows_sockets_ && instance_count_ == 0 ) WSACleanup(); windows_sockets_initialized_ = false; @@ -139,10 +139,10 @@ namespace netstream } // ---------------------------------------------------------------------- - void + void NetStreamSocket:: - BailOnNetStreamSocketError( std::string context) - const throw( NetStreamSocketException ) + BailOnNetStreamSocketError( std::string context) + const { #ifdef WIN32 int e = WSAGetLastError(); @@ -154,7 +154,7 @@ namespace netstream } // ---------------------------------------------------------------------- - int + int NetStreamSocket:: port() { @@ -163,10 +163,10 @@ namespace netstream // ---------------------------------------------------------------------- - bool + bool NetStreamSocket:: - datawaiting(int sock) - const throw() + datawaiting(int sock) + const { fd_set fds; FD_ZERO( &fds ); @@ -197,7 +197,7 @@ namespace netstream // First try nnn.nnn.nnn.nnn form saddr.s_addr = inet_addr(address.c_str()); - if (saddr.s_addr != static_cast(-1)) + if (saddr.s_addr != static_cast(-1)) { addr = saddr; return true; @@ -214,10 +214,9 @@ namespace netstream // ---------------------------------------------------------------------- - void + void NetStreamSocket:: accept() - throw( NetStreamSocketException ) { if( socket_ >= 0 ) return; @@ -237,7 +236,7 @@ namespace netstream server_socket_ = static_cast(socket( AF_INET, SOCK_STREAM, 0 )); if( server_socket_ < 0 ) BailOnNetStreamSocketError("netstream::NetStreamSocket::accept() @ socket"); - + //"Address already in use" error protection { int reuseaddr = 1; @@ -279,10 +278,9 @@ namespace netstream } // ---------------------------------------------------------------------- - void + void NetStreamSocket:: - set_blocking(bool blocking) - throw(NetStreamSocketException ) + set_blocking(bool blocking) { blocking_ = blocking; @@ -303,14 +301,13 @@ namespace netstream fcntl(server_socket_, F_SETFL, arg); #endif } - + } // ---------------------------------------------------------------------- - void + void NetStreamSocket:: connect() - throw( NetStreamSocketException ) { in_addr addr; if( !atoaddr( host_.c_str(), addr) ) @@ -338,11 +335,11 @@ namespace netstream } // ---------------------------------------------------------------------- - void + void NetStreamSocket:: close() { - // Close client-connection + // Close client-connection if( socket_ >= 0 ) { #ifdef WIN32 @@ -356,10 +353,9 @@ namespace netstream } // ---------------------------------------------------------------------- - void + void NetStreamSocket:: - send( std::vector b) - throw( NetStreamSocketException ) + send( std::vector b) { if( socket_ < 0 ) return; @@ -371,7 +367,7 @@ namespace netstream buf[i] = b[i]; } - if (verbose_) + if (verbose_) { cerr << "Send " << numbytes << " bytes via netstream::NetStreamSocket: ["; for(size_t i = 0; i < numbytes; ++i) @@ -380,7 +376,6 @@ namespace netstream cerr << " " << (int)b[i] << " "; } cerr << "]" << endl; - cerr.flush(); } unsigned char const *buf_ptr = buf; @@ -404,15 +399,14 @@ namespace netstream delete[] buf; } + - - + // ---------------------------------------------------------------------- void NetStreamSocket:: sendExact( const NetStreamStorage &b) - throw( NetStreamSocketException ) { int length = static_cast(b.size()); NetStreamStorage length_storage; @@ -424,12 +418,11 @@ namespace netstream } - + // ---------------------------------------------------------------------- - vector + vector NetStreamSocket:: receive(int bufSize) - throw( NetStreamSocketException ) { vector b; @@ -455,7 +448,7 @@ namespace netstream b[i] = buf[i]; } - if (verbose_) + if (verbose_) { cerr << "Rcvd " << a << " bytes via netstream::NetStreamSocket: ["; for(int i = 0; i < a; ++i) @@ -470,18 +463,17 @@ namespace netstream } // ---------------------------------------------------------------------- - + bool NetStreamSocket:: receiveExact( NetStreamStorage &msg ) - throw( NetStreamSocketException ) { /* receive length of vector */ unsigned char * const bufLength = new unsigned char[4]; int bytesRead = 0; int readThisTime = 0; - + while (bytesRead<4) { readThisTime = recv( socket_, (char*)(bufLength + bytesRead), 4-bytesRead, 0 ); @@ -502,7 +494,7 @@ namespace netstream unsigned char * const buf = new unsigned char[NN]; bytesRead = 0; readThisTime = 0; - + while (bytesRead= 0; } // ---------------------------------------------------------------------- - bool + bool NetStreamSocket:: - is_blocking() - throw() + is_blocking() { return blocking_; } @@ -561,9 +552,9 @@ namespace netstream #ifdef WIN32 // ---------------------------------------------------------------------- - std::string + std::string NetStreamSocket:: - GetWinsockErrorString(int err) + GetWinsockErrorString(int err) const { diff --git a/graphstream/gs-netstream/c++/src/netstream-socket.h b/graphstream/gs-netstream/c++/src/netstream-socket.h index b1fcc49fa..f2993c716 100644 --- a/graphstream/gs-netstream/c++/src/netstream-socket.h +++ b/graphstream/gs-netstream/c++/src/netstream-socket.h @@ -26,7 +26,7 @@ #endif // Disable exception handling warnings -#if defined(WIN32) && !defined(__MINGW32__) +#ifdef WIN32 #pragma warning( disable : 4290 ) #endif @@ -48,18 +48,18 @@ namespace netstream private: std::string what_; public: - NetStreamSocketException( std::string what ) throw() + NetStreamSocketException( std::string what ) { what_ = what; //std::cerr << "netstream::NetStreamSocketException: " << what << std::endl << std::flush; } - virtual const char* what() const throw() + virtual const char* what() const noexcept { return what_.c_str(); } - ~NetStreamSocketException() throw() {} + ~NetStreamSocketException() {} }; class NetStreamSocket @@ -76,18 +76,18 @@ namespace netstream ~NetStreamSocket(); /// Connects to host_:port_ - void connect() throw( NetStreamSocketException ); + void connect(); /// Wait for a incoming connection to port_ - void accept() throw( NetStreamSocketException ); - void send( const std::vector ) throw( NetStreamSocketException ); - void sendExact( const NetStreamStorage & ) throw( NetStreamSocketException ); - std::vector receive( int bufSize = 2048 ) throw( NetStreamSocketException ); - bool receiveExact( NetStreamStorage &) throw( NetStreamSocketException ); + void accept(); + void send( const std::vector ) ; + void sendExact( const NetStreamStorage & ) ; + std::vector receive( int bufSize = 2048 ) ; + bool receiveExact( NetStreamStorage &) ; void close(); int port(); - void set_blocking(bool) throw( NetStreamSocketException ); - bool is_blocking() throw(); + void set_blocking(bool) ; + bool is_blocking() ; bool has_client_connection() const; // If verbose, each send and received data is written to stderr @@ -96,12 +96,12 @@ namespace netstream private: void init(); - void BailOnNetStreamSocketError( std::string ) const throw( NetStreamSocketException ); + void BailOnNetStreamSocketError( std::string ) const ; #ifdef WIN32 std::string GetWinsockErrorString(int err) const; #endif bool atoaddr(std::string, struct in_addr& addr); - bool datawaiting(int sock) const throw(); + bool datawaiting(int sock) const ; std::string host_; int port_; diff --git a/graphstream/gs-netstream/c++/src/netstream-storage.cpp b/graphstream/gs-netstream/c++/src/netstream-storage.cpp index b684b9159..46934d96b 100644 --- a/graphstream/gs-netstream/c++/src/netstream-storage.cpp +++ b/graphstream/gs-netstream/c++/src/netstream-storage.cpp @@ -18,7 +18,6 @@ #include #include #include -#include using namespace std; @@ -35,11 +34,11 @@ namespace netstream // ---------------------------------------------------------------------- - NetStreamStorage::NetStreamStorage(unsigned char packet[], size_t length) + NetStreamStorage::NetStreamStorage(unsigned char packet[], int length) { store.reserve(length); // Get the content - for(size_t i = 0; i < length; ++i) store.push_back(packet[i]); + for(int i = 0; i < length; ++i) store.push_back(packet[i]); init(); } @@ -91,7 +90,7 @@ namespace netstream * Reads a char form the array * @return The read char (between 0 and 255) */ - unsigned char NetStreamStorage::readChar() throw(std::invalid_argument) + unsigned char NetStreamStorage::readChar() { if ( !valid_pos() ) { @@ -105,19 +104,88 @@ namespace netstream /** * */ - void NetStreamStorage::writeChar(unsigned char value) throw() + void NetStreamStorage::writeChar(unsigned char value) { store.push_back(value); iter_ = store.begin(); } + + size_t NetStreamStorage::varintSize(uint_fast64_t data){ + // 7 bits -> 127 + if(data < (1L << 7)){return 1;} + // 14 bits -> 16383 + if(data < (1L << 14)){return 2;} + // 21 bits -> 2097151 + if(data < (1L << 21)){return 3;} + // 28 bits -> 268435455 + if(data < (1L << 28)){return 4;} + // 35 bits -> 34359738367 + if(data < (1L << 35)){return 5;} + // 42 bits -> 4398046511103 + if(data < (1L << 42)){return 6;} + // 49 bits -> 562949953421311 + if(data < (1L << 49)){return 7;} + // 56 bits -> 72057594037927935 + if(data < (1L << 56)){return 8;} + return 9; + } + + + // ---------------------------------------------------------------------- + /** + * Reads a varint form the array + * @return The read varint + */ + int_fast64_t NetStreamStorage::readVarint() + { + uint_fast64_t number = readUnsignedVarint(); + return (int_fast64_t)((number & 1) == 0) ? number >> 1 : -(number >> 1); + } + // ---------------------------------------------------------------------- + /** + * + */ + void NetStreamStorage::writeVarint(int_fast64_t value) + { + writeUnsignedVarint((value << 1) ^ (value >> 63)); + } + // ---------------------------------------------------------------------- + /** + * Reads a unsigned varint form the array + * @return The read u_varint + */ + uint_fast64_t NetStreamStorage::readUnsignedVarint() + { + // TODO + return 0; + } + // ---------------------------------------------------------------------- + /** + * + */ + void NetStreamStorage::writeUnsignedVarint(uint_fast64_t value) + { + size_t size = varintSize(value); + + unsigned char buffer[size]; + for(int i = 0; i < size; i++){ + int head=128; + if(i==size-1) head = 0; + long b = ((value >> (7*i)) & 127) ^ head; + buffer[size-1-i] = ((unsigned char)(b & 255 )); + } + writeByEndianess(buffer, size); + } + + // ---------------------------------------------------------------------- /** * Reads a byte form the array * @return The read byte (between -128 and 127) */ - int NetStreamStorage::readByte() throw(std::invalid_argument) + int NetStreamStorage::readByte() { int i = static_cast(readChar()); if (i < 128) return i; @@ -129,7 +197,7 @@ namespace netstream /** * */ - void NetStreamStorage::writeByte(int value) throw(std::invalid_argument) + void NetStreamStorage::writeByte(int value) { if (value < -128 || value > 127) { @@ -144,16 +212,17 @@ namespace netstream * Reads an unsigned byte form the array * @return The read byte (between 0 and 255) */ - int NetStreamStorage::readUnsignedByte() throw(std::invalid_argument) + int NetStreamStorage::readUnsignedByte() { return static_cast(readChar()); } + // ---------------------------------------------------------------------- /** * */ - void NetStreamStorage::writeUnsignedByte(int value) throw(std::invalid_argument) + void NetStreamStorage::writeUnsignedByte(int value) { if (value < 0 || value > 255) { @@ -168,14 +237,14 @@ namespace netstream * Reads a string form the array * @return The read string */ - std::string NetStreamStorage::readString() throw(std::invalid_argument) + std::string NetStreamStorage::readString() { int len = readInt(); checkReadSafe(len); - StorageType::const_iterator e = iter_; - std::advance(e, len); - const string tmp(iter_, e); - iter_ = e; + StorageType::const_iterator end = iter_; + std::advance(end, len); + const string tmp(iter_, end); + iter_ = end; return tmp; } @@ -185,10 +254,9 @@ namespace netstream * Writes a string into the array; * @param s The string to be written */ - void NetStreamStorage::writeString(const std::string &s) throw() + void NetStreamStorage::writeString(const std::string &s) { - writeUnsignedVarInt(static_cast(s.length())); - + writeUnsignedVarint(static_cast(s.length())); store.insert(store.end(), s.begin(), s.end()); iter_ = store.begin(); } @@ -199,7 +267,7 @@ namespace netstream * Reads a string list form the array * @return The read string */ - std::vector NetStreamStorage::readStringList() throw(std::invalid_argument) + std::vector NetStreamStorage::readStringList() { std::vector tmp; const int len = readInt(); @@ -217,9 +285,9 @@ namespace netstream * Writes a string into the array; * @param s The string to be written */ - void NetStreamStorage::writeStringList(const std::vector &s) throw() + void NetStreamStorage::writeStringList(const std::vector &s) { - writeInt(static_cast(s.size())); + writeUnsignedVarint(s.size()); for (std::vector::const_iterator it = s.begin(); it!=s.end() ; it++) { writeString(*it); @@ -235,7 +303,7 @@ namespace netstream * * @return the unspoiled integer value (between -32768 and 32767) */ - int NetStreamStorage::readShort() throw(std::invalid_argument) + int NetStreamStorage::readShort() { short value = 0; unsigned char *p_value = reinterpret_cast(&value); @@ -245,7 +313,7 @@ namespace netstream // ---------------------------------------------------------------------- - void NetStreamStorage::writeShort( int value ) throw(std::invalid_argument) + void NetStreamStorage::writeShort( int value ) { if (value < -32768 || value > 32767) { @@ -255,6 +323,7 @@ namespace netstream short svalue = static_cast(value); unsigned char *p_svalue = reinterpret_cast(&svalue); writeByEndianess(p_svalue, 2); + } @@ -266,20 +335,20 @@ namespace netstream * * @return the unspoiled integer value (between -2.147.483.648 and 2.147.483.647) */ - GS_INT NetStreamStorage::readInt() throw(std::invalid_argument) + int NetStreamStorage::readInt() { - GS_INT value = 0; + int value = 0; unsigned char *p_value = reinterpret_cast(&value); - readByEndianess(p_value, sizeof(GS_INT)); + readByEndianess(p_value, 4); return value; } // ---------------------------------------------------------------------- - void NetStreamStorage::writeInt( int value ) throw() + void NetStreamStorage::writeInt( int value ) { unsigned char *p_value = reinterpret_cast(&value); - writeByEndianess(p_value, sizeof(GS_INT)); + writeByEndianess(p_value, 4); } // ---------------------------------------------------------------------- @@ -290,20 +359,20 @@ namespace netstream * * @return the unspoiled integer value (between -??? and ???) */ - GS_LONG NetStreamStorage::readLong() throw(std::invalid_argument) + long NetStreamStorage::readLong() { - GS_LONG value = (GS_LONG)0L; + long value = 0L; unsigned char *p_value = reinterpret_cast(&value); - readByEndianess(p_value, sizeof(GS_LONG)); + readByEndianess(p_value, 8); return value; } // ---------------------------------------------------------------------- - void NetStreamStorage::writeLong( GS_LONG value ) throw() + void NetStreamStorage::writeLong( long value ) { unsigned char *p_value = reinterpret_cast(&value); - writeByEndianess(p_value, sizeof(GS_LONG)); + writeByEndianess(p_value, 8); } @@ -315,37 +384,37 @@ namespace netstream * * @return the unspoiled float value */ - GS_FLOAT NetStreamStorage::readFloat() throw(std::invalid_argument) + float NetStreamStorage::readFloat() { - GS_FLOAT value = 0; + float value = 0; unsigned char *p_value = reinterpret_cast(&value); - readByEndianess(p_value, sizeof(GS_FLOAT)); + readByEndianess(p_value, 4); return value; } // ---------------------------------------------------------------------- - void NetStreamStorage::writeFloat( GS_FLOAT value ) throw() + void NetStreamStorage::writeFloat( float value ) { unsigned char *p_value = reinterpret_cast(&value); - writeByEndianess(p_value, sizeof(GS_FLOAT)); + writeByEndianess(p_value, 4); } // ---------------------------------------------------------------------- - void NetStreamStorage::writeDouble( GS_DOUBLE value ) throw () + void NetStreamStorage::writeDouble( double value ) { unsigned char *p_value = reinterpret_cast(&value); - writeByEndianess(p_value, sizeof(GS_DOUBLE)); + writeByEndianess(p_value, 8); } // ---------------------------------------------------------------------- - GS_DOUBLE NetStreamStorage::readDouble( ) throw (std::invalid_argument) + double NetStreamStorage::readDouble( ) { - GS_DOUBLE value = 0; + double value = 0; unsigned char *p_value = reinterpret_cast(&value); - readByEndianess(p_value, sizeof(GS_DOUBLE)); + readByEndianess(p_value, 8); return value; } @@ -368,7 +437,7 @@ namespace netstream // ---------------------------------------------------------------------- - void NetStreamStorage::checkReadSafe(unsigned int num) const throw(std::invalid_argument) + void NetStreamStorage::checkReadSafe(unsigned int num) const { if (std::distance(iter_, store.end()) < static_cast(num)) { @@ -390,29 +459,29 @@ namespace netstream // ---------------------------------------------------------------------- - void NetStreamStorage::writeByEndianess(const unsigned char * b, unsigned int sz) + void NetStreamStorage::writeByEndianess(const unsigned char * begin, unsigned int size) { - const unsigned char * e = &(b[sz]); + const unsigned char * end = &(begin[size]); if (bigEndian_) - store.insert(store.end(), b, e); + store.insert(store.end(), begin, end); else - store.insert(store.end(), std::reverse_iterator(e), std::reverse_iterator(b)); + store.insert(store.end(), std::reverse_iterator(end), std::reverse_iterator(begin)); iter_ = store.begin(); } // ---------------------------------------------------------------------- - void NetStreamStorage::readByEndianess(unsigned char * array, int sz) + void NetStreamStorage::readByEndianess(unsigned char * array, int size) { - checkReadSafe(sz); + checkReadSafe(size); if (bigEndian_) { - for (int i = 0; i < sz; ++i) + for (int i = 0; i < size; ++i) array[i] = readCharUnsafe(); } else { - for (int i = sz - 1; i >= 0; --i) + for (int i = size - 1; i >= 0; --i) array[i] = readCharUnsafe(); } } @@ -430,7 +499,7 @@ namespace netstream ostream &operator<<( ostream &out, const NetStreamStorage & s) { - out< 127 - if(data < ((GS_LONG)1L << 7)){ - return 1; - } - - // 14 bits -> 16383 - if(data < ((GS_LONG)1L << 14)){ - return 2; - } - - // 21 bits -> 2097151 - if(data < ((GS_LONG)1L << 21)){ - return 3; - } - - // 28 bits -> 268435455 - if(data < ((GS_LONG)1L << 28)){ - return 4; - } - - // 35 bits -> 34359738367 - if(data < ((GS_LONG)1L << 35)){ - return 5; - } - - // 42 bits -> 4398046511103 - if(data < ((GS_LONG)1L << 42)){ - return 6; - } - - // 49 bits -> 562949953421311 - if(data < ((GS_LONG)1L << 49)){ - return 7; - } - - // 56 bits -> 72057594037927935 - if(data < ((GS_LONG)1L << 56)){ - return 8; - } - - return 9; -} - - -// ---------------------------------------------------------------------- -void NetStreamStorage::writeUnsignedVarInt( GS_LONG data ) throw() -{ - int sz = varintSize(data); - unsigned char *p_value = (unsigned char*)malloc(sz); - for(int i = 0; i < sz; i++){ - int head=128; - if(i==sz-1) head = 0; - GS_LONG b = ((data >> (7*i)) & 127) ^ head; - p_value[sz-1-i] = ((unsigned char)(b & 255)); - } - writeByEndianess(p_value, sz); - // free(p_value); -} - - -/* - protected ByteBuffer encodeUnsignedVarint(Object in) { - long data = ((Number)in).longValue(); - - int size = varintSize(data); - - ByteBuffer buff = ByteBuffer.allocate(size); - for(int i = 0; i < size; i++){ - int head=128; - if(i==size-1) head = 0; - long b = ((data >> (7*i)) & 127) ^ head; - buff.put((byte)(b & 255 )); - } - buff.rewind(); - return buff; - } - - - private void putVarint(ByteBuffer buffer, long number, int byteSize) { - for(int i = 0; i < byteSize; i++){ - int head=128; - if(i==byteSize-1) head = 0; - long b = ((number >> (7*i)) & 127) ^ head; - buffer.put((byte)(b & 255 )); - } - } -*/ } diff --git a/graphstream/gs-netstream/c++/src/netstream-storage.h b/graphstream/gs-netstream/c++/src/netstream-storage.h index ed4912a6e..c20fcbaa3 100644 --- a/graphstream/gs-netstream/c++/src/netstream-storage.h +++ b/graphstream/gs-netstream/c++/src/netstream-storage.h @@ -17,7 +17,7 @@ #include #include #include -#include "netstream-sizes.h" +#include namespace netstream { @@ -41,7 +41,7 @@ class NetStreamStorage void init(); /// Check if the next \p num bytes can be read safely - void checkReadSafe(unsigned int num) const throw(std::invalid_argument); + void checkReadSafe(unsigned int num) const; /// Read a byte \em without validity check unsigned char readCharUnsafe(); /// Write \p size elements of array \p begin according to endianess @@ -56,8 +56,8 @@ class NetStreamStorage /// Standard Constructor NetStreamStorage(); - /// Constructor, that fills the storage with an char array. - NetStreamStorage(unsigned char[], size_t length); + /// Constructor, that fills the storage with an char array. If length is -1, the whole array is handed over + NetStreamStorage(unsigned char[], int length=-1); // Destructor virtual ~NetStreamStorage(); @@ -67,45 +67,49 @@ class NetStreamStorage void reset(); - virtual unsigned char readChar() throw(std::invalid_argument); - virtual void writeChar(unsigned char) throw(); + virtual size_t varintSize(uint_fast64_t); + virtual uint_fast64_t readUnsignedVarint() ; + virtual void writeUnsignedVarint(uint_fast64_t) ; - virtual GS_INT readByte() throw(std::invalid_argument); - virtual void writeByte(GS_INT) throw(std::invalid_argument); -// virtual void writeByte(unsigned char) throw(); + virtual int_fast64_t readVarint() ; + virtual void writeVarint(int_fast64_t) ; - virtual int readUnsignedByte() throw(std::invalid_argument); - virtual void writeUnsignedByte(int) throw(std::invalid_argument); + virtual unsigned char readChar() ; + virtual void writeChar(unsigned char) ; - virtual std::string readString() throw(std::invalid_argument); - virtual void writeString(const std::string& s) throw(); + virtual int readByte() ; + virtual void writeByte(int) ; +// virtual void writeByte(unsigned char) ; - virtual std::vector readStringList() throw(std::invalid_argument); - virtual void writeStringList(const std::vector &s) throw(); + virtual int readUnsignedByte() ; + virtual void writeUnsignedByte(int) ; - virtual GS_INT readShort() throw(std::invalid_argument); - virtual void writeShort(GS_INT) throw(std::invalid_argument); + virtual std::string readString() ; + virtual void writeString(const std::string& s) ; - virtual GS_INT readInt() throw(std::invalid_argument); - virtual void writeInt(GS_INT) throw(); + virtual std::vector readStringList() ; + virtual void writeStringList(const std::vector &s) ; - GS_INT varintSize(GS_LONG data); - virtual void writeUnsignedVarInt(GS_LONG data) throw(); + virtual int readShort() ; + virtual void writeShort(int) ; - virtual GS_LONG readLong() throw(std::invalid_argument); - virtual void writeLong(GS_LONG) throw(); + virtual int readInt() ; + virtual void writeInt(int) ; - virtual GS_FLOAT readFloat() throw(std::invalid_argument); - virtual void writeFloat( GS_FLOAT ) throw(); + virtual long readLong() ; + virtual void writeLong(long) ; - virtual GS_DOUBLE readDouble() throw(std::invalid_argument); - virtual void writeDouble( GS_DOUBLE ) throw(); + virtual float readFloat() ; + virtual void writeFloat( float ) ; + + virtual double readDouble() ; + virtual void writeDouble( double ) ; virtual void writePacket(unsigned char* packet, int length); virtual void writeStorage(netstream::NetStreamStorage& store); - virtual NetStreamStorage operator+(const NetStreamStorage & storage); + virtual NetStreamStorage operator+(const NetStreamStorage & storage); // Some enabled functions of the underlying std::list From 7569a3949dc52ea4d859fa4e382529148c93010f Mon Sep 17 00:00:00 2001 From: John Pye Date: Mon, 6 Dec 2021 23:07:13 +1100 Subject: [PATCH 02/12] updated gc-8.0.6 --- gc/AUTHORS | 19 + gc/BCC_MAKEFILE | 6 +- gc/CMakeLists.txt | 814 +++++++----------------- gc/ChangeLog | 363 ++++++++++- gc/Makefile.am | 52 +- gc/Makefile.direct | 24 +- gc/NT_MAKEFILE | 10 +- gc/OS2_MAKEFILE | 6 +- gc/README.QUICK | 2 +- gc/README.md | 24 +- gc/SMakefile.amiga | 8 +- gc/WCC_MAKEFILE | 5 +- gc/allchblk.c | 108 +++- gc/alloc.c | 28 +- gc/backgraph.c | 7 +- gc/bdw-gc.pc.in | 2 +- gc/blacklst.c | 3 +- gc/build/s60v3/libgc.mmp | 2 + gc/configure.ac | 225 ++++--- gc/cord/cord.am | 10 +- gc/cord/cordbscs.c | 33 +- gc/cord/cordprnt.c | 22 +- gc/cord/tests/cordtest.c | 18 +- gc/cord/tests/de.c | 1 + gc/cord/tests/de_win.c | 15 +- gc/darwin_stop_world.c | 13 +- gc/dbg_mlc.c | 2 +- gc/digimars.mak | 3 +- gc/doc/README.OS2 | 2 +- gc/doc/README.amiga | 20 +- gc/doc/README.cmake | 2 +- gc/doc/README.darwin | 67 +- gc/doc/README.ews4800 | 2 +- gc/doc/README.macros | 15 +- gc/doc/README.solaris2 | 2 +- gc/doc/README.win32 | 2 +- gc/doc/finalization.md | 8 +- gc/doc/gcdescr.md | 27 +- gc/doc/gcinterface.md | 22 +- gc/doc/leak.md | 57 +- gc/doc/overview.md | 12 +- gc/doc/porting.md | 15 +- gc/doc/scale.md | 10 +- gc/doc/simple_example.md | 3 +- gc/dyn_load.c | 12 +- gc/extra/msvc_dbg.c | 36 +- gc/extra/pcr_interface.c | 2 + gc/finalize.c | 10 +- gc/fnlz_mlc.c | 8 +- gc/gc.mak | 10 +- gc/gc_cpp.cc | 42 +- gc/headers.c | 35 +- gc/include/ec.h | 4 +- gc/include/gc.h | 71 +-- gc/include/gc_allocator.h | 5 +- gc/include/gc_config_macros.h | 19 +- gc/include/gc_cpp.h | 35 +- gc/include/gc_disclaim.h | 3 + gc/include/gc_pthread_redirects.h | 5 + gc/include/gc_typed.h | 5 +- gc/include/gc_version.h | 2 +- gc/include/include.am | 3 - gc/include/javaxfc.h | 5 + gc/include/new_gc_alloc.h | 16 +- gc/include/private/dbg_mlc.h | 12 +- gc/include/private/gc_atomic_ops.h | 7 +- gc/include/private/gc_hdrs.h | 2 +- gc/include/private/gc_locks.h | 6 +- gc/include/private/gc_pmark.h | 16 +- gc/include/private/gc_priv.h | 129 ++-- gc/include/private/gcconfig.h | 532 +++++++++------- gc/include/private/pthread_support.h | 2 +- gc/include/private/specific.h | 5 + gc/include/private/thread_local_alloc.h | 2 +- gc/mach_dep.c | 8 +- gc/mallocx.c | 8 +- gc/mark.c | 51 +- gc/mark_rts.c | 7 +- gc/misc.c | 135 ++-- gc/new_hblk.c | 2 +- gc/os_dep.c | 313 +++++---- gc/pthread_stop_world.c | 63 +- gc/pthread_support.c | 123 ++-- gc/reclaim.c | 55 +- gc/specific.c | 6 +- gc/tests/disclaim_bench.c | 2 + gc/tests/disclaim_test.c | 4 +- gc/tests/disclaim_weakmap_test.c | 472 ++++++++++++++ gc/tests/initsecondarythread.c | 2 + gc/tests/middle.c | 2 + gc/tests/realloc_test.c | 2 + gc/tests/smash_test.c | 15 +- gc/tests/staticrootstest.c | 2 + gc/tests/subthread_create.c | 2 +- gc/tests/test.c | 29 +- gc/tests/test_cpp.cc | 23 +- gc/tests/tests.am | 27 +- gc/tests/threadkey_test.c | 4 +- gc/tests/trace_test.c | 3 + gc/win32_threads.c | 328 ++++++++-- 100 files changed, 3053 insertions(+), 1767 deletions(-) create mode 100644 gc/tests/disclaim_weakmap_test.c diff --git a/gc/AUTHORS b/gc/AUTHORS index 1c453ef2c..a5a4fb208 100644 --- a/gc/AUTHORS +++ b/gc/AUTHORS @@ -28,6 +28,7 @@ Akira Tagoh Alain Novak Alan Dosser Alan J. Demers +Alaskan Emily Aleksey Demakov Alessandro Bruni Alex Ronne Petersen @@ -102,8 +103,10 @@ Chris Metcalf Christian Joensson Christian Limpach Christian Thalinger +Christian Weisgerber Christoffe Raffali Clay Spence +Clement Chigot Colin LeMahieu Craig McDaniel Dai Sato @@ -135,6 +138,7 @@ Davide Angelocola Demyan Kimitsa Dick Porter Dietmar Planitzer +Dima Pasechnik Dimitris Vyzovitis Dimitry Andric Djamel Magri @@ -149,6 +153,7 @@ Eric Benson Eric Holk Erik M. Bray Fabian Thylman +Fabrice Fontaine Fergus Henderson Franklin Chen Fred Gilham @@ -181,6 +186,7 @@ Ian Searle Igor Khavkine Ivan Demakov Ivan Maidanski +Ivan R Jaap Boender Jack Andrews Jacob Navia @@ -191,6 +197,7 @@ Jan Alexander Steffens Jan Wielemaker Jani Kajala Jared McNeill +Jasper Lievisse Adriaanse Jay Krell Jean-Baptiste Nivois Jean-Claude Beaudoin @@ -213,10 +220,12 @@ Johannes Schmidt Johannes Totz John Bowman John Clements +John David Anglin John Ellis John Merryweather Cooper Jon Moore Jonas Echterhoff +Jonas Hahnfeld Jonathan Bachrach Jonathan Chambers Jonathan Clark @@ -253,6 +262,7 @@ Louis Zhuang Lucas Meijer Ludovic Courtes Maarten Thibaut +Mahder Gebremedhin Manuel A. Fernandez Montecelo Manuel Serrano Marc Recht @@ -269,6 +279,7 @@ Mark Weiser Martin Hirzel Martin Koeppe Martin Tauchmann +Massimiliano Gubinelli Matt Austern Matthew Flatt Matthias Andree @@ -296,6 +307,7 @@ Neale Ferguson Neil Sharman Nicolas Cannasse Niibe Yutaka +Nikita Ermakov Niklas Therning Noah Lavine Nobuyuki Hikichi @@ -312,6 +324,7 @@ Paul Graham Paul Nash Per Bothner Peter Bigot +Peter Budai Peter Chubb Peter Colson Peter Housel @@ -342,6 +355,7 @@ Reza Shahidi Richard Earnshaw Richard Henderson Richard Sandiford +Richard Zidlicky Rob Haack Robert Brazile Rodrigo Kumpera @@ -364,6 +378,7 @@ Shiro Kawai Simon Gornall Simon Posnjak Slava Sysoltsev +Sorawee Porncharoenwase Stefan Ring Stefano Rivera Sugioka Toshinobu @@ -380,9 +395,11 @@ Thomas Klausner Thomas Linder Puls Thomas Maier Thomas Schwinge +Thomas Thiriez Thorsten Glaser Tilman Vogel Tim Bingham +Tim Gates Timothy N. Newsham Tom Tromey Tommaso Tagliapietra @@ -397,12 +414,14 @@ Ulrich Weigand Uros Bizjak Vernon Lee Victor Ivrii +Victor Romero Vitaly Magerya Vladimir Tsichevski Walter Bright Walter Underwood Wilson Ho Wink Saville +Wookey Xi Wang Xiaokun Zhu Yann Dirson diff --git a/gc/BCC_MAKEFILE b/gc/BCC_MAKEFILE index 10ac184a0..f6398c1dd 100644 --- a/gc/BCC_MAKEFILE +++ b/gc/BCC_MAKEFILE @@ -13,7 +13,9 @@ lib= $(bcbin)\tlib link= $(bcbin)\ilink32 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 -DENABLE_DISCLAIM -DGC_OPERATOR_NEW_ARRAY +defines= -DALL_INTERIOR_POINTERS -DNO_EXECUTE_PERMISSION \ + -DENABLE_DISCLAIM -DGC_ATOMIC_UNCOLLECTABLE -DJAVA_FINALIZATION \ + -DGC_GCJ_SUPPORT -DGC_OPERATOR_NEW_ARRAY -DUSE_MUNMAP .c.obj: $(cc) @&&| @@ -33,7 +35,7 @@ XXXOBJS= XXXalloc.obj XXXreclaim.obj XXXallchblk.obj XXXmisc.obj \ XXXobj_map.obj XXXblacklst.obj XXXfinalize.obj XXXnew_hblk.obj \ XXXdbg_mlc.obj XXXmalloc.obj XXXdyn_load.obj \ XXXtypd_mlc.obj XXXptr_chck.obj XXXgc_cpp.obj XXXmallocx.obj \ - XXXfnlz_mlc.obj + XXXfnlz_mlc.obj XXXgcj_mlc.obj OBJS= $(XXXOBJS:XXX=) diff --git a/gc/CMakeLists.txt b/gc/CMakeLists.txt index 697c5c053..c8ebd9b04 100644 --- a/gc/CMakeLists.txt +++ b/gc/CMakeLists.txt @@ -21,592 +21,232 @@ # this will generate gc.sln # -cmake_minimum_required(VERSION 3.1) - -option(enable_cplusplus "C++ support" OFF) -if (enable_cplusplus) - project(gc) -else() - project(gc C) -endif() - -include(CheckCCompilerFlag) -include(CheckCSourceCompiles) -include(CheckFunctionExists) -include(CheckIncludeFile) -include(CheckSymbolExists) -include(CTest) - -# Customize the build by passing "-D=ON|OFF" in the command line. -option(GC_BUILD_SHARED_LIBS "Build shared libraries" ON) -option(build_cord "Build cord library" ON) -option(build_tests "Build tests" OFF) -option(enable_threads "Support threads" ON) -option(enable_parallel_mark "Parallelize marking and free list construction" ON) -option(enable_thread_local_alloc "Turn on thread-local allocation optimization" ON) -option(enable_threads_discovery "Enable threads discovery in GC" ON) -option(enable_throw_bad_alloc_library "Turn on C++ gctba library build" ON) -option(enable_gcj_support "Support for gcj" ON) -option(enable_sigrt_signals "Use SIGRTMIN-based signals for thread suspend/resume" OFF) -option(enable_gc_debug "Support for pointer back-tracing" OFF) -option(disable_gc_debug "Disable debugging like GC_dump and its callees" OFF) -option(enable_java_finalization "Support for java finalization" ON) -option(enable_atomic_uncollectable "Support for atomic uncollectible allocation" ON) -option(enable_redirect_malloc "Redirect malloc and friends to GC routines" OFF) -option(enable_disclaim "Support alternative finalization interface" ON) -option(enable_large_config "Optimize for large heap or root set" OFF) -option(enable_gc_assertions "Enable collector-internal assertion checking" OFF) -option(enable_mmap "Use mmap instead of sbrk to expand the heap" OFF) -option(enable_munmap "Return page to the OS if empty for N collections" ON) -option(enable_dynamic_loading "Enable tracing of dynamic library data roots" ON) -option(enable_register_main_static_data "Perform the initial guess of data root sets" ON) -option(enable_checksums "Report erroneously cleared dirty bits" OFF) -option(enable_werror "Pass -Werror to the C compiler (treat warnings as errors)" OFF) -option(enable_single_obj_compilation "Compile all libgc source files into single .o" OFF) -option(enable_handle_fork "Attempt to ensure a usable collector after fork()" ON) -option(disable_handle_fork "Prohibit installation of pthread_atfork() handlers" OFF) -option(install_headers "Install header files" ON) - -add_definitions("-DALL_INTERIOR_POINTERS -DNO_EXECUTE_PERMISSION") - -if(GC_BUILD_SHARED_LIBS) - set(GC_LIBRARY_BUILD_TYPE SHARED) -else(GC_BUILD_SHARED_LIBS) - set(GC_LIBRARY_BUILD_TYPE STATIC) -endif(GC_BUILD_SHARED_LIBS) - -# Set struct packing alignment to word (instead of 1-byte). -if (BORLAND) - add_compile_options(/a4) -elseif (WATCOM) - add_compile_options(/zp4) -endif() - -# Output all warnings. -if (BORLAND) - # All warnings except for particular ones. - add_compile_options(/w /w-pro /w-aus /w-par /w-ccc /w-inl /w-rch) -elseif (MSVC) - # All warnings but ignoring "unreferenced formal parameter" and - # "conditional expression is constant" ones. - add_compile_options(/W4 /wd4100 /wd4127) - # Disable crt security warnings, since unfortunately they warn about all - # sorts of safe uses of strncpy. - add_definitions("-D_CRT_SECURE_NO_DEPRECATE") -elseif (WATCOM) - add_compile_options(/wx) -else() - # TODO add -[W]pedantic -Wno-long-long - add_compile_options(-Wall -Wextra) -endif() - -include_directories(include) - -set(SRC alloc.c reclaim.c allchblk.c misc.c mach_dep.c os_dep.c +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 + -DALL_INTERIOR_POINTERS -DNO_EXECUTE_PERMISSION") + +#LIBATOMIC #TODO +#ADD_LIBRARY(atomic_ops STATIC ) +#SET_TARGET_PROPERTIES(atomic_ops PROPERTIES COMPILE_FLAGS -DNO_DEBUGGING) + + +#LIBGC + +INCLUDE_DIRECTORIES(include) +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 dyn_load.c typd_mlc.c ptr_chck.c - mallocx.c gc_dlopen.c) -set(THREADDLLIBS) - -set(_HOST ${CMAKE_SYSTEM_PROCESSOR}-unknown-${CMAKE_SYSTEM}) -string(TOLOWER ${_HOST} HOST) -message(STATUS "TARGET = ${HOST}") - -if (enable_threads) - find_package(Threads REQUIRED) - message(STATUS "Thread library: ${CMAKE_THREAD_LIBS_INIT}") - include_directories(libatomic_ops/src) - include_directories(${Threads_INCLUDE_DIR}) - set(THREADDLLIBS ${CMAKE_THREAD_LIBS_INIT}) - if (NOT (APPLE OR CYGWIN OR MSYS OR WIN32 OR HOST MATCHES mips-.*-irix6.*)) - set(THREADDLLIBS ${THREADDLLIBS} -ldl) - # The predefined CMAKE_DL_LIBS may be broken. - endif() -endif(enable_threads) - -# Thread support detection. -if (CMAKE_USE_PTHREADS_INIT) - set(SRC ${SRC} pthread_start.c pthread_support.c pthread_stop_world.c) - if (HOST MATCHES .*-.*-hpux10.*) - message(FATAL_ERROR "HP/UX 10 POSIX threads are not supported.") - endif() - # Assume the compiler supports C11 (GCC) atomic intrinsics. - add_definitions("-DGC_BUILTIN_ATOMIC") - # Common defines for POSIX platforms. - add_definitions("-DGC_THREADS -D_REENTRANT") - if (enable_parallel_mark) - add_definitions("-DPARALLEL_MARK") - endif() - if (enable_thread_local_alloc) - add_definitions("-DTHREAD_LOCAL_ALLOC") - set(SRC ${SRC} thread_local_alloc.c) - endif() - message("Explicit GC_INIT() calls may be required.") - if (HOST MATCHES .*-.*-hpux11.*) - message("Only HP/UX 11 POSIX threads are supported.") - add_definitions("-D_POSIX_C_SOURCE=199506L") - elseif (HOST MATCHES .*-.*-netbsd.*) - message("Only on NetBSD 2.0 or later.") - add_definitions("-D_PTHREADS") - endif() - if (ANDROID OR MSYS) # ANDROID variable is defined by CMake v3.7.0+. - # Android NDK does not provide pthread_atfork. - elseif (APPLE) - if (enable_handle_fork AND NOT disable_handle_fork) - # The incremental mode conflicts with fork handling. - if (enable_parallel_mark) - add_definitions("-DHANDLE_FORK") - endif(enable_parallel_mark) - endif() - set(SRC ${SRC} darwin_stop_world.c) - elseif (enable_handle_fork AND NOT disable_handle_fork) - add_definitions("-DHANDLE_FORK") - endif() - if (enable_sigrt_signals) - add_definitions("-DGC_USESIGRT_SIGNALS") - endif() - if (CYGWIN OR MSYS) - set(SRC ${SRC} win32_threads.c) - endif() -elseif (CMAKE_USE_WIN32_THREADS_INIT) - add_definitions("-DGC_THREADS") - if (enable_parallel_mark) - add_definitions("-DPARALLEL_MARK") - endif() - if (enable_thread_local_alloc AND (enable_parallel_mark OR NOT GC_BUILD_SHARED_LIBS)) - # Imply THREAD_LOCAL_ALLOC unless GC_DLL. - add_definitions("-DTHREAD_LOCAL_ALLOC") - set(SRC ${SRC} thread_local_alloc.c) - endif() - add_definitions("-DEMPTY_GETENV_RESULTS") - set(SRC ${SRC} win32_threads.c) -elseif (CMAKE_HP_PTHREADS_INIT OR CMAKE_USE_SPROC_INIT) - message(FATAL_ERROR "Unsupported thread package") -endif() - -if (disable_handle_fork) - add_definitions("-DNO_HANDLE_FORK") -endif() - -if (enable_gcj_support) - add_definitions("-DGC_GCJ_SUPPORT") - if (enable_threads AND NOT (enable_thread_local_alloc AND HOST MATCHES .*-.*-kfreebsd.*-gnu)) - # FIXME: For a reason, gctest hangs up on kFreeBSD if both of - # THREAD_LOCAL_ALLOC and GC_ENABLE_SUSPEND_THREAD are defined. - add_definitions("-DGC_ENABLE_SUSPEND_THREAD") - endif() - set(SRC ${SRC} gcj_mlc.c) -endif(enable_gcj_support) - -if (enable_disclaim) - add_definitions("-DENABLE_DISCLAIM") - set(SRC ${SRC} fnlz_mlc.c) -endif() - -if (enable_java_finalization) - add_definitions("-DJAVA_FINALIZATION") -endif() - -if (enable_atomic_uncollectable) - add_definitions("-DGC_ATOMIC_UNCOLLECTABLE") -endif() - -if (enable_gc_debug) - add_definitions("-DDBG_HDRS_ALL -DKEEP_BACK_PTRS") - if (HOST MATCHES i.86-.*-dgux.*|ia64-.*-linux.*|i586-.*-linux.*|i686-.*-linux.*|x86-.*-linux.*|x86_64-.*-linux.*) - add_definitions("-DMAKE_BACK_GRAPH") - if (HOST MATCHES .*-.*-.*linux.*) - add_definitions("-DSAVE_CALL_COUNT=8") - endif() - set(SRC ${SRC} backgraph.c) - endif() -endif(enable_gc_debug) - -if (disable_gc_debug) - add_definitions("-DNO_DEBUGGING") -elseif (WINCE) - # Read environment variables from ".gc.env" file. - add_definitions("-DGC_READ_ENV_FILE") -endif() - -if (enable_redirect_malloc) - if (enable_gc_debug) - add_definitions("-DREDIRECT_MALLOC=GC_debug_malloc_replacement") - add_definitions("-DREDIRECT_REALLOC=GC_debug_realloc_replacement") - add_definitions("-DREDIRECT_FREE=GC_debug_free") - else() - add_definitions("-DREDIRECT_MALLOC=GC_malloc") - endif() - add_definitions("-DGC_USE_DLOPEN_WRAP") -endif(enable_redirect_malloc) - -if (enable_munmap) - add_definitions("-DUSE_MMAP -DUSE_MUNMAP") -elseif (enable_mmap) - add_definitions("-DUSE_MMAP") -endif() - -if (NOT enable_dynamic_loading) - add_definitions("-DIGNORE_DYNAMIC_LOADING") -endif() - -if (NOT enable_register_main_static_data) - add_definitions("-DGC_DONT_REGISTER_MAIN_STATIC_DATA") -endif() - -if (enable_large_config) - add_definitions("-DLARGE_CONFIG") -endif() - -if (enable_gc_assertions) - add_definitions("-DGC_ASSERTIONS") -endif() - -if (NOT enable_threads_discovery) - add_definitions("-DGC_NO_THREADS_DISCOVERY") -endif() - -if (enable_checksums) - if (enable_munmap OR enable_threads) - message(FATAL_ERROR "CHECKSUMS not compatible with USE_MUNMAP or threads") - endif() - add_definitions("-DCHECKSUMS") - set(SRC ${SRC} checksums.c) -endif(enable_checksums) - -if (enable_werror) - if (BORLAND) - add_compile_options(/w!) - elseif (MSVC) - add_compile_options(/WX) - # Workaround "typedef ignored on left of ..." warning reported in - # imagehlp.h of e.g. Windows Kit 8.1. - add_compile_options(/wd4091) - elseif (WATCOM) - add_compile_options(/we) - else() - add_compile_options(-Werror) - if (APPLE) - # _dyld_bind_fully_image_containing_address is deprecated in OS X 10.5+ - add_compile_options(-Wno-deprecated-declarations) - endif() - endif() -endif(enable_werror) - -if (enable_single_obj_compilation OR GC_BUILD_SHARED_LIBS) - set(SRC extra/gc.c) # override SRC - if (CMAKE_USE_PTHREADS_INIT) - add_definitions("-DGC_PTHREAD_START_STANDALONE") - set(SRC ${SRC} pthread_start.c) - endif(CMAKE_USE_PTHREADS_INIT) -elseif (BORLAND) - # Suppress "GC_push_contents_hdr() is declared but never used" warning. - add_compile_options(/w-use) -endif() - -# Add implementation of backtrace() and backtrace_symbols(). -if (MSVC) - set(SRC ${SRC} extra/msvc_dbg.c) -endif() - -# Instruct check_c_source_compiles and similar CMake checks not to ignore -# compiler warnings (like "implicit declaration of function"). -if (NOT BORLAND AND NOT MSVC AND NOT WATCOM) - check_c_compiler_flag(-Werror HAVE_FLAG_WERROR) - if (HAVE_FLAG_WERROR) - SET(CMAKE_REQUIRED_FLAGS "-Werror") - endif(HAVE_FLAG_WERROR) -endif() - -if (GC_BUILD_SHARED_LIBS) - add_definitions("-DGC_DLL") - # Pass -fvisibility=hidden option if supported. - check_c_compiler_flag(-fvisibility=hidden HAVE_FLAG_F_VISIBILITY_HIDDEN) - if (HAVE_FLAG_F_VISIBILITY_HIDDEN) - add_definitions("-DGC_VISIBILITY_HIDDEN_SET") - add_compile_options(-fvisibility=hidden) - else() - add_definitions("-DGC_NO_VISIBILITY") - endif() - check_c_compiler_flag(-Wl,--no-undefined HAVE_FLAG_WL_NO_UNDEFINED) -else() - add_definitions("-DGC_NOT_DLL") - if (WIN32) - # Do not require the clients to link with "user32" system library. - add_definitions("-DDONT_USE_USER32_DLL") - endif(WIN32) -endif() - -# Disable strict aliasing optimizations. -# It could re-enabled back by a flag passed in CFLAGS_EXTRA. -check_c_compiler_flag(-fno-strict-aliasing HAVE_FLAG_F_NO_STRICT_ALIASING) -if (HAVE_FLAG_F_NO_STRICT_ALIASING) - add_compile_options(-fno-strict-aliasing) -endif() - -# Extra user-defined flags to pass both to C and C++ compilers. -if (DEFINED CFLAGS_EXTRA) - add_compile_options(${CFLAGS_EXTRA}) -endif() - -# Check whether execinfo.h header file is present. -check_include_file(execinfo.h HAVE_EXECINFO_H) -if (NOT HAVE_EXECINFO_H) - add_definitions("-DGC_MISSING_EXECINFO_H") -endif() - -# Check for getcontext (uClibc can be configured without it, for example). -check_function_exists(getcontext HAVE_GETCONTEXT) -if (NOT HAVE_GETCONTEXT) - add_definitions("-DNO_GETCONTEXT") -endif() - -# Check whether dl_iterate_phdr exists (as a strong symbol). -check_function_exists(dl_iterate_phdr HAVE_DL_ITERATE_PHDR) -if (HAVE_DL_ITERATE_PHDR) - add_definitions("-DHAVE_DL_ITERATE_PHDR") -endif() - -check_symbol_exists(sigsetjmp setjmp.h HAVE_SIGSETJMP) -if (NOT HAVE_SIGSETJMP) - add_definitions("-DGC_NO_SIGSETJMP") -endif() - -# pthread_setname_np, if available, may have 1, 2 or 3 arguments. -if (CMAKE_USE_PTHREADS_INIT) - check_c_source_compiles(" -#include \n -int main(void) { (void)pthread_setname_np(\"thread-name\"); return 0; }" - HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID) - if (HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID) - # Define to use 'pthread_setname_np(const char*)' function. - add_definitions("-DHAVE_PTHREAD_SETNAME_NP_WITHOUT_TID") - else() - check_c_source_compiles(" -#include \n -int main(void) {\n - (void)pthread_setname_np(pthread_self(), \"thread-name-%u\", 0); return 0; }" - HAVE_PTHREAD_SETNAME_NP_WITH_TID_AND_ARG) - if (HAVE_PTHREAD_SETNAME_NP_WITH_TID_AND_ARG) - # Define to use 'pthread_setname_np(pthread_t, const char*, void *)'. - add_definitions("-DHAVE_PTHREAD_SETNAME_NP_WITH_TID_AND_ARG") - else() - check_c_source_compiles(" -#if defined(__linux__) || defined(__GLIBC__) || defined(__GNU__) || defined(__CYGWIN__)\n -#define _GNU_SOURCE 1\n -#endif\n -#include \n -int main(void) {\n - (void)pthread_setname_np(pthread_self(), \"thread-name\"); return 0; }" - HAVE_PTHREAD_SETNAME_NP_WITH_TID) - if (HAVE_PTHREAD_SETNAME_NP_WITH_TID) - # Define to use 'pthread_setname_np(pthread_t, const char*)' function. - add_definitions("-DHAVE_PTHREAD_SETNAME_NP_WITH_TID") - endif() - endif(HAVE_PTHREAD_SETNAME_NP_WITH_TID_AND_ARG) - endif (HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID) -endif() - -# Check for dladdr (used for debugging). -check_c_source_compiles(" -#define _GNU_SOURCE 1\n -#include \n -int main(void) { Dl_info info; (void)dladdr(\"\", &info); return 0; }" - HAVE_DLADDR) -if (HAVE_DLADDR) - # Define to use 'dladdr' function. - add_definitions("-DHAVE_DLADDR") -endif() - -add_library(omcgc ${GC_LIBRARY_BUILD_TYPE} ${SRC}) -if (enable_threads) - target_link_libraries(omcgc PRIVATE ${THREADDLLIBS}) -endif() - -if (enable_cplusplus) - add_library(omcgccpp ${GC_LIBRARY_BUILD_TYPE} gc_badalc.cc gc_cpp.cc) - target_link_libraries(omcgccpp PRIVATE omcgc) - if (enable_throw_bad_alloc_library) - # The same as gccpp but contains only gc_badalc. - add_library(omcgctba ${GC_LIBRARY_BUILD_TYPE} gc_badalc.cc) - target_link_libraries(omcgctba PRIVATE omcgc) - endif(enable_throw_bad_alloc_library) -endif() - -if (build_cord) - set(CORD_SRC cord/cordbscs.c cord/cordprnt.c cord/cordxtra.c) - add_library(omccord ${GC_LIBRARY_BUILD_TYPE} ${CORD_SRC}) - target_link_libraries(omccord PRIVATE omcgc) - install(TARGETS omccord EXPORT cordExports) -endif() - -if (GC_BUILD_SHARED_LIBS AND HAVE_FLAG_WL_NO_UNDEFINED) - # Declare that the libraries do not refer to external symbols. - # TODO: use add_link_options() when cmake_minimum_required > 3.13 - target_link_libraries(omcgc PRIVATE -Wl,--no-undefined) - if (enable_cplusplus) - target_link_libraries(omcgccpp PRIVATE -Wl,--no-undefined) - if (enable_throw_bad_alloc_library) - target_link_libraries(omcgctba PRIVATE -Wl,--no-undefined) - endif(enable_throw_bad_alloc_library) - endif(enable_cplusplus) - if (build_cord) - target_link_libraries(omccord PRIVATE -Wl,--no-undefined) - endif(build_cord) -endif() - -install(TARGETS omcgc EXPORT gcExports) - -if (enable_cplusplus) - install(TARGETS omcgccpp EXPORT gccppExports) -endif() - -if (install_headers) - install(FILES include/gc.h - include/gc_backptr.h - include/gc_config_macros.h - include/gc_gcj.h - include/gc_inline.h - include/gc_mark.h - include/gc_pthread_redirects.h - include/gc_tiny_fl.h - include/gc_typed.h - include/gc_version.h - include/javaxfc.h - include/leak_detector.h - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gc) - install(FILES include/extra/gc.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - if (enable_cplusplus) - install(FILES include/gc_allocator.h - include/gc_cpp.h - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gc) - install(FILES include/extra/gc_cpp.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - endif() - if (enable_disclaim) - install(FILES include/gc_disclaim.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gc) - endif() - if (build_cord) - install(FILES include/cord.h - include/cord_pos.h - include/ec.h - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gc) - endif() -endif(install_headers) - -if (build_tests) - if (build_cord) - add_executable(cordtest cord/tests/cordtest.c) - target_link_libraries(cordtest PRIVATE omccord omcgc) - add_test(NAME cordtest COMMAND cordtest) - - if (WIN32 AND NOT CYGWIN) - add_executable(de cord/tests/de.c cord/tests/de_win.c - cord/tests/de_win.rc) - set_target_properties(de PROPERTIES WIN32_EXECUTABLE TRUE) - target_link_libraries(de PRIVATE omccord omcgc omcgdi32) - endif() - endif(build_cord) - - # Compile some tests as C++ to test extern "C" in header files. - if (enable_cplusplus) - set_source_files_properties(tests/leak_test.c tests/test.c - PROPERTIES LANGUAGE CXX) - # To avoid "treating 'c' input as 'c++' when in C++ mode" Clang warning. - if (NOT (BORLAND OR MSVC OR WATCOM)) - add_compile_options(-x c++) - endif() - endif(enable_cplusplus) - - add_executable(gctest WIN32 tests/test.c) - target_link_libraries(gctest PRIVATE omcgc ${THREADDLLIBS}) - add_test(NAME gctest COMMAND gctest) - if (WATCOM) - # Suppress "conditional expression in if statement is always true/false" - # and "unreachable code" warnings in GC_MALLOC_[ATOMIC_]WORDS. - target_compile_options(gctest PRIVATE - /wcd=13 /wcd=201 /wcd=367 /wcd=368 /wcd=726) - endif() - - add_executable(hugetest tests/huge_test.c) - target_link_libraries(hugetest PRIVATE omcgc) - add_test(NAME hugetest COMMAND hugetest) - - add_executable(leaktest tests/leak_test.c) - target_link_libraries(leaktest PRIVATE omcgc) - add_test(NAME leaktest COMMAND leaktest) - - add_executable(middletest tests/middle.c) - target_link_libraries(middletest PRIVATE omcgc) - add_test(NAME middletest COMMAND middletest) - - add_executable(realloc_test tests/realloc_test.c) - target_link_libraries(realloc_test PRIVATE omcgc) - add_test(NAME realloc_test COMMAND realloc_test) - - add_executable(smashtest tests/smash_test.c) - target_link_libraries(smashtest PRIVATE omcgc) - add_test(NAME smashtest COMMAND smashtest) - - if (NOT (GC_BUILD_SHARED_LIBS AND WIN32)) - add_library(staticrootslib_test ${GC_LIBRARY_BUILD_TYPE} tests/staticrootslib.c) - target_link_libraries(staticrootslib_test PRIVATE omcgc) - add_library(staticrootslib2_test ${GC_LIBRARY_BUILD_TYPE} tests/staticrootslib.c) - target_compile_options(staticrootslib2_test PRIVATE "-DSTATICROOTSLIB2") - target_link_libraries(staticrootslib2_test PRIVATE omcgc) - add_executable(staticrootstest tests/staticrootstest.c) - target_compile_options(staticrootstest PRIVATE "-DSTATICROOTSLIB2") - target_link_libraries(staticrootstest PRIVATE - omcgc staticrootslib_test staticrootslib2_test) - add_test(NAME staticrootstest COMMAND staticrootstest) - endif() - - if (enable_gc_debug) - add_executable(tracetest tests/trace_test.c) - target_link_libraries(tracetest PRIVATE omcgc) - add_test(NAME tracetest COMMAND tracetest) - endif() - - if (enable_threads) - add_executable(test_atomic_ops tests/test_atomic_ops.c) - target_link_libraries(test_atomic_ops PRIVATE omcgc) - add_test(NAME test_atomic_ops COMMAND test_atomic_ops) - - add_executable(threadleaktest tests/thread_leak_test.c) - target_link_libraries(threadleaktest PRIVATE omcgc ${THREADDLLIBS}) - add_test(NAME threadleaktest COMMAND threadleaktest) - - if (NOT WIN32) - add_executable(threadkey_test tests/threadkey_test.c) - target_link_libraries(threadkey_test PRIVATE omcgc ${THREADDLLIBS}) - add_test(NAME threadkey_test COMMAND threadkey_test) - endif() - - add_executable(subthreadcreate_test tests/subthread_create.c) - target_link_libraries(subthreadcreate_test PRIVATE omcgc ${THREADDLLIBS}) - add_test(NAME subthreadcreate_test COMMAND subthreadcreate_test) - - add_executable(initsecondarythread_test tests/initsecondarythread.c) - target_link_libraries(initsecondarythread_test PRIVATE omcgc ${THREADDLLIBS}) - add_test(NAME initsecondarythread_test COMMAND initsecondarythread_test) - endif(enable_threads) - - if (enable_cplusplus) - add_executable(test_cpp WIN32 tests/test_cpp.cc) - target_link_libraries(test_cpp PRIVATE omcgc gccpp) - add_test(NAME test_cpp COMMAND test_cpp) - endif() - - if (enable_disclaim) - add_executable(disclaim_bench tests/disclaim_bench.c) - target_link_libraries(disclaim_bench PRIVATE omcgc) - add_test(NAME disclaim_bench COMMAND disclaim_bench) - - add_executable(disclaim_test tests/disclaim_test.c) - target_link_libraries(disclaim_test PRIVATE omcgc ${THREADDLLIBS}) - add_test(NAME disclaim_test COMMAND disclaim_test) - - add_executable(disclaim_weakmap_test tests/disclaim_weakmap_test.c) - target_link_libraries(disclaim_weakmap_test PRIVATE omcgc ${THREADDLLIBS}) - add_test(NAME disclaim_weakmap_test COMMAND disclaim_weakmap_test) - endif() -endif(build_tests) + mallocx.c) +SET(LIBS) +OPTION(enable_threads "TODO" NO) +IF(enable_threads) + FIND_PACKAGE(Threads REQUIRED) + MESSAGE("Thread Model: ${CMAKE_THREAD_LIBS_INIT}" ) + INCLUDE_DIRECTORIES(${Threads_INCLUDE_DIR}) + SET(LIBS ${LIBS} ${Threads_LIBRARIES}) +ENDIF(enable_threads) + +OPTION(enable_handle_fork "Attempt to ensure a usable collector after fork()" ON) + +OPTION(enable_thread_local_alloc "Turn on thread-local allocation optimization" ON) + +OPTION(enable_parallel_mark "Parallelize marking and free list construction" ON) + +#IF(Threads_FOUND) +# ADD_DEFINITIONS("") +#ELSE +# MESSAGE("Parallel mark requires enable_threads ON" ) +#ENDIF(Threads_FOUND) + +#OPTION(enable_cplusplus "install C++ support" ON) +SET(SRC ${SRC} gc_cpp.cc) + +SET(_HOST ${CMAKE_HOST_SYSTEM_PROCESSOR}--${CMAKE_SYSTEM}) #FIXME missing the vendor field. +STRING(TOLOWER ${_HOST} HOST) +MESSAGE("HOST = ${HOST}") + +# Thread Detection. Relying on cmake for lib and includes. +#TODO check cmake detection +IF(CMAKE_USE_PTHREADS_INIT) + SET(SRC ${SRC} gc_dlopen.c pthread_start.c pthread_stop_world.c + pthread_support.c) + # Common defines for most POSIX platforms. + IF( HOST MATCHES .*-.*-aix.*|.*-.*-android.*|.*-.*-cygwin.*|.*-.*-darwin.*|.*-.*-.*freebsd.*|.*-.*-haiku.*|.*-.*-gnu.*|.*-.*-hpux11.*|.*-.*-irix.*|.*-.*-.*linux.*|.*-.*-msys.*|.*-.*-nacl.*|.*-.*-netbsd.*|.*-.*-openbsd.*|.*-.*-osf.*|.*-.*-solaris.*) + ADD_DEFINITIONS("-DGC_THREADS -D_REENTRANT") + IF(enable_parallel_mark) + ADD_DEFINITIONS("-DPARALLEL_MARK") + ENDIF(enable_parallel_mark) + IF(enable_thread_local_alloc) + ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC") + SET(SRC ${SRC} specific.c thread_local_alloc.c) + ENDIF(enable_thread_local_alloc) + MESSAGE("Explicit GC_INIT() calls may be required.") + ENDIF() + IF ( HOST MATCHES .*-.*-hpux11.*) + MESSAGE("Only HP/UX 11 POSIX threads are supported.") + ADD_DEFINITIONS("-D_POSIX_C_SOURCE=199506L") #TODO test -DVAR=value. Alternative is COMPILE_DEFINITIONS property + ENDIF() + IF ( HOST MATCHES .*-.*-hpux10.*) + MESSAGE("HP/UX 10 POSIX threads are not supported.") + ENDIF() + IF ( HOST MATCHES .*-.*-netbsd.*) + MESSAGE("Only on NetBSD 2.0 or later.") + ADD_DEFINITIONS("-D_PTHREADS") + ENDIF() + IF( HOST MATCHES .*-.*-android.*) + # Android NDK does not provide pthread_atfork. + ELSEIF( HOST MATCHES .*-.*-aix.*|.*-.*-cygwin.*|.*-.*-freebsd.*|.*-.*-haiku.*|.*-.*-hpux11.*|.*-.*-irix.*|.*-.*-kfreebsd.*-gnu|.*-.*-.*linux.*|.*-.*-netbsd.*|.*-.*-openbsd.*|.*-.*-osf.*|.*-.*-solaris.*) + IF(enable_handle_fork) + ADD_DEFINITIONS("-DHANDLE_FORK") + ENDIF(enable_handle_fork) + ENDIF() + IF ( HOST MATCHES .*-.*-cygwin.*|.*-.*-msys.*) + SET(SRC ${SRC} win32_threads.c) + ENDIF() + IF ( HOST MATCHES .*-.*-darwin.*) + IF(enable_handle_fork) + # The incremental mode conflicts with fork handling. + IF(enable_parallel_mark) + ADD_DEFINITIONS("-DHANDLE_FORK") + ENDIF(enable_parallel_mark) + ENDIF(enable_handle_fork) + SET(SRC ${SRC} darwin_stop_world.c) + #TODO + #darwin_threads=true + ENDIF() +ENDIF(CMAKE_USE_PTHREADS_INIT) + +IF(CMAKE_USE_WIN32_THREADS_INIT) + ADD_DEFINITIONS("-DGC_THREADS") + IF(enable_parallel_mark) + ADD_DEFINITIONS("-DPARALLEL_MARK") + IF(enable_thread_local_alloc) + ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC") + SET(SRC ${SRC} thread_local_alloc.c) + ENDIF(enable_thread_local_alloc) + ENDIF() + ADD_DEFINITIONS("-DEMPTY_GETENV_RESULTS") #TODO test + SET(SRC ${SRC} win32_threads.c) +ENDIF(CMAKE_USE_WIN32_THREADS_INIT) + +OPTION(enable_gcj_support "Support for gcj" ON) +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) + +OPTION(enable_disclaim "Support alternative finalization interface" ON) +IF(enable_disclaim) + ADD_DEFINITIONS("-DENABLE_DISCLAIM") + SET(SRC ${SRC} fnlz_mlc.c) +ENDIF(enable_disclaim) + +OPTION(enable_java_finalization "Support for java finalization" ON) +IF(enable_java_finalization) + ADD_DEFINITIONS("-DJAVA_FINALIZATION") +ENDIF(enable_java_finalization) + +OPTION(enable_atomic_uncollectable "Support for atomic uncollectible allocation" ON) +IF(enable_atomic_uncollectable) + ADD_DEFINITIONS("-DGC_ATOMIC_UNCOLLECTABLE") +ENDIF(enable_atomic_uncollectable) + +OPTION(enable_gc_debug "Support for pointer back-tracing" NO) +IF(enable_gc_debug) + ADD_DEFINITIONS("-DDBG_HDRS_ALL -DKEEP_BACK_PTRS") + IF (HOST MATCHES ia64-.*-linux.*|i586-.*-linux.*|i686-.*-linux.*|x86-.*-linux.*|x86_64-.*-linux.*) + ADD_DEFINITIONS("-DMAKE_BACK_GRAPH") + ADD_DEFINITIONS("-DSAVE_CALL_COUNT=8") + SET(SRC ${SRC} backgraph.c) + ENDIF() + IF (HOST MATCHES i.86-.*-dgux.*) + ADD_DEFINITIONS("-DMAKE_BACK_GRAPH") + SET(SRC ${SRC} backgraph.c) + ENDIF() +ENDIF(enable_gc_debug) + +OPTION(enable_redirect_malloc "Redirect malloc and friends to GC routines" NO) +IF(enable_redirect_malloc) + IF(enable_gc_debug) + ADD_DEFINITIONS("-DREDIRECT_MALLOC=GC_debug_malloc_replacement") + ADD_DEFINITIONS("-DREDIRECT_REALLOC=GC_debug_realloc_replacement") + ADD_DEFINITIONS("-DREDIRECT_FREE=GC_debug_free") + ELSE(enable_gc_debug) + ADD_DEFINITIONS("-DREDIRECT_MALLOC=GC_malloc") + ENDIF(enable_gc_debug) + ADD_DEFINITIONS("-DGC_USE_DLOPEN_WRAP") +ENDIF(enable_redirect_malloc) + +OPTION(enable_mmap "Use mmap instead of sbrk to expand the heap" NO) + +OPTION(enable_munmap "Return page to the OS if empty for N collections" ON) +IF(enable_munmap) + ADD_DEFINITIONS("-DUSE_MMAP -DUSE_MUNMAP") +ELSEIF(enable_mmap) + ADD_DEFINITIONS("-DUSE_MMAP") +ENDIF() + +OPTION(enable_dynamic_loading "Enable tracing of dynamic library data roots" ON) +IF(NOT enable_dynamic_loading) + ADD_DEFINITIONS("-DIGNORE_DYNAMIC_LOADING") +ENDIF() + +OPTION(enable_register_main_static_data "Perform the initial guess of data root sets" ON) +IF(NOT enable_register_main_static_data) + ADD_DEFINITIONS("-DGC_DONT_REGISTER_MAIN_STATIC_DATA") +ENDIF() + +OPTION(enable_large_config "Optimize for large heap or root set" NO) +IF(enable_large_config) + ADD_DEFINITIONS("-DLARGE_CONFIG") +ENDIF(enable_large_config) + +OPTION(enable_gc_assertions "Enable collector-internal assertion checking" NO) +IF(enable_gc_assertions) + ADD_DEFINITIONS("-DGC_ASSERTIONS") +ENDIF(enable_gc_assertions) + +OPTION(enable_threads_discovery "Enable threads discovery in GC" ON) +IF(NOT enable_threads_discovery) + ADD_DEFINITIONS("-DGC_NO_THREADS_DISCOVERY") +ENDIF() + +OPTION(enable_checksums "Report erroneously cleared dirty bits" NO) +IF(enable_checksums) + IF(enable_munmap OR enable_threads) + MESSAGE("CHECKSUMS not compatible with USE_MUNMAP or threads") + ENDIF() + ADD_DEFINITIONS("-DCHECKSUMS") + SET(SRC ${SRC} checksums.c) +ENDIF(enable_checksums) + +ADD_LIBRARY( gc-lib STATIC ${SRC}) +SET_TARGET_PROPERTIES(gc-lib PROPERTIES + COMPILE_DEFINITIONS GC_NOT_DLL) +#TODO TARGET_LINK_LIBRARIES(... ... ${LIBS}) + +ADD_LIBRARY( gcmt-dll SHARED ${SRC}) + +IF(WIN32) + ADD_EXECUTABLE(cord cord/cordbscs.c cord/cordxtra.c + cord/tests/de.c cord/tests/de_win.c) + SET_TARGET_PROPERTIES(cord PROPERTIES WIN32_EXECUTABLE TRUE) + SET_TARGET_PROPERTIES(cord PROPERTIES + COMPILE_DEFINITIONS GC_NOT_DLL) + TARGET_LINK_LIBRARIES(cord gc-lib) + TARGET_LINK_LIBRARIES(cord gdi32) +ENDIF(WIN32) + +ADD_SUBDIRECTORY(tests) diff --git a/gc/ChangeLog b/gc/ChangeLog index 367662783..3dcd4b320 100644 --- a/gc/ChangeLog +++ b/gc/ChangeLog @@ -1,22 +1,205 @@ -== [8.0.2] (not released yet) == - +== [8.0.6] 2021-09-28 == + +* Add loop to handle abort error like in suspend logic on Darwin +* Add support of OpenBSD/aarch64 +* Add threading libraries to bdw-gc.pc +* Allocate start_info struct on the stack in GC_pthread_create +* Allow GC_PAUSE_TIME_TARGET environment variable values smaller than 5 ms +* Avoid compiler warning about unused d in GC_CALLOC/MALLOC_EXPLICITLY_TYPED +* Avoid gcc stringop-overflow warning for intended overflow in smashtest +* Check _MSVC_LANG macro in addition to __cplusplus (MS VC) +* Compile C++ code with exception handling enabled in NT_MAKEFILE +* Define OS_TYPE and DATAEND for UWP targets +* Disable mprotect-based incremental GC if /proc roots are used (Linux) +* Do not report 'Incremental GC incompatible' warning more than once +* Do not use Manual VDB mode if C malloc is redirected +* Do not use iOS private symbols +* Eliminate 'GC_non_gc_bytes is deprecated' warning in new_gc_alloc.h +* Eliminate 'GC_old_bus_handler defined but not used' compiler warning +* Eliminate 'cast between incompatible func types' warnings for FARPROC vars +* Eliminate 'comparing signed and unsigned values' BCC warning in cordtest +* Eliminate 'gc_pthread_redirects.h should contain header guard' code defect +* Eliminate 'implicit declaration of sbrk' gcc warning if -std=c11 on Cygwin +* Eliminate 'possible loss of data' BCC and MS VC warnings +* Eliminate 'static GC_sysinfo definition has incomplete type' Clang warning +* Eliminate 'unused function' compiler warnings (GC_add_map_entry, GC_lock) +* Eliminate 'while clause does not guard' GCC warning in GC_parse_map_entry +* Enable sbrk-to-mmap fallback on major supported Unix-like platforms +* Ensure process is running on one CPU core if AO ops are emulated with locks +* Explicitly zero-initialize trace_buf (fix trace_buf initialization) +* Fix 'ACCESS_VIOLATION in marker' GC warning on Win32 async thread start +* Fix 'GC_generic_malloc must be available' GCC error in new_gc_alloc.h +* Fix 'ISO C++17 does not allow dynamic exception spec' clang-8 error +* Fix 'Wrong __data_start/_end pair' if -Bsymbolic-functions used (Linux) +* Fix 'condition pred!=NULL is always true' compiler warning +* Fix 'external linkage required for var because of dllimport' error on MinGW +* Fix 'ulong undefined' compilation error on AIX +* Fix 'undefined reference to __data_start' linker error on RISC-V +* Fix 'use of undeclared BUS_PAGE_FAULT' compilation error on FreeBSD 12 +* Fix 'write to GC log failed' error (Cygwin) +* Fix 'wrong finalization data' gctest failure on Windows +* Fix CMake build on macOS Catalina +* Fix GC_OPENBSD_THREADS definition (OpenBSD/hppa) +* Fix GC_proc_fd value in child process at fork (Solaris) +* Fix GC_with_callee_saves_pushed for Android NDK r23 (clang-12) +* Fix MPROTECT_VDB definition for single-threaded GC builds +* Fix OS_TYPE and USE_MMAP_ANON definitions for Cygwin/x64 +* Fix STACKBOTTOM on 32-bit HP/UX 11.11 +* Fix abort in GC_printf when gctest is built as WinMain executable (Cygwin) +* Fix assertion violation in register_dynlib_callback on Android +* Fix build for OS X (CMake) +* Fix building of shared library with C++ support on MinGW +* Fix compiling by Makefile.direct on OpenBSD/UltraSparc +* Fix configure message about 'AIX gcc optimization fix' +* Fix cordtest build in SMakefile.amiga +* Fix data race regarding *rlh value in generic_malloc_many +* Fix first_thread stack_base initialization if custom GC_stackbottom (Win32) +* Fix gc_allocator.h compilation by Clang +* Fix gc_cflags variable name in configure (HP/UX) +* Fix handling of areas smaller than page size in GC_scratch_recycle +* Fix incorrect markup formatting in documentation +* Fix misaligned tlfs passed to AO_load on m68k +* Fix missing GC_quiet declaration in pcr_interface.c +* Fix missing gc_dlopen.c and specific.c in CMake script +* Fix missing scratch_last_end_ptr update (Irix) +* Fix mmap() failures on AIX, HP/UX and Haiku +* Fix overflow of scratch_free_ptr value +* Fix page_was_[ever_]dirty() for static roots (Solaris) +* Fix printf format specifier in simple_example.md +* Fix save_callers for multi-threaded case if built-in backtrace unavailable +* Fix subexpression widening in memhash() of disclaim_weakmap_test +* Fix test_cpp failure caused by arbitrary link order (Win32) +* Fix test_cpp failure when gc_cpp resides in a dll (Borland, Watcom) +* Fix various typos mostly in documentation files +* Fix word size, data start and alignment for OpenBSD/mips64(el) +* Include when using alloca on AIX +* Limit number of unmapped regions (Linux and DragonFly) +* New macro to avoid system-wide new/delete inlining in gc_cpp.h (Win32) +* Prevent GetThreadContext failure (Windows) +* Prevent WARN of incompatible incremental GC if default or manual VDB +* Reduce a time period between GetExitCodeThread and SuspendThread (Win32) +* Refactoring of WoW64 workaround (Win32) +* Refine GC_INIT documentation about its multiple invocation +* Refine GC_parallel documentation in gc.h +* Refine do_blocking() documentation in gc.h +* Remove a misleading comment about Solaris in gc.h +* Remove cord .h files from list of non-installed headers (Automake) +* Remove dead part of condition to define NEED_FIND_LIMIT in gc_priv.h +* Remove gcmt-lib generation by CMake +* Support MSYS builds by CMake and configure +* Update documentation about the incremental collector support +* Use HEURISTIC2 on OpenBSD when single-threaded +* Use pstat_getprocvm to determine main stack bottom on HP-UX +* Workaround 'expression is only useful for its side effects' WCC warning +* Workaround clang-3.8/s390x bug when processing __builtin_frame_address +* Workaround fread fail after enable_incremental if malloc redirected (Linux) + + +== [8.0.4] 2019-03-02 == + +* Avoid a full GC when growing finalizer tables if in incremental mode +* Avoid potential race in hb_sz access between realloc and reclaim_block +* Avoid test.o rebuild on tests folder timestamp change (Makefile.direct) +* Avoid unexpected heap growth in gctest caused by GC_disable +* Ensure result of every variant of MS_TIME_DIFF has unsigned long type +* Fix 'duplicate symbol' error for tests using multiple static libs (OS X) +* Fix 'undefined reference to __data_start' linker error (Android/aarch64) +* Fix 'unexpected mark stack overflow' abort in push_all_stack +* Fix 'wrong __data_start/_end pair' error on Android +* Fix BSD_TIME variant of MS_TIME_DIFF for the case of a.tv_usec < b.tv_usec +* Fix GetThreadContext stale register values use if WoW64 (Win32) +* Fix invalid initializer of CLOCK_TYPE variables if BSD_TIME +* Fix thread_info() count argument value (OS X) +* Support de_win.c compilation by Makefile.direct (cord/de) + + +== [8.0.2] 2018-12-23 == + +* Abort with appropriate message if executable pages cannot be allocated +* Add initial testing of GC_enable/disable, MALLOC[_ATOMIC]_IGNORE_OFF_PAGE +* Add paths to filenames mentioned in the copyright section in README +* Add test using disclaim notifiers to implement a weak map +* Adjust #error messages format +* Allow to force executable pages allocation in gctest +* Avoid potential 'macro redefinition' errors for config.h macros * Call real pthread_sigmask instead of its wrapper in start_mark_threads +* Check result of pthread_mutex_unlock in specific.c * Default to a single-threaded build for Nintendo, Orbis, Sony PSP targets +* Default to non-executable memory allocation across all make scripts +* Define GC_ATOMIC_UNCOLLECTABLE and JAVA_FINALIZATION in all make scripts +* Do not prevent GC from looking at environment variables (BCC_MAKEFILE) +* Do not use 'ifndef AO_CLEAR' in mark, pthread_support and gctest +* Do not use spin locks if AO test-and-set is emulated (pthreads) +* Document HANDLE_FORK macro optional usage in Makefile.direct +* Document assertion in the setters that used to return old value +* Eliminate 'assigned value never used' compiler warning in test_cpp WinMain +* Eliminate 'casting signed to bigger unsigned int' CSA warning * Eliminate 'different const qualifiers' MS VC warnings in cordbscs +* Eliminate 'function is never used' cppcheck warning for calloc/realloc +* Eliminate 'non-virtual destructor for class with inheritors' CSA warning +* Eliminate 'pointer targets differ in signedness' compiler warning (Win32) +* Eliminate 'struct member is never used' cppcheck warnings in os_dep +* Eliminate 'uninitialized var' cppcheck false positive in mach_dep, os_dep +* Eliminate 'unreferenced formal parameter' compiler warning in msvc_dbg +* Eliminate redundant check in backwards_height * Fix 'USE_MUNMAP macro redefinition' error for NaCl +* Fix 'collecting from unknown thread' abort in leak-finding mode for Win32 +* Fix 'mprotect remapping failed' abort on NetBSD with PaX enabled +* Fix 'too wide non-owner permissions are set for resource' code defect +* Fix GC_VSNPRINTF in cordprnt for DJGPP and MS VC for WinCE +* Fix GC_register_disclaim_proc for leak-finding mode +* Fix a deadlock in write_fault_handler if AO_or is emulated * Fix comment typo in CMakeLists.txt * Fix concurrent bitmap update in GC_dirty -* Fix GC_VSNPRINTF in cordprnt for DJGPP and MS VC for WinCE +* Fix deadlocks in write and suspend handlers if AO test-and-set is emulated +* Fix executable memory allocation in GC_unix_get_mem +* Fix hbp overflow in GC_install_counts +* Fix linkage with a system libatomic_ops shared library +* Fix lock assertion violation in get_index if GC_ALWAYS_MULTITHREADED * Fix marking of finalizer closure object +* Fix marks and hb_n_marks consistency when disclaim returns true * Fix memory allocation on GCF (Linux/x64) * Fix missing curses.h in cord/de when compiling manually (MS VC, MinGW) +* Fix test_cpp assertion violation in find-leak mode +* Fix tests linkage with internal atomic_ops.o * Fix unneeded end_stubborn_change/ptr_store_and_dirty in disclaim_test +* Guard against potential buffer overflow in CORD_next and CORD_pos_fetch +* New macro to suppress printing of leaked objects +* Pass -Wall -Wextra -Wpedantic to g++ if supported (configure) +* Prefix internal durango_get_mem symbol with 'GC_' +* Prevent double inclusion of javaxfc.h and private/specific.h +* Print relevant message in tests not appropriate for leak detection mode +* Reduce scope of local variables in GC_remove_all_threads_but_me +* Refine HIDE_POINTER documentation for the case of the leak-finding mode * Refine documentation in gc_disclaim.h * Remove extra USE_MMAP definition for Interix +* Remove redundant header double-inclusion checks in the private headers +* Remove strlen calls with a constant string argument in msvc_dbg * Specify register_disclaim_proc and finalized_malloc argument as non-null +* Support UWP/arm64 target * Test marking of finalizer closure object in disclaim_test +* Turn off leak detection mode explicitly in cord/de +* Turn off parallel marker, thread-local allocation if used AO ops emulated +* Turn on gcj functionality in BCC, DMC, NT, OS/2, WCC makefiles +* Turn on memory unmapping in BCC/DMC/NT/WCC makefiles and Makefile.direct +* Update NO_EXECUTE_PERMISSION documentation +* Update documentation about arm64 ABI in gcconfig.h * Use AO_or in async_set_pht_entry_from_index if available +* Use GC_WORD_MAX macro across all C source files +* Use macro to operate on a flag residing in GC_stop_count +* Use standalone private macro to guard against ptr_t redefinition +* Workaround '#error' cppcheck messages in backgraph and private headers +* Workaround 'AST broken' syntax error reported by cppcheck in GC_mark_some +* Workaround 'GC_dump function is never used' cppcheck warning +* Workaround 'local address assignment to a global variable' CSA warning +* Workaround 'local variable end shadows outer symbol' cppcheck warnings +* Workaround 'local variable obj_displ shadows outer symbol' cppcheck warning +* Workaround 'nonlocal var will use ptr to local var' cppcheck false positive +* Workaround 'pointer addition with NULL pointer' cppcheck error in msvc_dbg +* Workaround 'potential non-terminated string' false positive in cordbscs +* Workaround 'value of _MAX_PATH is unknown' cppcheck warning +* Workaround cppcheck warnings regarding CLOCKS_PER_SEC, REDIRECT_REALLOC == [8.0.0] 2018-09-05 == @@ -232,21 +415,110 @@ * Workaround Thread Sanitizer (TSan) false positive warnings -== [7.6.10] (not released yet) == - +== [7.6.14] 2021-09-28 == + +* Add loop to handle abort error like in suspend logic on Darwin +* Add support of OpenBSD/aarch64 +* Add threading libraries to bdw-gc.pc +* Disable mprotect-based incremental GC if /proc roots are used (Linux) +* Do not use iOS private symbols +* Eliminate 'GC_old_bus_handler defined but not used' compiler warning +* Eliminate 'comparing signed and unsigned values' BCC warning in cordtest +* Eliminate 'possible loss of data' BCC and MS VC warnings +* Eliminate 'static GC_sysinfo definition has incomplete type' Clang warning +* Eliminate 'unused function GC_add_map_entry' compiler warning +* Eliminate 'while clause does not guard' GCC warning in GC_parse_map_entry +* Explicitly zero-initialize trace_buf (fix trace_buf initialization) +* Fix 'ACCESS_VIOLATION in marker' GC warning on Win32 async thread start +* Fix 'GC_generic_malloc must be available' GCC error in new_gc_alloc.h +* Fix 'ulong undefined' compilation error on AIX +* Fix 'undefined reference to __data_start' linker error on RISC-V +* Fix 'write to GC log failed' error +* Fix GC_proc_fd value in child process at fork (Solaris) +* Fix MPROTECT_VDB definition for single-threaded GC builds +* Fix OS_TYPE and USE_MMAP_ANON definitions for Cygwin/x64 +* Fix STACKBOTTOM on 32-bit HP/UX 11.11 +* Fix abort in GC_printf when gctest is built as WinMain executable (Cygwin) +* Fix assertion violation in register_dynlib_callback on Android +* Fix compiling by Makefile.direct on OpenBSD/UltraSparc +* Fix configure message about 'AIX gcc optimization fix' +* Fix cordtest build in SMakefile.amiga +* Fix data race regarding *rlh value in generic_malloc_many +* Fix first_thread stack_base initialization if custom GC_stackbottom (Win32) +* Fix gc_allocator.h compilation by Clang +* Fix gc_cflags variable name in configure (HP/UX) +* Fix handling of areas smaller than page size in GC_scratch_recycle +* Fix incorrect define GC_OPENBSD_THREADS on sparc64 +* Fix misaligned tlfs passed to AO_load on m68k +* Fix missing GC_quiet declaration in pcr_interface.c +* Fix missing gc_dlopen.c in CMake script +* Fix missing scratch_last_end_ptr update (Irix) +* Fix overflow of scratch_free_ptr value +* Fix page_was_[ever_]dirty() for static roots (Solaris) +* Fix printf format specifier in simple_example.html +* Fix save_callers for multi-threaded case if built-in backtrace unavailable +* Fix test_cpp failure caused by arbitrary link order (Win32) +* Fix test_cpp failure when gc_cpp resides in a dll (Borland, Watcom) +* Fix various typos mostly in documentation files +* Fix word size, data start and alignment for OpenBSD/mips64(el) +* Prevent GetThreadContext failure (Windows) +* Prevent WARN of incompatible incremental GC if default or manual VDB +* Reduce a time period between GetExitCodeThread and SuspendThread (Win32) +* Refactoring of WoW64 workaround (Win32) +* Remove a misleading comment about Solaris in gc.h +* Workaround 'expression is only useful for its side effects' WCC warning +* Workaround fread fail after enable_incremental if malloc redirected (Linux) + + +== [7.6.12] 2019-03-01 == + +* Eliminate 'assigned value never used' compiler warning in test_cpp WinMain +* Fix 'mprotect remapping failed' abort on NetBSD with PaX enabled +* Fix 'undefined reference to __data_start' linker error (Android/aarch64) +* Fix 'unexpected mark stack overflow' abort in push_all_stack +* Fix 'wrong __data_start/_end pair' error on Android +* Fix BSD_TIME variant of MS_TIME_DIFF for the case of a.tv_usec < b.tv_usec +* Fix GetThreadContext stale register values use if WoW64 (Win32) +* Fix executable memory allocation in GC_unix_get_mem +* Fix invalid initializer of CLOCK_TYPE variables if BSD_TIME +* Fix thread_info() count argument value (OS X) +* Update NO_EXECUTE_PERMISSION documentation + + +== [7.6.10] 2018-12-13 == + +* Add paths to filenames mentioned in the copyright section in README * Call real pthread_sigmask instead of its wrapper in start_mark_threads +* Eliminate 'casting signed to bigger unsigned int' CSA warning +* Eliminate 'non-virtual destructor for class with inheritors' CSA warning +* Fix 'collecting from unknown thread' abort in leak-finding mode for Win32 +* Fix 'too wide non-owner permissions are set for resource' code defect * Fix 'undefined reference to GC_incremental' linker error in pthread_start +* Fix GC_VSNPRINTF in cordprnt for DJGPP and MS VC for WinCE +* Fix GC_register_disclaim_proc for leak-finding mode +* Fix a deadlock in write_fault_handler if AO_or is emulated * Fix comment typos in CMakeLists.txt, backgraph.c, de.c, gcconfig.h * Fix concurrent bitmap update in GC_dirty * Fix delete operator redirection if gc_cpp is built as .dll (Cygwin, MinGW) -* Fix GC_VSNPRINTF in cordprnt for DJGPP and MS VC for WinCE +* Fix hbp overflow in GC_install_counts +* Fix linkage with a system libatomic_ops shared library +* Fix lock assertion violation in get_index if GC_ALWAYS_MULTITHREADED * Fix marking of finalizer closure object +* Fix marks and hb_n_marks consistency when disclaim returns true * Fix memory allocation on GCF (Linux/x64) * Fix missing curses.h in cord/de when compiling manually (MS VC, MinGW) * Fix start_world not resuming all threads on Darwin +* Fix test_cpp assertion violation in find-leak mode +* Fix tests linkage with internal atomic_ops.o * Fix unneeded end_stubborn_change in disclaim_test +* Guard against potential buffer overflow in CORD_next and CORD_pos_fetch +* New macro to suppress printing of leaked objects +* Prevent double inclusion of javaxfc.h and private/specific.h +* Reduce scope of local variables in GC_remove_all_threads_but_me +* Refine HIDE_POINTER documentation for the case of the leak-finding mode * Refine documentation in gc_disclaim.h * Test marking of finalizer closure object in disclaim_test +* Update documentation about arm64 ABI in gcconfig.h * Use AO_or in async_set_pht_entry_from_index if available * Use include gc.h with the angle brackets in the man page synopsis @@ -684,12 +956,40 @@ Also, includes 7.4.6 changes Also, includes 7.4.4 changes -== [7.4.16] (not released yet) == +== [7.4.20] 2021-09-28 == + +* Do not hold GC_fault_handler_lock when in Sleep (Windows) +* Eliminate 'static GC_sysinfo definition has incomplete type' Clang warning +* Eliminate 'unused function GC_add_map_entry' compiler warning +* Eliminate 'while clause does not guard' GCC warning in GC_parse_map_entry +* Fix OS_TYPE and USE_MMAP_ANON definitions for Cygwin/x64 +* Fix abort in GC_printf when gctest is built as WinMain executable (Cygwin) +* Fix configure message about 'AIX gcc optimization fix' +* Fix cordtest build in SMakefile.amiga +* Prevent GetThreadContext failure (Windows) +* Refactoring of WoW64 workaround (Win32) + +Also, includes 7.2o changes + +== [7.4.18] 2019-03-01 == + +* Fix 'wrong __data_start/_end pair' error on Android +* Fix thread_info() count argument value (OS X) + +Also, includes 7.2n changes + + +== [7.4.16] 2018-12-13 == + +* Fix 'collecting from unknown thread' abort in leak-finding mode for Win32 * Fix 'undefined reference to GC_incremental' linker error in pthread_start +* Fix GC_register_disclaim_proc for leak-finding mode * Fix concurrent bitmap update in GC_dirty * Fix marking of finalizer closure object +* Fix marks and hb_n_marks consistency when disclaim returns true * Fix missing curses.h in cord/de when compiling manually (MS VC, MinGW) +* Refine documentation in gc_disclaim.h Also, includes 7.2m changes @@ -1182,10 +1482,55 @@ Also, includes 7.2e, 7.2d, 7.2c, 7.2b changes Also, includes 7.2 changes -== [7.2m] (not released yet) == +== [7.2o] 2021-09-28 == + +* Add loop to handle abort error like in suspend logic on Darwin +* Disable mprotect-based incremental GC if /proc roots are used (Linux) +* Explicitly zero-initialize trace_buf (fix trace_buf initialization) +* Fix 'ACCESS_VIOLATION in marker' GC warning on Win32 async thread start +* Fix 'GC_generic_malloc must be available' GCC error in new_gc_alloc.h +* Fix 'expected function body after declarator' clang error in gc_cpp.cc +* Fix 'write to GC log failed' error +* Fix GC_proc_fd value in child process at fork (Solaris) +* Fix assertion violation in register_dynlib_callback on Android +* Fix configure message about 'AIX gcc optimization fix' +* Fix data race regarding *rlh value in generic_malloc_many +* Fix first_thread stack_base initialization if custom GC_stackbottom (Win32) +* Fix fread failure after enable_incremental if malloc is redirected (Linux) +* Fix gc_cflags variable name in configure (HP/UX) +* Fix handling of areas smaller than page size on recycle scratch area +* Fix incorrect define GC_OPENBSD_THREADS on sparc64 +* Fix misaligned tlfs passed to AO_load on m68k +* Fix missing GC_quiet declaration in pcr_interface.c +* Fix missing gc_dlopen.c in CMake script +* Fix missing scratch_last_end_ptr update (Irix) +* Fix overflow of scratch_free_ptr value +* Fix page_was_[ever_]dirty() for static roots (Solaris) +* Fix printf format specifier in simple_example.html +* Fix save_callers for multi-threaded case if built-in backtrace unavailable +* Fix various typos in comments and documentation files +* Fix word size, data start and alignment for OpenBSD/mips64(el) +* Prevent WARN of incompatible incremental GC if default or manual VDB +* Reduce a time period between GetExitCodeThread and SuspendThread (Win32) +* Remove a misleading comment about Solaris in gc.h + + +== [7.2n] 2019-03-01 == + +* Fix 'mprotect remapping failed' abort on NetBSD with PaX enabled +* Fix 'unexpected mark stack overflow' abort in push_all_stack +* Fix BSD_TIME variant of MS_TIME_DIFF for the case of a.tv_usec < b.tv_usec +* Fix GetThreadContext stale register values use if WoW64 (Win32) +* Fix executable memory allocation in GC_unix_get_mem +* Fix invalid initializer of CLOCK_TYPE variables if BSD_TIME + + +== [7.2m] 2018-12-11 == * Fix comment typos in CMakeLists.txt, backgraph.c, de.c, gcconfig.h +* Fix hbp overflow in GC_install_counts * Fix start_world not resuming all threads on Darwin +* Guard against potential buffer overflow in CORD_next and CORD_pos_fetch == [7.2l] 2018-08-10 == @@ -7870,7 +8215,7 @@ process. * Separate gc_conf_macros.h from gc.h. * Added generic GC_THREADS client-defined macro to set the appropriate GC_XXX_THREADS internal macro. (gc_config_macros.h.) -* Add debugging versions of _ignore_off_page allocation primitves. +* Add debugging versions of _ignore_off_page allocation primitives. * Moved declarations of GC_make_closure and GC_debug_invoke_finalizer from gc.h to gc_priv.h. * Reset GC_fail_count even if only a small allocation succeeds. diff --git a/gc/Makefile.am b/gc/Makefile.am index b2cf88274..f22115c47 100644 --- a/gc/Makefile.am +++ b/gc/Makefile.am @@ -14,8 +14,8 @@ # 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 = 5:1:4 -LIBGCCPP_VER_INFO = 5:0:4 +LIBGC_VER_INFO = 5:4:4 +LIBGCCPP_VER_INFO = 5:1:4 ## FIXME: `make distcheck' in this directory will not currently work. ## This is most likely to the explicit flags passed to submakes. @@ -54,21 +54,21 @@ pkgconfig_DATA = bdw-gc.pc # C Library # --------- -lib_LTLIBRARIES += libomcgc.la +lib_LTLIBRARIES += libgc.la if SINGLE_GC_OBJ -libomcgc_la_SOURCES = extra/gc.c +libgc_la_SOURCES = extra/gc.c if PTHREAD_START_STANDALONE AM_CPPFLAGS += -DGC_PTHREAD_START_STANDALONE -libomcgc_la_SOURCES += pthread_start.c +libgc_la_SOURCES += pthread_start.c endif else EXTRA_DIST += extra/gc.c -libomcgc_la_SOURCES = \ +libgc_la_SOURCES = \ allchblk.c alloc.c blacklst.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 \ @@ -78,33 +78,33 @@ libomcgc_la_SOURCES = \ # --------------------------------- if WIN32_THREADS -libomcgc_la_SOURCES += win32_threads.c +libgc_la_SOURCES += win32_threads.c else if PTHREADS # Not Cygwin or MinGW. -libomcgc_la_SOURCES += pthread_start.c pthread_support.c +libgc_la_SOURCES += pthread_start.c pthread_support.c if DARWIN_THREADS -libomcgc_la_SOURCES += darwin_stop_world.c +libgc_la_SOURCES += darwin_stop_world.c else -libomcgc_la_SOURCES += pthread_stop_world.c +libgc_la_SOURCES += pthread_stop_world.c endif endif endif if THREAD_LOCAL_ALLOC -libomcgc_la_SOURCES += thread_local_alloc.c +libgc_la_SOURCES += thread_local_alloc.c endif if MAKE_BACK_GRAPH -libomcgc_la_SOURCES += backgraph.c +libgc_la_SOURCES += backgraph.c endif if CHECKSUMS -libomcgc_la_SOURCES += checksums.c +libgc_la_SOURCES += checksums.c endif if ENABLE_DISCLAIM -libomcgc_la_SOURCES += fnlz_mlc.c +libgc_la_SOURCES += fnlz_mlc.c pkginclude_HEADERS += include/gc_disclaim.h endif @@ -112,21 +112,21 @@ endif endif if USE_INTERNAL_LIBATOMIC_OPS -nodist_libomcgc_la_SOURCES = libatomic_ops/src/atomic_ops.c +nodist_libgc_la_SOURCES = libatomic_ops/src/atomic_ops.c endif if NEED_ATOMIC_OPS_ASM -nodist_libomcgc_la_SOURCES = libatomic_ops/src/atomic_ops_sysdeps.S +nodist_libgc_la_SOURCES = libatomic_ops/src/atomic_ops_sysdeps.S endif # Include THREADDLLIBS here to ensure that the correct versions of # linuxthread semaphore functions get linked: -libomcgc_la_LIBADD = @addobjs@ $(THREADDLLIBS) $(UNWINDLIBS) $(ATOMIC_OPS_LIBS) -libomcgc_la_DEPENDENCIES = @addobjs@ -libomcgc_la_LDFLAGS = $(extra_ldflags_libgc) -version-info $(LIBGC_VER_INFO) \ +libgc_la_LIBADD = @addobjs@ $(THREADDLLIBS) $(UNWINDLIBS) $(ATOMIC_OPS_LIBS) +libgc_la_DEPENDENCIES = @addobjs@ +libgc_la_LDFLAGS = $(extra_ldflags_libgc) -version-info $(LIBGC_VER_INFO) \ -no-undefined -EXTRA_libomcgc_la_SOURCES = ia64_save_regs_in_stack.s sparc_mach_dep.S \ +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 @@ -135,9 +135,9 @@ if CPLUSPLUS lib_LTLIBRARIES += libgccpp.la pkginclude_HEADERS += include/gc_allocator.h include/gc_cpp.h include_HEADERS += include/extra/gc_cpp.h -libomcgccpp_la_SOURCES = gc_cpp.cc -libomcgccpp_la_LIBADD = ./libgc.la -libomcgccpp_la_LDFLAGS = -version-info $(LIBGCCPP_VER_INFO) -no-undefined +libgccpp_la_SOURCES = gc_cpp.cc +libgccpp_la_LIBADD = ./libgc.la +libgccpp_la_LDFLAGS = -version-info $(LIBGCCPP_VER_INFO) -no-undefined endif ## FIXME: If Visual C++ users use Makefile.am, this should go into @@ -157,7 +157,7 @@ CXXFLAGS += $(CFLAGS_EXTRA) ## FIXME: relies on internal code generated by automake. ## FIXME: ./configure --enable-dependency-tracking should be used -#all_objs = @addobjs@ $(libomcgc_la_OBJECTS) +#all_objs = @addobjs@ $(libgc_la_OBJECTS) #$(all_objs) : include/private/gcconfig.h include/private/gc_priv.h \ #include/private/gc_hdrs.h include/gc.h include/gc_gcj.h \ #include/gc_pthread_redirects.h include/gc_config_macros.h \ @@ -208,7 +208,7 @@ EXTRA_DIST += tools/if_mach.c tools/if_not_there.c tools/setjmp_t.c \ extra/symbian/global_end.cpp extra/symbian/global_start.cpp \ extra/symbian/init_global_static_roots.cpp extra/symbian.cpp \ extra/pcr_interface.c extra/real_malloc.c \ - build/s60v3/bld.inf build/s60v3/libomcgc.mmp \ + build/s60v3/bld.inf build/s60v3/libgc.mmp \ extra/Mac_files/datastart.c extra/Mac_files/dataend.c \ extra/Mac_files/MacOS_config.h \ include/private/msvc_dbg.h extra/msvc_dbg.c tools/callprocs.sh @@ -224,4 +224,4 @@ 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 -## libomcgc.a on HP/UX. There may be a better fix. +## libgc.a on HP/UX. There may be a better fix. diff --git a/gc/Makefile.direct b/gc/Makefile.direct index 9e4186b7c..30c70c3b8 100644 --- a/gc/Makefile.direct +++ b/gc/Makefile.direct @@ -46,8 +46,9 @@ AO_SRC_DIR=$(srcdir)/libatomic_ops CFLAGS_EXTRA= # We need CFLAGS_FOR_PIC because we might be building a shared library. CFLAGS= -O -I$(srcdir)/include -I$(AO_SRC_DIR)/src \ - -DGC_ATOMIC_UNCOLLECTABLE -DNO_EXECUTE_PERMISSION -DALL_INTERIOR_POINTERS \ - -DENABLE_DISCLAIM $(CFLAGS_FOR_PIC) $(CFLAGS_EXTRA) + -DALL_INTERIOR_POINTERS -DENABLE_DISCLAIM -DGC_ATOMIC_UNCOLLECTABLE \ + -DGC_GCJ_SUPPORT -DJAVA_FINALIZATION -DNO_EXECUTE_PERMISSION \ + -DUSE_MMAP -DUSE_MUNMAP $(CFLAGS_FOR_PIC) $(CFLAGS_EXTRA) # To build the collector with threads support, add to the above: # -DGC_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC @@ -55,6 +56,9 @@ CFLAGS= -O -I$(srcdir)/include -I$(AO_SRC_DIR)/src \ # To build the preload library that intercepts malloc, add: # -DGC_USE_DLOPEN_WRAP -DREDIRECT_MALLOC=GC_malloc -fpic +# To build the collector with fork() support by default, add to the above: +# -DHANDLE_FORK + # HOSTCC and HOSTCFLAGS are used to build executables that will be run as # part of the build process, i.e. on the build machine. These will usually # be the same as CC and CFLAGS, except in a cross-compilation environment. @@ -188,13 +192,11 @@ specific.o pthread_support.o thread_local_alloc.o win32_threads.o: \ dbg_mlc.o gcj_mlc.o: $(srcdir)/include/private/dbg_mlc.h -tests/test.o: tests $(srcdir)/tests/test.c +tests/test.o: $(srcdir)/tests/test.c + mkdir tests || cat /dev/null $(CC) $(CFLAGS) -c $(srcdir)/tests/test.c mv test.o tests/test.o -tests: - mkdir tests - base_lib gc.a: $(OBJS) dyn_load.o $(UTILS) rm -f dont_ar_1 ./if_mach SPARC SOLARIS touch dont_ar_1 @@ -224,7 +226,7 @@ test_cpp$(EXEEXT): $(srcdir)/tests/test_cpp.cc $(srcdir)/include/gc_cpp.h \ $(srcdir)/include/gc.h gc_cpp.o base_lib $(UTILS) rm -f test_cpp$(EXEEXT) ./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$(EXEEXT) || $(CXX) $(CXXFLAGS) -o test_cpp$(EXEEXT) $(srcdir)/tests/test_cpp.cc gc_cpp.o gc.a `./threadlibs` + ./if_not_there test_cpp$(EXEEXT) || $(CXX) $(CXXFLAGS) -DGC_NOT_DLL -o test_cpp$(EXEEXT) $(srcdir)/tests/test_cpp.cc gc_cpp.o gc.a `./threadlibs` check-cpp: test_cpp$(EXEEXT) ./test_cpp @@ -287,12 +289,11 @@ dyn_test: # 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) 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 OPENBSD $(CC) -c -o mach_dep2.o $(srcdir)/sparc_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 @@ -338,7 +339,8 @@ cord/cordtest$(EXEEXT): $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) \ ./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$(EXEEXT) || $(CC) $(CFLAGS) -o cord/cordtest$(EXEEXT) $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) gc.a `./threadlibs` -cord/de: $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o base_lib \ +cord/de: $(srcdir)/cord/tests/de.c $(srcdir)/cord/tests/de_win.c \ + $(srcdir)/cord/tests/de_win.h 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 -lcurses -ltermlib -lucb `./threadlibs` @@ -349,7 +351,7 @@ cord/de: $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o base_lib \ ./if_mach ALPHA LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs` ./if_mach IA64 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs` ./if_mach M68K AMIGA $(CC) $(CFLAGS) -UGC_AMIGA_MAKINGLIB -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses - ./if_not_there cord/de$(EXEEXT) || $(CC) $(CFLAGS) -o cord/de$(EXEEXT) $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) `./threadlibs` + ./if_not_there cord/de$(EXEEXT) || $(CC) $(CFLAGS) -o cord/de$(EXEEXT) $(srcdir)/cord/tests/de.c $(srcdir)/cord/tests/de_win.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) `./threadlibs` if_mach$(EXEEXT): $(srcdir)/tools/if_mach.c \ $(srcdir)/include/private/gcconfig.h diff --git a/gc/NT_MAKEFILE b/gc/NT_MAKEFILE index 479e64f3e..02430ed83 100644 --- a/gc/NT_MAKEFILE +++ b/gc/NT_MAKEFILE @@ -76,6 +76,10 @@ LINK_GC=$(link) $(ldebug) $(LINK_DLL_FLAGS) CFLAGS_SPECIFIC=$(CFLAGS_DEBUG) $(CFLAGS_GCDLL) $(CFLAGS_MT) +CFLAGS_DEFAULT=-DALL_INTERIOR_POINTERS -DENABLE_DISCLAIM -DGC_ATOMIC_UNCOLLECTABLE -DGC_GCJ_SUPPORT -DJAVA_FINALIZATION -DNO_EXECUTE_PERMISSION -DUSE_MUNMAP + +CXXFLAGS_SPECIFIC=/EHsc + # 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: @@ -87,17 +91,17 @@ CFLAGS_SPECIFIC=$(CFLAGS_DEBUG) $(CFLAGS_GCDLL) $(CFLAGS_MT) 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 dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj extra\msvc_dbg.obj thread_local_alloc.obj +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 dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj gcj_mlc.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) $(CFLAGS_SPECIFIC) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DENABLE_DISCLAIM -DCORD_NOT_DLL -D_CRT_SECURE_NO_DEPRECATE $*.c /Fo$*.obj /wd4100 /wd4127 /wd4701 + $(cc) $(cdebug) $(cflags) $(CFLAGS_SPECIFIC) -Iinclude -I$(AO_INCLUDE_DIR) $(CFLAGS_DEFAULT) -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) $(CFLAGS_SPECIFIC) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -D_CRT_SECURE_NO_DEPRECATE $*.cpp /Fo$*.obj + $(cc) $(cdebug) $(cflags) $(CFLAGS_SPECIFIC) -Iinclude $(CFLAGS_DEFAULT) $(CXXFLAGS_SPECIFIC) -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 diff --git a/gc/OS2_MAKEFILE b/gc/OS2_MAKEFILE index 400fa73d6..da725aa1d 100644 --- a/gc/OS2_MAKEFILE +++ b/gc/OS2_MAKEFILE @@ -5,12 +5,12 @@ # Significantly revised for GC version 4.4 by Mark Boulter (Jan 1994). -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 typd_mlc.obj ptr_chck.obj mallocx.obj +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 typd_mlc.obj ptr_chck.obj mallocx.obj gcj_mlc.obj CORDOBJS= cord\cordbscs.obj cord\cordxtra.obj cord\cordprnt.obj CC= icc -CFLAGS= /O /Q /DSMALL_CONFIG /DALL_INTERIOR_POINTERS /DENABLE_DISCLAIM +CFLAGS= /O /Q /DALL_INTERIOR_POINTERS /DENABLE_DISCLAIM /DGC_ATOMIC_UNCOLLECTABLE /DGC_GCJ_SUPPORT /DJAVA_FINALIZATION /DNO_EXECUTE_PERMISSION /DSMALL_CONFIG # Use /Ti instead of /O for debugging # Setjmp_test may yield overly optimistic results when compiled # without optimization. @@ -20,7 +20,7 @@ all: $(OBJS) gctest.exe cord\cordtest.exe $(OBJS) test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h ## ERASE THE LIB FIRST - if it is already there then this command will fail -## (make sure its there or erase will fail!) +## (make sure it is there or erase will fail!) gc.lib: $(OBJS) echo . > gc.lib erase gc.lib diff --git a/gc/README.QUICK b/gc/README.QUICK index d96ff47f1..0648ab727 100644 --- a/gc/README.QUICK +++ b/gc/README.QUICK @@ -2,7 +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 +Copyright (c) 2009-2019 Ivan Maidanski THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. diff --git a/gc/README.md b/gc/README.md index 916720337..c1fe8104a 100644 --- a/gc/README.md +++ b/gc/README.md @@ -1,6 +1,6 @@ # Boehm-Demers-Weiser Garbage Collector -This is version 8.0.0 (experimental release) of a conservative garbage +This is version 8.0.6 of a conservative garbage collector for C and C++. @@ -103,7 +103,7 @@ address space. There are a number of routines which modify the pointer recognition algorithm. `GC_register_displacement` allows certain interior pointers -to be recognized even if `ALL_INTERIOR_POINTERS` is nor defined. +to be recognized even if `ALL_INTERIOR_POINTERS` is not defined. `GC_malloc_ignore_off_page` allows some pointers into the middle of large objects to be disregarded, greatly reducing the probability of accidental retention of large objects. For most purposes it seems @@ -264,7 +264,7 @@ Note that usually only `GC_malloc` is necessary. `GC_clear_roots` and `GC_add_roots` calls may be required if the collector has to trace from nonstandard places (e.g. from dynamic library data areas on a machine on which the collector doesn't already understand them.) On -some machines, it may be desirable to set `GC_stacktop` to a good +some machines, it may be desirable to set `GC_stackbottom` to a good approximation of the stack base. (This enhances code portability on HP PA machines, since there is no good way for the collector to compute this value.) Client code may include "gc.h", which defines @@ -359,7 +359,7 @@ If only `GC_malloc` is intended to be used, it might be appropriate to define: #define malloc(n) GC_malloc(n) #define calloc(m,n) GC_malloc((m)*(n)) -For small pieces of VERY allocation intensive code, gc_inl.h includes +For small pieces of VERY allocation intensive code, gc_inline.h includes some allocation macros that may be used in place of `GC_malloc` and friends. @@ -458,7 +458,7 @@ extra arguments, where appropriate. If gc.h is included without `GC_DEBUG` defined, then all these macros will instead be defined to their nondebugging 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 +of 16 bytes from 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 dbg_mlc.c file.) @@ -515,7 +515,7 @@ They will decrease with the number of processors if parallel marking is enabled. (On 2007 vintage machines, GC times may be on the order of 5 msecs -per MB of accessible memory that needs to be scanned and processor. +per MB of accessible memory that needs to be scanned and processed. Your mileage may vary.) The incremental/generational collection facility may help in some cases. @@ -551,13 +551,13 @@ GitHub. * 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 + * Copyright (c) 2008-2019 Ivan Maidanski The files pthread_stop_world.c, pthread_support.c and some others are also * Copyright (c) 1998 by Fergus Henderson. All rights reserved. -The file gc.h is also +The file include/gc.h is also * Copyright (c) 2007 Free Software Foundation, Inc @@ -565,14 +565,18 @@ 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 +The files extra/msvc_dbg.c and include/private/msvc_dbg.h are * Copyright (c) 2004-2005 Andrei Polushin -The file initsecondarythread.c is +The file tests/initsecondarythread.c is * Copyright (c) 2011 Ludovic Courtes +The file tests/disclaim_weakmap_test.c is + + * Copyright (c) 2018 Petter A. Urkedal + Several files supporting GNU-style builds are copyrighted by the Free Software Foundation, and carry a different license from that given below. diff --git a/gc/SMakefile.amiga b/gc/SMakefile.amiga index 5e27b22a4..ca75cf6a8 100644 --- a/gc/SMakefile.amiga +++ b/gc/SMakefile.amiga @@ -52,7 +52,7 @@ CSCOPT= $(OPT) DEFINE AMIGA IGNORE=100 IGNORE=161 all: gctest setjmp_t cord/cordtest clean: - delete *.lib gctest setjmp_t *.o *.lnk cord/*.o cord/*.lib cord/*.lnk cord/cordtest + delete *.lib gctest setjmp_t *.o *.lnk cord/*.o cord/*.lib cord/*.lnk cord/tests/*.o cord/cordtest smake test: setjmp_t gctest cord/cordtest @@ -66,8 +66,8 @@ gctest: gc$(CPU).lib GCAmigaOS$(CPU).lib test.o setjmp_t: setjmp_t.o gc.h $(LINKER) LIB:c.o setjmp_t.o to setjmp_t lib LIB:sc.lib -cord/cordtest: cord/cordtest.o cord/cord$(CPU).lib gc$(CPU).lib - slink LIB:c.o cord/cordtest.o LIB $(MATHLIB) gc$(CPU).lib cord/cord$(CPU).lib LIB:sc.lib TO cord/cordtest +cord/cordtest: cord/tests/cordtest.o cord/cord$(CPU).lib gc$(CPU).lib + slink LIB:c.o cord/tests/cordtest.o LIB $(MATHLIB) gc$(CPU).lib cord/cord$(CPU).lib LIB:sc.lib TO cord/cordtest #------------------LIBBING---------------------------- @@ -168,5 +168,5 @@ cord/cordprnt.o: cord/cordprnt.c cord/cordxtra.o: cord/cordxtra.c sc cord/cordxtra.c $(CSCOPT) -cord/cordtest.o: cord/tests/cordtest.c +cord/tests/cordtest.o: cord/tests/cordtest.c sc cord/tests/cordtest.c $(CSCOPT) diff --git a/gc/WCC_MAKEFILE b/gc/WCC_MAKEFILE index 0aae2df70..61a1db530 100644 --- a/gc/WCC_MAKEFILE +++ b/gc/WCC_MAKEFILE @@ -25,7 +25,7 @@ CPU=5 OPTIM=-oneatx -s #OPTIM=-ohneatx -s -DEFS=-DALL_INTERIOR_POINTERS -DENABLE_DISCLAIM #-DSMALL_CONFIG +DEFS=-DALL_INTERIOR_POINTERS -DENABLE_DISCLAIM -DGC_ATOMIC_UNCOLLECTABLE -DGC_GCJ_SUPPORT -DJAVA_FINALIZATION -DNO_EXECUTE_PERMISSION #-DSMALL_CONFIG ##### @@ -48,6 +48,7 @@ SYSTEM=Unknown SYSFLAG=-DDOS4GW -bt=dos !else ifdef MSWIN32 SYSFLAG=-DMSWIN32 -bt=nt +DEFS=$(DEFS) -DUSE_MUNMAP !else ifdef OS2 SYSFLAG=-DOS2 -bt=os2 !else @@ -75,7 +76,7 @@ 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 malloc.obj dyn_load.obj & - typd_mlc.obj ptr_chck.obj mallocx.obj fnlz_mlc.obj + typd_mlc.obj ptr_chck.obj mallocx.obj fnlz_mlc.obj gcj_mlc.obj all: gc.lib gctest.exe test_cpp.exe diff --git a/gc/allchblk.c b/gc/allchblk.c index 030de4624..8d550c444 100644 --- a/gc/allchblk.c +++ b/gc/allchblk.c @@ -326,8 +326,8 @@ GC_INLINE void GC_remove_from_fl(hdr *hhdr) GC_remove_from_fl_at(hhdr, GC_hblk_fl_from_blocks(divHBLKSZ(hhdr->hb_sz))); } -/* Return a pointer to the free block ending just before h, if any. */ -STATIC struct hblk * GC_free_block_ending_at(struct hblk *h) +/* Return a pointer to the block ending just before h, if any. */ +static struct hblk * get_block_ending_at(struct hblk *h) { struct hblk * p = h - 1; hdr * phdr; @@ -338,16 +338,27 @@ STATIC struct hblk * GC_free_block_ending_at(struct hblk *h) phdr = HDR(p); } if (0 != phdr) { - if(HBLK_IS_FREE(phdr)) { + return p; + } + p = GC_prev_block(h - 1); + if (p) { + phdr = HDR(p); + if ((ptr_t)p + phdr -> hb_sz == (ptr_t)h) { return p; - } else { - return 0; } } - p = GC_prev_block(h - 1); - if (0 != p) { - phdr = HDR(p); - if (HBLK_IS_FREE(phdr) && (ptr_t)p + phdr -> hb_sz == (ptr_t)h) { + return NULL; +} + +/* Return a pointer to the free block ending just before h, if any. */ +STATIC struct hblk * GC_free_block_ending_at(struct hblk *h) +{ + struct hblk * p = get_block_ending_at(h); + + if (p /* != NULL */) { /* CPPCHECK */ + hdr * phdr = HDR(p); + + if (HBLK_IS_FREE(phdr)) { return p; } } @@ -395,6 +406,60 @@ STATIC void GC_add_to_fl(struct hblk *h, hdr *hhdr) GC_INNER int GC_unmap_threshold = MUNMAP_THRESHOLD; +#ifdef COUNT_UNMAPPED_REGIONS + /* GC_unmap_old will avoid creating more than this many unmapped regions, */ + /* but an unmapped region may be split again so exceeding the limit. */ + + /* Return the change in number of unmapped regions if the block h swaps */ + /* from its current state of mapped/unmapped to the opposite state. */ + static int calc_num_unmapped_regions_delta(struct hblk *h, hdr *hhdr) + { + struct hblk * prev = get_block_ending_at(h); + struct hblk * next; + GC_bool prev_unmapped = FALSE; + GC_bool next_unmapped = FALSE; + + next = GC_next_block((struct hblk *)((ptr_t)h + hhdr->hb_sz), TRUE); + /* Ensure next is contiguous with h. */ + if ((ptr_t)next != GC_unmap_end((ptr_t)h, (size_t)hhdr->hb_sz)) { + next = NULL; + } + if (prev != NULL) { + hdr * prevhdr = HDR(prev); + prev_unmapped = !IS_MAPPED(prevhdr); + } + if (next != NULL) { + hdr * nexthdr = HDR(next); + next_unmapped = !IS_MAPPED(nexthdr); + } + + if (prev_unmapped && next_unmapped) { + /* If h unmapped, merge two unmapped regions into one. */ + /* If h remapped, split one unmapped region into two. */ + return IS_MAPPED(hhdr) ? -1 : 1; + } + if (!prev_unmapped && !next_unmapped) { + /* If h unmapped, create an isolated unmapped region. */ + /* If h remapped, remove it. */ + return IS_MAPPED(hhdr) ? 1 : -1; + } + /* If h unmapped, merge it with previous or next unmapped region. */ + /* If h remapped, reduce either previous or next unmapped region. */ + /* In either way, no change to the number of unmapped regions. */ + return 0; + } +#endif /* COUNT_UNMAPPED_REGIONS */ + +/* Update GC_num_unmapped_regions assuming the block h changes */ +/* from its current state of mapped/unmapped to the opposite state. */ +GC_INLINE void GC_adjust_num_unmapped(struct hblk *h GC_ATTR_UNUSED, + hdr *hhdr GC_ATTR_UNUSED) +{ +# ifdef COUNT_UNMAPPED_REGIONS + GC_num_unmapped_regions += calc_num_unmapped_regions_delta(h, hhdr); +# endif +} + /* Unmap blocks that haven't been recently touched. This is the only way */ /* way blocks are ever unmapped. */ GC_INNER void GC_unmap_old(void) @@ -403,6 +468,12 @@ GC_INNER void GC_unmap_old(void) if (GC_unmap_threshold == 0) return; /* unmapping disabled */ +# ifdef COUNT_UNMAPPED_REGIONS + /* Skip unmapping if we have already exceeded the soft limit. */ + /* This forgoes any opportunities to merge unmapped regions though. */ + if (GC_num_unmapped_regions >= GC_UNMAPPED_REGIONS_SOFT_LIMIT) + return; +# endif for (i = 0; i <= N_HBLK_FLS; ++i) { struct hblk * h; @@ -416,6 +487,19 @@ GC_INNER void GC_unmap_old(void) /* truncated counter value wrapping is handled correctly). */ if ((unsigned short)(GC_gc_no - hhdr->hb_last_reclaimed) > (unsigned short)GC_unmap_threshold) { +# ifdef COUNT_UNMAPPED_REGIONS + /* Continue with unmapping the block only if it will not */ + /* create too many unmapped regions, or if unmapping */ + /* reduces the number of regions. */ + int delta = calc_num_unmapped_regions_delta(h, hhdr); + signed_word regions = GC_num_unmapped_regions + delta; + + if (delta >= 0 && regions >= GC_UNMAPPED_REGIONS_SOFT_LIMIT) { + GC_COND_LOG_PRINTF("Unmapped regions limit reached!\n"); + return; + } + GC_num_unmapped_regions = regions; +# endif GC_unmap((ptr_t)h, (size_t)hhdr->hb_sz); hhdr -> hb_flags |= WAS_UNMAPPED; } @@ -472,17 +556,21 @@ GC_INNER void GC_merge_unmapped(void) if (IS_MAPPED(hhdr) && !IS_MAPPED(nexthdr)) { /* make both consistent, so that we can merge */ if (size > nextsize) { + GC_adjust_num_unmapped(next, nexthdr); GC_remap((ptr_t)next, nextsize); } else { + GC_adjust_num_unmapped(h, hhdr); GC_unmap((ptr_t)h, size); GC_unmap_gap((ptr_t)h, size, (ptr_t)next, nextsize); hhdr -> hb_flags |= WAS_UNMAPPED; } } else if (IS_MAPPED(nexthdr) && !IS_MAPPED(hhdr)) { if (size > nextsize) { + GC_adjust_num_unmapped(next, nexthdr); GC_unmap((ptr_t)next, nextsize); GC_unmap_gap((ptr_t)h, size, (ptr_t)next, nextsize); } else { + GC_adjust_num_unmapped(h, hhdr); GC_remap((ptr_t)h, size); hhdr -> hb_flags &= ~WAS_UNMAPPED; hhdr -> hb_last_reclaimed = nexthdr -> hb_last_reclaimed; @@ -731,6 +819,7 @@ GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n, int may_split) /* Make sure it's mapped before we mangle it. */ # ifdef USE_MUNMAP if (!IS_MAPPED(hhdr)) { + GC_adjust_num_unmapped(hbp, hhdr); GC_remap((ptr_t)hbp, (size_t)hhdr->hb_sz); hhdr -> hb_flags &= ~WAS_UNMAPPED; } @@ -805,6 +894,7 @@ GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n, int may_split) if( size_avail >= size_needed ) { # ifdef USE_MUNMAP if (!IS_MAPPED(hhdr)) { + GC_adjust_num_unmapped(hbp, hhdr); GC_remap((ptr_t)hbp, (size_t)hhdr->hb_sz); hhdr -> hb_flags &= ~WAS_UNMAPPED; /* Note: This may leave adjacent, mapped free blocks. */ diff --git a/gc/alloc.c b/gc/alloc.c index 06213ce86..d1525a05f 100644 --- a/gc/alloc.c +++ b/gc/alloc.c @@ -3,7 +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 + * Copyright (c) 2008-2019 Ivan Maidanski * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. @@ -124,7 +124,7 @@ const char * const GC_copyright[] = "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 ", +"Copyright (c) 2008-2019 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." }; @@ -173,7 +173,7 @@ GC_INNER int GC_CALLBACK GC_never_stop_func(void) #endif #ifndef NO_CLOCK - STATIC CLOCK_TYPE GC_start_time = 0; + STATIC CLOCK_TYPE GC_start_time = CLOCK_TYPE_INITIALIZER; /* Time at which we stopped world. */ /* used only in GC_timeout_stop_func. */ #endif @@ -349,7 +349,7 @@ STATIC void GC_clear_a_few_frames(void) /* Heap size at which we need a collection to avoid expanding past */ /* limits used by blacklisting. */ -STATIC word GC_collect_at_heapsize = (word)(-1); +STATIC word GC_collect_at_heapsize = GC_WORD_MAX; /* Have we allocated enough to amortize a collection? */ GC_INNER GC_bool GC_should_collect(void) @@ -485,7 +485,7 @@ GC_API GC_on_collection_event_proc GC_CALL GC_get_on_collection_event(void) GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func) { # ifndef NO_CLOCK - CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */ + CLOCK_TYPE start_time = CLOCK_TYPE_INITIALIZER; GC_bool start_time_valid; # endif @@ -715,7 +715,7 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func) { unsigned i; # ifndef NO_CLOCK - CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */ + CLOCK_TYPE start_time = CLOCK_TYPE_INITIALIZER; # endif GC_ASSERT(I_HOLD_LOCK()); @@ -984,7 +984,7 @@ GC_INLINE int GC_compute_heap_usage_percent(void) { word used = GC_composite_in_use + GC_atomic_in_use; word heap_sz = GC_heapsize - GC_unmapped_bytes; - return used >= heap_sz ? 0 : used < ((word)-1) / 100 ? + return used >= heap_sz ? 0 : used < GC_WORD_MAX / 100 ? (int)((used * 100) / heap_sz) : (int)(used / (heap_sz / 100)); } @@ -993,8 +993,8 @@ GC_INLINE int GC_compute_heap_usage_percent(void) STATIC void GC_finish_collection(void) { # ifndef NO_CLOCK - CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */ - CLOCK_TYPE finalize_time = 0; + CLOCK_TYPE start_time = CLOCK_TYPE_INITIALIZER; + CLOCK_TYPE finalize_time = CLOCK_TYPE_INITIALIZER; # endif GC_ASSERT(I_HOLD_LOCK()); @@ -1261,13 +1261,13 @@ GC_INNER void GC_add_to_heap(struct hblk *p, size_t bytes) GC_heapsize += bytes; /* Normally the caller calculates a new GC_collect_at_heapsize, - * but this is also called directly from alloc_mark_stack, so + * but this is also called directly from GC_scratch_recycle_inner, so * adjust here. It will be recalculated when called from * GC_expand_hp_inner. */ GC_collect_at_heapsize += bytes; if (GC_collect_at_heapsize < GC_heapsize /* wrapped */) - GC_collect_at_heapsize = (word)(-1); + GC_collect_at_heapsize = GC_WORD_MAX; if ((word)p <= (word)GC_least_plausible_heap_addr || GC_least_plausible_heap_addr == 0) { @@ -1307,7 +1307,7 @@ GC_INNER void GC_add_to_heap(struct hblk *p, size_t bytes) } #endif -void * GC_least_plausible_heap_addr = (void *)ONES; +void * GC_least_plausible_heap_addr = (void *)GC_WORD_MAX; void * GC_greatest_plausible_heap_addr = 0; GC_INLINE word GC_max(word x, word y) @@ -1388,7 +1388,7 @@ GC_INNER GC_bool GC_expand_hp_inner(word n) GC_collect_at_heapsize = GC_heapsize + expansion_slop - 2*MAXHINCR*HBLKSIZE; if (GC_collect_at_heapsize < GC_heapsize /* wrapped */) - GC_collect_at_heapsize = (word)(-1); + GC_collect_at_heapsize = GC_WORD_MAX; if (GC_on_heap_resize) (*GC_on_heap_resize)(GC_heapsize); @@ -1419,8 +1419,6 @@ 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 */ diff --git a/gc/backgraph.c b/gc/backgraph.c index 20047fb96..5565a35c2 100644 --- a/gc/backgraph.c +++ b/gc/backgraph.c @@ -32,7 +32,8 @@ /* #include */ -#if !defined(DBG_HDRS_ALL) || (ALIGNMENT != CPP_WORDSZ/8) /* || !defined(UNIX_LIKE) */ +#if (!defined(DBG_HDRS_ALL) || (ALIGNMENT != CPP_WORDSZ/8) \ + /* || !defined(UNIX_LIKE) */) && !defined(CPPCHECK) # error The configuration does not support MAKE_BACK_GRAPH #endif @@ -239,7 +240,7 @@ static void add_edge(ptr_t p, ptr_t q) if (((word)pred & FLAG_MANY) != 0) { n_edges = e -> n_edges; - } else if (pred != NULL && ((word)pred & 1) == 0) { + } else if (((word)pred & 1) == 0) { /* A misinterpreted freelist link. */ n_edges = 1; local = -1; @@ -399,7 +400,7 @@ static word backwards_height(ptr_t p) if (((word)pred & FLAG_MANY) != 0) { n_edges = e -> n_edges; - } else if (pred != NULL && ((word)pred & 1) == 0) { + } else if (((word)pred & 1) == 0) { /* A misinterpreted freelist link. */ n_edges = 1; local = -1; diff --git a/gc/bdw-gc.pc.in b/gc/bdw-gc.pc.in index ef4c23410..23678f430 100644 --- a/gc/bdw-gc.pc.in +++ b/gc/bdw-gc.pc.in @@ -6,5 +6,5 @@ includedir=@includedir@ Name: Boehm-Demers-Weiser Conservative Garbage Collector Description: A garbage collector for C and C++ Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lgc +Libs: -L${libdir} @ATOMIC_OPS_LIBS@ -lgc @THREADDLLIBS@ Cflags: -I${includedir} diff --git a/gc/blacklst.c b/gc/blacklst.c index 31511ae18..45d1ef40f 100644 --- a/gc/blacklst.c +++ b/gc/blacklst.c @@ -175,8 +175,7 @@ GC_INNER void GC_unpromote_black_lists(void) GC_copy_bl(GC_old_stack_bl, GC_incomplete_stack_bl); } -#if defined(set_pht_entry_from_index_concurrent) && defined(PARALLEL_MARK) \ - && defined(THREAD_SANITIZER) +#if defined(PARALLEL_MARK) && defined(THREAD_SANITIZER) # define backlist_set_pht_entry_from_index(db, index) \ set_pht_entry_from_index_concurrent(db, index) #else diff --git a/gc/build/s60v3/libgc.mmp b/gc/build/s60v3/libgc.mmp index 7fee8ad1a..a0dad4c8e 100644 --- a/gc/build/s60v3/libgc.mmp +++ b/gc/build/s60v3/libgc.mmp @@ -18,8 +18,10 @@ CAPABILITY PowerMgmt ReadDeviceData ReadUserData WriteDeviceData WriteUserData S MACRO ALL_INTERIOR_POINTERS MACRO NO_EXECUTE_PERMISSION MACRO USE_MMAP +MACRO GC_ATOMIC_UNCOLLECTABLE MACRO GC_DONT_REGISTER_MAIN_STATIC_DATA MACRO GC_DLL +MACRO JAVA_FINALIZATION MACRO SYMBIAN MACRO ENABLE_DISCLAIM //MACRO GC_GCJ_SUPPORT diff --git a/gc/configure.ac b/gc/configure.ac index 045a028a3..3b38e6fc8 100644 --- a/gc/configure.ac +++ b/gc/configure.ac @@ -1,6 +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 +# Copyright (c) 2009-2019 Ivan Maidanski # # THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED # OR IMPLIED. ANY USE IS AT YOUR OWN RISK. @@ -14,7 +14,7 @@ dnl Process this file with autoconf to produce configure. dnl Initialization. -AC_INIT(gc,8.0.0,https://github.com/ivmai/bdwgc/issues) +AC_INIT(gc,8.0.6,https://github.com/ivmai/bdwgc/issues) dnl Version must conform to: [0-9]+[.][0-9]+[.][0-9]+ AC_CONFIG_SRCDIR(gcj_mlc.c) @@ -22,7 +22,6 @@ AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_TARGET AC_PREREQ(2.61) GC_SET_VERSION -AC_CONFIG_AUX_DIR([.]) AM_INIT_AUTOMAKE([foreign nostdinc subdir-objects]) AC_CONFIG_HEADERS([include/config.h]) AM_MAINTAINER_MODE @@ -53,9 +52,9 @@ if test :"$GCC": = :yes: ; then gc_cflags="${gc_cflags} -fexceptions" else case "$host" in - hppa*-*-hpux* ) + hppa*-*-hpux* ) if test :$GCC: != :"yes": ; then - gc_cflags="${gc_flags} +ESdbgasm" + gc_cflags="${gc_cflags} +ESdbgasm" fi # :TODO: actually we should check using Autoconf if # the compiler supports this option. @@ -187,6 +186,8 @@ CFLAGS="$old_CFLAGS" THREADDLLIBS= need_atomic_ops_asm=false +use_parallel_mark=no +use_thread_local_alloc=no # Libraries needed to support dynamic loading and/or threads. case "$THREADS" in no | none | single) @@ -199,17 +200,13 @@ case "$THREADS" in case "$host" in *-*-aix* | *-*-android* | *-*-cygwin* | *-*-darwin* | *-*-dragonfly* | \ *-*-freebsd* | *-*-haiku* | *-*-hpux11* | *-*-irix* | \ - *-*-kfreebsd*-gnu | *-*-gnu* | *-*-*linux* | *-*-nacl* | \ + *-*-kfreebsd*-gnu | *-*-gnu* | *-*-*linux* | *-*-msys* | *-*-nacl* | \ *-*-netbsd* | *-*-openbsd* | *-*-osf* | *-*-solaris*) AC_DEFINE(GC_THREADS) AC_DEFINE([_REENTRANT], [1], [Required define if using POSIX threads.]) - if test "${enable_parallel_mark}" != no; then - AC_DEFINE(PARALLEL_MARK) - fi - if test "${enable_thread_local_alloc}" != no; then - AC_DEFINE(THREAD_LOCAL_ALLOC) - fi + use_parallel_mark=$enable_parallel_mark + use_thread_local_alloc=$enable_thread_local_alloc default_threadlibs=true AC_MSG_WARN("Explicit GC_INIT() calls may be required.") ;; @@ -244,7 +241,7 @@ case "$THREADS" in *-*-solaris*) THREADDLLIBS="-lpthread -lrt" ;; - *-*-cygwin*) + *-*-cygwin* | *-*-msys*) # Cygwin doesn't have a real libpthread, so Libtool can't link # against it. THREADDLLIBS="" @@ -253,13 +250,9 @@ case "$THREADS" in *-*-mingw*) AC_DEFINE(GC_WIN32_PTHREADS) # Using pthreads-win32 (or other non-Cygwin pthreads) library. - if test "${enable_parallel_mark}" != no; then - AC_DEFINE(PARALLEL_MARK) - fi - if test "${enable_thread_local_alloc}" != no; then - AC_DEFINE(THREAD_LOCAL_ALLOC) - fi THREADDLLIBS="-lpthread" + use_parallel_mark=$enable_parallel_mark + use_thread_local_alloc=$enable_thread_local_alloc win32_threads=true ;; *-*-darwin*) @@ -286,15 +279,11 @@ case "$THREADS" in ;; win32) AC_DEFINE(GC_THREADS) - if test "${enable_parallel_mark}" != no; then - AC_DEFINE(PARALLEL_MARK) - fi - if test "${enable_thread_local_alloc}" != no; then - if test "${enable_parallel_mark}" != no \ - -o "${enable_shared}" != yes -o "${enable_static}" != no; then - # Imply THREAD_LOCAL_ALLOC unless GC_DLL. - AC_DEFINE(THREAD_LOCAL_ALLOC) - fi + use_parallel_mark=$enable_parallel_mark + if test "${enable_parallel_mark}" != no \ + -o "${enable_shared}" != yes -o "${enable_static}" != no; then + # Imply THREAD_LOCAL_ALLOC unless GC_DLL. + use_thread_local_alloc=$enable_thread_local_alloc fi if test "${enable_win32_dllmain}" = yes; then AC_DEFINE(GC_INSIDE_DLL, 1, @@ -310,12 +299,8 @@ case "$THREADS" in AC_MSG_RESULT($THREADDLLIBS) # Use pthread GCC switch THREADDLLIBS=-pthread - if test "${enable_parallel_mark}" != no; then - AC_DEFINE(PARALLEL_MARK) - fi - if test "${enable_thread_local_alloc}" != no; then - AC_DEFINE(THREAD_LOCAL_ALLOC) - fi + use_parallel_mark=$enable_parallel_mark + use_thread_local_alloc=$enable_thread_local_alloc AC_MSG_WARN("Explicit GC_INIT() calls may be required.") AM_CFLAGS="-pthread $AM_CFLAGS" ;; @@ -324,22 +309,14 @@ case "$THREADS" in THREADDLLIBS=-lpthread AC_DEFINE(GC_THREADS) AC_DEFINE(_REENTRANT) - if test "${enable_parallel_mark}" != no; then - AC_DEFINE(PARALLEL_MARK) - fi - if test "${enable_thread_local_alloc}" != no; then - AC_DEFINE(THREAD_LOCAL_ALLOC) - fi + use_parallel_mark=$enable_parallel_mark + use_thread_local_alloc=$enable_thread_local_alloc ;; rtems) THREADS=posix AC_DEFINE(GC_THREADS) - if test "${enable_parallel_mark}" != no; then - AC_DEFINE(PARALLEL_MARK) - fi - if test "${enable_thread_local_alloc}" != no; then - AC_DEFINE(THREAD_LOCAL_ALLOC) - fi + use_parallel_mark=$enable_parallel_mark + use_thread_local_alloc=$enable_thread_local_alloc ;; decosf1 | irix | mach | os2 | solaris | dce | vxworks) AC_MSG_ERROR(thread package $THREADS not yet supported) @@ -353,8 +330,6 @@ AM_CONDITIONAL(THREADS, test x$THREADS != xnone) AM_CONDITIONAL(PTHREADS, test x$THREADS = xposix) AM_CONDITIONAL(DARWIN_THREADS, test x$darwin_threads = xtrue) AM_CONDITIONAL(WIN32_THREADS, test x$win32_threads = xtrue) -AM_CONDITIONAL(THREAD_LOCAL_ALLOC, - test x$enable_thread_local_alloc != xno -a x$THREADS != xnone) compiler_suncc=no pthread_start_standalone=no @@ -403,6 +378,7 @@ if test "$GCC" = yes; then AS_IF([test "$ac_cv_cc_pedantic" = yes], [WPEDANTIC="-Wpedantic -Wno-long-long"]) CFLAGS="-Wall $WEXTRA $WPEDANTIC $CFLAGS" + CXXFLAGS="-Wall $WEXTRA $WPEDANTIC $CXXFLAGS" fi AC_MSG_CHECKING(for xlc) @@ -459,8 +435,8 @@ case "$host" in mips-sgi-irix6*) ;; # We never want libdl on darwin. It is a fake libdl that just ends up making # dyld calls anyway. The same applies to Cygwin. - *-*-darwin*) ;; - *-*-cygwin*) ;; + *-*-cygwin* | *-*-darwin* | *-*-msys*) + ;; *) AC_CHECK_LIB(dl, dlopen, THREADDLLIBS="$THREADDLLIBS -ldl") ;; @@ -482,14 +458,14 @@ AC_CHECK_HEADER([execinfo.h], [], # extra LD Flags which are required for targets case "${host}" in *-*-darwin*) - extra_ldflags_libomcgc=-Wl,-single_module + extra_ldflags_libgc=-Wl,-single_module ;; esac -AC_SUBST(extra_ldflags_libomcgc) +AC_SUBST(extra_ldflags_libgc) AC_SUBST(EXTRA_TEST_LIBS) -target_all=libomcgc.la +target_all=libgc.la AC_SUBST(target_all) dnl If the target is an eCos system, use the appropriate eCos @@ -521,7 +497,7 @@ AM_CONDITIONAL(CPLUSPLUS, test "${enable_cplusplus}" = yes) if test "$GCC" = yes; then if test "${enable_cplusplus}" = yes; then case "$host" in - *-*-cygwin* | *-*-mingw*) + *-*-cygwin* | *-*-mingw* | *-*-msys*) AC_MSG_CHECKING([whether libsupc++ required]) SUPC="`$CXX -print-file-name=libsupc++.a 2>/dev/null`" if test -n "$SUPC" -a "$SUPC" != "libsupc++.a"; then @@ -556,8 +532,7 @@ esac AC_MSG_RESULT($enable_shared) # Compile with GC_DLL defined unless building static libraries. -if test "${enable_shared}" = yes; then - if test "${enable_static}" = no; then +if test "${enable_shared}" = yes -a "${enable_static}" = no; then AC_DEFINE(GC_DLL) if test "$GCC" = yes; then # Pass -fvisibility=hidden option if supported @@ -572,7 +547,16 @@ if test "${enable_shared}" = yes; then [CFLAGS="-DGC_NO_VISIBILITY $CFLAGS"]) AC_MSG_RESULT($ac_cv_fvisibility_hidden) fi - fi +else + + case "$host" in + *-*-cygwin* | *-*-mingw* | *-*-msys*) + # Use inline version of GC new and delete operators in test_cpp + # otherwise the system ones might be used instead because of arbitrary + # ordering of object files when linking. + CXXFLAGS="$CXXFLAGS -DGC_NOT_DLL" + ;; + esac fi # Configuration of machine-dependent code @@ -642,10 +626,9 @@ if false; then AC_EXEEXT fi -dnl As of 4.13a2, the collector will not properly work on Solaris when +dnl The collector might not properly work on IBM AIX when dnl built with gcc and -O. So we remove -O in the appropriate case. -dnl Not needed anymore on Solaris. -AC_MSG_CHECKING(whether Solaris gcc optimization fix is necessary) +AC_MSG_CHECKING(whether AIX gcc optimization fix is necessary) case "$host" in *aix*) if test "$GCC" = yes; then @@ -856,40 +839,6 @@ if test "${enable_large_config}" = yes; then [Define to optimize for large heaps or root sets.]) fi -AC_ARG_ENABLE(handle-fork, - [AC_HELP_STRING([--enable-handle-fork[=yes|no|auto|manual]], - [attempt to ensure a usable collector after fork() - in multi-threaded programs (default: auto; - manual: GC_atfork_prepare/parent/child should be - called by the client)])]) -if test "${enable_handle_fork}" = yes; then - AC_DEFINE(HANDLE_FORK, 1, - [Define to install pthread_atfork() handlers by default.]) -elif test "${enable_handle_fork}" = no; then - AC_DEFINE(NO_HANDLE_FORK, 1, - [Prohibit installation of pthread_atfork() handlers.]) -elif test "${enable_handle_fork}" != manual -a x$THREADS = xposix; then - # If the option is omitted, pthread_atfork handlers are installed - # by default for the targets where pthread_atfork is known to work. - case "$host" in - *-*-android*) - # Android NDK does not provide pthread_atfork. - ;; - *-*-darwin*) - # The incremental mode (which is off if parallel marking) conflicts - # with fork handling on Darwin. - if test "${enable_parallel_mark}" != no; then - AC_DEFINE(HANDLE_FORK) - fi - ;; - *-*-aix* | *-*-cygwin* | *-*-freebsd* | *-*-haiku* | \ - *-*-hpux11* | *-*-irix* | *-*-kfreebsd*-gnu | \ - *-*-*linux* | *-*-netbsd* | *-*-openbsd* | *-*-osf* | *-*-solaris*) - AC_DEFINE(HANDLE_FORK) - ;; - esac -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 targeting an embedded system. FIXME. @@ -1022,6 +971,8 @@ AC_ARG_ENABLE(docs, [do not build and install documentation])]) AM_CONDITIONAL(ENABLE_DOCS, test x$enable_docs != xno) +AM_CONDITIONAL(ENABLE_SHARED, test x$enable_shared = xyes) + # Atomic Ops # ---------- @@ -1081,13 +1032,17 @@ AS_IF([test x"$with_libatomic_ops" = xno \ AC_MSG_CHECKING([which libatomic_ops to use]) AS_IF([test x"$with_libatomic_ops" != xno], [ AS_IF([test x"$with_libatomic_ops" != xnone -a x"$THREADS" != xnone], - [ AC_MSG_RESULT([external]) ], + [ AC_MSG_RESULT([external]) + ATOMIC_OPS_LIBS="-latomic_ops" + AC_SUBST([ATOMIC_OPS_LIBS]) ], [ AC_MSG_RESULT([none]) AS_IF([test x"$THREADS" != xnone], [ AC_DEFINE([GC_BUILTIN_ATOMIC], [1], [Use C11 (GCC) atomic intrinsics instead of - libatomic_ops primitives.]) ]) ]) ], + libatomic_ops primitives.]) ]) ]) + AO_TRYLINK_CFLAGS="" ], [ AC_MSG_RESULT([internal]) + AO_TRYLINK_CFLAGS="-I${srcdir}/libatomic_ops/src" ATOMIC_OPS_CFLAGS='-I$(top_builddir)/libatomic_ops/src -I$(top_srcdir)/libatomic_ops/src' ATOMIC_OPS_LIBS="" AC_SUBST([ATOMIC_OPS_CFLAGS]) @@ -1098,6 +1053,84 @@ AM_CONDITIONAL([USE_INTERNAL_LIBATOMIC_OPS], AM_CONDITIONAL([NEED_ATOMIC_OPS_ASM], [test x$with_libatomic_ops = xno -a x$need_atomic_ops_asm = xtrue]) +# Check whether particular AO primitives are emulated with locks. +# The check below is based on the fact that linking with the libatomic_ops +# binary file is not needed in case of absence of the emulation (except for +# Solaris SPARC). +AS_IF([test x$with_libatomic_ops != xnone -a x$need_atomic_ops_asm != xtrue], + [ old_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $AO_TRYLINK_CFLAGS $CFLAGS_EXTRA" + AC_MSG_CHECKING([for lock-free AO_or primitive]) + AC_TRY_LINK([#include "atomic_ops.h"], + [AO_t x=0;AO_or(&x,1)], + [ AC_MSG_RESULT(yes) + AC_DEFINE([HAVE_LOCKFREE_AO_OR], [1], + [libatomic_ops AO_or primitive implementation is lock-free.]) ], + [ AC_MSG_RESULT(no) ]) + AC_MSG_CHECKING([for lock-free AO load/store, test-and-set primitives]) + AC_TRY_LINK([#include "atomic_ops.h"], + [AO_t x=0;unsigned char c=0;AO_TS_t z=AO_TS_INITIALIZER; + (void)AO_test_and_set_acquire(&z);AO_CLEAR(&z);AO_compiler_barrier(); + AO_store(&x,AO_load(&x)+1);AO_char_store(&c,AO_char_load(&c)+1); + AO_store_release(&x,AO_load_acquire(&x)+1)], + [ AC_MSG_RESULT(yes) ], + [ AC_MSG_RESULT(no) + use_thread_local_alloc=no + AC_DEFINE([BASE_ATOMIC_OPS_EMULATED], [1], + [AO load, store and/or test-and-set primitives are + implemented in libatomic_ops using locks.]) ]) + AS_IF([test x$use_parallel_mark != xno], + [ AC_MSG_CHECKING( + [for lock-free compare-and-swap and fetch-and-add primitives]) + AC_TRY_LINK( + [#define AO_REQUIRE_CAS + #include "atomic_ops.h"], + [AO_t x=0;(void)AO_fetch_and_add(&x,1);(void)AO_compare_and_swap(&x,1,2)], + [ AC_MSG_RESULT(yes) ], + [ AC_MSG_RESULT(no) + use_parallel_mark=no ]) ]) + CFLAGS="$old_CFLAGS" ]) + +AS_IF([test x$use_parallel_mark != xno], + [ AC_DEFINE(PARALLEL_MARK) ]) +AS_IF([test x$use_thread_local_alloc != xno], + [ AC_DEFINE(THREAD_LOCAL_ALLOC) ]) +AM_CONDITIONAL(THREAD_LOCAL_ALLOC, test x$use_thread_local_alloc != xno) + +AC_ARG_ENABLE(handle-fork, + [ AC_HELP_STRING([--enable-handle-fork[=yes|no|auto|manual]], + [attempt to ensure a usable collector after fork() + in multi-threaded programs (default: auto; + manual: GC_atfork_prepare/parent/child should be + called by the client)]) ]) +if test "${enable_handle_fork}" = yes; then + AC_DEFINE(HANDLE_FORK, 1, + [Define to install pthread_atfork() handlers by default.]) +elif test "${enable_handle_fork}" = no; then + AC_DEFINE(NO_HANDLE_FORK, 1, + [Prohibit installation of pthread_atfork() handlers.]) +elif test "${enable_handle_fork}" != manual -a x$THREADS = xposix; then + # If the option is omitted, pthread_atfork handlers are installed + # by default for the targets where pthread_atfork is known to work. + case "$host" in + *-*-android*) + # Android NDK does not provide pthread_atfork. + ;; + *-*-darwin*) + # The incremental mode (which is off if parallel marking) conflicts + # with fork handling on Darwin. + if test x$use_parallel_mark != xno; then + AC_DEFINE(HANDLE_FORK) + fi + ;; + *-*-aix* | *-*-cygwin* | *-*-freebsd* | *-*-haiku* | \ + *-*-hpux11* | *-*-irix* | *-*-kfreebsd*-gnu | \ + *-*-*linux* | *-*-netbsd* | *-*-openbsd* | *-*-osf* | *-*-solaris*) + AC_DEFINE(HANDLE_FORK) + ;; + esac +fi + dnl Produce the Files dnl ----------------- diff --git a/gc/cord/cord.am b/gc/cord/cord.am index e80e06fb1..c2ea532df 100644 --- a/gc/cord/cord.am +++ b/gc/cord/cord.am @@ -7,7 +7,7 @@ LIBCORD_VER_INFO = 5:0:4 lib_LTLIBRARIES += libcord.la -libcord_la_LIBADD = $(top_builddir)/libomcgc.la +libcord_la_LIBADD = $(top_builddir)/libgc.la libcord_la_LDFLAGS = -version-info $(LIBCORD_VER_INFO) -no-undefined libcord_la_CPPFLAGS = $(AM_CPPFLAGS) @@ -19,7 +19,13 @@ libcord_la_SOURCES = \ TESTS += cordtest$(EXEEXT) check_PROGRAMS += cordtest cordtest_SOURCES = cord/tests/cordtest.c -cordtest_LDADD = $(top_builddir)/libomcgc.la $(top_builddir)/libcord.la +cordtest_LDADD = $(top_builddir)/libcord.la + +## In case of static libraries build, libgc.a is already referenced in +## dependency_libs attribute of libcord.la file. +if ENABLE_SHARED +cordtest_LDADD += $(top_builddir)/libgc.la +endif EXTRA_DIST += \ cord/tests/de.c \ diff --git a/gc/cord/cordbscs.c b/gc/cord/cordbscs.c index ff0d23997..1b4ec28b3 100644 --- a/gc/cord/cordbscs.c +++ b/gc/cord/cordbscs.c @@ -170,7 +170,13 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny) char * result = (char *)GC_MALLOC_ATOMIC(result_len + 1); if (result == 0) OUT_OF_MEMORY; - memcpy(result, x, lenx); +# ifdef LINT2 + memcpy(result, x, lenx + 1); +# else + memcpy(result, x, lenx); + /* No need to copy the terminating zero */ + /* as result[lenx] is written below. */ +# endif memcpy(result + lenx, y, leny); result[result_len] = '\0'; return((CORD) result); @@ -774,19 +780,30 @@ void CORD__extend_path(CORD_pos p) char CORD__pos_fetch(CORD_pos p) { /* Leaf is a function node */ - struct CORD_pe * pe = &((p)[0].path[(p)[0].path_len]); - CORD leaf = pe -> pe_cord; - struct Function * f = &(((CordRep *)leaf) -> function); - - if (!IS_FUNCTION(leaf)) ABORT("CORD_pos_fetch: bad leaf"); + struct CORD_pe * pe; + CORD leaf; + struct Function * f; + + if (!CORD_pos_valid(p)) + ABORT("CORD_pos_fetch: invalid argument"); + pe = &p[0].path[p[0].path_len]; + leaf = pe -> pe_cord; + if (!IS_FUNCTION(leaf)) + ABORT("CORD_pos_fetch: bad leaf"); + f = &((CordRep *)leaf)->function; return ((*(f -> fn))(p[0].cur_pos - pe -> pe_start_pos, f -> client_data)); } void CORD__next(CORD_pos p) { size_t cur_pos = p[0].cur_pos + 1; - struct CORD_pe * current_pe = &((p)[0].path[(p)[0].path_len]); - CORD leaf = current_pe -> pe_cord; + struct CORD_pe * current_pe; + CORD leaf; + + if (!CORD_pos_valid(p)) + ABORT("CORD_next: invalid argument"); + current_pe = &p[0].path[p[0].path_len]; + leaf = current_pe -> pe_cord; /* Leaf is not a string or we're at end of leaf */ p[0].cur_pos = cur_pos; diff --git a/gc/cord/cordprnt.c b/gc/cord/cordprnt.c index d9d9f5365..7eaf3723a 100644 --- a/gc/cord/cordprnt.c +++ b/gc/cord/cordprnt.c @@ -52,7 +52,7 @@ static int ec_len(CORD_ec x) { - return(CORD_len(x[0].ec_cord) + (x[0].ec_bufptr - x[0].ec_buf)); + return (int)(CORD_len(x[0].ec_cord) + (x[0].ec_bufptr - x[0].ec_buf)); } /* Possible nonumeric precision values. */ @@ -232,7 +232,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args) } else { short * pos_ptr; pos_ptr = va_arg(args, short *); - *pos_ptr = ec_len(result); + *pos_ptr = (short)ec_len(result); } goto done; case 'r': @@ -241,18 +241,18 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args) if (prec == VARIABLE) prec = va_arg(args, int); arg = va_arg(args, CORD); len = CORD_len(arg); - if (prec != NONE && len > (size_t)prec) { + if (prec != NONE && len > (unsigned)prec) { if (prec < 0) return(-1); - arg = CORD_substr(arg, 0, prec); + arg = CORD_substr(arg, 0, (unsigned)prec); len = (unsigned)prec; } - if (width != NONE && len < (size_t)width) { - char * blanks = - (char *)GC_MALLOC_ATOMIC(width - len + 1); + if (width != NONE && len < (unsigned)width) { + char * blanks = (char *)GC_MALLOC_ATOMIC( + (unsigned)width - len + 1); if (NULL == blanks) OUT_OF_MEMORY; - memset(blanks, ' ', width-len); - blanks[width-len] = '\0'; + memset(blanks, ' ', (unsigned)width - len); + blanks[(unsigned)width - len] = '\0'; if (left_adj) { arg = CORD_cat(arg, blanks); } else { @@ -307,7 +307,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args) if (prec != NONE && prec > max_size) max_size = prec; max_size += CONV_RESULT_LEN; if (max_size >= CORD_BUFSZ) { - buf = (char *)GC_MALLOC_ATOMIC(max_size + 1); + buf = (char *)GC_MALLOC_ATOMIC((unsigned)max_size + 1); if (NULL == buf) OUT_OF_MEMORY; } else { if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf) @@ -352,7 +352,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args) && !defined(__EMX__)) va_end(vsprintf_args); # endif - len = (size_t)res; + len = (unsigned)res; if ((char *)(GC_word)res == buf) { /* old style vsprintf */ len = strlen(buf); diff --git a/gc/cord/tests/cordtest.c b/gc/cord/tests/cordtest.c index c3ad01f42..a41600c0f 100644 --- a/gc/cord/tests/cordtest.c +++ b/gc/cord/tests/cordtest.c @@ -40,7 +40,8 @@ int count; int test_fn(char c, void * client_data) { - if (client_data != (void *)13) ABORT("bad client data"); + if (client_data != (void *)(GC_word)13) + ABORT("bad client data"); if (count < 64*1024+1) { if ((count & 1) == 0) { if (c != 'b') ABORT("bad char"); @@ -65,7 +66,7 @@ char id_cord_fn(size_t i, void * client_data) void test_basics(void) { CORD x = CORD_from_char_star("ab"); - int i; + size_t i; CORD y; CORD_pos p; @@ -81,7 +82,8 @@ void test_basics(void) if (CORD_len(x) != 128*1024+1) ABORT("bad length"); count = 0; - if (CORD_iter5(x, 64*1024-1, test_fn, CORD_NO_FN, (void *)13) == 0) { + if (CORD_iter5(x, 64*1024-1, test_fn, CORD_NO_FN, + (void *)(GC_word)13) == 0) { ABORT("CORD_iter5 failed"); } if (count != 64*1024 + 2) ABORT("CORD_iter5 failed"); @@ -89,7 +91,7 @@ void test_basics(void) count = 0; CORD_set_pos(p, x, 64*1024-1); while(CORD_pos_valid(p)) { - (void) test_fn(CORD_pos_fetch(p), (void *)13); + (void)test_fn(CORD_pos_fetch(p), (void *)(GC_word)13); CORD_next(p); } if (count != 64*1024 + 2) ABORT("Position based iteration failed"); @@ -113,7 +115,8 @@ void test_basics(void) if (CORD_len(x) != 128*1024+1) ABORT("bad length"); count = 0; - if (CORD_iter5(x, 64*1024-1, test_fn, CORD_NO_FN, (void *)13) == 0) { + if (CORD_iter5(x, 64*1024-1, test_fn, CORD_NO_FN, + (void *)(GC_word)13) == 0) { ABORT("CORD_iter5 failed"); } if (count != 64*1024 + 2) ABORT("CORD_iter5 failed"); @@ -128,7 +131,8 @@ void test_basics(void) while(CORD_pos_valid(p)) { char c = CORD_pos_fetch(p); - if(c != i) ABORT("Traversal of function node failed"); + if ((size_t)(unsigned char)c != i) + ABORT("Traversal of function node failed"); CORD_next(p); i++; } @@ -311,6 +315,8 @@ int main(void) # ifndef NO_INCREMENTAL GC_enable_incremental(); # endif + if (GC_get_find_leak()) + printf("This test program is not designed for leak detection mode\n"); test_basics(); test_extras(); test_printf(); diff --git a/gc/cord/tests/de.c b/gc/cord/tests/de.c index 0d0dc5f49..2707405a1 100644 --- a/gc/cord/tests/de.c +++ b/gc/cord/tests/de.c @@ -596,6 +596,7 @@ int main(int argc, char **argv) cshow(stdout); argc = ccommand(&argv); # endif + GC_set_find_leak(0); /* app is not for testing leak detection mode */ GC_INIT(); # ifndef NO_INCREMENTAL GC_enable_incremental(); diff --git a/gc/cord/tests/de_win.c b/gc/cord/tests/de_win.c index 62cff6525..82f4c71d9 100644 --- a/gc/cord/tests/de_win.c +++ b/gc/cord/tests/de_win.c @@ -18,6 +18,8 @@ * * This was written by a nonexpert windows programmer. */ +#if defined(__BORLANDC__) || defined(__CYGWIN__) || defined(__MINGW32__) \ + || defined(__NT__) || defined(_WIN32) || defined(WIN32) #ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN 1 @@ -51,6 +53,7 @@ int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, WNDCLASS wndclass; HACCEL hAccel; + GC_set_find_leak(0); GC_INIT(); # ifndef NO_INCREMENTAL GC_enable_incremental(); @@ -144,7 +147,7 @@ char * plain_chars(char * text, size_t len) } /* Return the argument with all non-control-characters replaced by */ -/* blank, and all control characters c replaced by c + 32. */ +/* blank, and all control characters c replaced by c + 64. */ char * control_chars(char * text, size_t len) { char * result = (char *)GC_MALLOC_ATOMIC(len + 1); @@ -153,7 +156,7 @@ char * control_chars(char * text, size_t len) if (NULL == result) return NULL; for (i = 0; i < len; i++) { if (iscntrl(((unsigned char *)text)[i])) { - result[i] = text[i] + 0x40; + result[i] = (char)(text[i] + 0x40); } else { result[i] = ' '; } @@ -374,3 +377,11 @@ void invalidate_line(int i) get_line_rect(i, COLS*char_width, &line_r); InvalidateRect(hwnd, &line_r, FALSE); } + +#else + + extern int GC_quiet; + /* ANSI C doesn't allow translation units to be empty. */ + /* So we guarantee this one is nonempty. */ + +#endif /* !WIN32 */ diff --git a/gc/darwin_stop_world.c b/gc/darwin_stop_world.c index ab0be9d8f..3dbaa3fb7 100644 --- a/gc/darwin_stop_world.c +++ b/gc/darwin_stop_world.c @@ -196,10 +196,12 @@ STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p, /* else */ { mach_msg_type_number_t thread_state_count = GC_MACH_THREAD_STATE_COUNT; - /* Get the thread state (registers, etc) */ - kern_result = thread_get_state(thread, GC_MACH_THREAD_STATE, - (natural_t *)&state, - &thread_state_count); + /* Get the thread state (registers, etc.) */ + do { + kern_result = thread_get_state(thread, GC_MACH_THREAD_STATE, + (natural_t *)&state, + &thread_state_count); + } while (kern_result == KERN_ABORTED); } # ifdef DEBUG_THREADS GC_log_printf("thread_get_state returns value = %d\n", kern_result); @@ -656,7 +658,8 @@ GC_INLINE void GC_thread_resume(thread_act_t thread) kern_return_t kern_result; # if defined(DEBUG_THREADS) || defined(GC_ASSERTIONS) struct thread_basic_info info; - mach_msg_type_number_t outCount = THREAD_INFO_MAX; + mach_msg_type_number_t outCount = THREAD_BASIC_INFO_COUNT; + kern_result = thread_info(thread, THREAD_BASIC_INFO, (thread_info_t)&info, &outCount); if (kern_result != KERN_SUCCESS) diff --git a/gc/dbg_mlc.c b/gc/dbg_mlc.c index 4d547c150..920da6ce0 100644 --- a/gc/dbg_mlc.c +++ b/gc/dbg_mlc.c @@ -287,7 +287,7 @@ GC_INNER void *GC_store_debug_info_inner(void *p, word sz GC_ATTR_UNUSED, ((oh *)p) -> oh_bg_ptr = HIDE_BACK_PTR((ptr_t)0); # endif ((oh *)p) -> oh_string = string; - ((oh *)p) -> oh_int = (word)linenum; + ((oh *)p) -> oh_int = linenum; # ifndef SHORT_DBG_HDRS ((oh *)p) -> oh_sz = sz; ((oh *)p) -> oh_sf = START_FLAG ^ (word)result; diff --git a/gc/digimars.mak b/gc/digimars.mak index 40d6e143e..1388d3539 100644 --- a/gc/digimars.mak +++ b/gc/digimars.mak @@ -2,7 +2,7 @@ # compiler from www.digitalmars.com # Written by Walter Bright -DEFINES=-D_WINDOWS -DGC_DLL -DGC_THREADS -DGC_DISCOVER_TASK_THREADS -DALL_INTERIOR_POINTERS -DENABLE_DISCLAIM +DEFINES=-D_WINDOWS -DGC_DLL -DGC_THREADS -DGC_DISCOVER_TASK_THREADS -DALL_INTERIOR_POINTERS -DENABLE_DISCLAIM -DGC_ATOMIC_UNCOLLECTABLE -DGC_GCJ_SUPPORT -DJAVA_FINALIZATION -DNO_EXECUTE_PERMISSION -DUSE_MUNMAP CFLAGS=-Iinclude -Ilibatomic_ops\src $(DEFINES) -wx -g LFLAGS=/ma/implib/co CC=sc @@ -23,6 +23,7 @@ OBJS= \ dyn_load.obj\ finalize.obj\ gc_cpp.obj\ + gcj_mlc.obj\ headers.obj\ mach_dep.obj\ malloc.obj\ diff --git a/gc/doc/README.OS2 b/gc/doc/README.OS2 index 5345bbd0f..5aaf84c04 100644 --- a/gc/doc/README.OS2 +++ b/gc/doc/README.OS2 @@ -2,5 +2,5 @@ The code assumes static linking, and a single thread. The editor de has not been ported. The cord test program has. The supplied OS2_MAKEFILE assumes the IBM C Set/2 environment, but the code shouldn't. -Since we haven't figured out hoe to do perform partial links or to build static +Since we haven't figured out how to do partial linking or to build static libraries, clients currently need to link against a long list of executables. diff --git a/gc/doc/README.amiga b/gc/doc/README.amiga index d97251fb4..65ade9a0a 100644 --- a/gc/doc/README.amiga +++ b/gc/doc/README.amiga @@ -9,15 +9,15 @@ updated 'Makefile', and hope it compiles fine. WHATS NEW: 1. - Made a pretty big effort in preventing GCs allocating-functions from returning - chip-mem. + Made a pretty big effort in preventing GC allocating-functions from + returning chip-mem. The lower part of the new file AmigaOS.c does this in various ways, mainly by wrapping GC_malloc, GC_malloc_atomic, GC_malloc_uncollectable, GC_malloc_atomic_uncollectable, GC_malloc_ignore_off_page and GC_malloc_atomic_ignore_off_page. GC_realloc is also wrapped, but doesn't do the same effort in preventing to return chip-mem. - Other allocating-functions (f.ex. GC_*_typed_) can probably be + Other allocating-functions (e.g., GC_*_typed) can probably be used without any problems, but beware that the warn hook will not be called. In case of problems, don't define GC_AMIGA_FASTALLOC. @@ -81,7 +81,7 @@ WHATS NEW: GC_AMIGA_FASTALLOC by letting the function go thru the new GC_amiga_allocwrapper_do function-pointer (see gc.h). Means that sending function-pointers, such as GC_malloc, GC_malloc_atomic, etc., - for later to be called like f.ex this, (*GC_malloc_function_pointer)(size), + for later to be called, e.g., like this, (*GC_malloc_function_pointer)(size), will not wrap the function. This is normally not a big problem, unless all allocation function is called like this, which will cause the atexit un-allocating function never to be called. Then you either @@ -91,7 +91,7 @@ WHATS NEW: There are probably better ways this problem could be handled, unfortunately, I didn't find any without rewriting or replacing a lot of the GC-code, which I really didn't want to. (Making new GC_malloc_* functions, and just - define f.ex GC_malloc as GC_amiga_malloc should work too). + defining, e.g., GC_malloc as GC_amiga_malloc should work too). New Amiga-specific function: @@ -99,16 +99,16 @@ WHATS NEW: void GC_amiga_set_toany(void (*func)(void)); 'func' is a function that will be called right before gc has to change - allocation-method from MEMF_FAST to MEMF_ANY. Ie. when it is likely + allocation-method from MEMF_FAST to MEMF_ANY. I.e., when it is likely it will return chip-mem. 2. A few small compiler-specific additions to make it compile with SAS/C again. -3. Updated and rewritten the smakefile, so that it works again and that +3. Updated and rewritten the SMakefile.amiga, so that it works again and that the "unnecessary" 'SCOPTIONS' files could be removed. Also included the cord-smakefile stuff in the main smakefile, so that the cord smakefile - could be removed too. By writing smake -f Smakefile.smk, both gc.lib and + could be removed too. By typing "smake -f SMakefile.amiga", both gc.lib and cord.lib will be made. @@ -246,10 +246,10 @@ the SAS/C commercial development system. In keeping with the porting philosophy outlined above, this port will not behave well with Amiga specific code. Especially not inter- -process comms via messages, and setting up public structures like +process communications 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-compliant code. (ie. Stick to stdio +ANSI/POSIX compliant or near-compliant code. (i.e., 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 diff --git a/gc/doc/README.cmake b/gc/doc/README.cmake index e691fa952..4c5894b85 100644 --- a/gc/doc/README.cmake +++ b/gc/doc/README.cmake @@ -47,4 +47,4 @@ INPUT ----- The main input to cmake are the CMakeLists.txt files in each directory. For -help, goto cmake.org. +help, go to cmake.org. diff --git a/gc/doc/README.darwin b/gc/doc/README.darwin index 2727d0b15..7b5a3e7ac 100644 --- a/gc/doc/README.darwin +++ b/gc/doc/README.darwin @@ -36,11 +36,6 @@ if you have an application or set of libraries that all use the garbage collector, to create an initialization routine for each of them that calls GC_init(). Better safe than sorry. -The incremental collector is still a bit flaky on darwin. It seems to -work reliably with workarounds for a few possible bugs in place however -these workaround may not work correctly in all cases. There may also -be additional problems that I have not found. - Thread-local GC allocation will not work with threads that are not created using the GC-provided override of pthread_create(). Threads created without the GC-provided pthread_create() do not have the @@ -76,69 +71,11 @@ programs that use JNI. If you run code that does not follow the stack layout or stack pointer conventions laid out in the PPC Mach-O ABI, then this will likely crash the garbage collector. -The original incremental collector support unfortunately no longer works -on recent Darwin versions. It also relied on some undocumented kernel -structures. Mach, however, does have a very clean interface to exception -handing. The current implementation uses Mach's exception handling. +Mach has a very clean interface to exception handing. So, the current +implementation of the incremental collection uses Mach's exception handling. Much thanks goes to Andrew Stone, Dietmar Planitzer, Andrew Begel, Jeff Sturm, and Jesse Rosenstock for all their work on the Darwin/OS X port. -Brian Alliet - -== gc_cpp.h usage == - -Replacement of operator new and delete is apparently not supported with -dynamic libraries. This means that applications using gc_cpp.h -(including the built-in test) will probably not work correctly with -the collector in a dynamic library, unless special care is taken. - -See -http://article.gmane.org/gmane.comp.programming.garbage-collection.boehmgc/1421 -for some details. - -- Hans Boehm (based on information from Andrew Begel) - - -== Older Information (Most of this no longer applies to the current code) == - -While the GC should work on MacOS X Server, MacOS X and Darwin, I only tested -it on MacOS X Server. -I've added a PPC assembly version of GC_push_regs(), thus the setjmp() hack is -no longer necessary. Incremental collection is supported via mprotect/signal. -The current solution isn't really optimal because the signal handler must decode -the faulting PPC machine instruction in order to find the correct heap address. -Further, it must poke around in the register state which the kernel saved away -in some obscure register state structure before it calls the signal handler - -needless to say the layout of this structure is no where documented. -Threads and dynamic libraries are not yet supported (adding dynamic library -support via the low-level dyld API shouldn't be that hard). - -The original MacOS X port was brought to you by Andrew Stone. - - -June, 1 2000 - -Dietmar Planitzer - -Note from Andrew Begel: - -One more fix to enable gc.a to link successfully into a shared library for -MacOS X. You have to add -fno-common to the CFLAGS in the Makefile. MacOSX -disallows common symbols in anything that eventually finds its way into a -shared library. (I don't completely understand why, but -fno-common seems to -work and doesn't mess up the garbage collector's functionality). - -Feb 26, 2003 - -Jeff Sturm and Jesse Rosenstock provided a patch that adds thread support. -GC_THREADS should be defined in the build and in clients. Real -dynamic library support is still missing, i.e. dynamic library data segments -are still not scanned. Code that stores pointers to the garbage collected -heap in statically allocated variables should not reside in a dynamic -library. This still doesn't appear to be 100% reliable. - -Mar 10, 2003 -Brian Alliet contributed dynamic library support for MacOSX. It could also -use more testing. diff --git a/gc/doc/README.ews4800 b/gc/doc/README.ews4800 index da4cff398..83e8b1e07 100644 --- a/gc/doc/README.ews4800 +++ b/gc/doc/README.ews4800 @@ -24,7 +24,7 @@ GC on EWS4800 *** Caution: The following information is empirical. *** 32-bit: - ELF file has an unique format. (See a.out(4) and end(3C).) + ELF file has a unique format. (See a.out(4) and end(3C).) &_start : text segment diff --git a/gc/doc/README.macros b/gc/doc/README.macros index b16198b1c..bd3383383 100644 --- a/gc/doc/README.macros +++ b/gc/doc/README.macros @@ -22,7 +22,7 @@ instead of features. In many cases, this is a mistake. Many of the tested configuration macros are at least somewhat defined in either include/private/gcconfig.h or in Makefile.direct. Here is an attempt at documenting these macros: (Thanks to Walter Bright for suggesting -this. This is a work in progress) +this.) MACRO EXPLANATION ----- ----------- @@ -57,6 +57,10 @@ _ENABLE_ARRAYNEW operator new[] and delete[] are separately overloadable. Used in gc_cpp.h. +GC_NO_INLINE_STD_NEW Tested by gc_cpp.cc and gc_cpp.h. MS Windows only. + Define the system-wide new and delete operators in gccpp.dll + instead of providing an inline version of the operators. + _DLL Tested by gc_config_macros.h. Defined by Visual C++ if runtime dynamic libraries are in use. Used (only if none of GC_DLL, GC_NOT_DLL, __GNUC__ are defined) to test whether @@ -204,10 +208,11 @@ DONT_ADD_BYTE_AT_END Meaningful only with ALL_INTERIOR_POINTERS or NO_EXECUTE_PERMISSION May cause some or all of the heap to not have execute permission, i.e. it may be impossible to execute - code from the heap. Currently this only affects the incremental - collector on UNIX machines. It may greatly improve its performance, - since this may avoid some expensive cache synchronization. Alternatively, - GC_set_pages_executable can be called at the process initialization time. + code from the heap. Affects the incremental collector and memory unmapping. + It may greatly improve the performance, since this may avoid some expensive + cache synchronization. Portable clients should call + GC_set_pages_executable(1) at the process initialization time if the + execute permission is required. GC_NO_OPERATOR_NEW_ARRAY Declares that the C++ compiler does not support the new syntax "operator new[]" for allocating and deleting arrays. diff --git a/gc/doc/README.solaris2 b/gc/doc/README.solaris2 index b150f9c27..2bc56dd8a 100644 --- a/gc/doc/README.solaris2 +++ b/gc/doc/README.solaris2 @@ -61,7 +61,7 @@ delete.) I encountered "symbol : 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 +The fix appears to be to use a consistent toolchain. (As a non-Solaris-expert my solution involved hacking the libtool script, but I'm sure you can do something less ugly.) diff --git a/gc/doc/README.win32 b/gc/doc/README.win32 index aa81e66ec..de4ef7628 100644 --- a/gc/doc/README.win32 +++ b/gc/doc/README.win32 @@ -114,7 +114,7 @@ Note that all compilations were done under Windows 95 or NT. For unknown reason compiling under Windows 3.11 for NT (one attempt has been made) leads to broken executables. -Incremental collection is not supported. +Incremental collection is supported (except for MSDOS and OS/2). cord is not ported. diff --git a/gc/doc/finalization.md b/gc/doc/finalization.md index 13c14afba..75428cd68 100644 --- a/gc/doc/finalization.md +++ b/gc/doc/finalization.md @@ -51,7 +51,7 @@ In single-threaded code, it is also often easiest to have finalizers queue actions, which are then explicitly run during an explicit call by the user's program. -# Topologically Ordered Finalization +## Topologically ordered finalization Our _conservative garbage collector_ supports a form of finalization (with `GC_register_finalizer`) in which objects are finalized in topological order. @@ -67,7 +67,7 @@ making it accessible again. Or it may mutate the rest of the chain. Cycles involving one or more finalizable objects are never finalized. -# Why topological ordering? +## Why topological ordering? It is important to keep in mind that the choice of finalization ordering matters only in relatively rare cases. In spite of the fact that it has @@ -123,7 +123,7 @@ finalization simply extends this to object finalization; an finalizable object reachable from another finalizer via a pointer chain is presumed to be accessible by the finalizer, and thus should not be finalized. -# Programming with topological finalization +## Programming with topological finalization Experience with Cedar has shown that cycles or long chains of finalizable objects are typically not a problem. Finalizable objects are typically rare. @@ -141,7 +141,7 @@ cleared by the finalization procedure that deallocates the resource). If any references are still left at process exit, they can be explicitly deallocated then. -# Getting around topological finalization ordering +## Getting around topological finalization ordering There are certain situations in which cycles between finalizable objects are genuinely unavoidable. Most notably, C++ compilers introduce self-cycles diff --git a/gc/doc/gcdescr.md b/gc/doc/gcdescr.md index fbc020857..cc2354529 100644 --- a/gc/doc/gcdescr.md +++ b/gc/doc/gcdescr.md @@ -36,7 +36,7 @@ of a memory allocation: to be reachable from variables are again scanned similarly. 3. _Sweep phase_ Scans the heap for inaccessible, and hence unmarked, objects, and returns them to an appropriate free list for reuse. This is not - really a separate phase; even in non incremental mode this is operation + really a separate phase; even in non-incremental mode this operation is usually performed on demand during an allocation that discovers an empty free list. Thus the sweep phase is very unlikely to touch a page that would not have been touched shortly thereafter anyway. @@ -132,7 +132,7 @@ of fragmentation. In particular: * Programs with a large root set size and little live heap memory will expand the heap to amortize the cost of scanning the roots. - * GC v5 actually collect more frequently in non-incremental mode. The large + * GC v5 actually collects more frequently in non-incremental mode. The large block allocator usually refuses to split large heap blocks once the garbage collection threshold is reached. This often has the effect of collecting well before the heap fills up, thus reducing fragmentation and working set @@ -203,18 +203,19 @@ progression of mark states for a stop-the-world collection is: objects, roots, and then mark everything reachable from them. `scan_ptr` is advanced through the heap until all uncollectible objects are pushed, and objects reachable from them are marked. At that point, the next call - to `GC_mark_some` calls `GC_push_roots` to push the roots. It the advances - the mark state to + to `GC_mark_some` calls `GC_push_roots` to push the roots. It, then, + advances the mark state to 3. `MS_ROOTS_PUSHED` asserting that once the mark stack is empty, all reachable objects are marked. Once in this state, we work only on emptying the mark stack. Once this is completed, the state changes to - 4. `MS_NONE` indicating that reachable objects are marked. The core mark - routine `GC_mark_from`, is called repeatedly by several of the sub-phases - when the mark stack starts to fill up. It is also called repeatedly - in `MS_ROOTS_PUSHED` state to empty the mark stack. The routine is designed - to only perform a limited amount of marking at 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. + 4. `MS_NONE` indicating that reachable objects are marked. + +The core mark routine `GC_mark_from`, is called repeatedly by several of the +sub-phases when the mark stack starts to fill up. It is also called repeatedly +in `MS_ROOTS_PUSHED` state to empty the mark stack. The routine is designed +to only perform a limited amount of marking at 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. 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 @@ -255,7 +256,7 @@ block. This is done in the following steps: the page is not part of the garbage collected heap, a small integer _n_, indicating that the page is part of large object, starting at least _n_ pages back, or a pointer to a descriptor for the page. In the first case, - the candidate pointer `i` not a true pointer and can be safely ignored. + the candidate pointer is not a true pointer and can be safely ignored. In the last two cases, we can obtain a descriptor for the page containing the beginning of the object. * The starting address of the referenced object is computed. The page @@ -506,7 +507,7 @@ is otherwise similar to the global free lists. The local free lists are also linked using the first word in the object. In most cases this means they require considerably less time. -Local free lists are treated buy most of the rest of the collector as though +Local free lists are treated by most of the rest of the collector as though they were in-use reachable data. This requires some care, since pointer-free objects are not normally traced, and hence a special tracing procedure is required to mark all objects on pointer-free and gcj local free lists. diff --git a/gc/doc/gcinterface.md b/gc/doc/gcinterface.md index 4e7d309b7..fbada0041 100644 --- a/gc/doc/gcinterface.md +++ b/gc/doc/gcinterface.md @@ -1,7 +1,7 @@ # C/C++ Interface On many platforms, a single-threaded garbage collector library can be built -to act as a plug-in `malloc` replacement. (Build with +to act as a plug-in `malloc` replacement. (Build it with `-DREDIRECT_MALLOC=GC_malloc -DIGNORE_FREE`.) This is often the best way to deal with third-party libraries which leak or prematurely free objects. `-DREDIRECT_MALLOC=GC_malloc` is intended primarily as an easy way to adapt @@ -55,15 +55,15 @@ object for pointers to garbage-collectible memory, even if the block itself does not appear to be reachable. (Objects allocated in this way are effectively treated as roots by the collector.) -**void * `GC_REALLOC`(void * _old_, size_t _new_size_)** - Allocate a new +**void * `GC_REALLOC`(void * _old_, size_t _new_size_)** - Allocates a new object of the indicated size and copy (a prefix of) the old object into the new object. The old object is reused in place if convenient. If the original object was allocated with `GC_MALLOC_ATOMIC`, the new object is subject to the same constraints. If it was allocated as an uncollectible object, then the new object is uncollectible, and the old object (if different) is deallocated. -**void `GC_FREE`(void * _dead_)** - Explicitly deallocate an object. Typically -not useful for small collectible objects. +**void `GC_FREE`(void * _dead_)** - Explicitly deallocates an object. +Typically not useful for small collectible objects. **void * `GC_MALLOC_IGNORE_OFF_PAGE`(size_t _nbytes_)** and **void * `GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE`(size_t _nbytes_)** - Analogous @@ -84,9 +84,9 @@ code, though we try to ensure that it expands to a no-op on as many platforms as possible. In GC v7.0, it was required if thread-local allocation is enabled in the collector build, and `malloc` is not redirected to `GC_malloc`. -**void `GC_gcollect`(void)** - Explicitly force a garbage collection. +**void `GC_gcollect`(void)** - Explicitly forces a garbage collection. -**void `GC_enable_incremental`(void)** - Cause the garbage collector +**void `GC_enable_incremental`(void)** - Causes the garbage collector to perform a small amount of work every few invocations of `GC_MALLOC` or the like, instead of performing an entire collection at once. This is likely to increase total running time. It will improve response on a platform that @@ -94,13 +94,13 @@ either has suitable support in the garbage collector (Linux and most Unix versions, Win32 if the collector was suitably built). On many platforms this interacts poorly with system calls that write to the garbage collected heap. -**void `GC_set_warn_proc`(GC_warn_proc)** - Replace the default procedure +**void `GC_set_warn_proc`(GC_warn_proc)** - Replaces the default procedure used by the collector to print warnings. The collector may otherwise write to `stderr`, most commonly because `GC_malloc` was used in a situation in which `GC_malloc_ignore_off_page` would have been more appropriate. See `gc.h` for details. -**void `GC_REGISTER_FINALIZER`(...)** - Register a function to be called when +**void `GC_REGISTER_FINALIZER`(...)** - Registers a function to be called when an object becomes inaccessible. This is often useful as a backup method for releasing system resources (e.g. closing files) when the object referencing them becomes inaccessible. It is not an acceptable method to perform actions @@ -189,8 +189,8 @@ discouraged. This defines SGI-style allocators - * `alloc` - * `single_client_alloc` + * `traceable_alloc` + * `single_client_traceable_alloc` * `gc_alloc` * `single_client_gc_alloc` @@ -207,7 +207,7 @@ in garbage collectible memory by having those classes inherit from class `gc`. For details see `gc_cpp.h` file. Linking against `libgccpp` in addition to the `gc` library overrides `::new` -(and friends) to allocate traceable memory but uncollectible memory, making +(and friends) to allocate traceable but uncollectible memory, making it safe to refer to collectible objects from the resulting memory. ## C interface diff --git a/gc/doc/leak.md b/gc/doc/leak.md index 7d62af7bd..76456aa56 100644 --- a/gc/doc/leak.md +++ b/gc/doc/leak.md @@ -4,7 +4,7 @@ The garbage collector may be used as a leak detector. In this case, the primary function of the collector is to report objects that were allocated (typically with `GC_MALLOC`), not deallocated (normally with `GC_FREE`), but are no longer accessible. Since the object is no longer accessible, there -in normally no way to deallocate the object at a later time; thus it can +is normally no way to deallocate the object at a later time; thus it can safely be assumed that the object has been "leaked". This is substantially different from counting leak detectors, which simply @@ -35,13 +35,15 @@ To use the collector as a leak detector, follow the following steps: the garbage collector. 3. Arrange to call `GC_gcollect` at appropriate points to check for leaks. (For sufficiently long running programs, this will happen implicitly, but - probably not with sufficient frequency.) The second step can usually - be accomplished with the `-DREDIRECT_MALLOC=GC_malloc` option when the - collector is built, or by defining `malloc`, `calloc`, `realloc` and `free` - to call the corresponding garbage collector functions. But this, by itself, - will not yield very informative diagnostics, since the collector does not - keep track of information about how objects were allocated. The error - reports will include only object addresses. + probably not with sufficient frequency.) + +The second step can usually be accomplished with the +`-DREDIRECT_MALLOC=GC_malloc` option when the collector is built, or by +defining `malloc`, `calloc`, `realloc` and `free` to call the corresponding +garbage collector functions. But this, by itself, will not yield very +informative diagnostics, since the collector does not keep track of +information about how objects were allocated. The error reports will include +only object addresses. For more precise error reports, as much of the program as possible should use the all uppercase variants of these functions, after defining `GC_DEBUG`, and @@ -135,25 +137,28 @@ detection mode on a program a.out under Linux/X86 as follows: debug information. This will improve the quality of the leak reports. With this approach, it is no longer necessary to call `GC_` routines explicitly, though that can also improve the quality of the leak reports. - 4. Build the collector and install it in directory _foo_ as follows: - * `configure --prefix=_foo_ --enable-gc-debug --enable-redirect-malloc --disable-threads` - * `make` - * `make install` - - With a very recent collector on Linux, it may sometimes be safe to omit - the `--disable-threads`. But the combination of thread support and - `malloc` replacement is not yet rock solid. - 5. Set environment variables as follows: - * `LD_PRELOAD=`_foo_`/lib/libgc.so` - * `GC_FIND_LEAK` - - You may also want to set `GC_PRINT_STATS` (to confirm that the collector - is running) and/or `GC_LOOP_ON_ABORT` (to facilitate debugging from - another window if something goes wrong). + 4. Build the collector and install it in directory _foo_ as follows (it may + be safe to omit the `--disable-threads` option on Linux, but the combination + of thread support and `malloc` replacement is not yet rock solid): + + - `configure --prefix=_foo_ --enable-gc-debug --enable-redirect-malloc --disable-threads` + - `make` + - `make install` + + 5. Set environment variables as follows (the last two are optional, just to + confirm the collector is running, and to facilitate debugging from another + console window if something goes wrong, respectively): + + - `LD_PRELOAD=_foo_/lib/libgc.so` + - `GC_FIND_LEAK` + - `GC_PRINT_STATS` + - `GC_LOOP_ON_ABORT` + 6. Simply run `a.out` as you normally would. Note that if you run anything else (e.g. your editor) with those environment variables set, it will also be leak tested. This may or may not be useful and/or embarrassing. It can generate mountains of leak reports if the application was not designed - to avoid leaks, e.g. because it's always short-lived. This has not yet - been thoroughly tested on large applications, but it's known to do the right - thing on at least some small ones. + to avoid leaks, e.g. because it's always short-lived. + +This has not yet been thoroughly tested on large applications, but it's known +to do the right thing on at least some small ones. diff --git a/gc/doc/overview.md b/gc/doc/overview.md index fb3aa2a4e..f4f9a017f 100644 --- a/gc/doc/overview.md +++ b/gc/doc/overview.md @@ -130,7 +130,7 @@ We also expect that in many cases any additional overhead will be more than compensated for by decreased copying etc. if programs are written and tuned for garbage collection. -# Further Reading: +## Further reading **The beginnings of a frequently asked questions list for this collector are [here](http://www.hboehm.info/gc/faq.html)**. @@ -164,7 +164,7 @@ is a related letter to the editor and a minor correction in the next issue. Boehm, H., and [M. Weiser](http://www.ubiq.com/hypertext/weiser/weiser.html), [Garbage Collection in an Uncooperative Environment](http://www.hboehm.info/spe_gc_paper/), -_Software Practice & Experience_, September 1988, pp. 807-820. +_Software Practice and Experience_, September 1988, pp. 807-820. Boehm, H., A. Demers, and S. Shenker, [Mostly Parallel Garbage Collection](http://www.hboehm.info/gc/papers/pldi91.ps.Z), @@ -239,7 +239,7 @@ Henry Baker's [paper collection](http://home.pipeline.com/%7Ehbaker1/). Slides for Hans Boehm's [Allocation and GC Myths](http://www.hboehm.info/gc/myths.ps) talk. -# Current users: +## Current users Known current users of some variant of this collector include: @@ -300,7 +300,7 @@ The [Vesta](http://www.vestasys.org/) configuration management system. [Asymptote LaTeX-compatible vector graphics language](http://asymptote.sf.net/). -# More information on the BDWGC primary site +## Information provided on the BDWGC site [A simple illustration of how to build and use the collector](simple_example.md). @@ -324,7 +324,7 @@ The [Vesta](http://www.vestasys.org/) configuration management system. files of all garbage collector releases. It duplicates [Download](https://github.com/ivmai/bdwgc/wiki/Download) page on GitHub. -# More background information +## More background information [An attempt to establish a bound on space usage of conservative garbage collectors](http://www.hboehm.info/gc/bounds.html). @@ -352,7 +352,7 @@ version). [Related papers](http://www.hboehm.info/gc/papers/). -# Contacts and new release announcements +## Contacts and new release announcements GitHub and Stack Overflow are the major two places for communication. diff --git a/gc/doc/porting.md b/gc/doc/porting.md index bc2b253c1..7da0b7896 100644 --- a/gc/doc/porting.md +++ b/gc/doc/porting.md @@ -47,6 +47,7 @@ The `gcconfig.h` file consists of three sections: RISC variants.) On GNU-based systems, `cpp -dM empty_source_file.c` seems to generate a set of predefined macros. On some other systems, the "verbose" compiler option may do so, or the manual page may list them. + 2. A section that defines a small number of platform-specific macros, which are then used directly by the collector. For simple ports, this is where most of the effort is required. We describe the macros below. This section @@ -84,7 +85,7 @@ operating system: trace all memory between `DATASTART` and `DATAEND` for root pointers. On some platforms, this can be defined to a constant address, though experience has shown that to be risky. Ideally the linker will define - a symbol (e.g. `_data` whose address is the beginning of the data segment. + a symbol (e.g. `_data`) whose address is the beginning of the data segment. Sometimes the value can be computed using the `GC_SysVGetDataStart` function. Not used if either the next macro is defined, or if dynamic loading is supported, and the dynamic loading support defines a function @@ -114,8 +115,8 @@ operating system: three macros is defined, client code must explicitly set `GC_stackbottom` to an appropriate value before calling `GC_INIT` or any other `GC_` routine. * `LINUX_STACKBOTTOM` - May be defined instead of `STACKBOTTOM`. If defined, - then the cold end of the stack will be determined Currently we usually read - it from `/proc`. + then the cold end of the stack will be determined, we usually read it from + `/proc`. * `HEURISTIC1` - May be defined instead of `STACKBOTTOM`. `STACK_GRAN` should generally also be redefined. The cold end of the stack is determined by taking an address inside `GC_init`s frame, and rounding it up to the next @@ -154,7 +155,7 @@ or just tweaking of conditional compilation tests. For GC v7, if your platform supports `getcontext`, then defining the macro `UNIX_LIKE` for your OS in `gcconfig.h` (if it is not defined there yet) -is likely to solve the problem. otherwise, if you are using gcc, +is likely to solve the problem. Otherwise, if you are using gcc, `_builtin_unwind_init` will be used, and should work fine. If that is not applicable either, the implementation will try to use `setjmp`. This will work if your `setjmp` implementation saves all possibly pointer-valued registers @@ -226,7 +227,7 @@ If dynamic library data sections must also be traced, then: `gcconfig.h`. * An appropriate versions of the functions `GC_register_dynamic_libraries` should be defined in `dyn_load.c`. This function should invoke - `GC_cond_add_roots(_region_start, region_end_, TRUE)` on each dynamic + `GC_cond_add_roots(region_start, region_end, TRUE)` on each dynamic library data section. Implementations that scan for writable data segments are error prone, @@ -244,7 +245,7 @@ locking behavior in this case. For incremental and generational collection to work, `os_dep.c` must contain a suitable _virtual dirty bit_ implementation, which allows the collector -to track which heap pages (assumed to be a multiple of the collectors block +to track which heap pages (assumed to be a multiple of the collector's block size) have been written during a certain time interval. The collector provides several implementations, which might be adapted. The default (`DEFAULT_VDB`) is a placeholder which treats all pages as having been written. This ensures @@ -253,7 +254,7 @@ useless. ## Stack traces for debug support -If stack traces in objects are need for debug support, `GC_dave_callers` and +If stack traces in objects are needed for debug support, `GC_save_callers` and `GC_print_callers` must be implemented. ## Disclaimer diff --git a/gc/doc/scale.md b/gc/doc/scale.md index 75fb635be..2a3c69480 100644 --- a/gc/doc/scale.md +++ b/gc/doc/scale.md @@ -39,7 +39,8 @@ to be used together. is performed by the thread that triggered the collection, together with _N_ - 1 dedicated threads, where _N_ is the number of processors detected by the collector. The dedicated threads are created once at initialization - time. A second effect of this flag is to switch to a more concurrent + time (and optionally recreated in child processes after forking). + A second effect of this flag is to switch to a more concurrent implementation of `GC_malloc_many`, so that free lists can be built, and memory can be cleared, by more than one thread concurrently. * Building the collector with `-DTHREAD_LOCAL_ALLOC` adds support for @@ -142,9 +143,10 @@ These measurements do not use incremental collection, nor was prefetching enabled in the marker. We used the C version of the benchmark. All measurements are in elapsed seconds on an unloaded machine. -Number of threads| 1 marker thread (secs.) | 2 marker threads (secs.) ----|---|--- -1 client| 10.45| 7.85 | 2 clients| 19.95| 12.3 +Number of client threads| 1 marker thread (secs.)| 2 marker threads (secs.) +---|------|----- + 1| 10.45| 7.85 + 2| 19.95| 12.3 The execution time for the single threaded case is slightly worse than with simple locking. However, even the single-threaded benchmark runs faster than diff --git a/gc/doc/simple_example.md b/gc/doc/simple_example.md index e19d56863..1fefc83b5 100644 --- a/gc/doc/simple_example.md +++ b/gc/doc/simple_example.md @@ -99,7 +99,8 @@ The following program `loop.c` is a trivial example: assert(*p == 0); *p = (int *) GC_REALLOC(q, 2 * sizeof(int)); if (i % 100000 == 0) - printf("Heap size = %d\n", GC_get_heap_size()); + printf("Heap size = %lu bytes\n", + (unsigned long)GC_get_heap_size()); } return 0; } diff --git a/gc/dyn_load.c b/gc/dyn_load.c index 6692321c6..d857246b6 100644 --- a/gc/dyn_load.c +++ b/gc/dyn_load.c @@ -547,11 +547,15 @@ STATIC int GC_register_dynlib_callback(struct dl_phdr_info * info, 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); + GC_ASSERT((word)end <= + (((word)load_segs[j].end + GC_page_size - 1) & + ~(GC_page_size - 1))); /* Remove from the existing load segment */ load_segs[j].end2 = load_segs[j].end; load_segs[j].end = start; load_segs[j].start2 = end; + /* Note that start2 may be greater than end2 because of */ + /* p->p_memsz value multiple of page size. */ } break; } @@ -619,10 +623,10 @@ STATIC GC_bool GC_register_dynamic_libraries_dl_iterate_phdr(void) } else { ptr_t datastart, dataend; # ifdef DATASTART_IS_FUNC - static ptr_t datastart_cached = (ptr_t)(word)-1; + static ptr_t datastart_cached = (ptr_t)GC_WORD_MAX; /* Evaluate DATASTART only once. */ - if (datastart_cached == (ptr_t)(word)-1) { + if (datastart_cached == (ptr_t)GC_WORD_MAX) { datastart_cached = DATASTART; } datastart = datastart_cached; @@ -1214,7 +1218,7 @@ GC_INNER void GC_register_dynamic_libraries(void) #endif /* HPUX */ #ifdef AIX -# pragma alloca +# include # include # include GC_INNER void GC_register_dynamic_libraries(void) diff --git a/gc/extra/msvc_dbg.c b/gc/extra/msvc_dbg.c index 8a72976be..c744aaa5e 100644 --- a/gc/extra/msvc_dbg.c +++ b/gc/extra/msvc_dbg.c @@ -22,7 +22,7 @@ #if !defined(_M_AMD64) && defined(_MSC_VER) -/* X86_64 is currently missing some meachine-dependent code below. */ +/* X86_64 is currently missing some machine-dependent code below. */ #define GC_BUILD #include "private/msvc_dbg.h" @@ -212,6 +212,11 @@ size_t GetModuleNameFromStack(size_t skip, char* moduleName, size_t size) return 0; } +union sym_namebuf_u { + IMAGEHLP_SYMBOL sym; + char symNameBuffer[sizeof(IMAGEHLP_SYMBOL) + MAX_SYM_NAME]; +}; + size_t GetSymbolNameFromAddress(void* address, char* symbolName, size_t size, size_t* offsetBytes) { @@ -219,10 +224,8 @@ size_t GetSymbolNameFromAddress(void* address, char* symbolName, size_t size, if (offsetBytes) *offsetBytes = 0; __try { ULONG_ADDR dwOffset = 0; - union { - IMAGEHLP_SYMBOL sym; - char symNameBuffer[sizeof(IMAGEHLP_SYMBOL) + MAX_SYM_NAME]; - } u; + union sym_namebuf_u u; + u.sym.SizeOfStruct = sizeof(u.sym); u.sym.MaxNameLength = sizeof(u.symNameBuffer) - sizeof(u.sym); @@ -312,6 +315,7 @@ size_t GetDescriptionFromAddress(void* address, const char* format, char*const end = buffer + size; size_t line_number = 0; + (void)format; if (size) { *buffer = 0; } @@ -332,7 +336,7 @@ size_t GetDescriptionFromAddress(void* address, const char* format, if (size) { strncpy(buffer, "at ", size)[size - 1] = 0; } - buffer += strlen("at "); + buffer += sizeof("at ") - 1; size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer; buffer += GetSymbolNameFromAddress(address, buffer, size, NULL); @@ -341,7 +345,7 @@ size_t GetDescriptionFromAddress(void* address, const char* format, if (size) { strncpy(buffer, " in ", size)[size - 1] = 0; } - buffer += strlen(" in "); + buffer += sizeof(" in ") - 1; size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer; buffer += GetModuleNameFromAddress(address, buffer, size); @@ -352,18 +356,18 @@ size_t GetDescriptionFromStack(void* const frames[], size_t count, const char* format, char* description[], size_t size) { - char*const begin = (char*)description; - char*const end = begin + size; - char* buffer = begin + (count + 1) * sizeof(char*); + const GC_ULONG_PTR begin = (GC_ULONG_PTR)description; + const GC_ULONG_PTR end = begin + size; + GC_ULONG_PTR buffer = begin + (count + 1) * sizeof(char*); size_t i; - (void)format; + for (i = 0; i < count; ++i) { - 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[i] = (char*)buffer; + buffer += 1 + GetDescriptionFromAddress(frames[i], format, (char*)buffer, + end < buffer ? 0 : end - buffer); } - if (size) + if (description) description[count] = NULL; return buffer - begin; } diff --git a/gc/extra/pcr_interface.c b/gc/extra/pcr_interface.c index ff4618743..7266c1b3e 100644 --- a/gc/extra/pcr_interface.c +++ b/gc/extra/pcr_interface.c @@ -150,6 +150,8 @@ PCR_GC_Setup(void) return PCR_ERes_okay; } +extern GC_bool GC_quiet; + PCR_ERes PCR_GC_Run(void) { diff --git a/gc/finalize.c b/gc/finalize.c index 64a0ec227..d52525fe6 100644 --- a/gc/finalize.c +++ b/gc/finalize.c @@ -124,7 +124,9 @@ STATIC void GC_grow_table(struct hash_chain_entry ***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) { + /* In incremental mode we skip this optimization, as we want to */ + /* avoid triggering a full GC whenever possible. */ + if (log_old_size >= GC_ON_GROW_LOG_SIZE_MIN && !GC_incremental) { IF_CANCEL(int cancel_state;) DISABLE_CANCEL(cancel_state); @@ -632,6 +634,10 @@ GC_API GC_await_finalize_proc GC_CALL GC_get_await_finalize_proc(void) /* Possible finalization_marker procedures. Note that mark stack */ /* overflow is handled by the caller, and is not a disaster. */ +#if defined(_MSC_VER) && defined(I386) + GC_ATTR_NOINLINE + /* Otherwise some optimizer bug is tickled in VC for X86 (v19, at least). */ +#endif STATIC void GC_normal_finalize_mark_proc(ptr_t p) { GC_mark_stack_top = GC_push_obj(p, HDR(p), GC_mark_stack_top, @@ -1326,7 +1332,7 @@ GC_INNER void GC_notify_or_invoke_finalizers(void) # ifdef KEEP_BACK_PTRS long i; /* Stops when GC_gc_no wraps; that's OK. */ - last_back_trace_gc_no = (word)(-1); /* disable others. */ + last_back_trace_gc_no = GC_WORD_MAX; /* disable others. */ for (i = 0; i < GC_backtraces; ++i) { /* FIXME: This tolerates concurrent heap mutation, */ /* which may cause occasional mysterious results. */ diff --git a/gc/fnlz_mlc.c b/gc/fnlz_mlc.c index 1e1a6ed02..283566ee7 100644 --- a/gc/fnlz_mlc.c +++ b/gc/fnlz_mlc.c @@ -45,6 +45,7 @@ STATIC int GC_CALLBACK GC_finalized_disclaim(void *obj) const struct GC_finalizer_closure *fc = (struct GC_finalizer_closure *)(fc_word & ~(word)FINALIZER_CLOSURE_FLAG); + GC_ASSERT(!GC_find_leak); (*fc->proc)((word *)obj + 1, fc->cd); } return 0; @@ -85,8 +86,11 @@ GC_API void GC_CALL GC_register_disclaim_proc(int kind, GC_disclaim_proc proc, { GC_ASSERT((unsigned)kind < MAXOBJKINDS); GC_ASSERT(NONNULL_ARG_NOT_NULL(proc)); - GC_obj_kinds[kind].ok_disclaim_proc = proc; - GC_obj_kinds[kind].ok_mark_unconditionally = (GC_bool)mark_unconditionally; + if (!EXPECT(GC_find_leak, FALSE)) { + GC_obj_kinds[kind].ok_disclaim_proc = proc; + GC_obj_kinds[kind].ok_mark_unconditionally = + (GC_bool)mark_unconditionally; + } } GC_API GC_ATTR_MALLOC void * GC_CALL GC_finalized_malloc(size_t lb, diff --git a/gc/gc.mak b/gc/gc.mak index 987dbb584..62b51f5f9 100644 --- a/gc/gc.mak +++ b/gc/gc.mak @@ -120,7 +120,8 @@ CPP=cl.exe # 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 /EHsc /O2 /I include /D "NDEBUG" /D "WIN32"\ /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "ENABLE_DISCLAIM"\ - /D "GC_THREADS" /D "_CRT_SECURE_NO_DEPRECATE"\ + /D "GC_ATOMIC_UNCOLLECTABLE" /D "GC_THREADS" /D "JAVA_FINALIZATION"\ + /D "NO_EXECUTE_PERMISSION" /D "_CRT_SECURE_NO_DEPRECATE"\ /FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch"\ /I./libatomic_ops/src /Fo"$(INTDIR)/" /c CPP_OBJS=.\Release/ @@ -309,9 +310,10 @@ CPP=cl.exe # 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 /EHsc /Zi /Od /I include /D "_DEBUG"\ /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "ENABLE_DISCLAIM"\ - /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 + /D "GC_ASSERTIONS" /D "GC_ATOMIC_UNCOLLECTABLE" /D "GC_THREADS"\ + /D "JAVA_FINALIZATION" /D "NO_EXECUTE_PERMISSION"\ + /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/ diff --git a/gc/gc_cpp.cc b/gc/gc_cpp.cc index baf8ca498..9f4d673b2 100644 --- a/gc/gc_cpp.cc +++ b/gc/gc_cpp.cc @@ -9,7 +9,7 @@ */ /************************************************************************* -This implementation module for gc_c++.h provides an implementation of +This implementation module for gc_cpp.h provides an implementation of the global operators "new" and "delete" that calls the Boehm allocator. All objects allocated by this implementation will be uncollectible but part of the root set of the collector. @@ -44,7 +44,7 @@ GC_API void GC_CALL GC_throw_bad_alloc() { GC_ALLOCATOR_THROW_OR_ABORT(); } -#if !defined(_MSC_VER) && !defined(__DMC__) +#if !(defined(_MSC_VER) || defined(__DMC__)) || defined(GC_NO_INLINE_STD_NEW) # if !defined(GC_NEW_DELETE_THROW_NOT_NEEDED) \ && !defined(GC_NEW_DELETE_NEED_THROW) && GC_GNUC_PREREQ(4, 2) \ @@ -53,7 +53,13 @@ GC_API void GC_CALL GC_throw_bad_alloc() { # endif # ifdef GC_NEW_DELETE_NEED_THROW -# define GC_DECL_NEW_THROW throw(std::bad_alloc) +# if __cplusplus >= 201703L || _MSVC_LANG >= 201703L + // The "dynamic exception" syntax had been deprecated in C++11 + // and was removed in C++17. +# define GC_DECL_NEW_THROW noexcept(false) +# else +# define GC_DECL_NEW_THROW throw(std::bad_alloc) +# endif # else # define GC_DECL_NEW_THROW /* empty */ # endif @@ -65,6 +71,23 @@ GC_API void GC_CALL GC_throw_bad_alloc() { return obj; } +# 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) + { +# ifdef GC_DEBUG + void* obj = GC_debug_malloc_uncollectable(size, szFileName, nLine); +# else + void* obj = GC_MALLOC_UNCOLLECTABLE(size); + (void)szFileName; (void)nLine; +# endif + if (0 == obj) + GC_ALLOCATOR_THROW_OR_ABORT(); + return obj; + } +# endif // _MSC_VER + void operator delete(void* obj) GC_NOEXCEPT { GC_FREE(obj); } @@ -77,12 +100,21 @@ GC_API void GC_CALL GC_throw_bad_alloc() { return obj; } +# ifdef _MSC_VER + // This new operator is used by VC++ 7+ in Debug builds. + void* operator new[](size_t size, int nBlockUse, + const char* szFileName, int nLine) + { + return operator new(size, nBlockUse, szFileName, nLine); + } +# endif // _MSC_VER + void operator delete[](void* obj) GC_NOEXCEPT { GC_FREE(obj); } # endif // GC_OPERATOR_NEW_ARRAY -# if __cplusplus > 201103L // C++14 +# if __cplusplus >= 201402L || _MSVC_LANG >= 201402L // C++14 void operator delete(void* obj, size_t size) GC_NOEXCEPT { (void)size; // size is ignored GC_FREE(obj); @@ -96,4 +128,4 @@ GC_API void GC_CALL GC_throw_bad_alloc() { # endif # endif // C++14 -#endif // !_MSC_VER +#endif // !_MSC_VER && !__DMC__ || GC_NO_INLINE_STD_NEW diff --git a/gc/headers.c b/gc/headers.c index d2c283c56..837614e51 100644 --- a/gc/headers.c +++ b/gc/headers.c @@ -122,9 +122,10 @@ GC_INNER ptr_t GC_scratch_alloc(size_t bytes) bytes = ROUNDUP_GRANULE_SIZE(bytes); for (;;) { - scratch_free_ptr += bytes; - if ((word)scratch_free_ptr <= (word)GC_scratch_end_ptr) { + GC_ASSERT((word)GC_scratch_end_ptr >= (word)result); + if (bytes <= (word)GC_scratch_end_ptr - (word)result) { /* Unallocated space of scratch buffer has enough size. */ + scratch_free_ptr = result + bytes; return result; } @@ -132,8 +133,7 @@ GC_INNER ptr_t GC_scratch_alloc(size_t bytes) bytes_to_get = ROUNDUP_PAGESIZE_IF_MMAP(bytes); result = (ptr_t)GET_MEM(bytes_to_get); GC_add_to_our_memory(result, bytes_to_get); - /* Undo scratch free area pointer update; get memory directly. */ - scratch_free_ptr -= bytes; + /* No update of scratch free area pointer; get memory directly. */ if (result != NULL) { /* Update end point of last obtained area (needed only */ /* by GC_register_dynamic_libraries for some targets). */ @@ -149,10 +149,11 @@ GC_INNER ptr_t GC_scratch_alloc(size_t bytes) if (NULL == result) { WARN("Out of memory - trying to allocate requested amount" " (%" WARN_PRIdPTR " bytes)...\n", (word)bytes); - scratch_free_ptr -= bytes; /* Undo free area pointer update */ bytes_to_get = ROUNDUP_PAGESIZE_IF_MMAP(bytes); result = (ptr_t)GET_MEM(bytes_to_get); GC_add_to_our_memory(result, bytes_to_get); + if (result != NULL) + GC_scratch_last_end_ptr = result + bytes; return result; } /* Update scratch area pointers and retry. */ @@ -283,15 +284,19 @@ GC_INNER GC_bool GC_install_counts(struct hblk *h, size_t sz/* bytes */) struct hblk * hbp; for (hbp = h; (word)hbp < (word)h + sz; hbp += BOTTOM_SZ) { - if (!get_index((word) hbp)) return(FALSE); + if (!get_index((word)hbp)) + return FALSE; + if ((word)hbp > GC_WORD_MAX - (word)BOTTOM_SZ * HBLKSIZE) + break; /* overflow of hbp+=BOTTOM_SZ is expected */ } - if (!get_index((word)h + sz - 1)) return(FALSE); + if (!get_index((word)h + sz - 1)) + return FALSE; for (hbp = h + 1; (word)hbp < (word)h + sz; hbp += 1) { word i = HBLK_PTR_DIFF(hbp, h); SET_HDR(hbp, (hdr *)(i > MAX_JUMP? MAX_JUMP : i)); } - return(TRUE); + return TRUE; } /* Remove the header for block h */ @@ -342,9 +347,7 @@ void GC_apply_to_all_blocks(void (*fn)(struct hblk *h, word client_data), } } -/* Get the next valid block whose address is at least h */ -/* Return 0 if there is none. */ -GC_INNER struct hblk * GC_next_used_block(struct hblk *h) +GC_INNER struct hblk * GC_next_block(struct hblk *h, GC_bool allow_free) { REGISTER bottom_index * bi; REGISTER word j = ((word)h >> LOG_HBLKSIZE) & (BOTTOM_SZ-1); @@ -358,14 +361,15 @@ GC_INNER struct hblk * GC_next_used_block(struct hblk *h) while (bi != 0 && bi -> key < hi) bi = bi -> asc_link; j = 0; } - while(bi != 0) { + + while (bi != 0) { while (j < BOTTOM_SZ) { hdr * hhdr = bi -> index[j]; if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { j++; } else { - if (!HBLK_IS_FREE(hhdr)) { - return((struct hblk *) + if (allow_free || !HBLK_IS_FREE(hhdr)) { + return ((struct hblk *) (((bi -> key << LOG_BOTTOM_SZ) + j) << LOG_HBLKSIZE)); } else { @@ -379,9 +383,6 @@ GC_INNER struct hblk * GC_next_used_block(struct hblk *h) return(0); } -/* Get the last (highest address) block whose address is */ -/* at most h. Return 0 if there is none. */ -/* Unlike the above, this may return a free block. */ GC_INNER struct hblk * GC_prev_block(struct hblk *h) { bottom_index * bi; diff --git a/gc/include/ec.h b/gc/include/ec.h index 6375220cd..7473a5996 100644 --- a/gc/include/ec.h +++ b/gc/include/ec.h @@ -61,8 +61,8 @@ void CORD_ec_flush_buf(CORD_ec x); /* Append a character to an extensible cord. */ #define CORD_ec_append(x, c) \ - (((x)[0].ec_bufptr == (x)[0].ec_buf + CORD_BUFSZ ? \ - (CORD_ec_flush_buf(x), 0) : 0), \ + ((void)((x)[0].ec_bufptr == (x)[0].ec_buf + CORD_BUFSZ \ + ? (CORD_ec_flush_buf(x), 0) : 0), \ (void)(*(x)[0].ec_bufptr++ = (c))) /* Append a cord to an extensible cord. Structure remains shared with */ diff --git a/gc/include/gc.h b/gc/include/gc.h index b952285bf..2de57922f 100644 --- a/gc/include/gc.h +++ b/gc/include/gc.h @@ -24,7 +24,6 @@ * For better performance, also look at GC_MALLOC_ATOMIC, and * GC_enable_incremental. If you need an action to be performed * immediately before an object is collected, look at GC_register_finalizer. - * If you are using Solaris threads, look at the end of this file. * Everything else is best ignored unless you encounter performance * problems. */ @@ -90,11 +89,12 @@ GC_API GC_word GC_CALL GC_get_gc_no(void); #ifdef GC_THREADS GC_API GC_ATTR_DEPRECATED int GC_parallel; /* GC is parallelized for performance on */ - /* multiprocessors. Currently set only */ - /* implicitly if collector is built with */ - /* PARALLEL_MARK defined and if either: */ - /* Env variable GC_NPROC is set to > 1, or */ - /* GC_NPROC is not set and this is an MP. */ + /* multiprocessors. Set to a non-zero value */ + /* only implicitly if collector is built with */ + /* PARALLEL_MARK defined, and if either */ + /* GC_MARKERS (or GC_NPROCS) environment */ + /* variable is set to > 1, or multiple cores */ + /* (processors) are available. */ /* If GC_parallel is on (non-zero), incremental */ /* collection is only partially functional, */ /* and may not be desirable. The getter does */ @@ -1328,7 +1328,12 @@ GC_API int GC_CALL GC_invoke_finalizers(void); __asm__ __volatile__(" " : : "X"(ptr) : "memory") #else GC_API void GC_CALL GC_noop1(GC_word); -# define GC_reachable_here(ptr) GC_noop1((GC_word)(ptr)) +# ifdef LINT2 +# define GC_reachable_here(ptr) GC_noop1(~(GC_word)(ptr)^(~(GC_word)0)) + /* The expression matches the one of COVERT_DATAFLOW(). */ +# else +# define GC_reachable_here(ptr) GC_noop1((GC_word)(ptr)) +# endif #endif /* GC_set_warn_proc can be used to redirect or filter warning messages. */ @@ -1368,6 +1373,7 @@ GC_API void GC_CALL GC_abort_on_oom(void); /* that finalization code will arrange for hidden pointers to */ /* disappear. Otherwise objects can be accessed after they */ /* have been collected. */ +/* Should not be used in the leak-finding mode. */ /* Note that putting pointers in atomic objects or in */ /* non-pointer slots of "typed" objects is equivalent to */ /* disguising them in this way, and may have other advantages. */ @@ -1528,8 +1534,13 @@ GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */, /* the current thread (this means that the thread is not suspended and */ /* the thread's stack frames "belonging" to the functions in the */ /* "inactive" state are not scanned during garbage collections). It is */ -/* allowed for fn to call GC_call_with_gc_active() (even recursively), */ -/* thus temporarily toggling the collector's state back to "active". */ +/* assumed that the collector is already initialized and the current */ +/* thread is registered. It is allowed for fn to call */ +/* GC_call_with_gc_active() (even recursively), thus temporarily */ +/* toggling the collector's state back to "active". The latter */ +/* technique might be used to make stack scanning more precise (i.e. */ +/* scan only stack frames of functions that allocate garbage collected */ +/* memory and/or manipulate pointers to the garbage collected heap). */ GC_API void * GC_CALL GC_do_blocking(GC_fn_type /* fn */, void * /* client_data */) GC_ATTR_NONNULL(1); @@ -1887,38 +1898,20 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void); /* Required at least if GC is in a DLL. And doesn't hurt. */ #elif defined(_AIX) extern int _data[], _end[]; -# define GC_DATASTART ((void *)((ulong)_data)) -# define GC_DATAEND ((void *)((ulong)_end)) +# define GC_DATASTART ((void *)_data) +# define GC_DATAEND ((void *)_end) # define GC_INIT_CONF_ROOTS GC_add_roots(GC_DATASTART, GC_DATAEND) #elif (defined(HOST_ANDROID) || defined(__ANDROID__)) \ - && !defined(GC_NOT_DLL) && defined(IGNORE_DYNAMIC_LOADING) - /* It causes the entire binary section of memory be pushed as a root. */ - /* This might be a bad idea though because on some Android devices */ - /* some of the binary data might become unmapped thus causing SIGSEGV */ - /* with code SEGV_MAPERR. */ -# pragma weak _etext -# pragma weak __data_start + && defined(IGNORE_DYNAMIC_LOADING) + /* This is ugly but seems the only way to register data roots of the */ + /* client shared library if the GC dynamic loading support is off. */ # pragma weak __dso_handle - 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 \ - ? (__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) + extern int __dso_handle[]; + GC_API void * GC_CALL GC_find_limit(void * /* start */, int /* up */); +# define GC_INIT_CONF_ROOTS (void)(__dso_handle != 0 \ + ? (GC_add_roots(__dso_handle, \ + GC_find_limit(__dso_handle, \ + 1 /*up*/)), 0) : 0) #else # define GC_INIT_CONF_ROOTS /* empty */ #endif @@ -2014,7 +2007,7 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void); /* Portable clients should call this at the program start-up. More */ /* over, some platforms require this call to be done strictly from the */ -/* primordial thread. */ +/* primordial thread. Multiple invocations are harmless. */ #define GC_INIT() { GC_INIT_CONF_DONT_EXPAND; /* pre-init */ \ GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT; \ GC_INIT_CONF_MAX_RETRIES; \ diff --git a/gc/include/gc_allocator.h b/gc/include/gc_allocator.h index 491736fad..df5804379 100644 --- a/gc/include/gc_allocator.h +++ b/gc/include/gc_allocator.h @@ -44,7 +44,8 @@ #include // for placement new and bad_alloc #ifndef GC_ATTR_EXPLICIT -# if (__cplusplus >= 201103L) || defined(CPPCHECK) +# if __cplusplus >= 201103L && !defined(__clang__) || _MSVC_LANG >= 201103L \ + || defined(CPPCHECK) # define GC_ATTR_EXPLICIT explicit # else # define GC_ATTR_EXPLICIT /* empty */ @@ -65,7 +66,7 @@ # ifndef GC_NEW_ABORTS_ON_OOM # define GC_NEW_ABORTS_ON_OOM # endif -# elif __cplusplus >= 201103L +# elif __cplusplus >= 201103L || _MSVC_LANG >= 201103L # define GC_NOEXCEPT noexcept # else # define GC_NOEXCEPT throw() diff --git a/gc/include/gc_config_macros.h b/gc/include/gc_config_macros.h index d656e01ee..14c65eeee 100644 --- a/gc/include/gc_config_macros.h +++ b/gc/include/gc_config_macros.h @@ -83,13 +83,13 @@ #elif defined(GC_THREADS) # if defined(__linux__) # define GC_LINUX_THREADS +# elif defined(__OpenBSD__) +# define GC_OPENBSD_THREADS # elif defined(_PA_RISC1_1) || defined(_PA_RISC2_0) || defined(hppa) \ || defined(__HPPA) || (defined(__ia64) && defined(_HPUX_SOURCE)) # define GC_HPUX_THREADS # elif defined(__HAIKU__) # define GC_HAIKU_THREADS -# elif defined(__OpenBSD__) -# define GC_OPENBSD_THREADS # elif defined(__DragonFly__) || defined(__FreeBSD_kernel__) \ || (defined(__FreeBSD__) && !defined(SN_TARGET_ORBIS)) # define GC_FREEBSD_THREADS @@ -146,7 +146,7 @@ #if !defined(_REENTRANT) && defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) /* Better late than never. This fails if system headers that depend */ /* on this were previously included. */ -# define _REENTRANT +# define _REENTRANT 1 #endif #define __GC @@ -176,13 +176,22 @@ #if defined(GC_DLL) && !defined(GC_API) -# if defined(__MINGW32__) || defined(__CEGCC__) -# if defined(GC_BUILD) || defined(__MINGW32_DELAY_LOAD__) +# if defined(__CEGCC__) +# if defined(GC_BUILD) # define GC_API __declspec(dllexport) # else # define GC_API __declspec(dllimport) # endif +# elif defined(__MINGW32__) +# if defined(__cplusplus) && defined(GC_BUILD) +# define GC_API extern __declspec(dllexport) +# elif defined(GC_BUILD) || defined(__MINGW32_DELAY_LOAD__) +# define GC_API __declspec(dllexport) +# else +# define GC_API extern __declspec(dllimport) +# endif + # elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \ || defined(__CYGWIN__) # ifdef GC_BUILD diff --git a/gc/include/gc_cpp.h b/gc/include/gc_cpp.h index 3e166e669..eb4397f79 100644 --- a/gc/include/gc_cpp.h +++ b/gc/include/gc_cpp.h @@ -182,7 +182,7 @@ by UseGC. GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined. # ifndef GC_NEW_ABORTS_ON_OOM # define GC_NEW_ABORTS_ON_OOM # endif -# elif __cplusplus >= 201103L +# elif __cplusplus >= 201103L || _MSVC_LANG >= 201103L # define GC_NOEXCEPT noexcept # else # define GC_NOEXCEPT throw() @@ -306,14 +306,13 @@ inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp, void*) GC_NOEXCEPT; #endif +#ifndef GC_NO_INLINE_STD_NEW + #if defined(_MSC_VER) || defined(__DMC__) \ - || ((defined(__CYGWIN32__) || defined(__CYGWIN__) \ - || defined(__MINGW32__)) && !defined(GC_BUILD) && !defined(GC_NOT_DLL)) - // 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. + || ((defined(__BORLANDC__) || defined(__CYGWIN__) \ + || defined(__CYGWIN32__) || defined(__MINGW32__) \ + || defined(__WATCOMC__)) \ + && !defined(GC_BUILD) && !defined(GC_NOT_DLL)) // Inlining done to avoid mix up of new and delete operators by VC++ 9 (due // to arbitrary ordering during linking). @@ -343,7 +342,7 @@ inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp, GC_FREE(obj); } -# if __cplusplus > 201103L // C++14 +# if __cplusplus >= 201402L || _MSVC_LANG >= 201402L // C++14 inline void operator delete(void* obj, size_t size) GC_NOEXCEPT { (void)size; // size is ignored GC_FREE(obj); @@ -390,6 +389,24 @@ inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp, #endif // _MSC_VER +#elif defined(_MSC_VER) + // 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. +# ifdef GC_OPERATOR_NEW_ARRAY + void *operator new[](size_t size); + void operator delete[](void* obj); +# endif + + void* operator new(size_t size); + void operator delete(void* obj); + + void* operator new(size_t size, int /* nBlockUse */, + const char * szFileName, int nLine); +#endif // GC_NO_INLINE_STD_NEW && _MSC_VER + #ifdef GC_OPERATOR_NEW_ARRAY // The operator new for arrays, identical to the above. inline void* operator new[](size_t size, GC_NS_QUALIFY(GCPlacement) gcp, diff --git a/gc/include/gc_disclaim.h b/gc/include/gc_disclaim.h index 8123838ed..f2942cdb8 100644 --- a/gc/include/gc_disclaim.h +++ b/gc/include/gc_disclaim.h @@ -39,6 +39,8 @@ typedef int (GC_CALLBACK * GC_disclaim_proc)(void * /*obj*/); /* (including the referred closure object) will be protected from */ /* collection if "mark_from_all" is non-zero, but at the expense that */ /* long chains of objects will take many cycles to reclaim. */ +/* Calls to GC_free() will free its argument without inquiring "proc". */ +/* No-op in the leak-finding mode. */ GC_API void GC_CALL GC_register_disclaim_proc(int /*kind*/, GC_disclaim_proc /*proc*/, int /*mark_from_all*/) GC_ATTR_NONNULL(2); @@ -60,6 +62,7 @@ struct GC_finalizer_closure { /* 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. */ +/* The disclaim procedure is not invoked in the leak-finding mode. */ 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*/) GC_ATTR_NONNULL(2); diff --git a/gc/include/gc_pthread_redirects.h b/gc/include/gc_pthread_redirects.h index 92951c3c6..b235334aa 100644 --- a/gc/include/gc_pthread_redirects.h +++ b/gc/include/gc_pthread_redirects.h @@ -18,6 +18,9 @@ /* Our pthread support normally needs to intercept a number of thread */ /* calls. We arrange to do that here, if appropriate. */ +#ifndef GC_PTHREAD_REDIRECTS_H +#define GC_PTHREAD_REDIRECTS_H + /* Included from gc.h only. Included only if GC_PTHREADS. */ #if defined(GC_H) && defined(GC_PTHREADS) @@ -117,3 +120,5 @@ #endif /* !GC_NO_THREAD_REDIRECTS */ #endif /* GC_PTHREADS */ + +#endif /* GC_PTHREAD_REDIRECTS_H */ diff --git a/gc/include/gc_typed.h b/gc/include/gc_typed.h index 1ddc3f84e..f91c7bcec 100644 --- a/gc/include/gc_typed.h +++ b/gc/include/gc_typed.h @@ -105,8 +105,9 @@ GC_API GC_ATTR_MALLOC GC_ATTR_CALLOC_SIZE(1, 2) void * GC_CALL /* Returned object is cleared. */ #ifdef GC_DEBUG -# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) GC_MALLOC(bytes) -# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) GC_MALLOC((n) * (bytes)) +# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) ((void)(d), GC_MALLOC(bytes)) +# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) \ + ((void)(d), GC_MALLOC((n) * (bytes))) #else # define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) \ GC_malloc_explicitly_typed(bytes, d) diff --git a/gc/include/gc_version.h b/gc/include/gc_version.h index a8ee4b0f0..bbe31f9d7 100644 --- a/gc/include/gc_version.h +++ b/gc/include/gc_version.h @@ -30,7 +30,7 @@ /* it to keep the old-style build process working. */ #define GC_TMP_VERSION_MAJOR 8 #define GC_TMP_VERSION_MINOR 0 -#define GC_TMP_VERSION_MICRO 0 /* 8.0.0 */ +#define GC_TMP_VERSION_MICRO 6 /* 8.0.6 */ #ifdef GC_VERSION_MAJOR # if GC_TMP_VERSION_MAJOR != GC_VERSION_MAJOR \ diff --git a/gc/include/include.am b/gc/include/include.am index ef1867f8e..fd9a698fe 100644 --- a/gc/include/include.am +++ b/gc/include/include.am @@ -29,9 +29,6 @@ pkginclude_HEADERS += \ # headers which are not installed # dist_noinst_HEADERS += \ - include/cord.h \ - include/cord_pos.h \ - include/ec.h \ include/gc_alloc_ptrs.h \ include/new_gc_alloc.h \ include/private/darwin_semaphore.h \ diff --git a/gc/include/javaxfc.h b/gc/include/javaxfc.h index 27da68b3d..40ff5b7fb 100644 --- a/gc/include/javaxfc.h +++ b/gc/include/javaxfc.h @@ -15,6 +15,9 @@ * modified is included with the above copyright notice. */ +#ifndef GC_JAVAXFC_H +#define GC_JAVAXFC_H + #ifndef GC_H # include "gc.h" #endif @@ -58,3 +61,5 @@ GC_API void GC_CALL GC_finalize_all(void); #ifdef __cplusplus } /* extern "C" */ #endif + +#endif /* GC_JAVAXFC_H */ diff --git a/gc/include/new_gc_alloc.h b/gc/include/new_gc_alloc.h index a42733d77..7ff2a0b30 100644 --- a/gc/include/new_gc_alloc.h +++ b/gc/include/new_gc_alloc.h @@ -44,7 +44,8 @@ // allocator is usually a very bad choice for a garbage collected environment.) // -#ifndef GC_ALLOC_H +#ifndef GC_NEW_ALLOC_H +#define GC_NEW_ALLOC_H #include "gc.h" @@ -67,14 +68,14 @@ # define simple_alloc __simple_alloc #endif -#define GC_ALLOC_H - #include #include // We can't include gc_priv.h, since that pulls in way too much stuff. #include "gc_alloc_ptrs.h" +#include "gc_mark.h" // for GC_generic_malloc + #define GC_generic_malloc_words_small(lw, k) \ GC_generic_malloc((lw) * sizeof(GC_word), k) @@ -154,14 +155,15 @@ void * GC_aux_template::GC_out_of_line_malloc(size_t nwords, int kind) if (0 == op) GC_ALLOCATOR_THROW_OR_ABORT(); + GC_word non_gc_bytes = GC_get_non_gc_bytes(); GC_bytes_recently_allocd += GC_uncollectable_bytes_recently_allocd; - GC_non_gc_bytes += - GC_uncollectable_bytes_recently_allocd; + non_gc_bytes += GC_uncollectable_bytes_recently_allocd; GC_uncollectable_bytes_recently_allocd = 0; GC_bytes_recently_freed += GC_uncollectable_bytes_recently_freed; - GC_non_gc_bytes -= GC_uncollectable_bytes_recently_freed; + non_gc_bytes -= GC_uncollectable_bytes_recently_freed; GC_uncollectable_bytes_recently_freed = 0; + GC_set_non_gc_bytes(non_gc_bytes); GC_incr_bytes_allocd(GC_bytes_recently_allocd); GC_bytes_recently_allocd = 0; @@ -512,4 +514,4 @@ __STL_END_NAMESPACE #endif /* __STL_USE_STD_ALLOCATORS */ -#endif /* GC_ALLOC_H */ +#endif /* GC_NEW_ALLOC_H */ diff --git a/gc/include/private/dbg_mlc.h b/gc/include/private/dbg_mlc.h index 69cf95c3f..e38475a62 100644 --- a/gc/include/private/dbg_mlc.h +++ b/gc/include/private/dbg_mlc.h @@ -22,8 +22,8 @@ * included from header files that are frequently included by clients. */ -#ifndef _DBG_MLC_H -#define _DBG_MLC_H +#ifndef GC_DBG_MLC_H +#define GC_DBG_MLC_H #include "gc_priv.h" #ifdef KEEP_BACK_PTRS @@ -95,8 +95,8 @@ typedef struct { word oh_dummy; # endif # endif - const char * oh_string; /* object descriptor string */ - word oh_int; /* object descriptor integers */ + const char * oh_string; /* object descriptor string (file name) */ + signed_word oh_int; /* object descriptor integer (line number) */ # ifdef NEED_CALLINFO struct callinfo oh_ci[NFRAMES]; # endif @@ -158,7 +158,7 @@ typedef struct { #endif #if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH) -# ifdef SHORT_DBG_HDRS +# if defined(SHORT_DBG_HDRS) && !defined(CPPCHECK) # error Non-ptr stored in object results in GC_HAS_DEBUG_INFO malfunction /* We may mistakenly conclude that p has a debugging wrapper. */ # endif @@ -179,4 +179,4 @@ typedef struct { EXTERN_C_END -#endif /* _DBG_MLC_H */ +#endif /* GC_DBG_MLC_H */ diff --git a/gc/include/private/gc_atomic_ops.h b/gc/include/private/gc_atomic_ops.h index 776d45519..235f2c864 100644 --- a/gc/include/private/gc_atomic_ops.h +++ b/gc/include/private/gc_atomic_ops.h @@ -100,6 +100,11 @@ } /* extern "C" */ # endif +# ifndef NO_LOCKFREE_AO_OR + /* __atomic_or_fetch is assumed to be lock-free. */ +# define HAVE_LOCKFREE_AO_OR 1 +# endif + #else /* Fallback to libatomic_ops. */ # include "atomic_ops.h" @@ -109,7 +114,7 @@ /* only if AO_REQUIRE_CAS is defined (or if the corresponding */ /* AO_HAVE_x macro is defined). x86/x64 targets have AO_nop_full, */ /* AO_load_acquire, AO_store_release, at least. */ -# if !defined(AO_HAVE_load) || !defined(AO_HAVE_store) +# if (!defined(AO_HAVE_load) || !defined(AO_HAVE_store)) && !defined(CPPCHECK) # error AO_load or AO_store is missing; probably old version of atomic_ops # endif diff --git a/gc/include/private/gc_hdrs.h b/gc/include/private/gc_hdrs.h index 94f29e9c7..a6e7037a5 100644 --- a/gc/include/private/gc_hdrs.h +++ b/gc/include/private/gc_hdrs.h @@ -15,7 +15,7 @@ #ifndef GC_HEADERS_H #define GC_HEADERS_H -#if CPP_WORDSZ != 32 && CPP_WORDSZ < 36 +#if CPP_WORDSZ != 32 && CPP_WORDSZ < 36 && !defined(CPPCHECK) # error Get a real machine #endif diff --git a/gc/include/private/gc_locks.h b/gc/include/private/gc_locks.h index f6e45d59b..5b9ef4f39 100644 --- a/gc/include/private/gc_locks.h +++ b/gc/include/private/gc_locks.h @@ -54,7 +54,8 @@ # if (!defined(AO_HAVE_test_and_set_acquire) || defined(GC_RTEMS_PTHREADS) \ || defined(SN_TARGET_ORBIS) || defined(SN_TARGET_PS3) \ - || defined(GC_WIN32_THREADS) || defined(LINT2)) && defined(GC_PTHREADS) + || defined(GC_WIN32_THREADS) || defined(BASE_ATOMIC_OPS_EMULATED) \ + || defined(LINT2)) && defined(GC_PTHREADS) # define USE_PTHREAD_LOCKS # undef USE_SPIN_LOCK # endif @@ -182,6 +183,7 @@ EXTERN_C_BEGIN GC_EXTERN pthread_mutex_t GC_allocate_ml; # ifdef GC_ASSERTIONS + GC_INNER void GC_lock(void); # define UNCOND_LOCK() { GC_ASSERT(I_DONT_HOLD_LOCK()); \ GC_lock(); SET_LOCK_HOLDER(); } # define UNCOND_UNLOCK() \ @@ -191,6 +193,7 @@ # if defined(NO_PTHREAD_TRYLOCK) # define UNCOND_LOCK() pthread_mutex_lock(&GC_allocate_ml) # else + GC_INNER void GC_lock(void); # define UNCOND_LOCK() \ { if (0 != pthread_mutex_trylock(&GC_allocate_ml)) \ GC_lock(); } @@ -224,7 +227,6 @@ # define EXIT_GC() (void)(GC_collecting = FALSE) # endif # endif - GC_INNER void GC_lock(void); # endif /* GC_PTHREADS */ # if defined(GC_ALWAYS_MULTITHREADED) \ && (defined(USE_PTHREAD_LOCKS) || defined(USE_SPIN_LOCK)) diff --git a/gc/include/private/gc_pmark.h b/gc/include/private/gc_pmark.h index 2e657b0b4..15e798605 100644 --- a/gc/include/private/gc_pmark.h +++ b/gc/include/private/gc_pmark.h @@ -23,6 +23,8 @@ #define GC_PMARK_H #if defined(HAVE_CONFIG_H) && !defined(GC_PRIVATE_H) + /* When gc_pmark.h is included from gc_priv.h, some of macros might */ + /* be undefined in gcconfig.h, so skip config.h in this case. */ # include "config.h" #endif @@ -40,13 +42,8 @@ # include "dbg_mlc.h" #endif -#ifndef GC_MARK_H -# include "../gc_mark.h" -#endif - -#ifndef GC_PRIVATE_H -# include "gc_priv.h" -#endif +#include "../gc_mark.h" +#include "gc_priv.h" EXTERN_C_BEGIN @@ -153,7 +150,7 @@ GC_INLINE mse * GC_push_obj(ptr_t obj, hdr * hhdr, mse * mark_stack_top, /* Set mark bit, exit (using "break" statement) if it is already set. */ #ifdef USE_MARK_BYTES # if defined(PARALLEL_MARK) && defined(AO_HAVE_char_store) \ - && !defined(AO_USE_PTHREAD_DEFS) + && !defined(BASE_ATOMIC_OPS_EMULATED) /* 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 is only a performance issue. */ @@ -320,7 +317,8 @@ GC_INLINE mse * GC_push_contents_hdr(ptr_t current, mse * mark_stack_top, if ((low_prod >> 16) != 0) # endif /* MARK_BIT_PER_OBJ */ { -# ifdef MARK_BIT_PER_OBJ +# if defined(MARK_BIT_PER_OBJ) \ + && !defined(MARK_BIT_PER_GRANULE) /* for cppcheck */ size_t obj_displ; /* Accurate enough if HBLKSIZE <= 2**15. */ diff --git a/gc/include/private/gc_priv.h b/gc/include/private/gc_priv.h index 728e74ea4..629418f3d 100644 --- a/gc/include/private/gc_priv.h +++ b/gc/include/private/gc_priv.h @@ -26,7 +26,8 @@ # define GC_BUILD #endif -#if (defined(__linux__) || defined(__GLIBC__) || defined(__GNU__)) \ +#if (defined(__linux__) || defined(__GLIBC__) || defined(__GNU__) \ + || (defined(__CYGWIN__) && !defined(USE_MMAP))) \ && !defined(_GNU_SOURCE) /* Can't test LINUX, since this must be defined before other includes. */ # define _GNU_SOURCE 1 @@ -80,13 +81,8 @@ # endif #endif -#ifndef GC_TINY_FL_H -# include "../gc_tiny_fl.h" -#endif - -#ifndef GC_MARK_H -# include "../gc_mark.h" -#endif +#include "../gc_tiny_fl.h" +#include "../gc_mark.h" typedef GC_word word; typedef GC_signed_word signed_word; @@ -96,9 +92,12 @@ typedef int GC_bool; #define TRUE 1 #define FALSE 0 -typedef char * ptr_t; /* A generic pointer to which we can add */ +#ifndef PTR_T_DEFINED + typedef char * ptr_t; /* A generic pointer to which we can add */ /* byte displacements and which can be used */ /* for address comparisons. */ +# define PTR_T_DEFINED +#endif #ifndef SIZE_MAX # include @@ -122,9 +121,7 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ #define SIZET_SAT_ADD(a, b) \ (EXPECT((a) < GC_SIZE_MAX - (b), TRUE) ? (a) + (b) : GC_SIZE_MAX) -#ifndef GCCONFIG_H -# include "gcconfig.h" -#endif +#include "gcconfig.h" #if !defined(GC_ATOMIC_UNCOLLECTABLE) && defined(ATOMIC_UNCOLLECTABLE) /* For compatibility with old-style naming. */ @@ -170,6 +167,14 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ # define REGISTER register #endif +#if defined(M68K) && defined(__GNUC__) + /* By default, __alignof__(word) is 2 on m68k. Use this attribute to */ + /* have proper word alignment (i.e. 4-byte on a 32-bit arch). */ +# define GC_ATTR_WORD_ALIGNED __attribute__((__aligned__(sizeof(word)))) +#else +# define GC_ATTR_WORD_ALIGNED /* empty */ +#endif + #ifndef HEADERS_H # include "gc_hdrs.h" #endif @@ -257,19 +262,20 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ #if defined(THREADS) && !defined(NN_PLATFORM_CTR) \ && !defined(SN_TARGET_ORBIS) && !defined(SN_TARGET_PSP2) # include "gc_atomic_ops.h" +# ifndef AO_HAVE_compiler_barrier +# define AO_HAVE_compiler_barrier 1 +# endif #endif -#ifndef GC_LOCKS_H -# include "gc_locks.h" -#endif +#include "gc_locks.h" -#define ONES ((word)(signed_word)(-1)) +#define GC_WORD_MAX (~(word)0) # ifdef STACK_GROWS_DOWN # define COOLER_THAN > # define HOTTER_THAN < # define MAKE_COOLER(x,y) if ((word)((x) + (y)) > (word)(x)) {(x) += (y);} \ - else (x) = (ptr_t)ONES + else (x) = (ptr_t)GC_WORD_MAX # define MAKE_HOTTER(x,y) (x) -= (y) # else # define COOLER_THAN < @@ -432,14 +438,17 @@ EXTERN_C_END # undef GET_TIME # undef MS_TIME_DIFF # define CLOCK_TYPE struct timeval +# define CLOCK_TYPE_INITIALIZER { 0, 0 } # define GET_TIME(x) \ do { \ struct rusage rusage; \ getrusage(RUSAGE_SELF, &rusage); \ x = rusage.ru_utime; \ } while (0) -# define MS_TIME_DIFF(a,b) ((unsigned long)(a.tv_sec - b.tv_sec) * 1000 \ - + (unsigned long)(a.tv_usec - b.tv_usec) / 1000) +# define MS_TIME_DIFF(a,b) ((unsigned long)((long)(a.tv_sec-b.tv_sec) * 1000 \ + + (long)(a.tv_usec-b.tv_usec) / 1000)) + /* "a" time is expected to be not earlier than */ + /* "b" one; the result has unsigned long type. */ #elif defined(MSWIN32) || defined(MSWINCE) # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN 1 @@ -453,7 +462,7 @@ EXTERN_C_END # else # define GET_TIME(x) (void)(x = GetTickCount()) # endif -# define MS_TIME_DIFF(a,b) ((long)((a)-(b))) +# define MS_TIME_DIFF(a,b) ((unsigned long)((a)-(b))) #elif defined(NN_PLATFORM_CTR) # define CLOCK_TYPE long long EXTERN_C_BEGIN @@ -461,7 +470,7 @@ EXTERN_C_END CLOCK_TYPE n3ds_convert_tick_to_ms(CLOCK_TYPE tick); EXTERN_C_END # define GET_TIME(x) (void)(x = n3ds_get_system_tick()) -# define MS_TIME_DIFF(a,b) ((long)n3ds_convert_tick_to_ms((a)-(b))) +# define MS_TIME_DIFF(a,b) ((unsigned long)n3ds_convert_tick_to_ms((a)-(b))) #else /* !BSD_TIME && !NN_PLATFORM_CTR && !MSWIN32 && !MSWINCE */ # include # if defined(FREEBSD) && !defined(CLOCKS_PER_SEC) @@ -488,6 +497,11 @@ EXTERN_C_END /* Avoid using double type since some targets (like ARM) might */ /* require -lm option for double-to-long conversion. */ #endif /* !BSD_TIME && !MSWIN32 */ +# ifndef CLOCK_TYPE_INITIALIZER + /* This is used to initialize CLOCK_TYPE variables (to some value) */ + /* to avoid "variable might be uninitialized" compiler warnings. */ +# define CLOCK_TYPE_INITIALIZER 0 +# endif #endif /* !NO_CLOCK */ /* We use bzero and bcopy internally. They may not be available. */ @@ -860,8 +874,8 @@ EXTERN_C_BEGIN # define CPP_LOG_HBLKSIZE 13 # elif HBLKSIZE == 16384 # define CPP_LOG_HBLKSIZE 14 -# else -# error fix HBLKSIZE +# elif !defined(CPPCHECK) +# error Bad HBLKSIZE value # endif # undef HBLKSIZE #endif @@ -970,6 +984,9 @@ typedef word page_hash_table[PHT_SIZE]; # define set_pht_entry_from_index_concurrent(bl, index) \ AO_or((volatile AO_t *)&(bl)[divWORDSZ(index)], \ (AO_t)((word)1 << modWORDSZ(index))) +#else +# define set_pht_entry_from_index_concurrent(bl, index) \ + set_pht_entry_from_index(bl, index) #endif @@ -1223,8 +1240,8 @@ typedef struct GC_ms_entry { /* be pointers are also put here. */ /* The main fields should precede any */ /* conditionally included fields, so that */ -/* gc_inl.h will work even if a different set */ -/* of macros is defined when the client is */ +/* gc_inline.h will work even if a different */ +/* set of macros is defined when the client is */ /* compiled. */ struct _GC_arrays { @@ -1291,6 +1308,10 @@ struct _GC_arrays { # ifdef USE_MUNMAP # define GC_unmapped_bytes GC_arrays._unmapped_bytes word _unmapped_bytes; +# ifdef COUNT_UNMAPPED_REGIONS +# define GC_num_unmapped_regions GC_arrays._num_unmapped_regions + signed_word _num_unmapped_regions; +# endif # else # define GC_unmapped_bytes 0 # endif @@ -1530,8 +1551,14 @@ GC_EXTERN size_t GC_page_size; #endif #if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32) - struct _SYSTEM_INFO; - GC_EXTERN struct _SYSTEM_INFO GC_sysinfo; +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN 1 +# endif +# define NOSERVICE + EXTERN_C_END +# include + EXTERN_C_BEGIN + GC_EXTERN SYSTEM_INFO GC_sysinfo; GC_INNER GC_bool GC_is_heap_base(void *p); #endif @@ -1654,12 +1681,16 @@ void GC_apply_to_all_blocks(void (*fn)(struct hblk *h, word client_data), word client_data); /* Invoke fn(hbp, client_data) for each */ /* allocated heap block. */ -GC_INNER struct hblk * GC_next_used_block(struct hblk * h); - /* Return first in-use block >= h */ +GC_INNER struct hblk * GC_next_block(struct hblk *h, GC_bool allow_free); + /* Get the next block whose address is at least */ + /* h. Returned block is managed by GC. The */ + /* block must be in use unless allow_free is */ + /* true. Return 0 if there is no such block. */ GC_INNER struct hblk * GC_prev_block(struct hblk * h); - /* Return last block <= h. Returned block */ - /* is managed by GC, but may or may not be in */ - /* use. */ + /* Get the last (highest address) block whose */ + /* address is at most h. Returned block is */ + /* managed by GC, but may or may not be in use. */ + /* Return 0 if there is no such block. */ GC_INNER void GC_mark_init(void); GC_INNER void GC_clear_marks(void); /* Clear mark bits for all heap objects. */ @@ -1853,10 +1884,13 @@ 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); +#ifdef MARK_BIT_PER_GRANULE + GC_INNER GC_bool GC_add_map_entry(size_t sz); /* Add a heap block map for objects of */ /* size sz to obj_map. */ /* Return FALSE on failure. */ +#endif + GC_INNER void GC_register_displacement_inner(size_t offset); /* Version of GC_register_displacement */ /* that assumes lock is already held. */ @@ -1933,7 +1967,7 @@ 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) +#ifdef 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. */ @@ -2122,7 +2156,13 @@ GC_EXTERN GC_bool GC_print_back_height; GC_INNER void GC_remap(ptr_t start, size_t bytes); GC_INNER void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2, size_t bytes2); -#endif + + /* Compute end address for an unmap operation on the indicated block. */ + GC_INLINE ptr_t GC_unmap_end(ptr_t start, size_t bytes) + { + return (ptr_t)((word)(start + bytes) & ~(GC_page_size - 1)); + } +#endif /* USE_MUNMAP */ #ifdef CAN_HANDLE_FORK GC_EXTERN int GC_handle_fork; @@ -2174,6 +2214,17 @@ GC_EXTERN GC_bool GC_print_back_height; /* pointer-free system call buffers in the heap are */ /* not protected. */ +# ifdef CAN_HANDLE_FORK +# if defined(PROC_VDB) + GC_INNER void GC_dirty_update_child(void); + /* Update pid-specific resources (like /proc file */ + /* descriptors) needed by the dirty bits implementation */ + /* after fork in the child process. */ +# else +# define GC_dirty_update_child() (void)0 +# endif +# endif /* CAN_HANDLE_FORK */ + 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 */ @@ -2316,8 +2367,7 @@ GC_EXTERN signed_word GC_bytes_found; /* protected by GC_write_cs. */ # endif -# if defined(GC_DISABLE_INCREMENTAL) \ - || defined(set_pht_entry_from_index_concurrent) +# if defined(GC_DISABLE_INCREMENTAL) || defined(HAVE_LOCKFREE_AO_OR) # define GC_acquire_dirty_lock() (void)0 # define GC_release_dirty_lock() (void)0 # else @@ -2451,12 +2501,12 @@ GC_INNER void *GC_store_debug_info_inner(void *p, word sz, const char *str, #ifdef SEARCH_FOR_DATA_START GC_INNER void GC_init_linux_data_start(void); - ptr_t GC_find_limit(ptr_t, GC_bool); + void * GC_find_limit(void *, int); #endif #if defined(NETBSD) && defined(__ELF__) GC_INNER void GC_init_netbsd_elf(void); - ptr_t GC_find_limit(ptr_t, GC_bool); + void * GC_find_limit(void *, int); #endif #ifdef UNIX_LIKE @@ -2635,7 +2685,6 @@ GC_INNER void *GC_store_debug_info_inner(void *p, word sz, const char *str, /* Do we need the GC_find_limit machinery to find the end of a */ /* data segment. */ #if defined(HEURISTIC2) || defined(SEARCH_FOR_DATA_START) \ - || (!defined(STACKBOTTOM) && defined(HEURISTIC2)) \ || ((defined(SVR4) || defined(AIX) || defined(DGUX) \ || (defined(LINUX) && defined(SPARC))) && !defined(PCR)) # define NEED_FIND_LIMIT diff --git a/gc/include/private/gcconfig.h b/gc/include/private/gcconfig.h index 5671402b9..1979c58c6 100644 --- a/gc/include/private/gcconfig.h +++ b/gc/include/private/gcconfig.h @@ -25,12 +25,23 @@ #ifndef GCCONFIG_H #define GCCONFIG_H -# ifndef GC_PRIVATE_H - /* Fake ptr_t declaration, just to avoid compilation errors. */ - /* This avoids many instances if "ifndef GC_PRIVATE_H" below. */ - typedef struct GC_undefined_struct * ptr_t; -# include /* For size_t etc. */ -# endif +#ifdef CPPCHECK +# undef CLOCKS_PER_SEC +# undef FIXUP_POINTER +# undef POINTER_MASK +# undef POINTER_SHIFT +# undef REDIRECT_REALLOC +# undef _MAX_PATH +#endif + +#ifndef PTR_T_DEFINED + typedef char * ptr_t; +# define PTR_T_DEFINED +#endif + +#if !defined(sony_news) +# include /* For size_t, etc. */ +#endif /* Note: Only wrap our own declarations, and not the included headers. */ /* In this case, wrap our entire file, but temporarily unwrap/rewrap */ @@ -149,7 +160,8 @@ EXTERN_C_BEGIN # if defined(__aarch64__) # define AARCH64 # if !defined(LINUX) && !defined(DARWIN) && !defined(FREEBSD) \ - && !defined(NETBSD) && !defined(NN_BUILD_TARGET_PLATFORM_NX) + && !defined(NETBSD) && !defined(NN_BUILD_TARGET_PLATFORM_NX) \ + && !defined(OPENBSD) # define NOSYS # define mach_type_known # endif @@ -171,7 +183,7 @@ EXTERN_C_BEGIN # error SUNOS4 no longer supported # endif # if defined(hp9000s300) && !defined(CPPCHECK) -# error M68K based HP machines no longer supported. +# error M68K based HP machines no longer supported # endif # if defined(OPENBSD) && defined(m68k) # define M68K @@ -185,6 +197,10 @@ EXTERN_C_BEGIN # define ARM32 # define mach_type_known # endif +# if defined(OPENBSD) && defined(__aarch64__) +# define AARCH64 +# define mach_type_known +# endif # if defined(OPENBSD) && defined(__sh__) # define SH # define mach_type_known @@ -276,7 +292,7 @@ EXTERN_C_BEGIN # define mach_type_known # endif # if defined(ibm032) && !defined(CPPCHECK) -# error IBM PC/RT no longer supported. +# error IBM PC/RT no longer supported # endif # if (defined(sun) || defined(__sun)) && (defined(sparc) || defined(__sparc)) /* Test for SunOS 5.x */ @@ -539,10 +555,12 @@ EXTERN_C_BEGIN # if ((defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300)) \ || (defined(_WIN32) && !defined(__CYGWIN32__) && !defined(__CYGWIN__) \ && !defined(__INTERIX) && !defined(SYMBIAN)) -# if defined(__LP64__) || defined(_WIN64) +# if defined(__LP64__) || defined(_M_X64) # define X86_64 # elif defined(_M_ARM) # define ARM32 +# elif defined(_M_ARM64) +# define AARCH64 # else /* _M_IX86 */ # define I386 # endif @@ -693,7 +711,7 @@ EXTERN_C_BEGIN /* SYSV on an M68K actually means A/UX. */ /* The distinction in these cases is usually the stack starting address */ # if !defined(mach_type_known) && !defined(CPPCHECK) -# error "The collector has not been ported to this machine/OS combination." +# error The collector has not been ported to this machine/OS combination # endif /* Mapping is: M68K ==> Motorola 680X0 */ /* (NEXT, and SYSV (A/UX), */ @@ -720,6 +738,7 @@ EXTERN_C_BEGIN /* S390 ==> 390-like machine */ /* running LINUX */ /* AARCH64 ==> ARM AArch64 */ + /* (LP64 and ILP32 variants) */ /* ARM32 ==> Intel StrongARM */ /* IA64 ==> Intel IPF */ /* (e.g. Itanium) */ @@ -869,7 +888,8 @@ EXTERN_C_BEGIN && !(defined(POWERPC) && defined(DARWIN)) /* for MacOS X 10.3.9 */ \ && !defined(RTEMS) \ && !defined(__ARMCC_VERSION) /* does not exist in armcc gnu emu */ \ - && !defined(__clang__) /* since no-op in clang (3.0) */ + && (!defined(__clang__) \ + || (GC_CLANG_PREREQ(8, 0) && defined(HOST_ANDROID))) # define HAVE_BUILTIN_UNWIND_INIT # endif @@ -929,7 +949,10 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM -# define MPROTECT_VDB +# define COUNT_UNMAPPED_REGIONS +# if !defined(REDIRECT_MALLOC) +# define MPROTECT_VDB +# endif # ifdef __ELF__ # define DYNAMIC_LOADING EXTERN_C_END @@ -1019,6 +1042,7 @@ EXTERN_C_BEGIN # else # define LINUX_STACKBOTTOM # endif +# define COUNT_UNMAPPED_REGIONS # define DYNAMIC_LOADING # define SEARCH_FOR_DATA_START extern int _end[]; @@ -1064,17 +1088,7 @@ EXTERN_C_BEGIN # define OS_TYPE "OPENBSD" # define ALIGNMENT 4 # ifndef GC_OPENBSD_THREADS - EXTERN_C_END -# include -# include - EXTERN_C_BEGIN - /* USRSTACK is defined in but that is */ - /* protected by _KERNEL in file. */ -# ifdef USRSTACK -# define STACKBOTTOM ((ptr_t)USRSTACK) -# else -# define HEURISTIC2 -# endif +# define HEURISTIC2 # endif extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) @@ -1225,7 +1239,7 @@ EXTERN_C_BEGIN # define DATASTART_IS_FUNC # define DATAEND ((ptr_t)(_end)) # if !defined(USE_MMAP) && defined(REDIRECT_MALLOC) -# define USE_MMAP +# define USE_MMAP 1 /* Otherwise we now use calloc. Mmap may result in the */ /* heap interleaved with thread stacks, which can result in */ /* excessive blacklisting. Sbrk is unusable since it */ @@ -1271,9 +1285,10 @@ EXTERN_C_BEGIN # define OS_TYPE "LINUX" # ifdef __ELF__ # define DYNAMIC_LOADING -# else -# error --> Linux SPARC a.out not supported +# elif !defined(CPPCHECK) +# error Linux SPARC a.out not supported # endif +# define COUNT_UNMAPPED_REGIONS extern int _end[]; extern int _etext[]; # define DATAEND ((ptr_t)(_end)) @@ -1290,15 +1305,7 @@ EXTERN_C_BEGIN # ifdef OPENBSD # define OS_TYPE "OPENBSD" # ifndef GC_OPENBSD_THREADS - EXTERN_C_END -# include -# include - EXTERN_C_BEGIN -# ifdef USRSTACK -# define STACKBOTTOM ((ptr_t)USRSTACK) -# else -# define HEURISTIC2 -# endif +# define HEURISTIC2 # endif extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) @@ -1328,11 +1335,13 @@ EXTERN_C_BEGIN # endif extern char etext[]; extern char edata[]; - extern char end[]; +# if !defined(CPPCHECK) + extern char end[]; +# endif # define NEED_FIND_LIMIT # define DATASTART ((ptr_t)(&etext)) - ptr_t GC_find_limit(ptr_t, GC_bool); -# define DATAEND GC_find_limit(DATASTART, TRUE) + void * GC_find_limit(void *, int); +# define DATAEND (ptr_t)GC_find_limit(DATASTART, TRUE) # define DATAEND_IS_FUNC # define GC_HAVE_DATAREGION2 # define DATASTART2 ((ptr_t)(&edata)) @@ -1342,7 +1351,7 @@ EXTERN_C_BEGIN # ifdef I386 # define MACH_TYPE "I386" -# if defined(__LP64__) || defined(_WIN64) +# if (defined(__LP64__) || defined(_WIN64)) && !defined(CPPCHECK) # error This should be handled as X86_64 # else # define CPP_WORDSZ 32 @@ -1402,7 +1411,7 @@ EXTERN_C_BEGIN # endif # define DYNAMIC_LOADING # if !defined(USE_MMAP) && defined(REDIRECT_MALLOC) -# define USE_MMAP +# define USE_MMAP 1 /* Otherwise we now use calloc. Mmap may result in the */ /* heap interleaved with thread stacks, which can result in */ /* excessive blacklisting. Sbrk is unusable since it */ @@ -1444,7 +1453,7 @@ EXTERN_C_BEGIN # define GETPAGESIZE() (unsigned)sysconf(_SC_PAGESIZE) # define DYNAMIC_LOADING # ifndef USE_MMAP -# define USE_MMAP +# define USE_MMAP 1 # endif # define MAP_FAILED (void *) ((word)-1) # define HEAP_START (ptr_t)0x40000000 @@ -1452,7 +1461,8 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM -# if !defined(GC_LINUX_THREADS) || !defined(REDIRECT_MALLOC) +# define COUNT_UNMAPPED_REGIONS +# if !defined(REDIRECT_MALLOC) # define MPROTECT_VDB # else /* We seem to get random errors in incremental mode, */ @@ -1492,7 +1502,7 @@ EXTERN_C_BEGIN /* (setjmp is used instead to find data_start). The bug */ /* is fixed in Android NDK r8e (so, ok to use sigsetjmp */ /* if gcc4.8+, clang3.2+ or Android API level 18+). */ -# define GC_NO_SIGSETJMP +# define GC_NO_SIGSETJMP 1 # endif # else extern int etext[]; @@ -1529,6 +1539,8 @@ EXTERN_C_BEGIN # endif # ifdef CYGWIN32 # define OS_TYPE "CYGWIN32" +# define WOW64_THREAD_CONTEXT_WORKAROUND +# define RETRY_GET_THREAD_CONTEXT # define DATASTART ((ptr_t)GC_DATASTART) /* From gc.h */ # define DATAEND ((ptr_t)GC_DATAEND) # undef STACK_GRAN @@ -1559,6 +1571,8 @@ EXTERN_C_BEGIN # endif # ifdef MSWIN32 # define OS_TYPE "MSWIN32" +# define WOW64_THREAD_CONTEXT_WORKAROUND +# define RETRY_GET_THREAD_CONTEXT /* STACKBOTTOM and DATASTART are handled specially in */ /* os_dep.c. */ # define MPROTECT_VDB @@ -1585,15 +1599,7 @@ EXTERN_C_BEGIN # ifdef OPENBSD # define OS_TYPE "OPENBSD" # ifndef GC_OPENBSD_THREADS - EXTERN_C_END -# include -# include - EXTERN_C_BEGIN -# ifdef USRSTACK -# define STACKBOTTOM ((ptr_t)USRSTACK) -# else # define HEURISTIC2 -# endif # endif extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) @@ -1654,11 +1660,9 @@ EXTERN_C_BEGIN # include EXTERN_C_BEGIN extern int etext[]; - extern int end[]; void *rtems_get_stack_bottom(void); # define InitStackBottom rtems_get_stack_bottom() # define DATASTART ((ptr_t)etext) -# define DATAEND ((ptr_t)end) # define STACKBOTTOM ((ptr_t)InitStackBottom) # define SIG_SUSPEND SIGUSR1 # define SIG_THR_RESTART SIGUSR2 @@ -1693,7 +1697,7 @@ EXTERN_C_BEGIN # endif # ifdef DARWIN # define OS_TYPE "DARWIN" -# define DARWIN_DONT_PARSE_STACK +# define DARWIN_DONT_PARSE_STACK 1 # define DYNAMIC_LOADING /* XXX: see get_end(3), get_etext() and get_end() should not be used. */ /* These aren't used when dyld support is enabled (it is by default). */ @@ -1733,6 +1737,7 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define DYNAMIC_LOADING +# define COUNT_UNMAPPED_REGIONS extern int _end[]; # pragma weak __data_start extern int __data_start[]; @@ -1754,27 +1759,30 @@ EXTERN_C_BEGIN # endif # endif /* Linux */ # ifdef EWS4800 -# define HEURISTIC2 -# if defined(_MIPS_SZPTR) && (_MIPS_SZPTR == 64) - extern int _fdata[], _end[]; -# define DATASTART ((ptr_t)_fdata) -# define DATAEND ((ptr_t)_end) -# define CPP_WORDSZ _MIPS_SZPTR -# define ALIGNMENT (_MIPS_SZPTR/8) -# else - extern int etext[], edata[], end[]; - extern int _DYNAMIC_LINKING[], _gp[]; -# define DATASTART ((ptr_t)((((word)(etext) + 0x3ffff) & ~0x3ffff) \ - + ((word)(etext) & 0xffff))) -# define DATAEND ((ptr_t)(edata)) -# define GC_HAVE_DATAREGION2 -# define DATASTART2 (_DYNAMIC_LINKING \ - ? (ptr_t)(((word)_gp + 0x8000 + 0x3ffff) & ~0x3ffff) \ - : (ptr_t)edata) -# define DATAEND2 ((ptr_t)(end)) -# define ALIGNMENT 4 -# endif -# define OS_TYPE "EWS4800" +# define HEURISTIC2 +# if defined(_MIPS_SZPTR) && (_MIPS_SZPTR == 64) + extern int _fdata[], _end[]; +# define DATASTART ((ptr_t)_fdata) +# define DATAEND ((ptr_t)_end) +# define CPP_WORDSZ _MIPS_SZPTR +# define ALIGNMENT (_MIPS_SZPTR/8) +# else + extern int etext[], edata[]; +# if !defined(CPPCHECK) + extern int end[]; +# endif + extern int _DYNAMIC_LINKING[], _gp[]; +# define DATASTART ((ptr_t)((((word)(etext) + 0x3ffff) & ~0x3ffff) \ + + ((word)(etext) & 0xffff))) +# define DATAEND ((ptr_t)(edata)) +# define GC_HAVE_DATAREGION2 +# define DATASTART2 (_DYNAMIC_LINKING \ + ? (ptr_t)(((word)_gp + 0x8000 + 0x3ffff) & ~0x3ffff) \ + : (ptr_t)edata) +# define DATAEND2 ((ptr_t)(end)) +# define ALIGNMENT 4 +# endif +# define OS_TYPE "EWS4800" # endif # ifdef ULTRIX # define HEURISTIC2 @@ -1830,20 +1838,13 @@ EXTERN_C_BEGIN # endif # ifdef OPENBSD # define OS_TYPE "OPENBSD" -# define ALIGNMENT 4 +# define CPP_WORDSZ 64 /* all OpenBSD/mips platforms are 64-bit */ +# define ALIGNMENT 8 # ifndef GC_OPENBSD_THREADS - EXTERN_C_END -# include -# include - EXTERN_C_BEGIN -# ifdef USRSTACK -# define STACKBOTTOM ((ptr_t)USRSTACK) -# else -# define HEURISTIC2 -# endif +# define HEURISTIC2 # endif - extern int _fdata[]; -# define DATASTART ((ptr_t)_fdata) + extern int __data_start[]; +# define DATASTART ((ptr_t)__data_start) extern int _end[]; # define DATAEND ((ptr_t)(&_end)) # define DYNAMIC_LOADING @@ -1881,6 +1882,7 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define DYNAMIC_LOADING +# define COUNT_UNMAPPED_REGIONS extern int _end[]; extern int __data_start[]; # define DATASTART ((ptr_t)(__data_start)) @@ -1899,6 +1901,7 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define DYNAMIC_LOADING +# define COUNT_UNMAPPED_REGIONS extern int _end[]; extern int __data_start[]; # define DATASTART ((ptr_t)(__data_start)) @@ -1929,6 +1932,9 @@ EXTERN_C_BEGIN # define OS_TYPE "HPUX" extern int __data_start[]; # define DATASTART ((ptr_t)(__data_start)) +# ifdef USE_MMAP +# define USE_MMAP_ANON +# endif # ifdef USE_HPUX_FIXED_STACKBOTTOM /* The following appears to work for 7xx systems running HP/UX */ /* 9.xx. Furthermore, it might result in much faster */ @@ -1937,13 +1943,22 @@ EXTERN_C_BEGIN /* default, since it may not work on older machine/OS */ /* combinations. (Thanks to Raymond X.T. Nijssen for uncovering */ /* this.) */ + /* This technique also doesn't work with HP/UX 11.xx. The */ + /* stack size is settable using the kernel maxssiz variable, */ + /* and in 11.23 and latter, the size can be set dynamically. */ + /* It also doesn't handle SHMEM_MAGIC binaries which have */ + /* stack and data in the first quadrant. */ # define STACKBOTTOM ((ptr_t)0x7b033000) /* from /etc/conf/h/param.h */ -# else +# elif defined(USE_ENVIRON_POINTER) /* Gustavo Rodriguez-Rivera suggested changing HEURISTIC2 */ /* to this. Note that the GC must be initialized before the */ - /* first putenv call. */ + /* first putenv call. Unfortunately, some clients do not obey. */ extern char ** environ; # define STACKBOTTOM ((ptr_t)environ) +# elif !defined(HEURISTIC2) + /* This uses pst_vm_status support. */ +# define HPUX_MAIN_STACKBOTTOM +# define NEED_FIND_LIMIT # endif # define DYNAMIC_LOADING EXTERN_C_END @@ -1960,6 +1975,7 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM +# define COUNT_UNMAPPED_REGIONS # define DYNAMIC_LOADING # define SEARCH_FOR_DATA_START extern int _end[]; @@ -1968,15 +1984,7 @@ EXTERN_C_BEGIN # ifdef OPENBSD # define OS_TYPE "OPENBSD" # ifndef GC_OPENBSD_THREADS - EXTERN_C_END -# include -# include - EXTERN_C_BEGIN -# ifdef USRSTACK -# define STACKBOTTOM ((ptr_t)USRSTACK) -# else -# define HEURISTIC2 -# endif +# define HEURISTIC2 # endif extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) @@ -2004,15 +2012,7 @@ EXTERN_C_BEGIN # define OS_TYPE "OPENBSD" # define ELF_CLASS ELFCLASS64 # ifndef GC_OPENBSD_THREADS - EXTERN_C_END -# include -# include - EXTERN_C_BEGIN -# ifdef USRSTACK -# define STACKBOTTOM ((ptr_t)USRSTACK) -# else # define HEURISTIC2 -# endif # endif extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) @@ -2033,11 +2033,13 @@ EXTERN_C_BEGIN /* Handle unmapped hole alpha*-*-freebsd[45]* puts between etext and edata. */ extern char etext[]; extern char edata[]; - extern char end[]; +# if !defined(CPPCHECK) + extern char end[]; +# endif # define NEED_FIND_LIMIT # define DATASTART ((ptr_t)(&etext)) - ptr_t GC_find_limit(ptr_t, GC_bool); -# define DATAEND GC_find_limit(DATASTART, TRUE) + void * GC_find_limit(void *, int); +# define DATAEND (ptr_t)GC_find_limit(DATASTART, TRUE) # define DATAEND_IS_FUNC # define GC_HAVE_DATAREGION2 # define DATASTART2 ((ptr_t)(&edata)) @@ -2069,6 +2071,7 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM +# define COUNT_UNMAPPED_REGIONS # ifdef __ELF__ # define SEARCH_FOR_DATA_START # define DYNAMIC_LOADING @@ -2077,9 +2080,11 @@ EXTERN_C_BEGIN # endif extern int _end[]; # define DATAEND ((ptr_t)(_end)) -# define MPROTECT_VDB +# if !defined(REDIRECT_MALLOC) +# define MPROTECT_VDB /* Has only been superficially tested. May not */ /* work on all versions. */ +# endif # endif # endif @@ -2091,8 +2096,8 @@ EXTERN_C_BEGIN /* Requires 8 byte alignment for malloc */ # define ALIGNMENT 4 # else -# ifndef _LP64 -# error --> unknown ABI +# if !defined(_LP64) && !defined(CPPCHECK) +# error Unknown ABI # endif # define CPP_WORDSZ 64 /* Requires 16 byte alignment for malloc */ @@ -2101,6 +2106,9 @@ EXTERN_C_BEGIN # define OS_TYPE "HPUX" extern int __data_start[]; # define DATASTART ((ptr_t)(__data_start)) +# ifdef USE_MMAP +# define USE_MMAP_ANON +# endif /* Gustavo Rodriguez-Rivera suggested changing HEURISTIC2 */ /* to this. Note that the GC must be initialized before the */ /* first putenv call. */ @@ -2134,6 +2142,7 @@ EXTERN_C_BEGIN /* backing store. */ extern ptr_t GC_register_stackbottom; # define BACKING_STORE_BASE GC_register_stackbottom +# define COUNT_UNMAPPED_REGIONS # define SEARCH_FOR_DATA_START # ifdef __GNUC__ # define DYNAMIC_LOADING @@ -2142,8 +2151,10 @@ EXTERN_C_BEGIN /* statically linked executables and an undefined reference */ /* to _DYNAMIC */ # endif -# define MPROTECT_VDB +# if !defined(REDIRECT_MALLOC) +# define MPROTECT_VDB /* Requires Linux 2.3.47 or later. */ +# endif extern int _end[]; # define DATAEND ((ptr_t)(_end)) # ifdef __GNUC__ @@ -2164,17 +2175,6 @@ EXTERN_C_BEGIN # endif /* __INTEL_COMPILER */ # endif # endif -# ifdef CYGWIN32 -# define OS_TYPE "CYGWIN32" -# define DATASTART ((ptr_t)GC_DATASTART) /* From gc.h */ -# define DATAEND ((ptr_t)GC_DATAEND) -# undef STACK_GRAN -# define STACK_GRAN 0x10000 -# ifdef USE_MMAP -# define NEED_FIND_LIMIT -# define USE_MMAP_ANON -# endif -# endif # ifdef MSWIN32 /* FIXME: This is a very partial guess. There is no port, yet. */ # define OS_TYPE "MSWIN32" @@ -2241,6 +2241,7 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM +# define COUNT_UNMAPPED_REGIONS # define DYNAMIC_LOADING extern int __data_start[] __attribute__((__weak__)); # define DATASTART ((ptr_t)(__data_start)) @@ -2266,22 +2267,29 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM +# define COUNT_UNMAPPED_REGIONS # define DYNAMIC_LOADING - extern int __data_start[]; +# if defined(HOST_ANDROID) +# define SEARCH_FOR_DATA_START +# else + extern int __data_start[]; +# define DATASTART ((ptr_t)__data_start) +# endif extern int _end[]; -# define DATASTART ((ptr_t)__data_start) # define DATAEND ((ptr_t)(&_end)) # endif # ifdef DARWIN /* iOS */ # define OS_TYPE "DARWIN" -# define DARWIN_DONT_PARSE_STACK +# define DARWIN_DONT_PARSE_STACK 1 # define DYNAMIC_LOADING # define DATASTART ((ptr_t)get_etext()) # define DATAEND ((ptr_t)get_end()) # define STACKBOTTOM ((ptr_t)0x16fdfffff) # define USE_MMAP_ANON -# define MPROTECT_VDB + /* MPROTECT_VDB causes use of non-public API like exc_server, */ + /* this could be a reason for blocking the client application in */ + /* the store. */ EXTERN_C_END # include EXTERN_C_BEGIN @@ -2314,14 +2322,33 @@ EXTERN_C_BEGIN # define ELF_CLASS ELFCLASS64 # define DYNAMIC_LOADING # endif +# ifdef OPENBSD +# define OS_TYPE "OPENBSD" +# define ELF_CLASS ELFCLASS64 +# ifndef GC_OPENBSD_THREADS +# define HEURISTIC2 +# endif + extern int __data_start[]; +# define DATASTART ((ptr_t)__data_start) + extern int _end[]; +# define DATAEND ((ptr_t)(&_end)) +# define DYNAMIC_LOADING +# endif # ifdef NINTENDO_SWITCH extern int __bss_end[]; -# define NO_HANDLE_FORK +# define NO_HANDLE_FORK 1 # define DATASTART (ptr_t)ALIGNMENT /* cannot be null */ # define DATAEND (ptr_t)(&__bss_end) void *switch_get_stack_bottom(void); # define STACKBOTTOM ((ptr_t)switch_get_stack_bottom()) # endif +# ifdef MSWIN32 /* UWP */ +# define OS_TYPE "MSWIN32" + /* TODO: Enable GWW_VDB and/or MPROTECT_VDB */ +# ifndef DATAEND +# define DATAEND /* not needed */ +# endif +# endif # ifdef NOSYS /* __data_start is usually defined in the target linker script. */ extern int __data_start[]; @@ -2354,6 +2381,7 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM +# define COUNT_UNMAPPED_REGIONS # undef STACK_GRAN # define STACK_GRAN 0x10000000 # ifdef __ELF__ @@ -2406,13 +2434,13 @@ EXTERN_C_BEGIN # ifdef DARWIN /* iOS */ # define OS_TYPE "DARWIN" -# define DARWIN_DONT_PARSE_STACK +# define DARWIN_DONT_PARSE_STACK 1 # define DYNAMIC_LOADING # define DATASTART ((ptr_t)get_etext()) # define DATAEND ((ptr_t)get_end()) # define STACKBOTTOM ((ptr_t)0x30000000) # define USE_MMAP_ANON -# define MPROTECT_VDB + /* MPROTECT_VDB causes use of non-public API. */ EXTERN_C_END # include EXTERN_C_BEGIN @@ -2427,15 +2455,7 @@ EXTERN_C_BEGIN # ifdef OPENBSD # define OS_TYPE "OPENBSD" # ifndef GC_OPENBSD_THREADS - EXTERN_C_END -# include -# include - EXTERN_C_BEGIN -# ifdef USRSTACK -# define STACKBOTTOM ((ptr_t)USRSTACK) -# else -# define HEURISTIC2 -# endif +# define HEURISTIC2 # endif extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) @@ -2444,7 +2464,7 @@ EXTERN_C_BEGIN # define DYNAMIC_LOADING # endif # ifdef SN_TARGET_PSP2 -# define NO_HANDLE_FORK +# define NO_HANDLE_FORK 1 # define DATASTART (ptr_t)ALIGNMENT # define DATAEND (ptr_t)ALIGNMENT void *psp2_get_stack_bottom(void); @@ -2458,6 +2478,13 @@ EXTERN_C_BEGIN void *n3ds_get_stack_bottom(void); # define STACKBOTTOM ((ptr_t)n3ds_get_stack_bottom()) # endif +# ifdef MSWIN32 /* UWP */ +# define OS_TYPE "MSWIN32" + /* TODO: Enable GWW_VDB and/or MPROTECT_VDB */ +# ifndef DATAEND +# define DATAEND /* not needed */ +# endif +# endif # ifdef NOSYS /* __data_start is usually defined in the target linker script. */ extern int __data_start[]; @@ -2475,6 +2502,7 @@ EXTERN_C_BEGIN # define OS_TYPE "LINUX" # define DYNAMIC_LOADING # define LINUX_STACKBOTTOM +# define COUNT_UNMAPPED_REGIONS # define SEARCH_FOR_DATA_START extern int _end[]; # define DATAEND ((ptr_t)(_end)) @@ -2490,6 +2518,7 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM +# define COUNT_UNMAPPED_REGIONS # define DYNAMIC_LOADING # define SEARCH_FOR_DATA_START extern int _end[]; @@ -2505,15 +2534,7 @@ EXTERN_C_BEGIN # ifdef OPENBSD # define OS_TYPE "OPENBSD" # ifndef GC_OPENBSD_THREADS - EXTERN_C_END -# include -# include - EXTERN_C_BEGIN -# ifdef USRSTACK -# define STACKBOTTOM ((ptr_t)USRSTACK) -# else -# define HEURISTIC2 -# endif +# define HEURISTIC2 # endif extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) @@ -2537,6 +2558,7 @@ EXTERN_C_BEGIN # define OS_TYPE "LINUX" # define DYNAMIC_LOADING # define LINUX_STACKBOTTOM +# define COUNT_UNMAPPED_REGIONS # define SEARCH_FOR_DATA_START extern int _end[]; # define DATAEND ((ptr_t)(_end)) @@ -2549,6 +2571,7 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM +# define COUNT_UNMAPPED_REGIONS # undef STACK_GRAN # define STACK_GRAN 0x10000000 # define DYNAMIC_LOADING @@ -2583,15 +2606,7 @@ EXTERN_C_BEGIN # define OS_TYPE "OPENBSD" # define ELF_CLASS ELFCLASS64 # ifndef GC_OPENBSD_THREADS - EXTERN_C_END -# include -# include - EXTERN_C_BEGIN -# ifdef USRSTACK -# define STACKBOTTOM ((ptr_t)USRSTACK) -# else # define HEURISTIC2 -# endif # endif extern int __data_start[]; extern int _end[]; @@ -2602,13 +2617,14 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM -# if !defined(GC_LINUX_THREADS) || !defined(REDIRECT_MALLOC) +# if !defined(REDIRECT_MALLOC) # define MPROTECT_VDB # else /* We seem to get random errors in incremental mode, */ /* possibly because Linux threads is itself a malloc client */ /* and can't deal with the signals. */ # endif +# define COUNT_UNMAPPED_REGIONS # ifdef __ELF__ # define DYNAMIC_LOADING EXTERN_C_END @@ -2640,7 +2656,7 @@ EXTERN_C_BEGIN # endif # ifdef DARWIN # define OS_TYPE "DARWIN" -# define DARWIN_DONT_PARSE_STACK +# define DARWIN_DONT_PARSE_STACK 1 # define DYNAMIC_LOADING /* XXX: see get_end(3), get_etext() and get_end() should not be used. */ /* These aren't used when dyld support is enabled (it is by default) */ @@ -2677,6 +2693,11 @@ EXTERN_C_BEGIN /* SIGTSTP and SIGCONT could be used alternatively. */ # endif # define FREEBSD_STACKBOTTOM +# if defined(__DragonFly__) + /* DragonFly BSD still has vm.max_proc_mmap, according to */ + /* its mmap(2) man page. */ +# define COUNT_UNMAPPED_REGIONS +# endif # ifdef __ELF__ # define DYNAMIC_LOADING # endif @@ -2741,7 +2762,7 @@ EXTERN_C_BEGIN # endif # define DYNAMIC_LOADING # if !defined(USE_MMAP) && defined(REDIRECT_MALLOC) -# define USE_MMAP +# define USE_MMAP 1 /* Otherwise we now use calloc. Mmap may result in the */ /* heap interleaved with thread stacks, which can result in */ /* excessive blacklisting. Sbrk is unusable since it */ @@ -2753,6 +2774,13 @@ EXTERN_C_BEGIN # define HEAP_START DATAEND # endif # endif +# ifdef CYGWIN32 +# define OS_TYPE "CYGWIN32" +# define RETRY_GET_THREAD_CONTEXT +# ifdef USE_MMAP +# define USE_MMAP_ANON +# endif +# endif # ifdef MSWIN_XBOX1 # define NO_GETENV # define DATASTART (ptr_t)ALIGNMENT @@ -2761,7 +2789,7 @@ EXTERN_C_BEGIN # define STACKBOTTOM ((ptr_t)durango_get_stack_bottom()) # define GETPAGESIZE() 4096 # ifndef USE_MMAP -# define USE_MMAP +# define USE_MMAP 1 # endif /* The following is from sys/mman.h: */ # define PROT_NONE 0 @@ -2774,6 +2802,7 @@ EXTERN_C_BEGIN # endif # ifdef MSWIN32 # define OS_TYPE "MSWIN32" +# define RETRY_GET_THREAD_CONTEXT /* STACKBOTTOM and DATASTART are handled specially in */ /* os_dep.c. */ # if !defined(__GNUC__) || defined(__INTEL_COMPILER) \ @@ -2796,24 +2825,27 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM +# define COUNT_UNMAPPED_REGIONS # define MPROTECT_VDB # ifdef __ELF__ -# define DYNAMIC_LOADING +# if !defined(REDIRECT_MALLOC) +# define MPROTECT_VDB +# endif EXTERN_C_END # include EXTERN_C_BEGIN # if defined(__GLIBC__) && __GLIBC__ >= 2 # define SEARCH_FOR_DATA_START # else -# error --> unknown Hexagon libc configuration +# error Unknown Hexagon libc configuration # endif extern int _end[]; # define DATAEND ((ptr_t)(_end)) # elif !defined(CPPCHECK) -# error --> bad Hexagon Linux configuration +# error Bad Hexagon Linux configuration # endif # else -# error --> unknown Hexagon OS configuration +# error Unknown Hexagon OS configuration # endif # endif @@ -2828,6 +2860,7 @@ EXTERN_C_BEGIN extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) # define LINUX_STACKBOTTOM +# define COUNT_UNMAPPED_REGIONS # define DYNAMIC_LOADING # endif # endif @@ -2846,6 +2879,7 @@ EXTERN_C_BEGIN extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) # define LINUX_STACKBOTTOM +# define COUNT_UNMAPPED_REGIONS # define DYNAMIC_LOADING # endif # endif @@ -2856,9 +2890,10 @@ EXTERN_C_BEGIN # define ALIGNMENT (CPP_WORDSZ/8) # ifdef LINUX # define OS_TYPE "LINUX" - extern int __data_start[]; + extern int __data_start[] __attribute__((__weak__)); # define DATASTART ((ptr_t)__data_start) # define LINUX_STACKBOTTOM +# define COUNT_UNMAPPED_REGIONS # define DYNAMIC_LOADING # endif # endif /* RISCV */ @@ -2868,6 +2903,10 @@ EXTERN_C_BEGIN # define USE_LIBC_PRIVATES #endif +#ifdef NO_RETRY_GET_THREAD_CONTEXT +# undef RETRY_GET_THREAD_CONTEXT +#endif + #if defined(LINUX_STACKBOTTOM) && defined(NO_PROC_STAT) \ && !defined(USE_LIBC_PRIVATES) /* This combination will fail, since we have no way to get */ @@ -2879,7 +2918,7 @@ EXTERN_C_BEGIN #endif #if defined(USE_MMAP_ANON) && !defined(USE_MMAP) -# define USE_MMAP +# define USE_MMAP 1 #elif defined(LINUX) && defined(USE_MMAP) /* The kernel may do a somewhat better job merging mappings etc. */ /* with anonymous mappings. */ @@ -2925,14 +2964,17 @@ EXTERN_C_BEGIN #endif #ifndef DATAEND - extern int end[]; +# if !defined(CPPCHECK) + extern int end[]; +# endif # define DATAEND ((ptr_t)(end)) #endif /* Workaround for Android NDK clang 3.5+ (as of NDK r10e) which does */ /* not provide correct _end symbol. Unfortunately, alternate __end__ */ /* symbol is provided only by NDK "bfd" linker. */ -#if defined(HOST_ANDROID) && defined(__clang__) +#if defined(HOST_ANDROID) && defined(__clang__) \ + && !defined(BROKEN_UUENDUU_SYM) # undef DATAEND # pragma weak __end__ extern int __end__[]; @@ -3033,14 +3075,12 @@ EXTERN_C_BEGIN #if defined(CPPCHECK) # undef CPP_WORDSZ # define CPP_WORDSZ (__SIZEOF_POINTER__ * 8) -#endif - -#if CPP_WORDSZ != 32 && CPP_WORDSZ != 64 -# error --> bad word size +#elif CPP_WORDSZ != 32 && CPP_WORDSZ != 64 +# error Bad word size #endif #if !defined(ALIGNMENT) && !defined(CPPCHECK) -# error --> undefined ALIGNMENT +# error Undefined ALIGNMENT #endif #ifdef PCR @@ -3055,7 +3095,7 @@ EXTERN_C_BEGIN #if !defined(STACKBOTTOM) && (defined(ECOS) || defined(NOSYS)) \ && !defined(CPPCHECK) -# error --> undefined STACKBOTTOM +# error Undefined STACKBOTTOM #endif #ifdef IGNORE_DYNAMIC_LOADING @@ -3069,15 +3109,19 @@ EXTERN_C_BEGIN #if (defined(MSWIN32) || defined(MSWINCE)) && !defined(USE_WINALLOC) /* USE_WINALLOC is only an option for Cygwin. */ -# define USE_WINALLOC +# define USE_WINALLOC 1 #endif #ifdef USE_WINALLOC # undef USE_MMAP #endif -#if defined(LINUX) || defined(FREEBSD) || defined(SOLARIS) || defined(IRIX5) \ - || ((defined(USE_MMAP) || defined(USE_MUNMAP)) && !defined(USE_WINALLOC)) +#if defined(DARWIN) || defined(FREEBSD) || defined(HAIKU) \ + || defined(IRIX5) || defined(LINUX) || defined(NETBSD) \ + || defined(OPENBSD) || defined(SOLARIS) \ + || ((defined(CYGWIN32) || defined(USE_MMAP) || defined(USE_MUNMAP)) \ + && !defined(USE_WINALLOC)) + /* Try both sbrk and mmap, in that order. */ # define MMAP_SUPPORTED #endif @@ -3091,6 +3135,20 @@ EXTERN_C_BEGIN # define MUNMAP_THRESHOLD 2 #endif +#if defined(USE_MUNMAP) && defined(COUNT_UNMAPPED_REGIONS) \ + && !defined(GC_UNMAPPED_REGIONS_SOFT_LIMIT) + /* The default limit of vm.max_map_count on Linux is ~65530. */ + /* There is approximately one mapped region to every unmapped region. */ + /* Therefore if we aim to use up to half of vm.max_map_count for the */ + /* GC (leaving half for the rest of the process) then the number of */ + /* unmapped regions should be one quarter of vm.max_map_count. */ +# if defined(__DragonFly__) +# define GC_UNMAPPED_REGIONS_SOFT_LIMIT (1000000 / 4) +# else +# define GC_UNMAPPED_REGIONS_SOFT_LIMIT 16384 +# endif +#endif + #if defined(GC_DISABLE_INCREMENTAL) || defined(DEFAULT_VDB) # undef GWW_VDB # undef MPROTECT_VDB @@ -3107,6 +3165,12 @@ EXTERN_C_BEGIN # undef GWW_VDB #endif +#if defined(BASE_ATOMIC_OPS_EMULATED) + /* GC_write_fault_handler() cannot use lock-based atomic primitives */ + /* as this could lead to a deadlock. */ +# undef MPROTECT_VDB +#endif + #if defined(USE_MUNMAP) && defined(GWW_VDB) # undef MPROTECT_VDB /* TODO: Cannot deal with address space holes. */ /* Else if MPROTECT_VDB is available but not GWW_VDB then decide */ @@ -3116,6 +3180,11 @@ EXTERN_C_BEGIN /* PARALLEL_MARK does not cause undef MPROTECT_VDB any longer. */ +#if defined(USE_PROC_FOR_LIBRARIES) && defined(GC_LINUX_THREADS) + /* Incremental GC is incompatible with /proc roots. */ +# undef MPROTECT_VDB +#endif + #if defined(MPROTECT_VDB) && defined(GC_PREFER_MPROTECT_VDB) /* Choose MPROTECT_VDB manually (if multiple strategies available). */ # undef PCR_VDB @@ -3128,6 +3197,10 @@ EXTERN_C_BEGIN # undef MPROTECT_VDB #endif +#if defined(MPROTECT_VDB) && !defined(MSWIN32) && !defined(MSWINCE) +# include /* for SA_SIGINFO, SIGBUS */ +#endif + #if defined(SIGBUS) && !defined(HAVE_SIGBUS) && !defined(CPPCHECK) # define HAVE_SIGBUS #endif @@ -3136,7 +3209,8 @@ EXTERN_C_BEGIN # define NO_SA_SIGACTION #endif -#if defined(NO_SA_SIGACTION) && defined(MPROTECT_VDB) && !defined(DARWIN) \ +#if (defined(NO_SA_SIGACTION) || defined(GC_NO_SIGSETJMP)) \ + && defined(MPROTECT_VDB) && !defined(DARWIN) \ && !defined(MSWIN32) && !defined(MSWINCE) # undef MPROTECT_VDB #endif @@ -3155,7 +3229,7 @@ EXTERN_C_BEGIN || (defined(LINUX) && !defined(__gnu_linux__)) \ || (defined(RTEMS) && defined(I386)) || defined(HOST_ANDROID)) \ && !defined(NO_GETCONTEXT) -# define NO_GETCONTEXT +# define NO_GETCONTEXT 1 #endif #ifndef PREFETCH @@ -3221,33 +3295,33 @@ EXTERN_C_BEGIN #endif #if !defined(CPPCHECK) -#if defined(GC_IRIX_THREADS) && !defined(IRIX5) -# error --> inconsistent configuration -#endif -#if defined(GC_LINUX_THREADS) && !defined(LINUX) && !defined(NACL) -# error --> inconsistent configuration -#endif -#if defined(GC_NETBSD_THREADS) && !defined(NETBSD) -# error --> inconsistent configuration -#endif -#if defined(GC_FREEBSD_THREADS) && !defined(FREEBSD) -# error --> inconsistent configuration -#endif -#if defined(GC_SOLARIS_THREADS) && !defined(SOLARIS) -# error --> inconsistent configuration -#endif -#if defined(GC_HPUX_THREADS) && !defined(HPUX) -# error --> inconsistent configuration -#endif -#if defined(GC_AIX_THREADS) && !defined(_AIX) -# error --> inconsistent configuration -#endif -#if defined(GC_WIN32_THREADS) && !defined(CYGWIN32) && !defined(MSWIN32) \ - && !defined(MSWINCE) && !defined(MSWIN_XBOX1) -# error --> inconsistent configuration -#endif +# if defined(GC_IRIX_THREADS) && !defined(IRIX5) +# error Inconsistent configuration +# endif +# if defined(GC_LINUX_THREADS) && !defined(LINUX) && !defined(NACL) +# error Inconsistent configuration +# endif +# if defined(GC_NETBSD_THREADS) && !defined(NETBSD) +# error Inconsistent configuration +# endif +# if defined(GC_FREEBSD_THREADS) && !defined(FREEBSD) +# error Inconsistent configuration +# endif +# if defined(GC_SOLARIS_THREADS) && !defined(SOLARIS) +# error Inconsistent configuration +# endif +# if defined(GC_HPUX_THREADS) && !defined(HPUX) +# error Inconsistent configuration +# endif +# if defined(GC_AIX_THREADS) && !defined(_AIX) +# error Inconsistent configuration +# endif +# if defined(GC_WIN32_THREADS) && !defined(CYGWIN32) && !defined(MSWIN32) \ + && !defined(MSWINCE) && !defined(MSWIN_XBOX1) +# error Inconsistent configuration +# endif # if defined(GC_WIN32_PTHREADS) && defined(CYGWIN32) -# error --> inconsistent configuration +# error Inconsistent configuration # endif #endif /* !CPPCHECK */ @@ -3259,7 +3333,7 @@ EXTERN_C_BEGIN #endif #if defined(PARALLEL_MARK) && !defined(THREADS) && !defined(CPPCHECK) -# error "invalid config - PARALLEL_MARK requires GC_THREADS" +# error Invalid config: PARALLEL_MARK requires GC_THREADS #endif #if (((defined(MSWIN32) || defined(MSWINCE)) && !defined(__GNUC__)) \ @@ -3461,11 +3535,11 @@ EXTERN_C_BEGIN || (defined(SOLARIS) && (!defined(_XOPEN_SOURCE) \ || defined(__EXTENSIONS__))) \ || defined(LINUX)) && !defined(HAVE_DLADDR) -# define HAVE_DLADDR +# define HAVE_DLADDR 1 #endif #if defined(MAKE_BACK_GRAPH) && !defined(DBG_HDRS_ALL) -# define DBG_HDRS_ALL +# define DBG_HDRS_ALL 1 #endif #if defined(POINTER_MASK) && !defined(POINTER_SHIFT) @@ -3477,11 +3551,7 @@ EXTERN_C_BEGIN #endif #if !defined(FIXUP_POINTER) && defined(POINTER_MASK) -# if defined(CPPCHECK) -# define FIXUP_POINTER(p) (p = (p) << 4) /* e.g. */ -# else -# define FIXUP_POINTER(p) (p = ((p) & POINTER_MASK) << POINTER_SHIFT) -# endif +# define FIXUP_POINTER(p) (p = ((p) & POINTER_MASK) << POINTER_SHIFT) #endif #if defined(FIXUP_POINTER) @@ -3496,21 +3566,19 @@ EXTERN_C_BEGIN /* Some static sanity tests. */ #if !defined(CPPCHECK) -#if defined(MARK_BIT_PER_GRANULE) && defined(MARK_BIT_PER_OBJ) -# error Define only one of MARK_BIT_PER_GRANULE and MARK_BIT_PER_OBJ. -#endif - -#if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN) -# error "Only one of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd." -#endif -#if !defined(STACK_GROWS_UP) && !defined(STACK_GROWS_DOWN) -# error "One of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd." -#endif - -#if defined(REDIRECT_MALLOC) && defined(THREADS) && !defined(LINUX) \ +# if defined(MARK_BIT_PER_GRANULE) && defined(MARK_BIT_PER_OBJ) +# error Define only one of MARK_BIT_PER_GRANULE and MARK_BIT_PER_OBJ +# endif +# if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN) +# error Only one of STACK_GROWS_UP and STACK_GROWS_DOWN should be defined +# endif +# if !defined(STACK_GROWS_UP) && !defined(STACK_GROWS_DOWN) +# error One of STACK_GROWS_UP and STACK_GROWS_DOWN should be defined +# endif +# if defined(REDIRECT_MALLOC) && defined(THREADS) && !defined(LINUX) \ && !defined(REDIRECT_MALLOC_IN_HEADER) -# error "REDIRECT_MALLOC with THREADS works at most on Linux." -#endif +# error REDIRECT_MALLOC with THREADS works at most on Linux +# endif #endif /* !CPPCHECK */ #ifdef GC_PRIVATE_H @@ -3551,8 +3619,8 @@ EXTERN_C_BEGIN GC_page_size)) \ + GC_page_size - 1) # elif defined(MSWIN_XBOX1) - void *durango_get_mem(size_t bytes, size_t page_size); -# define GET_MEM(bytes) (struct hblk *)durango_get_mem(bytes, 0) + ptr_t GC_durango_get_mem(size_t bytes); +# define GET_MEM(bytes) (struct hblk *)GC_durango_get_mem(bytes) # elif defined(MSWIN32) || defined(CYGWIN32) ptr_t GC_win32_get_mem(size_t bytes); # define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes) diff --git a/gc/include/private/pthread_support.h b/gc/include/private/pthread_support.h index 2dc1541ac..17fe8b627 100644 --- a/gc/include/private/pthread_support.h +++ b/gc/include/private/pthread_support.h @@ -132,7 +132,7 @@ typedef struct GC_Thread_Rep { /* and detach. */ # ifdef THREAD_LOCAL_ALLOC - struct thread_local_freelists tlfs; + struct thread_local_freelists tlfs GC_ATTR_WORD_ALIGNED; # endif } * GC_thread; diff --git a/gc/include/private/specific.h b/gc/include/private/specific.h index a1873ac85..ec2ed9b4e 100644 --- a/gc/include/private/specific.h +++ b/gc/include/private/specific.h @@ -12,6 +12,9 @@ * by adding a lock. */ +#ifndef GC_SPECIFIC_H +#define GC_SPECIFIC_H + #include EXTERN_C_BEGIN @@ -113,3 +116,5 @@ GC_INLINE void * GC_getspecific(tsd * key) } EXTERN_C_END + +#endif /* GC_SPECIFIC_H */ diff --git a/gc/include/private/thread_local_alloc.h b/gc/include/private/thread_local_alloc.h index 276de402f..1ffa28b0c 100644 --- a/gc/include/private/thread_local_alloc.h +++ b/gc/include/private/thread_local_alloc.h @@ -95,7 +95,7 @@ typedef struct thread_local_freelists { /* Note: Preserve *_freelists names for some clients. */ # ifdef GC_GCJ_SUPPORT void * gcj_freelists[TINY_FREELISTS]; -# define ERROR_FL ((void *)(word)-1) +# define ERROR_FL ((void *)GC_WORD_MAX) /* Value used for gcj_freelists[-1]; allocation is */ /* erroneous. */ # endif diff --git a/gc/mach_dep.c b/gc/mach_dep.c index 60b73b228..49d81bb63 100644 --- a/gc/mach_dep.c +++ b/gc/mach_dep.c @@ -228,7 +228,7 @@ GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *), volatile ptr_t arg) { volatile int dummy; - void * volatile context = 0; + volatile ptr_t context = 0; # if defined(HAVE_PUSH_REGS) GC_push_regs(); @@ -263,7 +263,7 @@ GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *), /* getcontext() is broken, do not try again. */ /* E.g., to workaround a bug in Docker ubuntu_32bit. */ } else { - context = &ctxt; + context = (ptr_t)&ctxt; } if (EXPECT(0 == getcontext_works, FALSE)) getcontext_works = context != NULL ? 1 : -1; @@ -327,11 +327,11 @@ GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *), # endif /* !HAVE_PUSH_REGS */ /* TODO: context here is sometimes just zero. At the moment, the */ /* callees don't really need it. */ - fn(arg, context); + fn(arg, (/* no volatile */ void *)context); /* Strongly discourage the compiler from treating the above */ /* as a tail-call, since that would pop the register */ /* contents before we get a chance to look at them. */ - GC_noop1((word)(&dummy)); + GC_noop1(COVERT_DATAFLOW(&dummy)); } #endif /* !SN_TARGET_ORBIS && !SN_TARGET_PSP2 */ diff --git a/gc/mallocx.c b/gc/mallocx.c index 9e93c7071..77d284ad7 100644 --- a/gc/mallocx.c +++ b/gc/mallocx.c @@ -349,10 +349,9 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t lb, int k, void **result) struct hblk * hbp; hdr * hhdr; - rlh += lg; - while ((hbp = *rlh) != 0) { + while ((hbp = rlh[lg]) != NULL) { hhdr = HDR(hbp); - *rlh = hhdr -> hb_next; + rlh[lg] = hhdr -> hb_next; GC_ASSERT(hhdr -> hb_sz == lb); hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no; # ifdef PARALLEL_MARK @@ -416,6 +415,9 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t lb, int k, void **result) /* GC lock is needed for reclaim list access. We */ /* must decrement fl_builder_count before reacquiring */ /* the lock. Hopefully this path is rare. */ + + rlh = ok -> ok_reclaim_list; /* reload rlh after locking */ + if (NULL == rlh) break; } # endif } diff --git a/gc/mark.c b/gc/mark.c index b1d59026c..93b01c839 100644 --- a/gc/mark.c +++ b/gc/mark.c @@ -40,7 +40,7 @@ void GC_noop6(word arg1 GC_ATTR_UNUSED, word arg2 GC_ATTR_UNUSED, word arg5 GC_ATTR_UNUSED, word arg6 GC_ATTR_UNUSED) { /* Avoid GC_noop6 calls to be optimized away. */ -# ifdef AO_CLEAR +# if defined(AO_HAVE_compiler_barrier) && !defined(BASE_ATOMIC_OPS_EMULATED) AO_compiler_barrier(); /* to serve as a special side-effect */ # else GC_noop1(0); @@ -123,7 +123,7 @@ STATIC GC_bool GC_objects_are_marked = FALSE; /* Are there collectible marked objects in the heap? */ /* Is a collection in progress? Note that this can return true in the */ -/* nonincremental case, if a collection has been abandoned and the */ +/* non-incremental case, if a collection has been abandoned and the */ /* mark state is now MS_INVALID. */ GC_INNER GC_bool GC_collection_in_progress(void) { @@ -161,7 +161,7 @@ GC_INNER void GC_set_hdr_marks(hdr *hhdr) } # else for (i = 0; i < divWORDSZ(n_marks + WORDSZ); ++i) { - hhdr -> hb_marks[i] = ONES; + hhdr -> hb_marks[i] = GC_WORD_MAX; } # endif # ifdef MARK_BIT_PER_OBJ @@ -502,7 +502,8 @@ static void alloc_mark_stack(size_t); /* to the exception case; our results are invalid and we have */ /* to start over. This cannot be prevented since we can't */ /* block in DllMain. */ - if (GC_started_thread_while_stopped()) goto handle_ex; + if (GC_started_thread_while_stopped()) + goto handle_thr_start; # endif rm_handler: return ret_val; @@ -526,7 +527,7 @@ static void alloc_mark_stack(size_t); # endif er.alt_path = &&handle_ex; # pragma GCC diagnostic pop -# else /* pragma diagnostic is not supported */ +# elif !defined(CPPCHECK) /* pragma diagnostic is not supported */ er.alt_path = &&handle_ex; # endif er.ex_reg.handler = mark_ex_handler; @@ -539,7 +540,7 @@ static void alloc_mark_stack(size_t); goto handle_ex; # if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS) if (GC_started_thread_while_stopped()) - goto handle_ex; + goto handle_thr_start; # endif rm_handler: /* Uninstall the exception handler */ @@ -553,10 +554,17 @@ static void alloc_mark_stack(size_t); /* thread that is in the process of exiting, and disappears */ /* while we are marking it. This seems extremely difficult to */ /* avoid otherwise. */ - if (GC_incremental) { - WARN("Incremental GC incompatible with /proc roots\n", 0); - /* I'm not sure if this could still work ... */ - } +# ifndef DEFAULT_VDB + if (GC_auto_incremental) { + static GC_bool is_warned = FALSE; + + if (!is_warned) { + is_warned = TRUE; + WARN("Incremental GC incompatible with /proc roots\n", 0); + } + /* I'm not sure if this could still work ... */ + } +# endif GC_setup_temporary_fault_handler(); if(SETJMP(GC_jmp_buf) != 0) goto handle_ex; ret_val = GC_mark_some_inner(cold_gc_frame); @@ -578,6 +586,10 @@ static void alloc_mark_stack(size_t); " memory mapping disappeared\n", 0); } } +# if (defined(MSWIN32) || defined(MSWINCE)) && defined(GC_WIN32_THREADS) \ + && !defined(GC_PTHREADS) + handle_thr_start: +# endif /* We have bad roots on the stack. Discard mark stack. */ /* Rescan from marked objects. Redetermine roots. */ # ifdef REGISTER_LIBRARIES_EARLY @@ -1270,7 +1282,7 @@ GC_INNER void GC_scratch_recycle_inner(void *ptr, size_t bytes) /* TODO: Assert correct memory flags if GWW_VDB */ if (page_offset != 0) displ = GC_page_size - page_offset; - recycled_bytes = (bytes - displ) & ~(GC_page_size - 1); + recycled_bytes = bytes > displ ? (bytes - displ) & ~(GC_page_size-1) : 0; GC_COND_LOG_PRINTF("Recycle %lu/%lu scratch-allocated bytes at %p\n", (unsigned long)recycled_bytes, (unsigned long)bytes, ptr); @@ -1521,7 +1533,7 @@ struct trace_entry { word bytes_allocd; word arg1; word arg2; -} GC_trace_buf[TRACE_ENTRIES]; +} GC_trace_buf[TRACE_ENTRIES] = { { NULL, 0, 0, 0, 0 } }; int GC_trace_buf_ptr = 0; @@ -1605,7 +1617,8 @@ GC_INNER void GC_push_all_stack(ptr_t bottom, ptr_t top) # if defined(THREADS) && defined(MPROTECT_VDB) && !GC_auto_incremental # endif - ) { + && (word)GC_mark_stack_top + < (word)(GC_mark_stack_limit - INITIAL_MARK_STACK_SIZE/8)) { GC_push_all(bottom, top); } else # endif @@ -1961,8 +1974,8 @@ STATIC struct hblk * GC_push_next_marked(struct hblk *h) hdr * hhdr = HDR(h); if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr) || HBLK_IS_FREE(hhdr), FALSE)) { - h = GC_next_used_block(h); - if (h == 0) return(0); + h = GC_next_block(h, FALSE); + if (NULL == h) return NULL; hhdr = GC_find_header((ptr_t)h); } else { # ifdef LINT2 @@ -1983,8 +1996,8 @@ STATIC struct hblk * GC_push_next_marked(struct hblk *h) for (;;) { if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr) || HBLK_IS_FREE(hhdr), FALSE)) { - h = GC_next_used_block(h); - if (h == 0) return(0); + h = GC_next_block(h, FALSE); + if (NULL == h) return NULL; hhdr = GC_find_header((ptr_t)h); } else { # ifdef LINT2 @@ -2024,8 +2037,8 @@ STATIC struct hblk * GC_push_next_marked_uncollectable(struct hblk *h) for (;;) { if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr) || HBLK_IS_FREE(hhdr), FALSE)) { - h = GC_next_used_block(h); - if (h == 0) return(0); + h = GC_next_block(h, FALSE); + if (NULL == h) return NULL; hhdr = GC_find_header((ptr_t)h); } else { # ifdef LINT2 diff --git a/gc/mark_rts.c b/gc/mark_rts.c index 7d166eda5..9e3eb1938 100644 --- a/gc/mark_rts.c +++ b/gc/mark_rts.c @@ -502,8 +502,11 @@ STATIC void GC_remove_tmp_roots(void) GC_INNER ptr_t GC_approx_sp(void) { volatile word sp; -# if defined(CPPCHECK) || (__GNUC__ >= 4 /* GC_GNUC_PREREQ(4, 0) */ \ - && !defined(STACK_NOT_SCANNED)) +# if defined(S390) && !defined(CPPCHECK) && (__clang_major__ < 8) + /* Workaround a crash in SystemZTargetLowering of libLLVM-3.8. */ + sp = (word)&sp; +# elif defined(CPPCHECK) || (__GNUC__ >= 4 /* GC_GNUC_PREREQ(4, 0) */ \ + && !defined(STACK_NOT_SCANNED)) /* TODO: Use GC_GNUC_PREREQ after fixing a bug in cppcheck. */ sp = (word)__builtin_frame_address(0); # else diff --git a/gc/misc.c b/gc/misc.c index fe4605be6..0869e0125 100644 --- a/gc/misc.c +++ b/gc/misc.c @@ -314,7 +314,7 @@ STATIC void GC_init_size_map(void) } /* Make sure the recursive call is not a tail call, and the bzero */ /* call is not recognized as dead code. */ - GC_noop1((word)dummy); + GC_noop1(COVERT_DATAFLOW(dummy)); return(arg); } # endif /* !ASM_CLEAR_CODE */ @@ -545,7 +545,7 @@ GC_API void GC_CALL GC_get_heap_usage_safe(GC_word *pheap_size, pstats->non_gc_bytes = GC_non_gc_bytes; pstats->gc_no = GC_gc_no; /* could be -1 */ # ifdef PARALLEL_MARK - pstats->markers_m1 = (word)GC_markers_m1; + pstats->markers_m1 = (word)((signed_word)GC_markers_m1); # else pstats->markers_m1 = 0; /* one marker */ # endif @@ -764,7 +764,7 @@ GC_API int GC_CALL GC_is_init_called(void) STATIC void GC_exit_check(void) { if (GC_find_leak && !skip_gc_atexit) { -# if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) +# ifdef THREADS GC_in_thread_creation = TRUE; /* OK to collect from unknown thread. */ GC_gcollect(); GC_in_thread_creation = FALSE; @@ -817,9 +817,7 @@ GC_API int GC_CALL GC_is_init_called(void) #endif #if defined(MSWIN32) && !defined(MSWINRT_FLAVOR) && !defined(MSWIN_XBOX1) \ - && (!defined(SMALL_CONFIG) \ - || (!defined(_WIN64) && defined(GC_WIN32_THREADS) \ - && defined(CHECK_NOT_WOW64))) + && !defined(SMALL_CONFIG) STATIC void GC_win32_MessageBoxA(const char *msg, const char *caption, unsigned flags) { @@ -832,7 +830,7 @@ GC_API int GC_CALL GC_is_init_called(void) if (hU32) { FARPROC pfn = GetProcAddress(hU32, "MessageBoxA"); if (pfn) - (void)(*(int (WINAPI *)(HWND, LPCSTR, LPCSTR, UINT))pfn)( + (void)(*(int (WINAPI *)(HWND, LPCSTR, LPCSTR, UINT))(word)pfn)( NULL /* hWnd */, msg, caption, flags); (void)FreeLibrary(hU32); } @@ -925,30 +923,6 @@ GC_API void GC_CALL GC_init(void) initial_heap_sz = MINHINCR * HBLKSIZE; # endif -# if defined(MSWIN32) && !defined(_WIN64) && defined(GC_WIN32_THREADS) \ - && defined(CHECK_NOT_WOW64) - { - /* Windows: running 32-bit GC on 64-bit system is broken! */ - /* WoW64 bug affects SuspendThread, no workaround exists. */ - HMODULE hK32 = GetModuleHandle(TEXT("kernel32.dll")); - if (hK32) { - FARPROC pfn = GetProcAddress(hK32, "IsWow64Process"); - BOOL bIsWow64 = FALSE; - if (pfn - && (*(BOOL (WINAPI*)(HANDLE, BOOL*))pfn)(GetCurrentProcess(), - &bIsWow64) - && bIsWow64) { - GC_win32_MessageBoxA("This program uses BDWGC garbage collector" - " compiled for 32-bit but running on 64-bit Windows.\n" - "This is known to be broken due to a design flaw" - " in Windows itself! Expect erratic behavior...", - "32-bit program running on 64-bit system", - MB_ICONWARNING | MB_OK); - } - } - } -# endif - DISABLE_CANCEL(cancel_state); /* Note that although we are nominally called with the */ /* allocation lock held, the allocation lock is now */ @@ -983,14 +957,14 @@ GC_API void GC_CALL GC_init(void) # else { # ifndef MSWINCE - BOOL (WINAPI *pfn)(LPCRITICAL_SECTION, DWORD) = 0; + FARPROC pfn = 0; HMODULE hK32 = GetModuleHandle(TEXT("kernel32.dll")); if (hK32) - pfn = (BOOL (WINAPI *)(LPCRITICAL_SECTION, DWORD)) - GetProcAddress(hK32, - "InitializeCriticalSectionAndSpinCount"); + pfn = GetProcAddress(hK32, + "InitializeCriticalSectionAndSpinCount"); if (pfn) { - pfn(&GC_allocate_ml, SPIN_COUNT); + (*(BOOL (WINAPI *)(LPCRITICAL_SECTION, DWORD))(word)pfn)( + &GC_allocate_ml, SPIN_COUNT); } else # endif /* !MSWINCE */ /* else */ InitializeCriticalSection(&GC_allocate_ml); @@ -1031,7 +1005,7 @@ GC_API void GC_CALL GC_init(void) if (0 != file_name) # endif { - int log_d = open(file_name, O_CREAT|O_WRONLY|O_APPEND, 0666); + int log_d = open(file_name, O_CREAT | O_WRONLY | O_APPEND, 0644); if (log_d < 0) { GC_err_printf("Failed to open %s as log file\n", file_name); } else { @@ -1113,15 +1087,12 @@ GC_API void GC_CALL GC_init(void) } } # endif -# ifndef GC_DISABLE_INCREMENTAL +# if !defined(GC_DISABLE_INCREMENTAL) && !defined(NO_CLOCK) { char * time_limit_string = GETENV("GC_PAUSE_TIME_TARGET"); if (0 != time_limit_string) { long time_limit = atol(time_limit_string); - if (time_limit < 5) { - WARN("GC_PAUSE_TIME_TARGET environment variable value too small " - "or bad syntax: Ignoring\n", 0); - } else { + if (time_limit > 0) { GC_time_limit = time_limit; } } @@ -1154,7 +1125,7 @@ GC_API void GC_CALL GC_init(void) if (space_divisor_string != NULL) { int space_divisor = atoi(space_divisor_string); if (space_divisor > 0) - GC_free_space_divisor = (word)space_divisor; + GC_free_space_divisor = (unsigned)space_divisor; } } # ifdef USE_MUNMAP @@ -1212,7 +1183,7 @@ GC_API void GC_CALL GC_init(void) # if defined(USE_PROC_FOR_LIBRARIES) && defined(GC_LINUX_THREADS) WARN("USE_PROC_FOR_LIBRARIES + GC_LINUX_THREADS performs poorly.\n", 0); /* If thread stacks are cached, they tend to be scanned in */ - /* entirety as part of the root set. This wil grow them to */ + /* entirety as part of the root set. This will grow them to */ /* maximum size, and is generally not desirable. */ # endif # if defined(SEARCH_FOR_DATA_START) @@ -1258,7 +1229,9 @@ GC_API void GC_CALL GC_init(void) # endif # ifndef GC_DISABLE_INCREMENTAL if (GC_incremental || 0 != GETENV("GC_ENABLE_INCREMENTAL")) { -# if defined(CHECKSUMS) || defined(SMALL_CONFIG) +# if defined(BASE_ATOMIC_OPS_EMULATED) || defined(CHECKSUMS) \ + || defined(REDIRECT_MALLOC) || defined(REDIRECT_MALLOC_IN_HEADER) \ + || defined(SMALL_CONFIG) /* TODO: Implement CHECKSUMS for manual VDB. */ # else if (manual_vdb_allowed) { @@ -1301,6 +1274,9 @@ GC_API void GC_CALL GC_init(void) GC_set_max_heap_size(max_heap_sz); } } +# if defined(GC_ASSERTIONS) && defined(GC_ALWAYS_MULTITHREADED) + LOCK(); /* just to set GC_lock_holder */ +# endif if (!GC_expand_hp_inner(divHBLKSZ(initial_heap_sz))) { GC_err_printf("Can't start up: not enough memory\n"); EXIT(); @@ -1328,9 +1304,6 @@ GC_API void GC_CALL GC_init(void) GC_pcr_install(); # endif GC_is_initialized = TRUE; -# if defined(GC_ASSERTIONS) && defined(GC_ALWAYS_MULTITHREADED) - LOCK(); /* just to set GC_lock_holder */ -# endif # if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS) GC_thr_init(); # ifdef PARALLEL_MARK @@ -1403,7 +1376,9 @@ GC_API void GC_CALL GC_enable_incremental(void) GC_init(); LOCK(); } else { -# if !defined(CHECKSUMS) && !defined(SMALL_CONFIG) +# if !defined(BASE_ATOMIC_OPS_EMULATED) && !defined(CHECKSUMS) \ + && !defined(REDIRECT_MALLOC) \ + && !defined(REDIRECT_MALLOC_IN_HEADER) && !defined(SMALL_CONFIG) if (manual_vdb_allowed) { GC_manual_vdb = TRUE; GC_incremental = TRUE; @@ -1732,10 +1707,16 @@ GC_API void GC_CALL GC_enable_incremental(void) # define WRITE(level, buf, len) switch_log_write(buf, len) #else -# if !defined(AMIGA) && !defined(MSWIN_XBOX1) && !defined(SN_TARGET_ORBIS) \ - && !defined(SN_TARGET_PSP2) && !defined(__CC_ARM) -# include -# endif + +# if !defined(SN_TARGET_ORBIS) && !defined(SN_TARGET_PSP2) +# if !defined(AMIGA) && !defined(MSWIN_XBOX1) \ + && !defined(__CC_ARM) +# include +# endif +# if !defined(ECOS) && !defined(NOSYS) +# include +# endif +# endif /* !SN_TARGET_ORBIS && !SN_TARGET_PSP2 */ STATIC int GC_write(int fd, const char *buf, size_t len) { @@ -1753,7 +1734,7 @@ GC_API void GC_CALL GC_enable_incremental(void) IF_CANCEL(int cancel_state;) DISABLE_CANCEL(cancel_state); - while ((size_t)bytes_written < len) { + while ((unsigned)bytes_written < len) { # ifdef GC_SOLARIS_THREADS int result = syscall(SYS_write, fd, buf + bytes_written, len - bytes_written); @@ -1762,6 +1743,8 @@ GC_API void GC_CALL GC_enable_incremental(void) # endif if (-1 == result) { + if (EAGAIN == errno) /* Resource temporarily unavailable */ + continue; RESTORE_CANCEL(cancel_state); return(result); } @@ -1817,8 +1800,13 @@ void GC_printf(const char *format, ...) (void)WRITE(GC_stdout, buf, strlen(buf)); /* Ignore errors silently. */ # else - if (WRITE(GC_stdout, buf, strlen(buf)) < 0) + if (WRITE(GC_stdout, buf, strlen(buf)) < 0 +# if defined(CYGWIN32) + && GC_stdout != GC_DEFAULT_STDOUT_FD +# endif + ) { ABORT("write to stdout failed"); + } # endif } } @@ -1839,8 +1827,13 @@ void GC_log_printf(const char *format, ...) # ifdef NACL (void)WRITE(GC_log, buf, strlen(buf)); # else - if (WRITE(GC_log, buf, strlen(buf)) < 0) + if (WRITE(GC_log, buf, strlen(buf)) < 0 +# if defined(CYGWIN32) + && GC_log != GC_DEFAULT_STDERR_FD +# endif + ) { ABORT("write to GC log failed"); + } # endif } @@ -2130,7 +2123,7 @@ GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func fn, void *arg) result = fn(&base, arg); /* Strongly discourage the compiler from treating the above */ /* as a tail call. */ - GC_noop1((word)(&base)); + GC_noop1(COVERT_DATAFLOW(&base)); return result; } @@ -2155,13 +2148,13 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn, /* GC_get_main_stack_base() is unimplemented or broken for */ /* the platform). */ if ((word)GC_stackbottom HOTTER_THAN (word)(&stacksect)) - GC_stackbottom = (ptr_t)(&stacksect); + GC_stackbottom = (ptr_t)COVERT_DATAFLOW(&stacksect); if (GC_blocked_sp == NULL) { /* We are not inside GC_do_blocking() - do nothing more. */ client_data = fn(client_data); /* Prevent treating the above as a tail call. */ - GC_noop1((word)(&stacksect)); + GC_noop1(COVERT_DATAFLOW(&stacksect)); return client_data; /* result */ } @@ -2225,14 +2218,6 @@ STATIC void GC_do_blocking_inner(ptr_t data, void * context GC_ATTR_UNUSED) #endif /* !THREADS */ -/* Wrapper for functions that are likely to block (or, at least, do not */ -/* allocate garbage collected memory and/or manipulate pointers to the */ -/* garbage collected heap) for an appreciable length of time. */ -/* In the single threaded case, GC_do_blocking() (together */ -/* with GC_call_with_gc_active()) might be used to make stack scanning */ -/* more precise (i.e. scan only stack frames of functions that allocate */ -/* garbage collected memory and/or manipulate pointers to the garbage */ -/* collected heap). */ GC_API void * GC_CALL GC_do_blocking(GC_fn_type fn, void * client_data) { struct blocking_data my_data; @@ -2442,7 +2427,7 @@ GC_API int GC_CALL GC_get_all_interior_pointers(void) GC_API void GC_CALL GC_set_finalize_on_demand(int value) { - GC_ASSERT(value != -1); + GC_ASSERT(value != -1); /* -1 was used to retrieve old value in gc-7.2 */ /* value is of boolean type. */ GC_finalize_on_demand = value; } @@ -2454,7 +2439,7 @@ GC_API int GC_CALL GC_get_finalize_on_demand(void) GC_API void GC_CALL GC_set_java_finalization(int value) { - GC_ASSERT(value != -1); + GC_ASSERT(value != -1); /* -1 was used to retrieve old value in gc-7.2 */ /* value is of boolean type. */ GC_java_finalization = value; } @@ -2466,7 +2451,7 @@ GC_API int GC_CALL GC_get_java_finalization(void) GC_API void GC_CALL GC_set_dont_expand(int value) { - GC_ASSERT(value != -1); + GC_ASSERT(value != -1); /* -1 was used to retrieve old value in gc-7.2 */ /* value is of boolean type. */ GC_dont_expand = value; } @@ -2478,7 +2463,7 @@ GC_API int GC_CALL GC_get_dont_expand(void) GC_API void GC_CALL GC_set_no_dls(int value) { - GC_ASSERT(value != -1); + GC_ASSERT(value != -1); /* -1 was used to retrieve old value in gc-7.2 */ /* value is of boolean type. */ GC_no_dls = value; } @@ -2511,7 +2496,8 @@ GC_API GC_word GC_CALL GC_get_free_space_divisor(void) GC_API void GC_CALL GC_set_max_retries(GC_word value) { - GC_ASSERT(value != ~(word)0); + GC_ASSERT((GC_signed_word)value != -1); + /* -1 was used to retrieve old value in gc-7.2 */ GC_max_retries = value; } @@ -2522,7 +2508,7 @@ GC_API GC_word GC_CALL GC_get_max_retries(void) GC_API void GC_CALL GC_set_dont_precollect(int value) { - GC_ASSERT(value != -1); + GC_ASSERT(value != -1); /* -1 was used to retrieve old value in gc-7.2 */ /* value is of boolean type. */ GC_dont_precollect = value; } @@ -2545,7 +2531,8 @@ GC_API int GC_CALL GC_get_full_freq(void) GC_API void GC_CALL GC_set_time_limit(unsigned long value) { - GC_ASSERT(value != (unsigned long)-1L); + GC_ASSERT((long)value != -1L); + /* -1 was used to retrieve old value in gc-7.2 */ GC_time_limit = value; } diff --git a/gc/new_hblk.c b/gc/new_hblk.c index 5e3ce0682..88de14ddd 100644 --- a/gc/new_hblk.c +++ b/gc/new_hblk.c @@ -18,7 +18,7 @@ /* * This file contains the functions: * ptr_t GC_build_flXXX(h, old_fl) - * void GC_new_hblk(size) + * void GC_new_hblk(size, kind) */ #include diff --git a/gc/os_dep.c b/gc/os_dep.c index 6eee61aa0..b183423a0 100644 --- a/gc/os_dep.c +++ b/gc/os_dep.c @@ -71,7 +71,7 @@ #if defined(MMAP_SUPPORTED) || defined(ADD_HEAP_GUARD_PAGES) # if defined(USE_MUNMAP) && !defined(USE_MMAP) && !defined(CPPCHECK) -# error "invalid config - USE_MUNMAP requires USE_MMAP" +# error Invalid config: USE_MUNMAP requires USE_MMAP # endif # include # include @@ -303,10 +303,12 @@ GC_INNER char * GC_get_maps(void) GC_ASSERT(*p == 'r' || *p == '-'); *prot = (char *)p; /* Skip past protection field to offset field */ - while (!isspace(*p)) ++p; while (isspace(*p)) ++p; + while (!isspace(*p)) ++p; + while (isspace(*p)) p++; GC_ASSERT(isxdigit(*p)); /* Skip past offset field, which we ignore */ - while (!isspace(*p)) ++p; while (isspace(*p)) ++p; + while (!isspace(*p)) ++p; + while (isspace(*p)) p++; maj_dev_start = p; GC_ASSERT(isxdigit(*maj_dev_start)); *maj_dev = strtoul((char *)maj_dev_start, NULL, 16); @@ -420,11 +422,6 @@ GC_INNER char * GC_get_maps(void) # pragma weak __data_start # pragma weak data_start extern int __data_start[], data_start[]; -# ifdef HOST_ANDROID -# pragma weak _etext -# pragma weak __dso_handle - extern int _etext[], __dso_handle[]; -# endif EXTERN_C_END # endif /* LINUX */ @@ -434,20 +431,13 @@ GC_INNER char * GC_get_maps(void) { ptr_t data_end = DATAEND; -# if (defined(LINUX) || defined(HURD)) && !defined(IGNORE_PROG_DATA_START) +# if (defined(LINUX) || defined(HURD)) && defined(USE_PROG_DATA_START) /* Try the easy approaches first: */ -# ifdef HOST_ANDROID - /* Workaround for "gold" (default) linker (as of Android NDK r10e). */ - if ((word)__data_start < (word)_etext - && (word)_etext < (word)__dso_handle) { - GC_data_start = (ptr_t)(__dso_handle); -# ifdef DEBUG_ADD_DEL_ROOTS - GC_log_printf( - "__data_start is wrong; using __dso_handle as data start\n"); -# endif - } else -# endif - /* else */ if (COVERT_DATAFLOW(__data_start) != 0) { + /* However, this may lead to wrong data start value if libgc */ + /* code is put into a shared library (directly or indirectly) */ + /* which is linked with -Bsymbolic-functions option. Thus, */ + /* the following is not used by default. */ + if (COVERT_DATAFLOW(__data_start) != 0) { GC_data_start = (ptr_t)(__data_start); } else { GC_data_start = (ptr_t)(data_start); @@ -470,7 +460,7 @@ GC_INNER char * GC_get_maps(void) return; } - GC_data_start = GC_find_limit(data_end, FALSE); + GC_data_start = (ptr_t)GC_find_limit(data_end, FALSE); } #endif /* SEARCH_FOR_DATA_START */ @@ -511,7 +501,7 @@ GC_INNER char * GC_get_maps(void) { /* This may need to be environ, without the underscore, for */ /* some versions. */ - GC_data_start = GC_find_limit((ptr_t)&environ, FALSE); + GC_data_start = (ptr_t)GC_find_limit(&environ, FALSE); } #endif /* NETBSD */ @@ -983,6 +973,7 @@ GC_INNER size_t GC_page_size = 0; /* the smallest location q s.t. [q,p) is addressable (!up). */ /* We assume that p (up) or p-1 (!up) is addressable. */ /* Requires allocation lock. */ + GC_ATTR_NO_SANITIZE_ADDR STATIC ptr_t GC_find_limit_with_bound(ptr_t p, GC_bool up, ptr_t bound) { static volatile ptr_t result; @@ -1027,12 +1018,36 @@ GC_INNER size_t GC_page_size = 0; return(result); } - ptr_t GC_find_limit(ptr_t p, GC_bool up) + void * GC_find_limit(void * p, int up) { - return GC_find_limit_with_bound(p, up, up ? (ptr_t)(word)(-1) : 0); + return GC_find_limit_with_bound((ptr_t)p, (GC_bool)up, + up ? (ptr_t)GC_WORD_MAX : 0); } # endif /* NEED_FIND_LIMIT || USE_PROC_FOR_LIBRARIES */ +#ifdef HPUX_MAIN_STACKBOTTOM +# include +# include + + STATIC ptr_t GC_hpux_main_stack_base(void) + { + struct pst_vm_status vm_status; + int i = 0; + + while (pstat_getprocvm(&vm_status, sizeof(vm_status), 0, i++) == 1) { + if (vm_status.pst_type == PS_STACK) + return (ptr_t)vm_status.pst_vaddr; + } + + /* Old way to get the stack bottom. */ +# ifdef STACK_GROWS_UP + return (ptr_t)GC_find_limit(GC_approx_sp(), /* up= */ FALSE); +# else /* not HP_PA */ + return (ptr_t)GC_find_limit(GC_approx_sp(), TRUE); +# endif + } +#endif /* HPUX_MAIN_STACKBOTTOM */ + #ifdef HPUX_STACKBOTTOM #include @@ -1092,7 +1107,7 @@ GC_INNER size_t GC_page_size = 0; # endif result = backing_store_base_from_proc(); if (0 == result) { - result = GC_find_limit(GC_save_regs_in_stack(), FALSE); + result = (ptr_t)GC_find_limit(GC_save_regs_in_stack(), FALSE); /* Now seems to work better than constant displacement */ /* heuristic used in 6.X versions. The latter seems to */ /* fail for 2.6 kernels. */ @@ -1272,15 +1287,17 @@ GC_INNER size_t GC_page_size = 0; # else result = (ptr_t)((word)GC_approx_sp() & ~STACKBOTTOM_ALIGNMENT_M1); # endif +# elif defined(HPUX_MAIN_STACKBOTTOM) + result = GC_hpux_main_stack_base(); # elif defined(LINUX_STACKBOTTOM) - result = GC_linux_main_stack_base(); + result = GC_linux_main_stack_base(); # elif defined(FREEBSD_STACKBOTTOM) - result = GC_freebsd_main_stack_base(); + result = GC_freebsd_main_stack_base(); # elif defined(HEURISTIC2) { ptr_t sp = GC_approx_sp(); # ifdef STACK_GROWS_DOWN - result = GC_find_limit(sp, TRUE); + result = (ptr_t)GC_find_limit(sp, TRUE); # if defined(HEURISTIC2_LIMIT) && !defined(CPPCHECK) if ((word)result > (word)HEURISTIC2_LIMIT && (word)sp < (word)HEURISTIC2_LIMIT) { @@ -1288,7 +1305,7 @@ GC_INNER size_t GC_page_size = 0; } # endif # else - result = GC_find_limit(sp, FALSE); + result = (ptr_t)GC_find_limit(sp, FALSE); # if defined(HEURISTIC2_LIMIT) && !defined(CPPCHECK) if ((word)result < (word)HEURISTIC2_LIMIT && (word)sp > (word)HEURISTIC2_LIMIT) { @@ -1628,10 +1645,10 @@ void GC_register_data_segments(void) typedef UINT (WINAPI * GetWriteWatch_type)( DWORD, PVOID, GC_ULONG_PTR /* SIZE_T */, PVOID *, GC_ULONG_PTR *, PULONG); - static GetWriteWatch_type GetWriteWatch_func; + static FARPROC GetWriteWatch_func; static DWORD GetWriteWatch_alloc_flag; -# define GC_GWW_AVAILABLE() (GetWriteWatch_func != NULL) +# define GC_GWW_AVAILABLE() (GetWriteWatch_func != 0) static void detect_GetWriteWatch(void) { @@ -1673,8 +1690,7 @@ void GC_register_data_segments(void) hK32 = GetModuleHandle(TEXT("kernel32.dll")); # endif if (hK32 != (HMODULE)0 && - (GetWriteWatch_func = (GetWriteWatch_type)GetProcAddress(hK32, - "GetWriteWatch")) != NULL) { + (GetWriteWatch_func = GetProcAddress(hK32, "GetWriteWatch")) != 0) { /* Also check whether VirtualAlloc accepts MEM_WRITE_WATCH, */ /* as some versions of kernel32.dll have one but not the */ /* other, making the feature completely broken. */ @@ -1686,26 +1702,25 @@ void GC_register_data_segments(void) GC_ULONG_PTR count = 16; DWORD page_size; /* Check that it actually works. In spite of some */ - /* documentation it actually seems to exist on W2K. */ + /* documentation it actually seems to exist on Win2K. */ /* This test may be unnecessary, but ... */ - if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET, - page, GC_page_size, - pages, - &count, - &page_size) != 0) { + if ((*(GetWriteWatch_type)(word)GetWriteWatch_func)( + WRITE_WATCH_FLAG_RESET, page, + GC_page_size, pages, &count, + &page_size) != 0) { /* GetWriteWatch always fails. */ - GetWriteWatch_func = NULL; + GetWriteWatch_func = 0; } else { GetWriteWatch_alloc_flag = MEM_WRITE_WATCH; } VirtualFree(page, 0 /* dwSize */, MEM_RELEASE); } else { /* GetWriteWatch will be useless. */ - GetWriteWatch_func = NULL; + GetWriteWatch_func = 0; } } # ifndef SMALL_CONFIG - if (GetWriteWatch_func == NULL) { + if (!GetWriteWatch_func) { GC_COND_LOG_PRINTF("Did not find a usable GetWriteWatch()\n"); } else { GC_COND_LOG_PRINTF("Using GetWriteWatch()\n"); @@ -1734,7 +1749,7 @@ void GC_register_data_segments(void) /* assembly code to do that right. */ GC_INNER GC_bool GC_wnt = FALSE; - /* This is a Windows NT derivative, i.e. NT, W2K, XP or later. */ + /* This is a Windows NT derivative, i.e. NT, Win2K, XP or later. */ GC_INNER void GC_init_win32(void) { @@ -1937,7 +1952,7 @@ void GC_register_data_segments(void) word next_page = ((text_end + (word)max_page_size - 1) & ~((word)max_page_size - 1)); word page_offset = (text_end & ((word)max_page_size - 1)); - char * volatile result = (char *)(next_page + page_offset); + volatile ptr_t result = (char *)(next_page + page_offset); /* Note that this isn't equivalent to just adding */ /* max_page_size to &etext if &etext is at a page boundary */ @@ -1965,7 +1980,7 @@ void GC_register_data_segments(void) /* text and data segments, so plan A brought us something. */ result = (char *)GC_find_limit(DATAEND, FALSE); } - return((ptr_t)result); + return (/* no volatile */ ptr_t)result; } # endif @@ -1994,7 +2009,7 @@ void GC_register_data_segments(void) } else { GC_reset_fault_handler(); /* As above, we go to plan B */ - result = GC_find_limit(DATAEND, FALSE); + result = (ptr_t)GC_find_limit(DATAEND, FALSE); } return(result); } @@ -2163,7 +2178,7 @@ void GC_register_data_segments(void) # ifdef SYMBIAN char *path = GC_get_private_path_and_zero_file(); if (path != NULL) { - zero_fd = open(path, O_RDWR | O_CREAT, 0666); + zero_fd = open(path, O_RDWR | O_CREAT, 0644); free(path); } # else @@ -2184,7 +2199,11 @@ void GC_register_data_segments(void) GC_MMAP_FLAGS | OPT_MAP_ANON, zero_fd, 0/* offset */); # undef IGNORE_PAGES_EXECUTABLE - if (result == MAP_FAILED) return(0); + if (EXPECT(MAP_FAILED == result, FALSE)) { + if (HEAP_START == last_addr && GC_pages_executable && EACCES == errno) + ABORT("Cannot allocate executable pages"); + return NULL; + } last_addr = (ptr_t)(((word)result + bytes + GC_page_size - 1) & ~(GC_page_size - 1)); # if !defined(LINUX) @@ -2263,6 +2282,11 @@ ptr_t GC_unix_get_mem(size_t bytes) static GC_bool sbrk_failed = FALSE; ptr_t result = 0; + if (GC_pages_executable) { + /* If the allocated memory should have the execute permission */ + /* then sbrk() cannot be used. */ + return GC_unix_mmap_get_mem(bytes); + } if (!sbrk_failed) result = GC_unix_sbrk_get_mem(bytes); if (0 == result) { sbrk_failed = TRUE; @@ -2301,16 +2325,14 @@ void * os2_alloc(size_t bytes) # endif /* OS2 */ -# ifdef MSWIN_XBOX1 - void *durango_get_mem(size_t bytes, size_t page_size) +#ifdef MSWIN_XBOX1 + ptr_t GC_durango_get_mem(size_t bytes) { if (0 == bytes) return NULL; - return VirtualAlloc(NULL, bytes, MEM_COMMIT | MEM_TOP_DOWN, - PAGE_READWRITE); + return (ptr_t)VirtualAlloc(NULL, bytes, MEM_COMMIT | MEM_TOP_DOWN, + PAGE_READWRITE); } -# endif - -#ifdef MSWINCE +#elif defined(MSWINCE) ptr_t GC_wince_get_mem(size_t bytes) { ptr_t result = 0; /* initialized to prevent warning. */ @@ -2522,13 +2544,6 @@ STATIC ptr_t GC_unmap_start(ptr_t start, size_t bytes) return result; } -/* Compute end address for an unmap operation on the indicated */ -/* block. */ -STATIC ptr_t GC_unmap_end(ptr_t start, size_t bytes) -{ - return (ptr_t)((word)(start + bytes) & ~(GC_page_size - 1)); -} - /* Under Win32/WinCE we commit (map) and decommit (unmap) */ /* memory using VirtualAlloc and VirtualFree. These functions */ /* work on individual allocations of virtual memory, made */ @@ -2568,9 +2583,12 @@ GC_INNER void GC_unmap(ptr_t start, size_t bytes) /* We immediately remap it to prevent an intervening mmap from */ /* accidentally grabbing the same address space. */ { -# ifdef CYGWIN32 - /* Calling mmap() with the new protection flags on an */ - /* existing memory map with MAP_FIXED is broken on Cygwin. */ +# if defined(AIX) || defined(CYGWIN32) || defined(HAIKU) \ + || defined(HPUX) + /* On AIX, mmap(PROT_NONE) fails with ENOMEM unless the */ + /* environment variable XPG_SUS_ENV is set to ON. */ + /* On Cygwin, calling mmap() with the new protection flags on */ + /* an existing memory map with MAP_FIXED is broken. */ /* However, calling mprotect() on the given address range */ /* with PROT_NONE seems to work fine. */ if (mprotect(start_addr, len, PROT_NONE)) @@ -2632,8 +2650,10 @@ GC_INNER void GC_remap(ptr_t start, size_t bytes) # else /* It was already remapped with PROT_NONE. */ { -# ifdef NACL +# if defined(NACL) || defined(NETBSD) /* NaCl does not expose mprotect, but mmap should work fine. */ + /* In case of NetBSD, mprotect fails (unlike mmap) even */ + /* without PROT_EXEC if PaX MPROTECT feature is enabled. */ void *result = mmap(start_addr, len, (PROT_READ | PROT_WRITE) | (GC_pages_executable ? PROT_EXEC : 0), MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON, @@ -2694,7 +2714,8 @@ GC_INNER void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2, # else if (len != 0) { /* Immediately remap as above. */ -# ifdef CYGWIN32 +# if defined(AIX) || defined(CYGWIN32) || defined(HAIKU) \ + || defined(HPUX) if (mprotect(start_addr, len, PROT_NONE)) ABORT("mprotect(PROT_NONE) failed"); # else @@ -2880,8 +2901,8 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void) count = GC_GWW_BUF_LEN; /* GetWriteWatch is documented as returning non-zero when it */ /* fails, but the documentation doesn't explicitly say why it */ - /* would fail or what its behaviour will be if it fails. */ - /* It does appear to fail, at least on recent W2K instances, if */ + /* would fail or what its behavior will be if it fails. It */ + /* does appear to fail, at least on recent Win2K instances, if */ /* the underlying memory was not allocated with the appropriate */ /* flag. This is common if GC_enable_incremental is called */ /* shortly after GC initialization. To avoid modifying the */ @@ -2892,12 +2913,11 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void) /* loop condition. Since each partial call will reset the */ /* status of some pages, this should eventually terminate even */ /* in the overflow case. */ - if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET, - GC_heap_sects[i].hs_start, - GC_heap_sects[i].hs_bytes, - pages, - &count, - &page_size) != 0) { + if ((*(GetWriteWatch_type)(word)GetWriteWatch_func)( + WRITE_WATCH_FLAG_RESET, + GC_heap_sects[i].hs_start, + GC_heap_sects[i].hs_bytes, + pages, &count, &page_size) != 0) { static int warn_count = 0; struct hblk * start = (struct hblk *)GC_heap_sects[i].hs_start; static struct hblk *last_warned = 0; @@ -2959,10 +2979,7 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void) #endif /* DEFAULT_VDB */ #ifndef GC_DISABLE_INCREMENTAL -# ifndef THREADS -# define async_set_pht_entry_from_index(db, index) \ - set_pht_entry_from_index(db, index) -# elif defined(set_pht_entry_from_index_concurrent) +# if !defined(THREADS) || defined(HAVE_LOCKFREE_AO_OR) # define async_set_pht_entry_from_index(db, index) \ set_pht_entry_from_index_concurrent(db, index) # elif defined(AO_HAVE_test_and_set_acquire) @@ -3082,11 +3099,13 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void) #ifndef DARWIN STATIC SIG_HNDLR_PTR GC_old_segv_handler = 0; /* Also old MSWIN32 ACCESS_VIOLATION filter */ -# if !defined(MSWIN32) && !defined(MSWINCE) +# if defined(FREEBSD) || defined(HPUX) || defined(HURD) || defined(LINUX) STATIC SIG_HNDLR_PTR GC_old_bus_handler = 0; -# if defined(FREEBSD) || defined(HURD) || defined(HPUX) +# ifndef LINUX STATIC GC_bool GC_old_bus_handler_used_si = FALSE; # endif +# endif +# if !defined(MSWIN32) && !defined(MSWINCE) STATIC GC_bool GC_old_segv_handler_used_si = FALSE; # endif /* !MSWIN32 */ #endif /* !DARWIN */ @@ -3125,7 +3144,8 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void) # ifndef SEGV_ACCERR # define SEGV_ACCERR 2 # endif -# if defined(AARCH64) || defined(ARM32) || defined(MIPS) +# if defined(AARCH64) || defined(ARM32) || defined(MIPS) \ + || __FreeBSD__ >= 7 # define CODE_OK (si -> si_code == SEGV_ACCERR) # elif defined(POWERPC) # define AIM /* Pretend that we're AIM. */ @@ -3368,9 +3388,6 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void) # endif } else { GC_old_bus_handler = (SIG_HNDLR_PTR)(signed_word)oldact.sa_handler; -# if !defined(LINUX) - GC_old_bus_handler_used_si = FALSE; -# endif } if (GC_old_bus_handler == (SIG_HNDLR_PTR)(signed_word)SIG_IGN) { WARN("Previously ignored bus error!?\n", 0); @@ -3528,32 +3545,57 @@ STATIC void GC_protect_heap(void) # include # endif +# ifndef THREADS + static pid_t saved_proc_pid; /* pid used to compose /proc file name */ +# endif + # define INITIAL_BUF_SZ 16384 STATIC size_t GC_proc_buf_size = INITIAL_BUF_SZ; STATIC char *GC_proc_buf = NULL; - STATIC int GC_proc_fd = 0; + STATIC int GC_proc_fd = -1; -GC_INNER GC_bool GC_dirty_init(void) -{ + static GC_bool proc_dirty_open_files(void) + { char buf[40]; + pid_t pid = getpid(); - if (GC_bytes_allocd != 0 || GC_bytes_allocd_before_gc != 0) { - memset(GC_written_pages, 0xff, sizeof(page_hash_table)); - GC_VERBOSE_LOG_PRINTF( - "Allocated %lu bytes: all pages may have been written\n", - (unsigned long)(GC_bytes_allocd + GC_bytes_allocd_before_gc)); - } - - (void)snprintf(buf, sizeof(buf), "/proc/%ld/pagedata", (long)getpid()); + (void)snprintf(buf, sizeof(buf), "/proc/%ld/pagedata", (long)pid); buf[sizeof(buf) - 1] = '\0'; GC_proc_fd = open(buf, O_RDONLY); - if (GC_proc_fd < 0) { + if (-1 == GC_proc_fd) { WARN("/proc open failed; cannot enable GC incremental mode\n", 0); return FALSE; } if (syscall(SYS_fcntl, GC_proc_fd, F_SETFD, FD_CLOEXEC) == -1) WARN("Could not set FD_CLOEXEC for /proc\n", 0); +# ifndef THREADS + saved_proc_pid = pid; /* updated on success only */ +# endif + return TRUE; + } + +# ifdef CAN_HANDLE_FORK + GC_INNER void GC_dirty_update_child(void) + { + if (-1 == GC_proc_fd) + return; /* GC incremental mode is off */ + + close(GC_proc_fd); + if (!proc_dirty_open_files()) + GC_incremental = FALSE; /* should be safe to turn it off */ + } +# endif /* CAN_HANDLE_FORK */ +GC_INNER GC_bool GC_dirty_init(void) +{ + if (GC_bytes_allocd != 0 || GC_bytes_allocd_before_gc != 0) { + memset(GC_written_pages, 0xff, sizeof(page_hash_table)); + GC_VERBOSE_LOG_PRINTF( + "Allocated %lu bytes: all pages may have been written\n", + (unsigned long)(GC_bytes_allocd + GC_bytes_allocd_before_gc)); + } + if (!proc_dirty_open_files()) + return FALSE; GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size); if (GC_proc_buf == NULL) ABORT("Insufficient space for /proc read"); @@ -3567,6 +3609,23 @@ GC_INLINE void GC_proc_read_dirty(GC_bool output_unneeded) char * bufp = GC_proc_buf; int i; +# ifndef THREADS + /* If the current pid differs from the saved one, then we are in */ + /* the forked (child) process, the current /proc file should be */ + /* closed, the new one should be opened with the updated path. */ + /* Note, this is not needed for multi-threaded case because */ + /* fork_child_proc() reopens the file right after fork. */ + if (getpid() != saved_proc_pid + && (-1 == GC_proc_fd /* no need to retry */ + || (close(GC_proc_fd), !proc_dirty_open_files()))) { + /* Failed to reopen the file. Punt! */ + if (!output_unneeded) + memset(GC_grungy_pages, 0xff, sizeof(page_hash_table)); + memset(GC_written_pages, 0xff, sizeof(page_hash_table)); + return; + } +# endif + BZERO(GC_grungy_pages, sizeof(GC_grungy_pages)); if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) { /* Retry with larger buffer. */ @@ -3743,6 +3802,8 @@ GC_INNER GC_bool GC_dirty_init(void) /* side of labeling pages as dirty (and this implementation does). */ GC_INNER GC_bool GC_page_was_dirty(struct hblk *h) { + word index; + # ifdef PCR_VDB if (!GC_manual_vdb) { if ((word)h < (word)GC_vd_base @@ -3754,9 +3815,16 @@ GC_INNER GC_bool GC_dirty_init(void) # elif defined(DEFAULT_VDB) if (!GC_manual_vdb) return TRUE; +# elif defined(PROC_VDB) + /* Unless manual VDB is on, the bitmap covers all process memory. */ + if (GC_manual_vdb) # endif - return NULL == HDR(h) - || get_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h)); + { + if (NULL == HDR(h)) + return TRUE; + } + index = PHT_HASH(h); + return get_pht_entry_from_index(GC_grungy_pages, index); } # if defined(CHECKSUMS) || defined(PROC_VDB) @@ -3764,12 +3832,21 @@ GC_INNER GC_bool GC_dirty_init(void) GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk *h) { # if defined(GWW_VDB) || defined(PROC_VDB) + word index; + # ifdef MPROTECT_VDB if (!GC_GWW_AVAILABLE()) return TRUE; # endif - return NULL == HDR(h) - || get_pht_entry_from_index(GC_written_pages, PHT_HASH(h)); +# if defined(PROC_VDB) + if (GC_manual_vdb) +# endif + { + if (NULL == HDR(h)) + return TRUE; + } + index = PHT_HASH(h); + return get_pht_entry_from_index(GC_written_pages, index); # else /* TODO: implement me for MANUAL_VDB. */ (void)h; @@ -4025,24 +4102,28 @@ typedef enum { # define GC_mprotect_state GC_MP_NORMAL #endif /* !THREADS */ +struct mp_reply_s { + mach_msg_header_t head; + char data[256]; +}; + +struct mp_msg_s { + mach_msg_header_t head; + mach_msg_body_t msgh_body; + char data[1024]; +}; + STATIC void *GC_mprotect_thread(void *arg) { mach_msg_return_t r; /* These two structures contain some private kernel data. We don't */ /* need to access any of it so we don't bother defining a proper */ /* struct. The correct definitions are in the xnu source code. */ - struct reply_s { - mach_msg_header_t head; - char data[256]; - } reply; - struct msg_s { - mach_msg_header_t head; - mach_msg_body_t msgh_body; - char data[1024]; - } msg; + struct mp_reply_s reply; + struct mp_msg_s msg; mach_msg_id_t id; - if ((word)arg == (word)-1) return 0; /* to make compiler happy */ + if ((word)arg == GC_WORD_MAX) return 0; /* to prevent a compiler warning */ # if defined(CPPCHECK) reply.data[0] = 0; /* to prevent "field unused" warnings */ msg.data[0] = 0; @@ -4503,6 +4584,7 @@ GC_API int GC_CALL GC_get_pages_executable(void) # if defined(LINUX) # include +# if defined(SAVE_CALL_CHAIN) struct frame { long fr_local[8]; long fr_arg[6]; @@ -4514,6 +4596,7 @@ GC_API int GC_CALL GC_get_pages_executable(void) long fr_argd[6]; long fr_argx[0]; }; +# endif # elif defined (DRSNX) # include # elif defined(OPENBSD) @@ -4625,7 +4708,11 @@ GC_INNER void GC_save_callers(struct callinfo info[NFRAMES]) #endif for (; !((word)fp HOTTER_THAN (word)frame) - && !((word)GC_stackbottom HOTTER_THAN (word)fp) +# ifndef THREADS + && !((word)GC_stackbottom HOTTER_THAN (word)fp) +# elif defined(STACK_GROWS_UP) + && fp != NULL +# endif && nframes < NFRAMES; fp = (struct frame *)((long) fp -> FR_SAVFP + BIAS), nframes++) { # if NARGS > 0 diff --git a/gc/pthread_stop_world.c b/gc/pthread_stop_world.c index a94d46633..4b2c42975 100644 --- a/gc/pthread_stop_world.c +++ b/gc/pthread_stop_world.c @@ -114,9 +114,12 @@ STATIC void GC_remove_allowed_signals(sigset_t *set) static sigset_t suspend_handler_mask; +#define THREAD_RESTARTED 0x1 + STATIC volatile AO_t GC_stop_count = 0; - /* Incremented by two at the beginning of */ - /* GC_stop_world (the lowest bit is always 0). */ + /* Incremented by two (not to alter */ + /* THREAD_RESTARTED bit) at the beginning of */ + /* GC_stop_world. */ STATIC volatile AO_t GC_world_is_stopped = FALSE; /* FALSE ==> it is safe for threads to restart, */ @@ -241,6 +244,22 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy, void *context); errno = old_errno; } +#ifdef BASE_ATOMIC_OPS_EMULATED + /* The AO primitives emulated with locks cannot be used inside signal */ + /* handlers as this could cause a deadlock or a double lock. */ + /* The following "async" macro definitions are correct only for */ + /* an uniprocessor case and are provided for a test purpose. */ +# define ao_load_acquire_async(p) (*(p)) +# define ao_load_async(p) ao_load_acquire_async(p) +# define ao_store_release_async(p, v) (void)(*(p) = (v)) +# define ao_store_async(p, v) ao_store_release_async(p, v) +#else +# define ao_load_acquire_async(p) AO_load_acquire(p) +# define ao_load_async(p) AO_load(p) +# define ao_store_release_async(p, v) AO_store_release(p, v) +# define ao_store_async(p, v) AO_store(p, v) +#endif /* !BASE_ATOMIC_OPS_EMULATED */ + /* The lookup here is safe, since this is done on behalf */ /* of a thread which holds the allocation lock in order */ /* to stop the world. Thus concurrent modification of the */ @@ -272,13 +291,14 @@ GC_INLINE void GC_store_stack_ptr(GC_thread me) /* and fetched (by GC_push_all_stacks) using the atomic primitives to */ /* avoid the related TSan warning. */ # ifdef SPARC - AO_store((volatile AO_t *)&me->stop_info.stack_ptr, + ao_store_async((volatile AO_t *)&me->stop_info.stack_ptr, (AO_t)GC_save_regs_in_stack()); # else # ifdef IA64 me -> backing_store_ptr = GC_save_regs_in_stack(); # endif - AO_store((volatile AO_t *)&me->stop_info.stack_ptr, (AO_t)GC_approx_sp()); + ao_store_async((volatile AO_t *)&me->stop_info.stack_ptr, + (AO_t)GC_approx_sp()); # endif } @@ -288,7 +308,7 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED, pthread_t self = pthread_self(); GC_thread me; IF_CANCEL(int cancel_state;) - AO_t my_stop_count = AO_load_acquire(&GC_stop_count); + AO_t my_stop_count = ao_load_acquire_async(&GC_stop_count); /* After the barrier, this thread should see */ /* the actual content of GC_threads. */ @@ -304,12 +324,12 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED, # ifdef DEBUG_THREADS GC_log_printf("Suspending %p\n", (void *)self); # endif - GC_ASSERT(((word)my_stop_count & 1) == 0); + GC_ASSERT(((word)my_stop_count & THREAD_RESTARTED) == 0); me = GC_lookup_thread_async(self); # ifdef GC_ENABLE_SUSPEND_THREAD - if (AO_load(&me->suspended_ext)) { + if (ao_load_async(&me->suspended_ext)) { GC_store_stack_ptr(me); sem_post(&GC_suspend_ack_sem); suspend_self_inner(me); @@ -321,7 +341,7 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED, } # endif - if (((word)me->stop_info.last_stop_count & ~(word)0x1) + if (((word)me->stop_info.last_stop_count & ~(word)THREAD_RESTARTED) == (word)my_stop_count) { /* Duplicate signal. OK if we are retrying. */ if (!GC_retry_signals) { @@ -350,7 +370,7 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED, /* thread has been stopped. Note that sem_post() is */ /* the only async-signal-safe primitive in LinuxThreads. */ sem_post(&GC_suspend_ack_sem); - AO_store_release(&me->stop_info.last_stop_count, my_stop_count); + ao_store_release_async(&me->stop_info.last_stop_count, my_stop_count); /* Wait until that thread tells us to restart by sending */ /* this thread a GC_sig_thr_restart signal (should be masked */ @@ -364,8 +384,8 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED, /* this code should not be executed. */ do { sigsuspend (&suspend_handler_mask); - } while (AO_load_acquire(&GC_world_is_stopped) - && AO_load(&GC_stop_count) == my_stop_count); + } while (ao_load_acquire_async(&GC_world_is_stopped) + && ao_load_async(&GC_stop_count) == my_stop_count); # ifdef DEBUG_THREADS GC_log_printf("Continuing %p\n", (void *)self); @@ -383,10 +403,9 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED, if (GC_retry_signals) # endif { - /* Set the flag (the lowest bit of last_stop_count) that the */ - /* thread has been restarted. */ - AO_store_release(&me->stop_info.last_stop_count, - (AO_t)((word)my_stop_count | 1)); + /* Set the flag that the thread has been restarted. */ + ao_store_release_async(&me->stop_info.last_stop_count, + (AO_t)((word)my_stop_count | THREAD_RESTARTED)); } } RESTORE_CANCEL(cancel_state); @@ -525,7 +544,7 @@ STATIC void GC_restart_handler(int sig) static void *GC_CALLBACK suspend_self_inner(void *client_data) { GC_thread me = (GC_thread)client_data; - while (AO_load_acquire(&me->suspended_ext)) { + while (ao_load_acquire_async(&me->suspended_ext)) { /* TODO: Use sigsuspend() instead. */ GC_brief_async_signal_safe_sleep(); } @@ -629,6 +648,10 @@ STATIC void GC_restart_handler(int sig) } # endif /* GC_ENABLE_SUSPEND_THREAD */ +# undef ao_load_acquire_async +# undef ao_load_async +# undef ao_store_async +# undef ao_store_release_async #endif /* !GC_OPENBSD_UTHREADS && !NACL */ #ifdef IA64 @@ -896,7 +919,8 @@ GC_INNER void GC_stop_world(void) # if defined(GC_OPENBSD_UTHREADS) || defined(NACL) (void)GC_suspend_all(); # else - AO_store(&GC_stop_count, (AO_t)((word)GC_stop_count + 2)); + AO_store(&GC_stop_count, + (AO_t)((word)GC_stop_count + (THREAD_RESTARTED+1))); /* Only concurrent reads are possible. */ if (GC_manual_vdb) { GC_acquire_dirty_lock(); @@ -1099,8 +1123,9 @@ GC_INNER void GC_stop_world(void) # ifdef GC_ENABLE_SUSPEND_THREAD if (p -> suspended_ext) continue; # endif - if (GC_retry_signals && AO_load(&p->stop_info.last_stop_count) - == (AO_t)((word)GC_stop_count | 1)) + if (GC_retry_signals + && AO_load(&p->stop_info.last_stop_count) + == (AO_t)((word)GC_stop_count | THREAD_RESTARTED)) continue; /* The thread has been restarted. */ n_live_threads++; # endif diff --git a/gc/pthread_support.c b/gc/pthread_support.c index 8a78efed0..4891b3ac9 100644 --- a/gc/pthread_support.c +++ b/gc/pthread_support.c @@ -340,7 +340,7 @@ STATIC void * GC_mark_thread(void * id) word my_mark_no = 0; IF_CANCEL(int cancel_state;) - if ((word)id == (word)-1) return 0; /* to make compiler happy */ + if ((word)id == GC_WORD_MAX) return 0; /* to prevent a compiler warning */ DISABLE_CANCEL(cancel_state); /* Mark threads are not cancellable; they */ /* should be invisible to client. */ @@ -762,10 +762,11 @@ STATIC void GC_remove_all_threads_but_me(void) { pthread_t self = pthread_self(); int hv; - GC_thread p, next, me; for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) { - me = 0; + GC_thread p, next; + GC_thread me = NULL; + for (p = GC_threads[hv]; 0 != p; p = next) { next = p -> next; if (THREAD_EQUAL(p -> id, self) @@ -1122,7 +1123,10 @@ static void fork_child_proc(void) /* Turn off parallel marking in the child, since we are probably */ /* just going to exec, and we would have to restart mark threads. */ GC_parallel = FALSE; -# endif /* PARALLEL_MARK */ +# endif +# ifndef GC_DISABLE_INCREMENTAL + GC_dirty_update_child(); +# endif RESTORE_CANCEL(fork_cancel_state); UNLOCK(); /* Even though after a fork the child only inherits the single */ @@ -1241,11 +1245,7 @@ GC_INNER void GC_thr_init(void) } } -# ifndef GC_DARWIN_THREADS - GC_stop_init(); -# endif - - /* Set GC_nprocs. */ + /* Set GC_nprocs and available_markers_m1. */ { char * nprocs_string = GETENV("GC_NPROCS"); GC_nprocs = -1; @@ -1294,6 +1294,43 @@ GC_INNER void GC_thr_init(void) # endif } GC_COND_LOG_PRINTF("Number of processors = %d\n", GC_nprocs); + +# if defined(BASE_ATOMIC_OPS_EMULATED) && !defined(GC_DARWIN_THREADS) \ + && !defined(GC_OPENBSD_UTHREADS) && !defined(NACL) \ + && !defined(SN_TARGET_ORBIS) && !defined(SN_TARGET_PSP2) + /* Ensure the process is running on just one CPU core. */ + /* This is needed because the AO primitives emulated with */ + /* locks cannot be used inside signal handlers. */ + { + cpu_set_t mask; + int cpu_set_cnt = 0; + int cpu_lowest_set = 0; + int i = GC_nprocs > 1 ? GC_nprocs : 2; /* check at least 2 cores */ + + if (sched_getaffinity(0 /* current process */, + sizeof(mask), &mask) == -1) + ABORT_ARG1("sched_getaffinity failed", ": errno= %d", errno); + while (i-- > 0) + if (CPU_ISSET(i, &mask)) { + cpu_lowest_set = i; + cpu_set_cnt++; + } + if (0 == cpu_set_cnt) + ABORT("sched_getaffinity returned empty mask"); + if (cpu_set_cnt > 1) { + CPU_ZERO(&mask); + CPU_SET(cpu_lowest_set, &mask); /* select just one CPU */ + if (sched_setaffinity(0, sizeof(mask), &mask) == -1) + ABORT_ARG1("sched_setaffinity failed", ": errno= %d", errno); + WARN("CPU affinity mask is set to %p\n", (word)1 << cpu_lowest_set); + } + } +# endif /* BASE_ATOMIC_OPS_EMULATED */ + +# ifndef GC_DARWIN_THREADS + GC_stop_init(); +# endif + # ifdef PARALLEL_MARK if (available_markers_m1 <= 0) { /* Disable parallel marking. */ @@ -1423,7 +1460,7 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn, } else { /* The original stack. */ if ((word)GC_stackbottom HOTTER_THAN (word)(&stacksect)) - GC_stackbottom = (ptr_t)(&stacksect); + GC_stackbottom = (ptr_t)COVERT_DATAFLOW(&stacksect); } if (!me->thread_blocked) { @@ -1431,7 +1468,7 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn, UNLOCK(); client_data = fn(client_data); /* Prevent treating the above as a tail call. */ - GC_noop1((word)(&stacksect)); + GC_noop1(COVERT_DATAFLOW(&stacksect)); return client_data; /* result */ } @@ -1826,7 +1863,7 @@ GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread( int result; int detachstate; word my_flags = 0; - struct start_info * si; + struct start_info si; DCL_LOCK_STATE; /* This is otherwise saved only in an area mmapped by the thread */ /* library, which isn't visible to the collector. */ @@ -1836,21 +1873,13 @@ GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread( /* responsibility. */ INIT_REAL_SYMS(); - LOCK(); - si = (struct start_info *)GC_INTERNAL_MALLOC(sizeof(struct start_info), - NORMAL); - UNLOCK(); if (!EXPECT(parallel_initialized, TRUE)) GC_init_parallel(); - if (EXPECT(0 == si, FALSE) && - (si = (struct start_info *) - (*GC_get_oom_fn())(sizeof(struct start_info))) == 0) - return(ENOMEM); - if (sem_init(&(si -> registered), GC_SEM_INIT_PSHARED, 0) != 0) + if (sem_init(&si.registered, GC_SEM_INIT_PSHARED, 0) != 0) ABORT("sem_init failed"); - si -> start_routine = start_routine; - si -> arg = arg; + si.start_routine = start_routine; + si.arg = arg; LOCK(); if (!EXPECT(GC_thr_initialized, TRUE)) GC_thr_init(); @@ -1890,19 +1919,19 @@ GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread( pthread_attr_getdetachstate(attr, &detachstate); } if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED; - si -> flags = my_flags; + si.flags = my_flags; UNLOCK(); # ifdef DEBUG_THREADS GC_log_printf("About to start new thread from thread %p\n", (void *)pthread_self()); # endif set_need_to_lock(); - result = REAL_FUNC(pthread_create)(new_thread, attr, GC_start_routine, si); + result = REAL_FUNC(pthread_create)(new_thread, attr, GC_start_routine, + &si); /* Wait until child has been added to the thread table. */ - /* This also ensures that we hold onto si until the child is done */ - /* with it. Thus it doesn't matter whether it is otherwise */ - /* visible to the collector. */ + /* This also ensures that we hold onto the stack-allocated si until */ + /* the child is done with it. */ if (0 == result) { IF_CANCEL(int cancel_state;) @@ -1912,7 +1941,7 @@ GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread( # endif DISABLE_CANCEL(cancel_state); /* pthread_create is not a cancellation point. */ - while (0 != sem_wait(&(si -> registered))) { + while (0 != sem_wait(&si.registered)) { # if defined(GC_HAIKU_THREADS) /* To workaround some bug in Haiku semaphores. */ if (EACCES == errno) continue; @@ -1921,11 +1950,7 @@ GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread( } RESTORE_CANCEL(cancel_state); } - sem_destroy(&(si -> registered)); - LOCK(); - GC_INTERNAL_FREE(si); - UNLOCK(); - + sem_destroy(&si.registered); return(result); } #endif /* !SN_TARGET_ORBIS && !SN_TARGET_PSP2 */ @@ -1940,7 +1965,8 @@ STATIC void GC_pause(void) for (i = 0; i < GC_PAUSE_SPIN_CYCLES; ++i) { /* Something that's unlikely to be optimized away. */ -# ifdef AO_CLEAR +# if defined(AO_HAVE_compiler_barrier) \ + && !defined(BASE_ATOMIC_OPS_EMULATED) AO_compiler_barrier(); # else GC_noop1(i); @@ -2022,7 +2048,7 @@ STATIC void GC_generic_lock(pthread_mutex_t * lock) #endif /* !USE_SPIN_LOCK || ... */ -#ifdef AO_HAVE_char_load +#if defined(AO_HAVE_char_load) && !defined(BASE_ATOMIC_OPS_EMULATED) # define is_collecting() \ ((GC_bool)AO_char_load((unsigned char *)&GC_collecting)) #else @@ -2109,22 +2135,25 @@ GC_INNER void GC_lock(void) } } -#else /* !USE_SPIN_LOCK */ +#elif defined(USE_PTHREAD_LOCKS) -GC_INNER void GC_lock(void) -{ -#ifndef NO_PTHREAD_TRYLOCK - if (1 == GC_nprocs || is_collecting()) { +# ifndef NO_PTHREAD_TRYLOCK + GC_INNER void GC_lock(void) + { + if (1 == GC_nprocs || is_collecting()) { pthread_mutex_lock(&GC_allocate_ml); - } else { + } else { GC_generic_lock(&GC_allocate_ml); + } } -#else /* !NO_PTHREAD_TRYLOCK */ - pthread_mutex_lock(&GC_allocate_ml); -#endif /* !NO_PTHREAD_TRYLOCK */ -} +# elif defined(GC_ASSERTIONS) + GC_INNER void GC_lock(void) + { + pthread_mutex_lock(&GC_allocate_ml); + } +# endif -#endif /* !USE_SPIN_LOCK */ +#endif /* !USE_SPIN_LOCK && USE_PTHREAD_LOCKS */ #ifdef PARALLEL_MARK diff --git a/gc/reclaim.c b/gc/reclaim.c index f729f5d57..45ce4a11b 100644 --- a/gc/reclaim.c +++ b/gc/reclaim.c @@ -103,7 +103,9 @@ GC_INNER void GC_print_all_errors(void) } for (i = 0; i < n_leaked; i++) { ptr_t p = leaked[i]; - GC_print_heap_obj(p); +# ifndef SKIP_LEAKED_OBJECTS_PRINTING + GC_print_heap_obj(p); +# endif GC_free(p); } @@ -133,9 +135,9 @@ GC_INNER GC_bool GC_block_empty(hdr *hhdr) return (hhdr -> hb_n_marks == 0); } -STATIC GC_bool GC_block_nearly_full(hdr *hhdr) +STATIC GC_bool GC_block_nearly_full(hdr *hhdr, word sz) { - return (hhdr -> hb_n_marks > 7 * HBLK_OBJS(hhdr -> hb_sz)/8); + return hhdr -> hb_n_marks > HBLK_OBJS(sz) * 7 / 8; } /* TODO: This should perhaps again be specialized for USE_MARK_BYTES */ @@ -154,7 +156,11 @@ STATIC ptr_t GC_reclaim_clear(struct hblk *hbp, hdr *hhdr, word sz, signed_word n_bytes_found = 0; GC_ASSERT(hhdr == GC_find_header((ptr_t)hbp)); - GC_ASSERT(sz == hhdr -> hb_sz); +# ifndef THREADS + GC_ASSERT(sz == hhdr -> hb_sz); +# else + /* Skip the assertion because of a potential race with GC_realloc. */ +# endif GC_ASSERT((sz & (BYTES_PER_WORD-1)) == 0); p = (word *)(hbp->hb_body); plim = (word *)(hbp->hb_body + HBLKSIZE - sz); @@ -200,7 +206,9 @@ STATIC ptr_t GC_reclaim_uninit(struct hblk *hbp, hdr *hhdr, word sz, word *p, *plim; signed_word n_bytes_found = 0; - GC_ASSERT(sz == hhdr -> hb_sz); +# ifndef THREADS + GC_ASSERT(sz == hhdr -> hb_sz); +# endif p = (word *)(hbp->hb_body); plim = (word *)((ptr_t)hbp + HBLKSIZE - sz); @@ -231,13 +239,16 @@ STATIC ptr_t GC_reclaim_uninit(struct hblk *hbp, hdr *hhdr, word sz, struct obj_kind *ok = &GC_obj_kinds[hhdr->hb_obj_kind]; int (GC_CALLBACK *disclaim)(void *) = ok->ok_disclaim_proc; - GC_ASSERT(sz == hhdr -> hb_sz); +# ifndef THREADS + GC_ASSERT(sz == hhdr -> hb_sz); +# endif p = (word *)(hbp -> hb_body); plim = (word *)((ptr_t)p + HBLKSIZE - sz); while ((word)p <= (word)plim) { int marked = mark_bit_from_hdr(hhdr, bit_no); if (!marked && (*disclaim)(p)) { + set_mark_bit_from_hdr(hhdr, bit_no); hhdr -> hb_n_marks++; marked = 1; } @@ -278,8 +289,10 @@ STATIC void GC_reclaim_check(struct hblk *hbp, hdr *hhdr, word sz) { word bit_no; ptr_t p, plim; - GC_ASSERT(sz == hhdr -> hb_sz); +# ifndef THREADS + GC_ASSERT(sz == hhdr -> hb_sz); +# endif /* go through all words in block */ p = hbp->hb_body; plim = p + HBLKSIZE - sz; @@ -337,11 +350,10 @@ GC_INNER ptr_t GC_reclaim_generic(struct hblk * hbp, hdr *hhdr, size_t sz, * If entirely empty blocks are to be completely deallocated, then * caller should perform that check. */ -STATIC void GC_reclaim_small_nonempty_block(struct hblk *hbp, +STATIC void GC_reclaim_small_nonempty_block(struct hblk *hbp, word sz, GC_bool report_if_found) { hdr *hhdr = HDR(hbp); - word sz = hhdr -> hb_sz; struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind]; void **flh = &(ok -> ok_freelist[BYTES_TO_GRANULES(sz)]); @@ -387,9 +399,16 @@ STATIC void GC_reclaim_small_nonempty_block(struct hblk *hbp, STATIC void GC_reclaim_block(struct hblk *hbp, word report_if_found) { hdr * hhdr = HDR(hbp); - word sz = hhdr -> hb_sz; /* size of objects in current block */ + word sz; /* size of objects in current block */ struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind]; +# ifdef AO_HAVE_load + /* Atomic access is used to avoid racing with GC_realloc. */ + sz = (word)AO_load((volatile AO_t *)&hhdr->hb_sz); +# else + /* No race as GC_realloc holds the lock while updating hb_sz. */ + sz = hhdr -> hb_sz; +# endif if( sz > MAXOBJBYTES ) { /* 1 big object */ if( !mark_bit_from_hdr(hhdr, 0) ) { if (report_if_found) { @@ -437,7 +456,8 @@ STATIC void GC_reclaim_block(struct hblk *hbp, word report_if_found) GC_ASSERT(sz * hhdr -> hb_n_marks <= HBLKSIZE); # endif if (report_if_found) { - GC_reclaim_small_nonempty_block(hbp, TRUE /* report_if_found */); + GC_reclaim_small_nonempty_block(hbp, sz, + TRUE /* report_if_found */); } else if (empty) { # ifdef ENABLE_DISCLAIM if ((hhdr -> hb_flags & HAS_DISCLAIM) != 0) { @@ -448,7 +468,7 @@ STATIC void GC_reclaim_block(struct hblk *hbp, word report_if_found) GC_bytes_found += HBLKSIZE; GC_freehblk(hbp); } - } else if (GC_find_leak || !GC_block_nearly_full(hhdr)) { + } else if (GC_find_leak || !GC_block_nearly_full(hhdr, sz)) { /* group of smaller objects, enqueue the real work */ struct hblk **rlh = ok -> ok_reclaim_list; @@ -695,8 +715,9 @@ GC_INNER void GC_continue_reclaim(word sz /* granules */, int kind) while ((hbp = *rlh) != 0) { hhdr = HDR(hbp); *rlh = hhdr -> hb_next; - GC_reclaim_small_nonempty_block(hbp, FALSE); - if (*flh != 0) break; + GC_reclaim_small_nonempty_block(hbp, hhdr -> hb_sz, FALSE); + if (*flh != 0) + break; } } @@ -719,7 +740,7 @@ GC_INNER GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old) struct hblk ** rlp; struct hblk ** rlh; # ifndef NO_CLOCK - CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */ + CLOCK_TYPE start_time = CLOCK_TYPE_INITIALIZER; if (GC_print_stats == VERBOSE) GET_TIME(start_time); @@ -742,7 +763,7 @@ GC_INNER GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old) /* It's likely we'll need it this time, too */ /* It's been touched recently, so this */ /* shouldn't trigger paging. */ - GC_reclaim_small_nonempty_block(hbp, FALSE); + GC_reclaim_small_nonempty_block(hbp, hhdr->hb_sz, FALSE); } } } @@ -786,7 +807,7 @@ GC_INNER GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old) while ((hbp = *rlh) != 0) { hhdr = HDR(hbp); *rlh = hhdr->hb_next; - GC_reclaim_small_nonempty_block(hbp, FALSE); + GC_reclaim_small_nonempty_block(hbp, hhdr->hb_sz, FALSE); } } } diff --git a/gc/specific.c b/gc/specific.c index 624236fdf..451cf9086 100644 --- a/gc/specific.c +++ b/gc/specific.c @@ -72,7 +72,8 @@ GC_INNER int GC_setspecific(tsd * key, void * value) AO_store_release(&key->hash[hash_val].ao, (AO_t)entry); GC_dirty((/* no volatile */ void *)entry); GC_dirty(key->hash + hash_val); - pthread_mutex_unlock(&(key -> lock)); + if (pthread_mutex_unlock(&key->lock) != 0) + ABORT("pthread_mutex_unlock failed (setspecific)"); return 0; } @@ -128,7 +129,8 @@ GC_INNER void GC_remove_specific_after_fork(tsd * key, pthread_t t) /* With GC, we're done, since the pointers from the cache will */ /* be overwritten, all local pointers to the entries will be */ /* dropped, and the entry will then be reclaimed. */ - pthread_mutex_unlock(&(key -> lock)); + if (pthread_mutex_unlock(&key->lock) != 0) + ABORT("pthread_mutex_unlock failed (remove_specific after fork)"); } /* Note that even the slow path doesn't lock. */ diff --git a/gc/tests/disclaim_bench.c b/gc/tests/disclaim_bench.c index 8be81cf69..28feb1a5c 100644 --- a/gc/tests/disclaim_bench.c +++ b/gc/tests/disclaim_bench.c @@ -121,6 +121,8 @@ int main(int argc, char **argv) model_min = 0; model_max = 2; } + if (GC_get_find_leak()) + printf("This test program is not designed for leak detection mode\n"); keep_arr = (testobj_t *)GC_MALLOC(sizeof(void *) * KEEP_CNT); if (NULL == keep_arr) { diff --git a/gc/tests/disclaim_test.c b/gc/tests/disclaim_test.c index 4febf7f73..6af62f64e 100644 --- a/gc/tests/disclaim_test.c +++ b/gc/tests/disclaim_test.c @@ -84,7 +84,7 @@ void test_misc_sizes(void) } my_assert(memeq(p, 0, (size_t)1 << i)); memset(p, 0x56, (size_t)1 << i); - *(unsigned char *)p = i; + *(unsigned char *)p = (unsigned char)i; } } @@ -241,6 +241,8 @@ int main(void) # ifndef NO_INCREMENTAL GC_enable_incremental(); # endif + if (GC_get_find_leak()) + printf("This test program is not designed for leak detection mode\n"); test_misc_sizes(); diff --git a/gc/tests/disclaim_weakmap_test.c b/gc/tests/disclaim_weakmap_test.c new file mode 100644 index 000000000..516a3fd77 --- /dev/null +++ b/gc/tests/disclaim_weakmap_test.c @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2018 Petter A. Urkedal + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * 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. + */ + +/* This tests a case where disclaim notifiers sometimes return non-zero */ +/* in order to protect objects from collection. */ + +#include +#include +#include + +#ifdef HAVE_CONFIG_H + /* For GC_[P]THREADS */ +# include "config.h" +#endif + +#include "gc_disclaim.h" /* includes gc.h */ +#include "gc_mark.h" + +#ifdef GC_PTHREADS +# ifndef NTHREADS +# define NTHREADS 8 +# endif +# include +# include +# include "private/gc_atomic_ops.h" /* for AO_t and AO_fetch_and_add1 */ +#else +# undef NTHREADS +# define NTHREADS 1 +# define AO_t GC_word +#endif + +#ifdef LINT2 + /* Avoid include gc_priv.h. */ +# ifndef GC_API_PRIV +# define GC_API_PRIV GC_API +# endif +# ifdef __cplusplus + extern "C" { +# endif + GC_API_PRIV long GC_random(void); +# ifdef __cplusplus + } /* extern "C" */ +# endif +# undef rand +# define rand() (int)GC_random() +#endif /* LINT2 */ + +#define POP_SIZE 200 +#define MUTATE_CNT (5000000 / NTHREADS) +#define GROW_LIMIT (MUTATE_CNT / 10) + +#define WEAKMAP_CAPACITY 256 +#define WEAKMAP_MUTEX_COUNT 32 + +/* FINALIZER_CLOSURE_FLAG definition matches the one in fnlz_mlc.c. */ +#if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH) +# define FINALIZER_CLOSURE_FLAG 0x2 +# define INVALIDATE_FLAG 0x1 +#else +# define FINALIZER_CLOSURE_FLAG 0x1 +# define INVALIDATE_FLAG 0x2 +#endif + +#define my_assert(e) \ + if (!(e)) { \ + fflush(stdout); \ + fprintf(stderr, "Assertion failure, line %d: %s\n", __LINE__, #e); \ + exit(70); \ + } + +#define CHECK_OOM(p) \ + do { \ + if (NULL == (p)) { \ + fprintf(stderr, "Out of memory\n"); \ + exit(69); \ + } \ + } while (0) + +#ifndef AO_HAVE_fetch_and_add1 +# define AO_fetch_and_add1(p) ((*(p))++) + /* This is used only to update counters. */ +#endif + +unsigned memhash(void *src, size_t len) +{ + unsigned acc = 0; + size_t i; + + my_assert(len % sizeof(GC_word) == 0); + for (i = 0; i < len / sizeof(GC_word); ++i) { + acc = (unsigned)((2003 * (GC_word)acc + ((GC_word *)src)[i]) / 3); + } + return acc; +} + +static volatile AO_t stat_added; +static volatile AO_t stat_found; +static volatile AO_t stat_removed; +static volatile AO_t stat_skip_locked; +static volatile AO_t stat_skip_marked; + +struct weakmap_link { + GC_hidden_pointer obj; + struct weakmap_link *next; +}; + +struct weakmap { +# ifdef GC_PTHREADS + pthread_mutex_t mutex[WEAKMAP_MUTEX_COUNT]; +# endif + size_t key_size; + size_t obj_size; + size_t capacity; + unsigned weakobj_kind; + struct weakmap_link **links; /* NULL means weakmap is destroyed */ +}; + +void weakmap_lock(struct weakmap *wm, unsigned h) +{ +# ifdef GC_PTHREADS + int err = pthread_mutex_lock(&wm->mutex[h % WEAKMAP_MUTEX_COUNT]); + my_assert(0 == err); +# else + (void)wm; (void)h; +# endif +} + +int weakmap_trylock(struct weakmap *wm, unsigned h) +{ +# ifdef GC_PTHREADS + int err = pthread_mutex_trylock(&wm->mutex[h % WEAKMAP_MUTEX_COUNT]); + if (err != 0 && err != EBUSY) { + fprintf(stderr, "pthread_mutex_trylock: %s\n", strerror(err)); + exit(69); + } + return err; +# else + (void)wm; (void)h; + return 0; +# endif +} + +void weakmap_unlock(struct weakmap *wm, unsigned h) +{ +# ifdef GC_PTHREADS + int err = pthread_mutex_unlock(&wm->mutex[h % WEAKMAP_MUTEX_COUNT]); + my_assert(0 == err); +# else + (void)wm; (void)h; +# endif +} + +void *GC_CALLBACK set_mark_bit(void *obj) +{ + GC_set_mark_bit(obj); + return NULL; +} + +void *weakmap_add(struct weakmap *wm, void *obj) +{ + struct weakmap_link *link, *new_link, **first; + GC_word *new_base; + void *new_obj; + unsigned h; + size_t key_size = wm->key_size; + + /* Lock and look for an existing entry. */ + h = memhash(obj, key_size); + first = &wm->links[h % wm->capacity]; + weakmap_lock(wm, h); + + for (link = *first; link != NULL; link = link->next) { + void *old_obj = GC_get_find_leak() ? (void *)link->obj + : GC_REVEAL_POINTER(link->obj); + + if (memcmp(old_obj, obj, key_size) == 0) { + GC_call_with_alloc_lock(set_mark_bit, (GC_word *)old_obj - 1); + /* Pointers in the key part may have been freed and reused, */ + /* changing the keys without memcmp noticing. This is okay */ + /* as long as we update the mapped value. */ + if (memcmp((char *)old_obj + key_size, (char *)obj + key_size, + wm->obj_size - key_size) != 0) { + memcpy((char *)old_obj + key_size, (char *)obj + key_size, + wm->obj_size - key_size); + GC_end_stubborn_change((char *)old_obj + key_size); + } + weakmap_unlock(wm, h); + AO_fetch_and_add1(&stat_found); +# ifdef DEBUG_DISCLAIM_WEAKMAP + printf("Found %p, hash=%p\n", old_obj, (void *)(GC_word)h); +# endif + return old_obj; + } + } + + /* Create new object. */ + new_base = (GC_word *)GC_generic_malloc(sizeof(GC_word) + wm->obj_size, + wm->weakobj_kind); + CHECK_OOM(new_base); + *new_base = (GC_word)wm | FINALIZER_CLOSURE_FLAG; + new_obj = (void *)(new_base + 1); + memcpy(new_obj, obj, wm->obj_size); + GC_end_stubborn_change(new_base); + + /* Add the object to the map. */ + new_link = GC_NEW(struct weakmap_link); + CHECK_OOM(new_link); + new_link->obj = GC_get_find_leak() ? (GC_word)new_obj + : GC_HIDE_POINTER(new_obj); + new_link->next = *first; + GC_END_STUBBORN_CHANGE(new_link); + GC_PTR_STORE_AND_DIRTY(first, new_link); + weakmap_unlock(wm, h); + AO_fetch_and_add1(&stat_added); +# ifdef DEBUG_DISCLAIM_WEAKMAP + printf("Added %p, hash=%p\n", new_obj, (void *)(GC_word)h); +# endif + return new_obj; +} + +int GC_CALLBACK weakmap_disclaim(void *obj_base) +{ + struct weakmap *wm; + struct weakmap_link **link; + GC_word hdr; + void *obj; + unsigned h; + + /* Decode header word. */ + hdr = *(GC_word *)obj_base; + if ((hdr & FINALIZER_CLOSURE_FLAG) == 0) + return 0; /* on GC free list, ignore it. */ + + my_assert((hdr & INVALIDATE_FLAG) == 0); + wm = (struct weakmap *)(hdr & ~(GC_word)FINALIZER_CLOSURE_FLAG); + if (NULL == wm->links) + return 0; /* weakmap has been already destroyed */ + obj = (GC_word *)obj_base + 1; + + /* Lock and check for mark. */ + h = memhash(obj, wm->key_size); + if (weakmap_trylock(wm, h) != 0) { + AO_fetch_and_add1(&stat_skip_locked); +# ifdef DEBUG_DISCLAIM_WEAKMAP + printf("Skipping locked %p, hash=%p\n", obj, (void *)(GC_word)h); +# endif + return 1; + } + if (GC_is_marked(obj_base)) { + weakmap_unlock(wm, h); + AO_fetch_and_add1(&stat_skip_marked); +# ifdef DEBUG_DISCLAIM_WEAKMAP + printf("Skipping marked %p, hash=%p\n", obj, (void *)(GC_word)h); +# endif + return 1; + } + + /* Remove obj from wm. */ + AO_fetch_and_add1(&stat_removed); +# ifdef DEBUG_DISCLAIM_WEAKMAP + printf("Removing %p, hash=%p\n", obj, (void *)(GC_word)h); +# endif + *(GC_word *)obj_base |= INVALIDATE_FLAG; + for (link = &wm->links[h % wm->capacity];; link = &(*link)->next) { + void *old_obj; + + if (NULL == *link) { + fprintf(stderr, "Did not find %p\n", obj); + exit(70); + } + old_obj = GC_get_find_leak() ? (void *)(*link)->obj + : GC_REVEAL_POINTER((*link)->obj); + if (old_obj == obj) + break; + my_assert(memcmp(old_obj, obj, wm->key_size) != 0); + } + GC_PTR_STORE_AND_DIRTY(link, (*link)->next); + weakmap_unlock(wm, h); + return 0; +} + +struct weakmap *weakmap_new(size_t capacity, size_t key_size, size_t obj_size, + unsigned weakobj_kind) +{ + struct weakmap *wm = GC_NEW(struct weakmap); + + CHECK_OOM(wm); +# ifdef GC_PTHREADS + { + int i; + for (i = 0; i < WEAKMAP_MUTEX_COUNT; ++i) { + int err = pthread_mutex_init(&wm->mutex[i], NULL); + my_assert(err == 0); + } + } +# endif + wm->key_size = key_size; + wm->obj_size = obj_size; + wm->capacity = capacity; + wm->weakobj_kind = weakobj_kind; + GC_PTR_STORE_AND_DIRTY(&wm->links, + GC_MALLOC(sizeof(struct weakmap_link *) * capacity)); + CHECK_OOM(wm->links); + return wm; +} + +void weakmap_destroy(struct weakmap *wm) +{ +# ifdef GC_PTHREADS + int i; + + for (i = 0; i < WEAKMAP_MUTEX_COUNT; ++i) { + (void)pthread_mutex_destroy(&wm->mutex[i]); + } +# endif + wm->links = NULL; /* weakmap is destroyed */ +} + +struct weakmap *pair_hcset; + +#define PAIR_MAGIC_SIZE 16 /* should not exceed sizeof(pair_magic) */ + +struct pair_key { + struct pair *car, *cdr; +}; + +struct pair { + struct pair *car; + struct pair *cdr; + char magic[PAIR_MAGIC_SIZE]; + int checksum; +}; + +static const char * const pair_magic = "PAIR_MAGIC_BYTES"; + +struct pair *pair_new(struct pair *car, struct pair *cdr) +{ + struct pair tmpl; + + memset(&tmpl, 0, sizeof(tmpl)); /* To clear the paddings (to avoid */ + /* a compiler warning). */ + tmpl.car = car; + tmpl.cdr = cdr; + memcpy(tmpl.magic, pair_magic, PAIR_MAGIC_SIZE); + tmpl.checksum = 782 + (car? car->checksum : 0) + (cdr? cdr->checksum : 0); + return (struct pair *)weakmap_add(pair_hcset, &tmpl); +} + +void pair_check_rec(struct pair *p, int line) +{ + while (p != NULL) { + int checksum = 782; + + if (memcmp(p->magic, pair_magic, PAIR_MAGIC_SIZE) != 0) { + fprintf(stderr, "Magic bytes wrong for %p at %d\n", (void *)p, line); + exit(70); + } + if (p->car != NULL) + checksum += p->car->checksum; + if (p->cdr != NULL) + checksum += p->cdr->checksum; + if (p->checksum != checksum) { + fprintf(stderr, "Checksum failure for %p = (%p, %p) at %d\n", + (void *)p, (void *)p->car, (void *)p->cdr, line); + exit(70); + } + p = (rand() & 1) != 0 ? p->cdr : p->car; + } +} + +void *test(void *data) +{ + int i; + struct pair *p0, *p1; + struct pair *pop[POP_SIZE]; + + memset(pop, 0, sizeof(pop)); + for (i = 0; i < MUTATE_CNT; ++i) { + int bits = rand(); + int t = (bits >> 3) % POP_SIZE; + + switch (bits % (i > GROW_LIMIT ? 5 : 3)) { + case 0: + case 3: + if (pop[t] != NULL) + pop[t] = pop[t]->car; + break; + case 1: + case 4: + if (pop[t] != NULL) + pop[t] = pop[t]->cdr; + break; + case 2: + p0 = pop[rand() % POP_SIZE]; + p1 = pop[rand() % POP_SIZE]; + pop[t] = pair_new(p0, p1); + my_assert(pair_new(p0, p1) == pop[t]); + my_assert(pop[t]->car == p0); + my_assert(pop[t]->cdr == p1); + break; + } + pair_check_rec(pop[rand() % POP_SIZE], __LINE__); + } + return data; +} + +int main(void) +{ + unsigned weakobj_kind; + void **weakobj_free_list; +# ifdef GC_PTHREADS + int i; + pthread_t th[NTHREADS]; +# endif + + GC_set_all_interior_pointers(0); /* for a stricter test */ +# ifdef TEST_MANUAL_VDB + GC_set_manual_vdb_allowed(1); +# endif + GC_INIT(); + GC_init_finalized_malloc(); /* to register the displacements */ +# ifndef NO_INCREMENTAL + GC_enable_incremental(); +# endif + if (GC_get_find_leak()) + printf("This test program is not designed for leak detection mode\n"); + + weakobj_free_list = GC_new_free_list(); + CHECK_OOM(weakobj_free_list); + weakobj_kind = GC_new_kind(weakobj_free_list, /* 0 | */ GC_DS_LENGTH, + 1 /* adjust */, 1 /* clear */); + GC_register_disclaim_proc(weakobj_kind, weakmap_disclaim, + 1 /* mark_unconditionally */); + pair_hcset = weakmap_new(WEAKMAP_CAPACITY, sizeof(struct pair_key), + sizeof(struct pair), weakobj_kind); + +# ifdef GC_PTHREADS + for (i = 0; i < NTHREADS; ++i) { + int err = pthread_create(&th[i], NULL, test, NULL); + if (err != 0) { + fprintf(stderr, "Failed to create thread #%d: %s\n", + i, strerror(err)); + exit(1); + } + } + for (i = 0; i < NTHREADS; ++i) { + int err = pthread_join(th[i], NULL); + if (err != 0) { + fprintf(stderr, "Failed to join thread #%d: %s\n", i, strerror(err)); + exit(69); + } + } +# else + (void)test(NULL); +# endif + weakmap_destroy(pair_hcset); + printf("%u added, %u found; %u removed, %u locked, %u marked; %u remains\n", + (unsigned)stat_added, (unsigned)stat_found, (unsigned)stat_removed, + (unsigned)stat_skip_locked, (unsigned)stat_skip_marked, + (unsigned)stat_added - (unsigned)stat_removed); + return 0; +} diff --git a/gc/tests/initsecondarythread.c b/gc/tests/initsecondarythread.c index 788a86252..0ad855d8d 100644 --- a/gc/tests/initsecondarythread.c +++ b/gc/tests/initsecondarythread.c @@ -85,6 +85,8 @@ int main(void) GC_INIT(); # endif (void)GC_get_parallel(); /* linking fails if no threads support */ + if (GC_get_find_leak()) + printf("This test program is not designed for leak detection mode\n"); # ifdef GC_PTHREADS if ((code = pthread_create (&t, NULL, thread, NULL)) != 0) { fprintf(stderr, "Thread creation failed %d\n", code); diff --git a/gc/tests/middle.c b/gc/tests/middle.c index 55686f759..9a7cc3d08 100644 --- a/gc/tests/middle.c +++ b/gc/tests/middle.c @@ -11,6 +11,8 @@ int main (void) GC_set_all_interior_pointers(0); GC_INIT(); + if (GC_get_find_leak()) + printf("This test program is not designed for leak detection mode\n"); for (i = 0; i < 20000; ++i) { (void)GC_malloc_atomic(4096); diff --git a/gc/tests/realloc_test.c b/gc/tests/realloc_test.c index c7c80d738..8870971b4 100644 --- a/gc/tests/realloc_test.c +++ b/gc/tests/realloc_test.c @@ -10,6 +10,8 @@ int main(void) { unsigned long last_heap_size = 0; GC_INIT(); + if (GC_get_find_leak()) + printf("This test program is not designed for leak detection mode\n"); for (i = 0; i < COUNT; i++) { int **p = GC_NEW(int *); diff --git a/gc/tests/smash_test.c b/gc/tests/smash_test.c index 4ba7be047..9aab02de6 100644 --- a/gc/tests/smash_test.c +++ b/gc/tests/smash_test.c @@ -13,6 +13,8 @@ char * A[COUNT]; +char * volatile q; + int main(void) { int i; @@ -23,8 +25,17 @@ int main(void) for (i = 0; i < COUNT; ++i) { A[i] = p = (char*)GC_MALLOC(SIZE); - if (i%3000 == 0) GC_gcollect(); - if (i%5678 == 0 && p != 0) p[SIZE + i/2000] = 42; + if (i%3000 == 0) { + q = NULL; + GC_gcollect(); + } else if (i%5678 == 0 && p != 0) { + /* Write a byte past the end of the allocated object */ + /* but not beyond the last word of the object's memory. */ + /* A volatile intermediate pointer variable is used to */ + /* avoid a compiler complain of out-of-bounds access. */ + q = &p[(SIZE + i/2000) /* 42 */]; + *q = 42; + } } return 0; } diff --git a/gc/tests/staticrootstest.c b/gc/tests/staticrootstest.c index b43765d08..66aca2997 100644 --- a/gc/tests/staticrootstest.c +++ b/gc/tests/staticrootstest.c @@ -49,6 +49,8 @@ int main(void) GC_INIT(); # endif init_staticroot(); + if (GC_get_find_leak()) + printf("This test program is not designed for leak detection mode\n"); if (NULL == staticroot) { fprintf(stderr, "GC_malloc returned NULL\n"); return 2; diff --git a/gc/tests/subthread_create.c b/gc/tests/subthread_create.c index a40df51cb..2b3b46049 100644 --- a/gc/tests/subthread_create.c +++ b/gc/tests/subthread_create.c @@ -58,7 +58,7 @@ volatile AO_t thread_ended_cnt = 0; DWORD WINAPI entry(LPVOID arg) #endif { - int thread_num = AO_fetch_and_add1(&thread_created_cnt); + int thread_num = (int)AO_fetch_and_add1(&thread_created_cnt); GC_word my_depth = (GC_word)arg + 1; if (my_depth <= MAX_SUBTHREAD_DEPTH diff --git a/gc/tests/test.c b/gc/tests/test.c index 8ec8c13f2..8e2e3a6d0 100644 --- a/gc/tests/test.c +++ b/gc/tests/test.c @@ -156,6 +156,12 @@ # define INIT_MANUAL_VDB_ALLOWED /* empty */ #endif +#ifdef TEST_PAGES_EXECUTABLE +# define INIT_PAGES_EXECUTABLE GC_set_pages_executable(1) +#else +# define INIT_PAGES_EXECUTABLE (void)0 +#endif + #define CHECK_GCLIB_VERSION \ if (GC_get_version() != ((GC_VERSION_MAJOR<<16) \ | (GC_VERSION_MINOR<<8) \ @@ -185,7 +191,7 @@ #endif #define GC_COND_INIT() \ - INIT_FORK_SUPPORT; INIT_MANUAL_VDB_ALLOWED; \ + INIT_FORK_SUPPORT; INIT_MANUAL_VDB_ALLOWED; INIT_PAGES_EXECUTABLE; \ GC_OPT_INIT; CHECK_GCLIB_VERSION; \ INIT_PRINT_STATS; INIT_FIND_LEAK; INIT_PERF_MEASUREMENT @@ -196,7 +202,7 @@ } /* Define AO primitives for a single-threaded mode. */ -#ifndef AO_CLEAR +#ifndef AO_HAVE_compiler_barrier /* AO_t not defined. */ # define AO_t GC_word #endif @@ -1463,6 +1469,8 @@ void run_one_test(void) GC_FREE(GC_MALLOC_ATOMIC(0)); test_generic_malloc_or_special(GC_malloc_atomic(1)); AO_fetch_and_add1(&atomic_count); + GC_FREE(GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(1)); + GC_FREE(GC_MALLOC_IGNORE_OFF_PAGE(2)); } } # ifdef GC_GCJ_SUPPORT @@ -1553,6 +1561,10 @@ void run_one_test(void) # endif # endif /* DBG_HDRS_ALL */ tree_test(); +# ifdef TEST_WITH_SYSTEM_MALLOC + free(calloc(1,1)); + free(realloc(NULL, 64)); +# endif # ifndef NO_CLOCK if (print_stats) { CLOCK_TYPE tree_time; @@ -1583,6 +1595,13 @@ void run_one_test(void) # endif } +/* Execute some tests after termination of other test threads (if any). */ +void run_single_threaded_test(void) { + GC_disable(); + GC_FREE(GC_MALLOC(100)); + GC_enable(); +} + void GC_CALLBACK reachable_objs_counter(void *obj, size_t size, void *pcounter) { @@ -1897,6 +1916,7 @@ void GC_CALLBACK warn_proc(char *msg, GC_word p) # endif set_print_procs(); run_one_test(); + run_single_threaded_test(); check_heap_stats(); # ifndef MSWINCE fflush(stdout); @@ -1963,7 +1983,6 @@ void GC_CALLBACK warn_proc(char *msg, GC_word p) UNTESTED(GC_set_on_collection_event); UNTESTED(GC_set_on_heap_resize); UNTESTED(GC_set_oom_fn); - UNTESTED(GC_set_pages_executable); UNTESTED(GC_set_push_other_roots); UNTESTED(GC_set_start_callback); UNTESTED(GC_set_stop_func); @@ -1990,6 +2009,7 @@ void GC_CALLBACK warn_proc(char *msg, GC_word p) UNTESTED(GC_gcj_malloc_ignore_off_page); # endif # ifndef NO_DEBUGGING + UNTESTED(GC_dump); UNTESTED(GC_dump_regions); UNTESTED(GC_is_tmp_root); UNTESTED(GC_print_free_list); @@ -2204,6 +2224,7 @@ DWORD __stdcall thr_window(void * arg GC_ATTR_UNUSED) if (WaitForSingleObject(win_thr_h, INFINITE) != WAIT_OBJECT_0) FAIL; # endif + run_single_threaded_test(); check_heap_stats(); # if defined(CPPCHECK) && defined(GC_WIN32_THREADS) UNTESTED(GC_ExitThread); @@ -2245,6 +2266,7 @@ int test(void) != PCR_ERes_okay || code != 0) { GC_printf("Thread 2 failed\n"); } + run_single_threaded_test(); check_heap_stats(); return(0); } @@ -2357,6 +2379,7 @@ int main(void) } } # endif + run_single_threaded_test(); check_heap_stats(); (void)fflush(stdout); (void)pthread_attr_destroy(&attr); diff --git a/gc/tests/test_cpp.cc b/gc/tests/test_cpp.cc index 6f7efad5d..a9165a965 100644 --- a/gc/tests/test_cpp.cc +++ b/gc/tests/test_cpp.cc @@ -14,7 +14,7 @@ the code was modified is included with the above copyright notice. usage: test_cpp number-of-iterations This program tries to test the specific C++ functionality provided by -gc_c++.h that isn't tested by the more general test routines of the +gc_cpp.h that isn't tested by the more general test routines of the collector. A recommended value for number-of-iterations is 10, which will take a @@ -76,7 +76,8 @@ extern "C" { exit( 1 ); } #ifndef GC_ATTR_EXPLICIT -# if (__cplusplus >= 201103L) || defined(CPPCHECK) +# if __cplusplus >= 201103L && !defined(__clang__) || _MSVC_LANG >= 201103L \ + || defined(CPPCHECK) # define GC_ATTR_EXPLICIT explicit # else # define GC_ATTR_EXPLICIT /* empty */ @@ -89,6 +90,7 @@ class A {public: GC_ATTR_EXPLICIT A( int iArg ): i( iArg ) {} void Test( int iArg ) { my_assert( i == iArg );} + virtual ~A() {} int i;}; @@ -157,7 +159,14 @@ class C: public GC_NS_QUALIFY(gc_cleanup), public A { public: left = right = 0; level = -123456;} static void Test() { - my_assert( nFreed <= nAllocated && nFreed >= .8 * nAllocated );} + if (GC_is_incremental_mode() && nFreed < (nAllocated / 5) * 4) { + // An explicit GC might be needed to reach the expected number + // of the finalized objects. + GC_gcollect(); + } + my_assert(nFreed <= nAllocated); + my_assert(nFreed >= (nAllocated / 5) * 4 || GC_get_find_leak()); + } static int nFreed; static int nAllocated; @@ -180,7 +189,8 @@ class D: public GC_NS_QUALIFY(gc) { public: nFreed++; my_assert( (GC_word)self->i == (GC_word)data );} static void Test() { - my_assert( nFreed >= .8 * nAllocated );} + my_assert(nFreed >= (nAllocated / 5) * 4 || GC_get_find_leak()); + } int i; static int nFreed; @@ -218,7 +228,7 @@ class F: public E {public: } static void Test() { - my_assert(nFreedF >= .8 * nAllocatedF); + my_assert(nFreedF >= (nAllocatedF / 5) * 4 || GC_get_find_leak()); my_assert(2 * nFreedF == nFreed); } @@ -266,7 +276,6 @@ void* Undisguise( GC_word i ) { argv[argc] = NULL; break; } - argv[argc] = cmd; for (; *cmd != '\0'; cmd++) { if (*cmd != ' ' && *cmd != '\t') break; @@ -305,6 +314,8 @@ void* Undisguise( GC_word i ) { # ifndef NO_INCREMENTAL GC_enable_incremental(); # endif + if (GC_get_find_leak()) + GC_printf("This test program is not designed for leak detection mode\n"); int i, iters, n; # ifndef DONT_USE_STD_ALLOCATOR diff --git a/gc/tests/tests.am b/gc/tests/tests.am index b851f35a0..93f4b27d2 100644 --- a/gc/tests/tests.am +++ b/gc/tests/tests.am @@ -9,7 +9,8 @@ # modified is included with the above copyright notice. # Common libs to _LDADD for all tests. -test_ldadd = $(top_builddir)/libgc.la $(EXTRA_TEST_LIBS) +test_ldadd = $(nodist_libgc_la_OBJECTS) $(top_builddir)/libgc.la \ + $(EXTRA_TEST_LIBS) TESTS += gctest$(EXEEXT) check_PROGRAMS += gctest @@ -49,8 +50,8 @@ TESTS += staticrootstest$(EXEEXT) check_PROGRAMS += staticrootstest staticrootstest_SOURCES = tests/staticrootstest.c staticrootstest_CFLAGS = -DSTATICROOTSLIB2 -staticrootstest_LDADD = $(test_ldadd) libstaticrootslib_test.la \ - libstaticrootslib2_test.la +staticrootstest_LDADD = $(nodist_libgc_la_OBJECTS) $(EXTRA_TEST_LIBS) \ + libstaticrootslib_test.la libstaticrootslib2_test.la check_LTLIBRARIES += libstaticrootslib_test.la libstaticrootslib2_test.la libstaticrootslib_test_la_SOURCES = tests/staticrootslib.c libstaticrootslib_test_la_LIBADD = $(test_ldadd) @@ -60,6 +61,9 @@ libstaticrootslib2_test_la_SOURCES = tests/staticrootslib.c libstaticrootslib2_test_la_LIBADD = $(test_ldadd) libstaticrootslib2_test_la_CFLAGS = -DSTATICROOTSLIB2 libstaticrootslib2_test_la_LDFLAGS = -no-undefined -rpath /nowhere +if ENABLE_SHARED +staticrootstest_LDADD += $(top_builddir)/libgc.la +endif if KEEP_BACK_PTRS TESTS += tracetest$(EXEEXT) @@ -105,7 +109,13 @@ test_cpp_SOURCES = tests/test_cpp.cc if AVOID_CPP_LIB test_cpp_LDADD = gc_cpp.o $(test_ldadd) $(CXXLIBS) else -test_cpp_LDADD = libgccpp.la $(test_ldadd) $(CXXLIBS) +test_cpp_LDADD = libgccpp.la $(nodist_libgc_la_OBJECTS) \ + $(EXTRA_TEST_LIBS) $(CXXLIBS) +## In case of static libraries build, libgc.a is already referenced in +## dependency_libs attribute of libgccpp.la file. +if ENABLE_SHARED +test_cpp_LDADD += $(top_builddir)/libgc.la +endif endif endif @@ -124,6 +134,14 @@ check_PROGRAMS += disclaim_bench disclaim_bench_SOURCES = tests/disclaim_bench.c disclaim_bench_LDADD = $(test_ldadd) +TESTS += disclaim_weakmap_test$(EXEEXT) +check_PROGRAMS += disclaim_weakmap_test +disclaim_weakmap_test_SOURCES = tests/disclaim_weakmap_test.c +disclaim_weakmap_test_LDADD = $(test_ldadd) +if THREADS +disclaim_weakmap_test_LDADD += $(THREADDLLIBS) +endif + endif # Run the tests directly (without test-driver): @@ -138,6 +156,7 @@ check-without-test-driver: $(TESTS) ./staticrootstest$(EXEEXT) test ! -f disclaim_bench$(EXEEXT) || ./disclaim_bench$(EXEEXT) test ! -f disclaim_test$(EXEEXT) || ./disclaim_test$(EXEEXT) + test ! -f disclaim_weakmap_test$(EXEEXT) || ./disclaim_weakmap_test$(EXEEXT) test ! -f initsecondarythread_test$(EXEEXT) \ || ./initsecondarythread_test$(EXEEXT) test ! -f test_atomic_ops$(EXEEXT) || ./test_atomic_ops$(EXEEXT) diff --git a/gc/tests/threadkey_test.c b/gc/tests/threadkey_test.c index e348d7248..e224aac99 100644 --- a/gc/tests/threadkey_test.c +++ b/gc/tests/threadkey_test.c @@ -87,8 +87,10 @@ void make_key (void) int main (void) { int i; - GC_INIT (); + GC_INIT(); + if (GC_get_find_leak()) + printf("This test program is not designed for leak detection mode\n"); # ifdef GC_SOLARIS_THREADS pthread_key_create (&key, on_thread_exit); # else diff --git a/gc/tests/trace_test.c b/gc/tests/trace_test.c index 726519d0c..d97bbed15 100644 --- a/gc/tests/trace_test.c +++ b/gc/tests/trace_test.c @@ -39,7 +39,10 @@ struct treenode * mktree(int i) { int main(void) { int i; + GC_INIT(); + if (GC_get_find_leak()) + printf("This test program is not designed for leak detection mode\n"); for (i = 0; i < 10; ++i) { root[i] = mktree(12); } diff --git a/gc/win32_threads.c b/gc/win32_threads.c index 225d8e0dc..b5e45f066 100644 --- a/gc/win32_threads.c +++ b/gc/win32_threads.c @@ -74,6 +74,26 @@ #endif /* !GC_PTHREADS && !MSWINCE */ +/* PUSHED_REGS_COUNT is the number of copied registers in copy_ptr_regs. */ +static ptr_t copy_ptr_regs(word *regs, const CONTEXT *pcontext); +#if defined(I386) +# ifdef WOW64_THREAD_CONTEXT_WORKAROUND +# define PUSHED_REGS_COUNT 9 +# else +# define PUSHED_REGS_COUNT 7 +# endif +#elif defined(X86_64) || defined(SHx) +# define PUSHED_REGS_COUNT 15 +#elif defined(ARM32) +# define PUSHED_REGS_COUNT 13 +#elif defined(AARCH64) +# define PUSHED_REGS_COUNT 30 +#elif defined(MIPS) || defined(ALPHA) +# define PUSHED_REGS_COUNT 28 +#elif defined(PPC) +# define PUSHED_REGS_COUNT 29 +#endif + /* DllMain-based thread registration is currently incompatible */ /* with thread-local allocation, pthreads and WinCE. */ #if (defined(GC_DLL) || defined(GC_INSIDE_DLL)) \ @@ -168,7 +188,7 @@ GC_API void GC_CALL GC_use_threads_discovery(void) STATIC DWORD GC_main_thread = 0; -#define ADDR_LIMIT ((ptr_t)(word)-1) +#define ADDR_LIMIT ((ptr_t)GC_WORD_MAX) struct GC_Thread_Rep { union { @@ -179,6 +199,11 @@ struct GC_Thread_Rep { /* entries have invalid ids of */ /* zero and zero stack fields. */ /* Used only with GC_win32_dll_threads. */ + LONG long_in_use; /* The same but of the type that */ + /* matches the first argument of */ + /* InterlockedExchange(); volatile is */ + /* omitted because the ancient version */ + /* of the prototype lacks the qualifier.*/ # endif struct GC_Thread_Rep * next; /* Hash table link without */ @@ -249,6 +274,14 @@ struct GC_Thread_Rep { # ifdef THREAD_LOCAL_ALLOC struct thread_local_freelists tlfs; # endif + +# ifdef RETRY_GET_THREAD_CONTEXT + ptr_t context_sp; + word context_regs[PUSHED_REGS_COUNT]; + /* Populated as part of GC_suspend() as */ + /* resume/suspend loop may be needed for the */ + /* call to GetThreadContext() to succeed. */ +# endif }; typedef struct GC_Thread_Rep * GC_thread; @@ -315,7 +348,7 @@ STATIC volatile LONG GC_max_thread_index = 0; /* And now the version used if GC_win32_dll_threads is not set. */ /* This is a chained hash table, with much of the code borrowed */ -/* From the Posix implementation. */ +/* from the Posix implementation. */ #ifndef THREAD_TABLE_SZ # define THREAD_TABLE_SZ 256 /* Power of 2 (for speed). */ #endif @@ -324,8 +357,8 @@ STATIC volatile LONG GC_max_thread_index = 0; STATIC GC_thread GC_threads[THREAD_TABLE_SZ]; /* It may not be safe to allocate when we register the first thread. */ -/* Thus we allocated one statically. It does not contain any field we */ -/* need to push ("next" and "status" fields are unused). */ +/* Thus we allocated one statically. It does not contain any pointer */ +/* field we need to push ("next" and "status" fields are unused). */ static struct GC_Thread_Rep first_thread; static GC_bool first_thread_used = FALSE; @@ -365,7 +398,7 @@ STATIC GC_thread GC_new_thread(DWORD id) return(result); } -STATIC GC_bool GC_in_thread_creation = FALSE; +GC_INNER GC_bool GC_in_thread_creation = FALSE; /* Protected by allocation lock. */ GC_INLINE void GC_record_stack_base(GC_vthread me, @@ -415,9 +448,8 @@ STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb, /* around code that doesn't call back into the system libraries */ /* might be OK. But this hasn't been tested across all win32 */ /* variants. */ - /* cast away volatile qualifier */ for (i = 0; - InterlockedExchange((word*)&dll_thread_table[i].tm.in_use, 1) != 0; + InterlockedExchange(&dll_thread_table[i].tm.long_in_use, 1) != 0; i++) { /* Compare-and-swap would make this cleaner, but that's not */ /* supported before Windows 98 and NT 4.0. In Windows 2000, */ @@ -666,6 +698,10 @@ STATIC void GC_delete_gc_thread_no_free(GC_vthread t) /* see GC_stop_world() for the information. */ t -> stack_base = 0; t -> id = 0; + t -> suspended = FALSE; +# ifdef RETRY_GET_THREAD_CONTEXT + t -> context_sp = NULL; +# endif AO_store_release(&t->tm.in_use, FALSE); } else # endif @@ -919,7 +955,7 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn, UNLOCK(); client_data = fn(client_data); /* Prevent treating the above as a tail call. */ - GC_noop1((word)(&stacksect)); + GC_noop1(COVERT_DATAFLOW(&stacksect)); return client_data; /* result */ } @@ -1029,12 +1065,14 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn, STATIC void GC_remove_all_threads_but_me(void) { int hv; - GC_thread p, next, me = NULL; + GC_thread me = NULL; DWORD thread_id; pthread_t pthread_id = pthread_self(); /* same as in parent */ GC_ASSERT(!GC_win32_dll_threads); for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) { + GC_thread p, next; + for (p = GC_threads[hv]; 0 != p; p = next) { next = p -> tm.next; if (THREAD_EQUAL(p -> pthread_id, pthread_id) @@ -1160,41 +1198,101 @@ void GC_push_thread_structures(void) # endif } +#ifdef WOW64_THREAD_CONTEXT_WORKAROUND +# ifndef CONTEXT_EXCEPTION_ACTIVE +# define CONTEXT_EXCEPTION_ACTIVE 0x08000000 +# define CONTEXT_EXCEPTION_REQUEST 0x40000000 +# define CONTEXT_EXCEPTION_REPORTING 0x80000000 +# endif + static BOOL isWow64; /* Is running 32-bit code on Win64? */ +# define GET_THREAD_CONTEXT_FLAGS (isWow64 \ + ? CONTEXT_INTEGER | CONTEXT_CONTROL \ + | CONTEXT_EXCEPTION_REQUEST | CONTEXT_SEGMENTS \ + : CONTEXT_INTEGER | CONTEXT_CONTROL) +#else +# define GET_THREAD_CONTEXT_FLAGS (CONTEXT_INTEGER | CONTEXT_CONTROL) +#endif /* !WOW64_THREAD_CONTEXT_WORKAROUND */ + /* Suspend the given thread, if it's still active. */ STATIC void GC_suspend(GC_thread t) { # ifndef MSWINCE - /* Apparently the Windows 95 GetOpenFileName call creates */ - /* a thread that does not properly get cleaned up, and */ - /* SuspendThread on its descriptor may provoke a crash. */ - /* This reduces the probability of that event, though it still */ - /* appears there's a race here. */ DWORD exitCode; # endif +# ifdef RETRY_GET_THREAD_CONTEXT + int retry_cnt = 0; +# define MAX_SUSPEND_THREAD_RETRIES (1000 * 1000) +# endif + UNPROTECT_THREAD(t); -# ifndef MSWINCE - if (GetExitCodeThread(t -> handle, &exitCode) && - exitCode != STILL_ACTIVE) { + GC_acquire_dirty_lock(); + +# ifdef MSWINCE + /* SuspendThread() will fail if thread is running kernel code. */ + while (SuspendThread(THREAD_HANDLE(t)) == (DWORD)-1) { + GC_release_dirty_lock(); + Sleep(10); /* in millis */ + GC_acquire_dirty_lock(); + } +# elif defined(RETRY_GET_THREAD_CONTEXT) + for (;;) { + /* Apparently the Windows 95 GetOpenFileName call creates */ + /* a thread that does not properly get cleaned up, and */ + /* SuspendThread on its descriptor may provoke a crash. */ + /* This reduces the probability of that event, though it still */ + /* appears there is a race here. */ + if (GetExitCodeThread(t -> handle, &exitCode) + && exitCode != STILL_ACTIVE) { + GC_release_dirty_lock(); +# ifdef GC_PTHREADS + t -> stack_base = 0; /* prevent stack from being pushed */ +# else + /* This breaks pthread_join on Cygwin, which is guaranteed to */ + /* only see user threads. */ + GC_ASSERT(GC_win32_dll_threads); + GC_delete_gc_thread_no_free(t); +# endif + return; + } + + if (SuspendThread(t->handle) != (DWORD)-1) { + CONTEXT context; + + context.ContextFlags = GET_THREAD_CONTEXT_FLAGS; + if (GetThreadContext(t->handle, &context)) { + /* TODO: WoW64 extra workaround: if CONTEXT_EXCEPTION_ACTIVE */ + /* then Sleep(1) and retry. */ + t->context_sp = copy_ptr_regs(t->context_regs, &context); + break; /* success; the context pointer registers are saved */ + } + + /* Resume the thread, try to suspend it in a better location. */ + if (ResumeThread(t->handle) == (DWORD)-1) + ABORT("ResumeThread failed in suspend loop"); + } + if (retry_cnt > 1) { + GC_release_dirty_lock(); + Sleep(0); /* yield */ + GC_acquire_dirty_lock(); + } + if (++retry_cnt >= MAX_SUSPEND_THREAD_RETRIES) + ABORT("SuspendThread loop failed"); /* something must be wrong */ + } +# else + if (GetExitCodeThread(t -> handle, &exitCode) + && exitCode != STILL_ACTIVE) { + GC_release_dirty_lock(); # ifdef GC_PTHREADS t -> stack_base = 0; /* prevent stack from being pushed */ # else - /* this breaks pthread_join on Cygwin, which is guaranteed to */ - /* only see user pthreads */ GC_ASSERT(GC_win32_dll_threads); GC_delete_gc_thread_no_free(t); # endif return; } -# endif - GC_acquire_dirty_lock(); -# ifdef MSWINCE - /* SuspendThread() will fail if thread is running kernel code. */ - while (SuspendThread(THREAD_HANDLE(t)) == (DWORD)-1) - Sleep(10); /* in millis */ -# else if (SuspendThread(t -> handle) == (DWORD)-1) ABORT("SuspendThread failed"); -# endif /* !MSWINCE */ +# endif t -> suspended = (unsigned char)TRUE; GC_release_dirty_lock(); if (GC_on_thread_event) @@ -1380,30 +1478,23 @@ static GC_bool may_be_in_stack(ptr_t s) && !(last_info.Protect & PAGE_GUARD); } -STATIC word GC_push_stack_for(GC_thread thread, DWORD me) -{ - ptr_t sp, stack_min; - - struct GC_traced_stack_sect_s *traced_stack_sect = - thread -> traced_stack_sect; - if (thread -> id == me) { - GC_ASSERT(thread -> thread_blocked_sp == NULL); - sp = GC_approx_sp(); - } else if ((sp = thread -> thread_blocked_sp) == NULL) { - /* Use saved sp value for blocked threads. */ - /* For unblocked threads call GetThreadContext(). */ - CONTEXT context; - context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL; - if (!GetThreadContext(THREAD_HANDLE(thread), &context)) - ABORT("GetThreadContext failed"); - - /* Push all registers that might point into the heap. Frame */ - /* pointer registers are included in case client code was */ - /* compiled with the 'omit frame pointer' optimization. */ -# define PUSH1(reg) GC_push_one((word)context.reg) +/* Copy all registers that might point into the heap. Frame */ +/* pointer registers are included in case client code was */ +/* compiled with the 'omit frame pointer' optimization. */ +/* The context register values are stored to regs argument */ +/* which is expected to be of PUSHED_REGS_COUNT length exactly. */ +/* The functions returns the context stack pointer value. */ +static ptr_t copy_ptr_regs(word *regs, const CONTEXT *pcontext) { + ptr_t sp; + int cnt = 0; +# define context (*pcontext) +# define PUSH1(reg) (regs[cnt++] = (word)pcontext->reg) # define PUSH2(r1,r2) (PUSH1(r1), PUSH1(r2)) # define PUSH4(r1,r2,r3,r4) (PUSH2(r1,r2), PUSH2(r3,r4)) # if defined(I386) +# ifdef WOW64_THREAD_CONTEXT_WORKAROUND + PUSH2(ContextFlags, SegFs); /* cannot contain pointers */ +# endif PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp); sp = (ptr_t)context.Esp; # elif defined(X86_64) @@ -1414,6 +1505,12 @@ STATIC word GC_push_stack_for(GC_thread thread, DWORD me) PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11); PUSH1(R12); sp = (ptr_t)context.Sp; +# elif defined(AARCH64) + PUSH4(X0,X1,X2,X3),PUSH4(X4,X5,X6,X7),PUSH4(X8,X9,X10,X11); + PUSH4(X12,X13,X14,X15),PUSH4(X16,X17,X18,X19),PUSH4(X20,X21,X22,X23); + PUSH4(X24,X25,X26,X27),PUSH1(X28); + PUSH1(Lr); + sp = (ptr_t)context.Sp; # elif defined(SHx) PUSH4(R0,R1,R2,R3), PUSH4(R4,R5,R6,R7), PUSH4(R8,R9,R10,R11); PUSH2(R12,R13), PUSH1(R14); @@ -1436,9 +1533,111 @@ STATIC word GC_push_stack_for(GC_thread thread, DWORD me) PUSH4(IntA0,IntA1,IntA2,IntA3), PUSH4(IntA4,IntA5,IntT8,IntT9); PUSH4(IntT10,IntT11,IntT12,IntAt); sp = (ptr_t)context.IntSp; -# elif !defined(CPPCHECK) -# error "architecture is not supported" +# elif defined(CPPCHECK) + sp = (ptr_t)(word)cnt; /* to workaround "cnt not used" false positive */ +# else +# error Architecture is not supported +# endif +# undef context + GC_ASSERT(cnt == PUSHED_REGS_COUNT); + return sp; +} + +STATIC word GC_push_stack_for(GC_thread thread, DWORD me) +{ + ptr_t sp, stack_min; + + struct GC_traced_stack_sect_s *traced_stack_sect = + thread -> traced_stack_sect; + if (thread -> id == me) { + GC_ASSERT(thread -> thread_blocked_sp == NULL); + sp = GC_approx_sp(); + } else if ((sp = thread -> thread_blocked_sp) == NULL) { + /* Use saved sp value for blocked threads. */ + int i = 0; +# ifdef RETRY_GET_THREAD_CONTEXT + /* We cache context when suspending the thread since it may */ + /* require looping. */ + word *regs = thread->context_regs; + + if (thread->suspended) { + sp = thread->context_sp; + } else +# else + word regs[PUSHED_REGS_COUNT]; # endif + + /* else */ { + CONTEXT context; + + /* For unblocked threads call GetThreadContext(). */ + context.ContextFlags = GET_THREAD_CONTEXT_FLAGS; + if (GetThreadContext(THREAD_HANDLE(thread), &context)) { + sp = copy_ptr_regs(regs, &context); + } else { +# ifdef RETRY_GET_THREAD_CONTEXT + /* At least, try to use the stale context if saved. */ + sp = thread->context_sp; + if (NULL == sp) { + /* Skip the current thread, anyway its stack will */ + /* be pushed when the world is stopped. */ + return 0; + } +# else + ABORT("GetThreadContext failed"); +# endif + } + } + +# ifdef WOW64_THREAD_CONTEXT_WORKAROUND + i += 2; /* skip ContextFlags and SegFs */ +# endif + for (; i < PUSHED_REGS_COUNT; i++) + GC_push_one(regs[i]); + +# ifdef WOW64_THREAD_CONTEXT_WORKAROUND + /* WoW64 workaround. */ + if (isWow64) { + DWORD ContextFlags = (DWORD)regs[0]; + WORD SegFs = (WORD)regs[1]; + + if ((ContextFlags & CONTEXT_EXCEPTION_REPORTING) != 0 + && (ContextFlags & (CONTEXT_EXCEPTION_ACTIVE + /* | CONTEXT_SERVICE_ACTIVE */)) != 0) { + LDT_ENTRY selector; + PNT_TIB tib; + + if (!GetThreadSelectorEntry(THREAD_HANDLE(thread), SegFs, &selector)) + ABORT("GetThreadSelectorEntry failed"); + tib = (PNT_TIB)(selector.BaseLow + | (selector.HighWord.Bits.BaseMid << 16) + | (selector.HighWord.Bits.BaseHi << 24)); +# ifdef DEBUG_THREADS + GC_log_printf("TIB stack limit/base: %p .. %p\n", + (void *)tib->StackLimit, (void *)tib->StackBase); +# endif + GC_ASSERT(!((word)thread->stack_base + COOLER_THAN (word)tib->StackBase)); + + /* GetThreadContext() might return stale register values, */ + /* so we scan the entire stack region (down to the stack */ + /* limit). There is no 100% guarantee that all the */ + /* registers are pushed but we do our best (the proper */ + /* solution would be to fix it inside Windows OS). */ + sp = (ptr_t)tib->StackLimit; + } /* else */ +# ifdef DEBUG_THREADS + else { + static GC_bool logged; + if (!logged + && (ContextFlags & CONTEXT_EXCEPTION_REPORTING) == 0) { + GC_log_printf("CONTEXT_EXCEPTION_REQUEST not supported\n"); + logged = TRUE; + } + } +# endif + } +# endif /* WOW64_THREAD_CONTEXT_WORKAROUND */ } /* ! current thread */ /* Set stack_min to the lowest address in the thread stack, */ @@ -1523,6 +1722,8 @@ STATIC word GC_push_stack_for(GC_thread thread, DWORD me) return thread->stack_base - sp; /* stack grows down */ } +/* We hold allocation lock. Should do exactly the right thing if the */ +/* world is stopped. Should not fail if it isn't. */ GC_INNER void GC_push_all_stacks(void) { DWORD thread_id = GetCurrentThreadId(); @@ -1734,7 +1935,7 @@ GC_INNER void GC_get_next_stack(char *start, char *limit, { word my_mark_no = 0; - if ((word)id == (word)-1) return 0; /* to make compiler happy */ + if ((word)id == GC_WORD_MAX) return 0; /* to prevent a compiler warning */ marker_sp[(word)id] = GC_approx_sp(); # ifdef IA64 marker_bsp[(word)id] = GC_save_regs_in_stack(); @@ -2409,9 +2610,6 @@ GC_INNER void GC_get_next_stack(char *start, char *limit, GC_INNER void GC_thr_init(void) { struct GC_stack_base sb; -# ifdef GC_ASSERTIONS - int sb_result; -# endif GC_ASSERT(I_HOLD_LOCK()); if (GC_thr_initialized) return; @@ -2435,12 +2633,26 @@ GC_INNER void GC_thr_init(void) } # endif +# ifdef WOW64_THREAD_CONTEXT_WORKAROUND + /* Set isWow64 flag. */ + { + HMODULE hK32 = GetModuleHandle(TEXT("kernel32.dll")); + if (hK32) { + FARPROC pfn = GetProcAddress(hK32, "IsWow64Process"); + if (pfn + && !(*(BOOL (WINAPI*)(HANDLE, BOOL*))(word)pfn)( + GetCurrentProcess(), &isWow64)) + isWow64 = FALSE; /* IsWow64Process failed */ + } + } +# endif + /* Add the initial thread, so we can stop it. */ -# ifdef GC_ASSERTIONS - sb_result = + sb.mem_base = GC_stackbottom; + GC_ASSERT(sb.mem_base != NULL); +# ifdef IA64 + sb.reg_base = GC_register_stackbottom; # endif - GC_get_stack_base(&sb); - GC_ASSERT(sb_result == GC_SUCCESS); # if defined(PARALLEL_MARK) { From 5df4a6a70d4700d9886ca1fcf9aa4a105e9b0f3f Mon Sep 17 00:00:00 2001 From: John Pye Date: Thu, 13 Jan 2022 11:33:06 +1100 Subject: [PATCH 03/12] Update CMakeLists.txt gc lib target changed from `omcgc` to `gc-lib` to match `3rdParty/gc/CMakeLists.txt`. let's see... --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c8497d8d7..16aee8f74 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,20 +70,20 @@ set(enable_java_finalization OFF CACHE BOOL "Support for java finalization") set(enable_gcj_support OFF CACHE BOOL "Support for gcj") set(enable_large_config ON CACHE BOOL "Optimize for large heap or root set") omc_add_subdirectory(gc) -target_include_directories(omcgc PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/gc/include) +target_include_directories(gc-lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/gc/include) # make sure every target that links to gc-lib has its sources # compiled with -DGC_WIN32_PTHREADS (for pthreads on Windows, i.e., our MingW) # Or -DGC_THREADS (for auto detection on other systems.) # On Windows with MinGW OM uses pthreads-win32. GC_WIN32_PTHREADS is required # to be set explicitly for use of pthreads API on Windows. if(MINGW) - target_compile_definitions(omcgc PUBLIC GC_WIN32_PTHREADS) + target_compile_definitions(gc-lib PUBLIC GC_WIN32_PTHREADS) else() - target_compile_definitions(omcgc PUBLIC GC_THREADS) + target_compile_definitions(gc-lib PUBLIC GC_THREADS) endif(MINGW) # Finally add an alias for clarity purposes. -add_library(omc::3rd::omcgc ALIAS omcgc) +add_library(omc::3rd::omcgc ALIAS gc-lib) From d4bea9ec58a23cdf32725cefbff3b2b4483e75e4 Mon Sep 17 00:00:00 2001 From: John Pye Date: Thu, 13 Jan 2022 15:56:20 +1100 Subject: [PATCH 04/12] seems to be needed for building on Ubuntu 20.04 within OpenModelica. --- gc/tests/CMakeLists.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gc/tests/CMakeLists.txt b/gc/tests/CMakeLists.txt index 3c84220b9..a044372d7 100644 --- a/gc/tests/CMakeLists.txt +++ b/gc/tests/CMakeLists.txt @@ -45,3 +45,12 @@ ADD_TEST(NAME realloc_test COMMAND realloc_test) ADD_EXECUTABLE(smashtest smash_test.c) TARGET_LINK_LIBRARIES(smashtest gc-lib) ADD_TEST(NAME smashtest COMMAND smashtest) + +if(CMAKE_USE_PTHREADS_INIT) + target_link_libraries(gctest pthread) + target_link_libraries(hugetest pthread) + target_link_libraries(leaktest pthread) + target_link_libraries(middletest pthread) + target_link_libraries(realloc_test pthread) + target_link_libraries(smashtest pthread) +endif() From 35825d3444b45490d3f937368fc97ef56c034f0d Mon Sep 17 00:00:00 2001 From: John Pye Date: Thu, 13 Jan 2022 19:46:33 +1100 Subject: [PATCH 05/12] Revert "updated gc-8.0.6" This reverts commit 7569a3949dc52ea4d859fa4e382529148c93010f. --- gc/AUTHORS | 19 - gc/BCC_MAKEFILE | 6 +- gc/CMakeLists.txt | 814 +++++++++++++++++------- gc/ChangeLog | 363 +---------- gc/Makefile.am | 52 +- gc/Makefile.direct | 24 +- gc/NT_MAKEFILE | 10 +- gc/OS2_MAKEFILE | 6 +- gc/README.QUICK | 2 +- gc/README.md | 24 +- gc/SMakefile.amiga | 8 +- gc/WCC_MAKEFILE | 5 +- gc/allchblk.c | 108 +--- gc/alloc.c | 28 +- gc/backgraph.c | 7 +- gc/bdw-gc.pc.in | 2 +- gc/blacklst.c | 3 +- gc/build/s60v3/libgc.mmp | 2 - gc/configure.ac | 225 +++---- gc/cord/cord.am | 10 +- gc/cord/cordbscs.c | 33 +- gc/cord/cordprnt.c | 22 +- gc/cord/tests/cordtest.c | 18 +- gc/cord/tests/de.c | 1 - gc/cord/tests/de_win.c | 15 +- gc/darwin_stop_world.c | 13 +- gc/dbg_mlc.c | 2 +- gc/digimars.mak | 3 +- gc/doc/README.OS2 | 2 +- gc/doc/README.amiga | 20 +- gc/doc/README.cmake | 2 +- gc/doc/README.darwin | 67 +- gc/doc/README.ews4800 | 2 +- gc/doc/README.macros | 15 +- gc/doc/README.solaris2 | 2 +- gc/doc/README.win32 | 2 +- gc/doc/finalization.md | 8 +- gc/doc/gcdescr.md | 27 +- gc/doc/gcinterface.md | 22 +- gc/doc/leak.md | 57 +- gc/doc/overview.md | 12 +- gc/doc/porting.md | 15 +- gc/doc/scale.md | 10 +- gc/doc/simple_example.md | 3 +- gc/dyn_load.c | 12 +- gc/extra/msvc_dbg.c | 36 +- gc/extra/pcr_interface.c | 2 - gc/finalize.c | 10 +- gc/fnlz_mlc.c | 8 +- gc/gc.mak | 10 +- gc/gc_cpp.cc | 42 +- gc/headers.c | 35 +- gc/include/ec.h | 4 +- gc/include/gc.h | 71 ++- gc/include/gc_allocator.h | 5 +- gc/include/gc_config_macros.h | 19 +- gc/include/gc_cpp.h | 35 +- gc/include/gc_disclaim.h | 3 - gc/include/gc_pthread_redirects.h | 5 - gc/include/gc_typed.h | 5 +- gc/include/gc_version.h | 2 +- gc/include/include.am | 3 + gc/include/javaxfc.h | 5 - gc/include/new_gc_alloc.h | 16 +- gc/include/private/dbg_mlc.h | 12 +- gc/include/private/gc_atomic_ops.h | 7 +- gc/include/private/gc_hdrs.h | 2 +- gc/include/private/gc_locks.h | 6 +- gc/include/private/gc_pmark.h | 16 +- gc/include/private/gc_priv.h | 129 ++-- gc/include/private/gcconfig.h | 532 +++++++--------- gc/include/private/pthread_support.h | 2 +- gc/include/private/specific.h | 5 - gc/include/private/thread_local_alloc.h | 2 +- gc/mach_dep.c | 8 +- gc/mallocx.c | 8 +- gc/mark.c | 51 +- gc/mark_rts.c | 7 +- gc/misc.c | 135 ++-- gc/new_hblk.c | 2 +- gc/os_dep.c | 313 ++++----- gc/pthread_stop_world.c | 63 +- gc/pthread_support.c | 123 ++-- gc/reclaim.c | 55 +- gc/specific.c | 6 +- gc/tests/disclaim_bench.c | 2 - gc/tests/disclaim_test.c | 4 +- gc/tests/disclaim_weakmap_test.c | 472 -------------- gc/tests/initsecondarythread.c | 2 - gc/tests/middle.c | 2 - gc/tests/realloc_test.c | 2 - gc/tests/smash_test.c | 15 +- gc/tests/staticrootstest.c | 2 - gc/tests/subthread_create.c | 2 +- gc/tests/test.c | 29 +- gc/tests/test_cpp.cc | 23 +- gc/tests/tests.am | 27 +- gc/tests/threadkey_test.c | 4 +- gc/tests/trace_test.c | 3 - gc/win32_threads.c | 328 ++-------- 100 files changed, 1767 insertions(+), 3053 deletions(-) delete mode 100644 gc/tests/disclaim_weakmap_test.c diff --git a/gc/AUTHORS b/gc/AUTHORS index a5a4fb208..1c453ef2c 100644 --- a/gc/AUTHORS +++ b/gc/AUTHORS @@ -28,7 +28,6 @@ Akira Tagoh Alain Novak Alan Dosser Alan J. Demers -Alaskan Emily Aleksey Demakov Alessandro Bruni Alex Ronne Petersen @@ -103,10 +102,8 @@ Chris Metcalf Christian Joensson Christian Limpach Christian Thalinger -Christian Weisgerber Christoffe Raffali Clay Spence -Clement Chigot Colin LeMahieu Craig McDaniel Dai Sato @@ -138,7 +135,6 @@ Davide Angelocola Demyan Kimitsa Dick Porter Dietmar Planitzer -Dima Pasechnik Dimitris Vyzovitis Dimitry Andric Djamel Magri @@ -153,7 +149,6 @@ Eric Benson Eric Holk Erik M. Bray Fabian Thylman -Fabrice Fontaine Fergus Henderson Franklin Chen Fred Gilham @@ -186,7 +181,6 @@ Ian Searle Igor Khavkine Ivan Demakov Ivan Maidanski -Ivan R Jaap Boender Jack Andrews Jacob Navia @@ -197,7 +191,6 @@ Jan Alexander Steffens Jan Wielemaker Jani Kajala Jared McNeill -Jasper Lievisse Adriaanse Jay Krell Jean-Baptiste Nivois Jean-Claude Beaudoin @@ -220,12 +213,10 @@ Johannes Schmidt Johannes Totz John Bowman John Clements -John David Anglin John Ellis John Merryweather Cooper Jon Moore Jonas Echterhoff -Jonas Hahnfeld Jonathan Bachrach Jonathan Chambers Jonathan Clark @@ -262,7 +253,6 @@ Louis Zhuang Lucas Meijer Ludovic Courtes Maarten Thibaut -Mahder Gebremedhin Manuel A. Fernandez Montecelo Manuel Serrano Marc Recht @@ -279,7 +269,6 @@ Mark Weiser Martin Hirzel Martin Koeppe Martin Tauchmann -Massimiliano Gubinelli Matt Austern Matthew Flatt Matthias Andree @@ -307,7 +296,6 @@ Neale Ferguson Neil Sharman Nicolas Cannasse Niibe Yutaka -Nikita Ermakov Niklas Therning Noah Lavine Nobuyuki Hikichi @@ -324,7 +312,6 @@ Paul Graham Paul Nash Per Bothner Peter Bigot -Peter Budai Peter Chubb Peter Colson Peter Housel @@ -355,7 +342,6 @@ Reza Shahidi Richard Earnshaw Richard Henderson Richard Sandiford -Richard Zidlicky Rob Haack Robert Brazile Rodrigo Kumpera @@ -378,7 +364,6 @@ Shiro Kawai Simon Gornall Simon Posnjak Slava Sysoltsev -Sorawee Porncharoenwase Stefan Ring Stefano Rivera Sugioka Toshinobu @@ -395,11 +380,9 @@ Thomas Klausner Thomas Linder Puls Thomas Maier Thomas Schwinge -Thomas Thiriez Thorsten Glaser Tilman Vogel Tim Bingham -Tim Gates Timothy N. Newsham Tom Tromey Tommaso Tagliapietra @@ -414,14 +397,12 @@ Ulrich Weigand Uros Bizjak Vernon Lee Victor Ivrii -Victor Romero Vitaly Magerya Vladimir Tsichevski Walter Bright Walter Underwood Wilson Ho Wink Saville -Wookey Xi Wang Xiaokun Zhu Yann Dirson diff --git a/gc/BCC_MAKEFILE b/gc/BCC_MAKEFILE index f6398c1dd..10ac184a0 100644 --- a/gc/BCC_MAKEFILE +++ b/gc/BCC_MAKEFILE @@ -13,9 +13,7 @@ lib= $(bcbin)\tlib link= $(bcbin)\ilink32 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_EXECUTE_PERMISSION \ - -DENABLE_DISCLAIM -DGC_ATOMIC_UNCOLLECTABLE -DJAVA_FINALIZATION \ - -DGC_GCJ_SUPPORT -DGC_OPERATOR_NEW_ARRAY -DUSE_MUNMAP +defines= -DALL_INTERIOR_POINTERS -DNO_GETENV -DJAVA_FINALIZATION -DENABLE_DISCLAIM -DGC_OPERATOR_NEW_ARRAY .c.obj: $(cc) @&&| @@ -35,7 +33,7 @@ XXXOBJS= XXXalloc.obj XXXreclaim.obj XXXallchblk.obj XXXmisc.obj \ XXXobj_map.obj XXXblacklst.obj XXXfinalize.obj XXXnew_hblk.obj \ XXXdbg_mlc.obj XXXmalloc.obj XXXdyn_load.obj \ XXXtypd_mlc.obj XXXptr_chck.obj XXXgc_cpp.obj XXXmallocx.obj \ - XXXfnlz_mlc.obj XXXgcj_mlc.obj + XXXfnlz_mlc.obj OBJS= $(XXXOBJS:XXX=) diff --git a/gc/CMakeLists.txt b/gc/CMakeLists.txt index c8ebd9b04..697c5c053 100644 --- a/gc/CMakeLists.txt +++ b/gc/CMakeLists.txt @@ -21,232 +21,592 @@ # this will generate gc.sln # -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 - -DALL_INTERIOR_POINTERS -DNO_EXECUTE_PERMISSION") - -#LIBATOMIC #TODO -#ADD_LIBRARY(atomic_ops STATIC ) -#SET_TARGET_PROPERTIES(atomic_ops PROPERTIES COMPILE_FLAGS -DNO_DEBUGGING) - - -#LIBGC - -INCLUDE_DIRECTORIES(include) -INCLUDE_DIRECTORIES(libatomic_ops/src) - -SET(SRC alloc.c reclaim.c allchblk.c misc.c mach_dep.c os_dep.c +cmake_minimum_required(VERSION 3.1) + +option(enable_cplusplus "C++ support" OFF) +if (enable_cplusplus) + project(gc) +else() + project(gc C) +endif() + +include(CheckCCompilerFlag) +include(CheckCSourceCompiles) +include(CheckFunctionExists) +include(CheckIncludeFile) +include(CheckSymbolExists) +include(CTest) + +# Customize the build by passing "-D=ON|OFF" in the command line. +option(GC_BUILD_SHARED_LIBS "Build shared libraries" ON) +option(build_cord "Build cord library" ON) +option(build_tests "Build tests" OFF) +option(enable_threads "Support threads" ON) +option(enable_parallel_mark "Parallelize marking and free list construction" ON) +option(enable_thread_local_alloc "Turn on thread-local allocation optimization" ON) +option(enable_threads_discovery "Enable threads discovery in GC" ON) +option(enable_throw_bad_alloc_library "Turn on C++ gctba library build" ON) +option(enable_gcj_support "Support for gcj" ON) +option(enable_sigrt_signals "Use SIGRTMIN-based signals for thread suspend/resume" OFF) +option(enable_gc_debug "Support for pointer back-tracing" OFF) +option(disable_gc_debug "Disable debugging like GC_dump and its callees" OFF) +option(enable_java_finalization "Support for java finalization" ON) +option(enable_atomic_uncollectable "Support for atomic uncollectible allocation" ON) +option(enable_redirect_malloc "Redirect malloc and friends to GC routines" OFF) +option(enable_disclaim "Support alternative finalization interface" ON) +option(enable_large_config "Optimize for large heap or root set" OFF) +option(enable_gc_assertions "Enable collector-internal assertion checking" OFF) +option(enable_mmap "Use mmap instead of sbrk to expand the heap" OFF) +option(enable_munmap "Return page to the OS if empty for N collections" ON) +option(enable_dynamic_loading "Enable tracing of dynamic library data roots" ON) +option(enable_register_main_static_data "Perform the initial guess of data root sets" ON) +option(enable_checksums "Report erroneously cleared dirty bits" OFF) +option(enable_werror "Pass -Werror to the C compiler (treat warnings as errors)" OFF) +option(enable_single_obj_compilation "Compile all libgc source files into single .o" OFF) +option(enable_handle_fork "Attempt to ensure a usable collector after fork()" ON) +option(disable_handle_fork "Prohibit installation of pthread_atfork() handlers" OFF) +option(install_headers "Install header files" ON) + +add_definitions("-DALL_INTERIOR_POINTERS -DNO_EXECUTE_PERMISSION") + +if(GC_BUILD_SHARED_LIBS) + set(GC_LIBRARY_BUILD_TYPE SHARED) +else(GC_BUILD_SHARED_LIBS) + set(GC_LIBRARY_BUILD_TYPE STATIC) +endif(GC_BUILD_SHARED_LIBS) + +# Set struct packing alignment to word (instead of 1-byte). +if (BORLAND) + add_compile_options(/a4) +elseif (WATCOM) + add_compile_options(/zp4) +endif() + +# Output all warnings. +if (BORLAND) + # All warnings except for particular ones. + add_compile_options(/w /w-pro /w-aus /w-par /w-ccc /w-inl /w-rch) +elseif (MSVC) + # All warnings but ignoring "unreferenced formal parameter" and + # "conditional expression is constant" ones. + add_compile_options(/W4 /wd4100 /wd4127) + # Disable crt security warnings, since unfortunately they warn about all + # sorts of safe uses of strncpy. + add_definitions("-D_CRT_SECURE_NO_DEPRECATE") +elseif (WATCOM) + add_compile_options(/wx) +else() + # TODO add -[W]pedantic -Wno-long-long + add_compile_options(-Wall -Wextra) +endif() + +include_directories(include) + +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 dyn_load.c typd_mlc.c ptr_chck.c - mallocx.c) -SET(LIBS) -OPTION(enable_threads "TODO" NO) -IF(enable_threads) - FIND_PACKAGE(Threads REQUIRED) - MESSAGE("Thread Model: ${CMAKE_THREAD_LIBS_INIT}" ) - INCLUDE_DIRECTORIES(${Threads_INCLUDE_DIR}) - SET(LIBS ${LIBS} ${Threads_LIBRARIES}) -ENDIF(enable_threads) - -OPTION(enable_handle_fork "Attempt to ensure a usable collector after fork()" ON) - -OPTION(enable_thread_local_alloc "Turn on thread-local allocation optimization" ON) - -OPTION(enable_parallel_mark "Parallelize marking and free list construction" ON) - -#IF(Threads_FOUND) -# ADD_DEFINITIONS("") -#ELSE -# MESSAGE("Parallel mark requires enable_threads ON" ) -#ENDIF(Threads_FOUND) - -#OPTION(enable_cplusplus "install C++ support" ON) -SET(SRC ${SRC} gc_cpp.cc) - -SET(_HOST ${CMAKE_HOST_SYSTEM_PROCESSOR}--${CMAKE_SYSTEM}) #FIXME missing the vendor field. -STRING(TOLOWER ${_HOST} HOST) -MESSAGE("HOST = ${HOST}") - -# Thread Detection. Relying on cmake for lib and includes. -#TODO check cmake detection -IF(CMAKE_USE_PTHREADS_INIT) - SET(SRC ${SRC} gc_dlopen.c pthread_start.c pthread_stop_world.c - pthread_support.c) - # Common defines for most POSIX platforms. - IF( HOST MATCHES .*-.*-aix.*|.*-.*-android.*|.*-.*-cygwin.*|.*-.*-darwin.*|.*-.*-.*freebsd.*|.*-.*-haiku.*|.*-.*-gnu.*|.*-.*-hpux11.*|.*-.*-irix.*|.*-.*-.*linux.*|.*-.*-msys.*|.*-.*-nacl.*|.*-.*-netbsd.*|.*-.*-openbsd.*|.*-.*-osf.*|.*-.*-solaris.*) - ADD_DEFINITIONS("-DGC_THREADS -D_REENTRANT") - IF(enable_parallel_mark) - ADD_DEFINITIONS("-DPARALLEL_MARK") - ENDIF(enable_parallel_mark) - IF(enable_thread_local_alloc) - ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC") - SET(SRC ${SRC} specific.c thread_local_alloc.c) - ENDIF(enable_thread_local_alloc) - MESSAGE("Explicit GC_INIT() calls may be required.") - ENDIF() - IF ( HOST MATCHES .*-.*-hpux11.*) - MESSAGE("Only HP/UX 11 POSIX threads are supported.") - ADD_DEFINITIONS("-D_POSIX_C_SOURCE=199506L") #TODO test -DVAR=value. Alternative is COMPILE_DEFINITIONS property - ENDIF() - IF ( HOST MATCHES .*-.*-hpux10.*) - MESSAGE("HP/UX 10 POSIX threads are not supported.") - ENDIF() - IF ( HOST MATCHES .*-.*-netbsd.*) - MESSAGE("Only on NetBSD 2.0 or later.") - ADD_DEFINITIONS("-D_PTHREADS") - ENDIF() - IF( HOST MATCHES .*-.*-android.*) - # Android NDK does not provide pthread_atfork. - ELSEIF( HOST MATCHES .*-.*-aix.*|.*-.*-cygwin.*|.*-.*-freebsd.*|.*-.*-haiku.*|.*-.*-hpux11.*|.*-.*-irix.*|.*-.*-kfreebsd.*-gnu|.*-.*-.*linux.*|.*-.*-netbsd.*|.*-.*-openbsd.*|.*-.*-osf.*|.*-.*-solaris.*) - IF(enable_handle_fork) - ADD_DEFINITIONS("-DHANDLE_FORK") - ENDIF(enable_handle_fork) - ENDIF() - IF ( HOST MATCHES .*-.*-cygwin.*|.*-.*-msys.*) - SET(SRC ${SRC} win32_threads.c) - ENDIF() - IF ( HOST MATCHES .*-.*-darwin.*) - IF(enable_handle_fork) - # The incremental mode conflicts with fork handling. - IF(enable_parallel_mark) - ADD_DEFINITIONS("-DHANDLE_FORK") - ENDIF(enable_parallel_mark) - ENDIF(enable_handle_fork) - SET(SRC ${SRC} darwin_stop_world.c) - #TODO - #darwin_threads=true - ENDIF() -ENDIF(CMAKE_USE_PTHREADS_INIT) - -IF(CMAKE_USE_WIN32_THREADS_INIT) - ADD_DEFINITIONS("-DGC_THREADS") - IF(enable_parallel_mark) - ADD_DEFINITIONS("-DPARALLEL_MARK") - IF(enable_thread_local_alloc) - ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC") - SET(SRC ${SRC} thread_local_alloc.c) - ENDIF(enable_thread_local_alloc) - ENDIF() - ADD_DEFINITIONS("-DEMPTY_GETENV_RESULTS") #TODO test - SET(SRC ${SRC} win32_threads.c) -ENDIF(CMAKE_USE_WIN32_THREADS_INIT) - -OPTION(enable_gcj_support "Support for gcj" ON) -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) - -OPTION(enable_disclaim "Support alternative finalization interface" ON) -IF(enable_disclaim) - ADD_DEFINITIONS("-DENABLE_DISCLAIM") - SET(SRC ${SRC} fnlz_mlc.c) -ENDIF(enable_disclaim) - -OPTION(enable_java_finalization "Support for java finalization" ON) -IF(enable_java_finalization) - ADD_DEFINITIONS("-DJAVA_FINALIZATION") -ENDIF(enable_java_finalization) - -OPTION(enable_atomic_uncollectable "Support for atomic uncollectible allocation" ON) -IF(enable_atomic_uncollectable) - ADD_DEFINITIONS("-DGC_ATOMIC_UNCOLLECTABLE") -ENDIF(enable_atomic_uncollectable) - -OPTION(enable_gc_debug "Support for pointer back-tracing" NO) -IF(enable_gc_debug) - ADD_DEFINITIONS("-DDBG_HDRS_ALL -DKEEP_BACK_PTRS") - IF (HOST MATCHES ia64-.*-linux.*|i586-.*-linux.*|i686-.*-linux.*|x86-.*-linux.*|x86_64-.*-linux.*) - ADD_DEFINITIONS("-DMAKE_BACK_GRAPH") - ADD_DEFINITIONS("-DSAVE_CALL_COUNT=8") - SET(SRC ${SRC} backgraph.c) - ENDIF() - IF (HOST MATCHES i.86-.*-dgux.*) - ADD_DEFINITIONS("-DMAKE_BACK_GRAPH") - SET(SRC ${SRC} backgraph.c) - ENDIF() -ENDIF(enable_gc_debug) - -OPTION(enable_redirect_malloc "Redirect malloc and friends to GC routines" NO) -IF(enable_redirect_malloc) - IF(enable_gc_debug) - ADD_DEFINITIONS("-DREDIRECT_MALLOC=GC_debug_malloc_replacement") - ADD_DEFINITIONS("-DREDIRECT_REALLOC=GC_debug_realloc_replacement") - ADD_DEFINITIONS("-DREDIRECT_FREE=GC_debug_free") - ELSE(enable_gc_debug) - ADD_DEFINITIONS("-DREDIRECT_MALLOC=GC_malloc") - ENDIF(enable_gc_debug) - ADD_DEFINITIONS("-DGC_USE_DLOPEN_WRAP") -ENDIF(enable_redirect_malloc) - -OPTION(enable_mmap "Use mmap instead of sbrk to expand the heap" NO) - -OPTION(enable_munmap "Return page to the OS if empty for N collections" ON) -IF(enable_munmap) - ADD_DEFINITIONS("-DUSE_MMAP -DUSE_MUNMAP") -ELSEIF(enable_mmap) - ADD_DEFINITIONS("-DUSE_MMAP") -ENDIF() - -OPTION(enable_dynamic_loading "Enable tracing of dynamic library data roots" ON) -IF(NOT enable_dynamic_loading) - ADD_DEFINITIONS("-DIGNORE_DYNAMIC_LOADING") -ENDIF() - -OPTION(enable_register_main_static_data "Perform the initial guess of data root sets" ON) -IF(NOT enable_register_main_static_data) - ADD_DEFINITIONS("-DGC_DONT_REGISTER_MAIN_STATIC_DATA") -ENDIF() - -OPTION(enable_large_config "Optimize for large heap or root set" NO) -IF(enable_large_config) - ADD_DEFINITIONS("-DLARGE_CONFIG") -ENDIF(enable_large_config) - -OPTION(enable_gc_assertions "Enable collector-internal assertion checking" NO) -IF(enable_gc_assertions) - ADD_DEFINITIONS("-DGC_ASSERTIONS") -ENDIF(enable_gc_assertions) - -OPTION(enable_threads_discovery "Enable threads discovery in GC" ON) -IF(NOT enable_threads_discovery) - ADD_DEFINITIONS("-DGC_NO_THREADS_DISCOVERY") -ENDIF() - -OPTION(enable_checksums "Report erroneously cleared dirty bits" NO) -IF(enable_checksums) - IF(enable_munmap OR enable_threads) - MESSAGE("CHECKSUMS not compatible with USE_MUNMAP or threads") - ENDIF() - ADD_DEFINITIONS("-DCHECKSUMS") - SET(SRC ${SRC} checksums.c) -ENDIF(enable_checksums) - -ADD_LIBRARY( gc-lib STATIC ${SRC}) -SET_TARGET_PROPERTIES(gc-lib PROPERTIES - COMPILE_DEFINITIONS GC_NOT_DLL) -#TODO TARGET_LINK_LIBRARIES(... ... ${LIBS}) - -ADD_LIBRARY( gcmt-dll SHARED ${SRC}) - -IF(WIN32) - ADD_EXECUTABLE(cord cord/cordbscs.c cord/cordxtra.c - cord/tests/de.c cord/tests/de_win.c) - SET_TARGET_PROPERTIES(cord PROPERTIES WIN32_EXECUTABLE TRUE) - SET_TARGET_PROPERTIES(cord PROPERTIES - COMPILE_DEFINITIONS GC_NOT_DLL) - TARGET_LINK_LIBRARIES(cord gc-lib) - TARGET_LINK_LIBRARIES(cord gdi32) -ENDIF(WIN32) - -ADD_SUBDIRECTORY(tests) + mallocx.c gc_dlopen.c) +set(THREADDLLIBS) + +set(_HOST ${CMAKE_SYSTEM_PROCESSOR}-unknown-${CMAKE_SYSTEM}) +string(TOLOWER ${_HOST} HOST) +message(STATUS "TARGET = ${HOST}") + +if (enable_threads) + find_package(Threads REQUIRED) + message(STATUS "Thread library: ${CMAKE_THREAD_LIBS_INIT}") + include_directories(libatomic_ops/src) + include_directories(${Threads_INCLUDE_DIR}) + set(THREADDLLIBS ${CMAKE_THREAD_LIBS_INIT}) + if (NOT (APPLE OR CYGWIN OR MSYS OR WIN32 OR HOST MATCHES mips-.*-irix6.*)) + set(THREADDLLIBS ${THREADDLLIBS} -ldl) + # The predefined CMAKE_DL_LIBS may be broken. + endif() +endif(enable_threads) + +# Thread support detection. +if (CMAKE_USE_PTHREADS_INIT) + set(SRC ${SRC} pthread_start.c pthread_support.c pthread_stop_world.c) + if (HOST MATCHES .*-.*-hpux10.*) + message(FATAL_ERROR "HP/UX 10 POSIX threads are not supported.") + endif() + # Assume the compiler supports C11 (GCC) atomic intrinsics. + add_definitions("-DGC_BUILTIN_ATOMIC") + # Common defines for POSIX platforms. + add_definitions("-DGC_THREADS -D_REENTRANT") + if (enable_parallel_mark) + add_definitions("-DPARALLEL_MARK") + endif() + if (enable_thread_local_alloc) + add_definitions("-DTHREAD_LOCAL_ALLOC") + set(SRC ${SRC} thread_local_alloc.c) + endif() + message("Explicit GC_INIT() calls may be required.") + if (HOST MATCHES .*-.*-hpux11.*) + message("Only HP/UX 11 POSIX threads are supported.") + add_definitions("-D_POSIX_C_SOURCE=199506L") + elseif (HOST MATCHES .*-.*-netbsd.*) + message("Only on NetBSD 2.0 or later.") + add_definitions("-D_PTHREADS") + endif() + if (ANDROID OR MSYS) # ANDROID variable is defined by CMake v3.7.0+. + # Android NDK does not provide pthread_atfork. + elseif (APPLE) + if (enable_handle_fork AND NOT disable_handle_fork) + # The incremental mode conflicts with fork handling. + if (enable_parallel_mark) + add_definitions("-DHANDLE_FORK") + endif(enable_parallel_mark) + endif() + set(SRC ${SRC} darwin_stop_world.c) + elseif (enable_handle_fork AND NOT disable_handle_fork) + add_definitions("-DHANDLE_FORK") + endif() + if (enable_sigrt_signals) + add_definitions("-DGC_USESIGRT_SIGNALS") + endif() + if (CYGWIN OR MSYS) + set(SRC ${SRC} win32_threads.c) + endif() +elseif (CMAKE_USE_WIN32_THREADS_INIT) + add_definitions("-DGC_THREADS") + if (enable_parallel_mark) + add_definitions("-DPARALLEL_MARK") + endif() + if (enable_thread_local_alloc AND (enable_parallel_mark OR NOT GC_BUILD_SHARED_LIBS)) + # Imply THREAD_LOCAL_ALLOC unless GC_DLL. + add_definitions("-DTHREAD_LOCAL_ALLOC") + set(SRC ${SRC} thread_local_alloc.c) + endif() + add_definitions("-DEMPTY_GETENV_RESULTS") + set(SRC ${SRC} win32_threads.c) +elseif (CMAKE_HP_PTHREADS_INIT OR CMAKE_USE_SPROC_INIT) + message(FATAL_ERROR "Unsupported thread package") +endif() + +if (disable_handle_fork) + add_definitions("-DNO_HANDLE_FORK") +endif() + +if (enable_gcj_support) + add_definitions("-DGC_GCJ_SUPPORT") + if (enable_threads AND NOT (enable_thread_local_alloc AND HOST MATCHES .*-.*-kfreebsd.*-gnu)) + # FIXME: For a reason, gctest hangs up on kFreeBSD if both of + # THREAD_LOCAL_ALLOC and GC_ENABLE_SUSPEND_THREAD are defined. + add_definitions("-DGC_ENABLE_SUSPEND_THREAD") + endif() + set(SRC ${SRC} gcj_mlc.c) +endif(enable_gcj_support) + +if (enable_disclaim) + add_definitions("-DENABLE_DISCLAIM") + set(SRC ${SRC} fnlz_mlc.c) +endif() + +if (enable_java_finalization) + add_definitions("-DJAVA_FINALIZATION") +endif() + +if (enable_atomic_uncollectable) + add_definitions("-DGC_ATOMIC_UNCOLLECTABLE") +endif() + +if (enable_gc_debug) + add_definitions("-DDBG_HDRS_ALL -DKEEP_BACK_PTRS") + if (HOST MATCHES i.86-.*-dgux.*|ia64-.*-linux.*|i586-.*-linux.*|i686-.*-linux.*|x86-.*-linux.*|x86_64-.*-linux.*) + add_definitions("-DMAKE_BACK_GRAPH") + if (HOST MATCHES .*-.*-.*linux.*) + add_definitions("-DSAVE_CALL_COUNT=8") + endif() + set(SRC ${SRC} backgraph.c) + endif() +endif(enable_gc_debug) + +if (disable_gc_debug) + add_definitions("-DNO_DEBUGGING") +elseif (WINCE) + # Read environment variables from ".gc.env" file. + add_definitions("-DGC_READ_ENV_FILE") +endif() + +if (enable_redirect_malloc) + if (enable_gc_debug) + add_definitions("-DREDIRECT_MALLOC=GC_debug_malloc_replacement") + add_definitions("-DREDIRECT_REALLOC=GC_debug_realloc_replacement") + add_definitions("-DREDIRECT_FREE=GC_debug_free") + else() + add_definitions("-DREDIRECT_MALLOC=GC_malloc") + endif() + add_definitions("-DGC_USE_DLOPEN_WRAP") +endif(enable_redirect_malloc) + +if (enable_munmap) + add_definitions("-DUSE_MMAP -DUSE_MUNMAP") +elseif (enable_mmap) + add_definitions("-DUSE_MMAP") +endif() + +if (NOT enable_dynamic_loading) + add_definitions("-DIGNORE_DYNAMIC_LOADING") +endif() + +if (NOT enable_register_main_static_data) + add_definitions("-DGC_DONT_REGISTER_MAIN_STATIC_DATA") +endif() + +if (enable_large_config) + add_definitions("-DLARGE_CONFIG") +endif() + +if (enable_gc_assertions) + add_definitions("-DGC_ASSERTIONS") +endif() + +if (NOT enable_threads_discovery) + add_definitions("-DGC_NO_THREADS_DISCOVERY") +endif() + +if (enable_checksums) + if (enable_munmap OR enable_threads) + message(FATAL_ERROR "CHECKSUMS not compatible with USE_MUNMAP or threads") + endif() + add_definitions("-DCHECKSUMS") + set(SRC ${SRC} checksums.c) +endif(enable_checksums) + +if (enable_werror) + if (BORLAND) + add_compile_options(/w!) + elseif (MSVC) + add_compile_options(/WX) + # Workaround "typedef ignored on left of ..." warning reported in + # imagehlp.h of e.g. Windows Kit 8.1. + add_compile_options(/wd4091) + elseif (WATCOM) + add_compile_options(/we) + else() + add_compile_options(-Werror) + if (APPLE) + # _dyld_bind_fully_image_containing_address is deprecated in OS X 10.5+ + add_compile_options(-Wno-deprecated-declarations) + endif() + endif() +endif(enable_werror) + +if (enable_single_obj_compilation OR GC_BUILD_SHARED_LIBS) + set(SRC extra/gc.c) # override SRC + if (CMAKE_USE_PTHREADS_INIT) + add_definitions("-DGC_PTHREAD_START_STANDALONE") + set(SRC ${SRC} pthread_start.c) + endif(CMAKE_USE_PTHREADS_INIT) +elseif (BORLAND) + # Suppress "GC_push_contents_hdr() is declared but never used" warning. + add_compile_options(/w-use) +endif() + +# Add implementation of backtrace() and backtrace_symbols(). +if (MSVC) + set(SRC ${SRC} extra/msvc_dbg.c) +endif() + +# Instruct check_c_source_compiles and similar CMake checks not to ignore +# compiler warnings (like "implicit declaration of function"). +if (NOT BORLAND AND NOT MSVC AND NOT WATCOM) + check_c_compiler_flag(-Werror HAVE_FLAG_WERROR) + if (HAVE_FLAG_WERROR) + SET(CMAKE_REQUIRED_FLAGS "-Werror") + endif(HAVE_FLAG_WERROR) +endif() + +if (GC_BUILD_SHARED_LIBS) + add_definitions("-DGC_DLL") + # Pass -fvisibility=hidden option if supported. + check_c_compiler_flag(-fvisibility=hidden HAVE_FLAG_F_VISIBILITY_HIDDEN) + if (HAVE_FLAG_F_VISIBILITY_HIDDEN) + add_definitions("-DGC_VISIBILITY_HIDDEN_SET") + add_compile_options(-fvisibility=hidden) + else() + add_definitions("-DGC_NO_VISIBILITY") + endif() + check_c_compiler_flag(-Wl,--no-undefined HAVE_FLAG_WL_NO_UNDEFINED) +else() + add_definitions("-DGC_NOT_DLL") + if (WIN32) + # Do not require the clients to link with "user32" system library. + add_definitions("-DDONT_USE_USER32_DLL") + endif(WIN32) +endif() + +# Disable strict aliasing optimizations. +# It could re-enabled back by a flag passed in CFLAGS_EXTRA. +check_c_compiler_flag(-fno-strict-aliasing HAVE_FLAG_F_NO_STRICT_ALIASING) +if (HAVE_FLAG_F_NO_STRICT_ALIASING) + add_compile_options(-fno-strict-aliasing) +endif() + +# Extra user-defined flags to pass both to C and C++ compilers. +if (DEFINED CFLAGS_EXTRA) + add_compile_options(${CFLAGS_EXTRA}) +endif() + +# Check whether execinfo.h header file is present. +check_include_file(execinfo.h HAVE_EXECINFO_H) +if (NOT HAVE_EXECINFO_H) + add_definitions("-DGC_MISSING_EXECINFO_H") +endif() + +# Check for getcontext (uClibc can be configured without it, for example). +check_function_exists(getcontext HAVE_GETCONTEXT) +if (NOT HAVE_GETCONTEXT) + add_definitions("-DNO_GETCONTEXT") +endif() + +# Check whether dl_iterate_phdr exists (as a strong symbol). +check_function_exists(dl_iterate_phdr HAVE_DL_ITERATE_PHDR) +if (HAVE_DL_ITERATE_PHDR) + add_definitions("-DHAVE_DL_ITERATE_PHDR") +endif() + +check_symbol_exists(sigsetjmp setjmp.h HAVE_SIGSETJMP) +if (NOT HAVE_SIGSETJMP) + add_definitions("-DGC_NO_SIGSETJMP") +endif() + +# pthread_setname_np, if available, may have 1, 2 or 3 arguments. +if (CMAKE_USE_PTHREADS_INIT) + check_c_source_compiles(" +#include \n +int main(void) { (void)pthread_setname_np(\"thread-name\"); return 0; }" + HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID) + if (HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID) + # Define to use 'pthread_setname_np(const char*)' function. + add_definitions("-DHAVE_PTHREAD_SETNAME_NP_WITHOUT_TID") + else() + check_c_source_compiles(" +#include \n +int main(void) {\n + (void)pthread_setname_np(pthread_self(), \"thread-name-%u\", 0); return 0; }" + HAVE_PTHREAD_SETNAME_NP_WITH_TID_AND_ARG) + if (HAVE_PTHREAD_SETNAME_NP_WITH_TID_AND_ARG) + # Define to use 'pthread_setname_np(pthread_t, const char*, void *)'. + add_definitions("-DHAVE_PTHREAD_SETNAME_NP_WITH_TID_AND_ARG") + else() + check_c_source_compiles(" +#if defined(__linux__) || defined(__GLIBC__) || defined(__GNU__) || defined(__CYGWIN__)\n +#define _GNU_SOURCE 1\n +#endif\n +#include \n +int main(void) {\n + (void)pthread_setname_np(pthread_self(), \"thread-name\"); return 0; }" + HAVE_PTHREAD_SETNAME_NP_WITH_TID) + if (HAVE_PTHREAD_SETNAME_NP_WITH_TID) + # Define to use 'pthread_setname_np(pthread_t, const char*)' function. + add_definitions("-DHAVE_PTHREAD_SETNAME_NP_WITH_TID") + endif() + endif(HAVE_PTHREAD_SETNAME_NP_WITH_TID_AND_ARG) + endif (HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID) +endif() + +# Check for dladdr (used for debugging). +check_c_source_compiles(" +#define _GNU_SOURCE 1\n +#include \n +int main(void) { Dl_info info; (void)dladdr(\"\", &info); return 0; }" + HAVE_DLADDR) +if (HAVE_DLADDR) + # Define to use 'dladdr' function. + add_definitions("-DHAVE_DLADDR") +endif() + +add_library(omcgc ${GC_LIBRARY_BUILD_TYPE} ${SRC}) +if (enable_threads) + target_link_libraries(omcgc PRIVATE ${THREADDLLIBS}) +endif() + +if (enable_cplusplus) + add_library(omcgccpp ${GC_LIBRARY_BUILD_TYPE} gc_badalc.cc gc_cpp.cc) + target_link_libraries(omcgccpp PRIVATE omcgc) + if (enable_throw_bad_alloc_library) + # The same as gccpp but contains only gc_badalc. + add_library(omcgctba ${GC_LIBRARY_BUILD_TYPE} gc_badalc.cc) + target_link_libraries(omcgctba PRIVATE omcgc) + endif(enable_throw_bad_alloc_library) +endif() + +if (build_cord) + set(CORD_SRC cord/cordbscs.c cord/cordprnt.c cord/cordxtra.c) + add_library(omccord ${GC_LIBRARY_BUILD_TYPE} ${CORD_SRC}) + target_link_libraries(omccord PRIVATE omcgc) + install(TARGETS omccord EXPORT cordExports) +endif() + +if (GC_BUILD_SHARED_LIBS AND HAVE_FLAG_WL_NO_UNDEFINED) + # Declare that the libraries do not refer to external symbols. + # TODO: use add_link_options() when cmake_minimum_required > 3.13 + target_link_libraries(omcgc PRIVATE -Wl,--no-undefined) + if (enable_cplusplus) + target_link_libraries(omcgccpp PRIVATE -Wl,--no-undefined) + if (enable_throw_bad_alloc_library) + target_link_libraries(omcgctba PRIVATE -Wl,--no-undefined) + endif(enable_throw_bad_alloc_library) + endif(enable_cplusplus) + if (build_cord) + target_link_libraries(omccord PRIVATE -Wl,--no-undefined) + endif(build_cord) +endif() + +install(TARGETS omcgc EXPORT gcExports) + +if (enable_cplusplus) + install(TARGETS omcgccpp EXPORT gccppExports) +endif() + +if (install_headers) + install(FILES include/gc.h + include/gc_backptr.h + include/gc_config_macros.h + include/gc_gcj.h + include/gc_inline.h + include/gc_mark.h + include/gc_pthread_redirects.h + include/gc_tiny_fl.h + include/gc_typed.h + include/gc_version.h + include/javaxfc.h + include/leak_detector.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gc) + install(FILES include/extra/gc.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + if (enable_cplusplus) + install(FILES include/gc_allocator.h + include/gc_cpp.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gc) + install(FILES include/extra/gc_cpp.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + endif() + if (enable_disclaim) + install(FILES include/gc_disclaim.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gc) + endif() + if (build_cord) + install(FILES include/cord.h + include/cord_pos.h + include/ec.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gc) + endif() +endif(install_headers) + +if (build_tests) + if (build_cord) + add_executable(cordtest cord/tests/cordtest.c) + target_link_libraries(cordtest PRIVATE omccord omcgc) + add_test(NAME cordtest COMMAND cordtest) + + if (WIN32 AND NOT CYGWIN) + add_executable(de cord/tests/de.c cord/tests/de_win.c + cord/tests/de_win.rc) + set_target_properties(de PROPERTIES WIN32_EXECUTABLE TRUE) + target_link_libraries(de PRIVATE omccord omcgc omcgdi32) + endif() + endif(build_cord) + + # Compile some tests as C++ to test extern "C" in header files. + if (enable_cplusplus) + set_source_files_properties(tests/leak_test.c tests/test.c + PROPERTIES LANGUAGE CXX) + # To avoid "treating 'c' input as 'c++' when in C++ mode" Clang warning. + if (NOT (BORLAND OR MSVC OR WATCOM)) + add_compile_options(-x c++) + endif() + endif(enable_cplusplus) + + add_executable(gctest WIN32 tests/test.c) + target_link_libraries(gctest PRIVATE omcgc ${THREADDLLIBS}) + add_test(NAME gctest COMMAND gctest) + if (WATCOM) + # Suppress "conditional expression in if statement is always true/false" + # and "unreachable code" warnings in GC_MALLOC_[ATOMIC_]WORDS. + target_compile_options(gctest PRIVATE + /wcd=13 /wcd=201 /wcd=367 /wcd=368 /wcd=726) + endif() + + add_executable(hugetest tests/huge_test.c) + target_link_libraries(hugetest PRIVATE omcgc) + add_test(NAME hugetest COMMAND hugetest) + + add_executable(leaktest tests/leak_test.c) + target_link_libraries(leaktest PRIVATE omcgc) + add_test(NAME leaktest COMMAND leaktest) + + add_executable(middletest tests/middle.c) + target_link_libraries(middletest PRIVATE omcgc) + add_test(NAME middletest COMMAND middletest) + + add_executable(realloc_test tests/realloc_test.c) + target_link_libraries(realloc_test PRIVATE omcgc) + add_test(NAME realloc_test COMMAND realloc_test) + + add_executable(smashtest tests/smash_test.c) + target_link_libraries(smashtest PRIVATE omcgc) + add_test(NAME smashtest COMMAND smashtest) + + if (NOT (GC_BUILD_SHARED_LIBS AND WIN32)) + add_library(staticrootslib_test ${GC_LIBRARY_BUILD_TYPE} tests/staticrootslib.c) + target_link_libraries(staticrootslib_test PRIVATE omcgc) + add_library(staticrootslib2_test ${GC_LIBRARY_BUILD_TYPE} tests/staticrootslib.c) + target_compile_options(staticrootslib2_test PRIVATE "-DSTATICROOTSLIB2") + target_link_libraries(staticrootslib2_test PRIVATE omcgc) + add_executable(staticrootstest tests/staticrootstest.c) + target_compile_options(staticrootstest PRIVATE "-DSTATICROOTSLIB2") + target_link_libraries(staticrootstest PRIVATE + omcgc staticrootslib_test staticrootslib2_test) + add_test(NAME staticrootstest COMMAND staticrootstest) + endif() + + if (enable_gc_debug) + add_executable(tracetest tests/trace_test.c) + target_link_libraries(tracetest PRIVATE omcgc) + add_test(NAME tracetest COMMAND tracetest) + endif() + + if (enable_threads) + add_executable(test_atomic_ops tests/test_atomic_ops.c) + target_link_libraries(test_atomic_ops PRIVATE omcgc) + add_test(NAME test_atomic_ops COMMAND test_atomic_ops) + + add_executable(threadleaktest tests/thread_leak_test.c) + target_link_libraries(threadleaktest PRIVATE omcgc ${THREADDLLIBS}) + add_test(NAME threadleaktest COMMAND threadleaktest) + + if (NOT WIN32) + add_executable(threadkey_test tests/threadkey_test.c) + target_link_libraries(threadkey_test PRIVATE omcgc ${THREADDLLIBS}) + add_test(NAME threadkey_test COMMAND threadkey_test) + endif() + + add_executable(subthreadcreate_test tests/subthread_create.c) + target_link_libraries(subthreadcreate_test PRIVATE omcgc ${THREADDLLIBS}) + add_test(NAME subthreadcreate_test COMMAND subthreadcreate_test) + + add_executable(initsecondarythread_test tests/initsecondarythread.c) + target_link_libraries(initsecondarythread_test PRIVATE omcgc ${THREADDLLIBS}) + add_test(NAME initsecondarythread_test COMMAND initsecondarythread_test) + endif(enable_threads) + + if (enable_cplusplus) + add_executable(test_cpp WIN32 tests/test_cpp.cc) + target_link_libraries(test_cpp PRIVATE omcgc gccpp) + add_test(NAME test_cpp COMMAND test_cpp) + endif() + + if (enable_disclaim) + add_executable(disclaim_bench tests/disclaim_bench.c) + target_link_libraries(disclaim_bench PRIVATE omcgc) + add_test(NAME disclaim_bench COMMAND disclaim_bench) + + add_executable(disclaim_test tests/disclaim_test.c) + target_link_libraries(disclaim_test PRIVATE omcgc ${THREADDLLIBS}) + add_test(NAME disclaim_test COMMAND disclaim_test) + + add_executable(disclaim_weakmap_test tests/disclaim_weakmap_test.c) + target_link_libraries(disclaim_weakmap_test PRIVATE omcgc ${THREADDLLIBS}) + add_test(NAME disclaim_weakmap_test COMMAND disclaim_weakmap_test) + endif() +endif(build_tests) diff --git a/gc/ChangeLog b/gc/ChangeLog index 3dcd4b320..367662783 100644 --- a/gc/ChangeLog +++ b/gc/ChangeLog @@ -1,205 +1,22 @@ -== [8.0.6] 2021-09-28 == - -* Add loop to handle abort error like in suspend logic on Darwin -* Add support of OpenBSD/aarch64 -* Add threading libraries to bdw-gc.pc -* Allocate start_info struct on the stack in GC_pthread_create -* Allow GC_PAUSE_TIME_TARGET environment variable values smaller than 5 ms -* Avoid compiler warning about unused d in GC_CALLOC/MALLOC_EXPLICITLY_TYPED -* Avoid gcc stringop-overflow warning for intended overflow in smashtest -* Check _MSVC_LANG macro in addition to __cplusplus (MS VC) -* Compile C++ code with exception handling enabled in NT_MAKEFILE -* Define OS_TYPE and DATAEND for UWP targets -* Disable mprotect-based incremental GC if /proc roots are used (Linux) -* Do not report 'Incremental GC incompatible' warning more than once -* Do not use Manual VDB mode if C malloc is redirected -* Do not use iOS private symbols -* Eliminate 'GC_non_gc_bytes is deprecated' warning in new_gc_alloc.h -* Eliminate 'GC_old_bus_handler defined but not used' compiler warning -* Eliminate 'cast between incompatible func types' warnings for FARPROC vars -* Eliminate 'comparing signed and unsigned values' BCC warning in cordtest -* Eliminate 'gc_pthread_redirects.h should contain header guard' code defect -* Eliminate 'implicit declaration of sbrk' gcc warning if -std=c11 on Cygwin -* Eliminate 'possible loss of data' BCC and MS VC warnings -* Eliminate 'static GC_sysinfo definition has incomplete type' Clang warning -* Eliminate 'unused function' compiler warnings (GC_add_map_entry, GC_lock) -* Eliminate 'while clause does not guard' GCC warning in GC_parse_map_entry -* Enable sbrk-to-mmap fallback on major supported Unix-like platforms -* Ensure process is running on one CPU core if AO ops are emulated with locks -* Explicitly zero-initialize trace_buf (fix trace_buf initialization) -* Fix 'ACCESS_VIOLATION in marker' GC warning on Win32 async thread start -* Fix 'GC_generic_malloc must be available' GCC error in new_gc_alloc.h -* Fix 'ISO C++17 does not allow dynamic exception spec' clang-8 error -* Fix 'Wrong __data_start/_end pair' if -Bsymbolic-functions used (Linux) -* Fix 'condition pred!=NULL is always true' compiler warning -* Fix 'external linkage required for var because of dllimport' error on MinGW -* Fix 'ulong undefined' compilation error on AIX -* Fix 'undefined reference to __data_start' linker error on RISC-V -* Fix 'use of undeclared BUS_PAGE_FAULT' compilation error on FreeBSD 12 -* Fix 'write to GC log failed' error (Cygwin) -* Fix 'wrong finalization data' gctest failure on Windows -* Fix CMake build on macOS Catalina -* Fix GC_OPENBSD_THREADS definition (OpenBSD/hppa) -* Fix GC_proc_fd value in child process at fork (Solaris) -* Fix GC_with_callee_saves_pushed for Android NDK r23 (clang-12) -* Fix MPROTECT_VDB definition for single-threaded GC builds -* Fix OS_TYPE and USE_MMAP_ANON definitions for Cygwin/x64 -* Fix STACKBOTTOM on 32-bit HP/UX 11.11 -* Fix abort in GC_printf when gctest is built as WinMain executable (Cygwin) -* Fix assertion violation in register_dynlib_callback on Android -* Fix build for OS X (CMake) -* Fix building of shared library with C++ support on MinGW -* Fix compiling by Makefile.direct on OpenBSD/UltraSparc -* Fix configure message about 'AIX gcc optimization fix' -* Fix cordtest build in SMakefile.amiga -* Fix data race regarding *rlh value in generic_malloc_many -* Fix first_thread stack_base initialization if custom GC_stackbottom (Win32) -* Fix gc_allocator.h compilation by Clang -* Fix gc_cflags variable name in configure (HP/UX) -* Fix handling of areas smaller than page size in GC_scratch_recycle -* Fix incorrect markup formatting in documentation -* Fix misaligned tlfs passed to AO_load on m68k -* Fix missing GC_quiet declaration in pcr_interface.c -* Fix missing gc_dlopen.c and specific.c in CMake script -* Fix missing scratch_last_end_ptr update (Irix) -* Fix mmap() failures on AIX, HP/UX and Haiku -* Fix overflow of scratch_free_ptr value -* Fix page_was_[ever_]dirty() for static roots (Solaris) -* Fix printf format specifier in simple_example.md -* Fix save_callers for multi-threaded case if built-in backtrace unavailable -* Fix subexpression widening in memhash() of disclaim_weakmap_test -* Fix test_cpp failure caused by arbitrary link order (Win32) -* Fix test_cpp failure when gc_cpp resides in a dll (Borland, Watcom) -* Fix various typos mostly in documentation files -* Fix word size, data start and alignment for OpenBSD/mips64(el) -* Include when using alloca on AIX -* Limit number of unmapped regions (Linux and DragonFly) -* New macro to avoid system-wide new/delete inlining in gc_cpp.h (Win32) -* Prevent GetThreadContext failure (Windows) -* Prevent WARN of incompatible incremental GC if default or manual VDB -* Reduce a time period between GetExitCodeThread and SuspendThread (Win32) -* Refactoring of WoW64 workaround (Win32) -* Refine GC_INIT documentation about its multiple invocation -* Refine GC_parallel documentation in gc.h -* Refine do_blocking() documentation in gc.h -* Remove a misleading comment about Solaris in gc.h -* Remove cord .h files from list of non-installed headers (Automake) -* Remove dead part of condition to define NEED_FIND_LIMIT in gc_priv.h -* Remove gcmt-lib generation by CMake -* Support MSYS builds by CMake and configure -* Update documentation about the incremental collector support -* Use HEURISTIC2 on OpenBSD when single-threaded -* Use pstat_getprocvm to determine main stack bottom on HP-UX -* Workaround 'expression is only useful for its side effects' WCC warning -* Workaround clang-3.8/s390x bug when processing __builtin_frame_address -* Workaround fread fail after enable_incremental if malloc redirected (Linux) - - -== [8.0.4] 2019-03-02 == - -* Avoid a full GC when growing finalizer tables if in incremental mode -* Avoid potential race in hb_sz access between realloc and reclaim_block -* Avoid test.o rebuild on tests folder timestamp change (Makefile.direct) -* Avoid unexpected heap growth in gctest caused by GC_disable -* Ensure result of every variant of MS_TIME_DIFF has unsigned long type -* Fix 'duplicate symbol' error for tests using multiple static libs (OS X) -* Fix 'undefined reference to __data_start' linker error (Android/aarch64) -* Fix 'unexpected mark stack overflow' abort in push_all_stack -* Fix 'wrong __data_start/_end pair' error on Android -* Fix BSD_TIME variant of MS_TIME_DIFF for the case of a.tv_usec < b.tv_usec -* Fix GetThreadContext stale register values use if WoW64 (Win32) -* Fix invalid initializer of CLOCK_TYPE variables if BSD_TIME -* Fix thread_info() count argument value (OS X) -* Support de_win.c compilation by Makefile.direct (cord/de) - - -== [8.0.2] 2018-12-23 == - -* Abort with appropriate message if executable pages cannot be allocated -* Add initial testing of GC_enable/disable, MALLOC[_ATOMIC]_IGNORE_OFF_PAGE -* Add paths to filenames mentioned in the copyright section in README -* Add test using disclaim notifiers to implement a weak map -* Adjust #error messages format -* Allow to force executable pages allocation in gctest -* Avoid potential 'macro redefinition' errors for config.h macros +== [8.0.2] (not released yet) == + * Call real pthread_sigmask instead of its wrapper in start_mark_threads -* Check result of pthread_mutex_unlock in specific.c * Default to a single-threaded build for Nintendo, Orbis, Sony PSP targets -* Default to non-executable memory allocation across all make scripts -* Define GC_ATOMIC_UNCOLLECTABLE and JAVA_FINALIZATION in all make scripts -* Do not prevent GC from looking at environment variables (BCC_MAKEFILE) -* Do not use 'ifndef AO_CLEAR' in mark, pthread_support and gctest -* Do not use spin locks if AO test-and-set is emulated (pthreads) -* Document HANDLE_FORK macro optional usage in Makefile.direct -* Document assertion in the setters that used to return old value -* Eliminate 'assigned value never used' compiler warning in test_cpp WinMain -* Eliminate 'casting signed to bigger unsigned int' CSA warning * Eliminate 'different const qualifiers' MS VC warnings in cordbscs -* Eliminate 'function is never used' cppcheck warning for calloc/realloc -* Eliminate 'non-virtual destructor for class with inheritors' CSA warning -* Eliminate 'pointer targets differ in signedness' compiler warning (Win32) -* Eliminate 'struct member is never used' cppcheck warnings in os_dep -* Eliminate 'uninitialized var' cppcheck false positive in mach_dep, os_dep -* Eliminate 'unreferenced formal parameter' compiler warning in msvc_dbg -* Eliminate redundant check in backwards_height * Fix 'USE_MUNMAP macro redefinition' error for NaCl -* Fix 'collecting from unknown thread' abort in leak-finding mode for Win32 -* Fix 'mprotect remapping failed' abort on NetBSD with PaX enabled -* Fix 'too wide non-owner permissions are set for resource' code defect -* Fix GC_VSNPRINTF in cordprnt for DJGPP and MS VC for WinCE -* Fix GC_register_disclaim_proc for leak-finding mode -* Fix a deadlock in write_fault_handler if AO_or is emulated * Fix comment typo in CMakeLists.txt * Fix concurrent bitmap update in GC_dirty -* Fix deadlocks in write and suspend handlers if AO test-and-set is emulated -* Fix executable memory allocation in GC_unix_get_mem -* Fix hbp overflow in GC_install_counts -* Fix linkage with a system libatomic_ops shared library -* Fix lock assertion violation in get_index if GC_ALWAYS_MULTITHREADED +* Fix GC_VSNPRINTF in cordprnt for DJGPP and MS VC for WinCE * Fix marking of finalizer closure object -* Fix marks and hb_n_marks consistency when disclaim returns true * Fix memory allocation on GCF (Linux/x64) * Fix missing curses.h in cord/de when compiling manually (MS VC, MinGW) -* Fix test_cpp assertion violation in find-leak mode -* Fix tests linkage with internal atomic_ops.o * Fix unneeded end_stubborn_change/ptr_store_and_dirty in disclaim_test -* Guard against potential buffer overflow in CORD_next and CORD_pos_fetch -* New macro to suppress printing of leaked objects -* Pass -Wall -Wextra -Wpedantic to g++ if supported (configure) -* Prefix internal durango_get_mem symbol with 'GC_' -* Prevent double inclusion of javaxfc.h and private/specific.h -* Print relevant message in tests not appropriate for leak detection mode -* Reduce scope of local variables in GC_remove_all_threads_but_me -* Refine HIDE_POINTER documentation for the case of the leak-finding mode * Refine documentation in gc_disclaim.h * Remove extra USE_MMAP definition for Interix -* Remove redundant header double-inclusion checks in the private headers -* Remove strlen calls with a constant string argument in msvc_dbg * Specify register_disclaim_proc and finalized_malloc argument as non-null -* Support UWP/arm64 target * Test marking of finalizer closure object in disclaim_test -* Turn off leak detection mode explicitly in cord/de -* Turn off parallel marker, thread-local allocation if used AO ops emulated -* Turn on gcj functionality in BCC, DMC, NT, OS/2, WCC makefiles -* Turn on memory unmapping in BCC/DMC/NT/WCC makefiles and Makefile.direct -* Update NO_EXECUTE_PERMISSION documentation -* Update documentation about arm64 ABI in gcconfig.h * Use AO_or in async_set_pht_entry_from_index if available -* Use GC_WORD_MAX macro across all C source files -* Use macro to operate on a flag residing in GC_stop_count -* Use standalone private macro to guard against ptr_t redefinition -* Workaround '#error' cppcheck messages in backgraph and private headers -* Workaround 'AST broken' syntax error reported by cppcheck in GC_mark_some -* Workaround 'GC_dump function is never used' cppcheck warning -* Workaround 'local address assignment to a global variable' CSA warning -* Workaround 'local variable end shadows outer symbol' cppcheck warnings -* Workaround 'local variable obj_displ shadows outer symbol' cppcheck warning -* Workaround 'nonlocal var will use ptr to local var' cppcheck false positive -* Workaround 'pointer addition with NULL pointer' cppcheck error in msvc_dbg -* Workaround 'potential non-terminated string' false positive in cordbscs -* Workaround 'value of _MAX_PATH is unknown' cppcheck warning -* Workaround cppcheck warnings regarding CLOCKS_PER_SEC, REDIRECT_REALLOC == [8.0.0] 2018-09-05 == @@ -415,110 +232,21 @@ * Workaround Thread Sanitizer (TSan) false positive warnings -== [7.6.14] 2021-09-28 == - -* Add loop to handle abort error like in suspend logic on Darwin -* Add support of OpenBSD/aarch64 -* Add threading libraries to bdw-gc.pc -* Disable mprotect-based incremental GC if /proc roots are used (Linux) -* Do not use iOS private symbols -* Eliminate 'GC_old_bus_handler defined but not used' compiler warning -* Eliminate 'comparing signed and unsigned values' BCC warning in cordtest -* Eliminate 'possible loss of data' BCC and MS VC warnings -* Eliminate 'static GC_sysinfo definition has incomplete type' Clang warning -* Eliminate 'unused function GC_add_map_entry' compiler warning -* Eliminate 'while clause does not guard' GCC warning in GC_parse_map_entry -* Explicitly zero-initialize trace_buf (fix trace_buf initialization) -* Fix 'ACCESS_VIOLATION in marker' GC warning on Win32 async thread start -* Fix 'GC_generic_malloc must be available' GCC error in new_gc_alloc.h -* Fix 'ulong undefined' compilation error on AIX -* Fix 'undefined reference to __data_start' linker error on RISC-V -* Fix 'write to GC log failed' error -* Fix GC_proc_fd value in child process at fork (Solaris) -* Fix MPROTECT_VDB definition for single-threaded GC builds -* Fix OS_TYPE and USE_MMAP_ANON definitions for Cygwin/x64 -* Fix STACKBOTTOM on 32-bit HP/UX 11.11 -* Fix abort in GC_printf when gctest is built as WinMain executable (Cygwin) -* Fix assertion violation in register_dynlib_callback on Android -* Fix compiling by Makefile.direct on OpenBSD/UltraSparc -* Fix configure message about 'AIX gcc optimization fix' -* Fix cordtest build in SMakefile.amiga -* Fix data race regarding *rlh value in generic_malloc_many -* Fix first_thread stack_base initialization if custom GC_stackbottom (Win32) -* Fix gc_allocator.h compilation by Clang -* Fix gc_cflags variable name in configure (HP/UX) -* Fix handling of areas smaller than page size in GC_scratch_recycle -* Fix incorrect define GC_OPENBSD_THREADS on sparc64 -* Fix misaligned tlfs passed to AO_load on m68k -* Fix missing GC_quiet declaration in pcr_interface.c -* Fix missing gc_dlopen.c in CMake script -* Fix missing scratch_last_end_ptr update (Irix) -* Fix overflow of scratch_free_ptr value -* Fix page_was_[ever_]dirty() for static roots (Solaris) -* Fix printf format specifier in simple_example.html -* Fix save_callers for multi-threaded case if built-in backtrace unavailable -* Fix test_cpp failure caused by arbitrary link order (Win32) -* Fix test_cpp failure when gc_cpp resides in a dll (Borland, Watcom) -* Fix various typos mostly in documentation files -* Fix word size, data start and alignment for OpenBSD/mips64(el) -* Prevent GetThreadContext failure (Windows) -* Prevent WARN of incompatible incremental GC if default or manual VDB -* Reduce a time period between GetExitCodeThread and SuspendThread (Win32) -* Refactoring of WoW64 workaround (Win32) -* Remove a misleading comment about Solaris in gc.h -* Workaround 'expression is only useful for its side effects' WCC warning -* Workaround fread fail after enable_incremental if malloc redirected (Linux) - - -== [7.6.12] 2019-03-01 == - -* Eliminate 'assigned value never used' compiler warning in test_cpp WinMain -* Fix 'mprotect remapping failed' abort on NetBSD with PaX enabled -* Fix 'undefined reference to __data_start' linker error (Android/aarch64) -* Fix 'unexpected mark stack overflow' abort in push_all_stack -* Fix 'wrong __data_start/_end pair' error on Android -* Fix BSD_TIME variant of MS_TIME_DIFF for the case of a.tv_usec < b.tv_usec -* Fix GetThreadContext stale register values use if WoW64 (Win32) -* Fix executable memory allocation in GC_unix_get_mem -* Fix invalid initializer of CLOCK_TYPE variables if BSD_TIME -* Fix thread_info() count argument value (OS X) -* Update NO_EXECUTE_PERMISSION documentation - - -== [7.6.10] 2018-12-13 == - -* Add paths to filenames mentioned in the copyright section in README +== [7.6.10] (not released yet) == + * Call real pthread_sigmask instead of its wrapper in start_mark_threads -* Eliminate 'casting signed to bigger unsigned int' CSA warning -* Eliminate 'non-virtual destructor for class with inheritors' CSA warning -* Fix 'collecting from unknown thread' abort in leak-finding mode for Win32 -* Fix 'too wide non-owner permissions are set for resource' code defect * Fix 'undefined reference to GC_incremental' linker error in pthread_start -* Fix GC_VSNPRINTF in cordprnt for DJGPP and MS VC for WinCE -* Fix GC_register_disclaim_proc for leak-finding mode -* Fix a deadlock in write_fault_handler if AO_or is emulated * Fix comment typos in CMakeLists.txt, backgraph.c, de.c, gcconfig.h * Fix concurrent bitmap update in GC_dirty * Fix delete operator redirection if gc_cpp is built as .dll (Cygwin, MinGW) -* Fix hbp overflow in GC_install_counts -* Fix linkage with a system libatomic_ops shared library -* Fix lock assertion violation in get_index if GC_ALWAYS_MULTITHREADED +* Fix GC_VSNPRINTF in cordprnt for DJGPP and MS VC for WinCE * Fix marking of finalizer closure object -* Fix marks and hb_n_marks consistency when disclaim returns true * Fix memory allocation on GCF (Linux/x64) * Fix missing curses.h in cord/de when compiling manually (MS VC, MinGW) * Fix start_world not resuming all threads on Darwin -* Fix test_cpp assertion violation in find-leak mode -* Fix tests linkage with internal atomic_ops.o * Fix unneeded end_stubborn_change in disclaim_test -* Guard against potential buffer overflow in CORD_next and CORD_pos_fetch -* New macro to suppress printing of leaked objects -* Prevent double inclusion of javaxfc.h and private/specific.h -* Reduce scope of local variables in GC_remove_all_threads_but_me -* Refine HIDE_POINTER documentation for the case of the leak-finding mode * Refine documentation in gc_disclaim.h * Test marking of finalizer closure object in disclaim_test -* Update documentation about arm64 ABI in gcconfig.h * Use AO_or in async_set_pht_entry_from_index if available * Use include gc.h with the angle brackets in the man page synopsis @@ -956,40 +684,12 @@ Also, includes 7.4.6 changes Also, includes 7.4.4 changes -== [7.4.20] 2021-09-28 == - -* Do not hold GC_fault_handler_lock when in Sleep (Windows) -* Eliminate 'static GC_sysinfo definition has incomplete type' Clang warning -* Eliminate 'unused function GC_add_map_entry' compiler warning -* Eliminate 'while clause does not guard' GCC warning in GC_parse_map_entry -* Fix OS_TYPE and USE_MMAP_ANON definitions for Cygwin/x64 -* Fix abort in GC_printf when gctest is built as WinMain executable (Cygwin) -* Fix configure message about 'AIX gcc optimization fix' -* Fix cordtest build in SMakefile.amiga -* Prevent GetThreadContext failure (Windows) -* Refactoring of WoW64 workaround (Win32) - -Also, includes 7.2o changes +== [7.4.16] (not released yet) == - -== [7.4.18] 2019-03-01 == - -* Fix 'wrong __data_start/_end pair' error on Android -* Fix thread_info() count argument value (OS X) - -Also, includes 7.2n changes - - -== [7.4.16] 2018-12-13 == - -* Fix 'collecting from unknown thread' abort in leak-finding mode for Win32 * Fix 'undefined reference to GC_incremental' linker error in pthread_start -* Fix GC_register_disclaim_proc for leak-finding mode * Fix concurrent bitmap update in GC_dirty * Fix marking of finalizer closure object -* Fix marks and hb_n_marks consistency when disclaim returns true * Fix missing curses.h in cord/de when compiling manually (MS VC, MinGW) -* Refine documentation in gc_disclaim.h Also, includes 7.2m changes @@ -1482,55 +1182,10 @@ Also, includes 7.2e, 7.2d, 7.2c, 7.2b changes Also, includes 7.2 changes -== [7.2o] 2021-09-28 == - -* Add loop to handle abort error like in suspend logic on Darwin -* Disable mprotect-based incremental GC if /proc roots are used (Linux) -* Explicitly zero-initialize trace_buf (fix trace_buf initialization) -* Fix 'ACCESS_VIOLATION in marker' GC warning on Win32 async thread start -* Fix 'GC_generic_malloc must be available' GCC error in new_gc_alloc.h -* Fix 'expected function body after declarator' clang error in gc_cpp.cc -* Fix 'write to GC log failed' error -* Fix GC_proc_fd value in child process at fork (Solaris) -* Fix assertion violation in register_dynlib_callback on Android -* Fix configure message about 'AIX gcc optimization fix' -* Fix data race regarding *rlh value in generic_malloc_many -* Fix first_thread stack_base initialization if custom GC_stackbottom (Win32) -* Fix fread failure after enable_incremental if malloc is redirected (Linux) -* Fix gc_cflags variable name in configure (HP/UX) -* Fix handling of areas smaller than page size on recycle scratch area -* Fix incorrect define GC_OPENBSD_THREADS on sparc64 -* Fix misaligned tlfs passed to AO_load on m68k -* Fix missing GC_quiet declaration in pcr_interface.c -* Fix missing gc_dlopen.c in CMake script -* Fix missing scratch_last_end_ptr update (Irix) -* Fix overflow of scratch_free_ptr value -* Fix page_was_[ever_]dirty() for static roots (Solaris) -* Fix printf format specifier in simple_example.html -* Fix save_callers for multi-threaded case if built-in backtrace unavailable -* Fix various typos in comments and documentation files -* Fix word size, data start and alignment for OpenBSD/mips64(el) -* Prevent WARN of incompatible incremental GC if default or manual VDB -* Reduce a time period between GetExitCodeThread and SuspendThread (Win32) -* Remove a misleading comment about Solaris in gc.h - - -== [7.2n] 2019-03-01 == - -* Fix 'mprotect remapping failed' abort on NetBSD with PaX enabled -* Fix 'unexpected mark stack overflow' abort in push_all_stack -* Fix BSD_TIME variant of MS_TIME_DIFF for the case of a.tv_usec < b.tv_usec -* Fix GetThreadContext stale register values use if WoW64 (Win32) -* Fix executable memory allocation in GC_unix_get_mem -* Fix invalid initializer of CLOCK_TYPE variables if BSD_TIME - - -== [7.2m] 2018-12-11 == +== [7.2m] (not released yet) == * Fix comment typos in CMakeLists.txt, backgraph.c, de.c, gcconfig.h -* Fix hbp overflow in GC_install_counts * Fix start_world not resuming all threads on Darwin -* Guard against potential buffer overflow in CORD_next and CORD_pos_fetch == [7.2l] 2018-08-10 == @@ -8215,7 +7870,7 @@ process. * Separate gc_conf_macros.h from gc.h. * Added generic GC_THREADS client-defined macro to set the appropriate GC_XXX_THREADS internal macro. (gc_config_macros.h.) -* Add debugging versions of _ignore_off_page allocation primitives. +* Add debugging versions of _ignore_off_page allocation primitves. * Moved declarations of GC_make_closure and GC_debug_invoke_finalizer from gc.h to gc_priv.h. * Reset GC_fail_count even if only a small allocation succeeds. diff --git a/gc/Makefile.am b/gc/Makefile.am index f22115c47..b2cf88274 100644 --- a/gc/Makefile.am +++ b/gc/Makefile.am @@ -14,8 +14,8 @@ # 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 = 5:4:4 -LIBGCCPP_VER_INFO = 5:1:4 +LIBGC_VER_INFO = 5:1:4 +LIBGCCPP_VER_INFO = 5:0:4 ## FIXME: `make distcheck' in this directory will not currently work. ## This is most likely to the explicit flags passed to submakes. @@ -54,21 +54,21 @@ pkgconfig_DATA = bdw-gc.pc # C Library # --------- -lib_LTLIBRARIES += libgc.la +lib_LTLIBRARIES += libomcgc.la if SINGLE_GC_OBJ -libgc_la_SOURCES = extra/gc.c +libomcgc_la_SOURCES = extra/gc.c if PTHREAD_START_STANDALONE AM_CPPFLAGS += -DGC_PTHREAD_START_STANDALONE -libgc_la_SOURCES += pthread_start.c +libomcgc_la_SOURCES += pthread_start.c endif else EXTRA_DIST += extra/gc.c -libgc_la_SOURCES = \ +libomcgc_la_SOURCES = \ allchblk.c alloc.c blacklst.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 \ @@ -78,33 +78,33 @@ libgc_la_SOURCES = \ # --------------------------------- if WIN32_THREADS -libgc_la_SOURCES += win32_threads.c +libomcgc_la_SOURCES += win32_threads.c else if PTHREADS # Not Cygwin or MinGW. -libgc_la_SOURCES += pthread_start.c pthread_support.c +libomcgc_la_SOURCES += pthread_start.c pthread_support.c if DARWIN_THREADS -libgc_la_SOURCES += darwin_stop_world.c +libomcgc_la_SOURCES += darwin_stop_world.c else -libgc_la_SOURCES += pthread_stop_world.c +libomcgc_la_SOURCES += pthread_stop_world.c endif endif endif if THREAD_LOCAL_ALLOC -libgc_la_SOURCES += thread_local_alloc.c +libomcgc_la_SOURCES += thread_local_alloc.c endif if MAKE_BACK_GRAPH -libgc_la_SOURCES += backgraph.c +libomcgc_la_SOURCES += backgraph.c endif if CHECKSUMS -libgc_la_SOURCES += checksums.c +libomcgc_la_SOURCES += checksums.c endif if ENABLE_DISCLAIM -libgc_la_SOURCES += fnlz_mlc.c +libomcgc_la_SOURCES += fnlz_mlc.c pkginclude_HEADERS += include/gc_disclaim.h endif @@ -112,21 +112,21 @@ endif endif if USE_INTERNAL_LIBATOMIC_OPS -nodist_libgc_la_SOURCES = libatomic_ops/src/atomic_ops.c +nodist_libomcgc_la_SOURCES = libatomic_ops/src/atomic_ops.c endif if NEED_ATOMIC_OPS_ASM -nodist_libgc_la_SOURCES = libatomic_ops/src/atomic_ops_sysdeps.S +nodist_libomcgc_la_SOURCES = libatomic_ops/src/atomic_ops_sysdeps.S endif # Include THREADDLLIBS here to ensure that the correct versions of # 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 $(LIBGC_VER_INFO) \ +libomcgc_la_LIBADD = @addobjs@ $(THREADDLLIBS) $(UNWINDLIBS) $(ATOMIC_OPS_LIBS) +libomcgc_la_DEPENDENCIES = @addobjs@ +libomcgc_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 \ +EXTRA_libomcgc_la_SOURCES = ia64_save_regs_in_stack.s sparc_mach_dep.S \ sparc_netbsd_mach_dep.s sparc_sunos4_mach_dep.s if CPLUSPLUS @@ -135,9 +135,9 @@ if CPLUSPLUS lib_LTLIBRARIES += libgccpp.la pkginclude_HEADERS += include/gc_allocator.h 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 $(LIBGCCPP_VER_INFO) -no-undefined +libomcgccpp_la_SOURCES = gc_cpp.cc +libomcgccpp_la_LIBADD = ./libgc.la +libomcgccpp_la_LDFLAGS = -version-info $(LIBGCCPP_VER_INFO) -no-undefined endif ## FIXME: If Visual C++ users use Makefile.am, this should go into @@ -157,7 +157,7 @@ CXXFLAGS += $(CFLAGS_EXTRA) ## FIXME: relies on internal code generated by automake. ## FIXME: ./configure --enable-dependency-tracking should be used -#all_objs = @addobjs@ $(libgc_la_OBJECTS) +#all_objs = @addobjs@ $(libomcgc_la_OBJECTS) #$(all_objs) : include/private/gcconfig.h include/private/gc_priv.h \ #include/private/gc_hdrs.h include/gc.h include/gc_gcj.h \ #include/gc_pthread_redirects.h include/gc_config_macros.h \ @@ -208,7 +208,7 @@ EXTRA_DIST += tools/if_mach.c tools/if_not_there.c tools/setjmp_t.c \ extra/symbian/global_end.cpp extra/symbian/global_start.cpp \ extra/symbian/init_global_static_roots.cpp extra/symbian.cpp \ extra/pcr_interface.c extra/real_malloc.c \ - build/s60v3/bld.inf build/s60v3/libgc.mmp \ + build/s60v3/bld.inf build/s60v3/libomcgc.mmp \ extra/Mac_files/datastart.c extra/Mac_files/dataend.c \ extra/Mac_files/MacOS_config.h \ include/private/msvc_dbg.h extra/msvc_dbg.c tools/callprocs.sh @@ -224,4 +224,4 @@ 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. +## libomcgc.a on HP/UX. There may be a better fix. diff --git a/gc/Makefile.direct b/gc/Makefile.direct index 30c70c3b8..9e4186b7c 100644 --- a/gc/Makefile.direct +++ b/gc/Makefile.direct @@ -46,9 +46,8 @@ AO_SRC_DIR=$(srcdir)/libatomic_ops CFLAGS_EXTRA= # We need CFLAGS_FOR_PIC because we might be building a shared library. CFLAGS= -O -I$(srcdir)/include -I$(AO_SRC_DIR)/src \ - -DALL_INTERIOR_POINTERS -DENABLE_DISCLAIM -DGC_ATOMIC_UNCOLLECTABLE \ - -DGC_GCJ_SUPPORT -DJAVA_FINALIZATION -DNO_EXECUTE_PERMISSION \ - -DUSE_MMAP -DUSE_MUNMAP $(CFLAGS_FOR_PIC) $(CFLAGS_EXTRA) + -DGC_ATOMIC_UNCOLLECTABLE -DNO_EXECUTE_PERMISSION -DALL_INTERIOR_POINTERS \ + -DENABLE_DISCLAIM $(CFLAGS_FOR_PIC) $(CFLAGS_EXTRA) # To build the collector with threads support, add to the above: # -DGC_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC @@ -56,9 +55,6 @@ CFLAGS= -O -I$(srcdir)/include -I$(AO_SRC_DIR)/src \ # To build the preload library that intercepts malloc, add: # -DGC_USE_DLOPEN_WRAP -DREDIRECT_MALLOC=GC_malloc -fpic -# To build the collector with fork() support by default, add to the above: -# -DHANDLE_FORK - # HOSTCC and HOSTCFLAGS are used to build executables that will be run as # part of the build process, i.e. on the build machine. These will usually # be the same as CC and CFLAGS, except in a cross-compilation environment. @@ -192,11 +188,13 @@ specific.o pthread_support.o thread_local_alloc.o win32_threads.o: \ dbg_mlc.o gcj_mlc.o: $(srcdir)/include/private/dbg_mlc.h -tests/test.o: $(srcdir)/tests/test.c - mkdir tests || cat /dev/null +tests/test.o: tests $(srcdir)/tests/test.c $(CC) $(CFLAGS) -c $(srcdir)/tests/test.c mv test.o tests/test.o +tests: + mkdir tests + base_lib gc.a: $(OBJS) dyn_load.o $(UTILS) rm -f dont_ar_1 ./if_mach SPARC SOLARIS touch dont_ar_1 @@ -226,7 +224,7 @@ test_cpp$(EXEEXT): $(srcdir)/tests/test_cpp.cc $(srcdir)/include/gc_cpp.h \ $(srcdir)/include/gc.h gc_cpp.o base_lib $(UTILS) rm -f test_cpp$(EXEEXT) ./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$(EXEEXT) || $(CXX) $(CXXFLAGS) -DGC_NOT_DLL -o test_cpp$(EXEEXT) $(srcdir)/tests/test_cpp.cc gc_cpp.o gc.a `./threadlibs` + ./if_not_there test_cpp$(EXEEXT) || $(CXX) $(CXXFLAGS) -o test_cpp$(EXEEXT) $(srcdir)/tests/test_cpp.cc gc_cpp.o gc.a `./threadlibs` check-cpp: test_cpp$(EXEEXT) ./test_cpp @@ -289,11 +287,12 @@ dyn_test: # 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) rm -f mach_dep.o ./if_mach SPARC SOLARIS $(CC) -c -o mach_dep2.o $(srcdir)/sparc_mach_dep.S - ./if_mach SPARC OPENBSD $(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 @@ -339,8 +338,7 @@ cord/cordtest$(EXEEXT): $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) \ ./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$(EXEEXT) || $(CC) $(CFLAGS) -o cord/cordtest$(EXEEXT) $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) gc.a `./threadlibs` -cord/de: $(srcdir)/cord/tests/de.c $(srcdir)/cord/tests/de_win.c \ - $(srcdir)/cord/tests/de_win.h cord/cordbscs.o cord/cordxtra.o base_lib \ +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 -lcurses -ltermlib -lucb `./threadlibs` @@ -351,7 +349,7 @@ cord/de: $(srcdir)/cord/tests/de.c $(srcdir)/cord/tests/de_win.c \ ./if_mach ALPHA LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs` ./if_mach IA64 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs` ./if_mach M68K AMIGA $(CC) $(CFLAGS) -UGC_AMIGA_MAKINGLIB -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses - ./if_not_there cord/de$(EXEEXT) || $(CC) $(CFLAGS) -o cord/de$(EXEEXT) $(srcdir)/cord/tests/de.c $(srcdir)/cord/tests/de_win.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) `./threadlibs` + ./if_not_there cord/de$(EXEEXT) || $(CC) $(CFLAGS) -o cord/de$(EXEEXT) $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) `./threadlibs` if_mach$(EXEEXT): $(srcdir)/tools/if_mach.c \ $(srcdir)/include/private/gcconfig.h diff --git a/gc/NT_MAKEFILE b/gc/NT_MAKEFILE index 02430ed83..479e64f3e 100644 --- a/gc/NT_MAKEFILE +++ b/gc/NT_MAKEFILE @@ -76,10 +76,6 @@ LINK_GC=$(link) $(ldebug) $(LINK_DLL_FLAGS) CFLAGS_SPECIFIC=$(CFLAGS_DEBUG) $(CFLAGS_GCDLL) $(CFLAGS_MT) -CFLAGS_DEFAULT=-DALL_INTERIOR_POINTERS -DENABLE_DISCLAIM -DGC_ATOMIC_UNCOLLECTABLE -DGC_GCJ_SUPPORT -DJAVA_FINALIZATION -DNO_EXECUTE_PERMISSION -DUSE_MUNMAP - -CXXFLAGS_SPECIFIC=/EHsc - # 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: @@ -91,17 +87,17 @@ CXXFLAGS_SPECIFIC=/EHsc 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 dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj gcj_mlc.obj mallocx.obj extra\msvc_dbg.obj thread_local_alloc.obj +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 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) $(CFLAGS_SPECIFIC) -Iinclude -I$(AO_INCLUDE_DIR) $(CFLAGS_DEFAULT) -DCORD_NOT_DLL -D_CRT_SECURE_NO_DEPRECATE $*.c /Fo$*.obj /wd4100 /wd4127 /wd4701 + $(cc) $(cdebug) $(cflags) $(CFLAGS_SPECIFIC) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DENABLE_DISCLAIM -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) $(CFLAGS_SPECIFIC) -Iinclude $(CFLAGS_DEFAULT) $(CXXFLAGS_SPECIFIC) -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 diff --git a/gc/OS2_MAKEFILE b/gc/OS2_MAKEFILE index da725aa1d..400fa73d6 100644 --- a/gc/OS2_MAKEFILE +++ b/gc/OS2_MAKEFILE @@ -5,12 +5,12 @@ # Significantly revised for GC version 4.4 by Mark Boulter (Jan 1994). -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 typd_mlc.obj ptr_chck.obj mallocx.obj gcj_mlc.obj +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 typd_mlc.obj ptr_chck.obj mallocx.obj CORDOBJS= cord\cordbscs.obj cord\cordxtra.obj cord\cordprnt.obj CC= icc -CFLAGS= /O /Q /DALL_INTERIOR_POINTERS /DENABLE_DISCLAIM /DGC_ATOMIC_UNCOLLECTABLE /DGC_GCJ_SUPPORT /DJAVA_FINALIZATION /DNO_EXECUTE_PERMISSION /DSMALL_CONFIG +CFLAGS= /O /Q /DSMALL_CONFIG /DALL_INTERIOR_POINTERS /DENABLE_DISCLAIM # Use /Ti instead of /O for debugging # Setjmp_test may yield overly optimistic results when compiled # without optimization. @@ -20,7 +20,7 @@ all: $(OBJS) gctest.exe cord\cordtest.exe $(OBJS) test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h ## ERASE THE LIB FIRST - if it is already there then this command will fail -## (make sure it is there or erase will fail!) +## (make sure its there or erase will fail!) gc.lib: $(OBJS) echo . > gc.lib erase gc.lib diff --git a/gc/README.QUICK b/gc/README.QUICK index 0648ab727..d96ff47f1 100644 --- a/gc/README.QUICK +++ b/gc/README.QUICK @@ -2,7 +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-2019 Ivan Maidanski +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. diff --git a/gc/README.md b/gc/README.md index c1fe8104a..916720337 100644 --- a/gc/README.md +++ b/gc/README.md @@ -1,6 +1,6 @@ # Boehm-Demers-Weiser Garbage Collector -This is version 8.0.6 of a conservative garbage +This is version 8.0.0 (experimental release) of a conservative garbage collector for C and C++. @@ -103,7 +103,7 @@ address space. There are a number of routines which modify the pointer recognition algorithm. `GC_register_displacement` allows certain interior pointers -to be recognized even if `ALL_INTERIOR_POINTERS` is not defined. +to be recognized even if `ALL_INTERIOR_POINTERS` is nor defined. `GC_malloc_ignore_off_page` allows some pointers into the middle of large objects to be disregarded, greatly reducing the probability of accidental retention of large objects. For most purposes it seems @@ -264,7 +264,7 @@ Note that usually only `GC_malloc` is necessary. `GC_clear_roots` and `GC_add_roots` calls may be required if the collector has to trace from nonstandard places (e.g. from dynamic library data areas on a machine on which the collector doesn't already understand them.) On -some machines, it may be desirable to set `GC_stackbottom` to a good +some machines, it may be desirable to set `GC_stacktop` to a good approximation of the stack base. (This enhances code portability on HP PA machines, since there is no good way for the collector to compute this value.) Client code may include "gc.h", which defines @@ -359,7 +359,7 @@ If only `GC_malloc` is intended to be used, it might be appropriate to define: #define malloc(n) GC_malloc(n) #define calloc(m,n) GC_malloc((m)*(n)) -For small pieces of VERY allocation intensive code, gc_inline.h includes +For small pieces of VERY allocation intensive code, gc_inl.h includes some allocation macros that may be used in place of `GC_malloc` and friends. @@ -458,7 +458,7 @@ extra arguments, where appropriate. If gc.h is included without `GC_DEBUG` defined, then all these macros will instead be defined to their nondebugging equivalents. (`GC_REGISTER_FINALIZER` is necessary, since pointers to objects with debugging information are really pointers to a displacement -of 16 bytes from the object beginning, and some translation is necessary +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 dbg_mlc.c file.) @@ -515,7 +515,7 @@ They will decrease with the number of processors if parallel marking is enabled. (On 2007 vintage machines, GC times may be on the order of 5 msecs -per MB of accessible memory that needs to be scanned and processed. +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. @@ -551,13 +551,13 @@ GitHub. * 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-2019 Ivan Maidanski + * Copyright (c) 2008-2018 Ivan Maidanski The files pthread_stop_world.c, pthread_support.c and some others are also * Copyright (c) 1998 by Fergus Henderson. All rights reserved. -The file include/gc.h is also +The file gc.h is also * Copyright (c) 2007 Free Software Foundation, Inc @@ -565,18 +565,14 @@ The files Makefile.am and configure.ac are * Copyright (c) 2001 by Red Hat Inc. All rights reserved. -The files extra/msvc_dbg.c and include/private/msvc_dbg.h are +The files msvc_dbg.c and msvc_dbg.h are * Copyright (c) 2004-2005 Andrei Polushin -The file tests/initsecondarythread.c is +The file initsecondarythread.c is * Copyright (c) 2011 Ludovic Courtes -The file tests/disclaim_weakmap_test.c is - - * Copyright (c) 2018 Petter A. Urkedal - Several files supporting GNU-style builds are copyrighted by the Free Software Foundation, and carry a different license from that given below. diff --git a/gc/SMakefile.amiga b/gc/SMakefile.amiga index ca75cf6a8..5e27b22a4 100644 --- a/gc/SMakefile.amiga +++ b/gc/SMakefile.amiga @@ -52,7 +52,7 @@ CSCOPT= $(OPT) DEFINE AMIGA IGNORE=100 IGNORE=161 all: gctest setjmp_t cord/cordtest clean: - delete *.lib gctest setjmp_t *.o *.lnk cord/*.o cord/*.lib cord/*.lnk cord/tests/*.o cord/cordtest + delete *.lib gctest setjmp_t *.o *.lnk cord/*.o cord/*.lib cord/*.lnk cord/cordtest smake test: setjmp_t gctest cord/cordtest @@ -66,8 +66,8 @@ gctest: gc$(CPU).lib GCAmigaOS$(CPU).lib test.o setjmp_t: setjmp_t.o gc.h $(LINKER) LIB:c.o setjmp_t.o to setjmp_t lib LIB:sc.lib -cord/cordtest: cord/tests/cordtest.o cord/cord$(CPU).lib gc$(CPU).lib - slink LIB:c.o cord/tests/cordtest.o LIB $(MATHLIB) gc$(CPU).lib cord/cord$(CPU).lib LIB:sc.lib TO cord/cordtest +cord/cordtest: cord/cordtest.o cord/cord$(CPU).lib gc$(CPU).lib + slink LIB:c.o cord/cordtest.o LIB $(MATHLIB) gc$(CPU).lib cord/cord$(CPU).lib LIB:sc.lib TO cord/cordtest #------------------LIBBING---------------------------- @@ -168,5 +168,5 @@ cord/cordprnt.o: cord/cordprnt.c cord/cordxtra.o: cord/cordxtra.c sc cord/cordxtra.c $(CSCOPT) -cord/tests/cordtest.o: cord/tests/cordtest.c +cord/cordtest.o: cord/tests/cordtest.c sc cord/tests/cordtest.c $(CSCOPT) diff --git a/gc/WCC_MAKEFILE b/gc/WCC_MAKEFILE index 61a1db530..0aae2df70 100644 --- a/gc/WCC_MAKEFILE +++ b/gc/WCC_MAKEFILE @@ -25,7 +25,7 @@ CPU=5 OPTIM=-oneatx -s #OPTIM=-ohneatx -s -DEFS=-DALL_INTERIOR_POINTERS -DENABLE_DISCLAIM -DGC_ATOMIC_UNCOLLECTABLE -DGC_GCJ_SUPPORT -DJAVA_FINALIZATION -DNO_EXECUTE_PERMISSION #-DSMALL_CONFIG +DEFS=-DALL_INTERIOR_POINTERS -DENABLE_DISCLAIM #-DSMALL_CONFIG ##### @@ -48,7 +48,6 @@ SYSTEM=Unknown SYSFLAG=-DDOS4GW -bt=dos !else ifdef MSWIN32 SYSFLAG=-DMSWIN32 -bt=nt -DEFS=$(DEFS) -DUSE_MUNMAP !else ifdef OS2 SYSFLAG=-DOS2 -bt=os2 !else @@ -76,7 +75,7 @@ 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 malloc.obj dyn_load.obj & - typd_mlc.obj ptr_chck.obj mallocx.obj fnlz_mlc.obj gcj_mlc.obj + typd_mlc.obj ptr_chck.obj mallocx.obj fnlz_mlc.obj all: gc.lib gctest.exe test_cpp.exe diff --git a/gc/allchblk.c b/gc/allchblk.c index 8d550c444..030de4624 100644 --- a/gc/allchblk.c +++ b/gc/allchblk.c @@ -326,8 +326,8 @@ GC_INLINE void GC_remove_from_fl(hdr *hhdr) GC_remove_from_fl_at(hhdr, GC_hblk_fl_from_blocks(divHBLKSZ(hhdr->hb_sz))); } -/* Return a pointer to the block ending just before h, if any. */ -static struct hblk * get_block_ending_at(struct hblk *h) +/* Return a pointer to the free block ending just before h, if any. */ +STATIC struct hblk * GC_free_block_ending_at(struct hblk *h) { struct hblk * p = h - 1; hdr * phdr; @@ -338,27 +338,16 @@ static struct hblk * get_block_ending_at(struct hblk *h) phdr = HDR(p); } if (0 != phdr) { - return p; - } - p = GC_prev_block(h - 1); - if (p) { - phdr = HDR(p); - if ((ptr_t)p + phdr -> hb_sz == (ptr_t)h) { + if(HBLK_IS_FREE(phdr)) { return p; + } else { + return 0; } } - return NULL; -} - -/* Return a pointer to the free block ending just before h, if any. */ -STATIC struct hblk * GC_free_block_ending_at(struct hblk *h) -{ - struct hblk * p = get_block_ending_at(h); - - if (p /* != NULL */) { /* CPPCHECK */ - hdr * phdr = HDR(p); - - if (HBLK_IS_FREE(phdr)) { + p = GC_prev_block(h - 1); + if (0 != p) { + phdr = HDR(p); + if (HBLK_IS_FREE(phdr) && (ptr_t)p + phdr -> hb_sz == (ptr_t)h) { return p; } } @@ -406,60 +395,6 @@ STATIC void GC_add_to_fl(struct hblk *h, hdr *hhdr) GC_INNER int GC_unmap_threshold = MUNMAP_THRESHOLD; -#ifdef COUNT_UNMAPPED_REGIONS - /* GC_unmap_old will avoid creating more than this many unmapped regions, */ - /* but an unmapped region may be split again so exceeding the limit. */ - - /* Return the change in number of unmapped regions if the block h swaps */ - /* from its current state of mapped/unmapped to the opposite state. */ - static int calc_num_unmapped_regions_delta(struct hblk *h, hdr *hhdr) - { - struct hblk * prev = get_block_ending_at(h); - struct hblk * next; - GC_bool prev_unmapped = FALSE; - GC_bool next_unmapped = FALSE; - - next = GC_next_block((struct hblk *)((ptr_t)h + hhdr->hb_sz), TRUE); - /* Ensure next is contiguous with h. */ - if ((ptr_t)next != GC_unmap_end((ptr_t)h, (size_t)hhdr->hb_sz)) { - next = NULL; - } - if (prev != NULL) { - hdr * prevhdr = HDR(prev); - prev_unmapped = !IS_MAPPED(prevhdr); - } - if (next != NULL) { - hdr * nexthdr = HDR(next); - next_unmapped = !IS_MAPPED(nexthdr); - } - - if (prev_unmapped && next_unmapped) { - /* If h unmapped, merge two unmapped regions into one. */ - /* If h remapped, split one unmapped region into two. */ - return IS_MAPPED(hhdr) ? -1 : 1; - } - if (!prev_unmapped && !next_unmapped) { - /* If h unmapped, create an isolated unmapped region. */ - /* If h remapped, remove it. */ - return IS_MAPPED(hhdr) ? 1 : -1; - } - /* If h unmapped, merge it with previous or next unmapped region. */ - /* If h remapped, reduce either previous or next unmapped region. */ - /* In either way, no change to the number of unmapped regions. */ - return 0; - } -#endif /* COUNT_UNMAPPED_REGIONS */ - -/* Update GC_num_unmapped_regions assuming the block h changes */ -/* from its current state of mapped/unmapped to the opposite state. */ -GC_INLINE void GC_adjust_num_unmapped(struct hblk *h GC_ATTR_UNUSED, - hdr *hhdr GC_ATTR_UNUSED) -{ -# ifdef COUNT_UNMAPPED_REGIONS - GC_num_unmapped_regions += calc_num_unmapped_regions_delta(h, hhdr); -# endif -} - /* Unmap blocks that haven't been recently touched. This is the only way */ /* way blocks are ever unmapped. */ GC_INNER void GC_unmap_old(void) @@ -468,12 +403,6 @@ GC_INNER void GC_unmap_old(void) if (GC_unmap_threshold == 0) return; /* unmapping disabled */ -# ifdef COUNT_UNMAPPED_REGIONS - /* Skip unmapping if we have already exceeded the soft limit. */ - /* This forgoes any opportunities to merge unmapped regions though. */ - if (GC_num_unmapped_regions >= GC_UNMAPPED_REGIONS_SOFT_LIMIT) - return; -# endif for (i = 0; i <= N_HBLK_FLS; ++i) { struct hblk * h; @@ -487,19 +416,6 @@ GC_INNER void GC_unmap_old(void) /* truncated counter value wrapping is handled correctly). */ if ((unsigned short)(GC_gc_no - hhdr->hb_last_reclaimed) > (unsigned short)GC_unmap_threshold) { -# ifdef COUNT_UNMAPPED_REGIONS - /* Continue with unmapping the block only if it will not */ - /* create too many unmapped regions, or if unmapping */ - /* reduces the number of regions. */ - int delta = calc_num_unmapped_regions_delta(h, hhdr); - signed_word regions = GC_num_unmapped_regions + delta; - - if (delta >= 0 && regions >= GC_UNMAPPED_REGIONS_SOFT_LIMIT) { - GC_COND_LOG_PRINTF("Unmapped regions limit reached!\n"); - return; - } - GC_num_unmapped_regions = regions; -# endif GC_unmap((ptr_t)h, (size_t)hhdr->hb_sz); hhdr -> hb_flags |= WAS_UNMAPPED; } @@ -556,21 +472,17 @@ GC_INNER void GC_merge_unmapped(void) if (IS_MAPPED(hhdr) && !IS_MAPPED(nexthdr)) { /* make both consistent, so that we can merge */ if (size > nextsize) { - GC_adjust_num_unmapped(next, nexthdr); GC_remap((ptr_t)next, nextsize); } else { - GC_adjust_num_unmapped(h, hhdr); GC_unmap((ptr_t)h, size); GC_unmap_gap((ptr_t)h, size, (ptr_t)next, nextsize); hhdr -> hb_flags |= WAS_UNMAPPED; } } else if (IS_MAPPED(nexthdr) && !IS_MAPPED(hhdr)) { if (size > nextsize) { - GC_adjust_num_unmapped(next, nexthdr); GC_unmap((ptr_t)next, nextsize); GC_unmap_gap((ptr_t)h, size, (ptr_t)next, nextsize); } else { - GC_adjust_num_unmapped(h, hhdr); GC_remap((ptr_t)h, size); hhdr -> hb_flags &= ~WAS_UNMAPPED; hhdr -> hb_last_reclaimed = nexthdr -> hb_last_reclaimed; @@ -819,7 +731,6 @@ GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n, int may_split) /* Make sure it's mapped before we mangle it. */ # ifdef USE_MUNMAP if (!IS_MAPPED(hhdr)) { - GC_adjust_num_unmapped(hbp, hhdr); GC_remap((ptr_t)hbp, (size_t)hhdr->hb_sz); hhdr -> hb_flags &= ~WAS_UNMAPPED; } @@ -894,7 +805,6 @@ GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n, int may_split) if( size_avail >= size_needed ) { # ifdef USE_MUNMAP if (!IS_MAPPED(hhdr)) { - GC_adjust_num_unmapped(hbp, hhdr); GC_remap((ptr_t)hbp, (size_t)hhdr->hb_sz); hhdr -> hb_flags &= ~WAS_UNMAPPED; /* Note: This may leave adjacent, mapped free blocks. */ diff --git a/gc/alloc.c b/gc/alloc.c index d1525a05f..06213ce86 100644 --- a/gc/alloc.c +++ b/gc/alloc.c @@ -3,7 +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-2019 Ivan Maidanski + * 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. @@ -124,7 +124,7 @@ const char * const GC_copyright[] = "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-2019 Ivan Maidanski ", +"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." }; @@ -173,7 +173,7 @@ GC_INNER int GC_CALLBACK GC_never_stop_func(void) #endif #ifndef NO_CLOCK - STATIC CLOCK_TYPE GC_start_time = CLOCK_TYPE_INITIALIZER; + STATIC CLOCK_TYPE GC_start_time = 0; /* Time at which we stopped world. */ /* used only in GC_timeout_stop_func. */ #endif @@ -349,7 +349,7 @@ STATIC void GC_clear_a_few_frames(void) /* Heap size at which we need a collection to avoid expanding past */ /* limits used by blacklisting. */ -STATIC word GC_collect_at_heapsize = GC_WORD_MAX; +STATIC word GC_collect_at_heapsize = (word)(-1); /* Have we allocated enough to amortize a collection? */ GC_INNER GC_bool GC_should_collect(void) @@ -485,7 +485,7 @@ GC_API GC_on_collection_event_proc GC_CALL GC_get_on_collection_event(void) GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func) { # ifndef NO_CLOCK - CLOCK_TYPE start_time = CLOCK_TYPE_INITIALIZER; + CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */ GC_bool start_time_valid; # endif @@ -715,7 +715,7 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func) { unsigned i; # ifndef NO_CLOCK - CLOCK_TYPE start_time = CLOCK_TYPE_INITIALIZER; + CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */ # endif GC_ASSERT(I_HOLD_LOCK()); @@ -984,7 +984,7 @@ GC_INLINE int GC_compute_heap_usage_percent(void) { word used = GC_composite_in_use + GC_atomic_in_use; word heap_sz = GC_heapsize - GC_unmapped_bytes; - return used >= heap_sz ? 0 : used < GC_WORD_MAX / 100 ? + return used >= heap_sz ? 0 : used < ((word)-1) / 100 ? (int)((used * 100) / heap_sz) : (int)(used / (heap_sz / 100)); } @@ -993,8 +993,8 @@ GC_INLINE int GC_compute_heap_usage_percent(void) STATIC void GC_finish_collection(void) { # ifndef NO_CLOCK - CLOCK_TYPE start_time = CLOCK_TYPE_INITIALIZER; - CLOCK_TYPE finalize_time = CLOCK_TYPE_INITIALIZER; + CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */ + CLOCK_TYPE finalize_time = 0; # endif GC_ASSERT(I_HOLD_LOCK()); @@ -1261,13 +1261,13 @@ GC_INNER void GC_add_to_heap(struct hblk *p, size_t bytes) GC_heapsize += bytes; /* Normally the caller calculates a new GC_collect_at_heapsize, - * but this is also called directly from GC_scratch_recycle_inner, so + * but this is also called directly from alloc_mark_stack, so * adjust here. It will be recalculated when called from * GC_expand_hp_inner. */ GC_collect_at_heapsize += bytes; if (GC_collect_at_heapsize < GC_heapsize /* wrapped */) - GC_collect_at_heapsize = GC_WORD_MAX; + GC_collect_at_heapsize = (word)(-1); if ((word)p <= (word)GC_least_plausible_heap_addr || GC_least_plausible_heap_addr == 0) { @@ -1307,7 +1307,7 @@ GC_INNER void GC_add_to_heap(struct hblk *p, size_t bytes) } #endif -void * GC_least_plausible_heap_addr = (void *)GC_WORD_MAX; +void * GC_least_plausible_heap_addr = (void *)ONES; void * GC_greatest_plausible_heap_addr = 0; GC_INLINE word GC_max(word x, word y) @@ -1388,7 +1388,7 @@ GC_INNER GC_bool GC_expand_hp_inner(word n) GC_collect_at_heapsize = GC_heapsize + expansion_slop - 2*MAXHINCR*HBLKSIZE; if (GC_collect_at_heapsize < GC_heapsize /* wrapped */) - GC_collect_at_heapsize = GC_WORD_MAX; + GC_collect_at_heapsize = (word)(-1); if (GC_on_heap_resize) (*GC_on_heap_resize)(GC_heapsize); @@ -1419,6 +1419,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 */ diff --git a/gc/backgraph.c b/gc/backgraph.c index 5565a35c2..20047fb96 100644 --- a/gc/backgraph.c +++ b/gc/backgraph.c @@ -32,8 +32,7 @@ /* #include */ -#if (!defined(DBG_HDRS_ALL) || (ALIGNMENT != CPP_WORDSZ/8) \ - /* || !defined(UNIX_LIKE) */) && !defined(CPPCHECK) +#if !defined(DBG_HDRS_ALL) || (ALIGNMENT != CPP_WORDSZ/8) /* || !defined(UNIX_LIKE) */ # error The configuration does not support MAKE_BACK_GRAPH #endif @@ -240,7 +239,7 @@ static void add_edge(ptr_t p, ptr_t q) if (((word)pred & FLAG_MANY) != 0) { n_edges = e -> n_edges; - } else if (((word)pred & 1) == 0) { + } else if (pred != NULL && ((word)pred & 1) == 0) { /* A misinterpreted freelist link. */ n_edges = 1; local = -1; @@ -400,7 +399,7 @@ static word backwards_height(ptr_t p) if (((word)pred & FLAG_MANY) != 0) { n_edges = e -> n_edges; - } else if (((word)pred & 1) == 0) { + } else if (pred != NULL && ((word)pred & 1) == 0) { /* A misinterpreted freelist link. */ n_edges = 1; local = -1; diff --git a/gc/bdw-gc.pc.in b/gc/bdw-gc.pc.in index 23678f430..ef4c23410 100644 --- a/gc/bdw-gc.pc.in +++ b/gc/bdw-gc.pc.in @@ -6,5 +6,5 @@ includedir=@includedir@ Name: Boehm-Demers-Weiser Conservative Garbage Collector Description: A garbage collector for C and C++ Version: @PACKAGE_VERSION@ -Libs: -L${libdir} @ATOMIC_OPS_LIBS@ -lgc @THREADDLLIBS@ +Libs: -L${libdir} -lgc Cflags: -I${includedir} diff --git a/gc/blacklst.c b/gc/blacklst.c index 45d1ef40f..31511ae18 100644 --- a/gc/blacklst.c +++ b/gc/blacklst.c @@ -175,7 +175,8 @@ GC_INNER void GC_unpromote_black_lists(void) GC_copy_bl(GC_old_stack_bl, GC_incomplete_stack_bl); } -#if defined(PARALLEL_MARK) && defined(THREAD_SANITIZER) +#if defined(set_pht_entry_from_index_concurrent) && defined(PARALLEL_MARK) \ + && defined(THREAD_SANITIZER) # define backlist_set_pht_entry_from_index(db, index) \ set_pht_entry_from_index_concurrent(db, index) #else diff --git a/gc/build/s60v3/libgc.mmp b/gc/build/s60v3/libgc.mmp index a0dad4c8e..7fee8ad1a 100644 --- a/gc/build/s60v3/libgc.mmp +++ b/gc/build/s60v3/libgc.mmp @@ -18,10 +18,8 @@ CAPABILITY PowerMgmt ReadDeviceData ReadUserData WriteDeviceData WriteUserData S MACRO ALL_INTERIOR_POINTERS MACRO NO_EXECUTE_PERMISSION MACRO USE_MMAP -MACRO GC_ATOMIC_UNCOLLECTABLE MACRO GC_DONT_REGISTER_MAIN_STATIC_DATA MACRO GC_DLL -MACRO JAVA_FINALIZATION MACRO SYMBIAN MACRO ENABLE_DISCLAIM //MACRO GC_GCJ_SUPPORT diff --git a/gc/configure.ac b/gc/configure.ac index 3b38e6fc8..045a028a3 100644 --- a/gc/configure.ac +++ b/gc/configure.ac @@ -1,6 +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-2019 Ivan Maidanski +# 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. @@ -14,7 +14,7 @@ dnl Process this file with autoconf to produce configure. dnl Initialization. -AC_INIT(gc,8.0.6,https://github.com/ivmai/bdwgc/issues) +AC_INIT(gc,8.0.0,https://github.com/ivmai/bdwgc/issues) dnl Version must conform to: [0-9]+[.][0-9]+[.][0-9]+ AC_CONFIG_SRCDIR(gcj_mlc.c) @@ -22,6 +22,7 @@ AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_TARGET AC_PREREQ(2.61) GC_SET_VERSION +AC_CONFIG_AUX_DIR([.]) AM_INIT_AUTOMAKE([foreign nostdinc subdir-objects]) AC_CONFIG_HEADERS([include/config.h]) AM_MAINTAINER_MODE @@ -52,9 +53,9 @@ if test :"$GCC": = :yes: ; then gc_cflags="${gc_cflags} -fexceptions" else case "$host" in - hppa*-*-hpux* ) + hppa*-*-hpux* ) if test :$GCC: != :"yes": ; then - gc_cflags="${gc_cflags} +ESdbgasm" + gc_cflags="${gc_flags} +ESdbgasm" fi # :TODO: actually we should check using Autoconf if # the compiler supports this option. @@ -186,8 +187,6 @@ CFLAGS="$old_CFLAGS" THREADDLLIBS= need_atomic_ops_asm=false -use_parallel_mark=no -use_thread_local_alloc=no # Libraries needed to support dynamic loading and/or threads. case "$THREADS" in no | none | single) @@ -200,13 +199,17 @@ case "$THREADS" in case "$host" in *-*-aix* | *-*-android* | *-*-cygwin* | *-*-darwin* | *-*-dragonfly* | \ *-*-freebsd* | *-*-haiku* | *-*-hpux11* | *-*-irix* | \ - *-*-kfreebsd*-gnu | *-*-gnu* | *-*-*linux* | *-*-msys* | *-*-nacl* | \ + *-*-kfreebsd*-gnu | *-*-gnu* | *-*-*linux* | *-*-nacl* | \ *-*-netbsd* | *-*-openbsd* | *-*-osf* | *-*-solaris*) AC_DEFINE(GC_THREADS) AC_DEFINE([_REENTRANT], [1], [Required define if using POSIX threads.]) - use_parallel_mark=$enable_parallel_mark - use_thread_local_alloc=$enable_thread_local_alloc + if test "${enable_parallel_mark}" != no; then + AC_DEFINE(PARALLEL_MARK) + fi + if test "${enable_thread_local_alloc}" != no; then + AC_DEFINE(THREAD_LOCAL_ALLOC) + fi default_threadlibs=true AC_MSG_WARN("Explicit GC_INIT() calls may be required.") ;; @@ -241,7 +244,7 @@ case "$THREADS" in *-*-solaris*) THREADDLLIBS="-lpthread -lrt" ;; - *-*-cygwin* | *-*-msys*) + *-*-cygwin*) # Cygwin doesn't have a real libpthread, so Libtool can't link # against it. THREADDLLIBS="" @@ -250,9 +253,13 @@ case "$THREADS" in *-*-mingw*) AC_DEFINE(GC_WIN32_PTHREADS) # Using pthreads-win32 (or other non-Cygwin pthreads) library. + if test "${enable_parallel_mark}" != no; then + AC_DEFINE(PARALLEL_MARK) + fi + if test "${enable_thread_local_alloc}" != no; then + AC_DEFINE(THREAD_LOCAL_ALLOC) + fi THREADDLLIBS="-lpthread" - use_parallel_mark=$enable_parallel_mark - use_thread_local_alloc=$enable_thread_local_alloc win32_threads=true ;; *-*-darwin*) @@ -279,11 +286,15 @@ case "$THREADS" in ;; win32) AC_DEFINE(GC_THREADS) - use_parallel_mark=$enable_parallel_mark - if test "${enable_parallel_mark}" != no \ - -o "${enable_shared}" != yes -o "${enable_static}" != no; then - # Imply THREAD_LOCAL_ALLOC unless GC_DLL. - use_thread_local_alloc=$enable_thread_local_alloc + if test "${enable_parallel_mark}" != no; then + AC_DEFINE(PARALLEL_MARK) + fi + if test "${enable_thread_local_alloc}" != no; then + if test "${enable_parallel_mark}" != no \ + -o "${enable_shared}" != yes -o "${enable_static}" != no; then + # Imply THREAD_LOCAL_ALLOC unless GC_DLL. + AC_DEFINE(THREAD_LOCAL_ALLOC) + fi fi if test "${enable_win32_dllmain}" = yes; then AC_DEFINE(GC_INSIDE_DLL, 1, @@ -299,8 +310,12 @@ case "$THREADS" in AC_MSG_RESULT($THREADDLLIBS) # Use pthread GCC switch THREADDLLIBS=-pthread - use_parallel_mark=$enable_parallel_mark - use_thread_local_alloc=$enable_thread_local_alloc + if test "${enable_parallel_mark}" != no; then + AC_DEFINE(PARALLEL_MARK) + fi + if test "${enable_thread_local_alloc}" != no; then + AC_DEFINE(THREAD_LOCAL_ALLOC) + fi AC_MSG_WARN("Explicit GC_INIT() calls may be required.") AM_CFLAGS="-pthread $AM_CFLAGS" ;; @@ -309,14 +324,22 @@ case "$THREADS" in THREADDLLIBS=-lpthread AC_DEFINE(GC_THREADS) AC_DEFINE(_REENTRANT) - use_parallel_mark=$enable_parallel_mark - use_thread_local_alloc=$enable_thread_local_alloc + if test "${enable_parallel_mark}" != no; then + AC_DEFINE(PARALLEL_MARK) + fi + if test "${enable_thread_local_alloc}" != no; then + AC_DEFINE(THREAD_LOCAL_ALLOC) + fi ;; rtems) THREADS=posix AC_DEFINE(GC_THREADS) - use_parallel_mark=$enable_parallel_mark - use_thread_local_alloc=$enable_thread_local_alloc + if test "${enable_parallel_mark}" != no; then + AC_DEFINE(PARALLEL_MARK) + fi + if test "${enable_thread_local_alloc}" != no; then + AC_DEFINE(THREAD_LOCAL_ALLOC) + fi ;; decosf1 | irix | mach | os2 | solaris | dce | vxworks) AC_MSG_ERROR(thread package $THREADS not yet supported) @@ -330,6 +353,8 @@ AM_CONDITIONAL(THREADS, test x$THREADS != xnone) AM_CONDITIONAL(PTHREADS, test x$THREADS = xposix) AM_CONDITIONAL(DARWIN_THREADS, test x$darwin_threads = xtrue) AM_CONDITIONAL(WIN32_THREADS, test x$win32_threads = xtrue) +AM_CONDITIONAL(THREAD_LOCAL_ALLOC, + test x$enable_thread_local_alloc != xno -a x$THREADS != xnone) compiler_suncc=no pthread_start_standalone=no @@ -378,7 +403,6 @@ if test "$GCC" = yes; then AS_IF([test "$ac_cv_cc_pedantic" = yes], [WPEDANTIC="-Wpedantic -Wno-long-long"]) CFLAGS="-Wall $WEXTRA $WPEDANTIC $CFLAGS" - CXXFLAGS="-Wall $WEXTRA $WPEDANTIC $CXXFLAGS" fi AC_MSG_CHECKING(for xlc) @@ -435,8 +459,8 @@ case "$host" in mips-sgi-irix6*) ;; # We never want libdl on darwin. It is a fake libdl that just ends up making # dyld calls anyway. The same applies to Cygwin. - *-*-cygwin* | *-*-darwin* | *-*-msys*) - ;; + *-*-darwin*) ;; + *-*-cygwin*) ;; *) AC_CHECK_LIB(dl, dlopen, THREADDLLIBS="$THREADDLLIBS -ldl") ;; @@ -458,14 +482,14 @@ AC_CHECK_HEADER([execinfo.h], [], # extra LD Flags which are required for targets case "${host}" in *-*-darwin*) - extra_ldflags_libgc=-Wl,-single_module + extra_ldflags_libomcgc=-Wl,-single_module ;; esac -AC_SUBST(extra_ldflags_libgc) +AC_SUBST(extra_ldflags_libomcgc) AC_SUBST(EXTRA_TEST_LIBS) -target_all=libgc.la +target_all=libomcgc.la AC_SUBST(target_all) dnl If the target is an eCos system, use the appropriate eCos @@ -497,7 +521,7 @@ AM_CONDITIONAL(CPLUSPLUS, test "${enable_cplusplus}" = yes) if test "$GCC" = yes; then if test "${enable_cplusplus}" = yes; then case "$host" in - *-*-cygwin* | *-*-mingw* | *-*-msys*) + *-*-cygwin* | *-*-mingw*) AC_MSG_CHECKING([whether libsupc++ required]) SUPC="`$CXX -print-file-name=libsupc++.a 2>/dev/null`" if test -n "$SUPC" -a "$SUPC" != "libsupc++.a"; then @@ -532,7 +556,8 @@ esac AC_MSG_RESULT($enable_shared) # Compile with GC_DLL defined unless building static libraries. -if test "${enable_shared}" = yes -a "${enable_static}" = no; then +if test "${enable_shared}" = yes; then + if test "${enable_static}" = no; then AC_DEFINE(GC_DLL) if test "$GCC" = yes; then # Pass -fvisibility=hidden option if supported @@ -547,16 +572,7 @@ if test "${enable_shared}" = yes -a "${enable_static}" = no; then [CFLAGS="-DGC_NO_VISIBILITY $CFLAGS"]) AC_MSG_RESULT($ac_cv_fvisibility_hidden) fi -else - - case "$host" in - *-*-cygwin* | *-*-mingw* | *-*-msys*) - # Use inline version of GC new and delete operators in test_cpp - # otherwise the system ones might be used instead because of arbitrary - # ordering of object files when linking. - CXXFLAGS="$CXXFLAGS -DGC_NOT_DLL" - ;; - esac + fi fi # Configuration of machine-dependent code @@ -626,9 +642,10 @@ if false; then AC_EXEEXT fi -dnl The collector might not properly work on IBM AIX when +dnl As of 4.13a2, the collector will not properly work on Solaris when dnl built with gcc and -O. So we remove -O in the appropriate case. -AC_MSG_CHECKING(whether AIX gcc optimization fix is necessary) +dnl Not needed anymore on Solaris. +AC_MSG_CHECKING(whether Solaris gcc optimization fix is necessary) case "$host" in *aix*) if test "$GCC" = yes; then @@ -839,6 +856,40 @@ if test "${enable_large_config}" = yes; then [Define to optimize for large heaps or root sets.]) fi +AC_ARG_ENABLE(handle-fork, + [AC_HELP_STRING([--enable-handle-fork[=yes|no|auto|manual]], + [attempt to ensure a usable collector after fork() + in multi-threaded programs (default: auto; + manual: GC_atfork_prepare/parent/child should be + called by the client)])]) +if test "${enable_handle_fork}" = yes; then + AC_DEFINE(HANDLE_FORK, 1, + [Define to install pthread_atfork() handlers by default.]) +elif test "${enable_handle_fork}" = no; then + AC_DEFINE(NO_HANDLE_FORK, 1, + [Prohibit installation of pthread_atfork() handlers.]) +elif test "${enable_handle_fork}" != manual -a x$THREADS = xposix; then + # If the option is omitted, pthread_atfork handlers are installed + # by default for the targets where pthread_atfork is known to work. + case "$host" in + *-*-android*) + # Android NDK does not provide pthread_atfork. + ;; + *-*-darwin*) + # The incremental mode (which is off if parallel marking) conflicts + # with fork handling on Darwin. + if test "${enable_parallel_mark}" != no; then + AC_DEFINE(HANDLE_FORK) + fi + ;; + *-*-aix* | *-*-cygwin* | *-*-freebsd* | *-*-haiku* | \ + *-*-hpux11* | *-*-irix* | *-*-kfreebsd*-gnu | \ + *-*-*linux* | *-*-netbsd* | *-*-openbsd* | *-*-osf* | *-*-solaris*) + AC_DEFINE(HANDLE_FORK) + ;; + esac +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 targeting an embedded system. FIXME. @@ -971,8 +1022,6 @@ AC_ARG_ENABLE(docs, [do not build and install documentation])]) AM_CONDITIONAL(ENABLE_DOCS, test x$enable_docs != xno) -AM_CONDITIONAL(ENABLE_SHARED, test x$enable_shared = xyes) - # Atomic Ops # ---------- @@ -1032,17 +1081,13 @@ AS_IF([test x"$with_libatomic_ops" = xno \ AC_MSG_CHECKING([which libatomic_ops to use]) AS_IF([test x"$with_libatomic_ops" != xno], [ AS_IF([test x"$with_libatomic_ops" != xnone -a x"$THREADS" != xnone], - [ AC_MSG_RESULT([external]) - ATOMIC_OPS_LIBS="-latomic_ops" - AC_SUBST([ATOMIC_OPS_LIBS]) ], + [ AC_MSG_RESULT([external]) ], [ AC_MSG_RESULT([none]) AS_IF([test x"$THREADS" != xnone], [ AC_DEFINE([GC_BUILTIN_ATOMIC], [1], [Use C11 (GCC) atomic intrinsics instead of - libatomic_ops primitives.]) ]) ]) - AO_TRYLINK_CFLAGS="" ], + libatomic_ops primitives.]) ]) ]) ], [ AC_MSG_RESULT([internal]) - AO_TRYLINK_CFLAGS="-I${srcdir}/libatomic_ops/src" ATOMIC_OPS_CFLAGS='-I$(top_builddir)/libatomic_ops/src -I$(top_srcdir)/libatomic_ops/src' ATOMIC_OPS_LIBS="" AC_SUBST([ATOMIC_OPS_CFLAGS]) @@ -1053,84 +1098,6 @@ AM_CONDITIONAL([USE_INTERNAL_LIBATOMIC_OPS], AM_CONDITIONAL([NEED_ATOMIC_OPS_ASM], [test x$with_libatomic_ops = xno -a x$need_atomic_ops_asm = xtrue]) -# Check whether particular AO primitives are emulated with locks. -# The check below is based on the fact that linking with the libatomic_ops -# binary file is not needed in case of absence of the emulation (except for -# Solaris SPARC). -AS_IF([test x$with_libatomic_ops != xnone -a x$need_atomic_ops_asm != xtrue], - [ old_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $AO_TRYLINK_CFLAGS $CFLAGS_EXTRA" - AC_MSG_CHECKING([for lock-free AO_or primitive]) - AC_TRY_LINK([#include "atomic_ops.h"], - [AO_t x=0;AO_or(&x,1)], - [ AC_MSG_RESULT(yes) - AC_DEFINE([HAVE_LOCKFREE_AO_OR], [1], - [libatomic_ops AO_or primitive implementation is lock-free.]) ], - [ AC_MSG_RESULT(no) ]) - AC_MSG_CHECKING([for lock-free AO load/store, test-and-set primitives]) - AC_TRY_LINK([#include "atomic_ops.h"], - [AO_t x=0;unsigned char c=0;AO_TS_t z=AO_TS_INITIALIZER; - (void)AO_test_and_set_acquire(&z);AO_CLEAR(&z);AO_compiler_barrier(); - AO_store(&x,AO_load(&x)+1);AO_char_store(&c,AO_char_load(&c)+1); - AO_store_release(&x,AO_load_acquire(&x)+1)], - [ AC_MSG_RESULT(yes) ], - [ AC_MSG_RESULT(no) - use_thread_local_alloc=no - AC_DEFINE([BASE_ATOMIC_OPS_EMULATED], [1], - [AO load, store and/or test-and-set primitives are - implemented in libatomic_ops using locks.]) ]) - AS_IF([test x$use_parallel_mark != xno], - [ AC_MSG_CHECKING( - [for lock-free compare-and-swap and fetch-and-add primitives]) - AC_TRY_LINK( - [#define AO_REQUIRE_CAS - #include "atomic_ops.h"], - [AO_t x=0;(void)AO_fetch_and_add(&x,1);(void)AO_compare_and_swap(&x,1,2)], - [ AC_MSG_RESULT(yes) ], - [ AC_MSG_RESULT(no) - use_parallel_mark=no ]) ]) - CFLAGS="$old_CFLAGS" ]) - -AS_IF([test x$use_parallel_mark != xno], - [ AC_DEFINE(PARALLEL_MARK) ]) -AS_IF([test x$use_thread_local_alloc != xno], - [ AC_DEFINE(THREAD_LOCAL_ALLOC) ]) -AM_CONDITIONAL(THREAD_LOCAL_ALLOC, test x$use_thread_local_alloc != xno) - -AC_ARG_ENABLE(handle-fork, - [ AC_HELP_STRING([--enable-handle-fork[=yes|no|auto|manual]], - [attempt to ensure a usable collector after fork() - in multi-threaded programs (default: auto; - manual: GC_atfork_prepare/parent/child should be - called by the client)]) ]) -if test "${enable_handle_fork}" = yes; then - AC_DEFINE(HANDLE_FORK, 1, - [Define to install pthread_atfork() handlers by default.]) -elif test "${enable_handle_fork}" = no; then - AC_DEFINE(NO_HANDLE_FORK, 1, - [Prohibit installation of pthread_atfork() handlers.]) -elif test "${enable_handle_fork}" != manual -a x$THREADS = xposix; then - # If the option is omitted, pthread_atfork handlers are installed - # by default for the targets where pthread_atfork is known to work. - case "$host" in - *-*-android*) - # Android NDK does not provide pthread_atfork. - ;; - *-*-darwin*) - # The incremental mode (which is off if parallel marking) conflicts - # with fork handling on Darwin. - if test x$use_parallel_mark != xno; then - AC_DEFINE(HANDLE_FORK) - fi - ;; - *-*-aix* | *-*-cygwin* | *-*-freebsd* | *-*-haiku* | \ - *-*-hpux11* | *-*-irix* | *-*-kfreebsd*-gnu | \ - *-*-*linux* | *-*-netbsd* | *-*-openbsd* | *-*-osf* | *-*-solaris*) - AC_DEFINE(HANDLE_FORK) - ;; - esac -fi - dnl Produce the Files dnl ----------------- diff --git a/gc/cord/cord.am b/gc/cord/cord.am index c2ea532df..e80e06fb1 100644 --- a/gc/cord/cord.am +++ b/gc/cord/cord.am @@ -7,7 +7,7 @@ LIBCORD_VER_INFO = 5:0:4 lib_LTLIBRARIES += libcord.la -libcord_la_LIBADD = $(top_builddir)/libgc.la +libcord_la_LIBADD = $(top_builddir)/libomcgc.la libcord_la_LDFLAGS = -version-info $(LIBCORD_VER_INFO) -no-undefined libcord_la_CPPFLAGS = $(AM_CPPFLAGS) @@ -19,13 +19,7 @@ libcord_la_SOURCES = \ TESTS += cordtest$(EXEEXT) check_PROGRAMS += cordtest cordtest_SOURCES = cord/tests/cordtest.c -cordtest_LDADD = $(top_builddir)/libcord.la - -## In case of static libraries build, libgc.a is already referenced in -## dependency_libs attribute of libcord.la file. -if ENABLE_SHARED -cordtest_LDADD += $(top_builddir)/libgc.la -endif +cordtest_LDADD = $(top_builddir)/libomcgc.la $(top_builddir)/libcord.la EXTRA_DIST += \ cord/tests/de.c \ diff --git a/gc/cord/cordbscs.c b/gc/cord/cordbscs.c index 1b4ec28b3..ff0d23997 100644 --- a/gc/cord/cordbscs.c +++ b/gc/cord/cordbscs.c @@ -170,13 +170,7 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny) char * result = (char *)GC_MALLOC_ATOMIC(result_len + 1); if (result == 0) OUT_OF_MEMORY; -# ifdef LINT2 - memcpy(result, x, lenx + 1); -# else - memcpy(result, x, lenx); - /* No need to copy the terminating zero */ - /* as result[lenx] is written below. */ -# endif + memcpy(result, x, lenx); memcpy(result + lenx, y, leny); result[result_len] = '\0'; return((CORD) result); @@ -780,30 +774,19 @@ void CORD__extend_path(CORD_pos p) char CORD__pos_fetch(CORD_pos p) { /* Leaf is a function node */ - struct CORD_pe * pe; - CORD leaf; - struct Function * f; - - if (!CORD_pos_valid(p)) - ABORT("CORD_pos_fetch: invalid argument"); - pe = &p[0].path[p[0].path_len]; - leaf = pe -> pe_cord; - if (!IS_FUNCTION(leaf)) - ABORT("CORD_pos_fetch: bad leaf"); - f = &((CordRep *)leaf)->function; + struct CORD_pe * pe = &((p)[0].path[(p)[0].path_len]); + CORD leaf = pe -> pe_cord; + struct Function * f = &(((CordRep *)leaf) -> function); + + if (!IS_FUNCTION(leaf)) ABORT("CORD_pos_fetch: bad leaf"); return ((*(f -> fn))(p[0].cur_pos - pe -> pe_start_pos, f -> client_data)); } void CORD__next(CORD_pos p) { size_t cur_pos = p[0].cur_pos + 1; - struct CORD_pe * current_pe; - CORD leaf; - - if (!CORD_pos_valid(p)) - ABORT("CORD_next: invalid argument"); - current_pe = &p[0].path[p[0].path_len]; - leaf = current_pe -> pe_cord; + struct CORD_pe * current_pe = &((p)[0].path[(p)[0].path_len]); + CORD leaf = current_pe -> pe_cord; /* Leaf is not a string or we're at end of leaf */ p[0].cur_pos = cur_pos; diff --git a/gc/cord/cordprnt.c b/gc/cord/cordprnt.c index 7eaf3723a..d9d9f5365 100644 --- a/gc/cord/cordprnt.c +++ b/gc/cord/cordprnt.c @@ -52,7 +52,7 @@ static int ec_len(CORD_ec x) { - return (int)(CORD_len(x[0].ec_cord) + (x[0].ec_bufptr - x[0].ec_buf)); + return(CORD_len(x[0].ec_cord) + (x[0].ec_bufptr - x[0].ec_buf)); } /* Possible nonumeric precision values. */ @@ -232,7 +232,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args) } else { short * pos_ptr; pos_ptr = va_arg(args, short *); - *pos_ptr = (short)ec_len(result); + *pos_ptr = ec_len(result); } goto done; case 'r': @@ -241,18 +241,18 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args) if (prec == VARIABLE) prec = va_arg(args, int); arg = va_arg(args, CORD); len = CORD_len(arg); - if (prec != NONE && len > (unsigned)prec) { + if (prec != NONE && len > (size_t)prec) { if (prec < 0) return(-1); - arg = CORD_substr(arg, 0, (unsigned)prec); + arg = CORD_substr(arg, 0, prec); len = (unsigned)prec; } - if (width != NONE && len < (unsigned)width) { - char * blanks = (char *)GC_MALLOC_ATOMIC( - (unsigned)width - len + 1); + if (width != NONE && len < (size_t)width) { + char * blanks = + (char *)GC_MALLOC_ATOMIC(width - len + 1); if (NULL == blanks) OUT_OF_MEMORY; - memset(blanks, ' ', (unsigned)width - len); - blanks[(unsigned)width - len] = '\0'; + memset(blanks, ' ', width-len); + blanks[width-len] = '\0'; if (left_adj) { arg = CORD_cat(arg, blanks); } else { @@ -307,7 +307,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args) if (prec != NONE && prec > max_size) max_size = prec; max_size += CONV_RESULT_LEN; if (max_size >= CORD_BUFSZ) { - buf = (char *)GC_MALLOC_ATOMIC((unsigned)max_size + 1); + buf = (char *)GC_MALLOC_ATOMIC(max_size + 1); if (NULL == buf) OUT_OF_MEMORY; } else { if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf) @@ -352,7 +352,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args) && !defined(__EMX__)) va_end(vsprintf_args); # endif - len = (unsigned)res; + len = (size_t)res; if ((char *)(GC_word)res == buf) { /* old style vsprintf */ len = strlen(buf); diff --git a/gc/cord/tests/cordtest.c b/gc/cord/tests/cordtest.c index a41600c0f..c3ad01f42 100644 --- a/gc/cord/tests/cordtest.c +++ b/gc/cord/tests/cordtest.c @@ -40,8 +40,7 @@ int count; int test_fn(char c, void * client_data) { - if (client_data != (void *)(GC_word)13) - ABORT("bad client data"); + if (client_data != (void *)13) ABORT("bad client data"); if (count < 64*1024+1) { if ((count & 1) == 0) { if (c != 'b') ABORT("bad char"); @@ -66,7 +65,7 @@ char id_cord_fn(size_t i, void * client_data) void test_basics(void) { CORD x = CORD_from_char_star("ab"); - size_t i; + int i; CORD y; CORD_pos p; @@ -82,8 +81,7 @@ void test_basics(void) if (CORD_len(x) != 128*1024+1) ABORT("bad length"); count = 0; - if (CORD_iter5(x, 64*1024-1, test_fn, CORD_NO_FN, - (void *)(GC_word)13) == 0) { + if (CORD_iter5(x, 64*1024-1, test_fn, CORD_NO_FN, (void *)13) == 0) { ABORT("CORD_iter5 failed"); } if (count != 64*1024 + 2) ABORT("CORD_iter5 failed"); @@ -91,7 +89,7 @@ void test_basics(void) count = 0; CORD_set_pos(p, x, 64*1024-1); while(CORD_pos_valid(p)) { - (void)test_fn(CORD_pos_fetch(p), (void *)(GC_word)13); + (void) test_fn(CORD_pos_fetch(p), (void *)13); CORD_next(p); } if (count != 64*1024 + 2) ABORT("Position based iteration failed"); @@ -115,8 +113,7 @@ void test_basics(void) if (CORD_len(x) != 128*1024+1) ABORT("bad length"); count = 0; - if (CORD_iter5(x, 64*1024-1, test_fn, CORD_NO_FN, - (void *)(GC_word)13) == 0) { + if (CORD_iter5(x, 64*1024-1, test_fn, CORD_NO_FN, (void *)13) == 0) { ABORT("CORD_iter5 failed"); } if (count != 64*1024 + 2) ABORT("CORD_iter5 failed"); @@ -131,8 +128,7 @@ void test_basics(void) while(CORD_pos_valid(p)) { char c = CORD_pos_fetch(p); - if ((size_t)(unsigned char)c != i) - ABORT("Traversal of function node failed"); + if(c != i) ABORT("Traversal of function node failed"); CORD_next(p); i++; } @@ -315,8 +311,6 @@ int main(void) # ifndef NO_INCREMENTAL GC_enable_incremental(); # endif - if (GC_get_find_leak()) - printf("This test program is not designed for leak detection mode\n"); test_basics(); test_extras(); test_printf(); diff --git a/gc/cord/tests/de.c b/gc/cord/tests/de.c index 2707405a1..0d0dc5f49 100644 --- a/gc/cord/tests/de.c +++ b/gc/cord/tests/de.c @@ -596,7 +596,6 @@ int main(int argc, char **argv) cshow(stdout); argc = ccommand(&argv); # endif - GC_set_find_leak(0); /* app is not for testing leak detection mode */ GC_INIT(); # ifndef NO_INCREMENTAL GC_enable_incremental(); diff --git a/gc/cord/tests/de_win.c b/gc/cord/tests/de_win.c index 82f4c71d9..62cff6525 100644 --- a/gc/cord/tests/de_win.c +++ b/gc/cord/tests/de_win.c @@ -18,8 +18,6 @@ * * This was written by a nonexpert windows programmer. */ -#if defined(__BORLANDC__) || defined(__CYGWIN__) || defined(__MINGW32__) \ - || defined(__NT__) || defined(_WIN32) || defined(WIN32) #ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN 1 @@ -53,7 +51,6 @@ int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, WNDCLASS wndclass; HACCEL hAccel; - GC_set_find_leak(0); GC_INIT(); # ifndef NO_INCREMENTAL GC_enable_incremental(); @@ -147,7 +144,7 @@ char * plain_chars(char * text, size_t len) } /* Return the argument with all non-control-characters replaced by */ -/* blank, and all control characters c replaced by c + 64. */ +/* blank, and all control characters c replaced by c + 32. */ char * control_chars(char * text, size_t len) { char * result = (char *)GC_MALLOC_ATOMIC(len + 1); @@ -156,7 +153,7 @@ char * control_chars(char * text, size_t len) if (NULL == result) return NULL; for (i = 0; i < len; i++) { if (iscntrl(((unsigned char *)text)[i])) { - result[i] = (char)(text[i] + 0x40); + result[i] = text[i] + 0x40; } else { result[i] = ' '; } @@ -377,11 +374,3 @@ void invalidate_line(int i) get_line_rect(i, COLS*char_width, &line_r); InvalidateRect(hwnd, &line_r, FALSE); } - -#else - - extern int GC_quiet; - /* ANSI C doesn't allow translation units to be empty. */ - /* So we guarantee this one is nonempty. */ - -#endif /* !WIN32 */ diff --git a/gc/darwin_stop_world.c b/gc/darwin_stop_world.c index 3dbaa3fb7..ab0be9d8f 100644 --- a/gc/darwin_stop_world.c +++ b/gc/darwin_stop_world.c @@ -196,12 +196,10 @@ STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p, /* else */ { mach_msg_type_number_t thread_state_count = GC_MACH_THREAD_STATE_COUNT; - /* Get the thread state (registers, etc.) */ - do { - kern_result = thread_get_state(thread, GC_MACH_THREAD_STATE, - (natural_t *)&state, - &thread_state_count); - } while (kern_result == KERN_ABORTED); + /* Get the thread state (registers, etc) */ + kern_result = thread_get_state(thread, GC_MACH_THREAD_STATE, + (natural_t *)&state, + &thread_state_count); } # ifdef DEBUG_THREADS GC_log_printf("thread_get_state returns value = %d\n", kern_result); @@ -658,8 +656,7 @@ GC_INLINE void GC_thread_resume(thread_act_t thread) kern_return_t kern_result; # if defined(DEBUG_THREADS) || defined(GC_ASSERTIONS) struct thread_basic_info info; - mach_msg_type_number_t outCount = THREAD_BASIC_INFO_COUNT; - + mach_msg_type_number_t outCount = THREAD_INFO_MAX; kern_result = thread_info(thread, THREAD_BASIC_INFO, (thread_info_t)&info, &outCount); if (kern_result != KERN_SUCCESS) diff --git a/gc/dbg_mlc.c b/gc/dbg_mlc.c index 920da6ce0..4d547c150 100644 --- a/gc/dbg_mlc.c +++ b/gc/dbg_mlc.c @@ -287,7 +287,7 @@ GC_INNER void *GC_store_debug_info_inner(void *p, word sz GC_ATTR_UNUSED, ((oh *)p) -> oh_bg_ptr = HIDE_BACK_PTR((ptr_t)0); # endif ((oh *)p) -> oh_string = string; - ((oh *)p) -> oh_int = linenum; + ((oh *)p) -> oh_int = (word)linenum; # ifndef SHORT_DBG_HDRS ((oh *)p) -> oh_sz = sz; ((oh *)p) -> oh_sf = START_FLAG ^ (word)result; diff --git a/gc/digimars.mak b/gc/digimars.mak index 1388d3539..40d6e143e 100644 --- a/gc/digimars.mak +++ b/gc/digimars.mak @@ -2,7 +2,7 @@ # compiler from www.digitalmars.com # Written by Walter Bright -DEFINES=-D_WINDOWS -DGC_DLL -DGC_THREADS -DGC_DISCOVER_TASK_THREADS -DALL_INTERIOR_POINTERS -DENABLE_DISCLAIM -DGC_ATOMIC_UNCOLLECTABLE -DGC_GCJ_SUPPORT -DJAVA_FINALIZATION -DNO_EXECUTE_PERMISSION -DUSE_MUNMAP +DEFINES=-D_WINDOWS -DGC_DLL -DGC_THREADS -DGC_DISCOVER_TASK_THREADS -DALL_INTERIOR_POINTERS -DENABLE_DISCLAIM CFLAGS=-Iinclude -Ilibatomic_ops\src $(DEFINES) -wx -g LFLAGS=/ma/implib/co CC=sc @@ -23,7 +23,6 @@ OBJS= \ dyn_load.obj\ finalize.obj\ gc_cpp.obj\ - gcj_mlc.obj\ headers.obj\ mach_dep.obj\ malloc.obj\ diff --git a/gc/doc/README.OS2 b/gc/doc/README.OS2 index 5aaf84c04..5345bbd0f 100644 --- a/gc/doc/README.OS2 +++ b/gc/doc/README.OS2 @@ -2,5 +2,5 @@ The code assumes static linking, and a single thread. The editor de has not been ported. The cord test program has. The supplied OS2_MAKEFILE assumes the IBM C Set/2 environment, but the code shouldn't. -Since we haven't figured out how to do partial linking or to build static +Since we haven't figured out hoe to do perform partial links or to build static libraries, clients currently need to link against a long list of executables. diff --git a/gc/doc/README.amiga b/gc/doc/README.amiga index 65ade9a0a..d97251fb4 100644 --- a/gc/doc/README.amiga +++ b/gc/doc/README.amiga @@ -9,15 +9,15 @@ updated 'Makefile', and hope it compiles fine. WHATS NEW: 1. - Made a pretty big effort in preventing GC allocating-functions from - returning chip-mem. + Made a pretty big effort in preventing GCs allocating-functions from returning + chip-mem. The lower part of the new file AmigaOS.c does this in various ways, mainly by wrapping GC_malloc, GC_malloc_atomic, GC_malloc_uncollectable, GC_malloc_atomic_uncollectable, GC_malloc_ignore_off_page and GC_malloc_atomic_ignore_off_page. GC_realloc is also wrapped, but doesn't do the same effort in preventing to return chip-mem. - Other allocating-functions (e.g., GC_*_typed) can probably be + Other allocating-functions (f.ex. GC_*_typed_) can probably be used without any problems, but beware that the warn hook will not be called. In case of problems, don't define GC_AMIGA_FASTALLOC. @@ -81,7 +81,7 @@ WHATS NEW: GC_AMIGA_FASTALLOC by letting the function go thru the new GC_amiga_allocwrapper_do function-pointer (see gc.h). Means that sending function-pointers, such as GC_malloc, GC_malloc_atomic, etc., - for later to be called, e.g., like this, (*GC_malloc_function_pointer)(size), + for later to be called like f.ex this, (*GC_malloc_function_pointer)(size), will not wrap the function. This is normally not a big problem, unless all allocation function is called like this, which will cause the atexit un-allocating function never to be called. Then you either @@ -91,7 +91,7 @@ WHATS NEW: There are probably better ways this problem could be handled, unfortunately, I didn't find any without rewriting or replacing a lot of the GC-code, which I really didn't want to. (Making new GC_malloc_* functions, and just - defining, e.g., GC_malloc as GC_amiga_malloc should work too). + define f.ex GC_malloc as GC_amiga_malloc should work too). New Amiga-specific function: @@ -99,16 +99,16 @@ WHATS NEW: void GC_amiga_set_toany(void (*func)(void)); 'func' is a function that will be called right before gc has to change - allocation-method from MEMF_FAST to MEMF_ANY. I.e., when it is likely + allocation-method from MEMF_FAST to MEMF_ANY. Ie. when it is likely it will return chip-mem. 2. A few small compiler-specific additions to make it compile with SAS/C again. -3. Updated and rewritten the SMakefile.amiga, so that it works again and that +3. Updated and rewritten the smakefile, so that it works again and that the "unnecessary" 'SCOPTIONS' files could be removed. Also included the cord-smakefile stuff in the main smakefile, so that the cord smakefile - could be removed too. By typing "smake -f SMakefile.amiga", both gc.lib and + could be removed too. By writing smake -f Smakefile.smk, both gc.lib and cord.lib will be made. @@ -246,10 +246,10 @@ the SAS/C commercial development system. In keeping with the porting philosophy outlined above, this port will not behave well with Amiga specific code. Especially not inter- -process communications via messages, and setting up public structures like +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-compliant code. (i.e., 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 diff --git a/gc/doc/README.cmake b/gc/doc/README.cmake index 4c5894b85..e691fa952 100644 --- a/gc/doc/README.cmake +++ b/gc/doc/README.cmake @@ -47,4 +47,4 @@ INPUT ----- The main input to cmake are the CMakeLists.txt files in each directory. For -help, go to cmake.org. +help, goto cmake.org. diff --git a/gc/doc/README.darwin b/gc/doc/README.darwin index 7b5a3e7ac..2727d0b15 100644 --- a/gc/doc/README.darwin +++ b/gc/doc/README.darwin @@ -36,6 +36,11 @@ if you have an application or set of libraries that all use the garbage collector, to create an initialization routine for each of them that calls GC_init(). Better safe than sorry. +The incremental collector is still a bit flaky on darwin. It seems to +work reliably with workarounds for a few possible bugs in place however +these workaround may not work correctly in all cases. There may also +be additional problems that I have not found. + Thread-local GC allocation will not work with threads that are not created using the GC-provided override of pthread_create(). Threads created without the GC-provided pthread_create() do not have the @@ -71,11 +76,69 @@ programs that use JNI. If you run code that does not follow the stack layout or stack pointer conventions laid out in the PPC Mach-O ABI, then this will likely crash the garbage collector. -Mach has a very clean interface to exception handing. So, the current -implementation of the incremental collection uses Mach's exception handling. +The original incremental collector support unfortunately no longer works +on recent Darwin versions. It also relied on some undocumented kernel +structures. Mach, however, does have a very clean interface to exception +handing. The current implementation uses Mach's exception handling. Much thanks goes to Andrew Stone, Dietmar Planitzer, Andrew Begel, Jeff Sturm, and Jesse Rosenstock for all their work on the Darwin/OS X port. -Brian Alliet + +== gc_cpp.h usage == + +Replacement of operator new and delete is apparently not supported with +dynamic libraries. This means that applications using gc_cpp.h +(including the built-in test) will probably not work correctly with +the collector in a dynamic library, unless special care is taken. + +See +http://article.gmane.org/gmane.comp.programming.garbage-collection.boehmgc/1421 +for some details. + +- Hans Boehm (based on information from Andrew Begel) + + +== Older Information (Most of this no longer applies to the current code) == + +While the GC should work on MacOS X Server, MacOS X and Darwin, I only tested +it on MacOS X Server. +I've added a PPC assembly version of GC_push_regs(), thus the setjmp() hack is +no longer necessary. Incremental collection is supported via mprotect/signal. +The current solution isn't really optimal because the signal handler must decode +the faulting PPC machine instruction in order to find the correct heap address. +Further, it must poke around in the register state which the kernel saved away +in some obscure register state structure before it calls the signal handler - +needless to say the layout of this structure is no where documented. +Threads and dynamic libraries are not yet supported (adding dynamic library +support via the low-level dyld API shouldn't be that hard). + +The original MacOS X port was brought to you by Andrew Stone. + + +June, 1 2000 + +Dietmar Planitzer + +Note from Andrew Begel: + +One more fix to enable gc.a to link successfully into a shared library for +MacOS X. You have to add -fno-common to the CFLAGS in the Makefile. MacOSX +disallows common symbols in anything that eventually finds its way into a +shared library. (I don't completely understand why, but -fno-common seems to +work and doesn't mess up the garbage collector's functionality). + +Feb 26, 2003 + +Jeff Sturm and Jesse Rosenstock provided a patch that adds thread support. +GC_THREADS should be defined in the build and in clients. Real +dynamic library support is still missing, i.e. dynamic library data segments +are still not scanned. Code that stores pointers to the garbage collected +heap in statically allocated variables should not reside in a dynamic +library. This still doesn't appear to be 100% reliable. + +Mar 10, 2003 +Brian Alliet contributed dynamic library support for MacOSX. It could also +use more testing. diff --git a/gc/doc/README.ews4800 b/gc/doc/README.ews4800 index 83e8b1e07..da4cff398 100644 --- a/gc/doc/README.ews4800 +++ b/gc/doc/README.ews4800 @@ -24,7 +24,7 @@ GC on EWS4800 *** Caution: The following information is empirical. *** 32-bit: - ELF file has a unique format. (See a.out(4) and end(3C).) + ELF file has an unique format. (See a.out(4) and end(3C).) &_start : text segment diff --git a/gc/doc/README.macros b/gc/doc/README.macros index bd3383383..b16198b1c 100644 --- a/gc/doc/README.macros +++ b/gc/doc/README.macros @@ -22,7 +22,7 @@ instead of features. In many cases, this is a mistake. Many of the tested configuration macros are at least somewhat defined in either include/private/gcconfig.h or in Makefile.direct. Here is an attempt at documenting these macros: (Thanks to Walter Bright for suggesting -this.) +this. This is a work in progress) MACRO EXPLANATION ----- ----------- @@ -57,10 +57,6 @@ _ENABLE_ARRAYNEW operator new[] and delete[] are separately overloadable. Used in gc_cpp.h. -GC_NO_INLINE_STD_NEW Tested by gc_cpp.cc and gc_cpp.h. MS Windows only. - Define the system-wide new and delete operators in gccpp.dll - instead of providing an inline version of the operators. - _DLL Tested by gc_config_macros.h. Defined by Visual C++ if runtime dynamic libraries are in use. Used (only if none of GC_DLL, GC_NOT_DLL, __GNUC__ are defined) to test whether @@ -208,11 +204,10 @@ DONT_ADD_BYTE_AT_END Meaningful only with ALL_INTERIOR_POINTERS or NO_EXECUTE_PERMISSION May cause some or all of the heap to not have execute permission, i.e. it may be impossible to execute - code from the heap. Affects the incremental collector and memory unmapping. - It may greatly improve the performance, since this may avoid some expensive - cache synchronization. Portable clients should call - GC_set_pages_executable(1) at the process initialization time if the - execute permission is required. + code from the heap. Currently this only affects the incremental + collector on UNIX machines. It may greatly improve its performance, + since this may avoid some expensive cache synchronization. Alternatively, + GC_set_pages_executable can be called at the process initialization time. GC_NO_OPERATOR_NEW_ARRAY Declares that the C++ compiler does not support the new syntax "operator new[]" for allocating and deleting arrays. diff --git a/gc/doc/README.solaris2 b/gc/doc/README.solaris2 index 2bc56dd8a..b150f9c27 100644 --- a/gc/doc/README.solaris2 +++ b/gc/doc/README.solaris2 @@ -61,7 +61,7 @@ delete.) I encountered "symbol : 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 toolchain. (As a non-Solaris-expert +The fix appears to be to use a consistent tool chain. (As a non-Solaris-expert my solution involved hacking the libtool script, but I'm sure you can do something less ugly.) diff --git a/gc/doc/README.win32 b/gc/doc/README.win32 index de4ef7628..aa81e66ec 100644 --- a/gc/doc/README.win32 +++ b/gc/doc/README.win32 @@ -114,7 +114,7 @@ Note that all compilations were done under Windows 95 or NT. For unknown reason compiling under Windows 3.11 for NT (one attempt has been made) leads to broken executables. -Incremental collection is supported (except for MSDOS and OS/2). +Incremental collection is not supported. cord is not ported. diff --git a/gc/doc/finalization.md b/gc/doc/finalization.md index 75428cd68..13c14afba 100644 --- a/gc/doc/finalization.md +++ b/gc/doc/finalization.md @@ -51,7 +51,7 @@ In single-threaded code, it is also often easiest to have finalizers queue actions, which are then explicitly run during an explicit call by the user's program. -## Topologically ordered finalization +# Topologically Ordered Finalization Our _conservative garbage collector_ supports a form of finalization (with `GC_register_finalizer`) in which objects are finalized in topological order. @@ -67,7 +67,7 @@ making it accessible again. Or it may mutate the rest of the chain. Cycles involving one or more finalizable objects are never finalized. -## Why topological ordering? +# Why topological ordering? It is important to keep in mind that the choice of finalization ordering matters only in relatively rare cases. In spite of the fact that it has @@ -123,7 +123,7 @@ finalization simply extends this to object finalization; an finalizable object reachable from another finalizer via a pointer chain is presumed to be accessible by the finalizer, and thus should not be finalized. -## Programming with topological finalization +# Programming with topological finalization Experience with Cedar has shown that cycles or long chains of finalizable objects are typically not a problem. Finalizable objects are typically rare. @@ -141,7 +141,7 @@ cleared by the finalization procedure that deallocates the resource). If any references are still left at process exit, they can be explicitly deallocated then. -## Getting around topological finalization ordering +# Getting around topological finalization ordering There are certain situations in which cycles between finalizable objects are genuinely unavoidable. Most notably, C++ compilers introduce self-cycles diff --git a/gc/doc/gcdescr.md b/gc/doc/gcdescr.md index cc2354529..fbc020857 100644 --- a/gc/doc/gcdescr.md +++ b/gc/doc/gcdescr.md @@ -36,7 +36,7 @@ of a memory allocation: to be reachable from variables are again scanned similarly. 3. _Sweep phase_ Scans the heap for inaccessible, and hence unmarked, objects, and returns them to an appropriate free list for reuse. This is not - really a separate phase; even in non-incremental mode this operation + really a separate phase; even in non incremental mode this is operation is usually performed on demand during an allocation that discovers an empty free list. Thus the sweep phase is very unlikely to touch a page that would not have been touched shortly thereafter anyway. @@ -132,7 +132,7 @@ of fragmentation. In particular: * Programs with a large root set size and little live heap memory will expand the heap to amortize the cost of scanning the roots. - * GC v5 actually collects more frequently in non-incremental mode. The large + * GC v5 actually collect more frequently in non-incremental mode. The large block allocator usually refuses to split large heap blocks once the garbage collection threshold is reached. This often has the effect of collecting well before the heap fills up, thus reducing fragmentation and working set @@ -203,19 +203,18 @@ progression of mark states for a stop-the-world collection is: objects, roots, and then mark everything reachable from them. `scan_ptr` is advanced through the heap until all uncollectible objects are pushed, and objects reachable from them are marked. At that point, the next call - to `GC_mark_some` calls `GC_push_roots` to push the roots. It, then, - advances the mark state to + to `GC_mark_some` calls `GC_push_roots` to push the roots. It the advances + the mark state to 3. `MS_ROOTS_PUSHED` asserting that once the mark stack is empty, all reachable objects are marked. Once in this state, we work only on emptying the mark stack. Once this is completed, the state changes to - 4. `MS_NONE` indicating that reachable objects are marked. - -The core mark routine `GC_mark_from`, is called repeatedly by several of the -sub-phases when the mark stack starts to fill up. It is also called repeatedly -in `MS_ROOTS_PUSHED` state to empty the mark stack. The routine is designed -to only perform a limited amount of marking at 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. + 4. `MS_NONE` indicating that reachable objects are marked. The core mark + routine `GC_mark_from`, is called repeatedly by several of the sub-phases + when the mark stack starts to fill up. It is also called repeatedly + in `MS_ROOTS_PUSHED` state to empty the mark stack. The routine is designed + to only perform a limited amount of marking at 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. 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 @@ -256,7 +255,7 @@ block. This is done in the following steps: the page is not part of the garbage collected heap, a small integer _n_, indicating that the page is part of large object, starting at least _n_ pages back, or a pointer to a descriptor for the page. In the first case, - the candidate pointer is not a true pointer and can be safely ignored. + the candidate pointer `i` not a true pointer and can be safely ignored. In the last two cases, we can obtain a descriptor for the page containing the beginning of the object. * The starting address of the referenced object is computed. The page @@ -507,7 +506,7 @@ is otherwise similar to the global free lists. The local free lists are also linked using the first word in the object. In most cases this means they require considerably less time. -Local free lists are treated by most of the rest of the collector as though +Local free lists are treated buy most of the rest of the collector as though they were in-use reachable data. This requires some care, since pointer-free objects are not normally traced, and hence a special tracing procedure is required to mark all objects on pointer-free and gcj local free lists. diff --git a/gc/doc/gcinterface.md b/gc/doc/gcinterface.md index fbada0041..4e7d309b7 100644 --- a/gc/doc/gcinterface.md +++ b/gc/doc/gcinterface.md @@ -1,7 +1,7 @@ # C/C++ Interface On many platforms, a single-threaded garbage collector library can be built -to act as a plug-in `malloc` replacement. (Build it with +to act as a plug-in `malloc` replacement. (Build with `-DREDIRECT_MALLOC=GC_malloc -DIGNORE_FREE`.) This is often the best way to deal with third-party libraries which leak or prematurely free objects. `-DREDIRECT_MALLOC=GC_malloc` is intended primarily as an easy way to adapt @@ -55,15 +55,15 @@ object for pointers to garbage-collectible memory, even if the block itself does not appear to be reachable. (Objects allocated in this way are effectively treated as roots by the collector.) -**void * `GC_REALLOC`(void * _old_, size_t _new_size_)** - Allocates a new +**void * `GC_REALLOC`(void * _old_, size_t _new_size_)** - Allocate a new object of the indicated size and copy (a prefix of) the old object into the new object. The old object is reused in place if convenient. If the original object was allocated with `GC_MALLOC_ATOMIC`, the new object is subject to the same constraints. If it was allocated as an uncollectible object, then the new object is uncollectible, and the old object (if different) is deallocated. -**void `GC_FREE`(void * _dead_)** - Explicitly deallocates an object. -Typically not useful for small collectible objects. +**void `GC_FREE`(void * _dead_)** - Explicitly deallocate an object. Typically +not useful for small collectible objects. **void * `GC_MALLOC_IGNORE_OFF_PAGE`(size_t _nbytes_)** and **void * `GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE`(size_t _nbytes_)** - Analogous @@ -84,9 +84,9 @@ code, though we try to ensure that it expands to a no-op on as many platforms as possible. In GC v7.0, it was required if thread-local allocation is enabled in the collector build, and `malloc` is not redirected to `GC_malloc`. -**void `GC_gcollect`(void)** - Explicitly forces a garbage collection. +**void `GC_gcollect`(void)** - Explicitly force a garbage collection. -**void `GC_enable_incremental`(void)** - Causes the garbage collector +**void `GC_enable_incremental`(void)** - Cause the garbage collector to perform a small amount of work every few invocations of `GC_MALLOC` or the like, instead of performing an entire collection at once. This is likely to increase total running time. It will improve response on a platform that @@ -94,13 +94,13 @@ either has suitable support in the garbage collector (Linux and most Unix versions, Win32 if the collector was suitably built). On many platforms this interacts poorly with system calls that write to the garbage collected heap. -**void `GC_set_warn_proc`(GC_warn_proc)** - Replaces the default procedure +**void `GC_set_warn_proc`(GC_warn_proc)** - Replace the default procedure used by the collector to print warnings. The collector may otherwise write to `stderr`, most commonly because `GC_malloc` was used in a situation in which `GC_malloc_ignore_off_page` would have been more appropriate. See `gc.h` for details. -**void `GC_REGISTER_FINALIZER`(...)** - Registers a function to be called when +**void `GC_REGISTER_FINALIZER`(...)** - Register a function to be called when an object becomes inaccessible. This is often useful as a backup method for releasing system resources (e.g. closing files) when the object referencing them becomes inaccessible. It is not an acceptable method to perform actions @@ -189,8 +189,8 @@ discouraged. This defines SGI-style allocators - * `traceable_alloc` - * `single_client_traceable_alloc` + * `alloc` + * `single_client_alloc` * `gc_alloc` * `single_client_gc_alloc` @@ -207,7 +207,7 @@ in garbage collectible memory by having those classes inherit from class `gc`. For details see `gc_cpp.h` file. Linking against `libgccpp` in addition to the `gc` library overrides `::new` -(and friends) to allocate traceable but uncollectible memory, making +(and friends) to allocate traceable memory but uncollectible memory, making it safe to refer to collectible objects from the resulting memory. ## C interface diff --git a/gc/doc/leak.md b/gc/doc/leak.md index 76456aa56..7d62af7bd 100644 --- a/gc/doc/leak.md +++ b/gc/doc/leak.md @@ -4,7 +4,7 @@ The garbage collector may be used as a leak detector. In this case, the primary function of the collector is to report objects that were allocated (typically with `GC_MALLOC`), not deallocated (normally with `GC_FREE`), but are no longer accessible. Since the object is no longer accessible, there -is normally no way to deallocate the object at a later time; thus it can +in normally no way to deallocate the object at a later time; thus it can safely be assumed that the object has been "leaked". This is substantially different from counting leak detectors, which simply @@ -35,15 +35,13 @@ To use the collector as a leak detector, follow the following steps: the garbage collector. 3. Arrange to call `GC_gcollect` at appropriate points to check for leaks. (For sufficiently long running programs, this will happen implicitly, but - probably not with sufficient frequency.) - -The second step can usually be accomplished with the -`-DREDIRECT_MALLOC=GC_malloc` option when the collector is built, or by -defining `malloc`, `calloc`, `realloc` and `free` to call the corresponding -garbage collector functions. But this, by itself, will not yield very -informative diagnostics, since the collector does not keep track of -information about how objects were allocated. The error reports will include -only object addresses. + probably not with sufficient frequency.) The second step can usually + be accomplished with the `-DREDIRECT_MALLOC=GC_malloc` option when the + collector is built, or by defining `malloc`, `calloc`, `realloc` and `free` + to call the corresponding garbage collector functions. But this, by itself, + will not yield very informative diagnostics, since the collector does not + keep track of information about how objects were allocated. The error + reports will include only object addresses. For more precise error reports, as much of the program as possible should use the all uppercase variants of these functions, after defining `GC_DEBUG`, and @@ -137,28 +135,25 @@ detection mode on a program a.out under Linux/X86 as follows: debug information. This will improve the quality of the leak reports. With this approach, it is no longer necessary to call `GC_` routines explicitly, though that can also improve the quality of the leak reports. - 4. Build the collector and install it in directory _foo_ as follows (it may - be safe to omit the `--disable-threads` option on Linux, but the combination - of thread support and `malloc` replacement is not yet rock solid): - - - `configure --prefix=_foo_ --enable-gc-debug --enable-redirect-malloc --disable-threads` - - `make` - - `make install` - - 5. Set environment variables as follows (the last two are optional, just to - confirm the collector is running, and to facilitate debugging from another - console window if something goes wrong, respectively): - - - `LD_PRELOAD=_foo_/lib/libgc.so` - - `GC_FIND_LEAK` - - `GC_PRINT_STATS` - - `GC_LOOP_ON_ABORT` - + 4. Build the collector and install it in directory _foo_ as follows: + * `configure --prefix=_foo_ --enable-gc-debug --enable-redirect-malloc --disable-threads` + * `make` + * `make install` + + With a very recent collector on Linux, it may sometimes be safe to omit + the `--disable-threads`. But the combination of thread support and + `malloc` replacement is not yet rock solid. + 5. Set environment variables as follows: + * `LD_PRELOAD=`_foo_`/lib/libgc.so` + * `GC_FIND_LEAK` + + You may also want to set `GC_PRINT_STATS` (to confirm that the collector + is running) and/or `GC_LOOP_ON_ABORT` (to facilitate debugging from + another window if something goes wrong). 6. Simply run `a.out` as you normally would. Note that if you run anything else (e.g. your editor) with those environment variables set, it will also be leak tested. This may or may not be useful and/or embarrassing. It can generate mountains of leak reports if the application was not designed - to avoid leaks, e.g. because it's always short-lived. - -This has not yet been thoroughly tested on large applications, but it's known -to do the right thing on at least some small ones. + to avoid leaks, e.g. because it's always short-lived. This has not yet + been thoroughly tested on large applications, but it's known to do the right + thing on at least some small ones. diff --git a/gc/doc/overview.md b/gc/doc/overview.md index f4f9a017f..fb3aa2a4e 100644 --- a/gc/doc/overview.md +++ b/gc/doc/overview.md @@ -130,7 +130,7 @@ We also expect that in many cases any additional overhead will be more than compensated for by decreased copying etc. if programs are written and tuned for garbage collection. -## Further reading +# Further Reading: **The beginnings of a frequently asked questions list for this collector are [here](http://www.hboehm.info/gc/faq.html)**. @@ -164,7 +164,7 @@ is a related letter to the editor and a minor correction in the next issue. Boehm, H., and [M. Weiser](http://www.ubiq.com/hypertext/weiser/weiser.html), [Garbage Collection in an Uncooperative Environment](http://www.hboehm.info/spe_gc_paper/), -_Software Practice and Experience_, September 1988, pp. 807-820. +_Software Practice & Experience_, September 1988, pp. 807-820. Boehm, H., A. Demers, and S. Shenker, [Mostly Parallel Garbage Collection](http://www.hboehm.info/gc/papers/pldi91.ps.Z), @@ -239,7 +239,7 @@ Henry Baker's [paper collection](http://home.pipeline.com/%7Ehbaker1/). Slides for Hans Boehm's [Allocation and GC Myths](http://www.hboehm.info/gc/myths.ps) talk. -## Current users +# Current users: Known current users of some variant of this collector include: @@ -300,7 +300,7 @@ The [Vesta](http://www.vestasys.org/) configuration management system. [Asymptote LaTeX-compatible vector graphics language](http://asymptote.sf.net/). -## Information provided on the BDWGC site +# More information on the BDWGC primary site [A simple illustration of how to build and use the collector](simple_example.md). @@ -324,7 +324,7 @@ The [Vesta](http://www.vestasys.org/) configuration management system. files of all garbage collector releases. It duplicates [Download](https://github.com/ivmai/bdwgc/wiki/Download) page on GitHub. -## More background information +# More background information [An attempt to establish a bound on space usage of conservative garbage collectors](http://www.hboehm.info/gc/bounds.html). @@ -352,7 +352,7 @@ version). [Related papers](http://www.hboehm.info/gc/papers/). -## Contacts and new release announcements +# Contacts and new release announcements GitHub and Stack Overflow are the major two places for communication. diff --git a/gc/doc/porting.md b/gc/doc/porting.md index 7da0b7896..bc2b253c1 100644 --- a/gc/doc/porting.md +++ b/gc/doc/porting.md @@ -47,7 +47,6 @@ The `gcconfig.h` file consists of three sections: RISC variants.) On GNU-based systems, `cpp -dM empty_source_file.c` seems to generate a set of predefined macros. On some other systems, the "verbose" compiler option may do so, or the manual page may list them. - 2. A section that defines a small number of platform-specific macros, which are then used directly by the collector. For simple ports, this is where most of the effort is required. We describe the macros below. This section @@ -85,7 +84,7 @@ operating system: trace all memory between `DATASTART` and `DATAEND` for root pointers. On some platforms, this can be defined to a constant address, though experience has shown that to be risky. Ideally the linker will define - a symbol (e.g. `_data`) whose address is the beginning of the data segment. + a symbol (e.g. `_data` whose address is the beginning of the data segment. Sometimes the value can be computed using the `GC_SysVGetDataStart` function. Not used if either the next macro is defined, or if dynamic loading is supported, and the dynamic loading support defines a function @@ -115,8 +114,8 @@ operating system: three macros is defined, client code must explicitly set `GC_stackbottom` to an appropriate value before calling `GC_INIT` or any other `GC_` routine. * `LINUX_STACKBOTTOM` - May be defined instead of `STACKBOTTOM`. If defined, - then the cold end of the stack will be determined, we usually read it from - `/proc`. + then the cold end of the stack will be determined Currently we usually read + it from `/proc`. * `HEURISTIC1` - May be defined instead of `STACKBOTTOM`. `STACK_GRAN` should generally also be redefined. The cold end of the stack is determined by taking an address inside `GC_init`s frame, and rounding it up to the next @@ -155,7 +154,7 @@ or just tweaking of conditional compilation tests. For GC v7, if your platform supports `getcontext`, then defining the macro `UNIX_LIKE` for your OS in `gcconfig.h` (if it is not defined there yet) -is likely to solve the problem. Otherwise, if you are using gcc, +is likely to solve the problem. otherwise, if you are using gcc, `_builtin_unwind_init` will be used, and should work fine. If that is not applicable either, the implementation will try to use `setjmp`. This will work if your `setjmp` implementation saves all possibly pointer-valued registers @@ -227,7 +226,7 @@ If dynamic library data sections must also be traced, then: `gcconfig.h`. * An appropriate versions of the functions `GC_register_dynamic_libraries` should be defined in `dyn_load.c`. This function should invoke - `GC_cond_add_roots(region_start, region_end, TRUE)` on each dynamic + `GC_cond_add_roots(_region_start, region_end_, TRUE)` on each dynamic library data section. Implementations that scan for writable data segments are error prone, @@ -245,7 +244,7 @@ locking behavior in this case. For incremental and generational collection to work, `os_dep.c` must contain a suitable _virtual dirty bit_ implementation, which allows the collector -to track which heap pages (assumed to be a multiple of the collector's block +to track which heap pages (assumed to be a multiple of the collectors block size) have been written during a certain time interval. The collector provides several implementations, which might be adapted. The default (`DEFAULT_VDB`) is a placeholder which treats all pages as having been written. This ensures @@ -254,7 +253,7 @@ useless. ## Stack traces for debug support -If stack traces in objects are needed for debug support, `GC_save_callers` and +If stack traces in objects are need for debug support, `GC_dave_callers` and `GC_print_callers` must be implemented. ## Disclaimer diff --git a/gc/doc/scale.md b/gc/doc/scale.md index 2a3c69480..75fb635be 100644 --- a/gc/doc/scale.md +++ b/gc/doc/scale.md @@ -39,8 +39,7 @@ to be used together. is performed by the thread that triggered the collection, together with _N_ - 1 dedicated threads, where _N_ is the number of processors detected by the collector. The dedicated threads are created once at initialization - time (and optionally recreated in child processes after forking). - A second effect of this flag is to switch to a more concurrent + time. A second effect of this flag is to switch to a more concurrent implementation of `GC_malloc_many`, so that free lists can be built, and memory can be cleared, by more than one thread concurrently. * Building the collector with `-DTHREAD_LOCAL_ALLOC` adds support for @@ -143,10 +142,9 @@ These measurements do not use incremental collection, nor was prefetching enabled in the marker. We used the C version of the benchmark. All measurements are in elapsed seconds on an unloaded machine. -Number of client threads| 1 marker thread (secs.)| 2 marker threads (secs.) ----|------|----- - 1| 10.45| 7.85 - 2| 19.95| 12.3 +Number of threads| 1 marker thread (secs.) | 2 marker threads (secs.) +---|---|--- +1 client| 10.45| 7.85 | 2 clients| 19.95| 12.3 The execution time for the single threaded case is slightly worse than with simple locking. However, even the single-threaded benchmark runs faster than diff --git a/gc/doc/simple_example.md b/gc/doc/simple_example.md index 1fefc83b5..e19d56863 100644 --- a/gc/doc/simple_example.md +++ b/gc/doc/simple_example.md @@ -99,8 +99,7 @@ The following program `loop.c` is a trivial example: assert(*p == 0); *p = (int *) GC_REALLOC(q, 2 * sizeof(int)); if (i % 100000 == 0) - printf("Heap size = %lu bytes\n", - (unsigned long)GC_get_heap_size()); + printf("Heap size = %d\n", GC_get_heap_size()); } return 0; } diff --git a/gc/dyn_load.c b/gc/dyn_load.c index d857246b6..6692321c6 100644 --- a/gc/dyn_load.c +++ b/gc/dyn_load.c @@ -547,15 +547,11 @@ STATIC int GC_register_dynlib_callback(struct dl_phdr_info * info, 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 + GC_page_size - 1) & - ~(GC_page_size - 1))); + 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; - /* Note that start2 may be greater than end2 because of */ - /* p->p_memsz value multiple of page size. */ } break; } @@ -623,10 +619,10 @@ STATIC GC_bool GC_register_dynamic_libraries_dl_iterate_phdr(void) } else { ptr_t datastart, dataend; # ifdef DATASTART_IS_FUNC - static ptr_t datastart_cached = (ptr_t)GC_WORD_MAX; + static ptr_t datastart_cached = (ptr_t)(word)-1; /* Evaluate DATASTART only once. */ - if (datastart_cached == (ptr_t)GC_WORD_MAX) { + if (datastart_cached == (ptr_t)(word)-1) { datastart_cached = DATASTART; } datastart = datastart_cached; @@ -1218,7 +1214,7 @@ GC_INNER void GC_register_dynamic_libraries(void) #endif /* HPUX */ #ifdef AIX -# include +# pragma alloca # include # include GC_INNER void GC_register_dynamic_libraries(void) diff --git a/gc/extra/msvc_dbg.c b/gc/extra/msvc_dbg.c index c744aaa5e..8a72976be 100644 --- a/gc/extra/msvc_dbg.c +++ b/gc/extra/msvc_dbg.c @@ -22,7 +22,7 @@ #if !defined(_M_AMD64) && defined(_MSC_VER) -/* X86_64 is currently missing some machine-dependent code below. */ +/* X86_64 is currently missing some meachine-dependent code below. */ #define GC_BUILD #include "private/msvc_dbg.h" @@ -212,11 +212,6 @@ size_t GetModuleNameFromStack(size_t skip, char* moduleName, size_t size) return 0; } -union sym_namebuf_u { - IMAGEHLP_SYMBOL sym; - char symNameBuffer[sizeof(IMAGEHLP_SYMBOL) + MAX_SYM_NAME]; -}; - size_t GetSymbolNameFromAddress(void* address, char* symbolName, size_t size, size_t* offsetBytes) { @@ -224,8 +219,10 @@ size_t GetSymbolNameFromAddress(void* address, char* symbolName, size_t size, if (offsetBytes) *offsetBytes = 0; __try { ULONG_ADDR dwOffset = 0; - union sym_namebuf_u u; - + union { + IMAGEHLP_SYMBOL sym; + char symNameBuffer[sizeof(IMAGEHLP_SYMBOL) + MAX_SYM_NAME]; + } u; u.sym.SizeOfStruct = sizeof(u.sym); u.sym.MaxNameLength = sizeof(u.symNameBuffer) - sizeof(u.sym); @@ -315,7 +312,6 @@ size_t GetDescriptionFromAddress(void* address, const char* format, char*const end = buffer + size; size_t line_number = 0; - (void)format; if (size) { *buffer = 0; } @@ -336,7 +332,7 @@ size_t GetDescriptionFromAddress(void* address, const char* format, if (size) { strncpy(buffer, "at ", size)[size - 1] = 0; } - buffer += sizeof("at ") - 1; + buffer += strlen("at "); size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer; buffer += GetSymbolNameFromAddress(address, buffer, size, NULL); @@ -345,7 +341,7 @@ size_t GetDescriptionFromAddress(void* address, const char* format, if (size) { strncpy(buffer, " in ", size)[size - 1] = 0; } - buffer += sizeof(" in ") - 1; + buffer += strlen(" in "); size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer; buffer += GetModuleNameFromAddress(address, buffer, size); @@ -356,18 +352,18 @@ size_t GetDescriptionFromStack(void* const frames[], size_t count, const char* format, char* description[], size_t size) { - const GC_ULONG_PTR begin = (GC_ULONG_PTR)description; - const GC_ULONG_PTR end = begin + size; - GC_ULONG_PTR buffer = begin + (count + 1) * sizeof(char*); + char*const begin = (char*)description; + 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] = (char*)buffer; - buffer += 1 + GetDescriptionFromAddress(frames[i], format, (char*)buffer, - end < buffer ? 0 : end - 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) + if (size) description[count] = NULL; return buffer - begin; } diff --git a/gc/extra/pcr_interface.c b/gc/extra/pcr_interface.c index 7266c1b3e..ff4618743 100644 --- a/gc/extra/pcr_interface.c +++ b/gc/extra/pcr_interface.c @@ -150,8 +150,6 @@ PCR_GC_Setup(void) return PCR_ERes_okay; } -extern GC_bool GC_quiet; - PCR_ERes PCR_GC_Run(void) { diff --git a/gc/finalize.c b/gc/finalize.c index d52525fe6..64a0ec227 100644 --- a/gc/finalize.c +++ b/gc/finalize.c @@ -124,9 +124,7 @@ STATIC void GC_grow_table(struct hash_chain_entry ***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. */ - /* In incremental mode we skip this optimization, as we want to */ - /* avoid triggering a full GC whenever possible. */ - if (log_old_size >= GC_ON_GROW_LOG_SIZE_MIN && !GC_incremental) { + if (log_old_size >= GC_ON_GROW_LOG_SIZE_MIN) { IF_CANCEL(int cancel_state;) DISABLE_CANCEL(cancel_state); @@ -634,10 +632,6 @@ GC_API GC_await_finalize_proc GC_CALL GC_get_await_finalize_proc(void) /* Possible finalization_marker procedures. Note that mark stack */ /* overflow is handled by the caller, and is not a disaster. */ -#if defined(_MSC_VER) && defined(I386) - GC_ATTR_NOINLINE - /* Otherwise some optimizer bug is tickled in VC for X86 (v19, at least). */ -#endif STATIC void GC_normal_finalize_mark_proc(ptr_t p) { GC_mark_stack_top = GC_push_obj(p, HDR(p), GC_mark_stack_top, @@ -1332,7 +1326,7 @@ GC_INNER void GC_notify_or_invoke_finalizers(void) # ifdef KEEP_BACK_PTRS long i; /* Stops when GC_gc_no wraps; that's OK. */ - last_back_trace_gc_no = GC_WORD_MAX; /* disable others. */ + last_back_trace_gc_no = (word)(-1); /* disable others. */ for (i = 0; i < GC_backtraces; ++i) { /* FIXME: This tolerates concurrent heap mutation, */ /* which may cause occasional mysterious results. */ diff --git a/gc/fnlz_mlc.c b/gc/fnlz_mlc.c index 283566ee7..1e1a6ed02 100644 --- a/gc/fnlz_mlc.c +++ b/gc/fnlz_mlc.c @@ -45,7 +45,6 @@ STATIC int GC_CALLBACK GC_finalized_disclaim(void *obj) const struct GC_finalizer_closure *fc = (struct GC_finalizer_closure *)(fc_word & ~(word)FINALIZER_CLOSURE_FLAG); - GC_ASSERT(!GC_find_leak); (*fc->proc)((word *)obj + 1, fc->cd); } return 0; @@ -86,11 +85,8 @@ GC_API void GC_CALL GC_register_disclaim_proc(int kind, GC_disclaim_proc proc, { GC_ASSERT((unsigned)kind < MAXOBJKINDS); GC_ASSERT(NONNULL_ARG_NOT_NULL(proc)); - if (!EXPECT(GC_find_leak, FALSE)) { - GC_obj_kinds[kind].ok_disclaim_proc = proc; - GC_obj_kinds[kind].ok_mark_unconditionally = - (GC_bool)mark_unconditionally; - } + GC_obj_kinds[kind].ok_disclaim_proc = proc; + GC_obj_kinds[kind].ok_mark_unconditionally = (GC_bool)mark_unconditionally; } GC_API GC_ATTR_MALLOC void * GC_CALL GC_finalized_malloc(size_t lb, diff --git a/gc/gc.mak b/gc/gc.mak index 62b51f5f9..987dbb584 100644 --- a/gc/gc.mak +++ b/gc/gc.mak @@ -120,8 +120,7 @@ CPP=cl.exe # 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 /EHsc /O2 /I include /D "NDEBUG" /D "WIN32"\ /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "ENABLE_DISCLAIM"\ - /D "GC_ATOMIC_UNCOLLECTABLE" /D "GC_THREADS" /D "JAVA_FINALIZATION"\ - /D "NO_EXECUTE_PERMISSION" /D "_CRT_SECURE_NO_DEPRECATE"\ + /D "GC_THREADS" /D "_CRT_SECURE_NO_DEPRECATE"\ /FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch"\ /I./libatomic_ops/src /Fo"$(INTDIR)/" /c CPP_OBJS=.\Release/ @@ -310,10 +309,9 @@ CPP=cl.exe # 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 /EHsc /Zi /Od /I include /D "_DEBUG"\ /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "ENABLE_DISCLAIM"\ - /D "GC_ASSERTIONS" /D "GC_ATOMIC_UNCOLLECTABLE" /D "GC_THREADS"\ - /D "JAVA_FINALIZATION" /D "NO_EXECUTE_PERMISSION"\ - /D "_CRT_SECURE_NO_DEPRECATE" /FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch"\ - /Fo"$(INTDIR)/" /I./libatomic_ops/src /Fd"$(INTDIR)/" /c + /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/ diff --git a/gc/gc_cpp.cc b/gc/gc_cpp.cc index 9f4d673b2..baf8ca498 100644 --- a/gc/gc_cpp.cc +++ b/gc/gc_cpp.cc @@ -9,7 +9,7 @@ */ /************************************************************************* -This implementation module for gc_cpp.h provides an implementation of +This implementation module for gc_c++.h provides an implementation of the global operators "new" and "delete" that calls the Boehm allocator. All objects allocated by this implementation will be uncollectible but part of the root set of the collector. @@ -44,7 +44,7 @@ GC_API void GC_CALL GC_throw_bad_alloc() { GC_ALLOCATOR_THROW_OR_ABORT(); } -#if !(defined(_MSC_VER) || defined(__DMC__)) || defined(GC_NO_INLINE_STD_NEW) +#if !defined(_MSC_VER) && !defined(__DMC__) # if !defined(GC_NEW_DELETE_THROW_NOT_NEEDED) \ && !defined(GC_NEW_DELETE_NEED_THROW) && GC_GNUC_PREREQ(4, 2) \ @@ -53,13 +53,7 @@ GC_API void GC_CALL GC_throw_bad_alloc() { # endif # ifdef GC_NEW_DELETE_NEED_THROW -# if __cplusplus >= 201703L || _MSVC_LANG >= 201703L - // The "dynamic exception" syntax had been deprecated in C++11 - // and was removed in C++17. -# define GC_DECL_NEW_THROW noexcept(false) -# else -# define GC_DECL_NEW_THROW throw(std::bad_alloc) -# endif +# define GC_DECL_NEW_THROW throw(std::bad_alloc) # else # define GC_DECL_NEW_THROW /* empty */ # endif @@ -71,23 +65,6 @@ GC_API void GC_CALL GC_throw_bad_alloc() { return obj; } -# 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) - { -# ifdef GC_DEBUG - void* obj = GC_debug_malloc_uncollectable(size, szFileName, nLine); -# else - void* obj = GC_MALLOC_UNCOLLECTABLE(size); - (void)szFileName; (void)nLine; -# endif - if (0 == obj) - GC_ALLOCATOR_THROW_OR_ABORT(); - return obj; - } -# endif // _MSC_VER - void operator delete(void* obj) GC_NOEXCEPT { GC_FREE(obj); } @@ -100,21 +77,12 @@ GC_API void GC_CALL GC_throw_bad_alloc() { return obj; } -# ifdef _MSC_VER - // This new operator is used by VC++ 7+ in Debug builds. - void* operator new[](size_t size, int nBlockUse, - const char* szFileName, int nLine) - { - return operator new(size, nBlockUse, szFileName, nLine); - } -# endif // _MSC_VER - void operator delete[](void* obj) GC_NOEXCEPT { GC_FREE(obj); } # endif // GC_OPERATOR_NEW_ARRAY -# if __cplusplus >= 201402L || _MSVC_LANG >= 201402L // C++14 +# if __cplusplus > 201103L // C++14 void operator delete(void* obj, size_t size) GC_NOEXCEPT { (void)size; // size is ignored GC_FREE(obj); @@ -128,4 +96,4 @@ GC_API void GC_CALL GC_throw_bad_alloc() { # endif # endif // C++14 -#endif // !_MSC_VER && !__DMC__ || GC_NO_INLINE_STD_NEW +#endif // !_MSC_VER diff --git a/gc/headers.c b/gc/headers.c index 837614e51..d2c283c56 100644 --- a/gc/headers.c +++ b/gc/headers.c @@ -122,10 +122,9 @@ GC_INNER ptr_t GC_scratch_alloc(size_t bytes) bytes = ROUNDUP_GRANULE_SIZE(bytes); for (;;) { - GC_ASSERT((word)GC_scratch_end_ptr >= (word)result); - if (bytes <= (word)GC_scratch_end_ptr - (word)result) { + scratch_free_ptr += bytes; + if ((word)scratch_free_ptr <= (word)GC_scratch_end_ptr) { /* Unallocated space of scratch buffer has enough size. */ - scratch_free_ptr = result + bytes; return result; } @@ -133,7 +132,8 @@ GC_INNER ptr_t GC_scratch_alloc(size_t bytes) bytes_to_get = ROUNDUP_PAGESIZE_IF_MMAP(bytes); result = (ptr_t)GET_MEM(bytes_to_get); GC_add_to_our_memory(result, bytes_to_get); - /* No update of scratch free area pointer; get memory directly. */ + /* Undo scratch free area pointer update; get memory directly. */ + scratch_free_ptr -= bytes; if (result != NULL) { /* Update end point of last obtained area (needed only */ /* by GC_register_dynamic_libraries for some targets). */ @@ -149,11 +149,10 @@ GC_INNER ptr_t GC_scratch_alloc(size_t bytes) if (NULL == result) { WARN("Out of memory - trying to allocate requested amount" " (%" WARN_PRIdPTR " bytes)...\n", (word)bytes); + scratch_free_ptr -= bytes; /* Undo free area pointer update */ bytes_to_get = ROUNDUP_PAGESIZE_IF_MMAP(bytes); result = (ptr_t)GET_MEM(bytes_to_get); GC_add_to_our_memory(result, bytes_to_get); - if (result != NULL) - GC_scratch_last_end_ptr = result + bytes; return result; } /* Update scratch area pointers and retry. */ @@ -284,19 +283,15 @@ GC_INNER GC_bool GC_install_counts(struct hblk *h, size_t sz/* bytes */) struct hblk * hbp; for (hbp = h; (word)hbp < (word)h + sz; hbp += BOTTOM_SZ) { - if (!get_index((word)hbp)) - return FALSE; - if ((word)hbp > GC_WORD_MAX - (word)BOTTOM_SZ * HBLKSIZE) - break; /* overflow of hbp+=BOTTOM_SZ is expected */ + if (!get_index((word) hbp)) return(FALSE); } - if (!get_index((word)h + sz - 1)) - return FALSE; + if (!get_index((word)h + sz - 1)) return(FALSE); for (hbp = h + 1; (word)hbp < (word)h + sz; hbp += 1) { word i = HBLK_PTR_DIFF(hbp, h); SET_HDR(hbp, (hdr *)(i > MAX_JUMP? MAX_JUMP : i)); } - return TRUE; + return(TRUE); } /* Remove the header for block h */ @@ -347,7 +342,9 @@ void GC_apply_to_all_blocks(void (*fn)(struct hblk *h, word client_data), } } -GC_INNER struct hblk * GC_next_block(struct hblk *h, GC_bool allow_free) +/* Get the next valid block whose address is at least h */ +/* Return 0 if there is none. */ +GC_INNER struct hblk * GC_next_used_block(struct hblk *h) { REGISTER bottom_index * bi; REGISTER word j = ((word)h >> LOG_HBLKSIZE) & (BOTTOM_SZ-1); @@ -361,15 +358,14 @@ GC_INNER struct hblk * GC_next_block(struct hblk *h, GC_bool allow_free) while (bi != 0 && bi -> key < hi) bi = bi -> asc_link; j = 0; } - - while (bi != 0) { + while(bi != 0) { while (j < BOTTOM_SZ) { hdr * hhdr = bi -> index[j]; if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { j++; } else { - if (allow_free || !HBLK_IS_FREE(hhdr)) { - return ((struct hblk *) + if (!HBLK_IS_FREE(hhdr)) { + return((struct hblk *) (((bi -> key << LOG_BOTTOM_SZ) + j) << LOG_HBLKSIZE)); } else { @@ -383,6 +379,9 @@ GC_INNER struct hblk * GC_next_block(struct hblk *h, GC_bool allow_free) return(0); } +/* Get the last (highest address) block whose address is */ +/* at most h. Return 0 if there is none. */ +/* Unlike the above, this may return a free block. */ GC_INNER struct hblk * GC_prev_block(struct hblk *h) { bottom_index * bi; diff --git a/gc/include/ec.h b/gc/include/ec.h index 7473a5996..6375220cd 100644 --- a/gc/include/ec.h +++ b/gc/include/ec.h @@ -61,8 +61,8 @@ void CORD_ec_flush_buf(CORD_ec x); /* Append a character to an extensible cord. */ #define CORD_ec_append(x, c) \ - ((void)((x)[0].ec_bufptr == (x)[0].ec_buf + CORD_BUFSZ \ - ? (CORD_ec_flush_buf(x), 0) : 0), \ + (((x)[0].ec_bufptr == (x)[0].ec_buf + CORD_BUFSZ ? \ + (CORD_ec_flush_buf(x), 0) : 0), \ (void)(*(x)[0].ec_bufptr++ = (c))) /* Append a cord to an extensible cord. Structure remains shared with */ diff --git a/gc/include/gc.h b/gc/include/gc.h index 2de57922f..b952285bf 100644 --- a/gc/include/gc.h +++ b/gc/include/gc.h @@ -24,6 +24,7 @@ * For better performance, also look at GC_MALLOC_ATOMIC, and * GC_enable_incremental. If you need an action to be performed * immediately before an object is collected, look at GC_register_finalizer. + * If you are using Solaris threads, look at the end of this file. * Everything else is best ignored unless you encounter performance * problems. */ @@ -89,12 +90,11 @@ GC_API GC_word GC_CALL GC_get_gc_no(void); #ifdef GC_THREADS GC_API GC_ATTR_DEPRECATED int GC_parallel; /* GC is parallelized for performance on */ - /* multiprocessors. Set to a non-zero value */ - /* only implicitly if collector is built with */ - /* PARALLEL_MARK defined, and if either */ - /* GC_MARKERS (or GC_NPROCS) environment */ - /* variable is set to > 1, or multiple cores */ - /* (processors) are available. */ + /* multiprocessors. Currently set only */ + /* implicitly if collector is built with */ + /* PARALLEL_MARK defined and if either: */ + /* Env variable GC_NPROC is set to > 1, or */ + /* GC_NPROC is not set and this is an MP. */ /* If GC_parallel is on (non-zero), incremental */ /* collection is only partially functional, */ /* and may not be desirable. The getter does */ @@ -1328,12 +1328,7 @@ GC_API int GC_CALL GC_invoke_finalizers(void); __asm__ __volatile__(" " : : "X"(ptr) : "memory") #else GC_API void GC_CALL GC_noop1(GC_word); -# ifdef LINT2 -# define GC_reachable_here(ptr) GC_noop1(~(GC_word)(ptr)^(~(GC_word)0)) - /* The expression matches the one of COVERT_DATAFLOW(). */ -# else -# define GC_reachable_here(ptr) GC_noop1((GC_word)(ptr)) -# endif +# define GC_reachable_here(ptr) GC_noop1((GC_word)(ptr)) #endif /* GC_set_warn_proc can be used to redirect or filter warning messages. */ @@ -1373,7 +1368,6 @@ GC_API void GC_CALL GC_abort_on_oom(void); /* that finalization code will arrange for hidden pointers to */ /* disappear. Otherwise objects can be accessed after they */ /* have been collected. */ -/* Should not be used in the leak-finding mode. */ /* Note that putting pointers in atomic objects or in */ /* non-pointer slots of "typed" objects is equivalent to */ /* disguising them in this way, and may have other advantages. */ @@ -1534,13 +1528,8 @@ GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */, /* the current thread (this means that the thread is not suspended and */ /* the thread's stack frames "belonging" to the functions in the */ /* "inactive" state are not scanned during garbage collections). It is */ -/* assumed that the collector is already initialized and the current */ -/* thread is registered. It is allowed for fn to call */ -/* GC_call_with_gc_active() (even recursively), thus temporarily */ -/* toggling the collector's state back to "active". The latter */ -/* technique might be used to make stack scanning more precise (i.e. */ -/* scan only stack frames of functions that allocate garbage collected */ -/* memory and/or manipulate pointers to the garbage collected heap). */ +/* allowed for fn to call GC_call_with_gc_active() (even recursively), */ +/* thus temporarily toggling the collector's state back to "active". */ GC_API void * GC_CALL GC_do_blocking(GC_fn_type /* fn */, void * /* client_data */) GC_ATTR_NONNULL(1); @@ -1898,20 +1887,38 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void); /* Required at least if GC is in a DLL. And doesn't hurt. */ #elif defined(_AIX) extern int _data[], _end[]; -# define GC_DATASTART ((void *)_data) -# define GC_DATAEND ((void *)_end) +# define GC_DATASTART ((void *)((ulong)_data)) +# define GC_DATAEND ((void *)((ulong)_end)) # define GC_INIT_CONF_ROOTS GC_add_roots(GC_DATASTART, GC_DATAEND) #elif (defined(HOST_ANDROID) || defined(__ANDROID__)) \ - && defined(IGNORE_DYNAMIC_LOADING) - /* This is ugly but seems the only way to register data roots of the */ - /* client shared library if the GC dynamic loading support is off. */ + && !defined(GC_NOT_DLL) && defined(IGNORE_DYNAMIC_LOADING) + /* It causes the entire binary section of memory be pushed as a root. */ + /* This might be a bad idea though because on some Android devices */ + /* some of the binary data might become unmapped thus causing SIGSEGV */ + /* with code SEGV_MAPERR. */ +# pragma weak _etext +# pragma weak __data_start # pragma weak __dso_handle - extern int __dso_handle[]; - GC_API void * GC_CALL GC_find_limit(void * /* start */, int /* up */); -# define GC_INIT_CONF_ROOTS (void)(__dso_handle != 0 \ - ? (GC_add_roots(__dso_handle, \ - GC_find_limit(__dso_handle, \ - 1 /*up*/)), 0) : 0) + 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 \ + ? (__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 @@ -2007,7 +2014,7 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void); /* Portable clients should call this at the program start-up. More */ /* over, some platforms require this call to be done strictly from the */ -/* primordial thread. Multiple invocations are harmless. */ +/* primordial thread. */ #define GC_INIT() { GC_INIT_CONF_DONT_EXPAND; /* pre-init */ \ GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT; \ GC_INIT_CONF_MAX_RETRIES; \ diff --git a/gc/include/gc_allocator.h b/gc/include/gc_allocator.h index df5804379..491736fad 100644 --- a/gc/include/gc_allocator.h +++ b/gc/include/gc_allocator.h @@ -44,8 +44,7 @@ #include // for placement new and bad_alloc #ifndef GC_ATTR_EXPLICIT -# if __cplusplus >= 201103L && !defined(__clang__) || _MSVC_LANG >= 201103L \ - || defined(CPPCHECK) +# if (__cplusplus >= 201103L) || defined(CPPCHECK) # define GC_ATTR_EXPLICIT explicit # else # define GC_ATTR_EXPLICIT /* empty */ @@ -66,7 +65,7 @@ # ifndef GC_NEW_ABORTS_ON_OOM # define GC_NEW_ABORTS_ON_OOM # endif -# elif __cplusplus >= 201103L || _MSVC_LANG >= 201103L +# elif __cplusplus >= 201103L # define GC_NOEXCEPT noexcept # else # define GC_NOEXCEPT throw() diff --git a/gc/include/gc_config_macros.h b/gc/include/gc_config_macros.h index 14c65eeee..d656e01ee 100644 --- a/gc/include/gc_config_macros.h +++ b/gc/include/gc_config_macros.h @@ -83,13 +83,13 @@ #elif defined(GC_THREADS) # if defined(__linux__) # define GC_LINUX_THREADS -# elif defined(__OpenBSD__) -# define GC_OPENBSD_THREADS # elif defined(_PA_RISC1_1) || defined(_PA_RISC2_0) || defined(hppa) \ || defined(__HPPA) || (defined(__ia64) && defined(_HPUX_SOURCE)) # define GC_HPUX_THREADS # elif defined(__HAIKU__) # define GC_HAIKU_THREADS +# elif defined(__OpenBSD__) +# define GC_OPENBSD_THREADS # elif defined(__DragonFly__) || defined(__FreeBSD_kernel__) \ || (defined(__FreeBSD__) && !defined(SN_TARGET_ORBIS)) # define GC_FREEBSD_THREADS @@ -146,7 +146,7 @@ #if !defined(_REENTRANT) && defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) /* Better late than never. This fails if system headers that depend */ /* on this were previously included. */ -# define _REENTRANT 1 +# define _REENTRANT #endif #define __GC @@ -176,22 +176,13 @@ #if defined(GC_DLL) && !defined(GC_API) -# if defined(__CEGCC__) -# if defined(GC_BUILD) +# if defined(__MINGW32__) || defined(__CEGCC__) +# if defined(GC_BUILD) || defined(__MINGW32_DELAY_LOAD__) # define GC_API __declspec(dllexport) # else # define GC_API __declspec(dllimport) # endif -# elif defined(__MINGW32__) -# if defined(__cplusplus) && defined(GC_BUILD) -# define GC_API extern __declspec(dllexport) -# elif defined(GC_BUILD) || defined(__MINGW32_DELAY_LOAD__) -# define GC_API __declspec(dllexport) -# else -# define GC_API extern __declspec(dllimport) -# endif - # elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \ || defined(__CYGWIN__) # ifdef GC_BUILD diff --git a/gc/include/gc_cpp.h b/gc/include/gc_cpp.h index eb4397f79..3e166e669 100644 --- a/gc/include/gc_cpp.h +++ b/gc/include/gc_cpp.h @@ -182,7 +182,7 @@ by UseGC. GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined. # ifndef GC_NEW_ABORTS_ON_OOM # define GC_NEW_ABORTS_ON_OOM # endif -# elif __cplusplus >= 201103L || _MSVC_LANG >= 201103L +# elif __cplusplus >= 201103L # define GC_NOEXCEPT noexcept # else # define GC_NOEXCEPT throw() @@ -306,13 +306,14 @@ inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp, void*) GC_NOEXCEPT; #endif -#ifndef GC_NO_INLINE_STD_NEW - #if defined(_MSC_VER) || defined(__DMC__) \ - || ((defined(__BORLANDC__) || defined(__CYGWIN__) \ - || defined(__CYGWIN32__) || defined(__MINGW32__) \ - || defined(__WATCOMC__)) \ - && !defined(GC_BUILD) && !defined(GC_NOT_DLL)) + || ((defined(__CYGWIN32__) || defined(__CYGWIN__) \ + || defined(__MINGW32__)) && !defined(GC_BUILD) && !defined(GC_NOT_DLL)) + // 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). @@ -342,7 +343,7 @@ inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp, GC_FREE(obj); } -# if __cplusplus >= 201402L || _MSVC_LANG >= 201402L // C++14 +# if __cplusplus > 201103L // C++14 inline void operator delete(void* obj, size_t size) GC_NOEXCEPT { (void)size; // size is ignored GC_FREE(obj); @@ -389,24 +390,6 @@ inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp, #endif // _MSC_VER -#elif defined(_MSC_VER) - // 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. -# ifdef GC_OPERATOR_NEW_ARRAY - void *operator new[](size_t size); - void operator delete[](void* obj); -# endif - - void* operator new(size_t size); - void operator delete(void* obj); - - void* operator new(size_t size, int /* nBlockUse */, - const char * szFileName, int nLine); -#endif // GC_NO_INLINE_STD_NEW && _MSC_VER - #ifdef GC_OPERATOR_NEW_ARRAY // The operator new for arrays, identical to the above. inline void* operator new[](size_t size, GC_NS_QUALIFY(GCPlacement) gcp, diff --git a/gc/include/gc_disclaim.h b/gc/include/gc_disclaim.h index f2942cdb8..8123838ed 100644 --- a/gc/include/gc_disclaim.h +++ b/gc/include/gc_disclaim.h @@ -39,8 +39,6 @@ typedef int (GC_CALLBACK * GC_disclaim_proc)(void * /*obj*/); /* (including the referred closure object) will be protected from */ /* collection if "mark_from_all" is non-zero, but at the expense that */ /* long chains of objects will take many cycles to reclaim. */ -/* Calls to GC_free() will free its argument without inquiring "proc". */ -/* No-op in the leak-finding mode. */ GC_API void GC_CALL GC_register_disclaim_proc(int /*kind*/, GC_disclaim_proc /*proc*/, int /*mark_from_all*/) GC_ATTR_NONNULL(2); @@ -62,7 +60,6 @@ struct GC_finalizer_closure { /* 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. */ -/* The disclaim procedure is not invoked in the leak-finding mode. */ 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*/) GC_ATTR_NONNULL(2); diff --git a/gc/include/gc_pthread_redirects.h b/gc/include/gc_pthread_redirects.h index b235334aa..92951c3c6 100644 --- a/gc/include/gc_pthread_redirects.h +++ b/gc/include/gc_pthread_redirects.h @@ -18,9 +18,6 @@ /* Our pthread support normally needs to intercept a number of thread */ /* calls. We arrange to do that here, if appropriate. */ -#ifndef GC_PTHREAD_REDIRECTS_H -#define GC_PTHREAD_REDIRECTS_H - /* Included from gc.h only. Included only if GC_PTHREADS. */ #if defined(GC_H) && defined(GC_PTHREADS) @@ -120,5 +117,3 @@ #endif /* !GC_NO_THREAD_REDIRECTS */ #endif /* GC_PTHREADS */ - -#endif /* GC_PTHREAD_REDIRECTS_H */ diff --git a/gc/include/gc_typed.h b/gc/include/gc_typed.h index f91c7bcec..1ddc3f84e 100644 --- a/gc/include/gc_typed.h +++ b/gc/include/gc_typed.h @@ -105,9 +105,8 @@ GC_API GC_ATTR_MALLOC GC_ATTR_CALLOC_SIZE(1, 2) void * GC_CALL /* Returned object is cleared. */ #ifdef GC_DEBUG -# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) ((void)(d), GC_MALLOC(bytes)) -# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) \ - ((void)(d), GC_MALLOC((n) * (bytes))) +# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) GC_MALLOC(bytes) +# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) GC_MALLOC((n) * (bytes)) #else # define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) \ GC_malloc_explicitly_typed(bytes, d) diff --git a/gc/include/gc_version.h b/gc/include/gc_version.h index bbe31f9d7..a8ee4b0f0 100644 --- a/gc/include/gc_version.h +++ b/gc/include/gc_version.h @@ -30,7 +30,7 @@ /* it to keep the old-style build process working. */ #define GC_TMP_VERSION_MAJOR 8 #define GC_TMP_VERSION_MINOR 0 -#define GC_TMP_VERSION_MICRO 6 /* 8.0.6 */ +#define GC_TMP_VERSION_MICRO 0 /* 8.0.0 */ #ifdef GC_VERSION_MAJOR # if GC_TMP_VERSION_MAJOR != GC_VERSION_MAJOR \ diff --git a/gc/include/include.am b/gc/include/include.am index fd9a698fe..ef1867f8e 100644 --- a/gc/include/include.am +++ b/gc/include/include.am @@ -29,6 +29,9 @@ pkginclude_HEADERS += \ # headers which are not installed # dist_noinst_HEADERS += \ + include/cord.h \ + include/cord_pos.h \ + include/ec.h \ include/gc_alloc_ptrs.h \ include/new_gc_alloc.h \ include/private/darwin_semaphore.h \ diff --git a/gc/include/javaxfc.h b/gc/include/javaxfc.h index 40ff5b7fb..27da68b3d 100644 --- a/gc/include/javaxfc.h +++ b/gc/include/javaxfc.h @@ -15,9 +15,6 @@ * modified is included with the above copyright notice. */ -#ifndef GC_JAVAXFC_H -#define GC_JAVAXFC_H - #ifndef GC_H # include "gc.h" #endif @@ -61,5 +58,3 @@ GC_API void GC_CALL GC_finalize_all(void); #ifdef __cplusplus } /* extern "C" */ #endif - -#endif /* GC_JAVAXFC_H */ diff --git a/gc/include/new_gc_alloc.h b/gc/include/new_gc_alloc.h index 7ff2a0b30..a42733d77 100644 --- a/gc/include/new_gc_alloc.h +++ b/gc/include/new_gc_alloc.h @@ -44,8 +44,7 @@ // allocator is usually a very bad choice for a garbage collected environment.) // -#ifndef GC_NEW_ALLOC_H -#define GC_NEW_ALLOC_H +#ifndef GC_ALLOC_H #include "gc.h" @@ -68,14 +67,14 @@ # define simple_alloc __simple_alloc #endif +#define GC_ALLOC_H + #include #include // We can't include gc_priv.h, since that pulls in way too much stuff. #include "gc_alloc_ptrs.h" -#include "gc_mark.h" // for GC_generic_malloc - #define GC_generic_malloc_words_small(lw, k) \ GC_generic_malloc((lw) * sizeof(GC_word), k) @@ -155,15 +154,14 @@ void * GC_aux_template::GC_out_of_line_malloc(size_t nwords, int kind) if (0 == op) GC_ALLOCATOR_THROW_OR_ABORT(); - GC_word non_gc_bytes = GC_get_non_gc_bytes(); GC_bytes_recently_allocd += GC_uncollectable_bytes_recently_allocd; - non_gc_bytes += GC_uncollectable_bytes_recently_allocd; + GC_non_gc_bytes += + GC_uncollectable_bytes_recently_allocd; GC_uncollectable_bytes_recently_allocd = 0; GC_bytes_recently_freed += GC_uncollectable_bytes_recently_freed; - non_gc_bytes -= GC_uncollectable_bytes_recently_freed; + GC_non_gc_bytes -= GC_uncollectable_bytes_recently_freed; GC_uncollectable_bytes_recently_freed = 0; - GC_set_non_gc_bytes(non_gc_bytes); GC_incr_bytes_allocd(GC_bytes_recently_allocd); GC_bytes_recently_allocd = 0; @@ -514,4 +512,4 @@ __STL_END_NAMESPACE #endif /* __STL_USE_STD_ALLOCATORS */ -#endif /* GC_NEW_ALLOC_H */ +#endif /* GC_ALLOC_H */ diff --git a/gc/include/private/dbg_mlc.h b/gc/include/private/dbg_mlc.h index e38475a62..69cf95c3f 100644 --- a/gc/include/private/dbg_mlc.h +++ b/gc/include/private/dbg_mlc.h @@ -22,8 +22,8 @@ * included from header files that are frequently included by clients. */ -#ifndef GC_DBG_MLC_H -#define GC_DBG_MLC_H +#ifndef _DBG_MLC_H +#define _DBG_MLC_H #include "gc_priv.h" #ifdef KEEP_BACK_PTRS @@ -95,8 +95,8 @@ typedef struct { word oh_dummy; # endif # endif - const char * oh_string; /* object descriptor string (file name) */ - signed_word oh_int; /* object descriptor integer (line number) */ + const char * oh_string; /* object descriptor string */ + word oh_int; /* object descriptor integers */ # ifdef NEED_CALLINFO struct callinfo oh_ci[NFRAMES]; # endif @@ -158,7 +158,7 @@ typedef struct { #endif #if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH) -# if defined(SHORT_DBG_HDRS) && !defined(CPPCHECK) +# 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 @@ -179,4 +179,4 @@ typedef struct { EXTERN_C_END -#endif /* GC_DBG_MLC_H */ +#endif /* _DBG_MLC_H */ diff --git a/gc/include/private/gc_atomic_ops.h b/gc/include/private/gc_atomic_ops.h index 235f2c864..776d45519 100644 --- a/gc/include/private/gc_atomic_ops.h +++ b/gc/include/private/gc_atomic_ops.h @@ -100,11 +100,6 @@ } /* extern "C" */ # endif -# ifndef NO_LOCKFREE_AO_OR - /* __atomic_or_fetch is assumed to be lock-free. */ -# define HAVE_LOCKFREE_AO_OR 1 -# endif - #else /* Fallback to libatomic_ops. */ # include "atomic_ops.h" @@ -114,7 +109,7 @@ /* only if AO_REQUIRE_CAS is defined (or if the corresponding */ /* AO_HAVE_x macro is defined). x86/x64 targets have AO_nop_full, */ /* AO_load_acquire, AO_store_release, at least. */ -# if (!defined(AO_HAVE_load) || !defined(AO_HAVE_store)) && !defined(CPPCHECK) +# if !defined(AO_HAVE_load) || !defined(AO_HAVE_store) # error AO_load or AO_store is missing; probably old version of atomic_ops # endif diff --git a/gc/include/private/gc_hdrs.h b/gc/include/private/gc_hdrs.h index a6e7037a5..94f29e9c7 100644 --- a/gc/include/private/gc_hdrs.h +++ b/gc/include/private/gc_hdrs.h @@ -15,7 +15,7 @@ #ifndef GC_HEADERS_H #define GC_HEADERS_H -#if CPP_WORDSZ != 32 && CPP_WORDSZ < 36 && !defined(CPPCHECK) +#if CPP_WORDSZ != 32 && CPP_WORDSZ < 36 # error Get a real machine #endif diff --git a/gc/include/private/gc_locks.h b/gc/include/private/gc_locks.h index 5b9ef4f39..f6e45d59b 100644 --- a/gc/include/private/gc_locks.h +++ b/gc/include/private/gc_locks.h @@ -54,8 +54,7 @@ # if (!defined(AO_HAVE_test_and_set_acquire) || defined(GC_RTEMS_PTHREADS) \ || defined(SN_TARGET_ORBIS) || defined(SN_TARGET_PS3) \ - || defined(GC_WIN32_THREADS) || defined(BASE_ATOMIC_OPS_EMULATED) \ - || defined(LINT2)) && defined(GC_PTHREADS) + || defined(GC_WIN32_THREADS) || defined(LINT2)) && defined(GC_PTHREADS) # define USE_PTHREAD_LOCKS # undef USE_SPIN_LOCK # endif @@ -183,7 +182,6 @@ EXTERN_C_BEGIN GC_EXTERN pthread_mutex_t GC_allocate_ml; # ifdef GC_ASSERTIONS - GC_INNER void GC_lock(void); # define UNCOND_LOCK() { GC_ASSERT(I_DONT_HOLD_LOCK()); \ GC_lock(); SET_LOCK_HOLDER(); } # define UNCOND_UNLOCK() \ @@ -193,7 +191,6 @@ # if defined(NO_PTHREAD_TRYLOCK) # define UNCOND_LOCK() pthread_mutex_lock(&GC_allocate_ml) # else - GC_INNER void GC_lock(void); # define UNCOND_LOCK() \ { if (0 != pthread_mutex_trylock(&GC_allocate_ml)) \ GC_lock(); } @@ -227,6 +224,7 @@ # define EXIT_GC() (void)(GC_collecting = FALSE) # endif # endif + GC_INNER void GC_lock(void); # endif /* GC_PTHREADS */ # if defined(GC_ALWAYS_MULTITHREADED) \ && (defined(USE_PTHREAD_LOCKS) || defined(USE_SPIN_LOCK)) diff --git a/gc/include/private/gc_pmark.h b/gc/include/private/gc_pmark.h index 15e798605..2e657b0b4 100644 --- a/gc/include/private/gc_pmark.h +++ b/gc/include/private/gc_pmark.h @@ -23,8 +23,6 @@ #define GC_PMARK_H #if defined(HAVE_CONFIG_H) && !defined(GC_PRIVATE_H) - /* When gc_pmark.h is included from gc_priv.h, some of macros might */ - /* be undefined in gcconfig.h, so skip config.h in this case. */ # include "config.h" #endif @@ -42,8 +40,13 @@ # include "dbg_mlc.h" #endif -#include "../gc_mark.h" -#include "gc_priv.h" +#ifndef GC_MARK_H +# include "../gc_mark.h" +#endif + +#ifndef GC_PRIVATE_H +# include "gc_priv.h" +#endif EXTERN_C_BEGIN @@ -150,7 +153,7 @@ GC_INLINE mse * GC_push_obj(ptr_t obj, hdr * hhdr, mse * mark_stack_top, /* Set mark bit, exit (using "break" statement) if it is already set. */ #ifdef USE_MARK_BYTES # if defined(PARALLEL_MARK) && defined(AO_HAVE_char_store) \ - && !defined(BASE_ATOMIC_OPS_EMULATED) + && !defined(AO_USE_PTHREAD_DEFS) /* 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 is only a performance issue. */ @@ -317,8 +320,7 @@ GC_INLINE mse * GC_push_contents_hdr(ptr_t current, mse * mark_stack_top, if ((low_prod >> 16) != 0) # endif /* MARK_BIT_PER_OBJ */ { -# if defined(MARK_BIT_PER_OBJ) \ - && !defined(MARK_BIT_PER_GRANULE) /* for cppcheck */ +# ifdef MARK_BIT_PER_OBJ size_t obj_displ; /* Accurate enough if HBLKSIZE <= 2**15. */ diff --git a/gc/include/private/gc_priv.h b/gc/include/private/gc_priv.h index 629418f3d..728e74ea4 100644 --- a/gc/include/private/gc_priv.h +++ b/gc/include/private/gc_priv.h @@ -26,8 +26,7 @@ # define GC_BUILD #endif -#if (defined(__linux__) || defined(__GLIBC__) || defined(__GNU__) \ - || (defined(__CYGWIN__) && !defined(USE_MMAP))) \ +#if (defined(__linux__) || defined(__GLIBC__) || defined(__GNU__)) \ && !defined(_GNU_SOURCE) /* Can't test LINUX, since this must be defined before other includes. */ # define _GNU_SOURCE 1 @@ -81,8 +80,13 @@ # endif #endif -#include "../gc_tiny_fl.h" -#include "../gc_mark.h" +#ifndef GC_TINY_FL_H +# include "../gc_tiny_fl.h" +#endif + +#ifndef GC_MARK_H +# include "../gc_mark.h" +#endif typedef GC_word word; typedef GC_signed_word signed_word; @@ -92,12 +96,9 @@ typedef int GC_bool; #define TRUE 1 #define FALSE 0 -#ifndef PTR_T_DEFINED - typedef char * ptr_t; /* A generic pointer to which we can add */ +typedef char * ptr_t; /* A generic pointer to which we can add */ /* byte displacements and which can be used */ /* for address comparisons. */ -# define PTR_T_DEFINED -#endif #ifndef SIZE_MAX # include @@ -121,7 +122,9 @@ typedef int GC_bool; #define SIZET_SAT_ADD(a, b) \ (EXPECT((a) < GC_SIZE_MAX - (b), TRUE) ? (a) + (b) : GC_SIZE_MAX) -#include "gcconfig.h" +#ifndef GCCONFIG_H +# include "gcconfig.h" +#endif #if !defined(GC_ATOMIC_UNCOLLECTABLE) && defined(ATOMIC_UNCOLLECTABLE) /* For compatibility with old-style naming. */ @@ -167,14 +170,6 @@ typedef int GC_bool; # define REGISTER register #endif -#if defined(M68K) && defined(__GNUC__) - /* By default, __alignof__(word) is 2 on m68k. Use this attribute to */ - /* have proper word alignment (i.e. 4-byte on a 32-bit arch). */ -# define GC_ATTR_WORD_ALIGNED __attribute__((__aligned__(sizeof(word)))) -#else -# define GC_ATTR_WORD_ALIGNED /* empty */ -#endif - #ifndef HEADERS_H # include "gc_hdrs.h" #endif @@ -262,20 +257,19 @@ typedef int GC_bool; #if defined(THREADS) && !defined(NN_PLATFORM_CTR) \ && !defined(SN_TARGET_ORBIS) && !defined(SN_TARGET_PSP2) # include "gc_atomic_ops.h" -# ifndef AO_HAVE_compiler_barrier -# define AO_HAVE_compiler_barrier 1 -# endif #endif -#include "gc_locks.h" +#ifndef GC_LOCKS_H +# include "gc_locks.h" +#endif -#define GC_WORD_MAX (~(word)0) +#define ONES ((word)(signed_word)(-1)) # ifdef STACK_GROWS_DOWN # define COOLER_THAN > # define HOTTER_THAN < # define MAKE_COOLER(x,y) if ((word)((x) + (y)) > (word)(x)) {(x) += (y);} \ - else (x) = (ptr_t)GC_WORD_MAX + else (x) = (ptr_t)ONES # define MAKE_HOTTER(x,y) (x) -= (y) # else # define COOLER_THAN < @@ -438,17 +432,14 @@ EXTERN_C_END # undef GET_TIME # undef MS_TIME_DIFF # define CLOCK_TYPE struct timeval -# define CLOCK_TYPE_INITIALIZER { 0, 0 } # define GET_TIME(x) \ do { \ struct rusage rusage; \ getrusage(RUSAGE_SELF, &rusage); \ x = rusage.ru_utime; \ } while (0) -# define MS_TIME_DIFF(a,b) ((unsigned long)((long)(a.tv_sec-b.tv_sec) * 1000 \ - + (long)(a.tv_usec-b.tv_usec) / 1000)) - /* "a" time is expected to be not earlier than */ - /* "b" one; the result has unsigned long type. */ +# define MS_TIME_DIFF(a,b) ((unsigned long)(a.tv_sec - b.tv_sec) * 1000 \ + + (unsigned long)(a.tv_usec - b.tv_usec) / 1000) #elif defined(MSWIN32) || defined(MSWINCE) # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN 1 @@ -462,7 +453,7 @@ EXTERN_C_END # else # define GET_TIME(x) (void)(x = GetTickCount()) # endif -# define MS_TIME_DIFF(a,b) ((unsigned long)((a)-(b))) +# define MS_TIME_DIFF(a,b) ((long)((a)-(b))) #elif defined(NN_PLATFORM_CTR) # define CLOCK_TYPE long long EXTERN_C_BEGIN @@ -470,7 +461,7 @@ EXTERN_C_END CLOCK_TYPE n3ds_convert_tick_to_ms(CLOCK_TYPE tick); EXTERN_C_END # define GET_TIME(x) (void)(x = n3ds_get_system_tick()) -# define MS_TIME_DIFF(a,b) ((unsigned long)n3ds_convert_tick_to_ms((a)-(b))) +# define MS_TIME_DIFF(a,b) ((long)n3ds_convert_tick_to_ms((a)-(b))) #else /* !BSD_TIME && !NN_PLATFORM_CTR && !MSWIN32 && !MSWINCE */ # include # if defined(FREEBSD) && !defined(CLOCKS_PER_SEC) @@ -497,11 +488,6 @@ EXTERN_C_END /* Avoid using double type since some targets (like ARM) might */ /* require -lm option for double-to-long conversion. */ #endif /* !BSD_TIME && !MSWIN32 */ -# ifndef CLOCK_TYPE_INITIALIZER - /* This is used to initialize CLOCK_TYPE variables (to some value) */ - /* to avoid "variable might be uninitialized" compiler warnings. */ -# define CLOCK_TYPE_INITIALIZER 0 -# endif #endif /* !NO_CLOCK */ /* We use bzero and bcopy internally. They may not be available. */ @@ -874,8 +860,8 @@ EXTERN_C_BEGIN # define CPP_LOG_HBLKSIZE 13 # elif HBLKSIZE == 16384 # define CPP_LOG_HBLKSIZE 14 -# elif !defined(CPPCHECK) -# error Bad HBLKSIZE value +# else +# error fix HBLKSIZE # endif # undef HBLKSIZE #endif @@ -984,9 +970,6 @@ typedef word page_hash_table[PHT_SIZE]; # define set_pht_entry_from_index_concurrent(bl, index) \ AO_or((volatile AO_t *)&(bl)[divWORDSZ(index)], \ (AO_t)((word)1 << modWORDSZ(index))) -#else -# define set_pht_entry_from_index_concurrent(bl, index) \ - set_pht_entry_from_index(bl, index) #endif @@ -1240,8 +1223,8 @@ typedef struct GC_ms_entry { /* be pointers are also put here. */ /* The main fields should precede any */ /* conditionally included fields, so that */ -/* gc_inline.h will work even if a different */ -/* set of macros is defined when the client is */ +/* gc_inl.h will work even if a different set */ +/* of macros is defined when the client is */ /* compiled. */ struct _GC_arrays { @@ -1308,10 +1291,6 @@ struct _GC_arrays { # ifdef USE_MUNMAP # define GC_unmapped_bytes GC_arrays._unmapped_bytes word _unmapped_bytes; -# ifdef COUNT_UNMAPPED_REGIONS -# define GC_num_unmapped_regions GC_arrays._num_unmapped_regions - signed_word _num_unmapped_regions; -# endif # else # define GC_unmapped_bytes 0 # endif @@ -1551,14 +1530,8 @@ GC_EXTERN size_t GC_page_size; #endif #if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32) -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN 1 -# endif -# define NOSERVICE - EXTERN_C_END -# include - EXTERN_C_BEGIN - GC_EXTERN SYSTEM_INFO GC_sysinfo; + struct _SYSTEM_INFO; + GC_EXTERN struct _SYSTEM_INFO GC_sysinfo; GC_INNER GC_bool GC_is_heap_base(void *p); #endif @@ -1681,16 +1654,12 @@ void GC_apply_to_all_blocks(void (*fn)(struct hblk *h, word client_data), word client_data); /* Invoke fn(hbp, client_data) for each */ /* allocated heap block. */ -GC_INNER struct hblk * GC_next_block(struct hblk *h, GC_bool allow_free); - /* Get the next block whose address is at least */ - /* h. Returned block is managed by GC. The */ - /* block must be in use unless allow_free is */ - /* true. Return 0 if there is no such block. */ +GC_INNER struct hblk * GC_next_used_block(struct hblk * h); + /* Return first in-use block >= h */ GC_INNER struct hblk * GC_prev_block(struct hblk * h); - /* Get the last (highest address) block whose */ - /* address is at most h. Returned block is */ - /* managed by GC, but may or may not be in use. */ - /* Return 0 if there is no such block. */ + /* Return last block <= h. Returned block */ + /* is managed by GC, but may or may not be in */ + /* use. */ GC_INNER void GC_mark_init(void); GC_INNER void GC_clear_marks(void); /* Clear mark bits for all heap objects. */ @@ -1884,13 +1853,10 @@ GC_INNER void GC_scratch_recycle_inner(void *ptr, size_t bytes); /* Reuse the memory region by the heap. */ /* Heap block layout maps: */ -#ifdef MARK_BIT_PER_GRANULE - GC_INNER GC_bool GC_add_map_entry(size_t sz); +GC_INNER GC_bool GC_add_map_entry(size_t sz); /* Add a heap block map for objects of */ /* size sz to obj_map. */ /* Return FALSE on failure. */ -#endif - GC_INNER void GC_register_displacement_inner(size_t offset); /* Version of GC_register_displacement */ /* that assumes lock is already held. */ @@ -1967,7 +1933,7 @@ 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) -#ifdef THREADS +#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. */ @@ -2156,13 +2122,7 @@ GC_EXTERN GC_bool GC_print_back_height; GC_INNER void GC_remap(ptr_t start, size_t bytes); GC_INNER void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2, size_t bytes2); - - /* Compute end address for an unmap operation on the indicated block. */ - GC_INLINE ptr_t GC_unmap_end(ptr_t start, size_t bytes) - { - return (ptr_t)((word)(start + bytes) & ~(GC_page_size - 1)); - } -#endif /* USE_MUNMAP */ +#endif #ifdef CAN_HANDLE_FORK GC_EXTERN int GC_handle_fork; @@ -2214,17 +2174,6 @@ GC_EXTERN GC_bool GC_print_back_height; /* pointer-free system call buffers in the heap are */ /* not protected. */ -# ifdef CAN_HANDLE_FORK -# if defined(PROC_VDB) - GC_INNER void GC_dirty_update_child(void); - /* Update pid-specific resources (like /proc file */ - /* descriptors) needed by the dirty bits implementation */ - /* after fork in the child process. */ -# else -# define GC_dirty_update_child() (void)0 -# endif -# endif /* CAN_HANDLE_FORK */ - 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 */ @@ -2367,7 +2316,8 @@ GC_EXTERN signed_word GC_bytes_found; /* protected by GC_write_cs. */ # endif -# if defined(GC_DISABLE_INCREMENTAL) || defined(HAVE_LOCKFREE_AO_OR) +# if defined(GC_DISABLE_INCREMENTAL) \ + || defined(set_pht_entry_from_index_concurrent) # define GC_acquire_dirty_lock() (void)0 # define GC_release_dirty_lock() (void)0 # else @@ -2501,12 +2451,12 @@ GC_INNER void *GC_store_debug_info_inner(void *p, word sz, const char *str, #ifdef SEARCH_FOR_DATA_START GC_INNER void GC_init_linux_data_start(void); - void * GC_find_limit(void *, int); + ptr_t GC_find_limit(ptr_t, GC_bool); #endif #if defined(NETBSD) && defined(__ELF__) GC_INNER void GC_init_netbsd_elf(void); - void * GC_find_limit(void *, int); + ptr_t GC_find_limit(ptr_t, GC_bool); #endif #ifdef UNIX_LIKE @@ -2685,6 +2635,7 @@ GC_INNER void *GC_store_debug_info_inner(void *p, word sz, const char *str, /* Do we need the GC_find_limit machinery to find the end of a */ /* data segment. */ #if defined(HEURISTIC2) || defined(SEARCH_FOR_DATA_START) \ + || (!defined(STACKBOTTOM) && defined(HEURISTIC2)) \ || ((defined(SVR4) || defined(AIX) || defined(DGUX) \ || (defined(LINUX) && defined(SPARC))) && !defined(PCR)) # define NEED_FIND_LIMIT diff --git a/gc/include/private/gcconfig.h b/gc/include/private/gcconfig.h index 1979c58c6..5671402b9 100644 --- a/gc/include/private/gcconfig.h +++ b/gc/include/private/gcconfig.h @@ -25,23 +25,12 @@ #ifndef GCCONFIG_H #define GCCONFIG_H -#ifdef CPPCHECK -# undef CLOCKS_PER_SEC -# undef FIXUP_POINTER -# undef POINTER_MASK -# undef POINTER_SHIFT -# undef REDIRECT_REALLOC -# undef _MAX_PATH -#endif - -#ifndef PTR_T_DEFINED - typedef char * ptr_t; -# define PTR_T_DEFINED -#endif - -#if !defined(sony_news) -# include /* For size_t, etc. */ -#endif +# ifndef GC_PRIVATE_H + /* Fake ptr_t declaration, just to avoid compilation errors. */ + /* This avoids many instances if "ifndef GC_PRIVATE_H" below. */ + typedef struct GC_undefined_struct * ptr_t; +# include /* For size_t etc. */ +# endif /* Note: Only wrap our own declarations, and not the included headers. */ /* In this case, wrap our entire file, but temporarily unwrap/rewrap */ @@ -160,8 +149,7 @@ EXTERN_C_BEGIN # if defined(__aarch64__) # define AARCH64 # if !defined(LINUX) && !defined(DARWIN) && !defined(FREEBSD) \ - && !defined(NETBSD) && !defined(NN_BUILD_TARGET_PLATFORM_NX) \ - && !defined(OPENBSD) + && !defined(NETBSD) && !defined(NN_BUILD_TARGET_PLATFORM_NX) # define NOSYS # define mach_type_known # endif @@ -183,7 +171,7 @@ EXTERN_C_BEGIN # error SUNOS4 no longer supported # endif # if defined(hp9000s300) && !defined(CPPCHECK) -# error M68K based HP machines no longer supported +# error M68K based HP machines no longer supported. # endif # if defined(OPENBSD) && defined(m68k) # define M68K @@ -197,10 +185,6 @@ EXTERN_C_BEGIN # define ARM32 # define mach_type_known # endif -# if defined(OPENBSD) && defined(__aarch64__) -# define AARCH64 -# define mach_type_known -# endif # if defined(OPENBSD) && defined(__sh__) # define SH # define mach_type_known @@ -292,7 +276,7 @@ EXTERN_C_BEGIN # define mach_type_known # endif # if defined(ibm032) && !defined(CPPCHECK) -# error IBM PC/RT no longer supported +# error IBM PC/RT no longer supported. # endif # if (defined(sun) || defined(__sun)) && (defined(sparc) || defined(__sparc)) /* Test for SunOS 5.x */ @@ -555,12 +539,10 @@ EXTERN_C_BEGIN # if ((defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300)) \ || (defined(_WIN32) && !defined(__CYGWIN32__) && !defined(__CYGWIN__) \ && !defined(__INTERIX) && !defined(SYMBIAN)) -# if defined(__LP64__) || defined(_M_X64) +# if defined(__LP64__) || defined(_WIN64) # define X86_64 # elif defined(_M_ARM) # define ARM32 -# elif defined(_M_ARM64) -# define AARCH64 # else /* _M_IX86 */ # define I386 # endif @@ -711,7 +693,7 @@ EXTERN_C_BEGIN /* SYSV on an M68K actually means A/UX. */ /* The distinction in these cases is usually the stack starting address */ # if !defined(mach_type_known) && !defined(CPPCHECK) -# error The collector has not been ported to this machine/OS combination +# error "The collector has not been ported to this machine/OS combination." # endif /* Mapping is: M68K ==> Motorola 680X0 */ /* (NEXT, and SYSV (A/UX), */ @@ -738,7 +720,6 @@ EXTERN_C_BEGIN /* S390 ==> 390-like machine */ /* running LINUX */ /* AARCH64 ==> ARM AArch64 */ - /* (LP64 and ILP32 variants) */ /* ARM32 ==> Intel StrongARM */ /* IA64 ==> Intel IPF */ /* (e.g. Itanium) */ @@ -888,8 +869,7 @@ EXTERN_C_BEGIN && !(defined(POWERPC) && defined(DARWIN)) /* for MacOS X 10.3.9 */ \ && !defined(RTEMS) \ && !defined(__ARMCC_VERSION) /* does not exist in armcc gnu emu */ \ - && (!defined(__clang__) \ - || (GC_CLANG_PREREQ(8, 0) && defined(HOST_ANDROID))) + && !defined(__clang__) /* since no-op in clang (3.0) */ # define HAVE_BUILTIN_UNWIND_INIT # endif @@ -949,10 +929,7 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM -# define COUNT_UNMAPPED_REGIONS -# if !defined(REDIRECT_MALLOC) -# define MPROTECT_VDB -# endif +# define MPROTECT_VDB # ifdef __ELF__ # define DYNAMIC_LOADING EXTERN_C_END @@ -1042,7 +1019,6 @@ EXTERN_C_BEGIN # else # define LINUX_STACKBOTTOM # endif -# define COUNT_UNMAPPED_REGIONS # define DYNAMIC_LOADING # define SEARCH_FOR_DATA_START extern int _end[]; @@ -1088,7 +1064,17 @@ EXTERN_C_BEGIN # define OS_TYPE "OPENBSD" # define ALIGNMENT 4 # ifndef GC_OPENBSD_THREADS -# define HEURISTIC2 + EXTERN_C_END +# include +# include + EXTERN_C_BEGIN + /* USRSTACK is defined in but that is */ + /* protected by _KERNEL in file. */ +# ifdef USRSTACK +# define STACKBOTTOM ((ptr_t)USRSTACK) +# else +# define HEURISTIC2 +# endif # endif extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) @@ -1239,7 +1225,7 @@ EXTERN_C_BEGIN # define DATASTART_IS_FUNC # define DATAEND ((ptr_t)(_end)) # if !defined(USE_MMAP) && defined(REDIRECT_MALLOC) -# define USE_MMAP 1 +# define USE_MMAP /* Otherwise we now use calloc. Mmap may result in the */ /* heap interleaved with thread stacks, which can result in */ /* excessive blacklisting. Sbrk is unusable since it */ @@ -1285,10 +1271,9 @@ EXTERN_C_BEGIN # define OS_TYPE "LINUX" # ifdef __ELF__ # define DYNAMIC_LOADING -# elif !defined(CPPCHECK) -# error Linux SPARC a.out not supported +# else +# error --> Linux SPARC a.out not supported # endif -# define COUNT_UNMAPPED_REGIONS extern int _end[]; extern int _etext[]; # define DATAEND ((ptr_t)(_end)) @@ -1305,7 +1290,15 @@ EXTERN_C_BEGIN # ifdef OPENBSD # define OS_TYPE "OPENBSD" # ifndef GC_OPENBSD_THREADS -# define HEURISTIC2 + EXTERN_C_END +# include +# include + EXTERN_C_BEGIN +# ifdef USRSTACK +# define STACKBOTTOM ((ptr_t)USRSTACK) +# else +# define HEURISTIC2 +# endif # endif extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) @@ -1335,13 +1328,11 @@ EXTERN_C_BEGIN # endif extern char etext[]; extern char edata[]; -# if !defined(CPPCHECK) - extern char end[]; -# endif + extern char end[]; # define NEED_FIND_LIMIT # define DATASTART ((ptr_t)(&etext)) - void * GC_find_limit(void *, int); -# define DATAEND (ptr_t)GC_find_limit(DATASTART, TRUE) + ptr_t GC_find_limit(ptr_t, GC_bool); +# define DATAEND GC_find_limit(DATASTART, TRUE) # define DATAEND_IS_FUNC # define GC_HAVE_DATAREGION2 # define DATASTART2 ((ptr_t)(&edata)) @@ -1351,7 +1342,7 @@ EXTERN_C_BEGIN # ifdef I386 # define MACH_TYPE "I386" -# if (defined(__LP64__) || defined(_WIN64)) && !defined(CPPCHECK) +# if defined(__LP64__) || defined(_WIN64) # error This should be handled as X86_64 # else # define CPP_WORDSZ 32 @@ -1411,7 +1402,7 @@ EXTERN_C_BEGIN # endif # define DYNAMIC_LOADING # if !defined(USE_MMAP) && defined(REDIRECT_MALLOC) -# define USE_MMAP 1 +# define USE_MMAP /* Otherwise we now use calloc. Mmap may result in the */ /* heap interleaved with thread stacks, which can result in */ /* excessive blacklisting. Sbrk is unusable since it */ @@ -1453,7 +1444,7 @@ EXTERN_C_BEGIN # define GETPAGESIZE() (unsigned)sysconf(_SC_PAGESIZE) # define DYNAMIC_LOADING # ifndef USE_MMAP -# define USE_MMAP 1 +# define USE_MMAP # endif # define MAP_FAILED (void *) ((word)-1) # define HEAP_START (ptr_t)0x40000000 @@ -1461,8 +1452,7 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM -# define COUNT_UNMAPPED_REGIONS -# if !defined(REDIRECT_MALLOC) +# if !defined(GC_LINUX_THREADS) || !defined(REDIRECT_MALLOC) # define MPROTECT_VDB # else /* We seem to get random errors in incremental mode, */ @@ -1502,7 +1492,7 @@ EXTERN_C_BEGIN /* (setjmp is used instead to find data_start). The bug */ /* is fixed in Android NDK r8e (so, ok to use sigsetjmp */ /* if gcc4.8+, clang3.2+ or Android API level 18+). */ -# define GC_NO_SIGSETJMP 1 +# define GC_NO_SIGSETJMP # endif # else extern int etext[]; @@ -1539,8 +1529,6 @@ EXTERN_C_BEGIN # endif # ifdef CYGWIN32 # define OS_TYPE "CYGWIN32" -# define WOW64_THREAD_CONTEXT_WORKAROUND -# define RETRY_GET_THREAD_CONTEXT # define DATASTART ((ptr_t)GC_DATASTART) /* From gc.h */ # define DATAEND ((ptr_t)GC_DATAEND) # undef STACK_GRAN @@ -1571,8 +1559,6 @@ EXTERN_C_BEGIN # endif # ifdef MSWIN32 # define OS_TYPE "MSWIN32" -# define WOW64_THREAD_CONTEXT_WORKAROUND -# define RETRY_GET_THREAD_CONTEXT /* STACKBOTTOM and DATASTART are handled specially in */ /* os_dep.c. */ # define MPROTECT_VDB @@ -1599,7 +1585,15 @@ EXTERN_C_BEGIN # ifdef OPENBSD # define OS_TYPE "OPENBSD" # ifndef GC_OPENBSD_THREADS + EXTERN_C_END +# include +# include + EXTERN_C_BEGIN +# ifdef USRSTACK +# define STACKBOTTOM ((ptr_t)USRSTACK) +# else # define HEURISTIC2 +# endif # endif extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) @@ -1660,9 +1654,11 @@ EXTERN_C_BEGIN # include EXTERN_C_BEGIN extern int etext[]; + extern int end[]; void *rtems_get_stack_bottom(void); # define InitStackBottom rtems_get_stack_bottom() # define DATASTART ((ptr_t)etext) +# define DATAEND ((ptr_t)end) # define STACKBOTTOM ((ptr_t)InitStackBottom) # define SIG_SUSPEND SIGUSR1 # define SIG_THR_RESTART SIGUSR2 @@ -1697,7 +1693,7 @@ EXTERN_C_BEGIN # endif # ifdef DARWIN # define OS_TYPE "DARWIN" -# define DARWIN_DONT_PARSE_STACK 1 +# define DARWIN_DONT_PARSE_STACK # define DYNAMIC_LOADING /* XXX: see get_end(3), get_etext() and get_end() should not be used. */ /* These aren't used when dyld support is enabled (it is by default). */ @@ -1737,7 +1733,6 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define DYNAMIC_LOADING -# define COUNT_UNMAPPED_REGIONS extern int _end[]; # pragma weak __data_start extern int __data_start[]; @@ -1759,30 +1754,27 @@ EXTERN_C_BEGIN # endif # endif /* Linux */ # ifdef EWS4800 -# define HEURISTIC2 -# if defined(_MIPS_SZPTR) && (_MIPS_SZPTR == 64) - extern int _fdata[], _end[]; -# define DATASTART ((ptr_t)_fdata) -# define DATAEND ((ptr_t)_end) -# define CPP_WORDSZ _MIPS_SZPTR -# define ALIGNMENT (_MIPS_SZPTR/8) -# else - extern int etext[], edata[]; -# if !defined(CPPCHECK) - extern int end[]; -# endif - extern int _DYNAMIC_LINKING[], _gp[]; -# define DATASTART ((ptr_t)((((word)(etext) + 0x3ffff) & ~0x3ffff) \ - + ((word)(etext) & 0xffff))) -# define DATAEND ((ptr_t)(edata)) -# define GC_HAVE_DATAREGION2 -# define DATASTART2 (_DYNAMIC_LINKING \ - ? (ptr_t)(((word)_gp + 0x8000 + 0x3ffff) & ~0x3ffff) \ - : (ptr_t)edata) -# define DATAEND2 ((ptr_t)(end)) -# define ALIGNMENT 4 -# endif -# define OS_TYPE "EWS4800" +# define HEURISTIC2 +# if defined(_MIPS_SZPTR) && (_MIPS_SZPTR == 64) + extern int _fdata[], _end[]; +# define DATASTART ((ptr_t)_fdata) +# define DATAEND ((ptr_t)_end) +# define CPP_WORDSZ _MIPS_SZPTR +# define ALIGNMENT (_MIPS_SZPTR/8) +# else + extern int etext[], edata[], end[]; + extern int _DYNAMIC_LINKING[], _gp[]; +# define DATASTART ((ptr_t)((((word)(etext) + 0x3ffff) & ~0x3ffff) \ + + ((word)(etext) & 0xffff))) +# define DATAEND ((ptr_t)(edata)) +# define GC_HAVE_DATAREGION2 +# define DATASTART2 (_DYNAMIC_LINKING \ + ? (ptr_t)(((word)_gp + 0x8000 + 0x3ffff) & ~0x3ffff) \ + : (ptr_t)edata) +# define DATAEND2 ((ptr_t)(end)) +# define ALIGNMENT 4 +# endif +# define OS_TYPE "EWS4800" # endif # ifdef ULTRIX # define HEURISTIC2 @@ -1838,13 +1830,20 @@ EXTERN_C_BEGIN # endif # ifdef OPENBSD # define OS_TYPE "OPENBSD" -# define CPP_WORDSZ 64 /* all OpenBSD/mips platforms are 64-bit */ -# define ALIGNMENT 8 +# define ALIGNMENT 4 # ifndef GC_OPENBSD_THREADS -# define HEURISTIC2 + EXTERN_C_END +# include +# include + EXTERN_C_BEGIN +# ifdef USRSTACK +# define STACKBOTTOM ((ptr_t)USRSTACK) +# else +# define HEURISTIC2 +# endif # endif - extern int __data_start[]; -# define DATASTART ((ptr_t)__data_start) + extern int _fdata[]; +# define DATASTART ((ptr_t)_fdata) extern int _end[]; # define DATAEND ((ptr_t)(&_end)) # define DYNAMIC_LOADING @@ -1882,7 +1881,6 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define DYNAMIC_LOADING -# define COUNT_UNMAPPED_REGIONS extern int _end[]; extern int __data_start[]; # define DATASTART ((ptr_t)(__data_start)) @@ -1901,7 +1899,6 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define DYNAMIC_LOADING -# define COUNT_UNMAPPED_REGIONS extern int _end[]; extern int __data_start[]; # define DATASTART ((ptr_t)(__data_start)) @@ -1932,9 +1929,6 @@ EXTERN_C_BEGIN # define OS_TYPE "HPUX" extern int __data_start[]; # define DATASTART ((ptr_t)(__data_start)) -# ifdef USE_MMAP -# define USE_MMAP_ANON -# endif # ifdef USE_HPUX_FIXED_STACKBOTTOM /* The following appears to work for 7xx systems running HP/UX */ /* 9.xx. Furthermore, it might result in much faster */ @@ -1943,22 +1937,13 @@ EXTERN_C_BEGIN /* default, since it may not work on older machine/OS */ /* combinations. (Thanks to Raymond X.T. Nijssen for uncovering */ /* this.) */ - /* This technique also doesn't work with HP/UX 11.xx. The */ - /* stack size is settable using the kernel maxssiz variable, */ - /* and in 11.23 and latter, the size can be set dynamically. */ - /* It also doesn't handle SHMEM_MAGIC binaries which have */ - /* stack and data in the first quadrant. */ # define STACKBOTTOM ((ptr_t)0x7b033000) /* from /etc/conf/h/param.h */ -# elif defined(USE_ENVIRON_POINTER) +# else /* Gustavo Rodriguez-Rivera suggested changing HEURISTIC2 */ /* to this. Note that the GC must be initialized before the */ - /* first putenv call. Unfortunately, some clients do not obey. */ + /* first putenv call. */ extern char ** environ; # define STACKBOTTOM ((ptr_t)environ) -# elif !defined(HEURISTIC2) - /* This uses pst_vm_status support. */ -# define HPUX_MAIN_STACKBOTTOM -# define NEED_FIND_LIMIT # endif # define DYNAMIC_LOADING EXTERN_C_END @@ -1975,7 +1960,6 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM -# define COUNT_UNMAPPED_REGIONS # define DYNAMIC_LOADING # define SEARCH_FOR_DATA_START extern int _end[]; @@ -1984,7 +1968,15 @@ EXTERN_C_BEGIN # ifdef OPENBSD # define OS_TYPE "OPENBSD" # ifndef GC_OPENBSD_THREADS -# define HEURISTIC2 + EXTERN_C_END +# include +# include + EXTERN_C_BEGIN +# ifdef USRSTACK +# define STACKBOTTOM ((ptr_t)USRSTACK) +# else +# define HEURISTIC2 +# endif # endif extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) @@ -2012,7 +2004,15 @@ EXTERN_C_BEGIN # define OS_TYPE "OPENBSD" # define ELF_CLASS ELFCLASS64 # ifndef GC_OPENBSD_THREADS + EXTERN_C_END +# include +# include + EXTERN_C_BEGIN +# ifdef USRSTACK +# define STACKBOTTOM ((ptr_t)USRSTACK) +# else # define HEURISTIC2 +# endif # endif extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) @@ -2033,13 +2033,11 @@ EXTERN_C_BEGIN /* Handle unmapped hole alpha*-*-freebsd[45]* puts between etext and edata. */ extern char etext[]; extern char edata[]; -# if !defined(CPPCHECK) - extern char end[]; -# endif + extern char end[]; # define NEED_FIND_LIMIT # define DATASTART ((ptr_t)(&etext)) - void * GC_find_limit(void *, int); -# define DATAEND (ptr_t)GC_find_limit(DATASTART, TRUE) + ptr_t GC_find_limit(ptr_t, GC_bool); +# define DATAEND GC_find_limit(DATASTART, TRUE) # define DATAEND_IS_FUNC # define GC_HAVE_DATAREGION2 # define DATASTART2 ((ptr_t)(&edata)) @@ -2071,7 +2069,6 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM -# define COUNT_UNMAPPED_REGIONS # ifdef __ELF__ # define SEARCH_FOR_DATA_START # define DYNAMIC_LOADING @@ -2080,11 +2077,9 @@ EXTERN_C_BEGIN # endif extern int _end[]; # define DATAEND ((ptr_t)(_end)) -# if !defined(REDIRECT_MALLOC) -# define MPROTECT_VDB +# define MPROTECT_VDB /* Has only been superficially tested. May not */ /* work on all versions. */ -# endif # endif # endif @@ -2096,8 +2091,8 @@ EXTERN_C_BEGIN /* Requires 8 byte alignment for malloc */ # define ALIGNMENT 4 # else -# if !defined(_LP64) && !defined(CPPCHECK) -# error Unknown ABI +# ifndef _LP64 +# error --> unknown ABI # endif # define CPP_WORDSZ 64 /* Requires 16 byte alignment for malloc */ @@ -2106,9 +2101,6 @@ EXTERN_C_BEGIN # define OS_TYPE "HPUX" extern int __data_start[]; # define DATASTART ((ptr_t)(__data_start)) -# ifdef USE_MMAP -# define USE_MMAP_ANON -# endif /* Gustavo Rodriguez-Rivera suggested changing HEURISTIC2 */ /* to this. Note that the GC must be initialized before the */ /* first putenv call. */ @@ -2142,7 +2134,6 @@ EXTERN_C_BEGIN /* backing store. */ extern ptr_t GC_register_stackbottom; # define BACKING_STORE_BASE GC_register_stackbottom -# define COUNT_UNMAPPED_REGIONS # define SEARCH_FOR_DATA_START # ifdef __GNUC__ # define DYNAMIC_LOADING @@ -2151,10 +2142,8 @@ EXTERN_C_BEGIN /* statically linked executables and an undefined reference */ /* to _DYNAMIC */ # endif -# if !defined(REDIRECT_MALLOC) -# define MPROTECT_VDB +# define MPROTECT_VDB /* Requires Linux 2.3.47 or later. */ -# endif extern int _end[]; # define DATAEND ((ptr_t)(_end)) # ifdef __GNUC__ @@ -2175,6 +2164,17 @@ EXTERN_C_BEGIN # endif /* __INTEL_COMPILER */ # endif # endif +# ifdef CYGWIN32 +# define OS_TYPE "CYGWIN32" +# define DATASTART ((ptr_t)GC_DATASTART) /* From gc.h */ +# define DATAEND ((ptr_t)GC_DATAEND) +# undef STACK_GRAN +# define STACK_GRAN 0x10000 +# ifdef USE_MMAP +# define NEED_FIND_LIMIT +# define USE_MMAP_ANON +# endif +# endif # ifdef MSWIN32 /* FIXME: This is a very partial guess. There is no port, yet. */ # define OS_TYPE "MSWIN32" @@ -2241,7 +2241,6 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM -# define COUNT_UNMAPPED_REGIONS # define DYNAMIC_LOADING extern int __data_start[] __attribute__((__weak__)); # define DATASTART ((ptr_t)(__data_start)) @@ -2267,29 +2266,22 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM -# define COUNT_UNMAPPED_REGIONS # define DYNAMIC_LOADING -# if defined(HOST_ANDROID) -# define SEARCH_FOR_DATA_START -# else - extern int __data_start[]; -# define DATASTART ((ptr_t)__data_start) -# endif + extern int __data_start[]; extern int _end[]; +# define DATASTART ((ptr_t)__data_start) # define DATAEND ((ptr_t)(&_end)) # endif # ifdef DARWIN /* iOS */ # define OS_TYPE "DARWIN" -# define DARWIN_DONT_PARSE_STACK 1 +# define DARWIN_DONT_PARSE_STACK # define DYNAMIC_LOADING # define DATASTART ((ptr_t)get_etext()) # define DATAEND ((ptr_t)get_end()) # define STACKBOTTOM ((ptr_t)0x16fdfffff) # define USE_MMAP_ANON - /* MPROTECT_VDB causes use of non-public API like exc_server, */ - /* this could be a reason for blocking the client application in */ - /* the store. */ +# define MPROTECT_VDB EXTERN_C_END # include EXTERN_C_BEGIN @@ -2322,33 +2314,14 @@ EXTERN_C_BEGIN # define ELF_CLASS ELFCLASS64 # define DYNAMIC_LOADING # endif -# ifdef OPENBSD -# define OS_TYPE "OPENBSD" -# define ELF_CLASS ELFCLASS64 -# ifndef GC_OPENBSD_THREADS -# define HEURISTIC2 -# endif - extern int __data_start[]; -# define DATASTART ((ptr_t)__data_start) - extern int _end[]; -# define DATAEND ((ptr_t)(&_end)) -# define DYNAMIC_LOADING -# endif # ifdef NINTENDO_SWITCH extern int __bss_end[]; -# define NO_HANDLE_FORK 1 +# define NO_HANDLE_FORK # define DATASTART (ptr_t)ALIGNMENT /* cannot be null */ # define DATAEND (ptr_t)(&__bss_end) void *switch_get_stack_bottom(void); # define STACKBOTTOM ((ptr_t)switch_get_stack_bottom()) # endif -# ifdef MSWIN32 /* UWP */ -# define OS_TYPE "MSWIN32" - /* TODO: Enable GWW_VDB and/or MPROTECT_VDB */ -# ifndef DATAEND -# define DATAEND /* not needed */ -# endif -# endif # ifdef NOSYS /* __data_start is usually defined in the target linker script. */ extern int __data_start[]; @@ -2381,7 +2354,6 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM -# define COUNT_UNMAPPED_REGIONS # undef STACK_GRAN # define STACK_GRAN 0x10000000 # ifdef __ELF__ @@ -2434,13 +2406,13 @@ EXTERN_C_BEGIN # ifdef DARWIN /* iOS */ # define OS_TYPE "DARWIN" -# define DARWIN_DONT_PARSE_STACK 1 +# define DARWIN_DONT_PARSE_STACK # define DYNAMIC_LOADING # define DATASTART ((ptr_t)get_etext()) # define DATAEND ((ptr_t)get_end()) # define STACKBOTTOM ((ptr_t)0x30000000) # define USE_MMAP_ANON - /* MPROTECT_VDB causes use of non-public API. */ +# define MPROTECT_VDB EXTERN_C_END # include EXTERN_C_BEGIN @@ -2455,7 +2427,15 @@ EXTERN_C_BEGIN # ifdef OPENBSD # define OS_TYPE "OPENBSD" # ifndef GC_OPENBSD_THREADS -# define HEURISTIC2 + EXTERN_C_END +# include +# include + EXTERN_C_BEGIN +# ifdef USRSTACK +# define STACKBOTTOM ((ptr_t)USRSTACK) +# else +# define HEURISTIC2 +# endif # endif extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) @@ -2464,7 +2444,7 @@ EXTERN_C_BEGIN # define DYNAMIC_LOADING # endif # ifdef SN_TARGET_PSP2 -# define NO_HANDLE_FORK 1 +# define NO_HANDLE_FORK # define DATASTART (ptr_t)ALIGNMENT # define DATAEND (ptr_t)ALIGNMENT void *psp2_get_stack_bottom(void); @@ -2478,13 +2458,6 @@ EXTERN_C_BEGIN void *n3ds_get_stack_bottom(void); # define STACKBOTTOM ((ptr_t)n3ds_get_stack_bottom()) # endif -# ifdef MSWIN32 /* UWP */ -# define OS_TYPE "MSWIN32" - /* TODO: Enable GWW_VDB and/or MPROTECT_VDB */ -# ifndef DATAEND -# define DATAEND /* not needed */ -# endif -# endif # ifdef NOSYS /* __data_start is usually defined in the target linker script. */ extern int __data_start[]; @@ -2502,7 +2475,6 @@ EXTERN_C_BEGIN # define OS_TYPE "LINUX" # define DYNAMIC_LOADING # define LINUX_STACKBOTTOM -# define COUNT_UNMAPPED_REGIONS # define SEARCH_FOR_DATA_START extern int _end[]; # define DATAEND ((ptr_t)(_end)) @@ -2518,7 +2490,6 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM -# define COUNT_UNMAPPED_REGIONS # define DYNAMIC_LOADING # define SEARCH_FOR_DATA_START extern int _end[]; @@ -2534,7 +2505,15 @@ EXTERN_C_BEGIN # ifdef OPENBSD # define OS_TYPE "OPENBSD" # ifndef GC_OPENBSD_THREADS -# define HEURISTIC2 + EXTERN_C_END +# include +# include + EXTERN_C_BEGIN +# ifdef USRSTACK +# define STACKBOTTOM ((ptr_t)USRSTACK) +# else +# define HEURISTIC2 +# endif # endif extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) @@ -2558,7 +2537,6 @@ EXTERN_C_BEGIN # define OS_TYPE "LINUX" # define DYNAMIC_LOADING # define LINUX_STACKBOTTOM -# define COUNT_UNMAPPED_REGIONS # define SEARCH_FOR_DATA_START extern int _end[]; # define DATAEND ((ptr_t)(_end)) @@ -2571,7 +2549,6 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM -# define COUNT_UNMAPPED_REGIONS # undef STACK_GRAN # define STACK_GRAN 0x10000000 # define DYNAMIC_LOADING @@ -2606,7 +2583,15 @@ EXTERN_C_BEGIN # define OS_TYPE "OPENBSD" # define ELF_CLASS ELFCLASS64 # ifndef GC_OPENBSD_THREADS + EXTERN_C_END +# include +# include + EXTERN_C_BEGIN +# ifdef USRSTACK +# define STACKBOTTOM ((ptr_t)USRSTACK) +# else # define HEURISTIC2 +# endif # endif extern int __data_start[]; extern int _end[]; @@ -2617,14 +2602,13 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM -# if !defined(REDIRECT_MALLOC) +# if !defined(GC_LINUX_THREADS) || !defined(REDIRECT_MALLOC) # define MPROTECT_VDB # else /* We seem to get random errors in incremental mode, */ /* possibly because Linux threads is itself a malloc client */ /* and can't deal with the signals. */ # endif -# define COUNT_UNMAPPED_REGIONS # ifdef __ELF__ # define DYNAMIC_LOADING EXTERN_C_END @@ -2656,7 +2640,7 @@ EXTERN_C_BEGIN # endif # ifdef DARWIN # define OS_TYPE "DARWIN" -# define DARWIN_DONT_PARSE_STACK 1 +# define DARWIN_DONT_PARSE_STACK # define DYNAMIC_LOADING /* XXX: see get_end(3), get_etext() and get_end() should not be used. */ /* These aren't used when dyld support is enabled (it is by default) */ @@ -2693,11 +2677,6 @@ EXTERN_C_BEGIN /* SIGTSTP and SIGCONT could be used alternatively. */ # endif # define FREEBSD_STACKBOTTOM -# if defined(__DragonFly__) - /* DragonFly BSD still has vm.max_proc_mmap, according to */ - /* its mmap(2) man page. */ -# define COUNT_UNMAPPED_REGIONS -# endif # ifdef __ELF__ # define DYNAMIC_LOADING # endif @@ -2762,7 +2741,7 @@ EXTERN_C_BEGIN # endif # define DYNAMIC_LOADING # if !defined(USE_MMAP) && defined(REDIRECT_MALLOC) -# define USE_MMAP 1 +# define USE_MMAP /* Otherwise we now use calloc. Mmap may result in the */ /* heap interleaved with thread stacks, which can result in */ /* excessive blacklisting. Sbrk is unusable since it */ @@ -2774,13 +2753,6 @@ EXTERN_C_BEGIN # define HEAP_START DATAEND # endif # endif -# ifdef CYGWIN32 -# define OS_TYPE "CYGWIN32" -# define RETRY_GET_THREAD_CONTEXT -# ifdef USE_MMAP -# define USE_MMAP_ANON -# endif -# endif # ifdef MSWIN_XBOX1 # define NO_GETENV # define DATASTART (ptr_t)ALIGNMENT @@ -2789,7 +2761,7 @@ EXTERN_C_BEGIN # define STACKBOTTOM ((ptr_t)durango_get_stack_bottom()) # define GETPAGESIZE() 4096 # ifndef USE_MMAP -# define USE_MMAP 1 +# define USE_MMAP # endif /* The following is from sys/mman.h: */ # define PROT_NONE 0 @@ -2802,7 +2774,6 @@ EXTERN_C_BEGIN # endif # ifdef MSWIN32 # define OS_TYPE "MSWIN32" -# define RETRY_GET_THREAD_CONTEXT /* STACKBOTTOM and DATASTART are handled specially in */ /* os_dep.c. */ # if !defined(__GNUC__) || defined(__INTEL_COMPILER) \ @@ -2825,27 +2796,24 @@ EXTERN_C_BEGIN # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM -# define COUNT_UNMAPPED_REGIONS # define MPROTECT_VDB # ifdef __ELF__ -# if !defined(REDIRECT_MALLOC) -# define MPROTECT_VDB -# endif +# define DYNAMIC_LOADING EXTERN_C_END # include EXTERN_C_BEGIN # if defined(__GLIBC__) && __GLIBC__ >= 2 # define SEARCH_FOR_DATA_START # else -# error Unknown Hexagon libc configuration +# error --> unknown Hexagon libc configuration # endif extern int _end[]; # define DATAEND ((ptr_t)(_end)) # elif !defined(CPPCHECK) -# error Bad Hexagon Linux configuration +# error --> bad Hexagon Linux configuration # endif # else -# error Unknown Hexagon OS configuration +# error --> unknown Hexagon OS configuration # endif # endif @@ -2860,7 +2828,6 @@ EXTERN_C_BEGIN extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) # define LINUX_STACKBOTTOM -# define COUNT_UNMAPPED_REGIONS # define DYNAMIC_LOADING # endif # endif @@ -2879,7 +2846,6 @@ EXTERN_C_BEGIN extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) # define LINUX_STACKBOTTOM -# define COUNT_UNMAPPED_REGIONS # define DYNAMIC_LOADING # endif # endif @@ -2890,10 +2856,9 @@ EXTERN_C_BEGIN # define ALIGNMENT (CPP_WORDSZ/8) # ifdef LINUX # define OS_TYPE "LINUX" - extern int __data_start[] __attribute__((__weak__)); + extern int __data_start[]; # define DATASTART ((ptr_t)__data_start) # define LINUX_STACKBOTTOM -# define COUNT_UNMAPPED_REGIONS # define DYNAMIC_LOADING # endif # endif /* RISCV */ @@ -2903,10 +2868,6 @@ EXTERN_C_BEGIN # define USE_LIBC_PRIVATES #endif -#ifdef NO_RETRY_GET_THREAD_CONTEXT -# undef RETRY_GET_THREAD_CONTEXT -#endif - #if defined(LINUX_STACKBOTTOM) && defined(NO_PROC_STAT) \ && !defined(USE_LIBC_PRIVATES) /* This combination will fail, since we have no way to get */ @@ -2918,7 +2879,7 @@ EXTERN_C_BEGIN #endif #if defined(USE_MMAP_ANON) && !defined(USE_MMAP) -# define USE_MMAP 1 +# define USE_MMAP #elif defined(LINUX) && defined(USE_MMAP) /* The kernel may do a somewhat better job merging mappings etc. */ /* with anonymous mappings. */ @@ -2964,17 +2925,14 @@ EXTERN_C_BEGIN #endif #ifndef DATAEND -# if !defined(CPPCHECK) - extern int end[]; -# endif + extern int end[]; # define DATAEND ((ptr_t)(end)) #endif /* Workaround for Android NDK clang 3.5+ (as of NDK r10e) which does */ /* not provide correct _end symbol. Unfortunately, alternate __end__ */ /* symbol is provided only by NDK "bfd" linker. */ -#if defined(HOST_ANDROID) && defined(__clang__) \ - && !defined(BROKEN_UUENDUU_SYM) +#if defined(HOST_ANDROID) && defined(__clang__) # undef DATAEND # pragma weak __end__ extern int __end__[]; @@ -3075,12 +3033,14 @@ EXTERN_C_BEGIN #if defined(CPPCHECK) # undef CPP_WORDSZ # define CPP_WORDSZ (__SIZEOF_POINTER__ * 8) -#elif CPP_WORDSZ != 32 && CPP_WORDSZ != 64 -# error Bad word size +#endif + +#if CPP_WORDSZ != 32 && CPP_WORDSZ != 64 +# error --> bad word size #endif #if !defined(ALIGNMENT) && !defined(CPPCHECK) -# error Undefined ALIGNMENT +# error --> undefined ALIGNMENT #endif #ifdef PCR @@ -3095,7 +3055,7 @@ EXTERN_C_BEGIN #if !defined(STACKBOTTOM) && (defined(ECOS) || defined(NOSYS)) \ && !defined(CPPCHECK) -# error Undefined STACKBOTTOM +# error --> undefined STACKBOTTOM #endif #ifdef IGNORE_DYNAMIC_LOADING @@ -3109,19 +3069,15 @@ EXTERN_C_BEGIN #if (defined(MSWIN32) || defined(MSWINCE)) && !defined(USE_WINALLOC) /* USE_WINALLOC is only an option for Cygwin. */ -# define USE_WINALLOC 1 +# define USE_WINALLOC #endif #ifdef USE_WINALLOC # undef USE_MMAP #endif -#if defined(DARWIN) || defined(FREEBSD) || defined(HAIKU) \ - || defined(IRIX5) || defined(LINUX) || defined(NETBSD) \ - || defined(OPENBSD) || defined(SOLARIS) \ - || ((defined(CYGWIN32) || defined(USE_MMAP) || defined(USE_MUNMAP)) \ - && !defined(USE_WINALLOC)) - /* Try both sbrk and mmap, in that order. */ +#if defined(LINUX) || defined(FREEBSD) || defined(SOLARIS) || defined(IRIX5) \ + || ((defined(USE_MMAP) || defined(USE_MUNMAP)) && !defined(USE_WINALLOC)) # define MMAP_SUPPORTED #endif @@ -3135,20 +3091,6 @@ EXTERN_C_BEGIN # define MUNMAP_THRESHOLD 2 #endif -#if defined(USE_MUNMAP) && defined(COUNT_UNMAPPED_REGIONS) \ - && !defined(GC_UNMAPPED_REGIONS_SOFT_LIMIT) - /* The default limit of vm.max_map_count on Linux is ~65530. */ - /* There is approximately one mapped region to every unmapped region. */ - /* Therefore if we aim to use up to half of vm.max_map_count for the */ - /* GC (leaving half for the rest of the process) then the number of */ - /* unmapped regions should be one quarter of vm.max_map_count. */ -# if defined(__DragonFly__) -# define GC_UNMAPPED_REGIONS_SOFT_LIMIT (1000000 / 4) -# else -# define GC_UNMAPPED_REGIONS_SOFT_LIMIT 16384 -# endif -#endif - #if defined(GC_DISABLE_INCREMENTAL) || defined(DEFAULT_VDB) # undef GWW_VDB # undef MPROTECT_VDB @@ -3165,12 +3107,6 @@ EXTERN_C_BEGIN # undef GWW_VDB #endif -#if defined(BASE_ATOMIC_OPS_EMULATED) - /* GC_write_fault_handler() cannot use lock-based atomic primitives */ - /* as this could lead to a deadlock. */ -# undef MPROTECT_VDB -#endif - #if defined(USE_MUNMAP) && defined(GWW_VDB) # undef MPROTECT_VDB /* TODO: Cannot deal with address space holes. */ /* Else if MPROTECT_VDB is available but not GWW_VDB then decide */ @@ -3180,11 +3116,6 @@ EXTERN_C_BEGIN /* PARALLEL_MARK does not cause undef MPROTECT_VDB any longer. */ -#if defined(USE_PROC_FOR_LIBRARIES) && defined(GC_LINUX_THREADS) - /* Incremental GC is incompatible with /proc roots. */ -# undef MPROTECT_VDB -#endif - #if defined(MPROTECT_VDB) && defined(GC_PREFER_MPROTECT_VDB) /* Choose MPROTECT_VDB manually (if multiple strategies available). */ # undef PCR_VDB @@ -3197,10 +3128,6 @@ EXTERN_C_BEGIN # undef MPROTECT_VDB #endif -#if defined(MPROTECT_VDB) && !defined(MSWIN32) && !defined(MSWINCE) -# include /* for SA_SIGINFO, SIGBUS */ -#endif - #if defined(SIGBUS) && !defined(HAVE_SIGBUS) && !defined(CPPCHECK) # define HAVE_SIGBUS #endif @@ -3209,8 +3136,7 @@ EXTERN_C_BEGIN # define NO_SA_SIGACTION #endif -#if (defined(NO_SA_SIGACTION) || defined(GC_NO_SIGSETJMP)) \ - && defined(MPROTECT_VDB) && !defined(DARWIN) \ +#if defined(NO_SA_SIGACTION) && defined(MPROTECT_VDB) && !defined(DARWIN) \ && !defined(MSWIN32) && !defined(MSWINCE) # undef MPROTECT_VDB #endif @@ -3229,7 +3155,7 @@ EXTERN_C_BEGIN || (defined(LINUX) && !defined(__gnu_linux__)) \ || (defined(RTEMS) && defined(I386)) || defined(HOST_ANDROID)) \ && !defined(NO_GETCONTEXT) -# define NO_GETCONTEXT 1 +# define NO_GETCONTEXT #endif #ifndef PREFETCH @@ -3295,33 +3221,33 @@ EXTERN_C_BEGIN #endif #if !defined(CPPCHECK) -# if defined(GC_IRIX_THREADS) && !defined(IRIX5) -# error Inconsistent configuration -# endif -# if defined(GC_LINUX_THREADS) && !defined(LINUX) && !defined(NACL) -# error Inconsistent configuration -# endif -# if defined(GC_NETBSD_THREADS) && !defined(NETBSD) -# error Inconsistent configuration -# endif -# if defined(GC_FREEBSD_THREADS) && !defined(FREEBSD) -# error Inconsistent configuration -# endif -# if defined(GC_SOLARIS_THREADS) && !defined(SOLARIS) -# error Inconsistent configuration -# endif -# if defined(GC_HPUX_THREADS) && !defined(HPUX) -# error Inconsistent configuration -# endif -# if defined(GC_AIX_THREADS) && !defined(_AIX) -# error Inconsistent configuration -# endif -# if defined(GC_WIN32_THREADS) && !defined(CYGWIN32) && !defined(MSWIN32) \ - && !defined(MSWINCE) && !defined(MSWIN_XBOX1) -# error Inconsistent configuration -# endif +#if defined(GC_IRIX_THREADS) && !defined(IRIX5) +# error --> inconsistent configuration +#endif +#if defined(GC_LINUX_THREADS) && !defined(LINUX) && !defined(NACL) +# error --> inconsistent configuration +#endif +#if defined(GC_NETBSD_THREADS) && !defined(NETBSD) +# error --> inconsistent configuration +#endif +#if defined(GC_FREEBSD_THREADS) && !defined(FREEBSD) +# error --> inconsistent configuration +#endif +#if defined(GC_SOLARIS_THREADS) && !defined(SOLARIS) +# error --> inconsistent configuration +#endif +#if defined(GC_HPUX_THREADS) && !defined(HPUX) +# error --> inconsistent configuration +#endif +#if defined(GC_AIX_THREADS) && !defined(_AIX) +# error --> inconsistent configuration +#endif +#if defined(GC_WIN32_THREADS) && !defined(CYGWIN32) && !defined(MSWIN32) \ + && !defined(MSWINCE) && !defined(MSWIN_XBOX1) +# error --> inconsistent configuration +#endif # if defined(GC_WIN32_PTHREADS) && defined(CYGWIN32) -# error Inconsistent configuration +# error --> inconsistent configuration # endif #endif /* !CPPCHECK */ @@ -3333,7 +3259,7 @@ EXTERN_C_BEGIN #endif #if defined(PARALLEL_MARK) && !defined(THREADS) && !defined(CPPCHECK) -# error Invalid config: PARALLEL_MARK requires GC_THREADS +# error "invalid config - PARALLEL_MARK requires GC_THREADS" #endif #if (((defined(MSWIN32) || defined(MSWINCE)) && !defined(__GNUC__)) \ @@ -3535,11 +3461,11 @@ EXTERN_C_BEGIN || (defined(SOLARIS) && (!defined(_XOPEN_SOURCE) \ || defined(__EXTENSIONS__))) \ || defined(LINUX)) && !defined(HAVE_DLADDR) -# define HAVE_DLADDR 1 +# define HAVE_DLADDR #endif #if defined(MAKE_BACK_GRAPH) && !defined(DBG_HDRS_ALL) -# define DBG_HDRS_ALL 1 +# define DBG_HDRS_ALL #endif #if defined(POINTER_MASK) && !defined(POINTER_SHIFT) @@ -3551,7 +3477,11 @@ EXTERN_C_BEGIN #endif #if !defined(FIXUP_POINTER) && defined(POINTER_MASK) -# define FIXUP_POINTER(p) (p = ((p) & POINTER_MASK) << POINTER_SHIFT) +# if defined(CPPCHECK) +# define FIXUP_POINTER(p) (p = (p) << 4) /* e.g. */ +# else +# define FIXUP_POINTER(p) (p = ((p) & POINTER_MASK) << POINTER_SHIFT) +# endif #endif #if defined(FIXUP_POINTER) @@ -3566,19 +3496,21 @@ EXTERN_C_BEGIN /* Some static sanity tests. */ #if !defined(CPPCHECK) -# if defined(MARK_BIT_PER_GRANULE) && defined(MARK_BIT_PER_OBJ) -# error Define only one of MARK_BIT_PER_GRANULE and MARK_BIT_PER_OBJ -# endif -# if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN) -# error Only one of STACK_GROWS_UP and STACK_GROWS_DOWN should be defined -# endif -# if !defined(STACK_GROWS_UP) && !defined(STACK_GROWS_DOWN) -# error One of STACK_GROWS_UP and STACK_GROWS_DOWN should be defined -# endif -# if defined(REDIRECT_MALLOC) && defined(THREADS) && !defined(LINUX) \ +#if defined(MARK_BIT_PER_GRANULE) && defined(MARK_BIT_PER_OBJ) +# error Define only one of MARK_BIT_PER_GRANULE and MARK_BIT_PER_OBJ. +#endif + +#if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN) +# error "Only one of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd." +#endif +#if !defined(STACK_GROWS_UP) && !defined(STACK_GROWS_DOWN) +# error "One of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd." +#endif + +#if defined(REDIRECT_MALLOC) && defined(THREADS) && !defined(LINUX) \ && !defined(REDIRECT_MALLOC_IN_HEADER) -# error REDIRECT_MALLOC with THREADS works at most on Linux -# endif +# error "REDIRECT_MALLOC with THREADS works at most on Linux." +#endif #endif /* !CPPCHECK */ #ifdef GC_PRIVATE_H @@ -3619,8 +3551,8 @@ EXTERN_C_BEGIN GC_page_size)) \ + GC_page_size - 1) # elif defined(MSWIN_XBOX1) - ptr_t GC_durango_get_mem(size_t bytes); -# define GET_MEM(bytes) (struct hblk *)GC_durango_get_mem(bytes) + void *durango_get_mem(size_t bytes, size_t page_size); +# define GET_MEM(bytes) (struct hblk *)durango_get_mem(bytes, 0) # elif defined(MSWIN32) || defined(CYGWIN32) ptr_t GC_win32_get_mem(size_t bytes); # define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes) diff --git a/gc/include/private/pthread_support.h b/gc/include/private/pthread_support.h index 17fe8b627..2dc1541ac 100644 --- a/gc/include/private/pthread_support.h +++ b/gc/include/private/pthread_support.h @@ -132,7 +132,7 @@ typedef struct GC_Thread_Rep { /* and detach. */ # ifdef THREAD_LOCAL_ALLOC - struct thread_local_freelists tlfs GC_ATTR_WORD_ALIGNED; + struct thread_local_freelists tlfs; # endif } * GC_thread; diff --git a/gc/include/private/specific.h b/gc/include/private/specific.h index ec2ed9b4e..a1873ac85 100644 --- a/gc/include/private/specific.h +++ b/gc/include/private/specific.h @@ -12,9 +12,6 @@ * by adding a lock. */ -#ifndef GC_SPECIFIC_H -#define GC_SPECIFIC_H - #include EXTERN_C_BEGIN @@ -116,5 +113,3 @@ GC_INLINE void * GC_getspecific(tsd * key) } EXTERN_C_END - -#endif /* GC_SPECIFIC_H */ diff --git a/gc/include/private/thread_local_alloc.h b/gc/include/private/thread_local_alloc.h index 1ffa28b0c..276de402f 100644 --- a/gc/include/private/thread_local_alloc.h +++ b/gc/include/private/thread_local_alloc.h @@ -95,7 +95,7 @@ typedef struct thread_local_freelists { /* Note: Preserve *_freelists names for some clients. */ # ifdef GC_GCJ_SUPPORT void * gcj_freelists[TINY_FREELISTS]; -# define ERROR_FL ((void *)GC_WORD_MAX) +# define ERROR_FL ((void *)(word)-1) /* Value used for gcj_freelists[-1]; allocation is */ /* erroneous. */ # endif diff --git a/gc/mach_dep.c b/gc/mach_dep.c index 49d81bb63..60b73b228 100644 --- a/gc/mach_dep.c +++ b/gc/mach_dep.c @@ -228,7 +228,7 @@ GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *), volatile ptr_t arg) { volatile int dummy; - volatile ptr_t context = 0; + void * volatile context = 0; # if defined(HAVE_PUSH_REGS) GC_push_regs(); @@ -263,7 +263,7 @@ GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *), /* getcontext() is broken, do not try again. */ /* E.g., to workaround a bug in Docker ubuntu_32bit. */ } else { - context = (ptr_t)&ctxt; + context = &ctxt; } if (EXPECT(0 == getcontext_works, FALSE)) getcontext_works = context != NULL ? 1 : -1; @@ -327,11 +327,11 @@ GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *), # endif /* !HAVE_PUSH_REGS */ /* TODO: context here is sometimes just zero. At the moment, the */ /* callees don't really need it. */ - fn(arg, (/* no volatile */ void *)context); + fn(arg, context); /* Strongly discourage the compiler from treating the above */ /* as a tail-call, since that would pop the register */ /* contents before we get a chance to look at them. */ - GC_noop1(COVERT_DATAFLOW(&dummy)); + GC_noop1((word)(&dummy)); } #endif /* !SN_TARGET_ORBIS && !SN_TARGET_PSP2 */ diff --git a/gc/mallocx.c b/gc/mallocx.c index 77d284ad7..9e93c7071 100644 --- a/gc/mallocx.c +++ b/gc/mallocx.c @@ -349,9 +349,10 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t lb, int k, void **result) struct hblk * hbp; hdr * hhdr; - while ((hbp = rlh[lg]) != NULL) { + rlh += lg; + while ((hbp = *rlh) != 0) { hhdr = HDR(hbp); - rlh[lg] = hhdr -> hb_next; + *rlh = hhdr -> hb_next; GC_ASSERT(hhdr -> hb_sz == lb); hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no; # ifdef PARALLEL_MARK @@ -415,9 +416,6 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t lb, int k, void **result) /* GC lock is needed for reclaim list access. We */ /* must decrement fl_builder_count before reacquiring */ /* the lock. Hopefully this path is rare. */ - - rlh = ok -> ok_reclaim_list; /* reload rlh after locking */ - if (NULL == rlh) break; } # endif } diff --git a/gc/mark.c b/gc/mark.c index 93b01c839..b1d59026c 100644 --- a/gc/mark.c +++ b/gc/mark.c @@ -40,7 +40,7 @@ void GC_noop6(word arg1 GC_ATTR_UNUSED, word arg2 GC_ATTR_UNUSED, word arg5 GC_ATTR_UNUSED, word arg6 GC_ATTR_UNUSED) { /* Avoid GC_noop6 calls to be optimized away. */ -# if defined(AO_HAVE_compiler_barrier) && !defined(BASE_ATOMIC_OPS_EMULATED) +# ifdef AO_CLEAR AO_compiler_barrier(); /* to serve as a special side-effect */ # else GC_noop1(0); @@ -123,7 +123,7 @@ STATIC GC_bool GC_objects_are_marked = FALSE; /* Are there collectible marked objects in the heap? */ /* Is a collection in progress? Note that this can return true in the */ -/* non-incremental case, if a collection has been abandoned and the */ +/* nonincremental case, if a collection has been abandoned and the */ /* mark state is now MS_INVALID. */ GC_INNER GC_bool GC_collection_in_progress(void) { @@ -161,7 +161,7 @@ GC_INNER void GC_set_hdr_marks(hdr *hhdr) } # else for (i = 0; i < divWORDSZ(n_marks + WORDSZ); ++i) { - hhdr -> hb_marks[i] = GC_WORD_MAX; + hhdr -> hb_marks[i] = ONES; } # endif # ifdef MARK_BIT_PER_OBJ @@ -502,8 +502,7 @@ static void alloc_mark_stack(size_t); /* to the exception case; our results are invalid and we have */ /* to start over. This cannot be prevented since we can't */ /* block in DllMain. */ - if (GC_started_thread_while_stopped()) - goto handle_thr_start; + if (GC_started_thread_while_stopped()) goto handle_ex; # endif rm_handler: return ret_val; @@ -527,7 +526,7 @@ static void alloc_mark_stack(size_t); # endif er.alt_path = &&handle_ex; # pragma GCC diagnostic pop -# elif !defined(CPPCHECK) /* pragma diagnostic is not supported */ +# else /* pragma diagnostic is not supported */ er.alt_path = &&handle_ex; # endif er.ex_reg.handler = mark_ex_handler; @@ -540,7 +539,7 @@ static void alloc_mark_stack(size_t); goto handle_ex; # if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS) if (GC_started_thread_while_stopped()) - goto handle_thr_start; + goto handle_ex; # endif rm_handler: /* Uninstall the exception handler */ @@ -554,17 +553,10 @@ static void alloc_mark_stack(size_t); /* thread that is in the process of exiting, and disappears */ /* while we are marking it. This seems extremely difficult to */ /* avoid otherwise. */ -# ifndef DEFAULT_VDB - if (GC_auto_incremental) { - static GC_bool is_warned = FALSE; - - if (!is_warned) { - is_warned = TRUE; - WARN("Incremental GC incompatible with /proc roots\n", 0); - } - /* I'm not sure if this could still work ... */ - } -# endif + if (GC_incremental) { + WARN("Incremental GC incompatible with /proc roots\n", 0); + /* I'm not sure if this could still work ... */ + } GC_setup_temporary_fault_handler(); if(SETJMP(GC_jmp_buf) != 0) goto handle_ex; ret_val = GC_mark_some_inner(cold_gc_frame); @@ -586,10 +578,6 @@ static void alloc_mark_stack(size_t); " memory mapping disappeared\n", 0); } } -# if (defined(MSWIN32) || defined(MSWINCE)) && defined(GC_WIN32_THREADS) \ - && !defined(GC_PTHREADS) - handle_thr_start: -# endif /* We have bad roots on the stack. Discard mark stack. */ /* Rescan from marked objects. Redetermine roots. */ # ifdef REGISTER_LIBRARIES_EARLY @@ -1282,7 +1270,7 @@ GC_INNER void GC_scratch_recycle_inner(void *ptr, size_t bytes) /* TODO: Assert correct memory flags if GWW_VDB */ if (page_offset != 0) displ = GC_page_size - page_offset; - recycled_bytes = bytes > displ ? (bytes - displ) & ~(GC_page_size-1) : 0; + recycled_bytes = (bytes - displ) & ~(GC_page_size - 1); GC_COND_LOG_PRINTF("Recycle %lu/%lu scratch-allocated bytes at %p\n", (unsigned long)recycled_bytes, (unsigned long)bytes, ptr); @@ -1533,7 +1521,7 @@ struct trace_entry { word bytes_allocd; word arg1; word arg2; -} GC_trace_buf[TRACE_ENTRIES] = { { NULL, 0, 0, 0, 0 } }; +} GC_trace_buf[TRACE_ENTRIES]; int GC_trace_buf_ptr = 0; @@ -1617,8 +1605,7 @@ GC_INNER void GC_push_all_stack(ptr_t bottom, ptr_t top) # if defined(THREADS) && defined(MPROTECT_VDB) && !GC_auto_incremental # endif - && (word)GC_mark_stack_top - < (word)(GC_mark_stack_limit - INITIAL_MARK_STACK_SIZE/8)) { + ) { GC_push_all(bottom, top); } else # endif @@ -1974,8 +1961,8 @@ STATIC struct hblk * GC_push_next_marked(struct hblk *h) hdr * hhdr = HDR(h); if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr) || HBLK_IS_FREE(hhdr), FALSE)) { - h = GC_next_block(h, FALSE); - if (NULL == h) return NULL; + h = GC_next_used_block(h); + if (h == 0) return(0); hhdr = GC_find_header((ptr_t)h); } else { # ifdef LINT2 @@ -1996,8 +1983,8 @@ STATIC struct hblk * GC_push_next_marked(struct hblk *h) for (;;) { if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr) || HBLK_IS_FREE(hhdr), FALSE)) { - h = GC_next_block(h, FALSE); - if (NULL == h) return NULL; + h = GC_next_used_block(h); + if (h == 0) return(0); hhdr = GC_find_header((ptr_t)h); } else { # ifdef LINT2 @@ -2037,8 +2024,8 @@ STATIC struct hblk * GC_push_next_marked_uncollectable(struct hblk *h) for (;;) { if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr) || HBLK_IS_FREE(hhdr), FALSE)) { - h = GC_next_block(h, FALSE); - if (NULL == h) return NULL; + h = GC_next_used_block(h); + if (h == 0) return(0); hhdr = GC_find_header((ptr_t)h); } else { # ifdef LINT2 diff --git a/gc/mark_rts.c b/gc/mark_rts.c index 9e3eb1938..7d166eda5 100644 --- a/gc/mark_rts.c +++ b/gc/mark_rts.c @@ -502,11 +502,8 @@ STATIC void GC_remove_tmp_roots(void) GC_INNER ptr_t GC_approx_sp(void) { volatile word sp; -# if defined(S390) && !defined(CPPCHECK) && (__clang_major__ < 8) - /* Workaround a crash in SystemZTargetLowering of libLLVM-3.8. */ - sp = (word)&sp; -# elif defined(CPPCHECK) || (__GNUC__ >= 4 /* GC_GNUC_PREREQ(4, 0) */ \ - && !defined(STACK_NOT_SCANNED)) +# if defined(CPPCHECK) || (__GNUC__ >= 4 /* GC_GNUC_PREREQ(4, 0) */ \ + && !defined(STACK_NOT_SCANNED)) /* TODO: Use GC_GNUC_PREREQ after fixing a bug in cppcheck. */ sp = (word)__builtin_frame_address(0); # else diff --git a/gc/misc.c b/gc/misc.c index 0869e0125..fe4605be6 100644 --- a/gc/misc.c +++ b/gc/misc.c @@ -314,7 +314,7 @@ STATIC void GC_init_size_map(void) } /* Make sure the recursive call is not a tail call, and the bzero */ /* call is not recognized as dead code. */ - GC_noop1(COVERT_DATAFLOW(dummy)); + GC_noop1((word)dummy); return(arg); } # endif /* !ASM_CLEAR_CODE */ @@ -545,7 +545,7 @@ GC_API void GC_CALL GC_get_heap_usage_safe(GC_word *pheap_size, pstats->non_gc_bytes = GC_non_gc_bytes; pstats->gc_no = GC_gc_no; /* could be -1 */ # ifdef PARALLEL_MARK - pstats->markers_m1 = (word)((signed_word)GC_markers_m1); + pstats->markers_m1 = (word)GC_markers_m1; # else pstats->markers_m1 = 0; /* one marker */ # endif @@ -764,7 +764,7 @@ GC_API int GC_CALL GC_is_init_called(void) STATIC void GC_exit_check(void) { if (GC_find_leak && !skip_gc_atexit) { -# ifdef THREADS +# if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) GC_in_thread_creation = TRUE; /* OK to collect from unknown thread. */ GC_gcollect(); GC_in_thread_creation = FALSE; @@ -817,7 +817,9 @@ GC_API int GC_CALL GC_is_init_called(void) #endif #if defined(MSWIN32) && !defined(MSWINRT_FLAVOR) && !defined(MSWIN_XBOX1) \ - && !defined(SMALL_CONFIG) + && (!defined(SMALL_CONFIG) \ + || (!defined(_WIN64) && defined(GC_WIN32_THREADS) \ + && defined(CHECK_NOT_WOW64))) STATIC void GC_win32_MessageBoxA(const char *msg, const char *caption, unsigned flags) { @@ -830,7 +832,7 @@ GC_API int GC_CALL GC_is_init_called(void) if (hU32) { FARPROC pfn = GetProcAddress(hU32, "MessageBoxA"); if (pfn) - (void)(*(int (WINAPI *)(HWND, LPCSTR, LPCSTR, UINT))(word)pfn)( + (void)(*(int (WINAPI *)(HWND, LPCSTR, LPCSTR, UINT))pfn)( NULL /* hWnd */, msg, caption, flags); (void)FreeLibrary(hU32); } @@ -923,6 +925,30 @@ GC_API void GC_CALL GC_init(void) initial_heap_sz = MINHINCR * HBLKSIZE; # endif +# if defined(MSWIN32) && !defined(_WIN64) && defined(GC_WIN32_THREADS) \ + && defined(CHECK_NOT_WOW64) + { + /* Windows: running 32-bit GC on 64-bit system is broken! */ + /* WoW64 bug affects SuspendThread, no workaround exists. */ + HMODULE hK32 = GetModuleHandle(TEXT("kernel32.dll")); + if (hK32) { + FARPROC pfn = GetProcAddress(hK32, "IsWow64Process"); + BOOL bIsWow64 = FALSE; + if (pfn + && (*(BOOL (WINAPI*)(HANDLE, BOOL*))pfn)(GetCurrentProcess(), + &bIsWow64) + && bIsWow64) { + GC_win32_MessageBoxA("This program uses BDWGC garbage collector" + " compiled for 32-bit but running on 64-bit Windows.\n" + "This is known to be broken due to a design flaw" + " in Windows itself! Expect erratic behavior...", + "32-bit program running on 64-bit system", + MB_ICONWARNING | MB_OK); + } + } + } +# endif + DISABLE_CANCEL(cancel_state); /* Note that although we are nominally called with the */ /* allocation lock held, the allocation lock is now */ @@ -957,14 +983,14 @@ GC_API void GC_CALL GC_init(void) # else { # ifndef MSWINCE - FARPROC pfn = 0; + BOOL (WINAPI *pfn)(LPCRITICAL_SECTION, DWORD) = 0; HMODULE hK32 = GetModuleHandle(TEXT("kernel32.dll")); if (hK32) - pfn = GetProcAddress(hK32, - "InitializeCriticalSectionAndSpinCount"); + pfn = (BOOL (WINAPI *)(LPCRITICAL_SECTION, DWORD)) + GetProcAddress(hK32, + "InitializeCriticalSectionAndSpinCount"); if (pfn) { - (*(BOOL (WINAPI *)(LPCRITICAL_SECTION, DWORD))(word)pfn)( - &GC_allocate_ml, SPIN_COUNT); + pfn(&GC_allocate_ml, SPIN_COUNT); } else # endif /* !MSWINCE */ /* else */ InitializeCriticalSection(&GC_allocate_ml); @@ -1005,7 +1031,7 @@ GC_API void GC_CALL GC_init(void) if (0 != file_name) # endif { - int log_d = open(file_name, O_CREAT | O_WRONLY | O_APPEND, 0644); + int log_d = open(file_name, O_CREAT|O_WRONLY|O_APPEND, 0666); if (log_d < 0) { GC_err_printf("Failed to open %s as log file\n", file_name); } else { @@ -1087,12 +1113,15 @@ GC_API void GC_CALL GC_init(void) } } # endif -# if !defined(GC_DISABLE_INCREMENTAL) && !defined(NO_CLOCK) +# ifndef GC_DISABLE_INCREMENTAL { char * time_limit_string = GETENV("GC_PAUSE_TIME_TARGET"); if (0 != time_limit_string) { long time_limit = atol(time_limit_string); - if (time_limit > 0) { + if (time_limit < 5) { + WARN("GC_PAUSE_TIME_TARGET environment variable value too small " + "or bad syntax: Ignoring\n", 0); + } else { GC_time_limit = time_limit; } } @@ -1125,7 +1154,7 @@ GC_API void GC_CALL GC_init(void) if (space_divisor_string != NULL) { int space_divisor = atoi(space_divisor_string); if (space_divisor > 0) - GC_free_space_divisor = (unsigned)space_divisor; + GC_free_space_divisor = (word)space_divisor; } } # ifdef USE_MUNMAP @@ -1183,7 +1212,7 @@ GC_API void GC_CALL GC_init(void) # if defined(USE_PROC_FOR_LIBRARIES) && defined(GC_LINUX_THREADS) WARN("USE_PROC_FOR_LIBRARIES + GC_LINUX_THREADS performs poorly.\n", 0); /* If thread stacks are cached, they tend to be scanned in */ - /* entirety as part of the root set. This will grow them to */ + /* entirety as part of the root set. This wil grow them to */ /* maximum size, and is generally not desirable. */ # endif # if defined(SEARCH_FOR_DATA_START) @@ -1229,9 +1258,7 @@ GC_API void GC_CALL GC_init(void) # endif # ifndef GC_DISABLE_INCREMENTAL if (GC_incremental || 0 != GETENV("GC_ENABLE_INCREMENTAL")) { -# if defined(BASE_ATOMIC_OPS_EMULATED) || defined(CHECKSUMS) \ - || defined(REDIRECT_MALLOC) || defined(REDIRECT_MALLOC_IN_HEADER) \ - || defined(SMALL_CONFIG) +# if defined(CHECKSUMS) || defined(SMALL_CONFIG) /* TODO: Implement CHECKSUMS for manual VDB. */ # else if (manual_vdb_allowed) { @@ -1274,9 +1301,6 @@ GC_API void GC_CALL GC_init(void) GC_set_max_heap_size(max_heap_sz); } } -# if defined(GC_ASSERTIONS) && defined(GC_ALWAYS_MULTITHREADED) - LOCK(); /* just to set GC_lock_holder */ -# endif if (!GC_expand_hp_inner(divHBLKSZ(initial_heap_sz))) { GC_err_printf("Can't start up: not enough memory\n"); EXIT(); @@ -1304,6 +1328,9 @@ GC_API void GC_CALL GC_init(void) GC_pcr_install(); # endif GC_is_initialized = TRUE; +# if defined(GC_ASSERTIONS) && defined(GC_ALWAYS_MULTITHREADED) + LOCK(); /* just to set GC_lock_holder */ +# endif # if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS) GC_thr_init(); # ifdef PARALLEL_MARK @@ -1376,9 +1403,7 @@ GC_API void GC_CALL GC_enable_incremental(void) GC_init(); LOCK(); } else { -# if !defined(BASE_ATOMIC_OPS_EMULATED) && !defined(CHECKSUMS) \ - && !defined(REDIRECT_MALLOC) \ - && !defined(REDIRECT_MALLOC_IN_HEADER) && !defined(SMALL_CONFIG) +# if !defined(CHECKSUMS) && !defined(SMALL_CONFIG) if (manual_vdb_allowed) { GC_manual_vdb = TRUE; GC_incremental = TRUE; @@ -1707,16 +1732,10 @@ GC_API void GC_CALL GC_enable_incremental(void) # define WRITE(level, buf, len) switch_log_write(buf, len) #else - -# if !defined(SN_TARGET_ORBIS) && !defined(SN_TARGET_PSP2) -# if !defined(AMIGA) && !defined(MSWIN_XBOX1) \ - && !defined(__CC_ARM) -# include -# endif -# if !defined(ECOS) && !defined(NOSYS) -# include -# endif -# endif /* !SN_TARGET_ORBIS && !SN_TARGET_PSP2 */ +# if !defined(AMIGA) && !defined(MSWIN_XBOX1) && !defined(SN_TARGET_ORBIS) \ + && !defined(SN_TARGET_PSP2) && !defined(__CC_ARM) +# include +# endif STATIC int GC_write(int fd, const char *buf, size_t len) { @@ -1734,7 +1753,7 @@ GC_API void GC_CALL GC_enable_incremental(void) IF_CANCEL(int cancel_state;) DISABLE_CANCEL(cancel_state); - while ((unsigned)bytes_written < len) { + while ((size_t)bytes_written < len) { # ifdef GC_SOLARIS_THREADS int result = syscall(SYS_write, fd, buf + bytes_written, len - bytes_written); @@ -1743,8 +1762,6 @@ GC_API void GC_CALL GC_enable_incremental(void) # endif if (-1 == result) { - if (EAGAIN == errno) /* Resource temporarily unavailable */ - continue; RESTORE_CANCEL(cancel_state); return(result); } @@ -1800,13 +1817,8 @@ void GC_printf(const char *format, ...) (void)WRITE(GC_stdout, buf, strlen(buf)); /* Ignore errors silently. */ # else - if (WRITE(GC_stdout, buf, strlen(buf)) < 0 -# if defined(CYGWIN32) - && GC_stdout != GC_DEFAULT_STDOUT_FD -# endif - ) { + if (WRITE(GC_stdout, buf, strlen(buf)) < 0) ABORT("write to stdout failed"); - } # endif } } @@ -1827,13 +1839,8 @@ void GC_log_printf(const char *format, ...) # ifdef NACL (void)WRITE(GC_log, buf, strlen(buf)); # else - if (WRITE(GC_log, buf, strlen(buf)) < 0 -# if defined(CYGWIN32) - && GC_log != GC_DEFAULT_STDERR_FD -# endif - ) { + if (WRITE(GC_log, buf, strlen(buf)) < 0) ABORT("write to GC log failed"); - } # endif } @@ -2123,7 +2130,7 @@ GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func fn, void *arg) result = fn(&base, arg); /* Strongly discourage the compiler from treating the above */ /* as a tail call. */ - GC_noop1(COVERT_DATAFLOW(&base)); + GC_noop1((word)(&base)); return result; } @@ -2148,13 +2155,13 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn, /* GC_get_main_stack_base() is unimplemented or broken for */ /* the platform). */ if ((word)GC_stackbottom HOTTER_THAN (word)(&stacksect)) - GC_stackbottom = (ptr_t)COVERT_DATAFLOW(&stacksect); + GC_stackbottom = (ptr_t)(&stacksect); if (GC_blocked_sp == NULL) { /* We are not inside GC_do_blocking() - do nothing more. */ client_data = fn(client_data); /* Prevent treating the above as a tail call. */ - GC_noop1(COVERT_DATAFLOW(&stacksect)); + GC_noop1((word)(&stacksect)); return client_data; /* result */ } @@ -2218,6 +2225,14 @@ STATIC void GC_do_blocking_inner(ptr_t data, void * context GC_ATTR_UNUSED) #endif /* !THREADS */ +/* Wrapper for functions that are likely to block (or, at least, do not */ +/* allocate garbage collected memory and/or manipulate pointers to the */ +/* garbage collected heap) for an appreciable length of time. */ +/* In the single threaded case, GC_do_blocking() (together */ +/* with GC_call_with_gc_active()) might be used to make stack scanning */ +/* more precise (i.e. scan only stack frames of functions that allocate */ +/* garbage collected memory and/or manipulate pointers to the garbage */ +/* collected heap). */ GC_API void * GC_CALL GC_do_blocking(GC_fn_type fn, void * client_data) { struct blocking_data my_data; @@ -2427,7 +2442,7 @@ GC_API int GC_CALL GC_get_all_interior_pointers(void) GC_API void GC_CALL GC_set_finalize_on_demand(int value) { - GC_ASSERT(value != -1); /* -1 was used to retrieve old value in gc-7.2 */ + GC_ASSERT(value != -1); /* value is of boolean type. */ GC_finalize_on_demand = value; } @@ -2439,7 +2454,7 @@ GC_API int GC_CALL GC_get_finalize_on_demand(void) GC_API void GC_CALL GC_set_java_finalization(int value) { - GC_ASSERT(value != -1); /* -1 was used to retrieve old value in gc-7.2 */ + GC_ASSERT(value != -1); /* value is of boolean type. */ GC_java_finalization = value; } @@ -2451,7 +2466,7 @@ GC_API int GC_CALL GC_get_java_finalization(void) GC_API void GC_CALL GC_set_dont_expand(int value) { - GC_ASSERT(value != -1); /* -1 was used to retrieve old value in gc-7.2 */ + GC_ASSERT(value != -1); /* value is of boolean type. */ GC_dont_expand = value; } @@ -2463,7 +2478,7 @@ GC_API int GC_CALL GC_get_dont_expand(void) GC_API void GC_CALL GC_set_no_dls(int value) { - GC_ASSERT(value != -1); /* -1 was used to retrieve old value in gc-7.2 */ + GC_ASSERT(value != -1); /* value is of boolean type. */ GC_no_dls = value; } @@ -2496,8 +2511,7 @@ GC_API GC_word GC_CALL GC_get_free_space_divisor(void) GC_API void GC_CALL GC_set_max_retries(GC_word value) { - GC_ASSERT((GC_signed_word)value != -1); - /* -1 was used to retrieve old value in gc-7.2 */ + GC_ASSERT(value != ~(word)0); GC_max_retries = value; } @@ -2508,7 +2522,7 @@ GC_API GC_word GC_CALL GC_get_max_retries(void) GC_API void GC_CALL GC_set_dont_precollect(int value) { - GC_ASSERT(value != -1); /* -1 was used to retrieve old value in gc-7.2 */ + GC_ASSERT(value != -1); /* value is of boolean type. */ GC_dont_precollect = value; } @@ -2531,8 +2545,7 @@ GC_API int GC_CALL GC_get_full_freq(void) GC_API void GC_CALL GC_set_time_limit(unsigned long value) { - GC_ASSERT((long)value != -1L); - /* -1 was used to retrieve old value in gc-7.2 */ + GC_ASSERT(value != (unsigned long)-1L); GC_time_limit = value; } diff --git a/gc/new_hblk.c b/gc/new_hblk.c index 88de14ddd..5e3ce0682 100644 --- a/gc/new_hblk.c +++ b/gc/new_hblk.c @@ -18,7 +18,7 @@ /* * This file contains the functions: * ptr_t GC_build_flXXX(h, old_fl) - * void GC_new_hblk(size, kind) + * void GC_new_hblk(size) */ #include diff --git a/gc/os_dep.c b/gc/os_dep.c index b183423a0..6eee61aa0 100644 --- a/gc/os_dep.c +++ b/gc/os_dep.c @@ -71,7 +71,7 @@ #if defined(MMAP_SUPPORTED) || defined(ADD_HEAP_GUARD_PAGES) # if defined(USE_MUNMAP) && !defined(USE_MMAP) && !defined(CPPCHECK) -# error Invalid config: USE_MUNMAP requires USE_MMAP +# error "invalid config - USE_MUNMAP requires USE_MMAP" # endif # include # include @@ -303,12 +303,10 @@ GC_INNER char * GC_get_maps(void) GC_ASSERT(*p == 'r' || *p == '-'); *prot = (char *)p; /* Skip past protection field to offset field */ - while (!isspace(*p)) ++p; - while (isspace(*p)) p++; + while (!isspace(*p)) ++p; while (isspace(*p)) ++p; GC_ASSERT(isxdigit(*p)); /* Skip past offset field, which we ignore */ - while (!isspace(*p)) ++p; - while (isspace(*p)) p++; + while (!isspace(*p)) ++p; while (isspace(*p)) ++p; maj_dev_start = p; GC_ASSERT(isxdigit(*maj_dev_start)); *maj_dev = strtoul((char *)maj_dev_start, NULL, 16); @@ -422,6 +420,11 @@ GC_INNER char * GC_get_maps(void) # pragma weak __data_start # pragma weak data_start extern int __data_start[], data_start[]; +# ifdef HOST_ANDROID +# pragma weak _etext +# pragma weak __dso_handle + extern int _etext[], __dso_handle[]; +# endif EXTERN_C_END # endif /* LINUX */ @@ -431,13 +434,20 @@ GC_INNER char * GC_get_maps(void) { ptr_t data_end = DATAEND; -# if (defined(LINUX) || defined(HURD)) && defined(USE_PROG_DATA_START) +# if (defined(LINUX) || defined(HURD)) && !defined(IGNORE_PROG_DATA_START) /* Try the easy approaches first: */ - /* However, this may lead to wrong data start value if libgc */ - /* code is put into a shared library (directly or indirectly) */ - /* which is linked with -Bsymbolic-functions option. Thus, */ - /* the following is not used by default. */ - if (COVERT_DATAFLOW(__data_start) != 0) { +# ifdef HOST_ANDROID + /* Workaround for "gold" (default) linker (as of Android NDK r10e). */ + if ((word)__data_start < (word)_etext + && (word)_etext < (word)__dso_handle) { + GC_data_start = (ptr_t)(__dso_handle); +# ifdef DEBUG_ADD_DEL_ROOTS + GC_log_printf( + "__data_start is wrong; using __dso_handle as data start\n"); +# endif + } else +# endif + /* else */ if (COVERT_DATAFLOW(__data_start) != 0) { GC_data_start = (ptr_t)(__data_start); } else { GC_data_start = (ptr_t)(data_start); @@ -460,7 +470,7 @@ GC_INNER char * GC_get_maps(void) return; } - GC_data_start = (ptr_t)GC_find_limit(data_end, FALSE); + GC_data_start = GC_find_limit(data_end, FALSE); } #endif /* SEARCH_FOR_DATA_START */ @@ -501,7 +511,7 @@ GC_INNER char * GC_get_maps(void) { /* This may need to be environ, without the underscore, for */ /* some versions. */ - GC_data_start = (ptr_t)GC_find_limit(&environ, FALSE); + GC_data_start = GC_find_limit((ptr_t)&environ, FALSE); } #endif /* NETBSD */ @@ -973,7 +983,6 @@ GC_INNER size_t GC_page_size = 0; /* the smallest location q s.t. [q,p) is addressable (!up). */ /* We assume that p (up) or p-1 (!up) is addressable. */ /* Requires allocation lock. */ - GC_ATTR_NO_SANITIZE_ADDR STATIC ptr_t GC_find_limit_with_bound(ptr_t p, GC_bool up, ptr_t bound) { static volatile ptr_t result; @@ -1018,36 +1027,12 @@ GC_INNER size_t GC_page_size = 0; return(result); } - void * GC_find_limit(void * p, int up) + ptr_t GC_find_limit(ptr_t p, GC_bool up) { - return GC_find_limit_with_bound((ptr_t)p, (GC_bool)up, - up ? (ptr_t)GC_WORD_MAX : 0); + return GC_find_limit_with_bound(p, up, up ? (ptr_t)(word)(-1) : 0); } # endif /* NEED_FIND_LIMIT || USE_PROC_FOR_LIBRARIES */ -#ifdef HPUX_MAIN_STACKBOTTOM -# include -# include - - STATIC ptr_t GC_hpux_main_stack_base(void) - { - struct pst_vm_status vm_status; - int i = 0; - - while (pstat_getprocvm(&vm_status, sizeof(vm_status), 0, i++) == 1) { - if (vm_status.pst_type == PS_STACK) - return (ptr_t)vm_status.pst_vaddr; - } - - /* Old way to get the stack bottom. */ -# ifdef STACK_GROWS_UP - return (ptr_t)GC_find_limit(GC_approx_sp(), /* up= */ FALSE); -# else /* not HP_PA */ - return (ptr_t)GC_find_limit(GC_approx_sp(), TRUE); -# endif - } -#endif /* HPUX_MAIN_STACKBOTTOM */ - #ifdef HPUX_STACKBOTTOM #include @@ -1107,7 +1092,7 @@ GC_INNER size_t GC_page_size = 0; # endif result = backing_store_base_from_proc(); if (0 == result) { - result = (ptr_t)GC_find_limit(GC_save_regs_in_stack(), FALSE); + result = GC_find_limit(GC_save_regs_in_stack(), FALSE); /* Now seems to work better than constant displacement */ /* heuristic used in 6.X versions. The latter seems to */ /* fail for 2.6 kernels. */ @@ -1287,17 +1272,15 @@ GC_INNER size_t GC_page_size = 0; # else result = (ptr_t)((word)GC_approx_sp() & ~STACKBOTTOM_ALIGNMENT_M1); # endif -# elif defined(HPUX_MAIN_STACKBOTTOM) - result = GC_hpux_main_stack_base(); # elif defined(LINUX_STACKBOTTOM) - result = GC_linux_main_stack_base(); + result = GC_linux_main_stack_base(); # elif defined(FREEBSD_STACKBOTTOM) - result = GC_freebsd_main_stack_base(); + result = GC_freebsd_main_stack_base(); # elif defined(HEURISTIC2) { ptr_t sp = GC_approx_sp(); # ifdef STACK_GROWS_DOWN - result = (ptr_t)GC_find_limit(sp, TRUE); + result = GC_find_limit(sp, TRUE); # if defined(HEURISTIC2_LIMIT) && !defined(CPPCHECK) if ((word)result > (word)HEURISTIC2_LIMIT && (word)sp < (word)HEURISTIC2_LIMIT) { @@ -1305,7 +1288,7 @@ GC_INNER size_t GC_page_size = 0; } # endif # else - result = (ptr_t)GC_find_limit(sp, FALSE); + result = GC_find_limit(sp, FALSE); # if defined(HEURISTIC2_LIMIT) && !defined(CPPCHECK) if ((word)result < (word)HEURISTIC2_LIMIT && (word)sp > (word)HEURISTIC2_LIMIT) { @@ -1645,10 +1628,10 @@ void GC_register_data_segments(void) typedef UINT (WINAPI * GetWriteWatch_type)( DWORD, PVOID, GC_ULONG_PTR /* SIZE_T */, PVOID *, GC_ULONG_PTR *, PULONG); - static FARPROC GetWriteWatch_func; + static GetWriteWatch_type GetWriteWatch_func; static DWORD GetWriteWatch_alloc_flag; -# define GC_GWW_AVAILABLE() (GetWriteWatch_func != 0) +# define GC_GWW_AVAILABLE() (GetWriteWatch_func != NULL) static void detect_GetWriteWatch(void) { @@ -1690,7 +1673,8 @@ void GC_register_data_segments(void) hK32 = GetModuleHandle(TEXT("kernel32.dll")); # endif if (hK32 != (HMODULE)0 && - (GetWriteWatch_func = GetProcAddress(hK32, "GetWriteWatch")) != 0) { + (GetWriteWatch_func = (GetWriteWatch_type)GetProcAddress(hK32, + "GetWriteWatch")) != NULL) { /* Also check whether VirtualAlloc accepts MEM_WRITE_WATCH, */ /* as some versions of kernel32.dll have one but not the */ /* other, making the feature completely broken. */ @@ -1702,25 +1686,26 @@ void GC_register_data_segments(void) GC_ULONG_PTR count = 16; DWORD page_size; /* Check that it actually works. In spite of some */ - /* documentation it actually seems to exist on Win2K. */ + /* documentation it actually seems to exist on W2K. */ /* This test may be unnecessary, but ... */ - if ((*(GetWriteWatch_type)(word)GetWriteWatch_func)( - WRITE_WATCH_FLAG_RESET, page, - GC_page_size, pages, &count, - &page_size) != 0) { + if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET, + page, GC_page_size, + pages, + &count, + &page_size) != 0) { /* GetWriteWatch always fails. */ - GetWriteWatch_func = 0; + GetWriteWatch_func = NULL; } else { GetWriteWatch_alloc_flag = MEM_WRITE_WATCH; } VirtualFree(page, 0 /* dwSize */, MEM_RELEASE); } else { /* GetWriteWatch will be useless. */ - GetWriteWatch_func = 0; + GetWriteWatch_func = NULL; } } # ifndef SMALL_CONFIG - if (!GetWriteWatch_func) { + if (GetWriteWatch_func == NULL) { GC_COND_LOG_PRINTF("Did not find a usable GetWriteWatch()\n"); } else { GC_COND_LOG_PRINTF("Using GetWriteWatch()\n"); @@ -1749,7 +1734,7 @@ void GC_register_data_segments(void) /* assembly code to do that right. */ GC_INNER GC_bool GC_wnt = FALSE; - /* This is a Windows NT derivative, i.e. NT, Win2K, XP or later. */ + /* This is a Windows NT derivative, i.e. NT, W2K, XP or later. */ GC_INNER void GC_init_win32(void) { @@ -1952,7 +1937,7 @@ void GC_register_data_segments(void) word next_page = ((text_end + (word)max_page_size - 1) & ~((word)max_page_size - 1)); word page_offset = (text_end & ((word)max_page_size - 1)); - volatile ptr_t result = (char *)(next_page + page_offset); + char * volatile result = (char *)(next_page + page_offset); /* Note that this isn't equivalent to just adding */ /* max_page_size to &etext if &etext is at a page boundary */ @@ -1980,7 +1965,7 @@ void GC_register_data_segments(void) /* text and data segments, so plan A brought us something. */ result = (char *)GC_find_limit(DATAEND, FALSE); } - return (/* no volatile */ ptr_t)result; + return((ptr_t)result); } # endif @@ -2009,7 +1994,7 @@ void GC_register_data_segments(void) } else { GC_reset_fault_handler(); /* As above, we go to plan B */ - result = (ptr_t)GC_find_limit(DATAEND, FALSE); + result = GC_find_limit(DATAEND, FALSE); } return(result); } @@ -2178,7 +2163,7 @@ void GC_register_data_segments(void) # ifdef SYMBIAN char *path = GC_get_private_path_and_zero_file(); if (path != NULL) { - zero_fd = open(path, O_RDWR | O_CREAT, 0644); + zero_fd = open(path, O_RDWR | O_CREAT, 0666); free(path); } # else @@ -2199,11 +2184,7 @@ void GC_register_data_segments(void) GC_MMAP_FLAGS | OPT_MAP_ANON, zero_fd, 0/* offset */); # undef IGNORE_PAGES_EXECUTABLE - if (EXPECT(MAP_FAILED == result, FALSE)) { - if (HEAP_START == last_addr && GC_pages_executable && EACCES == errno) - ABORT("Cannot allocate executable pages"); - return NULL; - } + if (result == MAP_FAILED) return(0); last_addr = (ptr_t)(((word)result + bytes + GC_page_size - 1) & ~(GC_page_size - 1)); # if !defined(LINUX) @@ -2282,11 +2263,6 @@ ptr_t GC_unix_get_mem(size_t bytes) static GC_bool sbrk_failed = FALSE; ptr_t result = 0; - if (GC_pages_executable) { - /* If the allocated memory should have the execute permission */ - /* then sbrk() cannot be used. */ - return GC_unix_mmap_get_mem(bytes); - } if (!sbrk_failed) result = GC_unix_sbrk_get_mem(bytes); if (0 == result) { sbrk_failed = TRUE; @@ -2325,14 +2301,16 @@ void * os2_alloc(size_t bytes) # endif /* OS2 */ -#ifdef MSWIN_XBOX1 - ptr_t GC_durango_get_mem(size_t bytes) +# ifdef MSWIN_XBOX1 + void *durango_get_mem(size_t bytes, size_t page_size) { if (0 == bytes) return NULL; - return (ptr_t)VirtualAlloc(NULL, bytes, MEM_COMMIT | MEM_TOP_DOWN, - PAGE_READWRITE); + return VirtualAlloc(NULL, bytes, MEM_COMMIT | MEM_TOP_DOWN, + PAGE_READWRITE); } -#elif defined(MSWINCE) +# endif + +#ifdef MSWINCE ptr_t GC_wince_get_mem(size_t bytes) { ptr_t result = 0; /* initialized to prevent warning. */ @@ -2544,6 +2522,13 @@ STATIC ptr_t GC_unmap_start(ptr_t start, size_t bytes) return result; } +/* Compute end address for an unmap operation on the indicated */ +/* block. */ +STATIC ptr_t GC_unmap_end(ptr_t start, size_t bytes) +{ + return (ptr_t)((word)(start + bytes) & ~(GC_page_size - 1)); +} + /* Under Win32/WinCE we commit (map) and decommit (unmap) */ /* memory using VirtualAlloc and VirtualFree. These functions */ /* work on individual allocations of virtual memory, made */ @@ -2583,12 +2568,9 @@ GC_INNER void GC_unmap(ptr_t start, size_t bytes) /* We immediately remap it to prevent an intervening mmap from */ /* accidentally grabbing the same address space. */ { -# if defined(AIX) || defined(CYGWIN32) || defined(HAIKU) \ - || defined(HPUX) - /* On AIX, mmap(PROT_NONE) fails with ENOMEM unless the */ - /* environment variable XPG_SUS_ENV is set to ON. */ - /* On Cygwin, calling mmap() with the new protection flags on */ - /* an existing memory map with MAP_FIXED is broken. */ +# ifdef CYGWIN32 + /* Calling mmap() with the new protection flags on an */ + /* existing memory map with MAP_FIXED is broken on Cygwin. */ /* However, calling mprotect() on the given address range */ /* with PROT_NONE seems to work fine. */ if (mprotect(start_addr, len, PROT_NONE)) @@ -2650,10 +2632,8 @@ GC_INNER void GC_remap(ptr_t start, size_t bytes) # else /* It was already remapped with PROT_NONE. */ { -# if defined(NACL) || defined(NETBSD) +# ifdef NACL /* NaCl does not expose mprotect, but mmap should work fine. */ - /* In case of NetBSD, mprotect fails (unlike mmap) even */ - /* without PROT_EXEC if PaX MPROTECT feature is enabled. */ void *result = mmap(start_addr, len, (PROT_READ | PROT_WRITE) | (GC_pages_executable ? PROT_EXEC : 0), MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON, @@ -2714,8 +2694,7 @@ GC_INNER void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2, # else if (len != 0) { /* Immediately remap as above. */ -# if defined(AIX) || defined(CYGWIN32) || defined(HAIKU) \ - || defined(HPUX) +# ifdef CYGWIN32 if (mprotect(start_addr, len, PROT_NONE)) ABORT("mprotect(PROT_NONE) failed"); # else @@ -2901,8 +2880,8 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void) count = GC_GWW_BUF_LEN; /* GetWriteWatch is documented as returning non-zero when it */ /* fails, but the documentation doesn't explicitly say why it */ - /* would fail or what its behavior will be if it fails. It */ - /* does appear to fail, at least on recent Win2K instances, if */ + /* would fail or what its behaviour will be if it fails. */ + /* It does appear to fail, at least on recent W2K instances, if */ /* the underlying memory was not allocated with the appropriate */ /* flag. This is common if GC_enable_incremental is called */ /* shortly after GC initialization. To avoid modifying the */ @@ -2913,11 +2892,12 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void) /* loop condition. Since each partial call will reset the */ /* status of some pages, this should eventually terminate even */ /* in the overflow case. */ - if ((*(GetWriteWatch_type)(word)GetWriteWatch_func)( - WRITE_WATCH_FLAG_RESET, - GC_heap_sects[i].hs_start, - GC_heap_sects[i].hs_bytes, - pages, &count, &page_size) != 0) { + if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET, + GC_heap_sects[i].hs_start, + GC_heap_sects[i].hs_bytes, + pages, + &count, + &page_size) != 0) { static int warn_count = 0; struct hblk * start = (struct hblk *)GC_heap_sects[i].hs_start; static struct hblk *last_warned = 0; @@ -2979,7 +2959,10 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void) #endif /* DEFAULT_VDB */ #ifndef GC_DISABLE_INCREMENTAL -# if !defined(THREADS) || defined(HAVE_LOCKFREE_AO_OR) +# ifndef THREADS +# define async_set_pht_entry_from_index(db, index) \ + set_pht_entry_from_index(db, index) +# elif defined(set_pht_entry_from_index_concurrent) # define async_set_pht_entry_from_index(db, index) \ set_pht_entry_from_index_concurrent(db, index) # elif defined(AO_HAVE_test_and_set_acquire) @@ -3099,13 +3082,11 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void) #ifndef DARWIN STATIC SIG_HNDLR_PTR GC_old_segv_handler = 0; /* Also old MSWIN32 ACCESS_VIOLATION filter */ -# if defined(FREEBSD) || defined(HPUX) || defined(HURD) || defined(LINUX) +# if !defined(MSWIN32) && !defined(MSWINCE) STATIC SIG_HNDLR_PTR GC_old_bus_handler = 0; -# ifndef LINUX +# if defined(FREEBSD) || defined(HURD) || defined(HPUX) STATIC GC_bool GC_old_bus_handler_used_si = FALSE; # endif -# endif -# if !defined(MSWIN32) && !defined(MSWINCE) STATIC GC_bool GC_old_segv_handler_used_si = FALSE; # endif /* !MSWIN32 */ #endif /* !DARWIN */ @@ -3144,8 +3125,7 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void) # ifndef SEGV_ACCERR # define SEGV_ACCERR 2 # endif -# if defined(AARCH64) || defined(ARM32) || defined(MIPS) \ - || __FreeBSD__ >= 7 +# if defined(AARCH64) || defined(ARM32) || defined(MIPS) # define CODE_OK (si -> si_code == SEGV_ACCERR) # elif defined(POWERPC) # define AIM /* Pretend that we're AIM. */ @@ -3388,6 +3368,9 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void) # endif } else { GC_old_bus_handler = (SIG_HNDLR_PTR)(signed_word)oldact.sa_handler; +# if !defined(LINUX) + GC_old_bus_handler_used_si = FALSE; +# endif } if (GC_old_bus_handler == (SIG_HNDLR_PTR)(signed_word)SIG_IGN) { WARN("Previously ignored bus error!?\n", 0); @@ -3545,57 +3528,32 @@ STATIC void GC_protect_heap(void) # include # endif -# ifndef THREADS - static pid_t saved_proc_pid; /* pid used to compose /proc file name */ -# endif - # define INITIAL_BUF_SZ 16384 STATIC size_t GC_proc_buf_size = INITIAL_BUF_SZ; STATIC char *GC_proc_buf = NULL; - STATIC int GC_proc_fd = -1; + STATIC int GC_proc_fd = 0; - static GC_bool proc_dirty_open_files(void) - { +GC_INNER GC_bool GC_dirty_init(void) +{ char buf[40]; - pid_t pid = getpid(); - (void)snprintf(buf, sizeof(buf), "/proc/%ld/pagedata", (long)pid); + if (GC_bytes_allocd != 0 || GC_bytes_allocd_before_gc != 0) { + memset(GC_written_pages, 0xff, sizeof(page_hash_table)); + GC_VERBOSE_LOG_PRINTF( + "Allocated %lu bytes: all pages may have been written\n", + (unsigned long)(GC_bytes_allocd + GC_bytes_allocd_before_gc)); + } + + (void)snprintf(buf, sizeof(buf), "/proc/%ld/pagedata", (long)getpid()); buf[sizeof(buf) - 1] = '\0'; GC_proc_fd = open(buf, O_RDONLY); - if (-1 == GC_proc_fd) { + if (GC_proc_fd < 0) { WARN("/proc open failed; cannot enable GC incremental mode\n", 0); return FALSE; } if (syscall(SYS_fcntl, GC_proc_fd, F_SETFD, FD_CLOEXEC) == -1) WARN("Could not set FD_CLOEXEC for /proc\n", 0); -# ifndef THREADS - saved_proc_pid = pid; /* updated on success only */ -# endif - return TRUE; - } - -# ifdef CAN_HANDLE_FORK - GC_INNER void GC_dirty_update_child(void) - { - if (-1 == GC_proc_fd) - return; /* GC incremental mode is off */ - - close(GC_proc_fd); - if (!proc_dirty_open_files()) - GC_incremental = FALSE; /* should be safe to turn it off */ - } -# endif /* CAN_HANDLE_FORK */ -GC_INNER GC_bool GC_dirty_init(void) -{ - if (GC_bytes_allocd != 0 || GC_bytes_allocd_before_gc != 0) { - memset(GC_written_pages, 0xff, sizeof(page_hash_table)); - GC_VERBOSE_LOG_PRINTF( - "Allocated %lu bytes: all pages may have been written\n", - (unsigned long)(GC_bytes_allocd + GC_bytes_allocd_before_gc)); - } - if (!proc_dirty_open_files()) - return FALSE; GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size); if (GC_proc_buf == NULL) ABORT("Insufficient space for /proc read"); @@ -3609,23 +3567,6 @@ GC_INLINE void GC_proc_read_dirty(GC_bool output_unneeded) char * bufp = GC_proc_buf; int i; -# ifndef THREADS - /* If the current pid differs from the saved one, then we are in */ - /* the forked (child) process, the current /proc file should be */ - /* closed, the new one should be opened with the updated path. */ - /* Note, this is not needed for multi-threaded case because */ - /* fork_child_proc() reopens the file right after fork. */ - if (getpid() != saved_proc_pid - && (-1 == GC_proc_fd /* no need to retry */ - || (close(GC_proc_fd), !proc_dirty_open_files()))) { - /* Failed to reopen the file. Punt! */ - if (!output_unneeded) - memset(GC_grungy_pages, 0xff, sizeof(page_hash_table)); - memset(GC_written_pages, 0xff, sizeof(page_hash_table)); - return; - } -# endif - BZERO(GC_grungy_pages, sizeof(GC_grungy_pages)); if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) { /* Retry with larger buffer. */ @@ -3802,8 +3743,6 @@ GC_INNER GC_bool GC_dirty_init(void) /* side of labeling pages as dirty (and this implementation does). */ GC_INNER GC_bool GC_page_was_dirty(struct hblk *h) { - word index; - # ifdef PCR_VDB if (!GC_manual_vdb) { if ((word)h < (word)GC_vd_base @@ -3815,16 +3754,9 @@ GC_INNER GC_bool GC_dirty_init(void) # elif defined(DEFAULT_VDB) if (!GC_manual_vdb) return TRUE; -# elif defined(PROC_VDB) - /* Unless manual VDB is on, the bitmap covers all process memory. */ - if (GC_manual_vdb) # endif - { - if (NULL == HDR(h)) - return TRUE; - } - index = PHT_HASH(h); - return get_pht_entry_from_index(GC_grungy_pages, index); + return NULL == HDR(h) + || get_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h)); } # if defined(CHECKSUMS) || defined(PROC_VDB) @@ -3832,21 +3764,12 @@ GC_INNER GC_bool GC_dirty_init(void) GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk *h) { # if defined(GWW_VDB) || defined(PROC_VDB) - word index; - # ifdef MPROTECT_VDB if (!GC_GWW_AVAILABLE()) return TRUE; # endif -# if defined(PROC_VDB) - if (GC_manual_vdb) -# endif - { - if (NULL == HDR(h)) - return TRUE; - } - index = PHT_HASH(h); - return get_pht_entry_from_index(GC_written_pages, index); + return NULL == HDR(h) + || get_pht_entry_from_index(GC_written_pages, PHT_HASH(h)); # else /* TODO: implement me for MANUAL_VDB. */ (void)h; @@ -4102,28 +4025,24 @@ typedef enum { # define GC_mprotect_state GC_MP_NORMAL #endif /* !THREADS */ -struct mp_reply_s { - mach_msg_header_t head; - char data[256]; -}; - -struct mp_msg_s { - mach_msg_header_t head; - mach_msg_body_t msgh_body; - char data[1024]; -}; - STATIC void *GC_mprotect_thread(void *arg) { mach_msg_return_t r; /* These two structures contain some private kernel data. We don't */ /* need to access any of it so we don't bother defining a proper */ /* struct. The correct definitions are in the xnu source code. */ - struct mp_reply_s reply; - struct mp_msg_s msg; + struct reply_s { + mach_msg_header_t head; + char data[256]; + } reply; + struct msg_s { + mach_msg_header_t head; + mach_msg_body_t msgh_body; + char data[1024]; + } msg; mach_msg_id_t id; - if ((word)arg == GC_WORD_MAX) return 0; /* to prevent a compiler warning */ + if ((word)arg == (word)-1) return 0; /* to make compiler happy */ # if defined(CPPCHECK) reply.data[0] = 0; /* to prevent "field unused" warnings */ msg.data[0] = 0; @@ -4584,7 +4503,6 @@ GC_API int GC_CALL GC_get_pages_executable(void) # if defined(LINUX) # include -# if defined(SAVE_CALL_CHAIN) struct frame { long fr_local[8]; long fr_arg[6]; @@ -4596,7 +4514,6 @@ GC_API int GC_CALL GC_get_pages_executable(void) long fr_argd[6]; long fr_argx[0]; }; -# endif # elif defined (DRSNX) # include # elif defined(OPENBSD) @@ -4708,11 +4625,7 @@ GC_INNER void GC_save_callers(struct callinfo info[NFRAMES]) #endif for (; !((word)fp HOTTER_THAN (word)frame) -# ifndef THREADS - && !((word)GC_stackbottom HOTTER_THAN (word)fp) -# elif defined(STACK_GROWS_UP) - && fp != NULL -# endif + && !((word)GC_stackbottom HOTTER_THAN (word)fp) && nframes < NFRAMES; fp = (struct frame *)((long) fp -> FR_SAVFP + BIAS), nframes++) { # if NARGS > 0 diff --git a/gc/pthread_stop_world.c b/gc/pthread_stop_world.c index 4b2c42975..a94d46633 100644 --- a/gc/pthread_stop_world.c +++ b/gc/pthread_stop_world.c @@ -114,12 +114,9 @@ STATIC void GC_remove_allowed_signals(sigset_t *set) static sigset_t suspend_handler_mask; -#define THREAD_RESTARTED 0x1 - STATIC volatile AO_t GC_stop_count = 0; - /* Incremented by two (not to alter */ - /* THREAD_RESTARTED bit) at the beginning of */ - /* GC_stop_world. */ + /* Incremented by two at the beginning of */ + /* GC_stop_world (the lowest bit is always 0). */ STATIC volatile AO_t GC_world_is_stopped = FALSE; /* FALSE ==> it is safe for threads to restart, */ @@ -244,22 +241,6 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy, void *context); errno = old_errno; } -#ifdef BASE_ATOMIC_OPS_EMULATED - /* The AO primitives emulated with locks cannot be used inside signal */ - /* handlers as this could cause a deadlock or a double lock. */ - /* The following "async" macro definitions are correct only for */ - /* an uniprocessor case and are provided for a test purpose. */ -# define ao_load_acquire_async(p) (*(p)) -# define ao_load_async(p) ao_load_acquire_async(p) -# define ao_store_release_async(p, v) (void)(*(p) = (v)) -# define ao_store_async(p, v) ao_store_release_async(p, v) -#else -# define ao_load_acquire_async(p) AO_load_acquire(p) -# define ao_load_async(p) AO_load(p) -# define ao_store_release_async(p, v) AO_store_release(p, v) -# define ao_store_async(p, v) AO_store(p, v) -#endif /* !BASE_ATOMIC_OPS_EMULATED */ - /* The lookup here is safe, since this is done on behalf */ /* of a thread which holds the allocation lock in order */ /* to stop the world. Thus concurrent modification of the */ @@ -291,14 +272,13 @@ GC_INLINE void GC_store_stack_ptr(GC_thread me) /* and fetched (by GC_push_all_stacks) using the atomic primitives to */ /* avoid the related TSan warning. */ # ifdef SPARC - ao_store_async((volatile AO_t *)&me->stop_info.stack_ptr, + AO_store((volatile AO_t *)&me->stop_info.stack_ptr, (AO_t)GC_save_regs_in_stack()); # else # ifdef IA64 me -> backing_store_ptr = GC_save_regs_in_stack(); # endif - ao_store_async((volatile AO_t *)&me->stop_info.stack_ptr, - (AO_t)GC_approx_sp()); + AO_store((volatile AO_t *)&me->stop_info.stack_ptr, (AO_t)GC_approx_sp()); # endif } @@ -308,7 +288,7 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED, pthread_t self = pthread_self(); GC_thread me; IF_CANCEL(int cancel_state;) - AO_t my_stop_count = ao_load_acquire_async(&GC_stop_count); + AO_t my_stop_count = AO_load_acquire(&GC_stop_count); /* After the barrier, this thread should see */ /* the actual content of GC_threads. */ @@ -324,12 +304,12 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED, # ifdef DEBUG_THREADS GC_log_printf("Suspending %p\n", (void *)self); # endif - GC_ASSERT(((word)my_stop_count & THREAD_RESTARTED) == 0); + GC_ASSERT(((word)my_stop_count & 1) == 0); me = GC_lookup_thread_async(self); # ifdef GC_ENABLE_SUSPEND_THREAD - if (ao_load_async(&me->suspended_ext)) { + if (AO_load(&me->suspended_ext)) { GC_store_stack_ptr(me); sem_post(&GC_suspend_ack_sem); suspend_self_inner(me); @@ -341,7 +321,7 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED, } # endif - if (((word)me->stop_info.last_stop_count & ~(word)THREAD_RESTARTED) + if (((word)me->stop_info.last_stop_count & ~(word)0x1) == (word)my_stop_count) { /* Duplicate signal. OK if we are retrying. */ if (!GC_retry_signals) { @@ -370,7 +350,7 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED, /* thread has been stopped. Note that sem_post() is */ /* the only async-signal-safe primitive in LinuxThreads. */ sem_post(&GC_suspend_ack_sem); - ao_store_release_async(&me->stop_info.last_stop_count, my_stop_count); + AO_store_release(&me->stop_info.last_stop_count, my_stop_count); /* Wait until that thread tells us to restart by sending */ /* this thread a GC_sig_thr_restart signal (should be masked */ @@ -384,8 +364,8 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED, /* this code should not be executed. */ do { sigsuspend (&suspend_handler_mask); - } while (ao_load_acquire_async(&GC_world_is_stopped) - && ao_load_async(&GC_stop_count) == my_stop_count); + } while (AO_load_acquire(&GC_world_is_stopped) + && AO_load(&GC_stop_count) == my_stop_count); # ifdef DEBUG_THREADS GC_log_printf("Continuing %p\n", (void *)self); @@ -403,9 +383,10 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED, if (GC_retry_signals) # endif { - /* Set the flag that the thread has been restarted. */ - ao_store_release_async(&me->stop_info.last_stop_count, - (AO_t)((word)my_stop_count | THREAD_RESTARTED)); + /* Set the flag (the lowest bit of last_stop_count) that the */ + /* thread has been restarted. */ + AO_store_release(&me->stop_info.last_stop_count, + (AO_t)((word)my_stop_count | 1)); } } RESTORE_CANCEL(cancel_state); @@ -544,7 +525,7 @@ STATIC void GC_restart_handler(int sig) static void *GC_CALLBACK suspend_self_inner(void *client_data) { GC_thread me = (GC_thread)client_data; - while (ao_load_acquire_async(&me->suspended_ext)) { + while (AO_load_acquire(&me->suspended_ext)) { /* TODO: Use sigsuspend() instead. */ GC_brief_async_signal_safe_sleep(); } @@ -648,10 +629,6 @@ STATIC void GC_restart_handler(int sig) } # endif /* GC_ENABLE_SUSPEND_THREAD */ -# undef ao_load_acquire_async -# undef ao_load_async -# undef ao_store_async -# undef ao_store_release_async #endif /* !GC_OPENBSD_UTHREADS && !NACL */ #ifdef IA64 @@ -919,8 +896,7 @@ GC_INNER void GC_stop_world(void) # if defined(GC_OPENBSD_UTHREADS) || defined(NACL) (void)GC_suspend_all(); # else - AO_store(&GC_stop_count, - (AO_t)((word)GC_stop_count + (THREAD_RESTARTED+1))); + AO_store(&GC_stop_count, (AO_t)((word)GC_stop_count + 2)); /* Only concurrent reads are possible. */ if (GC_manual_vdb) { GC_acquire_dirty_lock(); @@ -1123,9 +1099,8 @@ GC_INNER void GC_stop_world(void) # ifdef GC_ENABLE_SUSPEND_THREAD if (p -> suspended_ext) continue; # endif - if (GC_retry_signals - && AO_load(&p->stop_info.last_stop_count) - == (AO_t)((word)GC_stop_count | THREAD_RESTARTED)) + if (GC_retry_signals && AO_load(&p->stop_info.last_stop_count) + == (AO_t)((word)GC_stop_count | 1)) continue; /* The thread has been restarted. */ n_live_threads++; # endif diff --git a/gc/pthread_support.c b/gc/pthread_support.c index 4891b3ac9..8a78efed0 100644 --- a/gc/pthread_support.c +++ b/gc/pthread_support.c @@ -340,7 +340,7 @@ STATIC void * GC_mark_thread(void * id) word my_mark_no = 0; IF_CANCEL(int cancel_state;) - if ((word)id == GC_WORD_MAX) return 0; /* to prevent a compiler warning */ + if ((word)id == (word)-1) return 0; /* to make compiler happy */ DISABLE_CANCEL(cancel_state); /* Mark threads are not cancellable; they */ /* should be invisible to client. */ @@ -762,11 +762,10 @@ STATIC void GC_remove_all_threads_but_me(void) { pthread_t self = pthread_self(); int hv; + GC_thread p, next, me; for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) { - GC_thread p, next; - GC_thread me = NULL; - + me = 0; for (p = GC_threads[hv]; 0 != p; p = next) { next = p -> next; if (THREAD_EQUAL(p -> id, self) @@ -1123,10 +1122,7 @@ static void fork_child_proc(void) /* Turn off parallel marking in the child, since we are probably */ /* just going to exec, and we would have to restart mark threads. */ GC_parallel = FALSE; -# endif -# ifndef GC_DISABLE_INCREMENTAL - GC_dirty_update_child(); -# endif +# endif /* PARALLEL_MARK */ RESTORE_CANCEL(fork_cancel_state); UNLOCK(); /* Even though after a fork the child only inherits the single */ @@ -1245,7 +1241,11 @@ GC_INNER void GC_thr_init(void) } } - /* Set GC_nprocs and available_markers_m1. */ +# ifndef GC_DARWIN_THREADS + GC_stop_init(); +# endif + + /* Set GC_nprocs. */ { char * nprocs_string = GETENV("GC_NPROCS"); GC_nprocs = -1; @@ -1294,43 +1294,6 @@ GC_INNER void GC_thr_init(void) # endif } GC_COND_LOG_PRINTF("Number of processors = %d\n", GC_nprocs); - -# if defined(BASE_ATOMIC_OPS_EMULATED) && !defined(GC_DARWIN_THREADS) \ - && !defined(GC_OPENBSD_UTHREADS) && !defined(NACL) \ - && !defined(SN_TARGET_ORBIS) && !defined(SN_TARGET_PSP2) - /* Ensure the process is running on just one CPU core. */ - /* This is needed because the AO primitives emulated with */ - /* locks cannot be used inside signal handlers. */ - { - cpu_set_t mask; - int cpu_set_cnt = 0; - int cpu_lowest_set = 0; - int i = GC_nprocs > 1 ? GC_nprocs : 2; /* check at least 2 cores */ - - if (sched_getaffinity(0 /* current process */, - sizeof(mask), &mask) == -1) - ABORT_ARG1("sched_getaffinity failed", ": errno= %d", errno); - while (i-- > 0) - if (CPU_ISSET(i, &mask)) { - cpu_lowest_set = i; - cpu_set_cnt++; - } - if (0 == cpu_set_cnt) - ABORT("sched_getaffinity returned empty mask"); - if (cpu_set_cnt > 1) { - CPU_ZERO(&mask); - CPU_SET(cpu_lowest_set, &mask); /* select just one CPU */ - if (sched_setaffinity(0, sizeof(mask), &mask) == -1) - ABORT_ARG1("sched_setaffinity failed", ": errno= %d", errno); - WARN("CPU affinity mask is set to %p\n", (word)1 << cpu_lowest_set); - } - } -# endif /* BASE_ATOMIC_OPS_EMULATED */ - -# ifndef GC_DARWIN_THREADS - GC_stop_init(); -# endif - # ifdef PARALLEL_MARK if (available_markers_m1 <= 0) { /* Disable parallel marking. */ @@ -1460,7 +1423,7 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn, } else { /* The original stack. */ if ((word)GC_stackbottom HOTTER_THAN (word)(&stacksect)) - GC_stackbottom = (ptr_t)COVERT_DATAFLOW(&stacksect); + GC_stackbottom = (ptr_t)(&stacksect); } if (!me->thread_blocked) { @@ -1468,7 +1431,7 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn, UNLOCK(); client_data = fn(client_data); /* Prevent treating the above as a tail call. */ - GC_noop1(COVERT_DATAFLOW(&stacksect)); + GC_noop1((word)(&stacksect)); return client_data; /* result */ } @@ -1863,7 +1826,7 @@ GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread( int result; int detachstate; word my_flags = 0; - struct start_info si; + struct start_info * si; DCL_LOCK_STATE; /* This is otherwise saved only in an area mmapped by the thread */ /* library, which isn't visible to the collector. */ @@ -1873,13 +1836,21 @@ GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread( /* responsibility. */ INIT_REAL_SYMS(); + LOCK(); + si = (struct start_info *)GC_INTERNAL_MALLOC(sizeof(struct start_info), + NORMAL); + UNLOCK(); if (!EXPECT(parallel_initialized, TRUE)) GC_init_parallel(); - if (sem_init(&si.registered, GC_SEM_INIT_PSHARED, 0) != 0) + if (EXPECT(0 == si, FALSE) && + (si = (struct start_info *) + (*GC_get_oom_fn())(sizeof(struct start_info))) == 0) + return(ENOMEM); + if (sem_init(&(si -> registered), GC_SEM_INIT_PSHARED, 0) != 0) ABORT("sem_init failed"); - si.start_routine = start_routine; - si.arg = arg; + si -> start_routine = start_routine; + si -> arg = arg; LOCK(); if (!EXPECT(GC_thr_initialized, TRUE)) GC_thr_init(); @@ -1919,19 +1890,19 @@ GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread( pthread_attr_getdetachstate(attr, &detachstate); } if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED; - si.flags = my_flags; + si -> flags = my_flags; UNLOCK(); # ifdef DEBUG_THREADS GC_log_printf("About to start new thread from thread %p\n", (void *)pthread_self()); # endif set_need_to_lock(); - result = REAL_FUNC(pthread_create)(new_thread, attr, GC_start_routine, - &si); + result = REAL_FUNC(pthread_create)(new_thread, attr, GC_start_routine, si); /* Wait until child has been added to the thread table. */ - /* This also ensures that we hold onto the stack-allocated si until */ - /* the child is done with it. */ + /* This also ensures that we hold onto si until the child is done */ + /* with it. Thus it doesn't matter whether it is otherwise */ + /* visible to the collector. */ if (0 == result) { IF_CANCEL(int cancel_state;) @@ -1941,7 +1912,7 @@ GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread( # endif DISABLE_CANCEL(cancel_state); /* pthread_create is not a cancellation point. */ - while (0 != sem_wait(&si.registered)) { + while (0 != sem_wait(&(si -> registered))) { # if defined(GC_HAIKU_THREADS) /* To workaround some bug in Haiku semaphores. */ if (EACCES == errno) continue; @@ -1950,7 +1921,11 @@ GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread( } RESTORE_CANCEL(cancel_state); } - sem_destroy(&si.registered); + sem_destroy(&(si -> registered)); + LOCK(); + GC_INTERNAL_FREE(si); + UNLOCK(); + return(result); } #endif /* !SN_TARGET_ORBIS && !SN_TARGET_PSP2 */ @@ -1965,8 +1940,7 @@ STATIC void GC_pause(void) for (i = 0; i < GC_PAUSE_SPIN_CYCLES; ++i) { /* Something that's unlikely to be optimized away. */ -# if defined(AO_HAVE_compiler_barrier) \ - && !defined(BASE_ATOMIC_OPS_EMULATED) +# ifdef AO_CLEAR AO_compiler_barrier(); # else GC_noop1(i); @@ -2048,7 +2022,7 @@ STATIC void GC_generic_lock(pthread_mutex_t * lock) #endif /* !USE_SPIN_LOCK || ... */ -#if defined(AO_HAVE_char_load) && !defined(BASE_ATOMIC_OPS_EMULATED) +#ifdef AO_HAVE_char_load # define is_collecting() \ ((GC_bool)AO_char_load((unsigned char *)&GC_collecting)) #else @@ -2135,25 +2109,22 @@ GC_INNER void GC_lock(void) } } -#elif defined(USE_PTHREAD_LOCKS) +#else /* !USE_SPIN_LOCK */ -# ifndef NO_PTHREAD_TRYLOCK - GC_INNER void GC_lock(void) - { - if (1 == GC_nprocs || is_collecting()) { +GC_INNER void GC_lock(void) +{ +#ifndef NO_PTHREAD_TRYLOCK + if (1 == GC_nprocs || is_collecting()) { pthread_mutex_lock(&GC_allocate_ml); - } else { + } else { GC_generic_lock(&GC_allocate_ml); - } - } -# elif defined(GC_ASSERTIONS) - GC_INNER void GC_lock(void) - { - pthread_mutex_lock(&GC_allocate_ml); } -# endif +#else /* !NO_PTHREAD_TRYLOCK */ + pthread_mutex_lock(&GC_allocate_ml); +#endif /* !NO_PTHREAD_TRYLOCK */ +} -#endif /* !USE_SPIN_LOCK && USE_PTHREAD_LOCKS */ +#endif /* !USE_SPIN_LOCK */ #ifdef PARALLEL_MARK diff --git a/gc/reclaim.c b/gc/reclaim.c index 45ce4a11b..f729f5d57 100644 --- a/gc/reclaim.c +++ b/gc/reclaim.c @@ -103,9 +103,7 @@ GC_INNER void GC_print_all_errors(void) } for (i = 0; i < n_leaked; i++) { ptr_t p = leaked[i]; -# ifndef SKIP_LEAKED_OBJECTS_PRINTING - GC_print_heap_obj(p); -# endif + GC_print_heap_obj(p); GC_free(p); } @@ -135,9 +133,9 @@ GC_INNER GC_bool GC_block_empty(hdr *hhdr) return (hhdr -> hb_n_marks == 0); } -STATIC GC_bool GC_block_nearly_full(hdr *hhdr, word sz) +STATIC GC_bool GC_block_nearly_full(hdr *hhdr) { - return hhdr -> hb_n_marks > HBLK_OBJS(sz) * 7 / 8; + return (hhdr -> hb_n_marks > 7 * HBLK_OBJS(hhdr -> hb_sz)/8); } /* TODO: This should perhaps again be specialized for USE_MARK_BYTES */ @@ -156,11 +154,7 @@ STATIC ptr_t GC_reclaim_clear(struct hblk *hbp, hdr *hhdr, word sz, signed_word n_bytes_found = 0; GC_ASSERT(hhdr == GC_find_header((ptr_t)hbp)); -# ifndef THREADS - GC_ASSERT(sz == hhdr -> hb_sz); -# else - /* Skip the assertion because of a potential race with GC_realloc. */ -# endif + GC_ASSERT(sz == hhdr -> hb_sz); GC_ASSERT((sz & (BYTES_PER_WORD-1)) == 0); p = (word *)(hbp->hb_body); plim = (word *)(hbp->hb_body + HBLKSIZE - sz); @@ -206,9 +200,7 @@ STATIC ptr_t GC_reclaim_uninit(struct hblk *hbp, hdr *hhdr, word sz, word *p, *plim; signed_word n_bytes_found = 0; -# ifndef THREADS - GC_ASSERT(sz == hhdr -> hb_sz); -# endif + GC_ASSERT(sz == hhdr -> hb_sz); p = (word *)(hbp->hb_body); plim = (word *)((ptr_t)hbp + HBLKSIZE - sz); @@ -239,16 +231,13 @@ STATIC ptr_t GC_reclaim_uninit(struct hblk *hbp, hdr *hhdr, word sz, struct obj_kind *ok = &GC_obj_kinds[hhdr->hb_obj_kind]; int (GC_CALLBACK *disclaim)(void *) = ok->ok_disclaim_proc; -# ifndef THREADS - GC_ASSERT(sz == hhdr -> hb_sz); -# endif + GC_ASSERT(sz == hhdr -> hb_sz); p = (word *)(hbp -> hb_body); plim = (word *)((ptr_t)p + HBLKSIZE - sz); while ((word)p <= (word)plim) { int marked = mark_bit_from_hdr(hhdr, bit_no); if (!marked && (*disclaim)(p)) { - set_mark_bit_from_hdr(hhdr, bit_no); hhdr -> hb_n_marks++; marked = 1; } @@ -289,10 +278,8 @@ STATIC void GC_reclaim_check(struct hblk *hbp, hdr *hhdr, word sz) { word bit_no; ptr_t p, plim; + GC_ASSERT(sz == hhdr -> hb_sz); -# ifndef THREADS - GC_ASSERT(sz == hhdr -> hb_sz); -# endif /* go through all words in block */ p = hbp->hb_body; plim = p + HBLKSIZE - sz; @@ -350,10 +337,11 @@ GC_INNER ptr_t GC_reclaim_generic(struct hblk * hbp, hdr *hhdr, size_t sz, * If entirely empty blocks are to be completely deallocated, then * caller should perform that check. */ -STATIC void GC_reclaim_small_nonempty_block(struct hblk *hbp, word sz, +STATIC void GC_reclaim_small_nonempty_block(struct hblk *hbp, GC_bool report_if_found) { hdr *hhdr = HDR(hbp); + word sz = hhdr -> hb_sz; struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind]; void **flh = &(ok -> ok_freelist[BYTES_TO_GRANULES(sz)]); @@ -399,16 +387,9 @@ STATIC void GC_reclaim_small_nonempty_block(struct hblk *hbp, word sz, STATIC void GC_reclaim_block(struct hblk *hbp, word report_if_found) { hdr * hhdr = HDR(hbp); - word sz; /* size of objects in current block */ + word sz = hhdr -> hb_sz; /* size of objects in current block */ struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind]; -# ifdef AO_HAVE_load - /* Atomic access is used to avoid racing with GC_realloc. */ - sz = (word)AO_load((volatile AO_t *)&hhdr->hb_sz); -# else - /* No race as GC_realloc holds the lock while updating hb_sz. */ - sz = hhdr -> hb_sz; -# endif if( sz > MAXOBJBYTES ) { /* 1 big object */ if( !mark_bit_from_hdr(hhdr, 0) ) { if (report_if_found) { @@ -456,8 +437,7 @@ STATIC void GC_reclaim_block(struct hblk *hbp, word report_if_found) GC_ASSERT(sz * hhdr -> hb_n_marks <= HBLKSIZE); # endif if (report_if_found) { - GC_reclaim_small_nonempty_block(hbp, sz, - TRUE /* report_if_found */); + GC_reclaim_small_nonempty_block(hbp, TRUE /* report_if_found */); } else if (empty) { # ifdef ENABLE_DISCLAIM if ((hhdr -> hb_flags & HAS_DISCLAIM) != 0) { @@ -468,7 +448,7 @@ STATIC void GC_reclaim_block(struct hblk *hbp, word report_if_found) GC_bytes_found += HBLKSIZE; GC_freehblk(hbp); } - } else if (GC_find_leak || !GC_block_nearly_full(hhdr, sz)) { + } else if (GC_find_leak || !GC_block_nearly_full(hhdr)) { /* group of smaller objects, enqueue the real work */ struct hblk **rlh = ok -> ok_reclaim_list; @@ -715,9 +695,8 @@ GC_INNER void GC_continue_reclaim(word sz /* granules */, int kind) while ((hbp = *rlh) != 0) { hhdr = HDR(hbp); *rlh = hhdr -> hb_next; - GC_reclaim_small_nonempty_block(hbp, hhdr -> hb_sz, FALSE); - if (*flh != 0) - break; + GC_reclaim_small_nonempty_block(hbp, FALSE); + if (*flh != 0) break; } } @@ -740,7 +719,7 @@ GC_INNER GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old) struct hblk ** rlp; struct hblk ** rlh; # ifndef NO_CLOCK - CLOCK_TYPE start_time = CLOCK_TYPE_INITIALIZER; + CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */ if (GC_print_stats == VERBOSE) GET_TIME(start_time); @@ -763,7 +742,7 @@ GC_INNER GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old) /* It's likely we'll need it this time, too */ /* It's been touched recently, so this */ /* shouldn't trigger paging. */ - GC_reclaim_small_nonempty_block(hbp, hhdr->hb_sz, FALSE); + GC_reclaim_small_nonempty_block(hbp, FALSE); } } } @@ -807,7 +786,7 @@ GC_INNER GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old) while ((hbp = *rlh) != 0) { hhdr = HDR(hbp); *rlh = hhdr->hb_next; - GC_reclaim_small_nonempty_block(hbp, hhdr->hb_sz, FALSE); + GC_reclaim_small_nonempty_block(hbp, FALSE); } } } diff --git a/gc/specific.c b/gc/specific.c index 451cf9086..624236fdf 100644 --- a/gc/specific.c +++ b/gc/specific.c @@ -72,8 +72,7 @@ GC_INNER int GC_setspecific(tsd * key, void * value) AO_store_release(&key->hash[hash_val].ao, (AO_t)entry); GC_dirty((/* no volatile */ void *)entry); GC_dirty(key->hash + hash_val); - if (pthread_mutex_unlock(&key->lock) != 0) - ABORT("pthread_mutex_unlock failed (setspecific)"); + pthread_mutex_unlock(&(key -> lock)); return 0; } @@ -129,8 +128,7 @@ GC_INNER void GC_remove_specific_after_fork(tsd * key, pthread_t t) /* With GC, we're done, since the pointers from the cache will */ /* be overwritten, all local pointers to the entries will be */ /* dropped, and the entry will then be reclaimed. */ - if (pthread_mutex_unlock(&key->lock) != 0) - ABORT("pthread_mutex_unlock failed (remove_specific after fork)"); + pthread_mutex_unlock(&(key -> lock)); } /* Note that even the slow path doesn't lock. */ diff --git a/gc/tests/disclaim_bench.c b/gc/tests/disclaim_bench.c index 28feb1a5c..8be81cf69 100644 --- a/gc/tests/disclaim_bench.c +++ b/gc/tests/disclaim_bench.c @@ -121,8 +121,6 @@ int main(int argc, char **argv) model_min = 0; model_max = 2; } - if (GC_get_find_leak()) - printf("This test program is not designed for leak detection mode\n"); keep_arr = (testobj_t *)GC_MALLOC(sizeof(void *) * KEEP_CNT); if (NULL == keep_arr) { diff --git a/gc/tests/disclaim_test.c b/gc/tests/disclaim_test.c index 6af62f64e..4febf7f73 100644 --- a/gc/tests/disclaim_test.c +++ b/gc/tests/disclaim_test.c @@ -84,7 +84,7 @@ void test_misc_sizes(void) } my_assert(memeq(p, 0, (size_t)1 << i)); memset(p, 0x56, (size_t)1 << i); - *(unsigned char *)p = (unsigned char)i; + *(unsigned char *)p = i; } } @@ -241,8 +241,6 @@ int main(void) # ifndef NO_INCREMENTAL GC_enable_incremental(); # endif - if (GC_get_find_leak()) - printf("This test program is not designed for leak detection mode\n"); test_misc_sizes(); diff --git a/gc/tests/disclaim_weakmap_test.c b/gc/tests/disclaim_weakmap_test.c deleted file mode 100644 index 516a3fd77..000000000 --- a/gc/tests/disclaim_weakmap_test.c +++ /dev/null @@ -1,472 +0,0 @@ -/* - * Copyright (c) 2018 Petter A. Urkedal - * - * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED - * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. - * - * Permission is hereby granted to use or copy this program - * for any purpose, provided the above notices are retained on all copies. - * 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. - */ - -/* This tests a case where disclaim notifiers sometimes return non-zero */ -/* in order to protect objects from collection. */ - -#include -#include -#include - -#ifdef HAVE_CONFIG_H - /* For GC_[P]THREADS */ -# include "config.h" -#endif - -#include "gc_disclaim.h" /* includes gc.h */ -#include "gc_mark.h" - -#ifdef GC_PTHREADS -# ifndef NTHREADS -# define NTHREADS 8 -# endif -# include -# include -# include "private/gc_atomic_ops.h" /* for AO_t and AO_fetch_and_add1 */ -#else -# undef NTHREADS -# define NTHREADS 1 -# define AO_t GC_word -#endif - -#ifdef LINT2 - /* Avoid include gc_priv.h. */ -# ifndef GC_API_PRIV -# define GC_API_PRIV GC_API -# endif -# ifdef __cplusplus - extern "C" { -# endif - GC_API_PRIV long GC_random(void); -# ifdef __cplusplus - } /* extern "C" */ -# endif -# undef rand -# define rand() (int)GC_random() -#endif /* LINT2 */ - -#define POP_SIZE 200 -#define MUTATE_CNT (5000000 / NTHREADS) -#define GROW_LIMIT (MUTATE_CNT / 10) - -#define WEAKMAP_CAPACITY 256 -#define WEAKMAP_MUTEX_COUNT 32 - -/* FINALIZER_CLOSURE_FLAG definition matches the one in fnlz_mlc.c. */ -#if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH) -# define FINALIZER_CLOSURE_FLAG 0x2 -# define INVALIDATE_FLAG 0x1 -#else -# define FINALIZER_CLOSURE_FLAG 0x1 -# define INVALIDATE_FLAG 0x2 -#endif - -#define my_assert(e) \ - if (!(e)) { \ - fflush(stdout); \ - fprintf(stderr, "Assertion failure, line %d: %s\n", __LINE__, #e); \ - exit(70); \ - } - -#define CHECK_OOM(p) \ - do { \ - if (NULL == (p)) { \ - fprintf(stderr, "Out of memory\n"); \ - exit(69); \ - } \ - } while (0) - -#ifndef AO_HAVE_fetch_and_add1 -# define AO_fetch_and_add1(p) ((*(p))++) - /* This is used only to update counters. */ -#endif - -unsigned memhash(void *src, size_t len) -{ - unsigned acc = 0; - size_t i; - - my_assert(len % sizeof(GC_word) == 0); - for (i = 0; i < len / sizeof(GC_word); ++i) { - acc = (unsigned)((2003 * (GC_word)acc + ((GC_word *)src)[i]) / 3); - } - return acc; -} - -static volatile AO_t stat_added; -static volatile AO_t stat_found; -static volatile AO_t stat_removed; -static volatile AO_t stat_skip_locked; -static volatile AO_t stat_skip_marked; - -struct weakmap_link { - GC_hidden_pointer obj; - struct weakmap_link *next; -}; - -struct weakmap { -# ifdef GC_PTHREADS - pthread_mutex_t mutex[WEAKMAP_MUTEX_COUNT]; -# endif - size_t key_size; - size_t obj_size; - size_t capacity; - unsigned weakobj_kind; - struct weakmap_link **links; /* NULL means weakmap is destroyed */ -}; - -void weakmap_lock(struct weakmap *wm, unsigned h) -{ -# ifdef GC_PTHREADS - int err = pthread_mutex_lock(&wm->mutex[h % WEAKMAP_MUTEX_COUNT]); - my_assert(0 == err); -# else - (void)wm; (void)h; -# endif -} - -int weakmap_trylock(struct weakmap *wm, unsigned h) -{ -# ifdef GC_PTHREADS - int err = pthread_mutex_trylock(&wm->mutex[h % WEAKMAP_MUTEX_COUNT]); - if (err != 0 && err != EBUSY) { - fprintf(stderr, "pthread_mutex_trylock: %s\n", strerror(err)); - exit(69); - } - return err; -# else - (void)wm; (void)h; - return 0; -# endif -} - -void weakmap_unlock(struct weakmap *wm, unsigned h) -{ -# ifdef GC_PTHREADS - int err = pthread_mutex_unlock(&wm->mutex[h % WEAKMAP_MUTEX_COUNT]); - my_assert(0 == err); -# else - (void)wm; (void)h; -# endif -} - -void *GC_CALLBACK set_mark_bit(void *obj) -{ - GC_set_mark_bit(obj); - return NULL; -} - -void *weakmap_add(struct weakmap *wm, void *obj) -{ - struct weakmap_link *link, *new_link, **first; - GC_word *new_base; - void *new_obj; - unsigned h; - size_t key_size = wm->key_size; - - /* Lock and look for an existing entry. */ - h = memhash(obj, key_size); - first = &wm->links[h % wm->capacity]; - weakmap_lock(wm, h); - - for (link = *first; link != NULL; link = link->next) { - void *old_obj = GC_get_find_leak() ? (void *)link->obj - : GC_REVEAL_POINTER(link->obj); - - if (memcmp(old_obj, obj, key_size) == 0) { - GC_call_with_alloc_lock(set_mark_bit, (GC_word *)old_obj - 1); - /* Pointers in the key part may have been freed and reused, */ - /* changing the keys without memcmp noticing. This is okay */ - /* as long as we update the mapped value. */ - if (memcmp((char *)old_obj + key_size, (char *)obj + key_size, - wm->obj_size - key_size) != 0) { - memcpy((char *)old_obj + key_size, (char *)obj + key_size, - wm->obj_size - key_size); - GC_end_stubborn_change((char *)old_obj + key_size); - } - weakmap_unlock(wm, h); - AO_fetch_and_add1(&stat_found); -# ifdef DEBUG_DISCLAIM_WEAKMAP - printf("Found %p, hash=%p\n", old_obj, (void *)(GC_word)h); -# endif - return old_obj; - } - } - - /* Create new object. */ - new_base = (GC_word *)GC_generic_malloc(sizeof(GC_word) + wm->obj_size, - wm->weakobj_kind); - CHECK_OOM(new_base); - *new_base = (GC_word)wm | FINALIZER_CLOSURE_FLAG; - new_obj = (void *)(new_base + 1); - memcpy(new_obj, obj, wm->obj_size); - GC_end_stubborn_change(new_base); - - /* Add the object to the map. */ - new_link = GC_NEW(struct weakmap_link); - CHECK_OOM(new_link); - new_link->obj = GC_get_find_leak() ? (GC_word)new_obj - : GC_HIDE_POINTER(new_obj); - new_link->next = *first; - GC_END_STUBBORN_CHANGE(new_link); - GC_PTR_STORE_AND_DIRTY(first, new_link); - weakmap_unlock(wm, h); - AO_fetch_and_add1(&stat_added); -# ifdef DEBUG_DISCLAIM_WEAKMAP - printf("Added %p, hash=%p\n", new_obj, (void *)(GC_word)h); -# endif - return new_obj; -} - -int GC_CALLBACK weakmap_disclaim(void *obj_base) -{ - struct weakmap *wm; - struct weakmap_link **link; - GC_word hdr; - void *obj; - unsigned h; - - /* Decode header word. */ - hdr = *(GC_word *)obj_base; - if ((hdr & FINALIZER_CLOSURE_FLAG) == 0) - return 0; /* on GC free list, ignore it. */ - - my_assert((hdr & INVALIDATE_FLAG) == 0); - wm = (struct weakmap *)(hdr & ~(GC_word)FINALIZER_CLOSURE_FLAG); - if (NULL == wm->links) - return 0; /* weakmap has been already destroyed */ - obj = (GC_word *)obj_base + 1; - - /* Lock and check for mark. */ - h = memhash(obj, wm->key_size); - if (weakmap_trylock(wm, h) != 0) { - AO_fetch_and_add1(&stat_skip_locked); -# ifdef DEBUG_DISCLAIM_WEAKMAP - printf("Skipping locked %p, hash=%p\n", obj, (void *)(GC_word)h); -# endif - return 1; - } - if (GC_is_marked(obj_base)) { - weakmap_unlock(wm, h); - AO_fetch_and_add1(&stat_skip_marked); -# ifdef DEBUG_DISCLAIM_WEAKMAP - printf("Skipping marked %p, hash=%p\n", obj, (void *)(GC_word)h); -# endif - return 1; - } - - /* Remove obj from wm. */ - AO_fetch_and_add1(&stat_removed); -# ifdef DEBUG_DISCLAIM_WEAKMAP - printf("Removing %p, hash=%p\n", obj, (void *)(GC_word)h); -# endif - *(GC_word *)obj_base |= INVALIDATE_FLAG; - for (link = &wm->links[h % wm->capacity];; link = &(*link)->next) { - void *old_obj; - - if (NULL == *link) { - fprintf(stderr, "Did not find %p\n", obj); - exit(70); - } - old_obj = GC_get_find_leak() ? (void *)(*link)->obj - : GC_REVEAL_POINTER((*link)->obj); - if (old_obj == obj) - break; - my_assert(memcmp(old_obj, obj, wm->key_size) != 0); - } - GC_PTR_STORE_AND_DIRTY(link, (*link)->next); - weakmap_unlock(wm, h); - return 0; -} - -struct weakmap *weakmap_new(size_t capacity, size_t key_size, size_t obj_size, - unsigned weakobj_kind) -{ - struct weakmap *wm = GC_NEW(struct weakmap); - - CHECK_OOM(wm); -# ifdef GC_PTHREADS - { - int i; - for (i = 0; i < WEAKMAP_MUTEX_COUNT; ++i) { - int err = pthread_mutex_init(&wm->mutex[i], NULL); - my_assert(err == 0); - } - } -# endif - wm->key_size = key_size; - wm->obj_size = obj_size; - wm->capacity = capacity; - wm->weakobj_kind = weakobj_kind; - GC_PTR_STORE_AND_DIRTY(&wm->links, - GC_MALLOC(sizeof(struct weakmap_link *) * capacity)); - CHECK_OOM(wm->links); - return wm; -} - -void weakmap_destroy(struct weakmap *wm) -{ -# ifdef GC_PTHREADS - int i; - - for (i = 0; i < WEAKMAP_MUTEX_COUNT; ++i) { - (void)pthread_mutex_destroy(&wm->mutex[i]); - } -# endif - wm->links = NULL; /* weakmap is destroyed */ -} - -struct weakmap *pair_hcset; - -#define PAIR_MAGIC_SIZE 16 /* should not exceed sizeof(pair_magic) */ - -struct pair_key { - struct pair *car, *cdr; -}; - -struct pair { - struct pair *car; - struct pair *cdr; - char magic[PAIR_MAGIC_SIZE]; - int checksum; -}; - -static const char * const pair_magic = "PAIR_MAGIC_BYTES"; - -struct pair *pair_new(struct pair *car, struct pair *cdr) -{ - struct pair tmpl; - - memset(&tmpl, 0, sizeof(tmpl)); /* To clear the paddings (to avoid */ - /* a compiler warning). */ - tmpl.car = car; - tmpl.cdr = cdr; - memcpy(tmpl.magic, pair_magic, PAIR_MAGIC_SIZE); - tmpl.checksum = 782 + (car? car->checksum : 0) + (cdr? cdr->checksum : 0); - return (struct pair *)weakmap_add(pair_hcset, &tmpl); -} - -void pair_check_rec(struct pair *p, int line) -{ - while (p != NULL) { - int checksum = 782; - - if (memcmp(p->magic, pair_magic, PAIR_MAGIC_SIZE) != 0) { - fprintf(stderr, "Magic bytes wrong for %p at %d\n", (void *)p, line); - exit(70); - } - if (p->car != NULL) - checksum += p->car->checksum; - if (p->cdr != NULL) - checksum += p->cdr->checksum; - if (p->checksum != checksum) { - fprintf(stderr, "Checksum failure for %p = (%p, %p) at %d\n", - (void *)p, (void *)p->car, (void *)p->cdr, line); - exit(70); - } - p = (rand() & 1) != 0 ? p->cdr : p->car; - } -} - -void *test(void *data) -{ - int i; - struct pair *p0, *p1; - struct pair *pop[POP_SIZE]; - - memset(pop, 0, sizeof(pop)); - for (i = 0; i < MUTATE_CNT; ++i) { - int bits = rand(); - int t = (bits >> 3) % POP_SIZE; - - switch (bits % (i > GROW_LIMIT ? 5 : 3)) { - case 0: - case 3: - if (pop[t] != NULL) - pop[t] = pop[t]->car; - break; - case 1: - case 4: - if (pop[t] != NULL) - pop[t] = pop[t]->cdr; - break; - case 2: - p0 = pop[rand() % POP_SIZE]; - p1 = pop[rand() % POP_SIZE]; - pop[t] = pair_new(p0, p1); - my_assert(pair_new(p0, p1) == pop[t]); - my_assert(pop[t]->car == p0); - my_assert(pop[t]->cdr == p1); - break; - } - pair_check_rec(pop[rand() % POP_SIZE], __LINE__); - } - return data; -} - -int main(void) -{ - unsigned weakobj_kind; - void **weakobj_free_list; -# ifdef GC_PTHREADS - int i; - pthread_t th[NTHREADS]; -# endif - - GC_set_all_interior_pointers(0); /* for a stricter test */ -# ifdef TEST_MANUAL_VDB - GC_set_manual_vdb_allowed(1); -# endif - GC_INIT(); - GC_init_finalized_malloc(); /* to register the displacements */ -# ifndef NO_INCREMENTAL - GC_enable_incremental(); -# endif - if (GC_get_find_leak()) - printf("This test program is not designed for leak detection mode\n"); - - weakobj_free_list = GC_new_free_list(); - CHECK_OOM(weakobj_free_list); - weakobj_kind = GC_new_kind(weakobj_free_list, /* 0 | */ GC_DS_LENGTH, - 1 /* adjust */, 1 /* clear */); - GC_register_disclaim_proc(weakobj_kind, weakmap_disclaim, - 1 /* mark_unconditionally */); - pair_hcset = weakmap_new(WEAKMAP_CAPACITY, sizeof(struct pair_key), - sizeof(struct pair), weakobj_kind); - -# ifdef GC_PTHREADS - for (i = 0; i < NTHREADS; ++i) { - int err = pthread_create(&th[i], NULL, test, NULL); - if (err != 0) { - fprintf(stderr, "Failed to create thread #%d: %s\n", - i, strerror(err)); - exit(1); - } - } - for (i = 0; i < NTHREADS; ++i) { - int err = pthread_join(th[i], NULL); - if (err != 0) { - fprintf(stderr, "Failed to join thread #%d: %s\n", i, strerror(err)); - exit(69); - } - } -# else - (void)test(NULL); -# endif - weakmap_destroy(pair_hcset); - printf("%u added, %u found; %u removed, %u locked, %u marked; %u remains\n", - (unsigned)stat_added, (unsigned)stat_found, (unsigned)stat_removed, - (unsigned)stat_skip_locked, (unsigned)stat_skip_marked, - (unsigned)stat_added - (unsigned)stat_removed); - return 0; -} diff --git a/gc/tests/initsecondarythread.c b/gc/tests/initsecondarythread.c index 0ad855d8d..788a86252 100644 --- a/gc/tests/initsecondarythread.c +++ b/gc/tests/initsecondarythread.c @@ -85,8 +85,6 @@ int main(void) GC_INIT(); # endif (void)GC_get_parallel(); /* linking fails if no threads support */ - if (GC_get_find_leak()) - printf("This test program is not designed for leak detection mode\n"); # ifdef GC_PTHREADS if ((code = pthread_create (&t, NULL, thread, NULL)) != 0) { fprintf(stderr, "Thread creation failed %d\n", code); diff --git a/gc/tests/middle.c b/gc/tests/middle.c index 9a7cc3d08..55686f759 100644 --- a/gc/tests/middle.c +++ b/gc/tests/middle.c @@ -11,8 +11,6 @@ int main (void) GC_set_all_interior_pointers(0); GC_INIT(); - if (GC_get_find_leak()) - printf("This test program is not designed for leak detection mode\n"); for (i = 0; i < 20000; ++i) { (void)GC_malloc_atomic(4096); diff --git a/gc/tests/realloc_test.c b/gc/tests/realloc_test.c index 8870971b4..c7c80d738 100644 --- a/gc/tests/realloc_test.c +++ b/gc/tests/realloc_test.c @@ -10,8 +10,6 @@ int main(void) { unsigned long last_heap_size = 0; GC_INIT(); - if (GC_get_find_leak()) - printf("This test program is not designed for leak detection mode\n"); for (i = 0; i < COUNT; i++) { int **p = GC_NEW(int *); diff --git a/gc/tests/smash_test.c b/gc/tests/smash_test.c index 9aab02de6..4ba7be047 100644 --- a/gc/tests/smash_test.c +++ b/gc/tests/smash_test.c @@ -13,8 +13,6 @@ char * A[COUNT]; -char * volatile q; - int main(void) { int i; @@ -25,17 +23,8 @@ int main(void) for (i = 0; i < COUNT; ++i) { A[i] = p = (char*)GC_MALLOC(SIZE); - if (i%3000 == 0) { - q = NULL; - GC_gcollect(); - } else if (i%5678 == 0 && p != 0) { - /* Write a byte past the end of the allocated object */ - /* but not beyond the last word of the object's memory. */ - /* A volatile intermediate pointer variable is used to */ - /* avoid a compiler complain of out-of-bounds access. */ - q = &p[(SIZE + i/2000) /* 42 */]; - *q = 42; - } + if (i%3000 == 0) GC_gcollect(); + if (i%5678 == 0 && p != 0) p[SIZE + i/2000] = 42; } return 0; } diff --git a/gc/tests/staticrootstest.c b/gc/tests/staticrootstest.c index 66aca2997..b43765d08 100644 --- a/gc/tests/staticrootstest.c +++ b/gc/tests/staticrootstest.c @@ -49,8 +49,6 @@ int main(void) GC_INIT(); # endif init_staticroot(); - if (GC_get_find_leak()) - printf("This test program is not designed for leak detection mode\n"); if (NULL == staticroot) { fprintf(stderr, "GC_malloc returned NULL\n"); return 2; diff --git a/gc/tests/subthread_create.c b/gc/tests/subthread_create.c index 2b3b46049..a40df51cb 100644 --- a/gc/tests/subthread_create.c +++ b/gc/tests/subthread_create.c @@ -58,7 +58,7 @@ volatile AO_t thread_ended_cnt = 0; DWORD WINAPI entry(LPVOID arg) #endif { - int thread_num = (int)AO_fetch_and_add1(&thread_created_cnt); + int thread_num = AO_fetch_and_add1(&thread_created_cnt); GC_word my_depth = (GC_word)arg + 1; if (my_depth <= MAX_SUBTHREAD_DEPTH diff --git a/gc/tests/test.c b/gc/tests/test.c index 8e2e3a6d0..8ec8c13f2 100644 --- a/gc/tests/test.c +++ b/gc/tests/test.c @@ -156,12 +156,6 @@ # define INIT_MANUAL_VDB_ALLOWED /* empty */ #endif -#ifdef TEST_PAGES_EXECUTABLE -# define INIT_PAGES_EXECUTABLE GC_set_pages_executable(1) -#else -# define INIT_PAGES_EXECUTABLE (void)0 -#endif - #define CHECK_GCLIB_VERSION \ if (GC_get_version() != ((GC_VERSION_MAJOR<<16) \ | (GC_VERSION_MINOR<<8) \ @@ -191,7 +185,7 @@ #endif #define GC_COND_INIT() \ - INIT_FORK_SUPPORT; INIT_MANUAL_VDB_ALLOWED; INIT_PAGES_EXECUTABLE; \ + INIT_FORK_SUPPORT; INIT_MANUAL_VDB_ALLOWED; \ GC_OPT_INIT; CHECK_GCLIB_VERSION; \ INIT_PRINT_STATS; INIT_FIND_LEAK; INIT_PERF_MEASUREMENT @@ -202,7 +196,7 @@ } /* Define AO primitives for a single-threaded mode. */ -#ifndef AO_HAVE_compiler_barrier +#ifndef AO_CLEAR /* AO_t not defined. */ # define AO_t GC_word #endif @@ -1469,8 +1463,6 @@ void run_one_test(void) GC_FREE(GC_MALLOC_ATOMIC(0)); test_generic_malloc_or_special(GC_malloc_atomic(1)); AO_fetch_and_add1(&atomic_count); - GC_FREE(GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(1)); - GC_FREE(GC_MALLOC_IGNORE_OFF_PAGE(2)); } } # ifdef GC_GCJ_SUPPORT @@ -1561,10 +1553,6 @@ void run_one_test(void) # endif # endif /* DBG_HDRS_ALL */ tree_test(); -# ifdef TEST_WITH_SYSTEM_MALLOC - free(calloc(1,1)); - free(realloc(NULL, 64)); -# endif # ifndef NO_CLOCK if (print_stats) { CLOCK_TYPE tree_time; @@ -1595,13 +1583,6 @@ void run_one_test(void) # endif } -/* Execute some tests after termination of other test threads (if any). */ -void run_single_threaded_test(void) { - GC_disable(); - GC_FREE(GC_MALLOC(100)); - GC_enable(); -} - void GC_CALLBACK reachable_objs_counter(void *obj, size_t size, void *pcounter) { @@ -1916,7 +1897,6 @@ void GC_CALLBACK warn_proc(char *msg, GC_word p) # endif set_print_procs(); run_one_test(); - run_single_threaded_test(); check_heap_stats(); # ifndef MSWINCE fflush(stdout); @@ -1983,6 +1963,7 @@ void GC_CALLBACK warn_proc(char *msg, GC_word p) UNTESTED(GC_set_on_collection_event); UNTESTED(GC_set_on_heap_resize); UNTESTED(GC_set_oom_fn); + UNTESTED(GC_set_pages_executable); UNTESTED(GC_set_push_other_roots); UNTESTED(GC_set_start_callback); UNTESTED(GC_set_stop_func); @@ -2009,7 +1990,6 @@ void GC_CALLBACK warn_proc(char *msg, GC_word p) UNTESTED(GC_gcj_malloc_ignore_off_page); # endif # ifndef NO_DEBUGGING - UNTESTED(GC_dump); UNTESTED(GC_dump_regions); UNTESTED(GC_is_tmp_root); UNTESTED(GC_print_free_list); @@ -2224,7 +2204,6 @@ DWORD __stdcall thr_window(void * arg GC_ATTR_UNUSED) if (WaitForSingleObject(win_thr_h, INFINITE) != WAIT_OBJECT_0) FAIL; # endif - run_single_threaded_test(); check_heap_stats(); # if defined(CPPCHECK) && defined(GC_WIN32_THREADS) UNTESTED(GC_ExitThread); @@ -2266,7 +2245,6 @@ int test(void) != PCR_ERes_okay || code != 0) { GC_printf("Thread 2 failed\n"); } - run_single_threaded_test(); check_heap_stats(); return(0); } @@ -2379,7 +2357,6 @@ int main(void) } } # endif - run_single_threaded_test(); check_heap_stats(); (void)fflush(stdout); (void)pthread_attr_destroy(&attr); diff --git a/gc/tests/test_cpp.cc b/gc/tests/test_cpp.cc index a9165a965..6f7efad5d 100644 --- a/gc/tests/test_cpp.cc +++ b/gc/tests/test_cpp.cc @@ -14,7 +14,7 @@ the code was modified is included with the above copyright notice. usage: test_cpp number-of-iterations This program tries to test the specific C++ functionality provided by -gc_cpp.h that isn't tested by the more general test routines of the +gc_c++.h that isn't tested by the more general test routines of the collector. A recommended value for number-of-iterations is 10, which will take a @@ -76,8 +76,7 @@ extern "C" { exit( 1 ); } #ifndef GC_ATTR_EXPLICIT -# if __cplusplus >= 201103L && !defined(__clang__) || _MSVC_LANG >= 201103L \ - || defined(CPPCHECK) +# if (__cplusplus >= 201103L) || defined(CPPCHECK) # define GC_ATTR_EXPLICIT explicit # else # define GC_ATTR_EXPLICIT /* empty */ @@ -90,7 +89,6 @@ class A {public: GC_ATTR_EXPLICIT A( int iArg ): i( iArg ) {} void Test( int iArg ) { my_assert( i == iArg );} - virtual ~A() {} int i;}; @@ -159,14 +157,7 @@ class C: public GC_NS_QUALIFY(gc_cleanup), public A { public: left = right = 0; level = -123456;} static void Test() { - if (GC_is_incremental_mode() && nFreed < (nAllocated / 5) * 4) { - // An explicit GC might be needed to reach the expected number - // of the finalized objects. - GC_gcollect(); - } - my_assert(nFreed <= nAllocated); - my_assert(nFreed >= (nAllocated / 5) * 4 || GC_get_find_leak()); - } + my_assert( nFreed <= nAllocated && nFreed >= .8 * nAllocated );} static int nFreed; static int nAllocated; @@ -189,8 +180,7 @@ class D: public GC_NS_QUALIFY(gc) { public: nFreed++; my_assert( (GC_word)self->i == (GC_word)data );} static void Test() { - my_assert(nFreed >= (nAllocated / 5) * 4 || GC_get_find_leak()); - } + my_assert( nFreed >= .8 * nAllocated );} int i; static int nFreed; @@ -228,7 +218,7 @@ class F: public E {public: } static void Test() { - my_assert(nFreedF >= (nAllocatedF / 5) * 4 || GC_get_find_leak()); + my_assert(nFreedF >= .8 * nAllocatedF); my_assert(2 * nFreedF == nFreed); } @@ -276,6 +266,7 @@ void* Undisguise( GC_word i ) { argv[argc] = NULL; break; } + argv[argc] = cmd; for (; *cmd != '\0'; cmd++) { if (*cmd != ' ' && *cmd != '\t') break; @@ -314,8 +305,6 @@ void* Undisguise( GC_word i ) { # ifndef NO_INCREMENTAL GC_enable_incremental(); # endif - if (GC_get_find_leak()) - GC_printf("This test program is not designed for leak detection mode\n"); int i, iters, n; # ifndef DONT_USE_STD_ALLOCATOR diff --git a/gc/tests/tests.am b/gc/tests/tests.am index 93f4b27d2..b851f35a0 100644 --- a/gc/tests/tests.am +++ b/gc/tests/tests.am @@ -9,8 +9,7 @@ # modified is included with the above copyright notice. # Common libs to _LDADD for all tests. -test_ldadd = $(nodist_libgc_la_OBJECTS) $(top_builddir)/libgc.la \ - $(EXTRA_TEST_LIBS) +test_ldadd = $(top_builddir)/libgc.la $(EXTRA_TEST_LIBS) TESTS += gctest$(EXEEXT) check_PROGRAMS += gctest @@ -50,8 +49,8 @@ TESTS += staticrootstest$(EXEEXT) check_PROGRAMS += staticrootstest staticrootstest_SOURCES = tests/staticrootstest.c staticrootstest_CFLAGS = -DSTATICROOTSLIB2 -staticrootstest_LDADD = $(nodist_libgc_la_OBJECTS) $(EXTRA_TEST_LIBS) \ - libstaticrootslib_test.la libstaticrootslib2_test.la +staticrootstest_LDADD = $(test_ldadd) libstaticrootslib_test.la \ + libstaticrootslib2_test.la check_LTLIBRARIES += libstaticrootslib_test.la libstaticrootslib2_test.la libstaticrootslib_test_la_SOURCES = tests/staticrootslib.c libstaticrootslib_test_la_LIBADD = $(test_ldadd) @@ -61,9 +60,6 @@ libstaticrootslib2_test_la_SOURCES = tests/staticrootslib.c libstaticrootslib2_test_la_LIBADD = $(test_ldadd) libstaticrootslib2_test_la_CFLAGS = -DSTATICROOTSLIB2 libstaticrootslib2_test_la_LDFLAGS = -no-undefined -rpath /nowhere -if ENABLE_SHARED -staticrootstest_LDADD += $(top_builddir)/libgc.la -endif if KEEP_BACK_PTRS TESTS += tracetest$(EXEEXT) @@ -109,13 +105,7 @@ test_cpp_SOURCES = tests/test_cpp.cc if AVOID_CPP_LIB test_cpp_LDADD = gc_cpp.o $(test_ldadd) $(CXXLIBS) else -test_cpp_LDADD = libgccpp.la $(nodist_libgc_la_OBJECTS) \ - $(EXTRA_TEST_LIBS) $(CXXLIBS) -## In case of static libraries build, libgc.a is already referenced in -## dependency_libs attribute of libgccpp.la file. -if ENABLE_SHARED -test_cpp_LDADD += $(top_builddir)/libgc.la -endif +test_cpp_LDADD = libgccpp.la $(test_ldadd) $(CXXLIBS) endif endif @@ -134,14 +124,6 @@ check_PROGRAMS += disclaim_bench disclaim_bench_SOURCES = tests/disclaim_bench.c disclaim_bench_LDADD = $(test_ldadd) -TESTS += disclaim_weakmap_test$(EXEEXT) -check_PROGRAMS += disclaim_weakmap_test -disclaim_weakmap_test_SOURCES = tests/disclaim_weakmap_test.c -disclaim_weakmap_test_LDADD = $(test_ldadd) -if THREADS -disclaim_weakmap_test_LDADD += $(THREADDLLIBS) -endif - endif # Run the tests directly (without test-driver): @@ -156,7 +138,6 @@ check-without-test-driver: $(TESTS) ./staticrootstest$(EXEEXT) test ! -f disclaim_bench$(EXEEXT) || ./disclaim_bench$(EXEEXT) test ! -f disclaim_test$(EXEEXT) || ./disclaim_test$(EXEEXT) - test ! -f disclaim_weakmap_test$(EXEEXT) || ./disclaim_weakmap_test$(EXEEXT) test ! -f initsecondarythread_test$(EXEEXT) \ || ./initsecondarythread_test$(EXEEXT) test ! -f test_atomic_ops$(EXEEXT) || ./test_atomic_ops$(EXEEXT) diff --git a/gc/tests/threadkey_test.c b/gc/tests/threadkey_test.c index e224aac99..e348d7248 100644 --- a/gc/tests/threadkey_test.c +++ b/gc/tests/threadkey_test.c @@ -87,10 +87,8 @@ void make_key (void) int main (void) { int i; + GC_INIT (); - GC_INIT(); - if (GC_get_find_leak()) - printf("This test program is not designed for leak detection mode\n"); # ifdef GC_SOLARIS_THREADS pthread_key_create (&key, on_thread_exit); # else diff --git a/gc/tests/trace_test.c b/gc/tests/trace_test.c index d97bbed15..726519d0c 100644 --- a/gc/tests/trace_test.c +++ b/gc/tests/trace_test.c @@ -39,10 +39,7 @@ struct treenode * mktree(int i) { int main(void) { int i; - GC_INIT(); - if (GC_get_find_leak()) - printf("This test program is not designed for leak detection mode\n"); for (i = 0; i < 10; ++i) { root[i] = mktree(12); } diff --git a/gc/win32_threads.c b/gc/win32_threads.c index b5e45f066..225d8e0dc 100644 --- a/gc/win32_threads.c +++ b/gc/win32_threads.c @@ -74,26 +74,6 @@ #endif /* !GC_PTHREADS && !MSWINCE */ -/* PUSHED_REGS_COUNT is the number of copied registers in copy_ptr_regs. */ -static ptr_t copy_ptr_regs(word *regs, const CONTEXT *pcontext); -#if defined(I386) -# ifdef WOW64_THREAD_CONTEXT_WORKAROUND -# define PUSHED_REGS_COUNT 9 -# else -# define PUSHED_REGS_COUNT 7 -# endif -#elif defined(X86_64) || defined(SHx) -# define PUSHED_REGS_COUNT 15 -#elif defined(ARM32) -# define PUSHED_REGS_COUNT 13 -#elif defined(AARCH64) -# define PUSHED_REGS_COUNT 30 -#elif defined(MIPS) || defined(ALPHA) -# define PUSHED_REGS_COUNT 28 -#elif defined(PPC) -# define PUSHED_REGS_COUNT 29 -#endif - /* DllMain-based thread registration is currently incompatible */ /* with thread-local allocation, pthreads and WinCE. */ #if (defined(GC_DLL) || defined(GC_INSIDE_DLL)) \ @@ -188,7 +168,7 @@ GC_API void GC_CALL GC_use_threads_discovery(void) STATIC DWORD GC_main_thread = 0; -#define ADDR_LIMIT ((ptr_t)GC_WORD_MAX) +#define ADDR_LIMIT ((ptr_t)(word)-1) struct GC_Thread_Rep { union { @@ -199,11 +179,6 @@ struct GC_Thread_Rep { /* entries have invalid ids of */ /* zero and zero stack fields. */ /* Used only with GC_win32_dll_threads. */ - LONG long_in_use; /* The same but of the type that */ - /* matches the first argument of */ - /* InterlockedExchange(); volatile is */ - /* omitted because the ancient version */ - /* of the prototype lacks the qualifier.*/ # endif struct GC_Thread_Rep * next; /* Hash table link without */ @@ -274,14 +249,6 @@ struct GC_Thread_Rep { # ifdef THREAD_LOCAL_ALLOC struct thread_local_freelists tlfs; # endif - -# ifdef RETRY_GET_THREAD_CONTEXT - ptr_t context_sp; - word context_regs[PUSHED_REGS_COUNT]; - /* Populated as part of GC_suspend() as */ - /* resume/suspend loop may be needed for the */ - /* call to GetThreadContext() to succeed. */ -# endif }; typedef struct GC_Thread_Rep * GC_thread; @@ -348,7 +315,7 @@ STATIC volatile LONG GC_max_thread_index = 0; /* And now the version used if GC_win32_dll_threads is not set. */ /* This is a chained hash table, with much of the code borrowed */ -/* from the Posix implementation. */ +/* From the Posix implementation. */ #ifndef THREAD_TABLE_SZ # define THREAD_TABLE_SZ 256 /* Power of 2 (for speed). */ #endif @@ -357,8 +324,8 @@ STATIC volatile LONG GC_max_thread_index = 0; STATIC GC_thread GC_threads[THREAD_TABLE_SZ]; /* It may not be safe to allocate when we register the first thread. */ -/* Thus we allocated one statically. It does not contain any pointer */ -/* field we need to push ("next" and "status" fields are unused). */ +/* Thus we allocated one statically. It does not contain any field we */ +/* need to push ("next" and "status" fields are unused). */ static struct GC_Thread_Rep first_thread; static GC_bool first_thread_used = FALSE; @@ -398,7 +365,7 @@ STATIC GC_thread GC_new_thread(DWORD id) return(result); } -GC_INNER GC_bool GC_in_thread_creation = FALSE; +STATIC GC_bool GC_in_thread_creation = FALSE; /* Protected by allocation lock. */ GC_INLINE void GC_record_stack_base(GC_vthread me, @@ -448,8 +415,9 @@ STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb, /* around code that doesn't call back into the system libraries */ /* might be OK. But this hasn't been tested across all win32 */ /* variants. */ + /* cast away volatile qualifier */ for (i = 0; - InterlockedExchange(&dll_thread_table[i].tm.long_in_use, 1) != 0; + InterlockedExchange((word*)&dll_thread_table[i].tm.in_use, 1) != 0; i++) { /* Compare-and-swap would make this cleaner, but that's not */ /* supported before Windows 98 and NT 4.0. In Windows 2000, */ @@ -698,10 +666,6 @@ STATIC void GC_delete_gc_thread_no_free(GC_vthread t) /* see GC_stop_world() for the information. */ t -> stack_base = 0; t -> id = 0; - t -> suspended = FALSE; -# ifdef RETRY_GET_THREAD_CONTEXT - t -> context_sp = NULL; -# endif AO_store_release(&t->tm.in_use, FALSE); } else # endif @@ -955,7 +919,7 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn, UNLOCK(); client_data = fn(client_data); /* Prevent treating the above as a tail call. */ - GC_noop1(COVERT_DATAFLOW(&stacksect)); + GC_noop1((word)(&stacksect)); return client_data; /* result */ } @@ -1065,14 +1029,12 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn, STATIC void GC_remove_all_threads_but_me(void) { int hv; - GC_thread me = NULL; + GC_thread p, next, me = NULL; DWORD thread_id; pthread_t pthread_id = pthread_self(); /* same as in parent */ GC_ASSERT(!GC_win32_dll_threads); for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) { - GC_thread p, next; - for (p = GC_threads[hv]; 0 != p; p = next) { next = p -> tm.next; if (THREAD_EQUAL(p -> pthread_id, pthread_id) @@ -1198,101 +1160,41 @@ void GC_push_thread_structures(void) # endif } -#ifdef WOW64_THREAD_CONTEXT_WORKAROUND -# ifndef CONTEXT_EXCEPTION_ACTIVE -# define CONTEXT_EXCEPTION_ACTIVE 0x08000000 -# define CONTEXT_EXCEPTION_REQUEST 0x40000000 -# define CONTEXT_EXCEPTION_REPORTING 0x80000000 -# endif - static BOOL isWow64; /* Is running 32-bit code on Win64? */ -# define GET_THREAD_CONTEXT_FLAGS (isWow64 \ - ? CONTEXT_INTEGER | CONTEXT_CONTROL \ - | CONTEXT_EXCEPTION_REQUEST | CONTEXT_SEGMENTS \ - : CONTEXT_INTEGER | CONTEXT_CONTROL) -#else -# define GET_THREAD_CONTEXT_FLAGS (CONTEXT_INTEGER | CONTEXT_CONTROL) -#endif /* !WOW64_THREAD_CONTEXT_WORKAROUND */ - /* Suspend the given thread, if it's still active. */ STATIC void GC_suspend(GC_thread t) { # ifndef MSWINCE + /* Apparently the Windows 95 GetOpenFileName call creates */ + /* a thread that does not properly get cleaned up, and */ + /* SuspendThread on its descriptor may provoke a crash. */ + /* This reduces the probability of that event, though it still */ + /* appears there's a race here. */ DWORD exitCode; # endif -# ifdef RETRY_GET_THREAD_CONTEXT - int retry_cnt = 0; -# define MAX_SUSPEND_THREAD_RETRIES (1000 * 1000) -# endif - UNPROTECT_THREAD(t); - GC_acquire_dirty_lock(); - -# ifdef MSWINCE - /* SuspendThread() will fail if thread is running kernel code. */ - while (SuspendThread(THREAD_HANDLE(t)) == (DWORD)-1) { - GC_release_dirty_lock(); - Sleep(10); /* in millis */ - GC_acquire_dirty_lock(); - } -# elif defined(RETRY_GET_THREAD_CONTEXT) - for (;;) { - /* Apparently the Windows 95 GetOpenFileName call creates */ - /* a thread that does not properly get cleaned up, and */ - /* SuspendThread on its descriptor may provoke a crash. */ - /* This reduces the probability of that event, though it still */ - /* appears there is a race here. */ - if (GetExitCodeThread(t -> handle, &exitCode) - && exitCode != STILL_ACTIVE) { - GC_release_dirty_lock(); -# ifdef GC_PTHREADS - t -> stack_base = 0; /* prevent stack from being pushed */ -# else - /* This breaks pthread_join on Cygwin, which is guaranteed to */ - /* only see user threads. */ - GC_ASSERT(GC_win32_dll_threads); - GC_delete_gc_thread_no_free(t); -# endif - return; - } - - if (SuspendThread(t->handle) != (DWORD)-1) { - CONTEXT context; - - context.ContextFlags = GET_THREAD_CONTEXT_FLAGS; - if (GetThreadContext(t->handle, &context)) { - /* TODO: WoW64 extra workaround: if CONTEXT_EXCEPTION_ACTIVE */ - /* then Sleep(1) and retry. */ - t->context_sp = copy_ptr_regs(t->context_regs, &context); - break; /* success; the context pointer registers are saved */ - } - - /* Resume the thread, try to suspend it in a better location. */ - if (ResumeThread(t->handle) == (DWORD)-1) - ABORT("ResumeThread failed in suspend loop"); - } - if (retry_cnt > 1) { - GC_release_dirty_lock(); - Sleep(0); /* yield */ - GC_acquire_dirty_lock(); - } - if (++retry_cnt >= MAX_SUSPEND_THREAD_RETRIES) - ABORT("SuspendThread loop failed"); /* something must be wrong */ - } -# else - if (GetExitCodeThread(t -> handle, &exitCode) - && exitCode != STILL_ACTIVE) { - GC_release_dirty_lock(); +# ifndef MSWINCE + if (GetExitCodeThread(t -> handle, &exitCode) && + exitCode != STILL_ACTIVE) { # ifdef GC_PTHREADS t -> stack_base = 0; /* prevent stack from being pushed */ # else + /* this breaks pthread_join on Cygwin, which is guaranteed to */ + /* only see user pthreads */ GC_ASSERT(GC_win32_dll_threads); GC_delete_gc_thread_no_free(t); # endif return; } +# endif + GC_acquire_dirty_lock(); +# ifdef MSWINCE + /* SuspendThread() will fail if thread is running kernel code. */ + while (SuspendThread(THREAD_HANDLE(t)) == (DWORD)-1) + Sleep(10); /* in millis */ +# else if (SuspendThread(t -> handle) == (DWORD)-1) ABORT("SuspendThread failed"); -# endif +# endif /* !MSWINCE */ t -> suspended = (unsigned char)TRUE; GC_release_dirty_lock(); if (GC_on_thread_event) @@ -1478,23 +1380,30 @@ static GC_bool may_be_in_stack(ptr_t s) && !(last_info.Protect & PAGE_GUARD); } -/* Copy all registers that might point into the heap. Frame */ -/* pointer registers are included in case client code was */ -/* compiled with the 'omit frame pointer' optimization. */ -/* The context register values are stored to regs argument */ -/* which is expected to be of PUSHED_REGS_COUNT length exactly. */ -/* The functions returns the context stack pointer value. */ -static ptr_t copy_ptr_regs(word *regs, const CONTEXT *pcontext) { - ptr_t sp; - int cnt = 0; -# define context (*pcontext) -# define PUSH1(reg) (regs[cnt++] = (word)pcontext->reg) +STATIC word GC_push_stack_for(GC_thread thread, DWORD me) +{ + ptr_t sp, stack_min; + + struct GC_traced_stack_sect_s *traced_stack_sect = + thread -> traced_stack_sect; + if (thread -> id == me) { + GC_ASSERT(thread -> thread_blocked_sp == NULL); + sp = GC_approx_sp(); + } else if ((sp = thread -> thread_blocked_sp) == NULL) { + /* Use saved sp value for blocked threads. */ + /* For unblocked threads call GetThreadContext(). */ + CONTEXT context; + context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL; + if (!GetThreadContext(THREAD_HANDLE(thread), &context)) + ABORT("GetThreadContext failed"); + + /* Push all registers that might point into the heap. Frame */ + /* pointer registers are included in case client code was */ + /* compiled with the 'omit frame pointer' optimization. */ +# define PUSH1(reg) GC_push_one((word)context.reg) # define PUSH2(r1,r2) (PUSH1(r1), PUSH1(r2)) # define PUSH4(r1,r2,r3,r4) (PUSH2(r1,r2), PUSH2(r3,r4)) # if defined(I386) -# ifdef WOW64_THREAD_CONTEXT_WORKAROUND - PUSH2(ContextFlags, SegFs); /* cannot contain pointers */ -# endif PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp); sp = (ptr_t)context.Esp; # elif defined(X86_64) @@ -1505,12 +1414,6 @@ static ptr_t copy_ptr_regs(word *regs, const CONTEXT *pcontext) { PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11); PUSH1(R12); sp = (ptr_t)context.Sp; -# elif defined(AARCH64) - PUSH4(X0,X1,X2,X3),PUSH4(X4,X5,X6,X7),PUSH4(X8,X9,X10,X11); - PUSH4(X12,X13,X14,X15),PUSH4(X16,X17,X18,X19),PUSH4(X20,X21,X22,X23); - PUSH4(X24,X25,X26,X27),PUSH1(X28); - PUSH1(Lr); - sp = (ptr_t)context.Sp; # elif defined(SHx) PUSH4(R0,R1,R2,R3), PUSH4(R4,R5,R6,R7), PUSH4(R8,R9,R10,R11); PUSH2(R12,R13), PUSH1(R14); @@ -1533,111 +1436,9 @@ static ptr_t copy_ptr_regs(word *regs, const CONTEXT *pcontext) { PUSH4(IntA0,IntA1,IntA2,IntA3), PUSH4(IntA4,IntA5,IntT8,IntT9); PUSH4(IntT10,IntT11,IntT12,IntAt); sp = (ptr_t)context.IntSp; -# elif defined(CPPCHECK) - sp = (ptr_t)(word)cnt; /* to workaround "cnt not used" false positive */ -# else -# error Architecture is not supported -# endif -# undef context - GC_ASSERT(cnt == PUSHED_REGS_COUNT); - return sp; -} - -STATIC word GC_push_stack_for(GC_thread thread, DWORD me) -{ - ptr_t sp, stack_min; - - struct GC_traced_stack_sect_s *traced_stack_sect = - thread -> traced_stack_sect; - if (thread -> id == me) { - GC_ASSERT(thread -> thread_blocked_sp == NULL); - sp = GC_approx_sp(); - } else if ((sp = thread -> thread_blocked_sp) == NULL) { - /* Use saved sp value for blocked threads. */ - int i = 0; -# ifdef RETRY_GET_THREAD_CONTEXT - /* We cache context when suspending the thread since it may */ - /* require looping. */ - word *regs = thread->context_regs; - - if (thread->suspended) { - sp = thread->context_sp; - } else -# else - word regs[PUSHED_REGS_COUNT]; +# elif !defined(CPPCHECK) +# error "architecture is not supported" # endif - - /* else */ { - CONTEXT context; - - /* For unblocked threads call GetThreadContext(). */ - context.ContextFlags = GET_THREAD_CONTEXT_FLAGS; - if (GetThreadContext(THREAD_HANDLE(thread), &context)) { - sp = copy_ptr_regs(regs, &context); - } else { -# ifdef RETRY_GET_THREAD_CONTEXT - /* At least, try to use the stale context if saved. */ - sp = thread->context_sp; - if (NULL == sp) { - /* Skip the current thread, anyway its stack will */ - /* be pushed when the world is stopped. */ - return 0; - } -# else - ABORT("GetThreadContext failed"); -# endif - } - } - -# ifdef WOW64_THREAD_CONTEXT_WORKAROUND - i += 2; /* skip ContextFlags and SegFs */ -# endif - for (; i < PUSHED_REGS_COUNT; i++) - GC_push_one(regs[i]); - -# ifdef WOW64_THREAD_CONTEXT_WORKAROUND - /* WoW64 workaround. */ - if (isWow64) { - DWORD ContextFlags = (DWORD)regs[0]; - WORD SegFs = (WORD)regs[1]; - - if ((ContextFlags & CONTEXT_EXCEPTION_REPORTING) != 0 - && (ContextFlags & (CONTEXT_EXCEPTION_ACTIVE - /* | CONTEXT_SERVICE_ACTIVE */)) != 0) { - LDT_ENTRY selector; - PNT_TIB tib; - - if (!GetThreadSelectorEntry(THREAD_HANDLE(thread), SegFs, &selector)) - ABORT("GetThreadSelectorEntry failed"); - tib = (PNT_TIB)(selector.BaseLow - | (selector.HighWord.Bits.BaseMid << 16) - | (selector.HighWord.Bits.BaseHi << 24)); -# ifdef DEBUG_THREADS - GC_log_printf("TIB stack limit/base: %p .. %p\n", - (void *)tib->StackLimit, (void *)tib->StackBase); -# endif - GC_ASSERT(!((word)thread->stack_base - COOLER_THAN (word)tib->StackBase)); - - /* GetThreadContext() might return stale register values, */ - /* so we scan the entire stack region (down to the stack */ - /* limit). There is no 100% guarantee that all the */ - /* registers are pushed but we do our best (the proper */ - /* solution would be to fix it inside Windows OS). */ - sp = (ptr_t)tib->StackLimit; - } /* else */ -# ifdef DEBUG_THREADS - else { - static GC_bool logged; - if (!logged - && (ContextFlags & CONTEXT_EXCEPTION_REPORTING) == 0) { - GC_log_printf("CONTEXT_EXCEPTION_REQUEST not supported\n"); - logged = TRUE; - } - } -# endif - } -# endif /* WOW64_THREAD_CONTEXT_WORKAROUND */ } /* ! current thread */ /* Set stack_min to the lowest address in the thread stack, */ @@ -1722,8 +1523,6 @@ STATIC word GC_push_stack_for(GC_thread thread, DWORD me) return thread->stack_base - sp; /* stack grows down */ } -/* We hold allocation lock. Should do exactly the right thing if the */ -/* world is stopped. Should not fail if it isn't. */ GC_INNER void GC_push_all_stacks(void) { DWORD thread_id = GetCurrentThreadId(); @@ -1935,7 +1734,7 @@ GC_INNER void GC_get_next_stack(char *start, char *limit, { word my_mark_no = 0; - if ((word)id == GC_WORD_MAX) return 0; /* to prevent a compiler warning */ + if ((word)id == (word)-1) return 0; /* to make compiler happy */ marker_sp[(word)id] = GC_approx_sp(); # ifdef IA64 marker_bsp[(word)id] = GC_save_regs_in_stack(); @@ -2610,6 +2409,9 @@ GC_INNER void GC_get_next_stack(char *start, char *limit, GC_INNER void GC_thr_init(void) { struct GC_stack_base sb; +# ifdef GC_ASSERTIONS + int sb_result; +# endif GC_ASSERT(I_HOLD_LOCK()); if (GC_thr_initialized) return; @@ -2633,26 +2435,12 @@ GC_INNER void GC_thr_init(void) } # endif -# ifdef WOW64_THREAD_CONTEXT_WORKAROUND - /* Set isWow64 flag. */ - { - HMODULE hK32 = GetModuleHandle(TEXT("kernel32.dll")); - if (hK32) { - FARPROC pfn = GetProcAddress(hK32, "IsWow64Process"); - if (pfn - && !(*(BOOL (WINAPI*)(HANDLE, BOOL*))(word)pfn)( - GetCurrentProcess(), &isWow64)) - isWow64 = FALSE; /* IsWow64Process failed */ - } - } -# endif - /* Add the initial thread, so we can stop it. */ - sb.mem_base = GC_stackbottom; - GC_ASSERT(sb.mem_base != NULL); -# ifdef IA64 - sb.reg_base = GC_register_stackbottom; +# ifdef GC_ASSERTIONS + sb_result = # endif + GC_get_stack_base(&sb); + GC_ASSERT(sb_result == GC_SUCCESS); # if defined(PARALLEL_MARK) { From 33276349eedb0cbbbc3f6271c2c43b7234821b6f Mon Sep 17 00:00:00 2001 From: John Pye Date: Fri, 14 Jan 2022 15:20:36 +1100 Subject: [PATCH 06/12] flexible naming of omcgc vs gc-lib --- CMakeLists.txt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 16aee8f74..b0ddbbdd0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,21 +69,25 @@ set(GC_BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries") set(enable_java_finalization OFF CACHE BOOL "Support for java finalization") set(enable_gcj_support OFF CACHE BOOL "Support for gcj") set(enable_large_config ON CACHE BOOL "Optimize for large heap or root set") + omc_add_subdirectory(gc) -target_include_directories(gc-lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/gc/include) +set(LIBOMCGC omcgc) +# note that native GC will have a different library name + +target_include_directories(${LIBOMCGC} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/gc/include) # make sure every target that links to gc-lib has its sources # compiled with -DGC_WIN32_PTHREADS (for pthreads on Windows, i.e., our MingW) # Or -DGC_THREADS (for auto detection on other systems.) # On Windows with MinGW OM uses pthreads-win32. GC_WIN32_PTHREADS is required # to be set explicitly for use of pthreads API on Windows. if(MINGW) - target_compile_definitions(gc-lib PUBLIC GC_WIN32_PTHREADS) + target_compile_definitions(${LIBOMCGC} PUBLIC GC_WIN32_PTHREADS) else() - target_compile_definitions(gc-lib PUBLIC GC_THREADS) + target_compile_definitions(${LIBOMCGC} PUBLIC GC_THREADS) endif(MINGW) # Finally add an alias for clarity purposes. -add_library(omc::3rd::omcgc ALIAS gc-lib) +add_library(omc::3rd::omcgc ALIAS ${LIBOMCGC}) From 0bac4ed1a6975291a55fbb2e4fc5a15d08419286 Mon Sep 17 00:00:00 2001 From: John Pye Date: Fri, 14 Jan 2022 15:22:35 +1100 Subject: [PATCH 07/12] ignore FMIL/include --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e35ce5038..32a940ba3 100644 --- a/.gitignore +++ b/.gitignore @@ -82,6 +82,7 @@ Ipopt-3.13.4/build FMIL/build/ FMIL/install/ +FMIL/include/ SuiteSparse/build/ @@ -149,4 +150,4 @@ sundials-5.4.0/build_msvc/ /libffi/install/ /libffi/x86_64-*-gnu/ -/libffi/x86_64-w64-mingw32/ \ No newline at end of file +/libffi/x86_64-w64-mingw32/ From 30c0e6bbb6650b8e422b73e670af1f437d611634 Mon Sep 17 00:00:00 2001 From: John Pye Date: Fri, 14 Jan 2022 17:41:43 +1100 Subject: [PATCH 08/12] Correcting Windows detection for MSYS2. See https://stackoverflow.com/questions/2989810 and https://stackoverflow.com/questions/17493759 --- graphstream/gs-netstream/c++/src/netstream-socket.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/graphstream/gs-netstream/c++/src/netstream-socket.cpp b/graphstream/gs-netstream/c++/src/netstream-socket.cpp index f5fa6d9af..f36c283e1 100644 --- a/graphstream/gs-netstream/c++/src/netstream-socket.cpp +++ b/graphstream/gs-netstream/c++/src/netstream-socket.cpp @@ -14,8 +14,7 @@ #endif - -#ifndef WIN32 +#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) #include #include #include @@ -25,7 +24,7 @@ #include #include #include -#else +#elif defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) #ifdef ERROR #undef ERROR #endif @@ -35,7 +34,8 @@ #ifndef vsnprintf #define vsnprintf _vsnprintf #endif - +#else +# error "UNRECOGNISED PLATFORM") #endif #include From 3602e6bb831c72ffebcae2f7a85521c3e92e8335 Mon Sep 17 00:00:00 2001 From: John Pye Date: Sat, 15 Jan 2022 19:47:28 +1100 Subject: [PATCH 09/12] detect windows as _WIN32 --- .../gs-netstream/c++/src/netstream-socket.cpp | 75 ++++++++----------- .../gs-netstream/c++/src/netstream-socket.h | 17 ++--- 2 files changed, 36 insertions(+), 56 deletions(-) diff --git a/graphstream/gs-netstream/c++/src/netstream-socket.cpp b/graphstream/gs-netstream/c++/src/netstream-socket.cpp index f36c283e1..45bd8d500 100644 --- a/graphstream/gs-netstream/c++/src/netstream-socket.cpp +++ b/graphstream/gs-netstream/c++/src/netstream-socket.cpp @@ -13,29 +13,24 @@ #include "netstream-socket.h" #endif - -#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) - #include - #include - #include - #include - #include - #include - #include - #include - #include -#elif defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) - #ifdef ERROR - #undef ERROR - #endif - - #include - - #ifndef vsnprintf - #define vsnprintf _vsnprintf - #endif +#ifndef _WIN32 +# include +# include +# include +# include +# include +# include +# include +# include +# include #else -# error "UNRECOGNISED PLATFORM") +# ifdef ERROR +# undef ERROR +# endif +# include +# ifndef vsnprintf +# define vsnprintf _vsnprintf +# endif #endif #include @@ -45,7 +40,6 @@ #include #include #include -#include using namespace std; @@ -59,7 +53,7 @@ using namespace std; namespace netstream { -#ifdef WIN32 +#ifdef _WIN32 bool NetStreamSocket::init_windows_sockets_ = true; bool NetStreamSocket::windows_sockets_initialized_ = false; int NetStreamSocket::instance_count_ = 0; @@ -96,7 +90,7 @@ namespace netstream NetStreamSocket:: init() { -#ifdef WIN32 +#ifdef _WIN32 instance_count_++; if( init_windows_sockets_ && !windows_sockets_initialized_ ) @@ -115,14 +109,14 @@ namespace netstream { // Close first an existing client connection ... close(); -#ifdef WIN32 +#ifdef _WIN32 instance_count_--; #endif // ... then the server socket if( server_socket_ >= 0 ) { -#ifdef WIN32 +#ifdef _WIN32 ::closesocket( server_socket_ ); #else ::close( server_socket_ ); @@ -130,7 +124,7 @@ namespace netstream server_socket_ = -1; } -#ifdef WIN32 +#ifdef _WIN32 if( server_socket_ == -1 && socket_ == -1 && init_windows_sockets_ && instance_count_ == 0 ) WSACleanup(); @@ -144,7 +138,7 @@ namespace netstream BailOnNetStreamSocketError( std::string context) const { -#ifdef WIN32 +#ifdef _WIN32 int e = WSAGetLastError(); std::string msg = GetWinsockErrorString( e ); #else @@ -222,7 +216,7 @@ namespace netstream return; struct sockaddr_in client_addr; -#ifdef WIN32 +#ifdef _WIN32 int addrlen = sizeof(client_addr); #else socklen_t addrlen = sizeof(client_addr); @@ -241,7 +235,7 @@ namespace netstream { int reuseaddr = 1; - #ifdef WIN32 + #ifdef _WIN32 //setsockopt(server_socket_, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseaddr, sizeof(reuseaddr)); // No address reuse in Windows!!! #else @@ -286,7 +280,7 @@ namespace netstream if( server_socket_ > 0 ) { -#ifdef WIN32 +#ifdef _WIN32 ULONG NonBlock = blocking_ ? 0 : 1; if (ioctlsocket(server_socket_, FIONBIO, &NonBlock) == SOCKET_ERROR) BailOnNetStreamSocketError("netstream::NetStreamSocket::set_blocking() Unable to initialize non blocking I/O"); @@ -342,7 +336,7 @@ namespace netstream // Close client-connection if( socket_ >= 0 ) { -#ifdef WIN32 +#ifdef _WIN32 ::closesocket( socket_ ); #else ::close( socket_ ); @@ -381,7 +375,7 @@ namespace netstream unsigned char const *buf_ptr = buf; while( numbytes > 0 ) { -#ifdef WIN32 +#ifdef _WIN32 int n = ::send( socket_, (const char*)buf_ptr, static_cast(numbytes), 0 ); #else int n = ::send( socket_, buf_ptr, numbytes, 0 ); @@ -550,7 +544,7 @@ namespace netstream } -#ifdef WIN32 +#ifdef _WIN32 // ---------------------------------------------------------------------- std::string NetStreamSocket:: @@ -615,15 +609,8 @@ namespace netstream return "unknown"; } -#endif // WIN32 +#endif // _WIN32 } // namespace tcpip - -/*----------------------------------------------------------------------- -* Source $Source: $ -* Version $Revision: 385 $ -* Date $Date: 2010-01-13 16:10:20 +0100 (Wed, 13 Jan 2010) $ -*----------------------------------------------------------------------- -* $Log: $ -*-----------------------------------------------------------------------*/ +// vim: ts=4:sw=4:noet diff --git a/graphstream/gs-netstream/c++/src/netstream-socket.h b/graphstream/gs-netstream/c++/src/netstream-socket.h index f2993c716..ea78ead7a 100644 --- a/graphstream/gs-netstream/c++/src/netstream-socket.h +++ b/graphstream/gs-netstream/c++/src/netstream-socket.h @@ -26,8 +26,8 @@ #endif // Disable exception handling warnings -#ifdef WIN32 - #pragma warning( disable : 4290 ) +#ifdef _WIN32 +# pragma warning( disable : 4290 ) #endif #include @@ -97,7 +97,7 @@ namespace netstream private: void init(); void BailOnNetStreamSocketError( std::string ) const ; -#ifdef WIN32 +#ifdef _WIN32 std::string GetWinsockErrorString(int err) const; #endif bool atoaddr(std::string, struct in_addr& addr); @@ -110,7 +110,7 @@ namespace netstream bool blocking_; bool verbose_; -#ifdef WIN32 +#ifdef _WIN32 static bool init_windows_sockets_; static bool windows_sockets_initialized_; static int instance_count_; @@ -121,11 +121,4 @@ namespace netstream #endif // BUILD_TCPIP - -/*----------------------------------------------------------------------- -* Source $Source: $ -* Version $Revision: 197 $ -* Date $Date: 2008-04-29 17:40:51 +0200 (Tue, 29 Apr 2008) $ -*----------------------------------------------------------------------- -* $Log:$ -*-----------------------------------------------------------------------*/ +// vim: ts=4:sw=4:noet From 42b0cdc1ba44610b73507fa1690c9c76fc63068a Mon Sep 17 00:00:00 2001 From: John Pye Date: Sat, 15 Jan 2022 22:00:40 +1100 Subject: [PATCH 10/12] add 'long long' in graphstream (needed on MSYS2, apparently) --- graphstream/gs-netstream/c++/src/netstream-sender.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/graphstream/gs-netstream/c++/src/netstream-sender.h b/graphstream/gs-netstream/c++/src/netstream-sender.h index aabf36630..157c85099 100644 --- a/graphstream/gs-netstream/c++/src/netstream-sender.h +++ b/graphstream/gs-netstream/c++/src/netstream-sender.h @@ -61,6 +61,7 @@ class NetStreamSender{ int _getType(bool object); int _getType(int object); int _getType(long object); + int _getType(long long object); int _getType(float object); int _getType(double object); int _getType(const string & object); @@ -83,6 +84,7 @@ class NetStreamSender{ void _encode(NetStreamStorage & event, bool value); void _encode(NetStreamStorage & event, int value); void _encode(NetStreamStorage & event, long value); + void _encode(NetStreamStorage & event, long long value); void _encode(NetStreamStorage & event, float value); void _encode(NetStreamStorage & event, double value); void _encode(NetStreamStorage & event, const string & value); @@ -91,6 +93,7 @@ class NetStreamSender{ void _encode(NetStreamStorage & event, const vector & value); void _encode(NetStreamStorage & event, const vector & value); void _encode(NetStreamStorage & event, const vector & value); + void _encode(NetStreamStorage & event, const vector & value); void _encode(NetStreamStorage & event, const vector & value); void _encode(NetStreamStorage & event, const vector & value); @@ -211,4 +214,4 @@ class NetStreamSender{ }; } -#endif \ No newline at end of file +#endif From 3048e68c2d7557b143eed5021357f1ace59cebe5 Mon Sep 17 00:00:00 2001 From: John Pye Date: Sun, 16 Jan 2022 00:33:57 +1100 Subject: [PATCH 11/12] use int64_t instead of long bc of windows sizes --- .../gs-netstream/c++/src/netstream-sender.cpp | 37 ++++++++++++------- .../gs-netstream/c++/src/netstream-sender.h | 11 ++---- .../c++/src/netstream-storage.cpp | 6 +-- .../gs-netstream/c++/src/netstream-storage.h | 4 +- 4 files changed, 32 insertions(+), 26 deletions(-) diff --git a/graphstream/gs-netstream/c++/src/netstream-sender.cpp b/graphstream/gs-netstream/c++/src/netstream-sender.cpp index cd8cc614c..bc997be63 100644 --- a/graphstream/gs-netstream/c++/src/netstream-sender.cpp +++ b/graphstream/gs-netstream/c++/src/netstream-sender.cpp @@ -74,21 +74,25 @@ int NetStreamSender::_getType(char object){ } int NetStreamSender::_getType(bool object){ -if(debug){ - cerr<<" NetStreamSender: _getType : bool"< & object){ -if(debug){ - cerr<<" NetStreamSender: _getType : long*"< & object){ + if(debug){ + cerr<<" NetStreamSender: _getType : long*"< & object){ if(debug){ cerr<<" NetStreamSender: _getType : float*"< & valu event.writeVarint((*i)); } } -void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ +void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ event.writeUnsignedVarint(value.size()); - for(vector::const_iterator i = value.begin(); i != value.end(); i++){ + for(vector::const_iterator i = value.begin(); i != value.end(); i++){ event.writeVarint((*i)); } } + void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ event.writeUnsignedVarint(value.size()); for(vector::const_iterator i = value.begin(); i != value.end(); i++){ diff --git a/graphstream/gs-netstream/c++/src/netstream-sender.h b/graphstream/gs-netstream/c++/src/netstream-sender.h index 157c85099..8814818a3 100644 --- a/graphstream/gs-netstream/c++/src/netstream-sender.h +++ b/graphstream/gs-netstream/c++/src/netstream-sender.h @@ -60,15 +60,14 @@ class NetStreamSender{ int _getType(char object); int _getType(bool object); int _getType(int object); - int _getType(long object); - int _getType(long long object); + int _getType(int64_t object); int _getType(float object); int _getType(double object); int _getType(const string & object); int _getType( const vector & object); int _getType( const vector & object); int _getType( const vector & object); - int _getType( const vector & object); + int _getType( const vector & object); int _getType( const vector & object); int _getType( const vector & object); @@ -83,8 +82,7 @@ class NetStreamSender{ void _encode(NetStreamStorage & event, char value); void _encode(NetStreamStorage & event, bool value); void _encode(NetStreamStorage & event, int value); - void _encode(NetStreamStorage & event, long value); - void _encode(NetStreamStorage & event, long long value); + void _encode(NetStreamStorage & event, int64_t value); void _encode(NetStreamStorage & event, float value); void _encode(NetStreamStorage & event, double value); void _encode(NetStreamStorage & event, const string & value); @@ -92,8 +90,7 @@ class NetStreamSender{ void _encode(NetStreamStorage & event, const vector & value); void _encode(NetStreamStorage & event, const vector & value); void _encode(NetStreamStorage & event, const vector & value); - void _encode(NetStreamStorage & event, const vector & value); - void _encode(NetStreamStorage & event, const vector & value); + void _encode(NetStreamStorage & event, const vector & value); void _encode(NetStreamStorage & event, const vector & value); void _encode(NetStreamStorage & event, const vector & value); diff --git a/graphstream/gs-netstream/c++/src/netstream-storage.cpp b/graphstream/gs-netstream/c++/src/netstream-storage.cpp index 46934d96b..8c18cac37 100644 --- a/graphstream/gs-netstream/c++/src/netstream-storage.cpp +++ b/graphstream/gs-netstream/c++/src/netstream-storage.cpp @@ -359,9 +359,9 @@ namespace netstream * * @return the unspoiled integer value (between -??? and ???) */ - long NetStreamStorage::readLong() + int64_t NetStreamStorage::readLong() { - long value = 0L; + int64_t value = 0L; unsigned char *p_value = reinterpret_cast(&value); readByEndianess(p_value, 8); return value; @@ -369,7 +369,7 @@ namespace netstream // ---------------------------------------------------------------------- - void NetStreamStorage::writeLong( long value ) + void NetStreamStorage::writeLong( int64_t value ) { unsigned char *p_value = reinterpret_cast(&value); writeByEndianess(p_value, 8); diff --git a/graphstream/gs-netstream/c++/src/netstream-storage.h b/graphstream/gs-netstream/c++/src/netstream-storage.h index c20fcbaa3..90fbc6d7a 100644 --- a/graphstream/gs-netstream/c++/src/netstream-storage.h +++ b/graphstream/gs-netstream/c++/src/netstream-storage.h @@ -96,8 +96,8 @@ class NetStreamStorage virtual int readInt() ; virtual void writeInt(int) ; - virtual long readLong() ; - virtual void writeLong(long) ; + virtual int64_t readLong() ; + virtual void writeLong(int64_t) ; virtual float readFloat() ; virtual void writeFloat( float ) ; From 70fce61a7c41bf85d5f910d2b571fad12a835fe6 Mon Sep 17 00:00:00 2001 From: John Pye Date: Sun, 16 Jan 2022 13:45:31 +1100 Subject: [PATCH 12/12] updating graphstream windows long. --- .../c++/src/netstream-constants.h | 20 +++++ .../gs-netstream/c++/src/netstream-sender.cpp | 89 +++++++++++++++---- .../gs-netstream/c++/src/netstream-sender.h | 37 ++++++-- .../c++/src/netstream-storage.cpp | 37 +++++--- .../gs-netstream/c++/src/netstream-storage.h | 3 + 5 files changed, 154 insertions(+), 32 deletions(-) diff --git a/graphstream/gs-netstream/c++/src/netstream-constants.h b/graphstream/gs-netstream/c++/src/netstream-constants.h index 620d6bf41..5faa18dac 100644 --- a/graphstream/gs-netstream/c++/src/netstream-constants.h +++ b/graphstream/gs-netstream/c++/src/netstream-constants.h @@ -154,16 +154,19 @@ namespace netstream{ * An array of bytes. Followed by first, a 16-bits integer for the number * of integers and then, a list of signed bytes. */ + const unsigned char TYPE_BYTE_ARRAY=0x53; /** * Followed by an 16-bit signed integer (a short) */ const unsigned char TYPE_SHORT=0x54; + /** * An array of shorts. Followed by first, a 16-bits integer for the number * of integers and then, a list of 16-bit signed shorts */ const unsigned char TYPE_SHORT_ARRAY=0x55; + /** * Followed by an 32-bit signed integer */ @@ -173,6 +176,7 @@ namespace netstream{ * of integers and then, a list of 32-bit signed integers */ const unsigned char TYPE_INT_ARRAY=0x57; + /** * Followed by an 64-bit signed integer */ @@ -182,6 +186,9 @@ namespace netstream{ * longs and then, a list of 62-bit signed integers */ const unsigned char TYPE_LONG_ARRAY=0x59; + +/** NOTE: see also LONGLONG below, out of order */ + /** * Followed by a single precision 32-bits floating point number */ @@ -219,6 +226,19 @@ namespace netstream{ */ const unsigned char TYPE_ARRAY=0x60; +/** + * Followed by an 64-bit signed integer + */ + const unsigned char TYPE_LONGLONG=0x61; +/** + * An array of longs. Followed by first, a 16-bits integer for the number of + * longs and then, a list of 62-bit signed integers + */ + const unsigned char TYPE_LONGLONG_ARRAY=0x62; + + + + }// end netstream namespace #endif diff --git a/graphstream/gs-netstream/c++/src/netstream-sender.cpp b/graphstream/gs-netstream/c++/src/netstream-sender.cpp index cd8cc614c..2cba00c8c 100644 --- a/graphstream/gs-netstream/c++/src/netstream-sender.cpp +++ b/graphstream/gs-netstream/c++/src/netstream-sender.cpp @@ -74,21 +74,40 @@ int NetStreamSender::_getType(char object){ } int NetStreamSender::_getType(bool object){ + if(debug){ + cerr<<" NetStreamSender: _getType : bool"< & object){ + if(debug){ + cerr<<" NetStreamSender: _getType : short*"< & object){ -if(debug){ - cerr<<" NetStreamSender: _getType : int*"< & object){ -if(debug){ - cerr<<" NetStreamSender: _getType : long*"< & object){ + if(debug){ + cerr<<" NetStreamSender: _getType : long long*" < & object){ if(debug){ cerr<<" NetStreamSender: _getType : float*"< & val event.writeByte((*i)); } } +void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ + event.writeUnsignedVarint(value.size()); + for(vector::const_iterator i = value.begin(); i != value.end(); i++){ + event.writeVarint((*i)); + } +} void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ event.writeUnsignedVarint(value.size()); for(vector::const_iterator i = value.begin(); i != value.end(); i++){ event.writeVarint((*i)); - } + } } void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ event.writeUnsignedVarint(value.size()); @@ -185,6 +237,13 @@ void NetStreamSender::_encode(NetStreamStorage & event, const vector & val event.writeVarint((*i)); } } +void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ + event.writeUnsignedVarint(value.size()); + for(vector::const_iterator i = value.begin(); i != value.end(); i++){ + event.writeVarint((*i)); + } +} + void NetStreamSender::_encode(NetStreamStorage & event, const vector & value){ event.writeUnsignedVarint(value.size()); for(vector::const_iterator i = value.begin(); i != value.end(); i++){ diff --git a/graphstream/gs-netstream/c++/src/netstream-sender.h b/graphstream/gs-netstream/c++/src/netstream-sender.h index 157c85099..5dfae8d70 100644 --- a/graphstream/gs-netstream/c++/src/netstream-sender.h +++ b/graphstream/gs-netstream/c++/src/netstream-sender.h @@ -14,17 +14,35 @@ #define NETSTREAM_SENDER_H - - #ifndef WIN32 #include #else #include #endif +#include +#define STATIC_ASSERT(condition) typedef char __static_assert##__LINE__[(condition)?1:-1] #include +#ifdef _WIN32 +STATIC_ASSERT(sizeof(short)==sizeof(int16_t)); +STATIC_ASSERT(sizeof(int)==sizeof(int32_t)); +STATIC_ASSERT(sizeof(long)==sizeof(int32_t)); +STATIC_ASSERT(sizeof(long long)==sizeof(int64_t)); +STATIC_ASSERT(sizeof(void*)==sizeof(int64_t)); +#define GS_LONG long long +#else +STATIC_ASSERT(sizeof(short)==sizeof(int16_t)); +STATIC_ASSERT(sizeof(int)==sizeof(int32_t)); +STATIC_ASSERT(sizeof(long)==sizeof(int64_t)); +STATIC_ASSERT(sizeof(long long)==sizeof(int64_t)); +STATIC_ASSERT(sizeof(void*)==sizeof(int64_t)); +#define GS_LONG long +#endif + +#define GS_STRINGIFY(VAR) #VAR + #include "netstream-storage.h" #include "netstream-socket.h" #include "netstream-constants.h" @@ -59,16 +77,19 @@ class NetStreamSender{ int _getType(char object); int _getType(bool object); + int _getType(short object); int _getType(int object); int _getType(long object); - int _getType(long long object); + int _getType(long long object); int _getType(float object); int _getType(double object); int _getType(const string & object); int _getType( const vector & object); int _getType( const vector & object); + int _getType( const vector & object); int _getType( const vector & object); int _getType( const vector & object); + int _getType( const vector & object); int _getType( const vector & object); int _getType( const vector & object); @@ -82,6 +103,7 @@ class NetStreamSender{ } void _encode(NetStreamStorage & event, char value); void _encode(NetStreamStorage & event, bool value); + void _encode(NetStreamStorage & event, short value); void _encode(NetStreamStorage & event, int value); void _encode(NetStreamStorage & event, long value); void _encode(NetStreamStorage & event, long long value); @@ -91,11 +113,12 @@ class NetStreamSender{ void _encode(NetStreamStorage & event, const vector & value); void _encode(NetStreamStorage & event, const vector & value); + void _encode(NetStreamStorage & event, const vector & value); void _encode(NetStreamStorage & event, const vector & value); - void _encode(NetStreamStorage & event, const vector & value); - void _encode(NetStreamStorage & event, const vector & value); - void _encode(NetStreamStorage & event, const vector & value); - void _encode(NetStreamStorage & event, const vector & value); + void _encode(NetStreamStorage & event, const vector & value); + void _encode(NetStreamStorage & event, const vector & value); + void _encode(NetStreamStorage & event, const vector & value); + void _encode(NetStreamStorage & event, const vector & value); void _sendEvent(NetStreamStorage &); diff --git a/graphstream/gs-netstream/c++/src/netstream-storage.cpp b/graphstream/gs-netstream/c++/src/netstream-storage.cpp index 46934d96b..5cac5c7e8 100644 --- a/graphstream/gs-netstream/c++/src/netstream-storage.cpp +++ b/graphstream/gs-netstream/c++/src/netstream-storage.cpp @@ -114,21 +114,21 @@ namespace netstream size_t NetStreamStorage::varintSize(uint_fast64_t data){ // 7 bits -> 127 - if(data < (1L << 7)){return 1;} + if(data < (1LL << 7)){return 1;} // 14 bits -> 16383 - if(data < (1L << 14)){return 2;} + if(data < (1LL << 14)){return 2;} // 21 bits -> 2097151 - if(data < (1L << 21)){return 3;} + if(data < (1LL << 21)){return 3;} // 28 bits -> 268435455 - if(data < (1L << 28)){return 4;} + if(data < (1LL << 28)){return 4;} // 35 bits -> 34359738367 - if(data < (1L << 35)){return 5;} + if(data < (1LL << 35)){return 5;} // 42 bits -> 4398046511103 - if(data < (1L << 42)){return 6;} + if(data < (1LL << 42)){return 6;} // 49 bits -> 562949953421311 - if(data < (1L << 49)){return 7;} + if(data < (1LL << 49)){return 7;} // 56 bits -> 72057594037927935 - if(data < (1L << 56)){return 8;} + if(data < (1LL << 56)){return 8;} return 9; } @@ -363,7 +363,7 @@ namespace netstream { long value = 0L; unsigned char *p_value = reinterpret_cast(&value); - readByEndianess(p_value, 8); + readByEndianess(p_value, sizeof(long)); return value; } @@ -372,8 +372,25 @@ namespace netstream void NetStreamStorage::writeLong( long value ) { unsigned char *p_value = reinterpret_cast(&value); - writeByEndianess(p_value, 8); + writeByEndianess(p_value, sizeof(long)); + } + + + + long long NetStreamStorage::readLongLong() + { + long long value = 0L; + unsigned char *p_value = reinterpret_cast(&value); + readByEndianess(p_value, sizeof(long long)); + return value; } + + void NetStreamStorage::writeLongLong( long long value ) + { + unsigned char *p_value = reinterpret_cast(&value); + writeByEndianess(p_value, sizeof(long long)); + } + // ---------------------------------------------------------------------- diff --git a/graphstream/gs-netstream/c++/src/netstream-storage.h b/graphstream/gs-netstream/c++/src/netstream-storage.h index c20fcbaa3..4a49d80b7 100644 --- a/graphstream/gs-netstream/c++/src/netstream-storage.h +++ b/graphstream/gs-netstream/c++/src/netstream-storage.h @@ -99,6 +99,9 @@ class NetStreamStorage virtual long readLong() ; virtual void writeLong(long) ; + virtual long long readLongLong() ; + virtual void writeLongLong(long long) ; + virtual float readFloat() ; virtual void writeFloat( float ) ;