Merge branch 'unstable' into minor-typos
This commit is contained in:
commit
fb1f4f4e7e
26
CONTRIBUTING
26
CONTRIBUTING
@ -8,13 +8,13 @@ each source file that you contribute.
|
||||
# IMPORTANT: HOW TO USE REDIS GITHUB ISSUES
|
||||
|
||||
* Github issues SHOULD ONLY BE USED to report bugs, and for DETAILED feature
|
||||
requests. Everything else belongs to the Redis Google Group.
|
||||
requests. Everything else belongs to the Redis Google Group:
|
||||
|
||||
https://groups.google.com/forum/m/#!forum/Redis-db
|
||||
|
||||
PLEASE DO NOT POST GENERAL QUESTIONS that are not about bugs or suspected
|
||||
bugs in the Github issues system. We'll be very happy to help you and provide
|
||||
all the support at the Reddit sub:
|
||||
|
||||
http://reddit.com/r/redis
|
||||
all the support in the mailing list.
|
||||
|
||||
There is also an active community of Redis users at Stack Overflow:
|
||||
|
||||
@ -22,7 +22,12 @@ each source file that you contribute.
|
||||
|
||||
# How to provide a patch for a new feature
|
||||
|
||||
1. If it is a major feature or a semantical change, please post it as a new submission in r/redis on Reddit at http://reddit.com/r/redis. Try to be passionate about why the feature is needed, make users upvote your proposal to gain traction and so forth. Read feedbacks about the community. But in this first step **please don't write code yet**.
|
||||
1. If it is a major feature or a semantical change, please don't start coding
|
||||
straight away: if your feature is not a conceptual fit you'll lose a lot of
|
||||
time writing the code without any reason. Start by posting in the mailing list
|
||||
and creating an issue at Github with the description of, exactly, what you want
|
||||
to accomplish and why. Use cases are important for features to be accepted.
|
||||
Here you'll see if there is consensus about your idea.
|
||||
|
||||
2. If in step 1 you get an acknowledgment from the project leaders, use the
|
||||
following procedure to submit a patch:
|
||||
@ -30,9 +35,16 @@ each source file that you contribute.
|
||||
a. Fork Redis on github ( http://help.github.com/fork-a-repo/ )
|
||||
b. Create a topic branch (git checkout -b my_branch)
|
||||
c. Push to your branch (git push origin my_branch)
|
||||
d. Initiate a pull request on github ( http://help.github.com/send-pull-requests/ )
|
||||
d. Initiate a pull request on github ( https://help.github.com/articles/creating-a-pull-request/ )
|
||||
e. Done :)
|
||||
|
||||
For minor fixes just open a pull request on Github.
|
||||
3. Keep in mind that we are very overloaded, so issues and PRs sometimes wait
|
||||
for a *very* long time. However this is not lack of interest, as the project
|
||||
gets more and more users, we find ourselves in a constant need to prioritize
|
||||
certain issues/PRs over others. If you think your issue/PR is very important
|
||||
try to popularize it, have other users commenting and sharing their point of
|
||||
view and so forth. This helps.
|
||||
|
||||
4. For minor fixes just open a pull request on Github.
|
||||
|
||||
Thanks!
|
||||
|
53
MANIFESTO
53
MANIFESTO
@ -34,7 +34,21 @@ Redis Manifesto
|
||||
so that the complexity is obvious and more complex operations can be
|
||||
performed as the sum of the basic operations.
|
||||
|
||||
4 - Code is like a poem; it's not just something we write to reach some
|
||||
4 - We believe in code efficiency. Computers get faster and faster, yet we
|
||||
believe that abusing computing capabilities is not wise: the amount of
|
||||
operations you can do for a given amount of energy remains anyway a
|
||||
significant parameter: it allows to do more with less computers and, at
|
||||
the same time, having a smaller environmental impact. Similarly Redis is
|
||||
able to "scale down" to smaller devices. It is perfectly usable in a
|
||||
Raspberry Pi and other small ARM based computers. Faster code having
|
||||
just the layers of abstractions that are really needed will also result,
|
||||
often, in more predictable performances. We think likewise about memory
|
||||
usage, one of the fundamental goals of the Redis project is to
|
||||
incrementally build more and more memory efficient data structures, so that
|
||||
problems that were not approachable in RAM in the past will be perfectly
|
||||
fine to handle in the future.
|
||||
|
||||
5 - Code is like a poem; it's not just something we write to reach some
|
||||
practical result. Sometimes people that are far from the Redis philosophy
|
||||
suggest using other code written by other authors (frequently in other
|
||||
languages) in order to implement something Redis currently lacks. But to us
|
||||
@ -45,23 +59,48 @@ Redis Manifesto
|
||||
when needed. At the same time, when writing the Redis story we're trying to
|
||||
write smaller stories that will fit in to other code.
|
||||
|
||||
5 - We're against complexity. We believe designing systems is a fight against
|
||||
6 - We're against complexity. We believe designing systems is a fight against
|
||||
complexity. We'll accept to fight the complexity when it's worthwhile but
|
||||
we'll try hard to recognize when a small feature is not worth 1000s of lines
|
||||
of code. Most of the time the best way to fight complexity is by not
|
||||
creating it at all.
|
||||
creating it at all. Complexity is also a form of lock-in: code that is
|
||||
very hard to understand cannot be modified by users in an independent way
|
||||
regardless of the license. One of the main Redis goals is to remain
|
||||
understandable, enough for a single programmer to have a clear idea of how
|
||||
it works in detail just reading the source code for a couple of weeks.
|
||||
|
||||
6 - Two levels of API. The Redis API has two levels: 1) a subset of the API fits
|
||||
7 - Threading is not a silver bullet. Instead of making Redis threaded we
|
||||
believe on the idea of an efficient (mostly) single threaded Redis core.
|
||||
Multiple of such cores, that may run in the same computer or may run
|
||||
in multiple computers, are abstracted away as a single big system by
|
||||
higher order protocols and features: Redis Cluster and the upcoming
|
||||
Redis Proxy are our main goals. A shared nothing approach is not just
|
||||
much simpler (see the previous point in this document), is also optimal
|
||||
in NUMA systems. In the specific case of Redis it allows for each instance
|
||||
to have a more limited amount of data, making the Redis persist-by-fork
|
||||
approach more sounding. In the future we may explore parallelism only for
|
||||
I/O, which is the low hanging fruit: minimal complexity could provide an
|
||||
improved single process experience.
|
||||
|
||||
8 - Two levels of API. The Redis API has two levels: 1) a subset of the API fits
|
||||
naturally into a distributed version of Redis and 2) a more complex API that
|
||||
supports multi-key operations. Both are useful if used judiciously but
|
||||
there's no way to make the more complex multi-keys API distributed in an
|
||||
opaque way without violating our other principles. We don't want to provide
|
||||
the illusion of something that will work magically when actually it can't in
|
||||
all cases. Instead we'll provide commands to quickly migrate keys from one
|
||||
instance to another to perform multi-key operations and expose the tradeoffs
|
||||
to the user.
|
||||
instance to another to perform multi-key operations and expose the
|
||||
trade-offs to the user.
|
||||
|
||||
7 - We optimize for joy. We believe writing code is a lot of hard work, and the
|
||||
9 - We optimize for joy. We believe writing code is a lot of hard work, and the
|
||||
only way it can be worth is by enjoying it. When there is no longer joy in
|
||||
writing code, the best thing to do is stop. To prevent this, we'll avoid
|
||||
taking paths that will make Redis less of a joy to develop.
|
||||
|
||||
10 - All the above points are put together in what we call opportunistic
|
||||
programming: trying to get the most for the user with minimal increases
|
||||
in complexity (hanging fruits). Solve 95% of the problem with 5% of the
|
||||
code when it is acceptable. Avoid a fixed schedule but follow the flow of
|
||||
user requests, inspiration, Redis internal readiness for certain features
|
||||
(sometimes many past changes reach a critical point making a previously
|
||||
complex feature very easy to obtain).
|
||||
|
24
README.md
24
README.md
@ -119,7 +119,7 @@ parameter (the path of the configuration file):
|
||||
It is possible to alter the Redis configuration by passing parameters directly
|
||||
as options using the command line. Examples:
|
||||
|
||||
% ./redis-server --port 9999 --slaveof 127.0.0.1 6379
|
||||
% ./redis-server --port 9999 --replicaof 127.0.0.1 6379
|
||||
% ./redis-server /etc/redis/6379.conf --loglevel debug
|
||||
|
||||
All the options in redis.conf are also supported as options using the command
|
||||
@ -166,6 +166,8 @@ for Ubuntu and Debian systems:
|
||||
% cd utils
|
||||
% ./install_server.sh
|
||||
|
||||
_Note_: `install_server.sh` will not work on Mac OSX; it is built for Linux only.
|
||||
|
||||
The script will ask you a few questions and will setup everything you need
|
||||
to run Redis properly as a background daemon that will start again on
|
||||
system reboots.
|
||||
@ -216,7 +218,7 @@ Inside the root are the following important directories:
|
||||
|
||||
* `src`: contains the Redis implementation, written in C.
|
||||
* `tests`: contains the unit tests, implemented in Tcl.
|
||||
* `deps`: contains libraries Redis uses. Everything needed to compile Redis is inside this directory; your system just needs to provide `libc`, a POSIX compatible interface and a C compiler. Notably `deps` contains a copy of `jemalloc`, which is the default allocator of Redis under Linux. Note that under `deps` there are also things which started with the Redis project, but for which the main repository is not `anitrez/redis`. An exception to this rule is `deps/geohash-int` which is the low level geocoding library used by Redis: it originated from a different project, but at this point it diverged so much that it is developed as a separated entity directly inside the Redis repository.
|
||||
* `deps`: contains libraries Redis uses. Everything needed to compile Redis is inside this directory; your system just needs to provide `libc`, a POSIX compatible interface and a C compiler. Notably `deps` contains a copy of `jemalloc`, which is the default allocator of Redis under Linux. Note that under `deps` there are also things which started with the Redis project, but for which the main repository is not `antirez/redis`.
|
||||
|
||||
There are a few more directories but they are not very important for our goals
|
||||
here. We'll focus mostly on `src`, where the Redis implementation is contained,
|
||||
@ -227,7 +229,7 @@ of complexity incrementally.
|
||||
Note: lately Redis was refactored quite a bit. Function names and file
|
||||
names have been changed, so you may find that this documentation reflects the
|
||||
`unstable` branch more closely. For instance in Redis 3.0 the `server.c`
|
||||
and `server.h` files were named to `redis.c` and `redis.h`. However the overall
|
||||
and `server.h` files were named `redis.c` and `redis.h`. However the overall
|
||||
structure is the same. Keep in mind that all the new developments and pull
|
||||
requests should be performed against the `unstable` branch.
|
||||
|
||||
@ -245,7 +247,7 @@ A few important fields in this structure are:
|
||||
* `server.db` is an array of Redis databases, where data is stored.
|
||||
* `server.commands` is the command table.
|
||||
* `server.clients` is a linked list of clients connected to the server.
|
||||
* `server.master` is a special client, the master, if the instance is a slave.
|
||||
* `server.master` is a special client, the master, if the instance is a replica.
|
||||
|
||||
There are tons of other fields. Most fields are commented directly inside
|
||||
the structure definition.
|
||||
@ -323,7 +325,7 @@ Inside server.c you can find code that handles other vital things of the Redis s
|
||||
networking.c
|
||||
---
|
||||
|
||||
This file defines all the I/O functions with clients, masters and slaves
|
||||
This file defines all the I/O functions with clients, masters and replicas
|
||||
(which in Redis are just special clients):
|
||||
|
||||
* `createClient()` allocates and initializes a new client.
|
||||
@ -390,21 +392,21 @@ replication.c
|
||||
|
||||
This is one of the most complex files inside Redis, it is recommended to
|
||||
approach it only after getting a bit familiar with the rest of the code base.
|
||||
In this file there is the implementation of both the master and slave role
|
||||
In this file there is the implementation of both the master and replica role
|
||||
of Redis.
|
||||
|
||||
One of the most important functions inside this file is `replicationFeedSlaves()` that writes commands to the clients representing slave instances connected
|
||||
to our master, so that the slaves can get the writes performed by the clients:
|
||||
One of the most important functions inside this file is `replicationFeedSlaves()` that writes commands to the clients representing replica instances connected
|
||||
to our master, so that the replicas can get the writes performed by the clients:
|
||||
this way their data set will remain synchronized with the one in the master.
|
||||
|
||||
This file also implements both the `SYNC` and `PSYNC` commands that are
|
||||
used in order to perform the first synchronization between masters and
|
||||
slaves, or to continue the replication after a disconnection.
|
||||
replicas, or to continue the replication after a disconnection.
|
||||
|
||||
Other C files
|
||||
---
|
||||
|
||||
* `t_hash.c`, `t_list.c`, `t_set.c`, `t_string.c` and `t_zset.c` contains the implementation of the Redis data types. They implement both an API to access a given data type, and the client commands implementations for these data types.
|
||||
* `t_hash.c`, `t_list.c`, `t_set.c`, `t_string.c`, `t_zset.c` and `t_stream.c` contains the implementation of the Redis data types. They implement both an API to access a given data type, and the client commands implementations for these data types.
|
||||
* `ae.c` implements the Redis event loop, it's a self contained library which is simple to read and understand.
|
||||
* `sds.c` is the Redis string library, check http://github.com/antirez/sds for more information.
|
||||
* `anet.c` is a library to use POSIX networking in a simpler way compared to the raw interface exposed by the kernel.
|
||||
@ -435,7 +437,7 @@ top comment inside `server.c`.
|
||||
After the command operates in some way, it returns a reply to the client,
|
||||
usually using `addReply()` or a similar function defined inside `networking.c`.
|
||||
|
||||
There are tons of commands implementations inside th Redis source code
|
||||
There are tons of commands implementations inside the Redis source code
|
||||
that can serve as examples of actual commands implementations. To write
|
||||
a few toy commands can be a good exercise to familiarize with the code base.
|
||||
|
||||
|
106
TLS.md
Normal file
106
TLS.md
Normal file
@ -0,0 +1,106 @@
|
||||
TLS Support -- Work In Progress
|
||||
===============================
|
||||
|
||||
This is a brief note to capture current thoughts/ideas and track pending action
|
||||
items.
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
### Building
|
||||
|
||||
To build with TLS support you'll need OpenSSL development libraries (e.g.
|
||||
libssl-dev on Debian/Ubuntu).
|
||||
|
||||
Run `make BUILD_TLS=yes`.
|
||||
|
||||
### Tests
|
||||
|
||||
To run Redis test suite with TLS, you'll need TLS support for TCL (i.e.
|
||||
`tcl-tls` package on Debian/Ubuntu).
|
||||
|
||||
1. Run `./utils/gen-test-certs.sh` to generate a root CA and a server
|
||||
certificate.
|
||||
|
||||
2. Run `./runtest --tls` or `./runtest-cluster --tls` to run Redis and Redis
|
||||
Cluster tests in TLS mode.
|
||||
|
||||
### Running manually
|
||||
|
||||
To manually run a Redis server with TLS mode (assuming `gen-test-certs.sh` was
|
||||
invoked so sample certificates/keys are available):
|
||||
|
||||
./src/redis-server --tls-port 6379 --port 0 \
|
||||
--tls-cert-file ./tests/tls/redis.crt \
|
||||
--tls-key-file ./tests/tls/redis.key \
|
||||
--tls-ca-cert-file ./tests/tls/ca.crt
|
||||
|
||||
To connect to this Redis server with `redis-cli`:
|
||||
|
||||
./src/redis-cli --tls \
|
||||
--cert ./tests/tls/redis.crt \
|
||||
--key ./tests/tls/redis.key \
|
||||
--cacert ./tests/tls/ca.crt
|
||||
|
||||
This will disable TCP and enable TLS on port 6379. It's also possible to have
|
||||
both TCP and TLS available, but you'll need to assign different ports.
|
||||
|
||||
To make a Replica connect to the master using TLS, use `--tls-replication yes`,
|
||||
and to make Redis Cluster use TLS across nodes use `--tls-cluster yes`.
|
||||
|
||||
Connections
|
||||
-----------
|
||||
|
||||
All socket operations now go through a connection abstraction layer that hides
|
||||
I/O and read/write event handling from the caller.
|
||||
|
||||
**Multi-threading I/O is not currently supported for TLS**, as a TLS connection
|
||||
needs to do its own manipulation of AE events which is not thread safe. The
|
||||
solution is probably to manage independent AE loops for I/O threads and longer
|
||||
term association of connections with threads. This may potentially improve
|
||||
overall performance as well.
|
||||
|
||||
Sync IO for TLS is currently implemented in a hackish way, i.e. making the
|
||||
socket blocking and configuring socket-level timeout. This means the timeout
|
||||
value may not be so accurate, and there would be a lot of syscall overhead.
|
||||
However I believe that getting rid of syncio completely in favor of pure async
|
||||
work is probably a better move than trying to fix that. For replication it would
|
||||
probably not be so hard. For cluster keys migration it might be more difficult,
|
||||
but there are probably other good reasons to improve that part anyway.
|
||||
|
||||
To-Do List
|
||||
==========
|
||||
|
||||
Additional TLS Features
|
||||
-----------------------
|
||||
|
||||
1. Add metrics to INFO?
|
||||
2. Add session caching support. Check if/how it's handled by clients to assess
|
||||
how useful/important it is.
|
||||
|
||||
redis-benchmark
|
||||
---------------
|
||||
|
||||
The current implementation is a mix of using hiredis for parsing and basic
|
||||
networking (establishing connections), but directly manipulating sockets for
|
||||
most actions.
|
||||
|
||||
This will need to be cleaned up for proper TLS support. The best approach is
|
||||
probably to migrate to hiredis async mode.
|
||||
|
||||
redis-cli
|
||||
---------
|
||||
|
||||
1. Add support for TLS in --slave and --rdb modes.
|
||||
|
||||
Others
|
||||
------
|
||||
|
||||
Consider the implications of allowing TLS to be configured on a separate port,
|
||||
making Redis listening on multiple ports.
|
||||
|
||||
This impacts many things, like
|
||||
1. Startup banner port notification
|
||||
2. Proctitle
|
||||
3. How slaves announce themselves
|
||||
4. Cluster bus port calculation
|
8
deps/Makefile
vendored
8
deps/Makefile
vendored
@ -41,9 +41,13 @@ distclean:
|
||||
|
||||
.PHONY: distclean
|
||||
|
||||
ifeq ($(BUILD_TLS),yes)
|
||||
HIREDIS_MAKE_FLAGS = USE_SSL=1
|
||||
endif
|
||||
|
||||
hiredis: .make-prerequisites
|
||||
@printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR)
|
||||
cd hiredis && $(MAKE) static
|
||||
cd hiredis && $(MAKE) static $(HIREDIS_MAKE_FLAGS)
|
||||
|
||||
.PHONY: hiredis
|
||||
|
||||
@ -77,7 +81,7 @@ JEMALLOC_LDFLAGS= $(LDFLAGS)
|
||||
|
||||
jemalloc: .make-prerequisites
|
||||
@printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR)
|
||||
cd jemalloc && ./configure --with-lg-quantum=3 --with-jemalloc-prefix=je_ --enable-cc-silence CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)"
|
||||
cd jemalloc && ./configure --with-version=5.1.0-0-g0 --with-lg-quantum=3 --with-jemalloc-prefix=je_ --enable-cc-silence CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)"
|
||||
cd jemalloc && $(MAKE) CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)" lib/libjemalloc.a
|
||||
|
||||
.PHONY: jemalloc
|
||||
|
34
deps/README.md
vendored
34
deps/README.md
vendored
@ -2,7 +2,6 @@ This directory contains all Redis dependencies, except for the libc that
|
||||
should be provided by the operating system.
|
||||
|
||||
* **Jemalloc** is our memory allocator, used as replacement for libc malloc on Linux by default. It has good performances and excellent fragmentation behavior. This component is upgraded from time to time.
|
||||
* **geohash-int** is inside the dependencies directory but is actually part of the Redis project, since it is our private fork (heavily modified) of a library initially developed for Ardb, which is in turn a fork of Redis.
|
||||
* **hiredis** is the official C client library for Redis. It is used by redis-cli, redis-benchmark and Redis Sentinel. It is part of the Redis official ecosystem but is developed externally from the Redis repository, so we just upgrade it as needed.
|
||||
* **linenoise** is a readline replacement. It is developed by the same authors of Redis but is managed as a separated project and updated as needed.
|
||||
* **lua** is Lua 5.1 with minor changes for security and additional libraries.
|
||||
@ -13,22 +12,39 @@ How to upgrade the above dependencies
|
||||
Jemalloc
|
||||
---
|
||||
|
||||
Jemalloc is unmodified. We only change settings via the `configure` script of Jemalloc using the `--with-lg-quantum` option, setting it to the value of 3 instead of 4. This provides us with more size classes that better suit the Redis data structures, in order to gain memory efficiency.
|
||||
|
||||
So in order to upgrade jemalloc:
|
||||
Jemalloc is modified with changes that allow us to implement the Redis
|
||||
active defragmentation logic. However this feature of Redis is not mandatory
|
||||
and Redis is able to understand if the Jemalloc version it is compiled
|
||||
against supports such Redis-specific modifications. So in theory, if you
|
||||
are not interested in the active defragmentation, you can replace Jemalloc
|
||||
just following tose steps:
|
||||
|
||||
1. Remove the jemalloc directory.
|
||||
2. Substitute it with the new jemalloc source tree.
|
||||
3. Edit the Makefile localted in the same directory as the README you are
|
||||
reading, and change the --with-version in the Jemalloc configure script
|
||||
options with the version you are using. This is required because otherwise
|
||||
Jemalloc configuration script is broken and will not work nested in another
|
||||
git repository.
|
||||
|
||||
Geohash
|
||||
---
|
||||
However note that we change Jemalloc settings via the `configure` script of Jemalloc using the `--with-lg-quantum` option, setting it to the value of 3 instead of 4. This provides us with more size classes that better suit the Redis data structures, in order to gain memory efficiency.
|
||||
|
||||
This is never upgraded since it's part of the Redis project. If there are changes to merge from Ardb there is the need to manually check differences, but at this point the source code is pretty different.
|
||||
If you want to upgrade Jemalloc while also providing support for
|
||||
active defragmentation, in addition to the above steps you need to perform
|
||||
the following additional steps:
|
||||
|
||||
5. In Jemalloc three, file `include/jemalloc/jemalloc_macros.h.in`, make sure
|
||||
to add `#define JEMALLOC_FRAG_HINT`.
|
||||
6. Implement the function `je_get_defrag_hint()` inside `src/jemalloc.c`. You
|
||||
can see how it is implemented in the current Jemalloc source tree shipped
|
||||
with Redis, and rewrite it according to the new Jemalloc internals, if they
|
||||
changed, otherwise you could just copy the old implementation if you are
|
||||
upgrading just to a similar version of Jemalloc.
|
||||
|
||||
Hiredis
|
||||
---
|
||||
|
||||
Hiredis uses the SDS string library, that must be the same version used inside Redis itself. Hiredis is also very critical for Sentinel. Historically Redis often used forked versions of hiredis in a way or the other. In order to upgrade it is adviced to take a lot of care:
|
||||
Hiredis uses the SDS string library, that must be the same version used inside Redis itself. Hiredis is also very critical for Sentinel. Historically Redis often used forked versions of hiredis in a way or the other. In order to upgrade it is advised to take a lot of care:
|
||||
|
||||
1. Check with diff if hiredis API changed and what impact it could have in Redis.
|
||||
2. Make sure thet the SDS library inside Hiredis and inside Redis are compatible.
|
||||
@ -61,6 +77,6 @@ and our version:
|
||||
|
||||
1. Makefile is modified to allow a different compiler than GCC.
|
||||
2. We have the implementation source code, and directly link to the following external libraries: `lua_cjson.o`, `lua_struct.o`, `lua_cmsgpack.o` and `lua_bit.o`.
|
||||
3. There is a security fix in `ldo.c`, line 498: The check for `LUA_SIGNATURE[0]` is removed in order toa void direct bytecode exectuion.
|
||||
3. There is a security fix in `ldo.c`, line 498: The check for `LUA_SIGNATURE[0]` is removed in order toa void direct bytecode execution.
|
||||
|
||||
|
||||
|
1
deps/hiredis/.gitignore
vendored
1
deps/hiredis/.gitignore
vendored
@ -5,3 +5,4 @@
|
||||
/*.dylib
|
||||
/*.a
|
||||
/*.pc
|
||||
*.dSYM
|
||||
|
80
deps/hiredis/.travis.yml
vendored
80
deps/hiredis/.travis.yml
vendored
@ -8,6 +8,12 @@ os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
branches:
|
||||
only:
|
||||
- staging
|
||||
- trying
|
||||
- master
|
||||
|
||||
before_script:
|
||||
- if [ "$TRAVIS_OS_NAME" == "osx" ] ; then brew update; brew install redis; fi
|
||||
|
||||
@ -20,20 +26,72 @@ addons:
|
||||
- libc6-dev-i386
|
||||
- libc6-dbg:i386
|
||||
- gcc-multilib
|
||||
- g++-multilib
|
||||
- valgrind
|
||||
|
||||
env:
|
||||
- CFLAGS="-Werror"
|
||||
- PRE="valgrind --track-origins=yes --leak-check=full"
|
||||
- TARGET="32bit" TARGET_VARS="32bit-vars" CFLAGS="-Werror"
|
||||
- TARGET="32bit" TARGET_VARS="32bit-vars" PRE="valgrind --track-origins=yes --leak-check=full"
|
||||
- BITS="32"
|
||||
- BITS="64"
|
||||
|
||||
script:
|
||||
- EXTRA_CMAKE_OPTS="-DENABLE_EXAMPLES:BOOL=ON -DHIREDIS_SSL:BOOL=ON";
|
||||
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
||||
if [ "$BITS" == "32" ]; then
|
||||
CFLAGS="-m32 -Werror";
|
||||
CXXFLAGS="-m32 -Werror";
|
||||
LDFLAGS="-m32";
|
||||
EXTRA_CMAKE_OPTS=;
|
||||
else
|
||||
CFLAGS="-Werror";
|
||||
CXXFLAGS="-Werror";
|
||||
fi;
|
||||
else
|
||||
TEST_PREFIX="valgrind --track-origins=yes --leak-check=full";
|
||||
if [ "$BITS" == "32" ]; then
|
||||
CFLAGS="-m32 -Werror";
|
||||
CXXFLAGS="-m32 -Werror";
|
||||
LDFLAGS="-m32";
|
||||
EXTRA_CMAKE_OPTS=;
|
||||
else
|
||||
CFLAGS="-Werror";
|
||||
CXXFLAGS="-Werror";
|
||||
fi;
|
||||
fi;
|
||||
export CFLAGS CXXFLAGS LDFLAGS TEST_PREFIX EXTRA_CMAKE_OPTS
|
||||
- mkdir build/ && cd build/
|
||||
- cmake .. ${EXTRA_CMAKE_OPTS}
|
||||
- make VERBOSE=1
|
||||
- ctest -V
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- os: osx
|
||||
env: PRE="valgrind --track-origins=yes --leak-check=full"
|
||||
include:
|
||||
# Windows MinGW cross compile on Linux
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: mingw
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- ninja-build
|
||||
- gcc-mingw-w64-x86-64
|
||||
- g++-mingw-w64-x86-64
|
||||
script:
|
||||
- mkdir build && cd build
|
||||
- CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_BUILD_WITH_INSTALL_RPATH=on
|
||||
- ninja -v
|
||||
|
||||
- os: osx
|
||||
env: TARGET="32bit" TARGET_VARS="32bit-vars" PRE="valgrind --track-origins=yes --leak-check=full"
|
||||
|
||||
script: make $TARGET CFLAGS="$CFLAGS" && make check PRE="$PRE" && make $TARGET_VARS hiredis-example
|
||||
# Windows MSVC 2017
|
||||
- os: windows
|
||||
compiler: msvc
|
||||
env:
|
||||
- MATRIX_EVAL="CC=cl.exe && CXX=cl.exe"
|
||||
before_install:
|
||||
- eval "${MATRIX_EVAL}"
|
||||
install:
|
||||
- choco install ninja
|
||||
script:
|
||||
- mkdir build && cd build
|
||||
- cmd.exe /C '"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64 &&
|
||||
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release &&
|
||||
ninja -v'
|
||||
- ctest -V
|
||||
|
62
deps/hiredis/CHANGELOG.md
vendored
62
deps/hiredis/CHANGELOG.md
vendored
@ -1,12 +1,18 @@
|
||||
### 1.0.0 (unreleased)
|
||||
|
||||
**Fixes**:
|
||||
**BREAKING CHANGES**:
|
||||
|
||||
* Catch a buffer overflow when formatting the error message
|
||||
* Import latest upstream sds. This breaks applications that are linked against the old hiredis v0.13
|
||||
* Fix warnings, when compiled with -Wshadow
|
||||
* Make hiredis compile in Cygwin on Windows, now CI-tested
|
||||
* Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now
|
||||
protocol errors. This is consistent with the RESP specification. On 32-bit
|
||||
platforms, the upper bound is lowered to `SIZE_MAX`.
|
||||
|
||||
* Change `redisReply.len` to `size_t`, as it denotes the the size of a string
|
||||
|
||||
User code should compare this to `size_t` values as well. If it was used to
|
||||
compare to other values, casting might be necessary or can be removed, if
|
||||
casting was applied before.
|
||||
|
||||
### 0.x.x (unreleased)
|
||||
**BREAKING CHANGES**:
|
||||
|
||||
* Change `redisReply.len` to `size_t`, as it denotes the the size of a string
|
||||
@ -14,6 +20,50 @@
|
||||
User code should compare this to `size_t` values as well.
|
||||
If it was used to compare to other values, casting might be necessary or can be removed, if casting was applied before.
|
||||
|
||||
* `redisReplyObjectFunctions.createArray` now takes `size_t` for its length parameter.
|
||||
|
||||
### 0.14.0 (2018-09-25)
|
||||
|
||||
* Make string2ll static to fix conflict with Redis (Tom Lee [c3188b])
|
||||
* Use -dynamiclib instead of -shared for OSX (Ryan Schmidt [a65537])
|
||||
* Use string2ll from Redis w/added tests (Michael Grunder [7bef04, 60f622])
|
||||
* Makefile - OSX compilation fixes (Ryan Schmidt [881fcb, 0e9af8])
|
||||
* Remove redundant NULL checks (Justin Brewer [54acc8, 58e6b8])
|
||||
* Fix bulk and multi-bulk length truncation (Justin Brewer [109197])
|
||||
* Fix SIGSEGV in OpenBSD by checking for NULL before calling freeaddrinfo (Justin Brewer [546d94])
|
||||
* Several POSIX compatibility fixes (Justin Brewer [bbeab8, 49bbaa, d1c1b6])
|
||||
* Makefile - Compatibility fixes (Dimitri Vorobiev [3238cf, 12a9d1])
|
||||
* Makefile - Fix make install on FreeBSD (Zach Shipko [a2ef2b])
|
||||
* Makefile - don't assume $(INSTALL) is cp (Igor Gnatenko [725a96])
|
||||
* Separate side-effect causing function from assert and small cleanup (amallia [b46413, 3c3234])
|
||||
* Don't send negative values to `__redisAsyncCommand` (Frederik Deweerdt [706129])
|
||||
* Fix leak if setsockopt fails (Frederik Deweerdt [e21c9c])
|
||||
* Fix libevent leak (zfz [515228])
|
||||
* Clean up GCC warning (Ichito Nagata [2ec774])
|
||||
* Keep track of errno in `__redisSetErrorFromErrno()` as snprintf may use it (Jin Qing [25cd88])
|
||||
* Solaris compilation fix (Donald Whyte [41b07d])
|
||||
* Reorder linker arguments when building examples (Tustfarm-heart [06eedd])
|
||||
* Keep track of subscriptions in case of rapid subscribe/unsubscribe (Hyungjin Kim [073dc8, be76c5, d46999])
|
||||
* libuv use after free fix (Paul Scott [cbb956])
|
||||
* Properly close socket fd on reconnect attempt (WSL [64d1ec])
|
||||
* Skip valgrind in OSX tests (Jan-Erik Rediger [9deb78])
|
||||
* Various updates for Travis testing OSX (Ted Nyman [fa3774, 16a459, bc0ea5])
|
||||
* Update libevent (Chris Xin [386802])
|
||||
* Change sds.h for building in C++ projects (Ali Volkan ATLI [f5b32e])
|
||||
* Use proper format specifier in redisFormatSdsCommandArgv (Paulino Huerta, Jan-Erik Rediger [360a06, 8655a6])
|
||||
* Better handling of NULL reply in example code (Jan-Erik Rediger [1b8ed3])
|
||||
* Prevent overflow when formatting an error (Jan-Erik Rediger [0335cb])
|
||||
* Compatibility fix for strerror_r (Tom Lee [bb1747])
|
||||
* Properly detect integer parse/overflow errors (Justin Brewer [93421f])
|
||||
* Adds CI for Windows and cygwin fixes (owent, [6c53d6, 6c3e40])
|
||||
* Catch a buffer overflow when formatting the error message
|
||||
* Import latest upstream sds. This breaks applications that are linked against the old hiredis v0.13
|
||||
* Fix warnings, when compiled with -Wshadow
|
||||
* Make hiredis compile in Cygwin on Windows, now CI-tested
|
||||
* Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now
|
||||
protocol errors. This is consistent with the RESP specification. On 32-bit
|
||||
platforms, the upper bound is lowered to `SIZE_MAX`.
|
||||
|
||||
* Remove backwards compatibility macro's
|
||||
|
||||
This removes the following old function aliases, use the new name now:
|
||||
@ -94,7 +144,7 @@ The parser, standalone since v0.12.0, can now be compiled on Windows
|
||||
|
||||
* Add IPv6 support
|
||||
|
||||
* Remove possiblity of multiple close on same fd
|
||||
* Remove possibility of multiple close on same fd
|
||||
|
||||
* Add ability to bind source address on connect
|
||||
|
||||
|
90
deps/hiredis/CMakeLists.txt
vendored
Normal file
90
deps/hiredis/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.4.0)
|
||||
INCLUDE(GNUInstallDirs)
|
||||
PROJECT(hiredis)
|
||||
|
||||
OPTION(ENABLE_SSL "Build hiredis_ssl for SSL support" OFF)
|
||||
|
||||
MACRO(getVersionBit name)
|
||||
SET(VERSION_REGEX "^#define ${name} (.+)$")
|
||||
FILE(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/hiredis.h"
|
||||
VERSION_BIT REGEX ${VERSION_REGEX})
|
||||
STRING(REGEX REPLACE ${VERSION_REGEX} "\\1" ${name} "${VERSION_BIT}")
|
||||
ENDMACRO(getVersionBit)
|
||||
|
||||
getVersionBit(HIREDIS_MAJOR)
|
||||
getVersionBit(HIREDIS_MINOR)
|
||||
getVersionBit(HIREDIS_PATCH)
|
||||
getVersionBit(HIREDIS_SONAME)
|
||||
SET(VERSION "${HIREDIS_MAJOR}.${HIREDIS_MINOR}.${HIREDIS_PATCH}")
|
||||
MESSAGE("Detected version: ${VERSION}")
|
||||
|
||||
PROJECT(hiredis VERSION "${VERSION}")
|
||||
|
||||
SET(ENABLE_EXAMPLES OFF CACHE BOOL "Enable building hiredis examples")
|
||||
|
||||
ADD_LIBRARY(hiredis SHARED
|
||||
async.c
|
||||
dict.c
|
||||
hiredis.c
|
||||
net.c
|
||||
read.c
|
||||
sds.c
|
||||
sockcompat.c)
|
||||
|
||||
SET_TARGET_PROPERTIES(hiredis
|
||||
PROPERTIES
|
||||
VERSION "${HIREDIS_SONAME}")
|
||||
IF(WIN32 OR MINGW)
|
||||
TARGET_LINK_LIBRARIES(hiredis PRIVATE ws2_32)
|
||||
ENDIF()
|
||||
TARGET_INCLUDE_DIRECTORIES(hiredis PUBLIC .)
|
||||
|
||||
CONFIGURE_FILE(hiredis.pc.in hiredis.pc @ONLY)
|
||||
|
||||
INSTALL(TARGETS hiredis
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
|
||||
INSTALL(FILES hiredis.h read.h sds.h async.h
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis)
|
||||
|
||||
INSTALL(DIRECTORY adapters
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis)
|
||||
|
||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis.pc
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
|
||||
IF(ENABLE_SSL)
|
||||
IF (NOT OPENSSL_ROOT_DIR)
|
||||
IF (APPLE)
|
||||
SET(OPENSSL_ROOT_DIR "/usr/local/opt/openssl")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
FIND_PACKAGE(OpenSSL REQUIRED)
|
||||
ADD_LIBRARY(hiredis_ssl SHARED
|
||||
ssl.c)
|
||||
TARGET_INCLUDE_DIRECTORIES(hiredis_ssl PRIVATE "${OPENSSL_INCLUDE_DIR}")
|
||||
TARGET_LINK_LIBRARIES(hiredis_ssl PRIVATE ${OPENSSL_LIBRARIES})
|
||||
CONFIGURE_FILE(hiredis_ssl.pc.in hiredis_ssl.pc @ONLY)
|
||||
|
||||
INSTALL(TARGETS hiredis_ssl
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
|
||||
INSTALL(FILES hiredis_ssl.h
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis)
|
||||
|
||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl.pc
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
ENDIF()
|
||||
|
||||
IF(NOT (WIN32 OR MINGW))
|
||||
ENABLE_TESTING()
|
||||
ADD_EXECUTABLE(hiredis-test test.c)
|
||||
TARGET_LINK_LIBRARIES(hiredis-test hiredis)
|
||||
ADD_TEST(NAME hiredis-test
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test.sh)
|
||||
ENDIF()
|
||||
|
||||
# Add examples
|
||||
IF(ENABLE_EXAMPLES)
|
||||
ADD_SUBDIRECTORY(examples)
|
||||
ENDIF(ENABLE_EXAMPLES)
|
128
deps/hiredis/Makefile
vendored
128
deps/hiredis/Makefile
vendored
@ -3,11 +3,17 @@
|
||||
# Copyright (C) 2010-2011 Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
# This file is released under the BSD license, see the COPYING file
|
||||
|
||||
OBJ=net.o hiredis.o sds.o async.o read.o
|
||||
OBJ=net.o hiredis.o sds.o async.o read.o sockcompat.o
|
||||
SSL_OBJ=ssl.o
|
||||
EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib
|
||||
ifeq ($(USE_SSL),1)
|
||||
EXAMPLES+=hiredis-example-ssl hiredis-example-libevent-ssl
|
||||
endif
|
||||
TESTS=hiredis-test
|
||||
LIBNAME=libhiredis
|
||||
SSL_LIBNAME=libhiredis_ssl
|
||||
PKGCONFNAME=hiredis.pc
|
||||
SSL_PKGCONFNAME=hiredis_ssl.pc
|
||||
|
||||
HIREDIS_MAJOR=$(shell grep HIREDIS_MAJOR hiredis.h | awk '{print $$3}')
|
||||
HIREDIS_MINOR=$(shell grep HIREDIS_MINOR hiredis.h | awk '{print $$3}')
|
||||
@ -36,71 +42,109 @@ endef
|
||||
export REDIS_TEST_CONFIG
|
||||
|
||||
# Fallback to gcc when $CC is not in $PATH.
|
||||
CC:=$(shell sh -c 'type $(CC) >/dev/null 2>/dev/null && echo $(CC) || echo gcc')
|
||||
CXX:=$(shell sh -c 'type $(CXX) >/dev/null 2>/dev/null && echo $(CXX) || echo g++')
|
||||
CC:=$(shell sh -c 'type $${CC%% *} >/dev/null 2>/dev/null && echo $(CC) || echo gcc')
|
||||
CXX:=$(shell sh -c 'type $${CXX%% *} >/dev/null 2>/dev/null && echo $(CXX) || echo g++')
|
||||
OPTIMIZATION?=-O3
|
||||
WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings
|
||||
WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings -Wno-missing-field-initializers
|
||||
DEBUG_FLAGS?= -g -ggdb
|
||||
REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG_FLAGS) $(ARCH)
|
||||
REAL_LDFLAGS=$(LDFLAGS) $(ARCH)
|
||||
REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CPPFLAGS) $(CFLAGS) $(WARNINGS) $(DEBUG_FLAGS)
|
||||
REAL_LDFLAGS=$(LDFLAGS)
|
||||
|
||||
DYLIBSUFFIX=so
|
||||
STLIBSUFFIX=a
|
||||
DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_SONAME)
|
||||
DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR)
|
||||
DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX)
|
||||
DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS)
|
||||
SSL_DYLIBNAME=$(SSL_LIBNAME).$(DYLIBSUFFIX)
|
||||
DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME)
|
||||
STLIBNAME=$(LIBNAME).$(STLIBSUFFIX)
|
||||
STLIB_MAKE_CMD=ar rcs $(STLIBNAME)
|
||||
SSL_STLIBNAME=$(SSL_LIBNAME).$(STLIBSUFFIX)
|
||||
STLIB_MAKE_CMD=$(AR) rcs
|
||||
|
||||
# Platform-specific overrides
|
||||
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
|
||||
|
||||
USE_SSL?=0
|
||||
|
||||
# This is required for test.c only
|
||||
ifeq ($(USE_SSL),1)
|
||||
CFLAGS+=-DHIREDIS_TEST_SSL
|
||||
endif
|
||||
|
||||
ifeq ($(uname_S),Linux)
|
||||
SSL_LDFLAGS=-lssl -lcrypto
|
||||
else
|
||||
OPENSSL_PREFIX?=/usr/local/opt/openssl
|
||||
CFLAGS+=-I$(OPENSSL_PREFIX)/include
|
||||
SSL_LDFLAGS+=-L$(OPENSSL_PREFIX)/lib -lssl -lcrypto
|
||||
endif
|
||||
|
||||
ifeq ($(uname_S),SunOS)
|
||||
REAL_LDFLAGS+= -ldl -lnsl -lsocket
|
||||
DYLIB_MAKE_CMD=$(CC) -G -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS)
|
||||
INSTALL= cp -r
|
||||
endif
|
||||
ifeq ($(uname_S),Darwin)
|
||||
DYLIBSUFFIX=dylib
|
||||
DYLIB_MINOR_NAME=$(LIBNAME).$(HIREDIS_SONAME).$(DYLIBSUFFIX)
|
||||
DYLIB_MAKE_CMD=$(CC) -shared -Wl,-install_name,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS)
|
||||
DYLIB_MAKE_CMD=$(CC) -dynamiclib -Wl,-install_name,$(PREFIX)/$(LIBRARY_PATH)/$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS)
|
||||
endif
|
||||
|
||||
all: $(DYLIBNAME) $(STLIBNAME) hiredis-test $(PKGCONFNAME)
|
||||
ifeq ($(USE_SSL),1)
|
||||
all: $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(SSL_PKGCONFNAME)
|
||||
endif
|
||||
|
||||
# Deps (use make dep to generate this)
|
||||
async.o: async.c fmacros.h async.h hiredis.h read.h sds.h net.h dict.c dict.h
|
||||
dict.o: dict.c fmacros.h dict.h
|
||||
hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h net.h
|
||||
net.o: net.c fmacros.h net.h hiredis.h read.h sds.h
|
||||
hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h net.h win32.h
|
||||
net.o: net.c fmacros.h net.h hiredis.h read.h sds.h sockcompat.h win32.h
|
||||
read.o: read.c fmacros.h read.h sds.h
|
||||
sds.o: sds.c sds.h
|
||||
sockcompat.o: sockcompat.c sockcompat.h
|
||||
ssl.o: ssl.c hiredis.h
|
||||
test.o: test.c fmacros.h hiredis.h read.h sds.h
|
||||
|
||||
$(DYLIBNAME): $(OBJ)
|
||||
$(DYLIB_MAKE_CMD) $(OBJ)
|
||||
$(DYLIB_MAKE_CMD) -o $(DYLIBNAME) $(OBJ) $(REAL_LDFLAGS)
|
||||
|
||||
$(STLIBNAME): $(OBJ)
|
||||
$(STLIB_MAKE_CMD) $(OBJ)
|
||||
$(STLIB_MAKE_CMD) $(STLIBNAME) $(OBJ)
|
||||
|
||||
$(SSL_DYLIBNAME): $(SSL_OBJ)
|
||||
$(DYLIB_MAKE_CMD) -o $(SSL_DYLIBNAME) $(SSL_OBJ) $(REAL_LDFLAGS) $(SSL_LDFLAGS)
|
||||
|
||||
$(SSL_STLIBNAME): $(SSL_OBJ)
|
||||
$(STLIB_MAKE_CMD) $(SSL_STLIBNAME) $(SSL_OBJ)
|
||||
|
||||
dynamic: $(DYLIBNAME)
|
||||
static: $(STLIBNAME)
|
||||
ifeq ($(USE_SSL),1)
|
||||
dynamic: $(SSL_DYLIBNAME)
|
||||
static: $(SSL_STLIBNAME)
|
||||
endif
|
||||
|
||||
# Binaries:
|
||||
hiredis-example-libevent: examples/example-libevent.c adapters/libevent.h $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -levent $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -levent $(STLIBNAME) $(REAL_LDFLAGS)
|
||||
|
||||
hiredis-example-libevent-ssl: examples/example-libevent-ssl.c adapters/libevent.h $(STLIBNAME) $(SSL_STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -levent $(STLIBNAME) $(SSL_STLIBNAME) $(REAL_LDFLAGS) $(SSL_LDFLAGS)
|
||||
|
||||
hiredis-example-libev: examples/example-libev.c adapters/libev.h $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -lev $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -lev $(STLIBNAME) $(REAL_LDFLAGS)
|
||||
|
||||
hiredis-example-glib: examples/example-glib.c adapters/glib.h $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) $(shell pkg-config --cflags --libs glib-2.0) -I. $< $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(shell pkg-config --cflags --libs glib-2.0) $(STLIBNAME) $(REAL_LDFLAGS)
|
||||
|
||||
hiredis-example-ivykis: examples/example-ivykis.c adapters/ivykis.h $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -livykis $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -livykis $(STLIBNAME) $(REAL_LDFLAGS)
|
||||
|
||||
hiredis-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -framework CoreFoundation $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -framework CoreFoundation $(STLIBNAME) $(REAL_LDFLAGS)
|
||||
|
||||
hiredis-example-ssl: examples/example-ssl.c $(STLIBNAME) $(SSL_STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(SSL_STLIBNAME) $(REAL_LDFLAGS) $(SSL_LDFLAGS)
|
||||
|
||||
ifndef AE_DIR
|
||||
hiredis-example-ae:
|
||||
@ -117,7 +161,7 @@ hiredis-example-libuv:
|
||||
@false
|
||||
else
|
||||
hiredis-example-libuv: examples/example-libuv.c adapters/libuv.h $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(LIBUV_DIR)/include $< $(LIBUV_DIR)/.libs/libuv.a -lpthread -lrt $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. -I$(LIBUV_DIR)/include $< $(LIBUV_DIR)/.libs/libuv.a -lpthread -lrt $(STLIBNAME) $(REAL_LDFLAGS)
|
||||
endif
|
||||
|
||||
ifeq ($(and $(QT_MOC),$(QT_INCLUDE_DIR),$(QT_LIBRARY_DIR)),)
|
||||
@ -134,38 +178,35 @@ hiredis-example-qt: examples/example-qt.cpp adapters/qt.h $(STLIBNAME)
|
||||
endif
|
||||
|
||||
hiredis-example: examples/example.c $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS)
|
||||
|
||||
examples: $(EXAMPLES)
|
||||
|
||||
hiredis-test: test.o $(STLIBNAME)
|
||||
TEST_LIBS = $(STLIBNAME)
|
||||
ifeq ($(USE_SSL),1)
|
||||
TEST_LIBS += $(SSL_STLIBNAME) -lssl -lcrypto -lpthread
|
||||
endif
|
||||
hiredis-test: test.o $(TEST_LIBS)
|
||||
|
||||
hiredis-%: %.o $(STLIBNAME)
|
||||
$(CC) $(REAL_CFLAGS) -o $@ $(REAL_LDFLAGS) $< $(STLIBNAME)
|
||||
$(CC) $(REAL_CFLAGS) -o $@ $< $(TEST_LIBS) $(REAL_LDFLAGS)
|
||||
|
||||
test: hiredis-test
|
||||
./hiredis-test
|
||||
|
||||
check: hiredis-test
|
||||
@echo "$$REDIS_TEST_CONFIG" | $(REDIS_SERVER) -
|
||||
$(PRE) ./hiredis-test -h 127.0.0.1 -p $(REDIS_PORT) -s /tmp/hiredis-test-redis.sock || \
|
||||
( kill `cat /tmp/hiredis-test-redis.pid` && false )
|
||||
kill `cat /tmp/hiredis-test-redis.pid`
|
||||
TEST_SSL=$(USE_SSL) ./test.sh
|
||||
|
||||
.c.o:
|
||||
$(CC) -std=c99 -pedantic -c $(REAL_CFLAGS) $<
|
||||
|
||||
clean:
|
||||
rm -rf $(DYLIBNAME) $(STLIBNAME) $(TESTS) $(PKGCONFNAME) examples/hiredis-example* *.o *.gcda *.gcno *.gcov
|
||||
rm -rf $(DYLIBNAME) $(STLIBNAME) $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(TESTS) $(PKGCONFNAME) examples/hiredis-example* *.o *.gcda *.gcno *.gcov
|
||||
|
||||
dep:
|
||||
$(CC) -MM *.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -MM *.c
|
||||
|
||||
ifeq ($(uname_S),SunOS)
|
||||
INSTALL?= cp -r
|
||||
endif
|
||||
|
||||
INSTALL?= cp -a
|
||||
INSTALL?= cp -pPR
|
||||
|
||||
$(PKGCONFNAME): hiredis.h
|
||||
@echo "Generating $@ for pkgconfig..."
|
||||
@ -180,9 +221,24 @@ $(PKGCONFNAME): hiredis.h
|
||||
@echo Libs: -L\$${libdir} -lhiredis >> $@
|
||||
@echo Cflags: -I\$${includedir} -D_FILE_OFFSET_BITS=64 >> $@
|
||||
|
||||
$(SSL_PKGCONFNAME): hiredis.h
|
||||
@echo "Generating $@ for pkgconfig..."
|
||||
@echo prefix=$(PREFIX) > $@
|
||||
@echo exec_prefix=\$${prefix} >> $@
|
||||
@echo libdir=$(PREFIX)/$(LIBRARY_PATH) >> $@
|
||||
@echo includedir=$(PREFIX)/$(INCLUDE_PATH) >> $@
|
||||
@echo >> $@
|
||||
@echo Name: hiredis_ssl >> $@
|
||||
@echo Description: SSL Support for hiredis. >> $@
|
||||
@echo Version: $(HIREDIS_MAJOR).$(HIREDIS_MINOR).$(HIREDIS_PATCH) >> $@
|
||||
@echo Requires: hiredis >> $@
|
||||
@echo Libs: -L\$${libdir} -lhiredis_ssl >> $@
|
||||
@echo Libs.private: -lssl -lcrypto >> $@
|
||||
|
||||
install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME)
|
||||
mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH)
|
||||
$(INSTALL) hiredis.h async.h read.h sds.h adapters $(INSTALL_INCLUDE_PATH)
|
||||
mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_INCLUDE_PATH)/adapters $(INSTALL_LIBRARY_PATH)
|
||||
$(INSTALL) hiredis.h async.h read.h sds.h $(INSTALL_INCLUDE_PATH)
|
||||
$(INSTALL) adapters/*.h $(INSTALL_INCLUDE_PATH)/adapters
|
||||
$(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME)
|
||||
cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIBNAME)
|
||||
$(INSTALL) $(STLIBNAME) $(INSTALL_LIBRARY_PATH)
|
||||
|
3
deps/hiredis/README.md
vendored
3
deps/hiredis/README.md
vendored
@ -286,6 +286,7 @@ return `REDIS_ERR`. The function to set the disconnect callback has the followin
|
||||
```c
|
||||
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
|
||||
```
|
||||
`ac->data` may be used to pass user data to this callback, the same can be done for redisConnectCallback.
|
||||
### Sending commands and their callbacks
|
||||
|
||||
In an asynchronous context, commands are automatically pipelined due to the nature of an event loop.
|
||||
@ -406,6 +407,6 @@ as soon as possible in order to prevent allocation of useless memory.
|
||||
## AUTHORS
|
||||
|
||||
Hiredis was written by Salvatore Sanfilippo (antirez at gmail) and
|
||||
Pieter Noordhuis (pcnoordhuis at gmail) and is released under the BSD license.
|
||||
Pieter Noordhuis (pcnoordhuis at gmail) and is released under the BSD license.
|
||||
Hiredis is currently maintained by Matt Stancliff (matt at genges dot com) and
|
||||
Jan-Erik Rediger (janerik at fnordig dot com)
|
||||
|
112
deps/hiredis/adapters/libevent.h
vendored
112
deps/hiredis/adapters/libevent.h
vendored
@ -34,48 +34,113 @@
|
||||
#include "../hiredis.h"
|
||||
#include "../async.h"
|
||||
|
||||
#define REDIS_LIBEVENT_DELETED 0x01
|
||||
#define REDIS_LIBEVENT_ENTERED 0x02
|
||||
|
||||
typedef struct redisLibeventEvents {
|
||||
redisAsyncContext *context;
|
||||
struct event *rev, *wev;
|
||||
struct event *ev;
|
||||
struct event_base *base;
|
||||
struct timeval tv;
|
||||
short flags;
|
||||
short state;
|
||||
} redisLibeventEvents;
|
||||
|
||||
static void redisLibeventReadEvent(int fd, short event, void *arg) {
|
||||
((void)fd); ((void)event);
|
||||
redisLibeventEvents *e = (redisLibeventEvents*)arg;
|
||||
redisAsyncHandleRead(e->context);
|
||||
static void redisLibeventDestroy(redisLibeventEvents *e) {
|
||||
free(e);
|
||||
}
|
||||
|
||||
static void redisLibeventWriteEvent(int fd, short event, void *arg) {
|
||||
((void)fd); ((void)event);
|
||||
static void redisLibeventHandler(int fd, short event, void *arg) {
|
||||
((void)fd);
|
||||
redisLibeventEvents *e = (redisLibeventEvents*)arg;
|
||||
redisAsyncHandleWrite(e->context);
|
||||
e->state |= REDIS_LIBEVENT_ENTERED;
|
||||
|
||||
#define CHECK_DELETED() if (e->state & REDIS_LIBEVENT_DELETED) {\
|
||||
redisLibeventDestroy(e);\
|
||||
return; \
|
||||
}
|
||||
|
||||
if ((event & EV_TIMEOUT) && (e->state & REDIS_LIBEVENT_DELETED) == 0) {
|
||||
redisAsyncHandleTimeout(e->context);
|
||||
CHECK_DELETED();
|
||||
}
|
||||
|
||||
if ((event & EV_READ) && e->context && (e->state & REDIS_LIBEVENT_DELETED) == 0) {
|
||||
redisAsyncHandleRead(e->context);
|
||||
CHECK_DELETED();
|
||||
}
|
||||
|
||||
if ((event & EV_WRITE) && e->context && (e->state & REDIS_LIBEVENT_DELETED) == 0) {
|
||||
redisAsyncHandleWrite(e->context);
|
||||
CHECK_DELETED();
|
||||
}
|
||||
|
||||
e->state &= ~REDIS_LIBEVENT_ENTERED;
|
||||
#undef CHECK_DELETED
|
||||
}
|
||||
|
||||
static void redisLibeventUpdate(void *privdata, short flag, int isRemove) {
|
||||
redisLibeventEvents *e = (redisLibeventEvents *)privdata;
|
||||
const struct timeval *tv = e->tv.tv_sec || e->tv.tv_usec ? &e->tv : NULL;
|
||||
|
||||
if (isRemove) {
|
||||
if ((e->flags & flag) == 0) {
|
||||
return;
|
||||
} else {
|
||||
e->flags &= ~flag;
|
||||
}
|
||||
} else {
|
||||
if (e->flags & flag) {
|
||||
return;
|
||||
} else {
|
||||
e->flags |= flag;
|
||||
}
|
||||
}
|
||||
|
||||
event_del(e->ev);
|
||||
event_assign(e->ev, e->base, e->context->c.fd, e->flags | EV_PERSIST,
|
||||
redisLibeventHandler, privdata);
|
||||
event_add(e->ev, tv);
|
||||
}
|
||||
|
||||
static void redisLibeventAddRead(void *privdata) {
|
||||
redisLibeventEvents *e = (redisLibeventEvents*)privdata;
|
||||
event_add(e->rev,NULL);
|
||||
redisLibeventUpdate(privdata, EV_READ, 0);
|
||||
}
|
||||
|
||||
static void redisLibeventDelRead(void *privdata) {
|
||||
redisLibeventEvents *e = (redisLibeventEvents*)privdata;
|
||||
event_del(e->rev);
|
||||
redisLibeventUpdate(privdata, EV_READ, 1);
|
||||
}
|
||||
|
||||
static void redisLibeventAddWrite(void *privdata) {
|
||||
redisLibeventEvents *e = (redisLibeventEvents*)privdata;
|
||||
event_add(e->wev,NULL);
|
||||
redisLibeventUpdate(privdata, EV_WRITE, 0);
|
||||
}
|
||||
|
||||
static void redisLibeventDelWrite(void *privdata) {
|
||||
redisLibeventEvents *e = (redisLibeventEvents*)privdata;
|
||||
event_del(e->wev);
|
||||
redisLibeventUpdate(privdata, EV_WRITE, 1);
|
||||
}
|
||||
|
||||
static void redisLibeventCleanup(void *privdata) {
|
||||
redisLibeventEvents *e = (redisLibeventEvents*)privdata;
|
||||
event_del(e->rev);
|
||||
event_del(e->wev);
|
||||
free(e);
|
||||
if (!e) {
|
||||
return;
|
||||
}
|
||||
event_del(e->ev);
|
||||
event_free(e->ev);
|
||||
e->ev = NULL;
|
||||
|
||||
if (e->state & REDIS_LIBEVENT_ENTERED) {
|
||||
e->state |= REDIS_LIBEVENT_DELETED;
|
||||
} else {
|
||||
redisLibeventDestroy(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void redisLibeventSetTimeout(void *privdata, struct timeval tv) {
|
||||
redisLibeventEvents *e = (redisLibeventEvents *)privdata;
|
||||
short flags = e->flags;
|
||||
e->flags = 0;
|
||||
e->tv = tv;
|
||||
redisLibeventUpdate(e, flags, 0);
|
||||
}
|
||||
|
||||
static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) {
|
||||
@ -87,7 +152,7 @@ static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) {
|
||||
return REDIS_ERR;
|
||||
|
||||
/* Create container for context and r/w events */
|
||||
e = (redisLibeventEvents*)malloc(sizeof(*e));
|
||||
e = (redisLibeventEvents*)calloc(1, sizeof(*e));
|
||||
e->context = ac;
|
||||
|
||||
/* Register functions to start/stop listening for events */
|
||||
@ -96,13 +161,12 @@ static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) {
|
||||
ac->ev.addWrite = redisLibeventAddWrite;
|
||||
ac->ev.delWrite = redisLibeventDelWrite;
|
||||
ac->ev.cleanup = redisLibeventCleanup;
|
||||
ac->ev.scheduleTimer = redisLibeventSetTimeout;
|
||||
ac->ev.data = e;
|
||||
|
||||
/* Initialize and install read/write events */
|
||||
e->rev = event_new(base, c->fd, EV_READ, redisLibeventReadEvent, e);
|
||||
e->wev = event_new(base, c->fd, EV_WRITE, redisLibeventWriteEvent, e);
|
||||
event_add(e->rev, NULL);
|
||||
event_add(e->wev, NULL);
|
||||
e->ev = event_new(base, c->fd, EV_READ | EV_WRITE, redisLibeventHandler, e);
|
||||
e->base = base;
|
||||
return REDIS_OK;
|
||||
}
|
||||
#endif
|
||||
|
9
deps/hiredis/adapters/libuv.h
vendored
9
deps/hiredis/adapters/libuv.h
vendored
@ -15,15 +15,12 @@ typedef struct redisLibuvEvents {
|
||||
|
||||
static void redisLibuvPoll(uv_poll_t* handle, int status, int events) {
|
||||
redisLibuvEvents* p = (redisLibuvEvents*)handle->data;
|
||||
int ev = (status ? p->events : events);
|
||||
|
||||
if (status != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (p->context != NULL && (events & UV_READABLE)) {
|
||||
if (p->context != NULL && (ev & UV_READABLE)) {
|
||||
redisAsyncHandleRead(p->context);
|
||||
}
|
||||
if (p->context != NULL && (events & UV_WRITABLE)) {
|
||||
if (p->context != NULL && (ev & UV_WRITABLE)) {
|
||||
redisAsyncHandleWrite(p->context);
|
||||
}
|
||||
}
|
||||
|
24
deps/hiredis/appveyor.yml
vendored
24
deps/hiredis/appveyor.yml
vendored
@ -1,24 +1,14 @@
|
||||
# Appveyor configuration file for CI build of hiredis on Windows (under Cygwin)
|
||||
environment:
|
||||
matrix:
|
||||
- CYG_ROOT: C:\cygwin64
|
||||
CYG_SETUP: setup-x86_64.exe
|
||||
CYG_MIRROR: http://cygwin.mirror.constant.com
|
||||
CYG_CACHE: C:\cygwin64\var\cache\setup
|
||||
CYG_BASH: C:\cygwin64\bin\bash
|
||||
- CYG_BASH: C:\cygwin64\bin\bash
|
||||
CC: gcc
|
||||
- CYG_ROOT: C:\cygwin
|
||||
CYG_SETUP: setup-x86.exe
|
||||
CYG_MIRROR: http://cygwin.mirror.constant.com
|
||||
CYG_CACHE: C:\cygwin\var\cache\setup
|
||||
CYG_BASH: C:\cygwin\bin\bash
|
||||
- CYG_BASH: C:\cygwin\bin\bash
|
||||
CC: gcc
|
||||
TARGET: 32bit
|
||||
TARGET_VARS: 32bit-vars
|
||||
CFLAGS: -m32
|
||||
CXXFLAGS: -m32
|
||||
LDFLAGS: -m32
|
||||
|
||||
# Cache Cygwin files to speed up build
|
||||
cache:
|
||||
- '%CYG_CACHE%'
|
||||
clone_depth: 1
|
||||
|
||||
# Attempt to ensure we don't try to convert line endings to Win32 CRLF as this will cause build to fail
|
||||
@ -27,10 +17,8 @@ init:
|
||||
|
||||
# Install needed build dependencies
|
||||
install:
|
||||
- ps: 'Start-FileDownload "http://cygwin.com/$env:CYG_SETUP" -FileName "$env:CYG_SETUP"'
|
||||
- '%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages automake,bison,gcc-core,libtool,make,gettext-devel,gettext,intltool,pkg-config,clang,llvm > NUL 2>&1'
|
||||
- '%CYG_BASH% -lc "cygcheck -dc cygwin"'
|
||||
|
||||
build_script:
|
||||
- 'echo building...'
|
||||
- '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; make LDFLAGS=$LDFLAGS CC=$CC $TARGET CFLAGS=$CFLAGS && make LDFLAGS=$LDFLAGS CC=$CC $TARGET_VARS hiredis-example"'
|
||||
- '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; mkdir build && cd build && cmake .. -G \"Unix Makefiles\" && make VERBOSE=1"'
|
||||
|
239
deps/hiredis/async.c
vendored
239
deps/hiredis/async.c
vendored
@ -32,7 +32,9 @@
|
||||
#include "fmacros.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
@ -40,22 +42,9 @@
|
||||
#include "net.h"
|
||||
#include "dict.c"
|
||||
#include "sds.h"
|
||||
#include "win32.h"
|
||||
|
||||
#define _EL_ADD_READ(ctx) do { \
|
||||
if ((ctx)->ev.addRead) (ctx)->ev.addRead((ctx)->ev.data); \
|
||||
} while(0)
|
||||
#define _EL_DEL_READ(ctx) do { \
|
||||
if ((ctx)->ev.delRead) (ctx)->ev.delRead((ctx)->ev.data); \
|
||||
} while(0)
|
||||
#define _EL_ADD_WRITE(ctx) do { \
|
||||
if ((ctx)->ev.addWrite) (ctx)->ev.addWrite((ctx)->ev.data); \
|
||||
} while(0)
|
||||
#define _EL_DEL_WRITE(ctx) do { \
|
||||
if ((ctx)->ev.delWrite) (ctx)->ev.delWrite((ctx)->ev.data); \
|
||||
} while(0)
|
||||
#define _EL_CLEANUP(ctx) do { \
|
||||
if ((ctx)->ev.cleanup) (ctx)->ev.cleanup((ctx)->ev.data); \
|
||||
} while(0);
|
||||
#include "async_private.h"
|
||||
|
||||
/* Forward declaration of function in hiredis.c */
|
||||
int __redisAppendCommand(redisContext *c, const char *cmd, size_t len);
|
||||
@ -126,6 +115,7 @@ static redisAsyncContext *redisAsyncInitialize(redisContext *c) {
|
||||
ac->ev.addWrite = NULL;
|
||||
ac->ev.delWrite = NULL;
|
||||
ac->ev.cleanup = NULL;
|
||||
ac->ev.scheduleTimer = NULL;
|
||||
|
||||
ac->onConnect = NULL;
|
||||
ac->onDisconnect = NULL;
|
||||
@ -150,56 +140,52 @@ static void __redisAsyncCopyError(redisAsyncContext *ac) {
|
||||
ac->errstr = c->errstr;
|
||||
}
|
||||
|
||||
redisAsyncContext *redisAsyncConnect(const char *ip, int port) {
|
||||
redisAsyncContext *redisAsyncConnectWithOptions(const redisOptions *options) {
|
||||
redisOptions myOptions = *options;
|
||||
redisContext *c;
|
||||
redisAsyncContext *ac;
|
||||
|
||||
c = redisConnectNonBlock(ip,port);
|
||||
if (c == NULL)
|
||||
myOptions.options |= REDIS_OPT_NONBLOCK;
|
||||
c = redisConnectWithOptions(&myOptions);
|
||||
if (c == NULL) {
|
||||
return NULL;
|
||||
|
||||
}
|
||||
ac = redisAsyncInitialize(c);
|
||||
if (ac == NULL) {
|
||||
redisFree(c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__redisAsyncCopyError(ac);
|
||||
return ac;
|
||||
}
|
||||
|
||||
redisAsyncContext *redisAsyncConnect(const char *ip, int port) {
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, ip, port);
|
||||
return redisAsyncConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
redisAsyncContext *redisAsyncConnectBind(const char *ip, int port,
|
||||
const char *source_addr) {
|
||||
redisContext *c = redisConnectBindNonBlock(ip,port,source_addr);
|
||||
redisAsyncContext *ac = redisAsyncInitialize(c);
|
||||
__redisAsyncCopyError(ac);
|
||||
return ac;
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, ip, port);
|
||||
options.endpoint.tcp.source_addr = source_addr;
|
||||
return redisAsyncConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port,
|
||||
const char *source_addr) {
|
||||
redisContext *c = redisConnectBindNonBlockWithReuse(ip,port,source_addr);
|
||||
redisAsyncContext *ac = redisAsyncInitialize(c);
|
||||
__redisAsyncCopyError(ac);
|
||||
return ac;
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, ip, port);
|
||||
options.options |= REDIS_OPT_REUSEADDR;
|
||||
options.endpoint.tcp.source_addr = source_addr;
|
||||
return redisAsyncConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
redisAsyncContext *redisAsyncConnectUnix(const char *path) {
|
||||
redisContext *c;
|
||||
redisAsyncContext *ac;
|
||||
|
||||
c = redisConnectUnixNonBlock(path);
|
||||
if (c == NULL)
|
||||
return NULL;
|
||||
|
||||
ac = redisAsyncInitialize(c);
|
||||
if (ac == NULL) {
|
||||
redisFree(c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__redisAsyncCopyError(ac);
|
||||
return ac;
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_UNIX(&options, path);
|
||||
return redisAsyncConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn) {
|
||||
@ -328,7 +314,7 @@ void redisAsyncFree(redisAsyncContext *ac) {
|
||||
}
|
||||
|
||||
/* Helper function to make the disconnect happen and clean up. */
|
||||
static void __redisAsyncDisconnect(redisAsyncContext *ac) {
|
||||
void __redisAsyncDisconnect(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
|
||||
/* Make sure error is accessible if there is any */
|
||||
@ -336,16 +322,23 @@ static void __redisAsyncDisconnect(redisAsyncContext *ac) {
|
||||
|
||||
if (ac->err == 0) {
|
||||
/* For clean disconnects, there should be no pending callbacks. */
|
||||
assert(__redisShiftCallback(&ac->replies,NULL) == REDIS_ERR);
|
||||
int ret = __redisShiftCallback(&ac->replies,NULL);
|
||||
assert(ret == REDIS_ERR);
|
||||
} else {
|
||||
/* Disconnection is caused by an error, make sure that pending
|
||||
* callbacks cannot call new commands. */
|
||||
c->flags |= REDIS_DISCONNECTING;
|
||||
}
|
||||
|
||||
/* cleanup event library on disconnect.
|
||||
* this is safe to call multiple times */
|
||||
_EL_CLEANUP(ac);
|
||||
|
||||
/* For non-clean disconnects, __redisAsyncFree() will execute pending
|
||||
* callbacks with a NULL-reply. */
|
||||
__redisAsyncFree(ac);
|
||||
if (!(c->flags & REDIS_NO_AUTO_FREE)) {
|
||||
__redisAsyncFree(ac);
|
||||
}
|
||||
}
|
||||
|
||||
/* Tries to do a clean disconnect from Redis, meaning it stops new commands
|
||||
@ -357,6 +350,9 @@ static void __redisAsyncDisconnect(redisAsyncContext *ac) {
|
||||
void redisAsyncDisconnect(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
c->flags |= REDIS_DISCONNECTING;
|
||||
|
||||
/** unset the auto-free flag here, because disconnect undoes this */
|
||||
c->flags &= ~REDIS_NO_AUTO_FREE;
|
||||
if (!(c->flags & REDIS_IN_CALLBACK) && ac->replies.head == NULL)
|
||||
__redisAsyncDisconnect(ac);
|
||||
}
|
||||
@ -364,6 +360,7 @@ void redisAsyncDisconnect(redisAsyncContext *ac) {
|
||||
static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply, redisCallback *dstcb) {
|
||||
redisContext *c = &(ac->c);
|
||||
dict *callbacks;
|
||||
redisCallback *cb;
|
||||
dictEntry *de;
|
||||
int pvariant;
|
||||
char *stype;
|
||||
@ -387,16 +384,28 @@ static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply,
|
||||
sname = sdsnewlen(reply->element[1]->str,reply->element[1]->len);
|
||||
de = dictFind(callbacks,sname);
|
||||
if (de != NULL) {
|
||||
memcpy(dstcb,dictGetEntryVal(de),sizeof(*dstcb));
|
||||
cb = dictGetEntryVal(de);
|
||||
|
||||
/* If this is an subscribe reply decrease pending counter. */
|
||||
if (strcasecmp(stype+pvariant,"subscribe") == 0) {
|
||||
cb->pending_subs -= 1;
|
||||
}
|
||||
|
||||
memcpy(dstcb,cb,sizeof(*dstcb));
|
||||
|
||||
/* If this is an unsubscribe message, remove it. */
|
||||
if (strcasecmp(stype+pvariant,"unsubscribe") == 0) {
|
||||
dictDelete(callbacks,sname);
|
||||
if (cb->pending_subs == 0)
|
||||
dictDelete(callbacks,sname);
|
||||
|
||||
/* If this was the last unsubscribe message, revert to
|
||||
* non-subscribe mode. */
|
||||
assert(reply->element[2]->type == REDIS_REPLY_INTEGER);
|
||||
if (reply->element[2]->integer == 0)
|
||||
|
||||
/* Unset subscribed flag only when no pipelined pending subscribe. */
|
||||
if (reply->element[2]->integer == 0
|
||||
&& dictSize(ac->sub.channels) == 0
|
||||
&& dictSize(ac->sub.patterns) == 0)
|
||||
c->flags &= ~REDIS_SUBSCRIBED;
|
||||
}
|
||||
}
|
||||
@ -410,7 +419,7 @@ static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply,
|
||||
|
||||
void redisProcessCallbacks(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
redisCallback cb = {NULL, NULL, NULL};
|
||||
redisCallback cb = {NULL, NULL, 0, NULL};
|
||||
void *reply = NULL;
|
||||
int status;
|
||||
|
||||
@ -492,22 +501,34 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
|
||||
* write event fires. When connecting was not successful, the connect callback
|
||||
* is called with a REDIS_ERR status and the context is free'd. */
|
||||
static int __redisAsyncHandleConnect(redisAsyncContext *ac) {
|
||||
int completed = 0;
|
||||
redisContext *c = &(ac->c);
|
||||
|
||||
if (redisCheckSocketError(c) == REDIS_ERR) {
|
||||
/* Try again later when connect(2) is still in progress. */
|
||||
if (errno == EINPROGRESS)
|
||||
return REDIS_OK;
|
||||
|
||||
if (ac->onConnect) ac->onConnect(ac,REDIS_ERR);
|
||||
if (redisCheckConnectDone(c, &completed) == REDIS_ERR) {
|
||||
/* Error! */
|
||||
redisCheckSocketError(c);
|
||||
if (ac->onConnect) ac->onConnect(ac, REDIS_ERR);
|
||||
__redisAsyncDisconnect(ac);
|
||||
return REDIS_ERR;
|
||||
} else if (completed == 1) {
|
||||
/* connected! */
|
||||
if (ac->onConnect) ac->onConnect(ac, REDIS_OK);
|
||||
c->flags |= REDIS_CONNECTED;
|
||||
return REDIS_OK;
|
||||
} else {
|
||||
return REDIS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark context as connected. */
|
||||
c->flags |= REDIS_CONNECTED;
|
||||
if (ac->onConnect) ac->onConnect(ac,REDIS_OK);
|
||||
return REDIS_OK;
|
||||
void redisAsyncRead(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
|
||||
if (redisBufferRead(c) == REDIS_ERR) {
|
||||
__redisAsyncDisconnect(ac);
|
||||
} else {
|
||||
/* Always re-schedule reads */
|
||||
_EL_ADD_READ(ac);
|
||||
redisProcessCallbacks(ac);
|
||||
}
|
||||
}
|
||||
|
||||
/* This function should be called when the socket is readable.
|
||||
@ -525,28 +546,13 @@ void redisAsyncHandleRead(redisAsyncContext *ac) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (redisBufferRead(c) == REDIS_ERR) {
|
||||
__redisAsyncDisconnect(ac);
|
||||
} else {
|
||||
/* Always re-schedule reads */
|
||||
_EL_ADD_READ(ac);
|
||||
redisProcessCallbacks(ac);
|
||||
}
|
||||
c->funcs->async_read(ac);
|
||||
}
|
||||
|
||||
void redisAsyncHandleWrite(redisAsyncContext *ac) {
|
||||
void redisAsyncWrite(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
int done = 0;
|
||||
|
||||
if (!(c->flags & REDIS_CONNECTED)) {
|
||||
/* Abort connect was not successful. */
|
||||
if (__redisAsyncHandleConnect(ac) != REDIS_OK)
|
||||
return;
|
||||
/* Try again later when the context is still not connected. */
|
||||
if (!(c->flags & REDIS_CONNECTED))
|
||||
return;
|
||||
}
|
||||
|
||||
if (redisBufferWrite(c,&done) == REDIS_ERR) {
|
||||
__redisAsyncDisconnect(ac);
|
||||
} else {
|
||||
@ -561,6 +567,51 @@ void redisAsyncHandleWrite(redisAsyncContext *ac) {
|
||||
}
|
||||
}
|
||||
|
||||
void redisAsyncHandleWrite(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
|
||||
if (!(c->flags & REDIS_CONNECTED)) {
|
||||
/* Abort connect was not successful. */
|
||||
if (__redisAsyncHandleConnect(ac) != REDIS_OK)
|
||||
return;
|
||||
/* Try again later when the context is still not connected. */
|
||||
if (!(c->flags & REDIS_CONNECTED))
|
||||
return;
|
||||
}
|
||||
|
||||
c->funcs->async_write(ac);
|
||||
}
|
||||
|
||||
void __redisSetError(redisContext *c, int type, const char *str);
|
||||
|
||||
void redisAsyncHandleTimeout(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
redisCallback cb;
|
||||
|
||||
if ((c->flags & REDIS_CONNECTED) && ac->replies.head == NULL) {
|
||||
/* Nothing to do - just an idle timeout */
|
||||
return;
|
||||
}
|
||||
|
||||
if (!c->err) {
|
||||
__redisSetError(c, REDIS_ERR_TIMEOUT, "Timeout");
|
||||
}
|
||||
|
||||
if (!(c->flags & REDIS_CONNECTED) && ac->onConnect) {
|
||||
ac->onConnect(ac, REDIS_ERR);
|
||||
}
|
||||
|
||||
while (__redisShiftCallback(&ac->replies, &cb) == REDIS_OK) {
|
||||
__redisRunCallback(ac, &cb, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Don't automatically sever the connection,
|
||||
* rather, allow to ignore <x> responses before the queue is clear
|
||||
*/
|
||||
__redisAsyncDisconnect(ac);
|
||||
}
|
||||
|
||||
/* Sets a pointer to the first argument and its length starting at p. Returns
|
||||
* the number of bytes to skip to get to the following argument. */
|
||||
static const char *nextArgument(const char *start, const char **str, size_t *len) {
|
||||
@ -583,6 +634,9 @@ static const char *nextArgument(const char *start, const char **str, size_t *len
|
||||
static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len) {
|
||||
redisContext *c = &(ac->c);
|
||||
redisCallback cb;
|
||||
struct dict *cbdict;
|
||||
dictEntry *de;
|
||||
redisCallback *existcb;
|
||||
int pvariant, hasnext;
|
||||
const char *cstr, *astr;
|
||||
size_t clen, alen;
|
||||
@ -596,6 +650,7 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
|
||||
/* Setup callback */
|
||||
cb.fn = fn;
|
||||
cb.privdata = privdata;
|
||||
cb.pending_subs = 1;
|
||||
|
||||
/* Find out which command will be appended. */
|
||||
p = nextArgument(cmd,&cstr,&clen);
|
||||
@ -612,9 +667,18 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
|
||||
while ((p = nextArgument(p,&astr,&alen)) != NULL) {
|
||||
sname = sdsnewlen(astr,alen);
|
||||
if (pvariant)
|
||||
ret = dictReplace(ac->sub.patterns,sname,&cb);
|
||||
cbdict = ac->sub.patterns;
|
||||
else
|
||||
ret = dictReplace(ac->sub.channels,sname,&cb);
|
||||
cbdict = ac->sub.channels;
|
||||
|
||||
de = dictFind(cbdict,sname);
|
||||
|
||||
if (de != NULL) {
|
||||
existcb = dictGetEntryVal(de);
|
||||
cb.pending_subs = existcb->pending_subs + 1;
|
||||
}
|
||||
|
||||
ret = dictReplace(cbdict,sname,&cb);
|
||||
|
||||
if (ret == 0) sdsfree(sname);
|
||||
}
|
||||
@ -676,6 +740,8 @@ int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *priv
|
||||
int len;
|
||||
int status;
|
||||
len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
|
||||
if (len < 0)
|
||||
return REDIS_ERR;
|
||||
status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
|
||||
sdsfree(cmd);
|
||||
return status;
|
||||
@ -685,3 +751,16 @@ int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
|
||||
int status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
|
||||
return status;
|
||||
}
|
||||
|
||||
void redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv) {
|
||||
if (!ac->c.timeout) {
|
||||
ac->c.timeout = calloc(1, sizeof(tv));
|
||||
}
|
||||
|
||||
if (tv.tv_sec == ac->c.timeout->tv_sec &&
|
||||
tv.tv_usec == ac->c.timeout->tv_usec) {
|
||||
return;
|
||||
}
|
||||
|
||||
*ac->c.timeout = tv;
|
||||
}
|
||||
|
13
deps/hiredis/async.h
vendored
13
deps/hiredis/async.h
vendored
@ -45,6 +45,7 @@ typedef void (redisCallbackFn)(struct redisAsyncContext*, void*, void*);
|
||||
typedef struct redisCallback {
|
||||
struct redisCallback *next; /* simple singly linked list */
|
||||
redisCallbackFn *fn;
|
||||
int pending_subs;
|
||||
void *privdata;
|
||||
} redisCallback;
|
||||
|
||||
@ -56,6 +57,7 @@ typedef struct redisCallbackList {
|
||||
/* Connection callback prototypes */
|
||||
typedef void (redisDisconnectCallback)(const struct redisAsyncContext*, int status);
|
||||
typedef void (redisConnectCallback)(const struct redisAsyncContext*, int status);
|
||||
typedef void(redisTimerCallback)(void *timer, void *privdata);
|
||||
|
||||
/* Context for an async connection to Redis */
|
||||
typedef struct redisAsyncContext {
|
||||
@ -80,6 +82,7 @@ typedef struct redisAsyncContext {
|
||||
void (*addWrite)(void *privdata);
|
||||
void (*delWrite)(void *privdata);
|
||||
void (*cleanup)(void *privdata);
|
||||
void (*scheduleTimer)(void *privdata, struct timeval tv);
|
||||
} ev;
|
||||
|
||||
/* Called when either the connection is terminated due to an error or per
|
||||
@ -92,6 +95,10 @@ typedef struct redisAsyncContext {
|
||||
/* Regular command callbacks */
|
||||
redisCallbackList replies;
|
||||
|
||||
/* Address used for connect() */
|
||||
struct sockaddr *saddr;
|
||||
size_t addrlen;
|
||||
|
||||
/* Subscription callbacks */
|
||||
struct {
|
||||
redisCallbackList invalid;
|
||||
@ -101,6 +108,7 @@ typedef struct redisAsyncContext {
|
||||
} redisAsyncContext;
|
||||
|
||||
/* Functions that proxy to hiredis */
|
||||
redisAsyncContext *redisAsyncConnectWithOptions(const redisOptions *options);
|
||||
redisAsyncContext *redisAsyncConnect(const char *ip, int port);
|
||||
redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, const char *source_addr);
|
||||
redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port,
|
||||
@ -108,12 +116,17 @@ redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port,
|
||||
redisAsyncContext *redisAsyncConnectUnix(const char *path);
|
||||
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);
|
||||
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
|
||||
|
||||
void redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv);
|
||||
void redisAsyncDisconnect(redisAsyncContext *ac);
|
||||
void redisAsyncFree(redisAsyncContext *ac);
|
||||
|
||||
/* Handle read/write events */
|
||||
void redisAsyncHandleRead(redisAsyncContext *ac);
|
||||
void redisAsyncHandleWrite(redisAsyncContext *ac);
|
||||
void redisAsyncHandleTimeout(redisAsyncContext *ac);
|
||||
void redisAsyncRead(redisAsyncContext *ac);
|
||||
void redisAsyncWrite(redisAsyncContext *ac);
|
||||
|
||||
/* Command functions for an async context. Write the command to the
|
||||
* output buffer and register the provided callback. */
|
||||
|
72
deps/hiredis/async_private.h
vendored
Normal file
72
deps/hiredis/async_private.h
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __HIREDIS_ASYNC_PRIVATE_H
|
||||
#define __HIREDIS_ASYNC_PRIVATE_H
|
||||
|
||||
#define _EL_ADD_READ(ctx) \
|
||||
do { \
|
||||
refreshTimeout(ctx); \
|
||||
if ((ctx)->ev.addRead) (ctx)->ev.addRead((ctx)->ev.data); \
|
||||
} while (0)
|
||||
#define _EL_DEL_READ(ctx) do { \
|
||||
if ((ctx)->ev.delRead) (ctx)->ev.delRead((ctx)->ev.data); \
|
||||
} while(0)
|
||||
#define _EL_ADD_WRITE(ctx) \
|
||||
do { \
|
||||
refreshTimeout(ctx); \
|
||||
if ((ctx)->ev.addWrite) (ctx)->ev.addWrite((ctx)->ev.data); \
|
||||
} while (0)
|
||||
#define _EL_DEL_WRITE(ctx) do { \
|
||||
if ((ctx)->ev.delWrite) (ctx)->ev.delWrite((ctx)->ev.data); \
|
||||
} while(0)
|
||||
#define _EL_CLEANUP(ctx) do { \
|
||||
if ((ctx)->ev.cleanup) (ctx)->ev.cleanup((ctx)->ev.data); \
|
||||
ctx->ev.cleanup = NULL; \
|
||||
} while(0);
|
||||
|
||||
static inline void refreshTimeout(redisAsyncContext *ctx) {
|
||||
if (ctx->c.timeout && ctx->ev.scheduleTimer &&
|
||||
(ctx->c.timeout->tv_sec || ctx->c.timeout->tv_usec)) {
|
||||
ctx->ev.scheduleTimer(ctx->ev.data, *ctx->c.timeout);
|
||||
// } else {
|
||||
// printf("Not scheduling timer.. (tmo=%p)\n", ctx->c.timeout);
|
||||
// if (ctx->c.timeout){
|
||||
// printf("tv_sec: %u. tv_usec: %u\n", ctx->c.timeout->tv_sec,
|
||||
// ctx->c.timeout->tv_usec);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
void __redisAsyncDisconnect(redisAsyncContext *ac);
|
||||
void redisProcessCallbacks(redisAsyncContext *ac);
|
||||
|
||||
#endif /* __HIREDIS_ASYNC_PRIVATE_H */
|
46
deps/hiredis/examples/CMakeLists.txt
vendored
Normal file
46
deps/hiredis/examples/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
INCLUDE(FindPkgConfig)
|
||||
# Check for GLib
|
||||
|
||||
PKG_CHECK_MODULES(GLIB2 glib-2.0)
|
||||
if (GLIB2_FOUND)
|
||||
INCLUDE_DIRECTORIES(${GLIB2_INCLUDE_DIRS})
|
||||
LINK_DIRECTORIES(${GLIB2_LIBRARY_DIRS})
|
||||
ADD_EXECUTABLE(example-glib example-glib.c)
|
||||
TARGET_LINK_LIBRARIES(example-glib hiredis ${GLIB2_LIBRARIES})
|
||||
ENDIF(GLIB2_FOUND)
|
||||
|
||||
FIND_PATH(LIBEV ev.h
|
||||
HINTS /usr/local /usr/opt/local
|
||||
ENV LIBEV_INCLUDE_DIR)
|
||||
|
||||
if (LIBEV)
|
||||
# Just compile and link with libev
|
||||
ADD_EXECUTABLE(example-libev example-libev.c)
|
||||
TARGET_LINK_LIBRARIES(example-libev hiredis ev)
|
||||
ENDIF()
|
||||
|
||||
FIND_PATH(LIBEVENT event.h)
|
||||
if (LIBEVENT)
|
||||
ADD_EXECUTABLE(example-libevent example-libevent)
|
||||
TARGET_LINK_LIBRARIES(example-libevent hiredis event)
|
||||
ENDIF()
|
||||
|
||||
FIND_PATH(LIBUV uv.h)
|
||||
IF (LIBUV)
|
||||
ADD_EXECUTABLE(example-libuv example-libuv.c)
|
||||
TARGET_LINK_LIBRARIES(example-libuv hiredis uv)
|
||||
ENDIF()
|
||||
|
||||
IF (APPLE)
|
||||
FIND_LIBRARY(CF CoreFoundation)
|
||||
ADD_EXECUTABLE(example-macosx example-macosx.c)
|
||||
TARGET_LINK_LIBRARIES(example-macosx hiredis ${CF})
|
||||
ENDIF()
|
||||
|
||||
IF (ENABLE_SSL)
|
||||
ADD_EXECUTABLE(example-ssl example-ssl.c)
|
||||
TARGET_LINK_LIBRARIES(example-ssl hiredis hiredis_ssl)
|
||||
ENDIF()
|
||||
|
||||
ADD_EXECUTABLE(example example.c)
|
||||
TARGET_LINK_LIBRARIES(example hiredis)
|
73
deps/hiredis/examples/example-libevent-ssl.c
vendored
Normal file
73
deps/hiredis/examples/example-libevent-ssl.c
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <hiredis.h>
|
||||
#include <hiredis_ssl.h>
|
||||
#include <async.h>
|
||||
#include <adapters/libevent.h>
|
||||
|
||||
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
|
||||
redisReply *reply = r;
|
||||
if (reply == NULL) return;
|
||||
printf("argv[%s]: %s\n", (char*)privdata, reply->str);
|
||||
|
||||
/* Disconnect after receiving the reply to GET */
|
||||
redisAsyncDisconnect(c);
|
||||
}
|
||||
|
||||
void connectCallback(const redisAsyncContext *c, int status) {
|
||||
if (status != REDIS_OK) {
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return;
|
||||
}
|
||||
printf("Connected...\n");
|
||||
}
|
||||
|
||||
void disconnectCallback(const redisAsyncContext *c, int status) {
|
||||
if (status != REDIS_OK) {
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return;
|
||||
}
|
||||
printf("Disconnected...\n");
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
struct event_base *base = event_base_new();
|
||||
if (argc < 5) {
|
||||
fprintf(stderr,
|
||||
"Usage: %s <key> <host> <port> <cert> <certKey> [ca]\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const char *value = argv[1];
|
||||
size_t nvalue = strlen(value);
|
||||
|
||||
const char *hostname = argv[2];
|
||||
int port = atoi(argv[3]);
|
||||
|
||||
const char *cert = argv[4];
|
||||
const char *certKey = argv[5];
|
||||
const char *caCert = argc > 5 ? argv[6] : NULL;
|
||||
|
||||
redisAsyncContext *c = redisAsyncConnect(hostname, port);
|
||||
if (c->err) {
|
||||
/* Let *c leak for now... */
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return 1;
|
||||
}
|
||||
if (redisSecureConnection(&c->c, caCert, cert, certKey, "sni") != REDIS_OK) {
|
||||
printf("SSL Error!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
redisLibeventAttach(c,base);
|
||||
redisAsyncSetConnectCallback(c,connectCallback);
|
||||
redisAsyncSetDisconnectCallback(c,disconnectCallback);
|
||||
redisAsyncCommand(c, NULL, NULL, "SET key %b", value, nvalue);
|
||||
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
|
||||
event_base_dispatch(base);
|
||||
return 0;
|
||||
}
|
15
deps/hiredis/examples/example-libevent.c
vendored
15
deps/hiredis/examples/example-libevent.c
vendored
@ -9,7 +9,12 @@
|
||||
|
||||
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
|
||||
redisReply *reply = r;
|
||||
if (reply == NULL) return;
|
||||
if (reply == NULL) {
|
||||
if (c->errstr) {
|
||||
printf("errstr: %s\n", c->errstr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
printf("argv[%s]: %s\n", (char*)privdata, reply->str);
|
||||
|
||||
/* Disconnect after receiving the reply to GET */
|
||||
@ -35,8 +40,14 @@ void disconnectCallback(const redisAsyncContext *c, int status) {
|
||||
int main (int argc, char **argv) {
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
struct event_base *base = event_base_new();
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
|
||||
struct timeval tv = {0};
|
||||
tv.tv_sec = 1;
|
||||
options.timeout = &tv;
|
||||
|
||||
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
|
||||
|
||||
redisAsyncContext *c = redisAsyncConnectWithOptions(&options);
|
||||
if (c->err) {
|
||||
/* Let *c leak for now... */
|
||||
printf("Error: %s\n", c->errstr);
|
||||
|
97
deps/hiredis/examples/example-ssl.c
vendored
Normal file
97
deps/hiredis/examples/example-ssl.c
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hiredis.h>
|
||||
#include <hiredis_ssl.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
unsigned int j;
|
||||
redisContext *c;
|
||||
redisReply *reply;
|
||||
if (argc < 4) {
|
||||
printf("Usage: %s <host> <port> <cert> <key> [ca]\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1";
|
||||
int port = atoi(argv[2]);
|
||||
const char *cert = argv[3];
|
||||
const char *key = argv[4];
|
||||
const char *ca = argc > 4 ? argv[5] : NULL;
|
||||
|
||||
struct timeval tv = { 1, 500000 }; // 1.5 seconds
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, hostname, port);
|
||||
options.timeout = &tv;
|
||||
c = redisConnectWithOptions(&options);
|
||||
|
||||
if (c == NULL || c->err) {
|
||||
if (c) {
|
||||
printf("Connection error: %s\n", c->errstr);
|
||||
redisFree(c);
|
||||
} else {
|
||||
printf("Connection error: can't allocate redis context\n");
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (redisSecureConnection(c, ca, cert, key, "sni") != REDIS_OK) {
|
||||
printf("Couldn't initialize SSL!\n");
|
||||
printf("Error: %s\n", c->errstr);
|
||||
redisFree(c);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* PING server */
|
||||
reply = redisCommand(c,"PING");
|
||||
printf("PING: %s\n", reply->str);
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Set a key */
|
||||
reply = redisCommand(c,"SET %s %s", "foo", "hello world");
|
||||
printf("SET: %s\n", reply->str);
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Set a key using binary safe API */
|
||||
reply = redisCommand(c,"SET %b %b", "bar", (size_t) 3, "hello", (size_t) 5);
|
||||
printf("SET (binary API): %s\n", reply->str);
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Try a GET and two INCR */
|
||||
reply = redisCommand(c,"GET foo");
|
||||
printf("GET foo: %s\n", reply->str);
|
||||
freeReplyObject(reply);
|
||||
|
||||
reply = redisCommand(c,"INCR counter");
|
||||
printf("INCR counter: %lld\n", reply->integer);
|
||||
freeReplyObject(reply);
|
||||
/* again ... */
|
||||
reply = redisCommand(c,"INCR counter");
|
||||
printf("INCR counter: %lld\n", reply->integer);
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Create a list of numbers, from 0 to 9 */
|
||||
reply = redisCommand(c,"DEL mylist");
|
||||
freeReplyObject(reply);
|
||||
for (j = 0; j < 10; j++) {
|
||||
char buf[64];
|
||||
|
||||
snprintf(buf,64,"%u",j);
|
||||
reply = redisCommand(c,"LPUSH mylist element-%s", buf);
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
|
||||
/* Let's check what we have inside the list */
|
||||
reply = redisCommand(c,"LRANGE mylist 0 -1");
|
||||
if (reply->type == REDIS_REPLY_ARRAY) {
|
||||
for (j = 0; j < reply->elements; j++) {
|
||||
printf("%u) %s\n", j, reply->element[j]->str);
|
||||
}
|
||||
}
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Disconnects and frees the context */
|
||||
redisFree(c);
|
||||
|
||||
return 0;
|
||||
}
|
17
deps/hiredis/examples/example.c
vendored
17
deps/hiredis/examples/example.c
vendored
@ -5,14 +5,27 @@
|
||||
#include <hiredis.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
unsigned int j;
|
||||
unsigned int j, isunix = 0;
|
||||
redisContext *c;
|
||||
redisReply *reply;
|
||||
const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1";
|
||||
|
||||
if (argc > 2) {
|
||||
if (*argv[2] == 'u' || *argv[2] == 'U') {
|
||||
isunix = 1;
|
||||
/* in this case, host is the path to the unix socket */
|
||||
printf("Will connect to unix socket @%s\n", hostname);
|
||||
}
|
||||
}
|
||||
|
||||
int port = (argc > 2) ? atoi(argv[2]) : 6379;
|
||||
|
||||
struct timeval timeout = { 1, 500000 }; // 1.5 seconds
|
||||
c = redisConnectWithTimeout(hostname, port, timeout);
|
||||
if (isunix) {
|
||||
c = redisConnectUnixWithTimeout(hostname, timeout);
|
||||
} else {
|
||||
c = redisConnectWithTimeout(hostname, port, timeout);
|
||||
}
|
||||
if (c == NULL || c->err) {
|
||||
if (c) {
|
||||
printf("Connection error: %s\n", c->errstr);
|
||||
|
19
deps/hiredis/fmacros.h
vendored
19
deps/hiredis/fmacros.h
vendored
@ -1,25 +1,12 @@
|
||||
#ifndef __HIREDIS_FMACRO_H
|
||||
#define __HIREDIS_FMACRO_H
|
||||
|
||||
#if defined(__linux__)
|
||||
#define _BSD_SOURCE
|
||||
#define _DEFAULT_SOURCE
|
||||
#endif
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
#include <sys/cdefs.h>
|
||||
#endif
|
||||
|
||||
#if defined(__sun__)
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
#else
|
||||
#if !(defined(__APPLE__) && defined(__MACH__))
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
#endif
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#define _OSX
|
||||
/* Enable TCP_KEEPALIVE */
|
||||
#define _DARWIN_C_SOURCE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
373
deps/hiredis/hiredis.c
vendored
373
deps/hiredis/hiredis.c
vendored
@ -34,7 +34,6 @@
|
||||
#include "fmacros.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
@ -42,12 +41,24 @@
|
||||
#include "hiredis.h"
|
||||
#include "net.h"
|
||||
#include "sds.h"
|
||||
#include "async.h"
|
||||
#include "win32.h"
|
||||
|
||||
static redisContextFuncs redisContextDefaultFuncs = {
|
||||
.free_privdata = NULL,
|
||||
.async_read = redisAsyncRead,
|
||||
.async_write = redisAsyncWrite,
|
||||
.read = redisNetRead,
|
||||
.write = redisNetWrite
|
||||
};
|
||||
|
||||
static redisReply *createReplyObject(int type);
|
||||
static void *createStringObject(const redisReadTask *task, char *str, size_t len);
|
||||
static void *createArrayObject(const redisReadTask *task, int elements);
|
||||
static void *createArrayObject(const redisReadTask *task, size_t elements);
|
||||
static void *createIntegerObject(const redisReadTask *task, long long value);
|
||||
static void *createDoubleObject(const redisReadTask *task, double value, char *str, size_t len);
|
||||
static void *createNilObject(const redisReadTask *task);
|
||||
static void *createBoolObject(const redisReadTask *task, int bval);
|
||||
|
||||
/* Default set of functions to build the reply. Keep in mind that such a
|
||||
* function returning NULL is interpreted as OOM. */
|
||||
@ -55,7 +66,9 @@ static redisReplyObjectFunctions defaultFunctions = {
|
||||
createStringObject,
|
||||
createArrayObject,
|
||||
createIntegerObject,
|
||||
createDoubleObject,
|
||||
createNilObject,
|
||||
createBoolObject,
|
||||
freeReplyObject
|
||||
};
|
||||
|
||||
@ -82,18 +95,19 @@ void freeReplyObject(void *reply) {
|
||||
case REDIS_REPLY_INTEGER:
|
||||
break; /* Nothing to free */
|
||||
case REDIS_REPLY_ARRAY:
|
||||
case REDIS_REPLY_MAP:
|
||||
case REDIS_REPLY_SET:
|
||||
if (r->element != NULL) {
|
||||
for (j = 0; j < r->elements; j++)
|
||||
if (r->element[j] != NULL)
|
||||
freeReplyObject(r->element[j]);
|
||||
freeReplyObject(r->element[j]);
|
||||
free(r->element);
|
||||
}
|
||||
break;
|
||||
case REDIS_REPLY_ERROR:
|
||||
case REDIS_REPLY_STATUS:
|
||||
case REDIS_REPLY_STRING:
|
||||
if (r->str != NULL)
|
||||
free(r->str);
|
||||
case REDIS_REPLY_DOUBLE:
|
||||
free(r->str);
|
||||
break;
|
||||
}
|
||||
free(r);
|
||||
@ -107,34 +121,49 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
|
||||
if (r == NULL)
|
||||
return NULL;
|
||||
|
||||
buf = malloc(len+1);
|
||||
if (buf == NULL) {
|
||||
freeReplyObject(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(task->type == REDIS_REPLY_ERROR ||
|
||||
task->type == REDIS_REPLY_STATUS ||
|
||||
task->type == REDIS_REPLY_STRING);
|
||||
task->type == REDIS_REPLY_STRING ||
|
||||
task->type == REDIS_REPLY_VERB);
|
||||
|
||||
/* Copy string value */
|
||||
memcpy(buf,str,len);
|
||||
buf[len] = '\0';
|
||||
if (task->type == REDIS_REPLY_VERB) {
|
||||
buf = malloc(len-4+1); /* Skip 4 bytes of verbatim type header. */
|
||||
if (buf == NULL) {
|
||||
freeReplyObject(r);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(r->vtype,str,3);
|
||||
r->vtype[3] = '\0';
|
||||
memcpy(buf,str+4,len-4);
|
||||
buf[len-4] = '\0';
|
||||
r->len = len-4;
|
||||
} else {
|
||||
buf = malloc(len+1);
|
||||
if (buf == NULL) {
|
||||
freeReplyObject(r);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(buf,str,len);
|
||||
buf[len] = '\0';
|
||||
r->len = len;
|
||||
}
|
||||
r->str = buf;
|
||||
r->len = len;
|
||||
|
||||
if (task->parent) {
|
||||
parent = task->parent->obj;
|
||||
assert(parent->type == REDIS_REPLY_ARRAY);
|
||||
assert(parent->type == REDIS_REPLY_ARRAY ||
|
||||
parent->type == REDIS_REPLY_MAP ||
|
||||
parent->type == REDIS_REPLY_SET);
|
||||
parent->element[task->idx] = r;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static void *createArrayObject(const redisReadTask *task, int elements) {
|
||||
static void *createArrayObject(const redisReadTask *task, size_t elements) {
|
||||
redisReply *r, *parent;
|
||||
|
||||
r = createReplyObject(REDIS_REPLY_ARRAY);
|
||||
r = createReplyObject(task->type);
|
||||
if (r == NULL)
|
||||
return NULL;
|
||||
|
||||
@ -150,7 +179,9 @@ static void *createArrayObject(const redisReadTask *task, int elements) {
|
||||
|
||||
if (task->parent) {
|
||||
parent = task->parent->obj;
|
||||
assert(parent->type == REDIS_REPLY_ARRAY);
|
||||
assert(parent->type == REDIS_REPLY_ARRAY ||
|
||||
parent->type == REDIS_REPLY_MAP ||
|
||||
parent->type == REDIS_REPLY_SET);
|
||||
parent->element[task->idx] = r;
|
||||
}
|
||||
return r;
|
||||
@ -167,7 +198,41 @@ static void *createIntegerObject(const redisReadTask *task, long long value) {
|
||||
|
||||
if (task->parent) {
|
||||
parent = task->parent->obj;
|
||||
assert(parent->type == REDIS_REPLY_ARRAY);
|
||||
assert(parent->type == REDIS_REPLY_ARRAY ||
|
||||
parent->type == REDIS_REPLY_MAP ||
|
||||
parent->type == REDIS_REPLY_SET);
|
||||
parent->element[task->idx] = r;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static void *createDoubleObject(const redisReadTask *task, double value, char *str, size_t len) {
|
||||
redisReply *r, *parent;
|
||||
|
||||
r = createReplyObject(REDIS_REPLY_DOUBLE);
|
||||
if (r == NULL)
|
||||
return NULL;
|
||||
|
||||
r->dval = value;
|
||||
r->str = malloc(len+1);
|
||||
if (r->str == NULL) {
|
||||
freeReplyObject(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The double reply also has the original protocol string representing a
|
||||
* double as a null terminated string. This way the caller does not need
|
||||
* to format back for string conversion, especially since Redis does efforts
|
||||
* to make the string more human readable avoiding the calssical double
|
||||
* decimal string conversion artifacts. */
|
||||
memcpy(r->str, str, len);
|
||||
r->str[len] = '\0';
|
||||
|
||||
if (task->parent) {
|
||||
parent = task->parent->obj;
|
||||
assert(parent->type == REDIS_REPLY_ARRAY ||
|
||||
parent->type == REDIS_REPLY_MAP ||
|
||||
parent->type == REDIS_REPLY_SET);
|
||||
parent->element[task->idx] = r;
|
||||
}
|
||||
return r;
|
||||
@ -182,7 +247,28 @@ static void *createNilObject(const redisReadTask *task) {
|
||||
|
||||
if (task->parent) {
|
||||
parent = task->parent->obj;
|
||||
assert(parent->type == REDIS_REPLY_ARRAY);
|
||||
assert(parent->type == REDIS_REPLY_ARRAY ||
|
||||
parent->type == REDIS_REPLY_MAP ||
|
||||
parent->type == REDIS_REPLY_SET);
|
||||
parent->element[task->idx] = r;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static void *createBoolObject(const redisReadTask *task, int bval) {
|
||||
redisReply *r, *parent;
|
||||
|
||||
r = createReplyObject(REDIS_REPLY_BOOL);
|
||||
if (r == NULL)
|
||||
return NULL;
|
||||
|
||||
r->integer = bval != 0;
|
||||
|
||||
if (task->parent) {
|
||||
parent = task->parent->obj;
|
||||
assert(parent->type == REDIS_REPLY_ARRAY ||
|
||||
parent->type == REDIS_REPLY_MAP ||
|
||||
parent->type == REDIS_REPLY_SET);
|
||||
parent->element[task->idx] = r;
|
||||
}
|
||||
return r;
|
||||
@ -432,11 +518,7 @@ cleanup:
|
||||
}
|
||||
|
||||
sdsfree(curarg);
|
||||
|
||||
/* No need to check cmd since it is the last statement that can fail,
|
||||
* but do it anyway to be as defensive as possible. */
|
||||
if (cmd != NULL)
|
||||
free(cmd);
|
||||
free(cmd);
|
||||
|
||||
return error_type;
|
||||
}
|
||||
@ -581,7 +663,7 @@ void __redisSetError(redisContext *c, int type, const char *str) {
|
||||
} else {
|
||||
/* Only REDIS_ERR_IO may lack a description! */
|
||||
assert(type == REDIS_ERR_IO);
|
||||
__redis_strerror_r(errno, c->errstr, sizeof(c->errstr));
|
||||
strerror_r(errno, c->errstr, sizeof(c->errstr));
|
||||
}
|
||||
}
|
||||
|
||||
@ -589,53 +671,48 @@ redisReader *redisReaderCreate(void) {
|
||||
return redisReaderCreateWithFunctions(&defaultFunctions);
|
||||
}
|
||||
|
||||
static redisContext *redisContextInit(void) {
|
||||
static redisContext *redisContextInit(const redisOptions *options) {
|
||||
redisContext *c;
|
||||
|
||||
c = calloc(1,sizeof(redisContext));
|
||||
c = calloc(1, sizeof(*c));
|
||||
if (c == NULL)
|
||||
return NULL;
|
||||
|
||||
c->err = 0;
|
||||
c->errstr[0] = '\0';
|
||||
c->funcs = &redisContextDefaultFuncs;
|
||||
c->obuf = sdsempty();
|
||||
c->reader = redisReaderCreate();
|
||||
c->tcp.host = NULL;
|
||||
c->tcp.source_addr = NULL;
|
||||
c->unix_sock.path = NULL;
|
||||
c->timeout = NULL;
|
||||
c->fd = REDIS_INVALID_FD;
|
||||
|
||||
if (c->obuf == NULL || c->reader == NULL) {
|
||||
redisFree(c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(void)options; /* options are used in other functions */
|
||||
return c;
|
||||
}
|
||||
|
||||
void redisFree(redisContext *c) {
|
||||
if (c == NULL)
|
||||
return;
|
||||
if (c->fd > 0)
|
||||
close(c->fd);
|
||||
if (c->obuf != NULL)
|
||||
sdsfree(c->obuf);
|
||||
if (c->reader != NULL)
|
||||
redisReaderFree(c->reader);
|
||||
if (c->tcp.host)
|
||||
free(c->tcp.host);
|
||||
if (c->tcp.source_addr)
|
||||
free(c->tcp.source_addr);
|
||||
if (c->unix_sock.path)
|
||||
free(c->unix_sock.path);
|
||||
if (c->timeout)
|
||||
free(c->timeout);
|
||||
redisNetClose(c);
|
||||
|
||||
sdsfree(c->obuf);
|
||||
redisReaderFree(c->reader);
|
||||
free(c->tcp.host);
|
||||
free(c->tcp.source_addr);
|
||||
free(c->unix_sock.path);
|
||||
free(c->timeout);
|
||||
free(c->saddr);
|
||||
if (c->funcs->free_privdata) {
|
||||
c->funcs->free_privdata(c->privdata);
|
||||
}
|
||||
memset(c, 0xff, sizeof(*c));
|
||||
free(c);
|
||||
}
|
||||
|
||||
int redisFreeKeepFd(redisContext *c) {
|
||||
int fd = c->fd;
|
||||
c->fd = -1;
|
||||
redisFD redisFreeKeepFd(redisContext *c) {
|
||||
redisFD fd = c->fd;
|
||||
c->fd = REDIS_INVALID_FD;
|
||||
redisFree(c);
|
||||
return fd;
|
||||
}
|
||||
@ -644,10 +721,13 @@ int redisReconnect(redisContext *c) {
|
||||
c->err = 0;
|
||||
memset(c->errstr, '\0', strlen(c->errstr));
|
||||
|
||||
if (c->fd > 0) {
|
||||
close(c->fd);
|
||||
if (c->privdata && c->funcs->free_privdata) {
|
||||
c->funcs->free_privdata(c->privdata);
|
||||
c->privdata = NULL;
|
||||
}
|
||||
|
||||
redisNetClose(c);
|
||||
|
||||
sdsfree(c->obuf);
|
||||
redisReaderFree(c->reader);
|
||||
|
||||
@ -668,108 +748,107 @@ int redisReconnect(redisContext *c) {
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
redisContext *redisConnectWithOptions(const redisOptions *options) {
|
||||
redisContext *c = redisContextInit(options);
|
||||
if (c == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (!(options->options & REDIS_OPT_NONBLOCK)) {
|
||||
c->flags |= REDIS_BLOCK;
|
||||
}
|
||||
if (options->options & REDIS_OPT_REUSEADDR) {
|
||||
c->flags |= REDIS_REUSEADDR;
|
||||
}
|
||||
if (options->options & REDIS_OPT_NOAUTOFREE) {
|
||||
c->flags |= REDIS_NO_AUTO_FREE;
|
||||
}
|
||||
|
||||
if (options->type == REDIS_CONN_TCP) {
|
||||
redisContextConnectBindTcp(c, options->endpoint.tcp.ip,
|
||||
options->endpoint.tcp.port, options->timeout,
|
||||
options->endpoint.tcp.source_addr);
|
||||
} else if (options->type == REDIS_CONN_UNIX) {
|
||||
redisContextConnectUnix(c, options->endpoint.unix_socket,
|
||||
options->timeout);
|
||||
} else if (options->type == REDIS_CONN_USERFD) {
|
||||
c->fd = options->endpoint.fd;
|
||||
c->flags |= REDIS_CONNECTED;
|
||||
} else {
|
||||
// Unknown type - FIXME - FREE
|
||||
return NULL;
|
||||
}
|
||||
if (options->timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) {
|
||||
redisContextSetTimeout(c, *options->timeout);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Connect to a Redis instance. On error the field error in the returned
|
||||
* context will be set to the return value of the error function.
|
||||
* When no set of reply functions is given, the default set will be used. */
|
||||
redisContext *redisConnect(const char *ip, int port) {
|
||||
redisContext *c;
|
||||
|
||||
c = redisContextInit();
|
||||
if (c == NULL)
|
||||
return NULL;
|
||||
|
||||
c->flags |= REDIS_BLOCK;
|
||||
redisContextConnectTcp(c,ip,port,NULL);
|
||||
return c;
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, ip, port);
|
||||
return redisConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) {
|
||||
redisContext *c;
|
||||
|
||||
c = redisContextInit();
|
||||
if (c == NULL)
|
||||
return NULL;
|
||||
|
||||
c->flags |= REDIS_BLOCK;
|
||||
redisContextConnectTcp(c,ip,port,&tv);
|
||||
return c;
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, ip, port);
|
||||
options.timeout = &tv;
|
||||
return redisConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
redisContext *redisConnectNonBlock(const char *ip, int port) {
|
||||
redisContext *c;
|
||||
|
||||
c = redisContextInit();
|
||||
if (c == NULL)
|
||||
return NULL;
|
||||
|
||||
c->flags &= ~REDIS_BLOCK;
|
||||
redisContextConnectTcp(c,ip,port,NULL);
|
||||
return c;
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, ip, port);
|
||||
options.options |= REDIS_OPT_NONBLOCK;
|
||||
return redisConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
redisContext *redisConnectBindNonBlock(const char *ip, int port,
|
||||
const char *source_addr) {
|
||||
redisContext *c = redisContextInit();
|
||||
c->flags &= ~REDIS_BLOCK;
|
||||
redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
|
||||
return c;
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, ip, port);
|
||||
options.endpoint.tcp.source_addr = source_addr;
|
||||
options.options |= REDIS_OPT_NONBLOCK;
|
||||
return redisConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
|
||||
const char *source_addr) {
|
||||
redisContext *c = redisContextInit();
|
||||
c->flags &= ~REDIS_BLOCK;
|
||||
c->flags |= REDIS_REUSEADDR;
|
||||
redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
|
||||
return c;
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, ip, port);
|
||||
options.endpoint.tcp.source_addr = source_addr;
|
||||
options.options |= REDIS_OPT_NONBLOCK|REDIS_OPT_REUSEADDR;
|
||||
return redisConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
redisContext *redisConnectUnix(const char *path) {
|
||||
redisContext *c;
|
||||
|
||||
c = redisContextInit();
|
||||
if (c == NULL)
|
||||
return NULL;
|
||||
|
||||
c->flags |= REDIS_BLOCK;
|
||||
redisContextConnectUnix(c,path,NULL);
|
||||
return c;
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_UNIX(&options, path);
|
||||
return redisConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) {
|
||||
redisContext *c;
|
||||
|
||||
c = redisContextInit();
|
||||
if (c == NULL)
|
||||
return NULL;
|
||||
|
||||
c->flags |= REDIS_BLOCK;
|
||||
redisContextConnectUnix(c,path,&tv);
|
||||
return c;
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_UNIX(&options, path);
|
||||
options.timeout = &tv;
|
||||
return redisConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
redisContext *redisConnectUnixNonBlock(const char *path) {
|
||||
redisContext *c;
|
||||
|
||||
c = redisContextInit();
|
||||
if (c == NULL)
|
||||
return NULL;
|
||||
|
||||
c->flags &= ~REDIS_BLOCK;
|
||||
redisContextConnectUnix(c,path,NULL);
|
||||
return c;
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_UNIX(&options, path);
|
||||
options.options |= REDIS_OPT_NONBLOCK;
|
||||
return redisConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
redisContext *redisConnectFd(int fd) {
|
||||
redisContext *c;
|
||||
|
||||
c = redisContextInit();
|
||||
if (c == NULL)
|
||||
return NULL;
|
||||
|
||||
c->fd = fd;
|
||||
c->flags |= REDIS_BLOCK | REDIS_CONNECTED;
|
||||
return c;
|
||||
redisContext *redisConnectFd(redisFD fd) {
|
||||
redisOptions options = {0};
|
||||
options.type = REDIS_CONN_USERFD;
|
||||
options.endpoint.fd = fd;
|
||||
return redisConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
/* Set read/write timeout on a blocking socket. */
|
||||
@ -789,7 +868,7 @@ int redisEnableKeepAlive(redisContext *c) {
|
||||
/* Use this function to handle a read event on the descriptor. It will try
|
||||
* and read some bytes from the socket and feed them to the reply parser.
|
||||
*
|
||||
* After this function is called, you may use redisContextReadReply to
|
||||
* After this function is called, you may use redisGetReplyFromReader to
|
||||
* see if there is a reply available. */
|
||||
int redisBufferRead(redisContext *c) {
|
||||
char buf[1024*16];
|
||||
@ -799,22 +878,15 @@ int redisBufferRead(redisContext *c) {
|
||||
if (c->err)
|
||||
return REDIS_ERR;
|
||||
|
||||
nread = read(c->fd,buf,sizeof(buf));
|
||||
if (nread == -1) {
|
||||
if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
|
||||
/* Try again later */
|
||||
nread = c->funcs->read(c, buf, sizeof(buf));
|
||||
if (nread > 0) {
|
||||
if (redisReaderFeed(c->reader, buf, nread) != REDIS_OK) {
|
||||
__redisSetError(c, c->reader->err, c->reader->errstr);
|
||||
return REDIS_ERR;
|
||||
} else {
|
||||
__redisSetError(c,REDIS_ERR_IO,NULL);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
} else if (nread == 0) {
|
||||
__redisSetError(c,REDIS_ERR_EOF,"Server closed the connection");
|
||||
} else if (nread < 0) {
|
||||
return REDIS_ERR;
|
||||
} else {
|
||||
if (redisReaderFeed(c->reader,buf,nread) != REDIS_OK) {
|
||||
__redisSetError(c,c->reader->err,c->reader->errstr);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
}
|
||||
return REDIS_OK;
|
||||
}
|
||||
@ -829,21 +901,15 @@ int redisBufferRead(redisContext *c) {
|
||||
* c->errstr to hold the appropriate error string.
|
||||
*/
|
||||
int redisBufferWrite(redisContext *c, int *done) {
|
||||
int nwritten;
|
||||
|
||||
/* Return early when the context has seen an error. */
|
||||
if (c->err)
|
||||
return REDIS_ERR;
|
||||
|
||||
if (sdslen(c->obuf) > 0) {
|
||||
nwritten = write(c->fd,c->obuf,sdslen(c->obuf));
|
||||
if (nwritten == -1) {
|
||||
if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
|
||||
/* Try again later */
|
||||
} else {
|
||||
__redisSetError(c,REDIS_ERR_IO,NULL);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
int nwritten = c->funcs->write(c);
|
||||
if (nwritten < 0) {
|
||||
return REDIS_ERR;
|
||||
} else if (nwritten > 0) {
|
||||
if (nwritten == (signed)sdslen(c->obuf)) {
|
||||
sdsfree(c->obuf);
|
||||
@ -1007,9 +1073,8 @@ void *redisvCommand(redisContext *c, const char *format, va_list ap) {
|
||||
|
||||
void *redisCommand(redisContext *c, const char *format, ...) {
|
||||
va_list ap;
|
||||
void *reply = NULL;
|
||||
va_start(ap,format);
|
||||
reply = redisvCommand(c,format,ap);
|
||||
void *reply = redisvCommand(c,format,ap);
|
||||
va_end(ap);
|
||||
return reply;
|
||||
}
|
||||
|
140
deps/hiredis/hiredis.h
vendored
140
deps/hiredis/hiredis.h
vendored
@ -35,14 +35,18 @@
|
||||
#define __HIREDIS_H
|
||||
#include "read.h"
|
||||
#include <stdarg.h> /* for va_list */
|
||||
#ifndef _MSC_VER
|
||||
#include <sys/time.h> /* for struct timeval */
|
||||
#else
|
||||
struct timeval; /* forward declaration */
|
||||
#endif
|
||||
#include <stdint.h> /* uintXX_t, etc */
|
||||
#include "sds.h" /* for sds */
|
||||
|
||||
#define HIREDIS_MAJOR 0
|
||||
#define HIREDIS_MINOR 13
|
||||
#define HIREDIS_PATCH 3
|
||||
#define HIREDIS_SONAME 0.13
|
||||
#define HIREDIS_MINOR 14
|
||||
#define HIREDIS_PATCH 0
|
||||
#define HIREDIS_SONAME 0.14
|
||||
|
||||
/* Connection type can be blocking or non-blocking and is set in the
|
||||
* least significant bit of the flags field in redisContext. */
|
||||
@ -74,36 +78,18 @@
|
||||
/* Flag that is set when we should set SO_REUSEADDR before calling bind() */
|
||||
#define REDIS_REUSEADDR 0x80
|
||||
|
||||
/**
|
||||
* Flag that indicates the user does not want the context to
|
||||
* be automatically freed upon error
|
||||
*/
|
||||
#define REDIS_NO_AUTO_FREE 0x200
|
||||
|
||||
#define REDIS_KEEPALIVE_INTERVAL 15 /* seconds */
|
||||
|
||||
/* number of times we retry to connect in the case of EADDRNOTAVAIL and
|
||||
* SO_REUSEADDR is being used. */
|
||||
#define REDIS_CONNECT_RETRIES 10
|
||||
|
||||
/* strerror_r has two completely different prototypes and behaviors
|
||||
* depending on system issues, so we need to operate on the error buffer
|
||||
* differently depending on which strerror_r we're using. */
|
||||
#ifndef _GNU_SOURCE
|
||||
/* "regular" POSIX strerror_r that does the right thing. */
|
||||
#define __redis_strerror_r(errno, buf, len) \
|
||||
do { \
|
||||
strerror_r((errno), (buf), (len)); \
|
||||
} while (0)
|
||||
#else
|
||||
/* "bad" GNU strerror_r we need to clean up after. */
|
||||
#define __redis_strerror_r(errno, buf, len) \
|
||||
do { \
|
||||
char *err_str = strerror_r((errno), (buf), (len)); \
|
||||
/* If return value _isn't_ the start of the buffer we passed in, \
|
||||
* then GNU strerror_r returned an internal static buffer and we \
|
||||
* need to copy the result into our private buffer. */ \
|
||||
if (err_str != (buf)) { \
|
||||
strncpy((buf), err_str, ((len) - 1)); \
|
||||
buf[(len)-1] = '\0'; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -112,8 +98,12 @@ extern "C" {
|
||||
typedef struct redisReply {
|
||||
int type; /* REDIS_REPLY_* */
|
||||
long long integer; /* The integer when type is REDIS_REPLY_INTEGER */
|
||||
double dval; /* The double when type is REDIS_REPLY_DOUBLE */
|
||||
size_t len; /* Length of string */
|
||||
char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */
|
||||
char *str; /* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING
|
||||
and REDIS_REPLY_DOUBLE (in additionl to dval). */
|
||||
char vtype[4]; /* Used for REDIS_REPLY_VERB, contains the null
|
||||
terminated 3 character content type, such as "txt". */
|
||||
size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */
|
||||
struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
|
||||
} redisReply;
|
||||
@ -133,14 +123,93 @@ void redisFreeSdsCommand(sds cmd);
|
||||
|
||||
enum redisConnectionType {
|
||||
REDIS_CONN_TCP,
|
||||
REDIS_CONN_UNIX
|
||||
REDIS_CONN_UNIX,
|
||||
REDIS_CONN_USERFD
|
||||
};
|
||||
|
||||
struct redisSsl;
|
||||
|
||||
#define REDIS_OPT_NONBLOCK 0x01
|
||||
#define REDIS_OPT_REUSEADDR 0x02
|
||||
|
||||
/**
|
||||
* Don't automatically free the async object on a connection failure,
|
||||
* or other implicit conditions. Only free on an explicit call to disconnect() or free()
|
||||
*/
|
||||
#define REDIS_OPT_NOAUTOFREE 0x04
|
||||
|
||||
/* In Unix systems a file descriptor is a regular signed int, with -1
|
||||
* representing an invalid descriptor. In Windows it is a SOCKET
|
||||
* (32- or 64-bit unsigned integer depending on the architecture), where
|
||||
* all bits set (~0) is INVALID_SOCKET. */
|
||||
#ifndef _WIN32
|
||||
typedef int redisFD;
|
||||
#define REDIS_INVALID_FD -1
|
||||
#else
|
||||
#ifdef _WIN64
|
||||
typedef unsigned long long redisFD; /* SOCKET = 64-bit UINT_PTR */
|
||||
#else
|
||||
typedef unsigned long redisFD; /* SOCKET = 32-bit UINT_PTR */
|
||||
#endif
|
||||
#define REDIS_INVALID_FD ((redisFD)(~0)) /* INVALID_SOCKET */
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
/*
|
||||
* the type of connection to use. This also indicates which
|
||||
* `endpoint` member field to use
|
||||
*/
|
||||
int type;
|
||||
/* bit field of REDIS_OPT_xxx */
|
||||
int options;
|
||||
/* timeout value. if NULL, no timeout is used */
|
||||
const struct timeval *timeout;
|
||||
union {
|
||||
/** use this field for tcp/ip connections */
|
||||
struct {
|
||||
const char *source_addr;
|
||||
const char *ip;
|
||||
int port;
|
||||
} tcp;
|
||||
/** use this field for unix domain sockets */
|
||||
const char *unix_socket;
|
||||
/**
|
||||
* use this field to have hiredis operate an already-open
|
||||
* file descriptor */
|
||||
redisFD fd;
|
||||
} endpoint;
|
||||
} redisOptions;
|
||||
|
||||
/**
|
||||
* Helper macros to initialize options to their specified fields.
|
||||
*/
|
||||
#define REDIS_OPTIONS_SET_TCP(opts, ip_, port_) \
|
||||
(opts)->type = REDIS_CONN_TCP; \
|
||||
(opts)->endpoint.tcp.ip = ip_; \
|
||||
(opts)->endpoint.tcp.port = port_;
|
||||
|
||||
#define REDIS_OPTIONS_SET_UNIX(opts, path) \
|
||||
(opts)->type = REDIS_CONN_UNIX; \
|
||||
(opts)->endpoint.unix_socket = path;
|
||||
|
||||
struct redisAsyncContext;
|
||||
struct redisContext;
|
||||
|
||||
typedef struct redisContextFuncs {
|
||||
void (*free_privdata)(void *);
|
||||
void (*async_read)(struct redisAsyncContext *);
|
||||
void (*async_write)(struct redisAsyncContext *);
|
||||
int (*read)(struct redisContext *, char *, size_t);
|
||||
int (*write)(struct redisContext *);
|
||||
} redisContextFuncs;
|
||||
|
||||
/* Context for a connection to Redis */
|
||||
typedef struct redisContext {
|
||||
const redisContextFuncs *funcs; /* Function table */
|
||||
|
||||
int err; /* Error flags, 0 when there is no error */
|
||||
char errstr[128]; /* String representation of error when applicable */
|
||||
int fd;
|
||||
redisFD fd;
|
||||
int flags;
|
||||
char *obuf; /* Write buffer */
|
||||
redisReader *reader; /* Protocol reader */
|
||||
@ -158,8 +227,15 @@ typedef struct redisContext {
|
||||
char *path;
|
||||
} unix_sock;
|
||||
|
||||
/* For non-blocking connect */
|
||||
struct sockadr *saddr;
|
||||
size_t addrlen;
|
||||
|
||||
/* Additional private data for hiredis addons such as SSL */
|
||||
void *privdata;
|
||||
} redisContext;
|
||||
|
||||
redisContext *redisConnectWithOptions(const redisOptions *options);
|
||||
redisContext *redisConnect(const char *ip, int port);
|
||||
redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv);
|
||||
redisContext *redisConnectNonBlock(const char *ip, int port);
|
||||
@ -170,7 +246,7 @@ redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
|
||||
redisContext *redisConnectUnix(const char *path);
|
||||
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv);
|
||||
redisContext *redisConnectUnixNonBlock(const char *path);
|
||||
redisContext *redisConnectFd(int fd);
|
||||
redisContext *redisConnectFd(redisFD fd);
|
||||
|
||||
/**
|
||||
* Reconnect the given context using the saved information.
|
||||
@ -186,7 +262,7 @@ int redisReconnect(redisContext *c);
|
||||
int redisSetTimeout(redisContext *c, const struct timeval tv);
|
||||
int redisEnableKeepAlive(redisContext *c);
|
||||
void redisFree(redisContext *c);
|
||||
int redisFreeKeepFd(redisContext *c);
|
||||
redisFD redisFreeKeepFd(redisContext *c);
|
||||
int redisBufferRead(redisContext *c);
|
||||
int redisBufferWrite(redisContext *c, int *done);
|
||||
|
||||
|
11
deps/hiredis/hiredis.pc.in
vendored
Normal file
11
deps/hiredis/hiredis.pc.in
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${exec_prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
pkgincludedir=${includedir}/hiredis
|
||||
|
||||
Name: hiredis
|
||||
Description: Minimalistic C client library for Redis.
|
||||
Version: @PROJECT_VERSION@
|
||||
Libs: -L${libdir} -lhiredis
|
||||
Cflags: -I${pkgincludedir} -D_FILE_OFFSET_BITS=64
|
53
deps/hiredis/hiredis_ssl.h
vendored
Normal file
53
deps/hiredis/hiredis_ssl.h
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019, Redis Labs
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __HIREDIS_SSL_H
|
||||
#define __HIREDIS_SSL_H
|
||||
|
||||
/* This is the underlying struct for SSL in ssl.h, which is not included to
|
||||
* keep build dependencies short here.
|
||||
*/
|
||||
struct ssl_st;
|
||||
|
||||
/**
|
||||
* Secure the connection using SSL. This should be done before any command is
|
||||
* executed on the connection.
|
||||
*/
|
||||
int redisSecureConnection(redisContext *c, const char *capath, const char *certpath,
|
||||
const char *keypath, const char *servername);
|
||||
|
||||
/**
|
||||
* Initiate SSL/TLS negotiation on a provided context.
|
||||
*/
|
||||
|
||||
int redisInitiateSSL(redisContext *c, struct ssl_st *ssl);
|
||||
|
||||
#endif /* __HIREDIS_SSL_H */
|
12
deps/hiredis/hiredis_ssl.pc.in
vendored
Normal file
12
deps/hiredis/hiredis_ssl.pc.in
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${exec_prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
pkgincludedir=${includedir}/hiredis
|
||||
|
||||
Name: hiredis_ssl
|
||||
Description: SSL Support for hiredis.
|
||||
Version: @PROJECT_VERSION@
|
||||
Requires: hiredis
|
||||
Libs: -L${libdir} -lhiredis_ssl
|
||||
Libs.private: -lssl -lcrypto
|
189
deps/hiredis/net.c
vendored
189
deps/hiredis/net.c
vendored
@ -34,43 +34,72 @@
|
||||
|
||||
#include "fmacros.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <poll.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "net.h"
|
||||
#include "sds.h"
|
||||
#include "sockcompat.h"
|
||||
#include "win32.h"
|
||||
|
||||
/* Defined in hiredis.c */
|
||||
void __redisSetError(redisContext *c, int type, const char *str);
|
||||
|
||||
static void redisContextCloseFd(redisContext *c) {
|
||||
if (c && c->fd >= 0) {
|
||||
void redisNetClose(redisContext *c) {
|
||||
if (c && c->fd != REDIS_INVALID_FD) {
|
||||
close(c->fd);
|
||||
c->fd = -1;
|
||||
c->fd = REDIS_INVALID_FD;
|
||||
}
|
||||
}
|
||||
|
||||
int redisNetRead(redisContext *c, char *buf, size_t bufcap) {
|
||||
int nread = recv(c->fd, buf, bufcap, 0);
|
||||
if (nread == -1) {
|
||||
if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
|
||||
/* Try again later */
|
||||
return 0;
|
||||
} else if(errno == ETIMEDOUT && (c->flags & REDIS_BLOCK)) {
|
||||
/* especially in windows */
|
||||
__redisSetError(c, REDIS_ERR_TIMEOUT, "recv timeout");
|
||||
return -1;
|
||||
} else {
|
||||
__redisSetError(c, REDIS_ERR_IO, NULL);
|
||||
return -1;
|
||||
}
|
||||
} else if (nread == 0) {
|
||||
__redisSetError(c, REDIS_ERR_EOF, "Server closed the connection");
|
||||
return -1;
|
||||
} else {
|
||||
return nread;
|
||||
}
|
||||
}
|
||||
|
||||
int redisNetWrite(redisContext *c) {
|
||||
int nwritten = send(c->fd, c->obuf, sdslen(c->obuf), 0);
|
||||
if (nwritten < 0) {
|
||||
if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
|
||||
/* Try again later */
|
||||
} else {
|
||||
__redisSetError(c, REDIS_ERR_IO, NULL);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
static void __redisSetErrorFromErrno(redisContext *c, int type, const char *prefix) {
|
||||
int errorno = errno; /* snprintf() may change errno */
|
||||
char buf[128] = { 0 };
|
||||
size_t len = 0;
|
||||
|
||||
if (prefix != NULL)
|
||||
len = snprintf(buf,sizeof(buf),"%s: ",prefix);
|
||||
__redis_strerror_r(errno, (char *)(buf + len), sizeof(buf) - len);
|
||||
strerror_r(errorno, (char *)(buf + len), sizeof(buf) - len);
|
||||
__redisSetError(c,type,buf);
|
||||
}
|
||||
|
||||
@ -78,15 +107,15 @@ static int redisSetReuseAddr(redisContext *c) {
|
||||
int on = 1;
|
||||
if (setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
||||
redisContextCloseFd(c);
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
static int redisCreateSocket(redisContext *c, int type) {
|
||||
int s;
|
||||
if ((s = socket(type, SOCK_STREAM, 0)) == -1) {
|
||||
redisFD s;
|
||||
if ((s = socket(type, SOCK_STREAM, 0)) == REDIS_INVALID_FD) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
@ -100,6 +129,7 @@ static int redisCreateSocket(redisContext *c, int type) {
|
||||
}
|
||||
|
||||
static int redisSetBlocking(redisContext *c, int blocking) {
|
||||
#ifndef _WIN32
|
||||
int flags;
|
||||
|
||||
/* Set the socket nonblocking.
|
||||
@ -107,7 +137,7 @@ static int redisSetBlocking(redisContext *c, int blocking) {
|
||||
* interrupted by a signal. */
|
||||
if ((flags = fcntl(c->fd, F_GETFL)) == -1) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_GETFL)");
|
||||
redisContextCloseFd(c);
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
@ -118,15 +148,23 @@ static int redisSetBlocking(redisContext *c, int blocking) {
|
||||
|
||||
if (fcntl(c->fd, F_SETFL, flags) == -1) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_SETFL)");
|
||||
redisContextCloseFd(c);
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
#else
|
||||
u_long mode = blocking ? 0 : 1;
|
||||
if (ioctl(c->fd, FIONBIO, &mode) == -1) {
|
||||
__redisSetErrorFromErrno(c, REDIS_ERR_IO, "ioctl(FIONBIO)");
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
int redisKeepAlive(redisContext *c, int interval) {
|
||||
int val = 1;
|
||||
int fd = c->fd;
|
||||
redisFD fd = c->fd;
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1){
|
||||
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
||||
@ -135,14 +173,13 @@ int redisKeepAlive(redisContext *c, int interval) {
|
||||
|
||||
val = interval;
|
||||
|
||||
#ifdef _OSX
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0) {
|
||||
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
||||
return REDIS_ERR;
|
||||
}
|
||||
#else
|
||||
#if defined(__GLIBC__) && !defined(__FreeBSD_kernel__)
|
||||
val = interval;
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) {
|
||||
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
||||
return REDIS_ERR;
|
||||
@ -170,7 +207,7 @@ static int redisSetTcpNoDelay(redisContext *c) {
|
||||
int yes = 1;
|
||||
if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(TCP_NODELAY)");
|
||||
redisContextCloseFd(c);
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
return REDIS_OK;
|
||||
@ -212,28 +249,50 @@ static int redisContextWaitReady(redisContext *c, long msec) {
|
||||
|
||||
if ((res = poll(wfd, 1, msec)) == -1) {
|
||||
__redisSetErrorFromErrno(c, REDIS_ERR_IO, "poll(2)");
|
||||
redisContextCloseFd(c);
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
} else if (res == 0) {
|
||||
errno = ETIMEDOUT;
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
||||
redisContextCloseFd(c);
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if (redisCheckSocketError(c) != REDIS_OK)
|
||||
if (redisCheckConnectDone(c, &res) != REDIS_OK || res == 0) {
|
||||
redisCheckSocketError(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
||||
redisContextCloseFd(c);
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
int redisCheckConnectDone(redisContext *c, int *completed) {
|
||||
int rc = connect(c->fd, (const struct sockaddr *)c->saddr, c->addrlen);
|
||||
if (rc == 0) {
|
||||
*completed = 1;
|
||||
return REDIS_OK;
|
||||
}
|
||||
switch (errno) {
|
||||
case EISCONN:
|
||||
*completed = 1;
|
||||
return REDIS_OK;
|
||||
case EALREADY:
|
||||
case EINPROGRESS:
|
||||
case EWOULDBLOCK:
|
||||
*completed = 0;
|
||||
return REDIS_OK;
|
||||
default:
|
||||
return REDIS_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
int redisCheckSocketError(redisContext *c) {
|
||||
int err = 0;
|
||||
int err = 0, errno_saved = errno;
|
||||
socklen_t errlen = sizeof(err);
|
||||
|
||||
if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
|
||||
@ -241,6 +300,10 @@ int redisCheckSocketError(redisContext *c) {
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if (err == 0) {
|
||||
err = errno_saved;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
errno = err;
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
||||
@ -251,11 +314,18 @@ int redisCheckSocketError(redisContext *c) {
|
||||
}
|
||||
|
||||
int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
|
||||
if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)) == -1) {
|
||||
const void *to_ptr = &tv;
|
||||
size_t to_sz = sizeof(tv);
|
||||
#ifdef _WIN32
|
||||
DWORD timeout_msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
to_ptr = &timeout_msec;
|
||||
to_sz = sizeof(timeout_msec);
|
||||
#endif
|
||||
if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,to_ptr,to_sz) == -1) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_RCVTIMEO)");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
if (setsockopt(c->fd,SOL_SOCKET,SO_SNDTIMEO,&tv,sizeof(tv)) == -1) {
|
||||
if (setsockopt(c->fd,SOL_SOCKET,SO_SNDTIMEO,to_ptr,to_sz) == -1) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_SNDTIMEO)");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
@ -265,7 +335,8 @@ int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
|
||||
static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
|
||||
const struct timeval *timeout,
|
||||
const char *source_addr) {
|
||||
int s, rv, n;
|
||||
redisFD s;
|
||||
int rv, n;
|
||||
char _port[6]; /* strlen("65535"); */
|
||||
struct addrinfo hints, *servinfo, *bservinfo, *p, *b;
|
||||
int blocking = (c->flags & REDIS_BLOCK);
|
||||
@ -285,8 +356,7 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
|
||||
* This is a bit ugly, but atleast it works and doesn't leak memory.
|
||||
**/
|
||||
if (c->tcp.host != addr) {
|
||||
if (c->tcp.host)
|
||||
free(c->tcp.host);
|
||||
free(c->tcp.host);
|
||||
|
||||
c->tcp.host = strdup(addr);
|
||||
}
|
||||
@ -299,8 +369,7 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
|
||||
memcpy(c->timeout, timeout, sizeof(struct timeval));
|
||||
}
|
||||
} else {
|
||||
if (c->timeout)
|
||||
free(c->timeout);
|
||||
free(c->timeout);
|
||||
c->timeout = NULL;
|
||||
}
|
||||
|
||||
@ -336,7 +405,7 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
|
||||
}
|
||||
for (p = servinfo; p != NULL; p = p->ai_next) {
|
||||
addrretry:
|
||||
if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1)
|
||||
if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == REDIS_INVALID_FD)
|
||||
continue;
|
||||
|
||||
c->fd = s;
|
||||
@ -356,6 +425,7 @@ addrretry:
|
||||
n = 1;
|
||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*) &n,
|
||||
sizeof(n)) < 0) {
|
||||
freeaddrinfo(bservinfo);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
@ -374,20 +444,34 @@ addrretry:
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* For repeat connection */
|
||||
free(c->saddr);
|
||||
c->saddr = malloc(p->ai_addrlen);
|
||||
memcpy(c->saddr, p->ai_addr, p->ai_addrlen);
|
||||
c->addrlen = p->ai_addrlen;
|
||||
|
||||
if (connect(s,p->ai_addr,p->ai_addrlen) == -1) {
|
||||
if (errno == EHOSTUNREACH) {
|
||||
redisContextCloseFd(c);
|
||||
redisNetClose(c);
|
||||
continue;
|
||||
} else if (errno == EINPROGRESS && !blocking) {
|
||||
/* This is ok. */
|
||||
} else if (errno == EINPROGRESS) {
|
||||
if (blocking) {
|
||||
goto wait_for_ready;
|
||||
}
|
||||
/* This is ok.
|
||||
* Note that even when it's in blocking mode, we unset blocking
|
||||
* for `connect()`
|
||||
*/
|
||||
} else if (errno == EADDRNOTAVAIL && reuseaddr) {
|
||||
if (++reuses >= REDIS_CONNECT_RETRIES) {
|
||||
goto error;
|
||||
} else {
|
||||
redisContextCloseFd(c);
|
||||
redisNetClose(c);
|
||||
goto addrretry;
|
||||
}
|
||||
} else {
|
||||
wait_for_ready:
|
||||
if (redisContextWaitReady(c,timeout_msec) != REDIS_OK)
|
||||
goto error;
|
||||
}
|
||||
@ -411,7 +495,10 @@ addrretry:
|
||||
error:
|
||||
rv = REDIS_ERR;
|
||||
end:
|
||||
freeaddrinfo(servinfo);
|
||||
if(servinfo) {
|
||||
freeaddrinfo(servinfo);
|
||||
}
|
||||
|
||||
return rv; // Need to return REDIS_OK if alright
|
||||
}
|
||||
|
||||
@ -427,11 +514,12 @@ int redisContextConnectBindTcp(redisContext *c, const char *addr, int port,
|
||||
}
|
||||
|
||||
int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout) {
|
||||
#ifndef _WIN32
|
||||
int blocking = (c->flags & REDIS_BLOCK);
|
||||
struct sockaddr_un sa;
|
||||
struct sockaddr_un *sa;
|
||||
long timeout_msec = -1;
|
||||
|
||||
if (redisCreateSocket(c,AF_LOCAL) < 0)
|
||||
if (redisCreateSocket(c,AF_UNIX) < 0)
|
||||
return REDIS_ERR;
|
||||
if (redisSetBlocking(c,0) != REDIS_OK)
|
||||
return REDIS_ERR;
|
||||
@ -448,17 +536,18 @@ int redisContextConnectUnix(redisContext *c, const char *path, const struct time
|
||||
memcpy(c->timeout, timeout, sizeof(struct timeval));
|
||||
}
|
||||
} else {
|
||||
if (c->timeout)
|
||||
free(c->timeout);
|
||||
free(c->timeout);
|
||||
c->timeout = NULL;
|
||||
}
|
||||
|
||||
if (redisContextTimeoutMsec(c,&timeout_msec) != REDIS_OK)
|
||||
return REDIS_ERR;
|
||||
|
||||
sa.sun_family = AF_LOCAL;
|
||||
strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1);
|
||||
if (connect(c->fd, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
|
||||
sa = (struct sockaddr_un*)(c->saddr = malloc(sizeof(struct sockaddr_un)));
|
||||
c->addrlen = sizeof(struct sockaddr_un);
|
||||
sa->sun_family = AF_UNIX;
|
||||
strncpy(sa->sun_path, path, sizeof(sa->sun_path) - 1);
|
||||
if (connect(c->fd, (struct sockaddr*)sa, sizeof(*sa)) == -1) {
|
||||
if (errno == EINPROGRESS && !blocking) {
|
||||
/* This is ok. */
|
||||
} else {
|
||||
@ -473,4 +562,10 @@ int redisContextConnectUnix(redisContext *c, const char *path, const struct time
|
||||
|
||||
c->flags |= REDIS_CONNECTED;
|
||||
return REDIS_OK;
|
||||
#else
|
||||
/* We currently do not support Unix sockets for Windows. */
|
||||
/* TODO(m): https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/ */
|
||||
errno = EPROTONOSUPPORT;
|
||||
return REDIS_ERR;
|
||||
#endif /* _WIN32 */
|
||||
}
|
||||
|
7
deps/hiredis/net.h
vendored
7
deps/hiredis/net.h
vendored
@ -37,9 +37,9 @@
|
||||
|
||||
#include "hiredis.h"
|
||||
|
||||
#if defined(__sun)
|
||||
#define AF_LOCAL AF_UNIX
|
||||
#endif
|
||||
void redisNetClose(redisContext *c);
|
||||
int redisNetRead(redisContext *c, char *buf, size_t bufcap);
|
||||
int redisNetWrite(redisContext *c);
|
||||
|
||||
int redisCheckSocketError(redisContext *c);
|
||||
int redisContextSetTimeout(redisContext *c, const struct timeval tv);
|
||||
@ -49,5 +49,6 @@ int redisContextConnectBindTcp(redisContext *c, const char *addr, int port,
|
||||
const char *source_addr);
|
||||
int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout);
|
||||
int redisKeepAlive(redisContext *c, int interval);
|
||||
int redisCheckConnectDone(redisContext *c, int *completed);
|
||||
|
||||
#endif
|
||||
|
254
deps/hiredis/read.c
vendored
254
deps/hiredis/read.c
vendored
@ -29,19 +29,22 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include "fmacros.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "read.h"
|
||||
#include "sds.h"
|
||||
#include "win32.h"
|
||||
|
||||
static void __redisReaderSetError(redisReader *r, int type, const char *str) {
|
||||
size_t len;
|
||||
@ -52,11 +55,9 @@ static void __redisReaderSetError(redisReader *r, int type, const char *str) {
|
||||
}
|
||||
|
||||
/* Clear input buffer on errors. */
|
||||
if (r->buf != NULL) {
|
||||
sdsfree(r->buf);
|
||||
r->buf = NULL;
|
||||
r->pos = r->len = 0;
|
||||
}
|
||||
sdsfree(r->buf);
|
||||
r->buf = NULL;
|
||||
r->pos = r->len = 0;
|
||||
|
||||
/* Reset task stack. */
|
||||
r->ridx = -1;
|
||||
@ -143,33 +144,79 @@ static char *seekNewline(char *s, size_t len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Read a long long value starting at *s, under the assumption that it will be
|
||||
* terminated by \r\n. Ambiguously returns -1 for unexpected input. */
|
||||
static long long readLongLong(char *s) {
|
||||
long long v = 0;
|
||||
int dec, mult = 1;
|
||||
char c;
|
||||
/* Convert a string into a long long. Returns REDIS_OK if the string could be
|
||||
* parsed into a (non-overflowing) long long, REDIS_ERR otherwise. The value
|
||||
* will be set to the parsed value when appropriate.
|
||||
*
|
||||
* Note that this function demands that the string strictly represents
|
||||
* a long long: no spaces or other characters before or after the string
|
||||
* representing the number are accepted, nor zeroes at the start if not
|
||||
* for the string "0" representing the zero number.
|
||||
*
|
||||
* Because of its strictness, it is safe to use this function to check if
|
||||
* you can convert a string into a long long, and obtain back the string
|
||||
* from the number without any loss in the string representation. */
|
||||
static int string2ll(const char *s, size_t slen, long long *value) {
|
||||
const char *p = s;
|
||||
size_t plen = 0;
|
||||
int negative = 0;
|
||||
unsigned long long v;
|
||||
|
||||
if (*s == '-') {
|
||||
mult = -1;
|
||||
s++;
|
||||
} else if (*s == '+') {
|
||||
mult = 1;
|
||||
s++;
|
||||
if (plen == slen)
|
||||
return REDIS_ERR;
|
||||
|
||||
/* Special case: first and only digit is 0. */
|
||||
if (slen == 1 && p[0] == '0') {
|
||||
if (value != NULL) *value = 0;
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
while ((c = *(s++)) != '\r') {
|
||||
dec = c - '0';
|
||||
if (dec >= 0 && dec < 10) {
|
||||
v *= 10;
|
||||
v += dec;
|
||||
} else {
|
||||
/* Should not happen... */
|
||||
return -1;
|
||||
}
|
||||
if (p[0] == '-') {
|
||||
negative = 1;
|
||||
p++; plen++;
|
||||
|
||||
/* Abort on only a negative sign. */
|
||||
if (plen == slen)
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
return mult*v;
|
||||
/* First digit should be 1-9, otherwise the string should just be 0. */
|
||||
if (p[0] >= '1' && p[0] <= '9') {
|
||||
v = p[0]-'0';
|
||||
p++; plen++;
|
||||
} else if (p[0] == '0' && slen == 1) {
|
||||
*value = 0;
|
||||
return REDIS_OK;
|
||||
} else {
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
while (plen < slen && p[0] >= '0' && p[0] <= '9') {
|
||||
if (v > (ULLONG_MAX / 10)) /* Overflow. */
|
||||
return REDIS_ERR;
|
||||
v *= 10;
|
||||
|
||||
if (v > (ULLONG_MAX - (p[0]-'0'))) /* Overflow. */
|
||||
return REDIS_ERR;
|
||||
v += p[0]-'0';
|
||||
|
||||
p++; plen++;
|
||||
}
|
||||
|
||||
/* Return if not all bytes were used. */
|
||||
if (plen < slen)
|
||||
return REDIS_ERR;
|
||||
|
||||
if (negative) {
|
||||
if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */
|
||||
return REDIS_ERR;
|
||||
if (value != NULL) *value = -v;
|
||||
} else {
|
||||
if (v > LLONG_MAX) /* Overflow. */
|
||||
return REDIS_ERR;
|
||||
if (value != NULL) *value = v;
|
||||
}
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
static char *readLine(redisReader *r, int *_len) {
|
||||
@ -198,7 +245,9 @@ static void moveToNextTask(redisReader *r) {
|
||||
|
||||
cur = &(r->rstack[r->ridx]);
|
||||
prv = &(r->rstack[r->ridx-1]);
|
||||
assert(prv->type == REDIS_REPLY_ARRAY);
|
||||
assert(prv->type == REDIS_REPLY_ARRAY ||
|
||||
prv->type == REDIS_REPLY_MAP ||
|
||||
prv->type == REDIS_REPLY_SET);
|
||||
if (cur->idx == prv->elements-1) {
|
||||
r->ridx--;
|
||||
} else {
|
||||
@ -220,10 +269,58 @@ static int processLineItem(redisReader *r) {
|
||||
|
||||
if ((p = readLine(r,&len)) != NULL) {
|
||||
if (cur->type == REDIS_REPLY_INTEGER) {
|
||||
if (r->fn && r->fn->createInteger)
|
||||
obj = r->fn->createInteger(cur,readLongLong(p));
|
||||
else
|
||||
if (r->fn && r->fn->createInteger) {
|
||||
long long v;
|
||||
if (string2ll(p, len, &v) == REDIS_ERR) {
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
||||
"Bad integer value");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
obj = r->fn->createInteger(cur,v);
|
||||
} else {
|
||||
obj = (void*)REDIS_REPLY_INTEGER;
|
||||
}
|
||||
} else if (cur->type == REDIS_REPLY_DOUBLE) {
|
||||
if (r->fn && r->fn->createDouble) {
|
||||
char buf[326], *eptr;
|
||||
double d;
|
||||
|
||||
if ((size_t)len >= sizeof(buf)) {
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
||||
"Double value is too large");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
memcpy(buf,p,len);
|
||||
buf[len] = '\0';
|
||||
|
||||
if (strcasecmp(buf,",inf") == 0) {
|
||||
d = INFINITY; /* Positive infinite. */
|
||||
} else if (strcasecmp(buf,",-inf") == 0) {
|
||||
d = -INFINITY; /* Nevative infinite. */
|
||||
} else {
|
||||
d = strtod((char*)buf,&eptr);
|
||||
if (buf[0] == '\0' || eptr[0] != '\0' || isnan(d)) {
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
||||
"Bad double value");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
}
|
||||
obj = r->fn->createDouble(cur,d,buf,len);
|
||||
} else {
|
||||
obj = (void*)REDIS_REPLY_DOUBLE;
|
||||
}
|
||||
} else if (cur->type == REDIS_REPLY_NIL) {
|
||||
if (r->fn && r->fn->createNil)
|
||||
obj = r->fn->createNil(cur);
|
||||
else
|
||||
obj = (void*)REDIS_REPLY_NIL;
|
||||
} else if (cur->type == REDIS_REPLY_BOOL) {
|
||||
int bval = p[0] == 't' || p[0] == 'T';
|
||||
if (r->fn && r->fn->createBool)
|
||||
obj = r->fn->createBool(cur,bval);
|
||||
else
|
||||
obj = (void*)REDIS_REPLY_BOOL;
|
||||
} else {
|
||||
/* Type will be error or status. */
|
||||
if (r->fn && r->fn->createString)
|
||||
@ -250,7 +347,7 @@ static int processBulkItem(redisReader *r) {
|
||||
redisReadTask *cur = &(r->rstack[r->ridx]);
|
||||
void *obj = NULL;
|
||||
char *p, *s;
|
||||
long len;
|
||||
long long len;
|
||||
unsigned long bytelen;
|
||||
int success = 0;
|
||||
|
||||
@ -259,9 +356,20 @@ static int processBulkItem(redisReader *r) {
|
||||
if (s != NULL) {
|
||||
p = r->buf+r->pos;
|
||||
bytelen = s-(r->buf+r->pos)+2; /* include \r\n */
|
||||
len = readLongLong(p);
|
||||
|
||||
if (len < 0) {
|
||||
if (string2ll(p, bytelen - 2, &len) == REDIS_ERR) {
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
||||
"Bad bulk string length");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if (len < -1 || (LLONG_MAX > SIZE_MAX && len > (long long)SIZE_MAX)) {
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
||||
"Bulk string length out of range");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if (len == -1) {
|
||||
/* The nil object can always be created. */
|
||||
if (r->fn && r->fn->createNil)
|
||||
obj = r->fn->createNil(cur);
|
||||
@ -272,10 +380,18 @@ static int processBulkItem(redisReader *r) {
|
||||
/* Only continue when the buffer contains the entire bulk item. */
|
||||
bytelen += len+2; /* include \r\n */
|
||||
if (r->pos+bytelen <= r->len) {
|
||||
if ((cur->type == REDIS_REPLY_VERB && len < 4) ||
|
||||
(cur->type == REDIS_REPLY_VERB && s[5] != ':'))
|
||||
{
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
||||
"Verbatim string 4 bytes of content type are "
|
||||
"missing or incorrectly encoded.");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
if (r->fn && r->fn->createString)
|
||||
obj = r->fn->createString(cur,s+2,len);
|
||||
else
|
||||
obj = (void*)REDIS_REPLY_STRING;
|
||||
obj = (void*)(long)cur->type;
|
||||
success = 1;
|
||||
}
|
||||
}
|
||||
@ -299,12 +415,13 @@ static int processBulkItem(redisReader *r) {
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
static int processMultiBulkItem(redisReader *r) {
|
||||
/* Process the array, map and set types. */
|
||||
static int processAggregateItem(redisReader *r) {
|
||||
redisReadTask *cur = &(r->rstack[r->ridx]);
|
||||
void *obj;
|
||||
char *p;
|
||||
long elements;
|
||||
int root = 0;
|
||||
long long elements;
|
||||
int root = 0, len;
|
||||
|
||||
/* Set error for nested multi bulks with depth > 7 */
|
||||
if (r->ridx == 8) {
|
||||
@ -313,10 +430,21 @@ static int processMultiBulkItem(redisReader *r) {
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if ((p = readLine(r,NULL)) != NULL) {
|
||||
elements = readLongLong(p);
|
||||
if ((p = readLine(r,&len)) != NULL) {
|
||||
if (string2ll(p, len, &elements) == REDIS_ERR) {
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
||||
"Bad multi-bulk length");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
root = (r->ridx == 0);
|
||||
|
||||
if (elements < -1 || (LLONG_MAX > SIZE_MAX && elements > SIZE_MAX)) {
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
||||
"Multi-bulk length out of range");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if (elements == -1) {
|
||||
if (r->fn && r->fn->createNil)
|
||||
obj = r->fn->createNil(cur);
|
||||
@ -330,10 +458,12 @@ static int processMultiBulkItem(redisReader *r) {
|
||||
|
||||
moveToNextTask(r);
|
||||
} else {
|
||||
if (cur->type == REDIS_REPLY_MAP) elements *= 2;
|
||||
|
||||
if (r->fn && r->fn->createArray)
|
||||
obj = r->fn->createArray(cur,elements);
|
||||
else
|
||||
obj = (void*)REDIS_REPLY_ARRAY;
|
||||
obj = (void*)(long)cur->type;
|
||||
|
||||
if (obj == NULL) {
|
||||
__redisReaderSetErrorOOM(r);
|
||||
@ -381,12 +511,30 @@ static int processItem(redisReader *r) {
|
||||
case ':':
|
||||
cur->type = REDIS_REPLY_INTEGER;
|
||||
break;
|
||||
case ',':
|
||||
cur->type = REDIS_REPLY_DOUBLE;
|
||||
break;
|
||||
case '_':
|
||||
cur->type = REDIS_REPLY_NIL;
|
||||
break;
|
||||
case '$':
|
||||
cur->type = REDIS_REPLY_STRING;
|
||||
break;
|
||||
case '*':
|
||||
cur->type = REDIS_REPLY_ARRAY;
|
||||
break;
|
||||
case '%':
|
||||
cur->type = REDIS_REPLY_MAP;
|
||||
break;
|
||||
case '~':
|
||||
cur->type = REDIS_REPLY_SET;
|
||||
break;
|
||||
case '#':
|
||||
cur->type = REDIS_REPLY_BOOL;
|
||||
break;
|
||||
case '=':
|
||||
cur->type = REDIS_REPLY_VERB;
|
||||
break;
|
||||
default:
|
||||
__redisReaderSetErrorProtocolByte(r,*p);
|
||||
return REDIS_ERR;
|
||||
@ -402,11 +550,17 @@ static int processItem(redisReader *r) {
|
||||
case REDIS_REPLY_ERROR:
|
||||
case REDIS_REPLY_STATUS:
|
||||
case REDIS_REPLY_INTEGER:
|
||||
case REDIS_REPLY_DOUBLE:
|
||||
case REDIS_REPLY_NIL:
|
||||
case REDIS_REPLY_BOOL:
|
||||
return processLineItem(r);
|
||||
case REDIS_REPLY_STRING:
|
||||
case REDIS_REPLY_VERB:
|
||||
return processBulkItem(r);
|
||||
case REDIS_REPLY_ARRAY:
|
||||
return processMultiBulkItem(r);
|
||||
case REDIS_REPLY_MAP:
|
||||
case REDIS_REPLY_SET:
|
||||
return processAggregateItem(r);
|
||||
default:
|
||||
assert(NULL);
|
||||
return REDIS_ERR; /* Avoid warning. */
|
||||
@ -416,12 +570,10 @@ static int processItem(redisReader *r) {
|
||||
redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) {
|
||||
redisReader *r;
|
||||
|
||||
r = calloc(sizeof(redisReader),1);
|
||||
r = calloc(1,sizeof(redisReader));
|
||||
if (r == NULL)
|
||||
return NULL;
|
||||
|
||||
r->err = 0;
|
||||
r->errstr[0] = '\0';
|
||||
r->fn = fn;
|
||||
r->buf = sdsempty();
|
||||
r->maxbuf = REDIS_READER_MAX_BUF;
|
||||
@ -435,10 +587,11 @@ redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) {
|
||||
}
|
||||
|
||||
void redisReaderFree(redisReader *r) {
|
||||
if (r == NULL)
|
||||
return;
|
||||
if (r->reply != NULL && r->fn && r->fn->freeObject)
|
||||
r->fn->freeObject(r->reply);
|
||||
if (r->buf != NULL)
|
||||
sdsfree(r->buf);
|
||||
sdsfree(r->buf);
|
||||
free(r);
|
||||
}
|
||||
|
||||
@ -517,8 +670,11 @@ int redisReaderGetReply(redisReader *r, void **reply) {
|
||||
|
||||
/* Emit a reply when there is one. */
|
||||
if (r->ridx == -1) {
|
||||
if (reply != NULL)
|
||||
if (reply != NULL) {
|
||||
*reply = r->reply;
|
||||
} else if (r->reply != NULL && r->fn && r->fn->freeObject) {
|
||||
r->fn->freeObject(r->reply);
|
||||
}
|
||||
r->reply = NULL;
|
||||
}
|
||||
return REDIS_OK;
|
||||
|
13
deps/hiredis/read.h
vendored
13
deps/hiredis/read.h
vendored
@ -45,6 +45,7 @@
|
||||
#define REDIS_ERR_EOF 3 /* End of file */
|
||||
#define REDIS_ERR_PROTOCOL 4 /* Protocol error */
|
||||
#define REDIS_ERR_OOM 5 /* Out of memory */
|
||||
#define REDIS_ERR_TIMEOUT 6 /* Timed out */
|
||||
#define REDIS_ERR_OTHER 2 /* Everything else... */
|
||||
|
||||
#define REDIS_REPLY_STRING 1
|
||||
@ -53,6 +54,14 @@
|
||||
#define REDIS_REPLY_NIL 4
|
||||
#define REDIS_REPLY_STATUS 5
|
||||
#define REDIS_REPLY_ERROR 6
|
||||
#define REDIS_REPLY_DOUBLE 7
|
||||
#define REDIS_REPLY_BOOL 8
|
||||
#define REDIS_REPLY_MAP 9
|
||||
#define REDIS_REPLY_SET 10
|
||||
#define REDIS_REPLY_ATTR 11
|
||||
#define REDIS_REPLY_PUSH 12
|
||||
#define REDIS_REPLY_BIGNUM 13
|
||||
#define REDIS_REPLY_VERB 14
|
||||
|
||||
#define REDIS_READER_MAX_BUF (1024*16) /* Default max unused reader buffer. */
|
||||
|
||||
@ -71,9 +80,11 @@ typedef struct redisReadTask {
|
||||
|
||||
typedef struct redisReplyObjectFunctions {
|
||||
void *(*createString)(const redisReadTask*, char*, size_t);
|
||||
void *(*createArray)(const redisReadTask*, int);
|
||||
void *(*createArray)(const redisReadTask*, size_t);
|
||||
void *(*createInteger)(const redisReadTask*, long long);
|
||||
void *(*createDouble)(const redisReadTask*, double, char*, size_t);
|
||||
void *(*createNil)(const redisReadTask*);
|
||||
void *(*createBool)(const redisReadTask*, int);
|
||||
void (*freeObject)(void*);
|
||||
} redisReplyObjectFunctions;
|
||||
|
||||
|
29
deps/hiredis/sds.c
vendored
29
deps/hiredis/sds.c
vendored
@ -219,7 +219,10 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {
|
||||
hdrlen = sdsHdrSize(type);
|
||||
if (oldtype==type) {
|
||||
newsh = s_realloc(sh, hdrlen+newlen+1);
|
||||
if (newsh == NULL) return NULL;
|
||||
if (newsh == NULL) {
|
||||
s_free(sh);
|
||||
return NULL;
|
||||
}
|
||||
s = (char*)newsh+hdrlen;
|
||||
} else {
|
||||
/* Since the header size changes, need to move the string forward,
|
||||
@ -592,6 +595,7 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
|
||||
/* Make sure there is always space for at least 1 char. */
|
||||
if (sdsavail(s)==0) {
|
||||
s = sdsMakeRoomFor(s,1);
|
||||
if (s == NULL) goto fmt_error;
|
||||
}
|
||||
|
||||
switch(*f) {
|
||||
@ -605,6 +609,7 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
|
||||
l = (next == 's') ? strlen(str) : sdslen(str);
|
||||
if (sdsavail(s) < l) {
|
||||
s = sdsMakeRoomFor(s,l);
|
||||
if (s == NULL) goto fmt_error;
|
||||
}
|
||||
memcpy(s+i,str,l);
|
||||
sdsinclen(s,l);
|
||||
@ -621,6 +626,7 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
|
||||
l = sdsll2str(buf,num);
|
||||
if (sdsavail(s) < l) {
|
||||
s = sdsMakeRoomFor(s,l);
|
||||
if (s == NULL) goto fmt_error;
|
||||
}
|
||||
memcpy(s+i,buf,l);
|
||||
sdsinclen(s,l);
|
||||
@ -638,6 +644,7 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
|
||||
l = sdsull2str(buf,unum);
|
||||
if (sdsavail(s) < l) {
|
||||
s = sdsMakeRoomFor(s,l);
|
||||
if (s == NULL) goto fmt_error;
|
||||
}
|
||||
memcpy(s+i,buf,l);
|
||||
sdsinclen(s,l);
|
||||
@ -662,6 +669,10 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
|
||||
/* Add null-term */
|
||||
s[i] = '\0';
|
||||
return s;
|
||||
|
||||
fmt_error:
|
||||
va_end(ap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Remove the part of the string from left and from right composed just of
|
||||
@ -1018,10 +1029,18 @@ sds *sdssplitargs(const char *line, int *argc) {
|
||||
if (*p) p++;
|
||||
}
|
||||
/* add the token to the vector */
|
||||
vector = s_realloc(vector,((*argc)+1)*sizeof(char*));
|
||||
vector[*argc] = current;
|
||||
(*argc)++;
|
||||
current = NULL;
|
||||
{
|
||||
char **new_vector = s_realloc(vector,((*argc)+1)*sizeof(char*));
|
||||
if (new_vector == NULL) {
|
||||
s_free(vector);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vector = new_vector;
|
||||
vector[*argc] = current;
|
||||
(*argc)++;
|
||||
current = NULL;
|
||||
}
|
||||
} else {
|
||||
/* Even on empty input string return something not NULL. */
|
||||
if (vector == NULL) vector = s_malloc(sizeof(void*));
|
||||
|
31
deps/hiredis/sds.h
vendored
31
deps/hiredis/sds.h
vendored
@ -34,6 +34,9 @@
|
||||
#define __SDS_H
|
||||
|
||||
#define SDS_MAX_PREALLOC (1024*1024)
|
||||
#ifdef _MSC_VER
|
||||
#define __attribute__(x)
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
@ -132,20 +135,20 @@ static inline void sdssetlen(sds s, size_t newlen) {
|
||||
case SDS_TYPE_5:
|
||||
{
|
||||
unsigned char *fp = ((unsigned char*)s)-1;
|
||||
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
|
||||
*fp = (unsigned char)(SDS_TYPE_5 | (newlen << SDS_TYPE_BITS));
|
||||
}
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
SDS_HDR(8,s)->len = newlen;
|
||||
SDS_HDR(8,s)->len = (uint8_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
SDS_HDR(16,s)->len = newlen;
|
||||
SDS_HDR(16,s)->len = (uint16_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_32:
|
||||
SDS_HDR(32,s)->len = newlen;
|
||||
SDS_HDR(32,s)->len = (uint32_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->len = newlen;
|
||||
SDS_HDR(64,s)->len = (uint64_t)newlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -156,21 +159,21 @@ static inline void sdsinclen(sds s, size_t inc) {
|
||||
case SDS_TYPE_5:
|
||||
{
|
||||
unsigned char *fp = ((unsigned char*)s)-1;
|
||||
unsigned char newlen = SDS_TYPE_5_LEN(flags)+inc;
|
||||
unsigned char newlen = SDS_TYPE_5_LEN(flags)+(unsigned char)inc;
|
||||
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
|
||||
}
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
SDS_HDR(8,s)->len += inc;
|
||||
SDS_HDR(8,s)->len += (uint8_t)inc;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
SDS_HDR(16,s)->len += inc;
|
||||
SDS_HDR(16,s)->len += (uint16_t)inc;
|
||||
break;
|
||||
case SDS_TYPE_32:
|
||||
SDS_HDR(32,s)->len += inc;
|
||||
SDS_HDR(32,s)->len += (uint32_t)inc;
|
||||
break;
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->len += inc;
|
||||
SDS_HDR(64,s)->len += (uint64_t)inc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -200,16 +203,16 @@ static inline void sdssetalloc(sds s, size_t newlen) {
|
||||
/* Nothing to do, this type has no total allocation info. */
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
SDS_HDR(8,s)->alloc = newlen;
|
||||
SDS_HDR(8,s)->alloc = (uint8_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
SDS_HDR(16,s)->alloc = newlen;
|
||||
SDS_HDR(16,s)->alloc = (uint16_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_32:
|
||||
SDS_HDR(32,s)->alloc = newlen;
|
||||
SDS_HDR(32,s)->alloc = (uint32_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->alloc = newlen;
|
||||
SDS_HDR(64,s)->alloc = (uint64_t)newlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
248
deps/hiredis/sockcompat.c
vendored
Normal file
248
deps/hiredis/sockcompat.c
vendored
Normal file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Marcus Geelnard <m at bitsnbites dot eu>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define REDIS_SOCKCOMPAT_IMPLEMENTATION
|
||||
#include "sockcompat.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
static int _wsaErrorToErrno(int err) {
|
||||
switch (err) {
|
||||
case WSAEWOULDBLOCK:
|
||||
return EWOULDBLOCK;
|
||||
case WSAEINPROGRESS:
|
||||
return EINPROGRESS;
|
||||
case WSAEALREADY:
|
||||
return EALREADY;
|
||||
case WSAENOTSOCK:
|
||||
return ENOTSOCK;
|
||||
case WSAEDESTADDRREQ:
|
||||
return EDESTADDRREQ;
|
||||
case WSAEMSGSIZE:
|
||||
return EMSGSIZE;
|
||||
case WSAEPROTOTYPE:
|
||||
return EPROTOTYPE;
|
||||
case WSAENOPROTOOPT:
|
||||
return ENOPROTOOPT;
|
||||
case WSAEPROTONOSUPPORT:
|
||||
return EPROTONOSUPPORT;
|
||||
case WSAEOPNOTSUPP:
|
||||
return EOPNOTSUPP;
|
||||
case WSAEAFNOSUPPORT:
|
||||
return EAFNOSUPPORT;
|
||||
case WSAEADDRINUSE:
|
||||
return EADDRINUSE;
|
||||
case WSAEADDRNOTAVAIL:
|
||||
return EADDRNOTAVAIL;
|
||||
case WSAENETDOWN:
|
||||
return ENETDOWN;
|
||||
case WSAENETUNREACH:
|
||||
return ENETUNREACH;
|
||||
case WSAENETRESET:
|
||||
return ENETRESET;
|
||||
case WSAECONNABORTED:
|
||||
return ECONNABORTED;
|
||||
case WSAECONNRESET:
|
||||
return ECONNRESET;
|
||||
case WSAENOBUFS:
|
||||
return ENOBUFS;
|
||||
case WSAEISCONN:
|
||||
return EISCONN;
|
||||
case WSAENOTCONN:
|
||||
return ENOTCONN;
|
||||
case WSAETIMEDOUT:
|
||||
return ETIMEDOUT;
|
||||
case WSAECONNREFUSED:
|
||||
return ECONNREFUSED;
|
||||
case WSAELOOP:
|
||||
return ELOOP;
|
||||
case WSAENAMETOOLONG:
|
||||
return ENAMETOOLONG;
|
||||
case WSAEHOSTUNREACH:
|
||||
return EHOSTUNREACH;
|
||||
case WSAENOTEMPTY:
|
||||
return ENOTEMPTY;
|
||||
default:
|
||||
/* We just return a generic I/O error if we could not find a relevant error. */
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
|
||||
static void _updateErrno(int success) {
|
||||
errno = success ? 0 : _wsaErrorToErrno(WSAGetLastError());
|
||||
}
|
||||
|
||||
static int _initWinsock() {
|
||||
static int s_initialized = 0;
|
||||
if (!s_initialized) {
|
||||
static WSADATA wsadata;
|
||||
int err = WSAStartup(MAKEWORD(2,2), &wsadata);
|
||||
if (err != 0) {
|
||||
errno = _wsaErrorToErrno(err);
|
||||
return 0;
|
||||
}
|
||||
s_initialized = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int win32_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
|
||||
/* Note: This function is likely to be called before other functions, so run init here. */
|
||||
if (!_initWinsock()) {
|
||||
return EAI_FAIL;
|
||||
}
|
||||
|
||||
switch (getaddrinfo(node, service, hints, res)) {
|
||||
case 0: return 0;
|
||||
case WSATRY_AGAIN: return EAI_AGAIN;
|
||||
case WSAEINVAL: return EAI_BADFLAGS;
|
||||
case WSAEAFNOSUPPORT: return EAI_FAMILY;
|
||||
case WSA_NOT_ENOUGH_MEMORY: return EAI_MEMORY;
|
||||
case WSAHOST_NOT_FOUND: return EAI_NONAME;
|
||||
case WSATYPE_NOT_FOUND: return EAI_SERVICE;
|
||||
case WSAESOCKTNOSUPPORT: return EAI_SOCKTYPE;
|
||||
default: return EAI_FAIL; /* Including WSANO_RECOVERY */
|
||||
}
|
||||
}
|
||||
|
||||
const char *win32_gai_strerror(int errcode) {
|
||||
switch (errcode) {
|
||||
case 0: errcode = 0; break;
|
||||
case EAI_AGAIN: errcode = WSATRY_AGAIN; break;
|
||||
case EAI_BADFLAGS: errcode = WSAEINVAL; break;
|
||||
case EAI_FAMILY: errcode = WSAEAFNOSUPPORT; break;
|
||||
case EAI_MEMORY: errcode = WSA_NOT_ENOUGH_MEMORY; break;
|
||||
case EAI_NONAME: errcode = WSAHOST_NOT_FOUND; break;
|
||||
case EAI_SERVICE: errcode = WSATYPE_NOT_FOUND; break;
|
||||
case EAI_SOCKTYPE: errcode = WSAESOCKTNOSUPPORT; break;
|
||||
default: errcode = WSANO_RECOVERY; break; /* Including EAI_FAIL */
|
||||
}
|
||||
return gai_strerror(errcode);
|
||||
}
|
||||
|
||||
void win32_freeaddrinfo(struct addrinfo *res) {
|
||||
freeaddrinfo(res);
|
||||
}
|
||||
|
||||
SOCKET win32_socket(int domain, int type, int protocol) {
|
||||
SOCKET s;
|
||||
|
||||
/* Note: This function is likely to be called before other functions, so run init here. */
|
||||
if (!_initWinsock()) {
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
_updateErrno((s = socket(domain, type, protocol)) != INVALID_SOCKET);
|
||||
return s;
|
||||
}
|
||||
|
||||
int win32_ioctl(SOCKET fd, unsigned long request, unsigned long *argp) {
|
||||
int ret = ioctlsocket(fd, (long)request, argp);
|
||||
_updateErrno(ret != SOCKET_ERROR);
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
|
||||
int win32_bind(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||
int ret = bind(sockfd, addr, addrlen);
|
||||
_updateErrno(ret != SOCKET_ERROR);
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
|
||||
int win32_connect(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||
int ret = connect(sockfd, addr, addrlen);
|
||||
_updateErrno(ret != SOCKET_ERROR);
|
||||
|
||||
/* For Winsock connect(), the WSAEWOULDBLOCK error means the same thing as
|
||||
* EINPROGRESS for POSIX connect(), so we do that translation to keep POSIX
|
||||
* logic consistent. */
|
||||
if (errno == EWOULDBLOCK) {
|
||||
errno = EINPROGRESS;
|
||||
}
|
||||
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
|
||||
int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, socklen_t *optlen) {
|
||||
int ret = 0;
|
||||
if ((level == SOL_SOCKET) && ((optname == SO_RCVTIMEO) || (optname == SO_SNDTIMEO))) {
|
||||
if (*optlen >= sizeof (struct timeval)) {
|
||||
struct timeval *tv = optval;
|
||||
DWORD timeout = 0;
|
||||
socklen_t dwlen = 0;
|
||||
ret = getsockopt(sockfd, level, optname, (char *)&timeout, &dwlen);
|
||||
tv->tv_sec = timeout / 1000;
|
||||
tv->tv_usec = (timeout * 1000) % 1000000;
|
||||
} else {
|
||||
ret = WSAEFAULT;
|
||||
}
|
||||
*optlen = sizeof (struct timeval);
|
||||
} else {
|
||||
ret = getsockopt(sockfd, level, optname, (char*)optval, optlen);
|
||||
}
|
||||
_updateErrno(ret != SOCKET_ERROR);
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
|
||||
int win32_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen) {
|
||||
int ret = 0;
|
||||
if ((level == SOL_SOCKET) && ((optname == SO_RCVTIMEO) || (optname == SO_SNDTIMEO))) {
|
||||
struct timeval *tv = optval;
|
||||
DWORD timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000;
|
||||
ret = setsockopt(sockfd, level, optname, (const char*)&timeout, sizeof(DWORD));
|
||||
} else {
|
||||
ret = setsockopt(sockfd, level, optname, (const char*)optval, optlen);
|
||||
}
|
||||
_updateErrno(ret != SOCKET_ERROR);
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
|
||||
int win32_close(SOCKET fd) {
|
||||
int ret = closesocket(fd);
|
||||
_updateErrno(ret != SOCKET_ERROR);
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
|
||||
ssize_t win32_recv(SOCKET sockfd, void *buf, size_t len, int flags) {
|
||||
int ret = recv(sockfd, (char*)buf, (int)len, flags);
|
||||
_updateErrno(ret != SOCKET_ERROR);
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
|
||||
ssize_t win32_send(SOCKET sockfd, const void *buf, size_t len, int flags) {
|
||||
int ret = send(sockfd, (const char*)buf, (int)len, flags);
|
||||
_updateErrno(ret != SOCKET_ERROR);
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
|
||||
int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout) {
|
||||
int ret = WSAPoll(fds, nfds, timeout);
|
||||
_updateErrno(ret != SOCKET_ERROR);
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
#endif /* _WIN32 */
|
91
deps/hiredis/sockcompat.h
vendored
Normal file
91
deps/hiredis/sockcompat.h
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Marcus Geelnard <m at bitsnbites dot eu>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __SOCKCOMPAT_H
|
||||
#define __SOCKCOMPAT_H
|
||||
|
||||
#ifndef _WIN32
|
||||
/* For POSIX systems we use the standard BSD socket API. */
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <poll.h>
|
||||
#else
|
||||
/* For Windows we use winsock. */
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600 /* To get WSAPoll etc. */
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef signed long ssize_t;
|
||||
#endif
|
||||
|
||||
/* Emulate the parts of the BSD socket API that we need (override the winsock signatures). */
|
||||
int win32_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
|
||||
const char *win32_gai_strerror(int errcode);
|
||||
void win32_freeaddrinfo(struct addrinfo *res);
|
||||
SOCKET win32_socket(int domain, int type, int protocol);
|
||||
int win32_ioctl(SOCKET fd, unsigned long request, unsigned long *argp);
|
||||
int win32_bind(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
int win32_connect(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, socklen_t *optlen);
|
||||
int win32_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen);
|
||||
int win32_close(SOCKET fd);
|
||||
ssize_t win32_recv(SOCKET sockfd, void *buf, size_t len, int flags);
|
||||
ssize_t win32_send(SOCKET sockfd, const void *buf, size_t len, int flags);
|
||||
typedef ULONG nfds_t;
|
||||
int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout);
|
||||
|
||||
#ifndef REDIS_SOCKCOMPAT_IMPLEMENTATION
|
||||
#define getaddrinfo(node, service, hints, res) win32_getaddrinfo(node, service, hints, res)
|
||||
#undef gai_strerror
|
||||
#define gai_strerror(errcode) win32_gai_strerror(errcode)
|
||||
#define freeaddrinfo(res) win32_freeaddrinfo(res)
|
||||
#define socket(domain, type, protocol) win32_socket(domain, type, protocol)
|
||||
#define ioctl(fd, request, argp) win32_ioctl(fd, request, argp)
|
||||
#define bind(sockfd, addr, addrlen) win32_bind(sockfd, addr, addrlen)
|
||||
#define connect(sockfd, addr, addrlen) win32_connect(sockfd, addr, addrlen)
|
||||
#define getsockopt(sockfd, level, optname, optval, optlen) win32_getsockopt(sockfd, level, optname, optval, optlen)
|
||||
#define setsockopt(sockfd, level, optname, optval, optlen) win32_setsockopt(sockfd, level, optname, optval, optlen)
|
||||
#define close(fd) win32_close(fd)
|
||||
#define recv(sockfd, buf, len, flags) win32_recv(sockfd, buf, len, flags)
|
||||
#define send(sockfd, buf, len, flags) win32_send(sockfd, buf, len, flags)
|
||||
#define poll(fds, nfds, timeout) win32_poll(fds, nfds, timeout)
|
||||
#endif /* REDIS_SOCKCOMPAT_IMPLEMENTATION */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* __SOCKCOMPAT_H */
|
448
deps/hiredis/ssl.c
vendored
Normal file
448
deps/hiredis/ssl.c
vendored
Normal file
@ -0,0 +1,448 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
* Copyright (c) 2019, Redis Labs
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "hiredis.h"
|
||||
#include "async.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "async_private.h"
|
||||
|
||||
void __redisSetError(redisContext *c, int type, const char *str);
|
||||
|
||||
/* The SSL context is attached to SSL/TLS connections as a privdata. */
|
||||
typedef struct redisSSLContext {
|
||||
/**
|
||||
* OpenSSL SSL_CTX; It is optional and will not be set when using
|
||||
* user-supplied SSL.
|
||||
*/
|
||||
SSL_CTX *ssl_ctx;
|
||||
|
||||
/**
|
||||
* OpenSSL SSL object.
|
||||
*/
|
||||
SSL *ssl;
|
||||
|
||||
/**
|
||||
* SSL_write() requires to be called again with the same arguments it was
|
||||
* previously called with in the event of an SSL_read/SSL_write situation
|
||||
*/
|
||||
size_t lastLen;
|
||||
|
||||
/** Whether the SSL layer requires read (possibly before a write) */
|
||||
int wantRead;
|
||||
|
||||
/**
|
||||
* Whether a write was requested prior to a read. If set, the write()
|
||||
* should resume whenever a read takes place, if possible
|
||||
*/
|
||||
int pendingWrite;
|
||||
} redisSSLContext;
|
||||
|
||||
/* Forward declaration */
|
||||
redisContextFuncs redisContextSSLFuncs;
|
||||
|
||||
#ifdef HIREDIS_SSL_TRACE
|
||||
/**
|
||||
* Callback used for debugging
|
||||
*/
|
||||
static void sslLogCallback(const SSL *ssl, int where, int ret) {
|
||||
const char *retstr = "";
|
||||
int should_log = 1;
|
||||
/* Ignore low-level SSL stuff */
|
||||
|
||||
if (where & SSL_CB_ALERT) {
|
||||
should_log = 1;
|
||||
}
|
||||
if (where == SSL_CB_HANDSHAKE_START || where == SSL_CB_HANDSHAKE_DONE) {
|
||||
should_log = 1;
|
||||
}
|
||||
if ((where & SSL_CB_EXIT) && ret == 0) {
|
||||
should_log = 1;
|
||||
}
|
||||
|
||||
if (!should_log) {
|
||||
return;
|
||||
}
|
||||
|
||||
retstr = SSL_alert_type_string(ret);
|
||||
printf("ST(0x%x). %s. R(0x%x)%s\n", where, SSL_state_string_long(ssl), ret, retstr);
|
||||
|
||||
if (where == SSL_CB_HANDSHAKE_DONE) {
|
||||
printf("Using SSL version %s. Cipher=%s\n", SSL_get_version(ssl), SSL_get_cipher_name(ssl));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* OpenSSL global initialization and locking handling callbacks.
|
||||
* Note that this is only required for OpenSSL < 1.1.0.
|
||||
*/
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
#define HIREDIS_USE_CRYPTO_LOCKS
|
||||
#endif
|
||||
|
||||
#ifdef HIREDIS_USE_CRYPTO_LOCKS
|
||||
typedef pthread_mutex_t sslLockType;
|
||||
static void sslLockInit(sslLockType *l) {
|
||||
pthread_mutex_init(l, NULL);
|
||||
}
|
||||
static void sslLockAcquire(sslLockType *l) {
|
||||
pthread_mutex_lock(l);
|
||||
}
|
||||
static void sslLockRelease(sslLockType *l) {
|
||||
pthread_mutex_unlock(l);
|
||||
}
|
||||
static pthread_mutex_t *ossl_locks;
|
||||
|
||||
static void opensslDoLock(int mode, int lkid, const char *f, int line) {
|
||||
sslLockType *l = ossl_locks + lkid;
|
||||
|
||||
if (mode & CRYPTO_LOCK) {
|
||||
sslLockAcquire(l);
|
||||
} else {
|
||||
sslLockRelease(l);
|
||||
}
|
||||
|
||||
(void)f;
|
||||
(void)line;
|
||||
}
|
||||
|
||||
static void initOpensslLocks(void) {
|
||||
unsigned ii, nlocks;
|
||||
if (CRYPTO_get_locking_callback() != NULL) {
|
||||
/* Someone already set the callback before us. Don't destroy it! */
|
||||
return;
|
||||
}
|
||||
nlocks = CRYPTO_num_locks();
|
||||
ossl_locks = malloc(sizeof(*ossl_locks) * nlocks);
|
||||
for (ii = 0; ii < nlocks; ii++) {
|
||||
sslLockInit(ossl_locks + ii);
|
||||
}
|
||||
CRYPTO_set_locking_callback(opensslDoLock);
|
||||
}
|
||||
#endif /* HIREDIS_USE_CRYPTO_LOCKS */
|
||||
|
||||
/**
|
||||
* SSL Connection initialization.
|
||||
*/
|
||||
|
||||
static int redisSSLConnect(redisContext *c, SSL_CTX *ssl_ctx, SSL *ssl) {
|
||||
if (c->privdata) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "redisContext was already associated");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
c->privdata = calloc(1, sizeof(redisSSLContext));
|
||||
|
||||
c->funcs = &redisContextSSLFuncs;
|
||||
redisSSLContext *rssl = c->privdata;
|
||||
|
||||
rssl->ssl_ctx = ssl_ctx;
|
||||
rssl->ssl = ssl;
|
||||
|
||||
SSL_set_mode(rssl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
SSL_set_fd(rssl->ssl, c->fd);
|
||||
SSL_set_connect_state(rssl->ssl);
|
||||
|
||||
ERR_clear_error();
|
||||
int rv = SSL_connect(rssl->ssl);
|
||||
if (rv == 1) {
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
rv = SSL_get_error(rssl->ssl, rv);
|
||||
if (((c->flags & REDIS_BLOCK) == 0) &&
|
||||
(rv == SSL_ERROR_WANT_READ || rv == SSL_ERROR_WANT_WRITE)) {
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
if (c->err == 0) {
|
||||
char err[512];
|
||||
if (rv == SSL_ERROR_SYSCALL)
|
||||
snprintf(err,sizeof(err)-1,"SSL_connect failed: %s",strerror(errno));
|
||||
else {
|
||||
unsigned long e = ERR_peek_last_error();
|
||||
snprintf(err,sizeof(err)-1,"SSL_connect failed: %s",
|
||||
ERR_reason_error_string(e));
|
||||
}
|
||||
__redisSetError(c, REDIS_ERR_IO, err);
|
||||
}
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
int redisInitiateSSL(redisContext *c, SSL *ssl) {
|
||||
return redisSSLConnect(c, NULL, ssl);
|
||||
}
|
||||
|
||||
int redisSecureConnection(redisContext *c, const char *capath,
|
||||
const char *certpath, const char *keypath, const char *servername) {
|
||||
|
||||
SSL_CTX *ssl_ctx = NULL;
|
||||
SSL *ssl = NULL;
|
||||
|
||||
/* Initialize global OpenSSL stuff */
|
||||
static int isInit = 0;
|
||||
if (!isInit) {
|
||||
isInit = 1;
|
||||
SSL_library_init();
|
||||
#ifdef HIREDIS_USE_CRYPTO_LOCKS
|
||||
initOpensslLocks();
|
||||
#endif
|
||||
}
|
||||
|
||||
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
if (!ssl_ctx) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "Failed to create SSL_CTX");
|
||||
goto error;
|
||||
}
|
||||
|
||||
#ifdef HIREDIS_SSL_TRACE
|
||||
SSL_CTX_set_info_callback(ssl_ctx, sslLogCallback);
|
||||
#endif
|
||||
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
||||
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
|
||||
if ((certpath != NULL && keypath == NULL) || (keypath != NULL && certpath == NULL)) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "certpath and keypath must be specified together");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (capath) {
|
||||
if (!SSL_CTX_load_verify_locations(ssl_ctx, capath, NULL)) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "Invalid CA certificate");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (certpath) {
|
||||
if (!SSL_CTX_use_certificate_chain_file(ssl_ctx, certpath)) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "Invalid client certificate");
|
||||
goto error;
|
||||
}
|
||||
if (!SSL_CTX_use_PrivateKey_file(ssl_ctx, keypath, SSL_FILETYPE_PEM)) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "Invalid client key");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
ssl = SSL_new(ssl_ctx);
|
||||
if (!ssl) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "Couldn't create new SSL instance");
|
||||
goto error;
|
||||
}
|
||||
if (servername) {
|
||||
if (!SSL_set_tlsext_host_name(ssl, servername)) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "Couldn't set server name indication");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return redisSSLConnect(c, ssl_ctx, ssl);
|
||||
|
||||
error:
|
||||
if (ssl) SSL_free(ssl);
|
||||
if (ssl_ctx) SSL_CTX_free(ssl_ctx);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
static int maybeCheckWant(redisSSLContext *rssl, int rv) {
|
||||
/**
|
||||
* If the error is WANT_READ or WANT_WRITE, the appropriate flags are set
|
||||
* and true is returned. False is returned otherwise
|
||||
*/
|
||||
if (rv == SSL_ERROR_WANT_READ) {
|
||||
rssl->wantRead = 1;
|
||||
return 1;
|
||||
} else if (rv == SSL_ERROR_WANT_WRITE) {
|
||||
rssl->pendingWrite = 1;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of redisContextFuncs for SSL connections.
|
||||
*/
|
||||
|
||||
static void redisSSLFreeContext(void *privdata){
|
||||
redisSSLContext *rsc = privdata;
|
||||
|
||||
if (!rsc) return;
|
||||
if (rsc->ssl) {
|
||||
SSL_free(rsc->ssl);
|
||||
rsc->ssl = NULL;
|
||||
}
|
||||
if (rsc->ssl_ctx) {
|
||||
SSL_CTX_free(rsc->ssl_ctx);
|
||||
rsc->ssl_ctx = NULL;
|
||||
}
|
||||
free(rsc);
|
||||
}
|
||||
|
||||
static int redisSSLRead(redisContext *c, char *buf, size_t bufcap) {
|
||||
redisSSLContext *rssl = c->privdata;
|
||||
|
||||
int nread = SSL_read(rssl->ssl, buf, bufcap);
|
||||
if (nread > 0) {
|
||||
return nread;
|
||||
} else if (nread == 0) {
|
||||
__redisSetError(c, REDIS_ERR_EOF, "Server closed the connection");
|
||||
return -1;
|
||||
} else {
|
||||
int err = SSL_get_error(rssl->ssl, nread);
|
||||
if (c->flags & REDIS_BLOCK) {
|
||||
/**
|
||||
* In blocking mode, we should never end up in a situation where
|
||||
* we get an error without it being an actual error, except
|
||||
* in the case of EINTR, which can be spuriously received from
|
||||
* debuggers or whatever.
|
||||
*/
|
||||
if (errno == EINTR) {
|
||||
return 0;
|
||||
} else {
|
||||
const char *msg = NULL;
|
||||
if (errno == EAGAIN) {
|
||||
msg = "Resource temporarily unavailable";
|
||||
}
|
||||
__redisSetError(c, REDIS_ERR_IO, msg);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We can very well get an EWOULDBLOCK/EAGAIN, however
|
||||
*/
|
||||
if (maybeCheckWant(rssl, err)) {
|
||||
return 0;
|
||||
} else {
|
||||
__redisSetError(c, REDIS_ERR_IO, NULL);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int redisSSLWrite(redisContext *c) {
|
||||
redisSSLContext *rssl = c->privdata;
|
||||
|
||||
size_t len = rssl->lastLen ? rssl->lastLen : sdslen(c->obuf);
|
||||
int rv = SSL_write(rssl->ssl, c->obuf, len);
|
||||
|
||||
if (rv > 0) {
|
||||
rssl->lastLen = 0;
|
||||
} else if (rv < 0) {
|
||||
rssl->lastLen = len;
|
||||
|
||||
int err = SSL_get_error(rssl->ssl, rv);
|
||||
if ((c->flags & REDIS_BLOCK) == 0 && maybeCheckWant(rssl, err)) {
|
||||
return 0;
|
||||
} else {
|
||||
__redisSetError(c, REDIS_ERR_IO, NULL);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void redisSSLAsyncRead(redisAsyncContext *ac) {
|
||||
int rv;
|
||||
redisSSLContext *rssl = ac->c.privdata;
|
||||
redisContext *c = &ac->c;
|
||||
|
||||
rssl->wantRead = 0;
|
||||
|
||||
if (rssl->pendingWrite) {
|
||||
int done;
|
||||
|
||||
/* This is probably just a write event */
|
||||
rssl->pendingWrite = 0;
|
||||
rv = redisBufferWrite(c, &done);
|
||||
if (rv == REDIS_ERR) {
|
||||
__redisAsyncDisconnect(ac);
|
||||
return;
|
||||
} else if (!done) {
|
||||
_EL_ADD_WRITE(ac);
|
||||
}
|
||||
}
|
||||
|
||||
rv = redisBufferRead(c);
|
||||
if (rv == REDIS_ERR) {
|
||||
__redisAsyncDisconnect(ac);
|
||||
} else {
|
||||
_EL_ADD_READ(ac);
|
||||
redisProcessCallbacks(ac);
|
||||
}
|
||||
}
|
||||
|
||||
static void redisSSLAsyncWrite(redisAsyncContext *ac) {
|
||||
int rv, done = 0;
|
||||
redisSSLContext *rssl = ac->c.privdata;
|
||||
redisContext *c = &ac->c;
|
||||
|
||||
rssl->pendingWrite = 0;
|
||||
rv = redisBufferWrite(c, &done);
|
||||
if (rv == REDIS_ERR) {
|
||||
__redisAsyncDisconnect(ac);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!done) {
|
||||
if (rssl->wantRead) {
|
||||
/* Need to read-before-write */
|
||||
rssl->pendingWrite = 1;
|
||||
_EL_DEL_WRITE(ac);
|
||||
} else {
|
||||
/* No extra reads needed, just need to write more */
|
||||
_EL_ADD_WRITE(ac);
|
||||
}
|
||||
} else {
|
||||
/* Already done! */
|
||||
_EL_DEL_WRITE(ac);
|
||||
}
|
||||
|
||||
/* Always reschedule a read */
|
||||
_EL_ADD_READ(ac);
|
||||
}
|
||||
|
||||
redisContextFuncs redisContextSSLFuncs = {
|
||||
.free_privdata = redisSSLFreeContext,
|
||||
.async_read = redisSSLAsyncRead,
|
||||
.async_write = redisSSLAsyncWrite,
|
||||
.read = redisSSLRead,
|
||||
.write = redisSSLWrite
|
||||
};
|
||||
|
235
deps/hiredis/test.c
vendored
235
deps/hiredis/test.c
vendored
@ -3,7 +3,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <netdb.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
@ -11,12 +13,16 @@
|
||||
#include <limits.h>
|
||||
|
||||
#include "hiredis.h"
|
||||
#ifdef HIREDIS_TEST_SSL
|
||||
#include "hiredis_ssl.h"
|
||||
#endif
|
||||
#include "net.h"
|
||||
|
||||
enum connection_type {
|
||||
CONN_TCP,
|
||||
CONN_UNIX,
|
||||
CONN_FD
|
||||
CONN_FD,
|
||||
CONN_SSL
|
||||
};
|
||||
|
||||
struct config {
|
||||
@ -31,6 +37,14 @@ struct config {
|
||||
struct {
|
||||
const char *path;
|
||||
} unix_sock;
|
||||
|
||||
struct {
|
||||
const char *host;
|
||||
int port;
|
||||
const char *ca_cert;
|
||||
const char *cert;
|
||||
const char *key;
|
||||
} ssl;
|
||||
};
|
||||
|
||||
/* The following lines make up our testing "framework" :) */
|
||||
@ -91,11 +105,27 @@ static int disconnect(redisContext *c, int keep_fd) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static redisContext *connect(struct config config) {
|
||||
static void do_ssl_handshake(redisContext *c, struct config config) {
|
||||
#ifdef HIREDIS_TEST_SSL
|
||||
redisSecureConnection(c, config.ssl.ca_cert, config.ssl.cert, config.ssl.key, NULL);
|
||||
if (c->err) {
|
||||
printf("SSL error: %s\n", c->errstr);
|
||||
redisFree(c);
|
||||
exit(1);
|
||||
}
|
||||
#else
|
||||
(void) c;
|
||||
(void) config;
|
||||
#endif
|
||||
}
|
||||
|
||||
static redisContext *do_connect(struct config config) {
|
||||
redisContext *c = NULL;
|
||||
|
||||
if (config.type == CONN_TCP) {
|
||||
c = redisConnect(config.tcp.host, config.tcp.port);
|
||||
} else if (config.type == CONN_SSL) {
|
||||
c = redisConnect(config.ssl.host, config.ssl.port);
|
||||
} else if (config.type == CONN_UNIX) {
|
||||
c = redisConnectUnix(config.unix_sock.path);
|
||||
} else if (config.type == CONN_FD) {
|
||||
@ -119,9 +149,21 @@ static redisContext *connect(struct config config) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (config.type == CONN_SSL) {
|
||||
do_ssl_handshake(c, config);
|
||||
}
|
||||
|
||||
return select_database(c);
|
||||
}
|
||||
|
||||
static void do_reconnect(redisContext *c, struct config config) {
|
||||
redisReconnect(c);
|
||||
|
||||
if (config.type == CONN_SSL) {
|
||||
do_ssl_handshake(c, config);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_format_commands(void) {
|
||||
char *cmd;
|
||||
int len;
|
||||
@ -248,7 +290,7 @@ static void test_append_formatted_commands(struct config config) {
|
||||
char *cmd;
|
||||
int len;
|
||||
|
||||
c = connect(config);
|
||||
c = do_connect(config);
|
||||
|
||||
test("Append format command: ");
|
||||
|
||||
@ -302,6 +344,82 @@ static void test_reply_reader(void) {
|
||||
strncasecmp(reader->errstr,"No support for",14) == 0);
|
||||
redisReaderFree(reader);
|
||||
|
||||
test("Correctly parses LLONG_MAX: ");
|
||||
reader = redisReaderCreate();
|
||||
redisReaderFeed(reader, ":9223372036854775807\r\n",22);
|
||||
ret = redisReaderGetReply(reader,&reply);
|
||||
test_cond(ret == REDIS_OK &&
|
||||
((redisReply*)reply)->type == REDIS_REPLY_INTEGER &&
|
||||
((redisReply*)reply)->integer == LLONG_MAX);
|
||||
freeReplyObject(reply);
|
||||
redisReaderFree(reader);
|
||||
|
||||
test("Set error when > LLONG_MAX: ");
|
||||
reader = redisReaderCreate();
|
||||
redisReaderFeed(reader, ":9223372036854775808\r\n",22);
|
||||
ret = redisReaderGetReply(reader,&reply);
|
||||
test_cond(ret == REDIS_ERR &&
|
||||
strcasecmp(reader->errstr,"Bad integer value") == 0);
|
||||
freeReplyObject(reply);
|
||||
redisReaderFree(reader);
|
||||
|
||||
test("Correctly parses LLONG_MIN: ");
|
||||
reader = redisReaderCreate();
|
||||
redisReaderFeed(reader, ":-9223372036854775808\r\n",23);
|
||||
ret = redisReaderGetReply(reader,&reply);
|
||||
test_cond(ret == REDIS_OK &&
|
||||
((redisReply*)reply)->type == REDIS_REPLY_INTEGER &&
|
||||
((redisReply*)reply)->integer == LLONG_MIN);
|
||||
freeReplyObject(reply);
|
||||
redisReaderFree(reader);
|
||||
|
||||
test("Set error when < LLONG_MIN: ");
|
||||
reader = redisReaderCreate();
|
||||
redisReaderFeed(reader, ":-9223372036854775809\r\n",23);
|
||||
ret = redisReaderGetReply(reader,&reply);
|
||||
test_cond(ret == REDIS_ERR &&
|
||||
strcasecmp(reader->errstr,"Bad integer value") == 0);
|
||||
freeReplyObject(reply);
|
||||
redisReaderFree(reader);
|
||||
|
||||
test("Set error when array < -1: ");
|
||||
reader = redisReaderCreate();
|
||||
redisReaderFeed(reader, "*-2\r\n+asdf\r\n",12);
|
||||
ret = redisReaderGetReply(reader,&reply);
|
||||
test_cond(ret == REDIS_ERR &&
|
||||
strcasecmp(reader->errstr,"Multi-bulk length out of range") == 0);
|
||||
freeReplyObject(reply);
|
||||
redisReaderFree(reader);
|
||||
|
||||
test("Set error when bulk < -1: ");
|
||||
reader = redisReaderCreate();
|
||||
redisReaderFeed(reader, "$-2\r\nasdf\r\n",11);
|
||||
ret = redisReaderGetReply(reader,&reply);
|
||||
test_cond(ret == REDIS_ERR &&
|
||||
strcasecmp(reader->errstr,"Bulk string length out of range") == 0);
|
||||
freeReplyObject(reply);
|
||||
redisReaderFree(reader);
|
||||
|
||||
#if LLONG_MAX > SIZE_MAX
|
||||
test("Set error when array > SIZE_MAX: ");
|
||||
reader = redisReaderCreate();
|
||||
redisReaderFeed(reader, "*9223372036854775807\r\n+asdf\r\n",29);
|
||||
ret = redisReaderGetReply(reader,&reply);
|
||||
test_cond(ret == REDIS_ERR &&
|
||||
strcasecmp(reader->errstr,"Multi-bulk length out of range") == 0);
|
||||
freeReplyObject(reply);
|
||||
redisReaderFree(reader);
|
||||
|
||||
test("Set error when bulk > SIZE_MAX: ");
|
||||
reader = redisReaderCreate();
|
||||
redisReaderFeed(reader, "$9223372036854775807\r\nasdf\r\n",28);
|
||||
ret = redisReaderGetReply(reader,&reply);
|
||||
test_cond(ret == REDIS_ERR &&
|
||||
strcasecmp(reader->errstr,"Bulk string length out of range") == 0);
|
||||
freeReplyObject(reply);
|
||||
redisReaderFree(reader);
|
||||
#endif
|
||||
|
||||
test("Works with NULL functions for reply: ");
|
||||
reader = redisReaderCreate();
|
||||
reader->fn = NULL;
|
||||
@ -356,20 +474,35 @@ static void test_free_null(void) {
|
||||
test_cond(reply == NULL);
|
||||
}
|
||||
|
||||
#define HIREDIS_BAD_DOMAIN "idontexist-noreally.com"
|
||||
static void test_blocking_connection_errors(void) {
|
||||
redisContext *c;
|
||||
struct addrinfo hints = {.ai_family = AF_INET};
|
||||
struct addrinfo *ai_tmp = NULL;
|
||||
|
||||
test("Returns error when host cannot be resolved: ");
|
||||
c = redisConnect((char*)"idontexist.test", 6379);
|
||||
test_cond(c->err == REDIS_ERR_OTHER &&
|
||||
(strcmp(c->errstr,"Name or service not known") == 0 ||
|
||||
strcmp(c->errstr,"Can't resolve: idontexist.test") == 0 ||
|
||||
strcmp(c->errstr,"nodename nor servname provided, or not known") == 0 ||
|
||||
strcmp(c->errstr,"No address associated with hostname") == 0 ||
|
||||
strcmp(c->errstr,"Temporary failure in name resolution") == 0 ||
|
||||
strcmp(c->errstr,"hostname nor servname provided, or not known") == 0 ||
|
||||
strcmp(c->errstr,"no address associated with name") == 0));
|
||||
redisFree(c);
|
||||
int rv = getaddrinfo(HIREDIS_BAD_DOMAIN, "6379", &hints, &ai_tmp);
|
||||
if (rv != 0) {
|
||||
// Address does *not* exist
|
||||
test("Returns error when host cannot be resolved: ");
|
||||
// First see if this domain name *actually* resolves to NXDOMAIN
|
||||
c = redisConnect(HIREDIS_BAD_DOMAIN, 6379);
|
||||
test_cond(
|
||||
c->err == REDIS_ERR_OTHER &&
|
||||
(strcmp(c->errstr, "Name or service not known") == 0 ||
|
||||
strcmp(c->errstr, "Can't resolve: " HIREDIS_BAD_DOMAIN) == 0 ||
|
||||
strcmp(c->errstr, "Name does not resolve") == 0 ||
|
||||
strcmp(c->errstr,
|
||||
"nodename nor servname provided, or not known") == 0 ||
|
||||
strcmp(c->errstr, "No address associated with hostname") == 0 ||
|
||||
strcmp(c->errstr, "Temporary failure in name resolution") == 0 ||
|
||||
strcmp(c->errstr,
|
||||
"hostname nor servname provided, or not known") == 0 ||
|
||||
strcmp(c->errstr, "no address associated with name") == 0));
|
||||
redisFree(c);
|
||||
} else {
|
||||
printf("Skipping NXDOMAIN test. Found evil ISP!\n");
|
||||
freeaddrinfo(ai_tmp);
|
||||
}
|
||||
|
||||
test("Returns error when the port is not open: ");
|
||||
c = redisConnect((char*)"localhost", 1);
|
||||
@ -387,7 +520,7 @@ static void test_blocking_connection(struct config config) {
|
||||
redisContext *c;
|
||||
redisReply *reply;
|
||||
|
||||
c = connect(config);
|
||||
c = do_connect(config);
|
||||
|
||||
test("Is able to deliver commands: ");
|
||||
reply = redisCommand(c,"PING");
|
||||
@ -468,7 +601,7 @@ static void test_blocking_connection_timeouts(struct config config) {
|
||||
const char *cmd = "DEBUG SLEEP 3\r\n";
|
||||
struct timeval tv;
|
||||
|
||||
c = connect(config);
|
||||
c = do_connect(config);
|
||||
test("Successfully completes a command when the timeout is not exceeded: ");
|
||||
reply = redisCommand(c,"SET foo fast");
|
||||
freeReplyObject(reply);
|
||||
@ -480,9 +613,10 @@ static void test_blocking_connection_timeouts(struct config config) {
|
||||
freeReplyObject(reply);
|
||||
disconnect(c, 0);
|
||||
|
||||
c = connect(config);
|
||||
c = do_connect(config);
|
||||
test("Does not return a reply when the command times out: ");
|
||||
s = write(c->fd, cmd, strlen(cmd));
|
||||
redisAppendFormattedCommand(c, cmd, strlen(cmd));
|
||||
s = c->funcs->write(c);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 10000;
|
||||
redisSetTimeout(c, tv);
|
||||
@ -491,7 +625,7 @@ static void test_blocking_connection_timeouts(struct config config) {
|
||||
freeReplyObject(reply);
|
||||
|
||||
test("Reconnect properly reconnects after a timeout: ");
|
||||
redisReconnect(c);
|
||||
do_reconnect(c, config);
|
||||
reply = redisCommand(c, "PING");
|
||||
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && strcmp(reply->str, "PONG") == 0);
|
||||
freeReplyObject(reply);
|
||||
@ -499,7 +633,7 @@ static void test_blocking_connection_timeouts(struct config config) {
|
||||
test("Reconnect properly uses owned parameters: ");
|
||||
config.tcp.host = "foo";
|
||||
config.unix_sock.path = "foo";
|
||||
redisReconnect(c);
|
||||
do_reconnect(c, config);
|
||||
reply = redisCommand(c, "PING");
|
||||
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && strcmp(reply->str, "PONG") == 0);
|
||||
freeReplyObject(reply);
|
||||
@ -514,7 +648,7 @@ static void test_blocking_io_errors(struct config config) {
|
||||
int major, minor;
|
||||
|
||||
/* Connect to target given by config. */
|
||||
c = connect(config);
|
||||
c = do_connect(config);
|
||||
{
|
||||
/* Find out Redis version to determine the path for the next test */
|
||||
const char *field = "redis_version:";
|
||||
@ -549,7 +683,7 @@ static void test_blocking_io_errors(struct config config) {
|
||||
strcmp(c->errstr,"Server closed the connection") == 0);
|
||||
redisFree(c);
|
||||
|
||||
c = connect(config);
|
||||
c = do_connect(config);
|
||||
test("Returns I/O error on socket timeout: ");
|
||||
struct timeval tv = { 0, 1000 };
|
||||
assert(redisSetTimeout(c,tv) == REDIS_OK);
|
||||
@ -583,7 +717,7 @@ static void test_invalid_timeout_errors(struct config config) {
|
||||
}
|
||||
|
||||
static void test_throughput(struct config config) {
|
||||
redisContext *c = connect(config);
|
||||
redisContext *c = do_connect(config);
|
||||
redisReply **replies;
|
||||
int i, num;
|
||||
long long t1, t2;
|
||||
@ -616,6 +750,17 @@ static void test_throughput(struct config config) {
|
||||
free(replies);
|
||||
printf("\t(%dx LRANGE with 500 elements: %.3fs)\n", num, (t2-t1)/1000000.0);
|
||||
|
||||
replies = malloc(sizeof(redisReply*)*num);
|
||||
t1 = usec();
|
||||
for (i = 0; i < num; i++) {
|
||||
replies[i] = redisCommand(c, "INCRBY incrkey %d", 1000000);
|
||||
assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_INTEGER);
|
||||
}
|
||||
t2 = usec();
|
||||
for (i = 0; i < num; i++) freeReplyObject(replies[i]);
|
||||
free(replies);
|
||||
printf("\t(%dx INCRBY: %.3fs)\n", num, (t2-t1)/1000000.0);
|
||||
|
||||
num = 10000;
|
||||
replies = malloc(sizeof(redisReply*)*num);
|
||||
for (i = 0; i < num; i++)
|
||||
@ -644,6 +789,19 @@ static void test_throughput(struct config config) {
|
||||
free(replies);
|
||||
printf("\t(%dx LRANGE with 500 elements (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0);
|
||||
|
||||
replies = malloc(sizeof(redisReply*)*num);
|
||||
for (i = 0; i < num; i++)
|
||||
redisAppendCommand(c,"INCRBY incrkey %d", 1000000);
|
||||
t1 = usec();
|
||||
for (i = 0; i < num; i++) {
|
||||
assert(redisGetReply(c, (void*)&replies[i]) == REDIS_OK);
|
||||
assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_INTEGER);
|
||||
}
|
||||
t2 = usec();
|
||||
for (i = 0; i < num; i++) freeReplyObject(replies[i]);
|
||||
free(replies);
|
||||
printf("\t(%dx INCRBY (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0);
|
||||
|
||||
disconnect(c, 0);
|
||||
}
|
||||
|
||||
@ -778,6 +936,23 @@ int main(int argc, char **argv) {
|
||||
throughput = 0;
|
||||
} else if (argc >= 1 && !strcmp(argv[0],"--skip-inherit-fd")) {
|
||||
test_inherit_fd = 0;
|
||||
#ifdef HIREDIS_TEST_SSL
|
||||
} else if (argc >= 2 && !strcmp(argv[0],"--ssl-port")) {
|
||||
argv++; argc--;
|
||||
cfg.ssl.port = atoi(argv[0]);
|
||||
} else if (argc >= 2 && !strcmp(argv[0],"--ssl-host")) {
|
||||
argv++; argc--;
|
||||
cfg.ssl.host = argv[0];
|
||||
} else if (argc >= 2 && !strcmp(argv[0],"--ssl-ca-cert")) {
|
||||
argv++; argc--;
|
||||
cfg.ssl.ca_cert = argv[0];
|
||||
} else if (argc >= 2 && !strcmp(argv[0],"--ssl-cert")) {
|
||||
argv++; argc--;
|
||||
cfg.ssl.cert = argv[0];
|
||||
} else if (argc >= 2 && !strcmp(argv[0],"--ssl-key")) {
|
||||
argv++; argc--;
|
||||
cfg.ssl.key = argv[0];
|
||||
#endif
|
||||
} else {
|
||||
fprintf(stderr, "Invalid argument: %s\n", argv[0]);
|
||||
exit(1);
|
||||
@ -806,6 +981,20 @@ int main(int argc, char **argv) {
|
||||
test_blocking_io_errors(cfg);
|
||||
if (throughput) test_throughput(cfg);
|
||||
|
||||
#ifdef HIREDIS_TEST_SSL
|
||||
if (cfg.ssl.port && cfg.ssl.host) {
|
||||
printf("\nTesting against SSL connection (%s:%d):\n", cfg.ssl.host, cfg.ssl.port);
|
||||
cfg.type = CONN_SSL;
|
||||
|
||||
test_blocking_connection(cfg);
|
||||
test_blocking_connection_timeouts(cfg);
|
||||
test_blocking_io_errors(cfg);
|
||||
test_invalid_timeout_errors(cfg);
|
||||
test_append_formatted_commands(cfg);
|
||||
if (throughput) test_throughput(cfg);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (test_inherit_fd) {
|
||||
printf("\nTesting against inherited fd (%s):\n", cfg.unix_sock.path);
|
||||
cfg.type = CONN_FD;
|
||||
|
70
deps/hiredis/test.sh
vendored
Executable file
70
deps/hiredis/test.sh
vendored
Executable file
@ -0,0 +1,70 @@
|
||||
#!/bin/sh -ue
|
||||
|
||||
REDIS_SERVER=${REDIS_SERVER:-redis-server}
|
||||
REDIS_PORT=${REDIS_PORT:-56379}
|
||||
REDIS_SSL_PORT=${REDIS_SSL_PORT:-56443}
|
||||
TEST_SSL=${TEST_SSL:-0}
|
||||
SSL_TEST_ARGS=
|
||||
|
||||
tmpdir=$(mktemp -d)
|
||||
PID_FILE=${tmpdir}/hiredis-test-redis.pid
|
||||
SOCK_FILE=${tmpdir}/hiredis-test-redis.sock
|
||||
|
||||
if [ "$TEST_SSL" = "1" ]; then
|
||||
SSL_CA_CERT=${tmpdir}/ca.crt
|
||||
SSL_CA_KEY=${tmpdir}/ca.key
|
||||
SSL_CERT=${tmpdir}/redis.crt
|
||||
SSL_KEY=${tmpdir}/redis.key
|
||||
|
||||
openssl genrsa -out ${tmpdir}/ca.key 4096
|
||||
openssl req \
|
||||
-x509 -new -nodes -sha256 \
|
||||
-key ${SSL_CA_KEY} \
|
||||
-days 3650 \
|
||||
-subj '/CN=Hiredis Test CA' \
|
||||
-out ${SSL_CA_CERT}
|
||||
openssl genrsa -out ${SSL_KEY} 2048
|
||||
openssl req \
|
||||
-new -sha256 \
|
||||
-key ${SSL_KEY} \
|
||||
-subj '/CN=Hiredis Test Cert' | \
|
||||
openssl x509 \
|
||||
-req -sha256 \
|
||||
-CA ${SSL_CA_CERT} \
|
||||
-CAkey ${SSL_CA_KEY} \
|
||||
-CAserial ${tmpdir}/ca.txt \
|
||||
-CAcreateserial \
|
||||
-days 365 \
|
||||
-out ${SSL_CERT}
|
||||
|
||||
SSL_TEST_ARGS="--ssl-host 127.0.0.1 --ssl-port ${REDIS_SSL_PORT} --ssl-ca-cert ${SSL_CA_CERT} --ssl-cert ${SSL_CERT} --ssl-key ${SSL_KEY}"
|
||||
fi
|
||||
|
||||
cleanup() {
|
||||
set +e
|
||||
kill $(cat ${PID_FILE})
|
||||
rm -rf ${tmpdir}
|
||||
}
|
||||
trap cleanup INT TERM EXIT
|
||||
|
||||
cat > ${tmpdir}/redis.conf <<EOF
|
||||
daemonize yes
|
||||
pidfile ${PID_FILE}
|
||||
port ${REDIS_PORT}
|
||||
bind 127.0.0.1
|
||||
unixsocket ${SOCK_FILE}
|
||||
EOF
|
||||
|
||||
if [ "$TEST_SSL" = "1" ]; then
|
||||
cat >> ${tmpdir}/redis.conf <<EOF
|
||||
tls-port ${REDIS_SSL_PORT}
|
||||
tls-ca-cert-file ${SSL_CA_CERT}
|
||||
tls-cert-file ${SSL_CERT}
|
||||
tls-key-file ${SSL_KEY}
|
||||
EOF
|
||||
fi
|
||||
|
||||
cat ${tmpdir}/redis.conf
|
||||
${REDIS_SERVER} ${tmpdir}/redis.conf
|
||||
|
||||
${TEST_PREFIX:-} ./hiredis-test -h 127.0.0.1 -p ${REDIS_PORT} -s ${SOCK_FILE} ${SSL_TEST_ARGS}
|
18
deps/hiredis/win32.h
vendored
18
deps/hiredis/win32.h
vendored
@ -2,10 +2,20 @@
|
||||
#define _WIN32_HELPER_INCLUDE
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#include <winsock2.h> /* for struct timeval */
|
||||
|
||||
#ifndef inline
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
#ifndef strcasecmp
|
||||
#define strcasecmp stricmp
|
||||
#endif
|
||||
|
||||
#ifndef strncasecmp
|
||||
#define strncasecmp strnicmp
|
||||
#endif
|
||||
|
||||
#ifndef va_copy
|
||||
#define va_copy(d,s) ((d) = (s))
|
||||
#endif
|
||||
@ -37,6 +47,10 @@ __inline int c99_snprintf(char* str, size_t size, const char* format, ...)
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#define strerror_r(errno,buf,len) strerror_s(buf,len,errno)
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* _WIN32_HELPER_INCLUDE */
|
||||
|
42
deps/jemalloc/.appveyor.yml
vendored
Normal file
42
deps/jemalloc/.appveyor.yml
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
version: '{build}'
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- MSYSTEM: MINGW64
|
||||
CPU: x86_64
|
||||
MSVC: amd64
|
||||
- MSYSTEM: MINGW32
|
||||
CPU: i686
|
||||
MSVC: x86
|
||||
- MSYSTEM: MINGW64
|
||||
CPU: x86_64
|
||||
- MSYSTEM: MINGW32
|
||||
CPU: i686
|
||||
- MSYSTEM: MINGW64
|
||||
CPU: x86_64
|
||||
MSVC: amd64
|
||||
CONFIG_FLAGS: --enable-debug
|
||||
- MSYSTEM: MINGW32
|
||||
CPU: i686
|
||||
MSVC: x86
|
||||
CONFIG_FLAGS: --enable-debug
|
||||
- MSYSTEM: MINGW64
|
||||
CPU: x86_64
|
||||
CONFIG_FLAGS: --enable-debug
|
||||
- MSYSTEM: MINGW32
|
||||
CPU: i686
|
||||
CONFIG_FLAGS: --enable-debug
|
||||
|
||||
install:
|
||||
- set PATH=c:\msys64\%MSYSTEM%\bin;c:\msys64\usr\bin;%PATH%
|
||||
- if defined MSVC call "c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %MSVC%
|
||||
- if defined MSVC pacman --noconfirm -Rsc mingw-w64-%CPU%-gcc gcc
|
||||
- pacman --noconfirm -Suy mingw-w64-%CPU%-make
|
||||
|
||||
build_script:
|
||||
- bash -c "autoconf"
|
||||
- bash -c "./configure $CONFIG_FLAGS"
|
||||
- mingw32-make
|
||||
- file lib/jemalloc.dll
|
||||
- mingw32-make tests
|
||||
- mingw32-make -k check
|
46
deps/jemalloc/.gitignore
vendored
46
deps/jemalloc/.gitignore
vendored
@ -1,5 +1,3 @@
|
||||
/*.gcov.*
|
||||
|
||||
/bin/jemalloc-config
|
||||
/bin/jemalloc.sh
|
||||
/bin/jeprof
|
||||
@ -21,10 +19,14 @@
|
||||
|
||||
/Makefile
|
||||
|
||||
/include/jemalloc/internal/jemalloc_internal.h
|
||||
/include/jemalloc/internal/jemalloc_preamble.h
|
||||
/include/jemalloc/internal/jemalloc_internal_defs.h
|
||||
/include/jemalloc/internal/private_namespace.gen.h
|
||||
/include/jemalloc/internal/private_namespace.h
|
||||
/include/jemalloc/internal/private_unnamespace.h
|
||||
/include/jemalloc/internal/private_namespace_jet.gen.h
|
||||
/include/jemalloc/internal/private_namespace_jet.h
|
||||
/include/jemalloc/internal/private_symbols.awk
|
||||
/include/jemalloc/internal/private_symbols_jet.awk
|
||||
/include/jemalloc/internal/public_namespace.h
|
||||
/include/jemalloc/internal/public_symbols.txt
|
||||
/include/jemalloc/internal/public_unnamespace.h
|
||||
@ -40,8 +42,9 @@
|
||||
/include/jemalloc/jemalloc_typedefs.h
|
||||
|
||||
/src/*.[od]
|
||||
/src/*.gcda
|
||||
/src/*.gcno
|
||||
/src/*.sym
|
||||
|
||||
/run_tests.out/
|
||||
|
||||
/test/test.sh
|
||||
test/include/test/jemalloc_test.h
|
||||
@ -50,26 +53,41 @@ test/include/test/jemalloc_test_defs.h
|
||||
/test/integration/[A-Za-z]*
|
||||
!/test/integration/[A-Za-z]*.*
|
||||
/test/integration/*.[od]
|
||||
/test/integration/*.gcda
|
||||
/test/integration/*.gcno
|
||||
/test/integration/*.out
|
||||
|
||||
/test/integration/cpp/[A-Za-z]*
|
||||
!/test/integration/cpp/[A-Za-z]*.*
|
||||
/test/integration/cpp/*.[od]
|
||||
/test/integration/cpp/*.out
|
||||
|
||||
/test/src/*.[od]
|
||||
/test/src/*.gcda
|
||||
/test/src/*.gcno
|
||||
|
||||
/test/stress/[A-Za-z]*
|
||||
!/test/stress/[A-Za-z]*.*
|
||||
/test/stress/*.[od]
|
||||
/test/stress/*.gcda
|
||||
/test/stress/*.gcno
|
||||
/test/stress/*.out
|
||||
|
||||
/test/unit/[A-Za-z]*
|
||||
!/test/unit/[A-Za-z]*.*
|
||||
/test/unit/*.[od]
|
||||
/test/unit/*.gcda
|
||||
/test/unit/*.gcno
|
||||
/test/unit/*.out
|
||||
|
||||
/VERSION
|
||||
|
||||
*.pdb
|
||||
*.sdf
|
||||
*.opendb
|
||||
*.VC.db
|
||||
*.opensdf
|
||||
*.cachefile
|
||||
*.suo
|
||||
*.user
|
||||
*.sln.docstates
|
||||
*.tmp
|
||||
.vs/
|
||||
/msvc/Win32/
|
||||
/msvc/x64/
|
||||
/msvc/projects/*/*/Debug*/
|
||||
/msvc/projects/*/*/Release*/
|
||||
/msvc/projects/*/*/Win32/
|
||||
/msvc/projects/*/*/x64/
|
||||
|
156
deps/jemalloc/.travis.yml
vendored
Normal file
156
deps/jemalloc/.travis.yml
vendored
Normal file
@ -0,0 +1,156 @@
|
||||
language: generic
|
||||
dist: precise
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: osx
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: osx
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: osx
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: osx
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: osx
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: osx
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- os: linux
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false,dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false,percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false,background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary,percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary,background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
- os: linux
|
||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu,background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||
|
||||
|
||||
before_script:
|
||||
- autoconf
|
||||
- ./configure ${COMPILER_FLAGS:+ CC="$CC $COMPILER_FLAGS" CXX="$CXX $COMPILER_FLAGS" } $CONFIGURE_FLAGS
|
||||
- make -j3
|
||||
- make -j3 tests
|
||||
|
||||
script:
|
||||
- make check
|
||||
|
4
deps/jemalloc/COPYING
vendored
4
deps/jemalloc/COPYING
vendored
@ -1,10 +1,10 @@
|
||||
Unless otherwise specified, files in the jemalloc source distribution are
|
||||
subject to the following license:
|
||||
--------------------------------------------------------------------------------
|
||||
Copyright (C) 2002-2015 Jason Evans <jasone@canonware.com>.
|
||||
Copyright (C) 2002-2018 Jason Evans <jasone@canonware.com>.
|
||||
All rights reserved.
|
||||
Copyright (C) 2007-2012 Mozilla Foundation. All rights reserved.
|
||||
Copyright (C) 2009-2015 Facebook, Inc. All rights reserved.
|
||||
Copyright (C) 2009-2018 Facebook, Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
596
deps/jemalloc/ChangeLog
vendored
596
deps/jemalloc/ChangeLog
vendored
@ -4,6 +4,600 @@ brevity. Much more detail can be found in the git revision history:
|
||||
|
||||
https://github.com/jemalloc/jemalloc
|
||||
|
||||
* 5.1.0 (May 4th, 2018)
|
||||
|
||||
This release is primarily about fine-tuning, ranging from several new features
|
||||
to numerous notable performance and portability enhancements. The release and
|
||||
prior dev versions have been running in multiple large scale applications for
|
||||
months, and the cumulative improvements are substantial in many cases.
|
||||
|
||||
Given the long and successful production runs, this release is likely a good
|
||||
candidate for applications to upgrade, from both jemalloc 5.0 and before. For
|
||||
performance-critical applications, the newly added TUNING.md provides
|
||||
guidelines on jemalloc tuning.
|
||||
|
||||
New features:
|
||||
- Implement transparent huge page support for internal metadata. (@interwq)
|
||||
- Add opt.thp to allow enabling / disabling transparent huge pages for all
|
||||
mappings. (@interwq)
|
||||
- Add maximum background thread count option. (@djwatson)
|
||||
- Allow prof_active to control opt.lg_prof_interval and prof.gdump.
|
||||
(@interwq)
|
||||
- Allow arena index lookup based on allocation addresses via mallctl.
|
||||
(@lionkov)
|
||||
- Allow disabling initial-exec TLS model. (@davidtgoldblatt, @KenMacD)
|
||||
- Add opt.lg_extent_max_active_fit to set the max ratio between the size of
|
||||
the active extent selected (to split off from) and the size of the requested
|
||||
allocation. (@interwq, @davidtgoldblatt)
|
||||
- Add retain_grow_limit to set the max size when growing virtual address
|
||||
space. (@interwq)
|
||||
- Add mallctl interfaces:
|
||||
+ arena.<i>.retain_grow_limit (@interwq)
|
||||
+ arenas.lookup (@lionkov)
|
||||
+ max_background_threads (@djwatson)
|
||||
+ opt.lg_extent_max_active_fit (@interwq)
|
||||
+ opt.max_background_threads (@djwatson)
|
||||
+ opt.metadata_thp (@interwq)
|
||||
+ opt.thp (@interwq)
|
||||
+ stats.metadata_thp (@interwq)
|
||||
|
||||
Portability improvements:
|
||||
- Support GNU/kFreeBSD configuration. (@paravoid)
|
||||
- Support m68k, nios2 and SH3 architectures. (@paravoid)
|
||||
- Fall back to FD_CLOEXEC when O_CLOEXEC is unavailable. (@zonyitoo)
|
||||
- Fix symbol listing for cross-compiling. (@tamird)
|
||||
- Fix high bits computation on ARM. (@davidtgoldblatt, @paravoid)
|
||||
- Disable the CPU_SPINWAIT macro for Power. (@davidtgoldblatt, @marxin)
|
||||
- Fix MSVC 2015 & 2017 builds. (@rustyx)
|
||||
- Improve RISC-V support. (@EdSchouten)
|
||||
- Set name mangling script in strict mode. (@nicolov)
|
||||
- Avoid MADV_HUGEPAGE on ARM. (@marxin)
|
||||
- Modify configure to determine return value of strerror_r.
|
||||
(@davidtgoldblatt, @cferris1000)
|
||||
- Make sure CXXFLAGS is tested with CPP compiler. (@nehaljwani)
|
||||
- Fix 32-bit build on MSVC. (@rustyx)
|
||||
- Fix external symbol on MSVC. (@maksqwe)
|
||||
- Avoid a printf format specifier warning. (@jasone)
|
||||
- Add configure option --disable-initial-exec-tls which can allow jemalloc to
|
||||
be dynamically loaded after program startup. (@davidtgoldblatt, @KenMacD)
|
||||
- AArch64: Add ILP32 support. (@cmuellner)
|
||||
- Add --with-lg-vaddr configure option to support cross compiling.
|
||||
(@cmuellner, @davidtgoldblatt)
|
||||
|
||||
Optimizations and refactors:
|
||||
- Improve active extent fit with extent_max_active_fit. This considerably
|
||||
reduces fragmentation over time and improves virtual memory and metadata
|
||||
usage. (@davidtgoldblatt, @interwq)
|
||||
- Eagerly coalesce large extents to reduce fragmentation. (@interwq)
|
||||
- sdallocx: only read size info when page aligned (i.e. possibly sampled),
|
||||
which speeds up the sized deallocation path significantly. (@interwq)
|
||||
- Avoid attempting new mappings for in place expansion with retain, since
|
||||
it rarely succeeds in practice and causes high overhead. (@interwq)
|
||||
- Refactor OOM handling in newImpl. (@wqfish)
|
||||
- Add internal fine-grained logging functionality for debugging use.
|
||||
(@davidtgoldblatt)
|
||||
- Refactor arena / tcache interactions. (@davidtgoldblatt)
|
||||
- Refactor extent management with dumpable flag. (@davidtgoldblatt)
|
||||
- Add runtime detection of lazy purging. (@interwq)
|
||||
- Use pairing heap instead of red-black tree for extents_avail. (@djwatson)
|
||||
- Use sysctl on startup in FreeBSD. (@trasz)
|
||||
- Use thread local prng state instead of atomic. (@djwatson)
|
||||
- Make decay to always purge one more extent than before, because in
|
||||
practice large extents are usually the ones that cross the decay threshold.
|
||||
Purging the additional extent helps save memory as well as reduce VM
|
||||
fragmentation. (@interwq)
|
||||
- Fast division by dynamic values. (@davidtgoldblatt)
|
||||
- Improve the fit for aligned allocation. (@interwq, @edwinsmith)
|
||||
- Refactor extent_t bitpacking. (@rkmisra)
|
||||
- Optimize the generated assembly for ticker operations. (@davidtgoldblatt)
|
||||
- Convert stats printing to use a structured text emitter. (@davidtgoldblatt)
|
||||
- Remove preserve_lru feature for extents management. (@djwatson)
|
||||
- Consolidate two memory loads into one on the fast deallocation path.
|
||||
(@davidtgoldblatt, @interwq)
|
||||
|
||||
Bug fixes (most of the issues are only relevant to jemalloc 5.0):
|
||||
- Fix deadlock with multithreaded fork in OS X. (@davidtgoldblatt)
|
||||
- Validate returned file descriptor before use. (@zonyitoo)
|
||||
- Fix a few background thread initialization and shutdown issues. (@interwq)
|
||||
- Fix an extent coalesce + decay race by taking both coalescing extents off
|
||||
the LRU list. (@interwq)
|
||||
- Fix potentially unbound increase during decay, caused by one thread keep
|
||||
stashing memory to purge while other threads generating new pages. The
|
||||
number of pages to purge is checked to prevent this. (@interwq)
|
||||
- Fix a FreeBSD bootstrap assertion. (@strejda, @interwq)
|
||||
- Handle 32 bit mutex counters. (@rkmisra)
|
||||
- Fix a indexing bug when creating background threads. (@davidtgoldblatt,
|
||||
@binliu19)
|
||||
- Fix arguments passed to extent_init. (@yuleniwo, @interwq)
|
||||
- Fix addresses used for ordering mutexes. (@rkmisra)
|
||||
- Fix abort_conf processing during bootstrap. (@interwq)
|
||||
- Fix include path order for out-of-tree builds. (@cmuellner)
|
||||
|
||||
Incompatible changes:
|
||||
- Remove --disable-thp. (@interwq)
|
||||
- Remove mallctl interfaces:
|
||||
+ config.thp (@interwq)
|
||||
|
||||
Documentation:
|
||||
- Add TUNING.md. (@interwq, @davidtgoldblatt, @djwatson)
|
||||
|
||||
* 5.0.1 (July 1, 2017)
|
||||
|
||||
This bugfix release fixes several issues, most of which are obscure enough
|
||||
that typical applications are not impacted.
|
||||
|
||||
Bug fixes:
|
||||
- Update decay->nunpurged before purging, in order to avoid potential update
|
||||
races and subsequent incorrect purging volume. (@interwq)
|
||||
- Only abort on dlsym(3) error if the failure impacts an enabled feature (lazy
|
||||
locking and/or background threads). This mitigates an initialization
|
||||
failure bug for which we still do not have a clear reproduction test case.
|
||||
(@interwq)
|
||||
- Modify tsd management so that it neither crashes nor leaks if a thread's
|
||||
only allocation activity is to call free() after TLS destructors have been
|
||||
executed. This behavior was observed when operating with GNU libc, and is
|
||||
unlikely to be an issue with other libc implementations. (@interwq)
|
||||
- Mask signals during background thread creation. This prevents signals from
|
||||
being inadvertently delivered to background threads. (@jasone,
|
||||
@davidtgoldblatt, @interwq)
|
||||
- Avoid inactivity checks within background threads, in order to prevent
|
||||
recursive mutex acquisition. (@interwq)
|
||||
- Fix extent_grow_retained() to use the specified hooks when the
|
||||
arena.<i>.extent_hooks mallctl is used to override the default hooks.
|
||||
(@interwq)
|
||||
- Add missing reentrancy support for custom extent hooks which allocate.
|
||||
(@interwq)
|
||||
- Post-fork(2), re-initialize the list of tcaches associated with each arena
|
||||
to contain no tcaches except the forking thread's. (@interwq)
|
||||
- Add missing post-fork(2) mutex reinitialization for extent_grow_mtx. This
|
||||
fixes potential deadlocks after fork(2). (@interwq)
|
||||
- Enforce minimum autoconf version (currently 2.68), since 2.63 is known to
|
||||
generate corrupt configure scripts. (@jasone)
|
||||
- Ensure that the configured page size (--with-lg-page) is no larger than the
|
||||
configured huge page size (--with-lg-hugepage). (@jasone)
|
||||
|
||||
* 5.0.0 (June 13, 2017)
|
||||
|
||||
Unlike all previous jemalloc releases, this release does not use naturally
|
||||
aligned "chunks" for virtual memory management, and instead uses page-aligned
|
||||
"extents". This change has few externally visible effects, but the internal
|
||||
impacts are... extensive. Many other internal changes combine to make this
|
||||
the most cohesively designed version of jemalloc so far, with ample
|
||||
opportunity for further enhancements.
|
||||
|
||||
Continuous integration is now an integral aspect of development thanks to the
|
||||
efforts of @davidtgoldblatt, and the dev branch tends to remain reasonably
|
||||
stable on the tested platforms (Linux, FreeBSD, macOS, and Windows). As a
|
||||
side effect the official release frequency may decrease over time.
|
||||
|
||||
New features:
|
||||
- Implement optional per-CPU arena support; threads choose which arena to use
|
||||
based on current CPU rather than on fixed thread-->arena associations.
|
||||
(@interwq)
|
||||
- Implement two-phase decay of unused dirty pages. Pages transition from
|
||||
dirty-->muzzy-->clean, where the first phase transition relies on
|
||||
madvise(... MADV_FREE) semantics, and the second phase transition discards
|
||||
pages such that they are replaced with demand-zeroed pages on next access.
|
||||
(@jasone)
|
||||
- Increase decay time resolution from seconds to milliseconds. (@jasone)
|
||||
- Implement opt-in per CPU background threads, and use them for asynchronous
|
||||
decay-driven unused dirty page purging. (@interwq)
|
||||
- Add mutex profiling, which collects a variety of statistics useful for
|
||||
diagnosing overhead/contention issues. (@interwq)
|
||||
- Add C++ new/delete operator bindings. (@djwatson)
|
||||
- Support manually created arena destruction, such that all data and metadata
|
||||
are discarded. Add MALLCTL_ARENAS_DESTROYED for accessing merged stats
|
||||
associated with destroyed arenas. (@jasone)
|
||||
- Add MALLCTL_ARENAS_ALL as a fixed index for use in accessing
|
||||
merged/destroyed arena statistics via mallctl. (@jasone)
|
||||
- Add opt.abort_conf to optionally abort if invalid configuration options are
|
||||
detected during initialization. (@interwq)
|
||||
- Add opt.stats_print_opts, so that e.g. JSON output can be selected for the
|
||||
stats dumped during exit if opt.stats_print is true. (@jasone)
|
||||
- Add --with-version=VERSION for use when embedding jemalloc into another
|
||||
project's git repository. (@jasone)
|
||||
- Add --disable-thp to support cross compiling. (@jasone)
|
||||
- Add --with-lg-hugepage to support cross compiling. (@jasone)
|
||||
- Add mallctl interfaces (various authors):
|
||||
+ background_thread
|
||||
+ opt.abort_conf
|
||||
+ opt.retain
|
||||
+ opt.percpu_arena
|
||||
+ opt.background_thread
|
||||
+ opt.{dirty,muzzy}_decay_ms
|
||||
+ opt.stats_print_opts
|
||||
+ arena.<i>.initialized
|
||||
+ arena.<i>.destroy
|
||||
+ arena.<i>.{dirty,muzzy}_decay_ms
|
||||
+ arena.<i>.extent_hooks
|
||||
+ arenas.{dirty,muzzy}_decay_ms
|
||||
+ arenas.bin.<i>.slab_size
|
||||
+ arenas.nlextents
|
||||
+ arenas.lextent.<i>.size
|
||||
+ arenas.create
|
||||
+ stats.background_thread.{num_threads,num_runs,run_interval}
|
||||
+ stats.mutexes.{ctl,background_thread,prof,reset}.
|
||||
{num_ops,num_spin_acq,num_wait,max_wait_time,total_wait_time,max_num_thds,
|
||||
num_owner_switch}
|
||||
+ stats.arenas.<i>.{dirty,muzzy}_decay_ms
|
||||
+ stats.arenas.<i>.uptime
|
||||
+ stats.arenas.<i>.{pmuzzy,base,internal,resident}
|
||||
+ stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
|
||||
+ stats.arenas.<i>.bins.<j>.{nslabs,reslabs,curslabs}
|
||||
+ stats.arenas.<i>.bins.<j>.mutex.
|
||||
{num_ops,num_spin_acq,num_wait,max_wait_time,total_wait_time,max_num_thds,
|
||||
num_owner_switch}
|
||||
+ stats.arenas.<i>.lextents.<j>.{nmalloc,ndalloc,nrequests,curlextents}
|
||||
+ stats.arenas.i.mutexes.{large,extent_avail,extents_dirty,extents_muzzy,
|
||||
extents_retained,decay_dirty,decay_muzzy,base,tcache_list}.
|
||||
{num_ops,num_spin_acq,num_wait,max_wait_time,total_wait_time,max_num_thds,
|
||||
num_owner_switch}
|
||||
|
||||
Portability improvements:
|
||||
- Improve reentrant allocation support, such that deadlock is less likely if
|
||||
e.g. a system library call in turn allocates memory. (@davidtgoldblatt,
|
||||
@interwq)
|
||||
- Support static linking of jemalloc with glibc. (@djwatson)
|
||||
|
||||
Optimizations and refactors:
|
||||
- Organize virtual memory as "extents" of virtual memory pages, rather than as
|
||||
naturally aligned "chunks", and store all metadata in arbitrarily distant
|
||||
locations. This reduces virtual memory external fragmentation, and will
|
||||
interact better with huge pages (not yet explicitly supported). (@jasone)
|
||||
- Fold large and huge size classes together; only small and large size classes
|
||||
remain. (@jasone)
|
||||
- Unify the allocation paths, and merge most fast-path branching decisions.
|
||||
(@davidtgoldblatt, @interwq)
|
||||
- Embed per thread automatic tcache into thread-specific data, which reduces
|
||||
conditional branches and dereferences. Also reorganize tcache to increase
|
||||
fast-path data locality. (@interwq)
|
||||
- Rewrite atomics to closely model the C11 API, convert various
|
||||
synchronization from mutex-based to atomic, and use the explicit memory
|
||||
ordering control to resolve various hypothetical races without increasing
|
||||
synchronization overhead. (@davidtgoldblatt)
|
||||
- Extensively optimize rtree via various methods:
|
||||
+ Add multiple layers of rtree lookup caching, since rtree lookups are now
|
||||
part of fast-path deallocation. (@interwq)
|
||||
+ Determine rtree layout at compile time. (@jasone)
|
||||
+ Make the tree shallower for common configurations. (@jasone)
|
||||
+ Embed the root node in the top-level rtree data structure, thus avoiding
|
||||
one level of indirection. (@jasone)
|
||||
+ Further specialize leaf elements as compared to internal node elements,
|
||||
and directly embed extent metadata needed for fast-path deallocation.
|
||||
(@jasone)
|
||||
+ Ignore leading always-zero address bits (architecture-specific).
|
||||
(@jasone)
|
||||
- Reorganize headers (ongoing work) to make them hermetic, and disentangle
|
||||
various module dependencies. (@davidtgoldblatt)
|
||||
- Convert various internal data structures such as size class metadata from
|
||||
boot-time-initialized to compile-time-initialized. Propagate resulting data
|
||||
structure simplifications, such as making arena metadata fixed-size.
|
||||
(@jasone)
|
||||
- Simplify size class lookups when constrained to size classes that are
|
||||
multiples of the page size. This speeds lookups, but the primary benefit is
|
||||
complexity reduction in code that was the source of numerous regressions.
|
||||
(@jasone)
|
||||
- Lock individual extents when possible for localized extent operations,
|
||||
rather than relying on a top-level arena lock. (@davidtgoldblatt, @jasone)
|
||||
- Use first fit layout policy instead of best fit, in order to improve
|
||||
packing. (@jasone)
|
||||
- If munmap(2) is not in use, use an exponential series to grow each arena's
|
||||
virtual memory, so that the number of disjoint virtual memory mappings
|
||||
remains low. (@jasone)
|
||||
- Implement per arena base allocators, so that arenas never share any virtual
|
||||
memory pages. (@jasone)
|
||||
- Automatically generate private symbol name mangling macros. (@jasone)
|
||||
|
||||
Incompatible changes:
|
||||
- Replace chunk hooks with an expanded/normalized set of extent hooks.
|
||||
(@jasone)
|
||||
- Remove ratio-based purging. (@jasone)
|
||||
- Remove --disable-tcache. (@jasone)
|
||||
- Remove --disable-tls. (@jasone)
|
||||
- Remove --enable-ivsalloc. (@jasone)
|
||||
- Remove --with-lg-size-class-group. (@jasone)
|
||||
- Remove --with-lg-tiny-min. (@jasone)
|
||||
- Remove --disable-cc-silence. (@jasone)
|
||||
- Remove --enable-code-coverage. (@jasone)
|
||||
- Remove --disable-munmap (replaced by opt.retain). (@jasone)
|
||||
- Remove Valgrind support. (@jasone)
|
||||
- Remove quarantine support. (@jasone)
|
||||
- Remove redzone support. (@jasone)
|
||||
- Remove mallctl interfaces (various authors):
|
||||
+ config.munmap
|
||||
+ config.tcache
|
||||
+ config.tls
|
||||
+ config.valgrind
|
||||
+ opt.lg_chunk
|
||||
+ opt.purge
|
||||
+ opt.lg_dirty_mult
|
||||
+ opt.decay_time
|
||||
+ opt.quarantine
|
||||
+ opt.redzone
|
||||
+ opt.thp
|
||||
+ arena.<i>.lg_dirty_mult
|
||||
+ arena.<i>.decay_time
|
||||
+ arena.<i>.chunk_hooks
|
||||
+ arenas.initialized
|
||||
+ arenas.lg_dirty_mult
|
||||
+ arenas.decay_time
|
||||
+ arenas.bin.<i>.run_size
|
||||
+ arenas.nlruns
|
||||
+ arenas.lrun.<i>.size
|
||||
+ arenas.nhchunks
|
||||
+ arenas.hchunk.<i>.size
|
||||
+ arenas.extend
|
||||
+ stats.cactive
|
||||
+ stats.arenas.<i>.lg_dirty_mult
|
||||
+ stats.arenas.<i>.decay_time
|
||||
+ stats.arenas.<i>.metadata.{mapped,allocated}
|
||||
+ stats.arenas.<i>.{npurge,nmadvise,purged}
|
||||
+ stats.arenas.<i>.huge.{allocated,nmalloc,ndalloc,nrequests}
|
||||
+ stats.arenas.<i>.bins.<j>.{nruns,reruns,curruns}
|
||||
+ stats.arenas.<i>.lruns.<j>.{nmalloc,ndalloc,nrequests,curruns}
|
||||
+ stats.arenas.<i>.hchunks.<j>.{nmalloc,ndalloc,nrequests,curhchunks}
|
||||
|
||||
Bug fixes:
|
||||
- Improve interval-based profile dump triggering to dump only one profile when
|
||||
a single allocation's size exceeds the interval. (@jasone)
|
||||
- Use prefixed function names (as controlled by --with-jemalloc-prefix) when
|
||||
pruning backtrace frames in jeprof. (@jasone)
|
||||
|
||||
* 4.5.0 (February 28, 2017)
|
||||
|
||||
This is the first release to benefit from much broader continuous integration
|
||||
testing, thanks to @davidtgoldblatt. Had we had this testing infrastructure
|
||||
in place for prior releases, it would have caught all of the most serious
|
||||
regressions fixed by this release.
|
||||
|
||||
New features:
|
||||
- Add --disable-thp and the opt.thp mallctl to provide opt-out mechanisms for
|
||||
transparent huge page integration. (@jasone)
|
||||
- Update zone allocator integration to work with macOS 10.12. (@glandium)
|
||||
- Restructure *CFLAGS configuration, so that CFLAGS behaves typically, and
|
||||
EXTRA_CFLAGS provides a way to specify e.g. -Werror during building, but not
|
||||
during configuration. (@jasone, @ronawho)
|
||||
|
||||
Bug fixes:
|
||||
- Fix DSS (sbrk(2)-based) allocation. This regression was first released in
|
||||
4.3.0. (@jasone)
|
||||
- Handle race in per size class utilization computation. This functionality
|
||||
was first released in 4.0.0. (@interwq)
|
||||
- Fix lock order reversal during gdump. (@jasone)
|
||||
- Fix/refactor tcache synchronization. This regression was first released in
|
||||
4.0.0. (@jasone)
|
||||
- Fix various JSON-formatted malloc_stats_print() bugs. This functionality
|
||||
was first released in 4.3.0. (@jasone)
|
||||
- Fix huge-aligned allocation. This regression was first released in 4.4.0.
|
||||
(@jasone)
|
||||
- When transparent huge page integration is enabled, detect what state pages
|
||||
start in according to the kernel's current operating mode, and only convert
|
||||
arena chunks to non-huge during purging if that is not their initial state.
|
||||
This functionality was first released in 4.4.0. (@jasone)
|
||||
- Fix lg_chunk clamping for the --enable-cache-oblivious --disable-fill case.
|
||||
This regression was first released in 4.0.0. (@jasone, @428desmo)
|
||||
- Properly detect sparc64 when building for Linux. (@glaubitz)
|
||||
|
||||
* 4.4.0 (December 3, 2016)
|
||||
|
||||
New features:
|
||||
- Add configure support for *-*-linux-android. (@cferris1000, @jasone)
|
||||
- Add the --disable-syscall configure option, for use on systems that place
|
||||
security-motivated limitations on syscall(2). (@jasone)
|
||||
- Add support for Debian GNU/kFreeBSD. (@thesam)
|
||||
|
||||
Optimizations:
|
||||
- Add extent serial numbers and use them where appropriate as a sort key that
|
||||
is higher priority than address, so that the allocation policy prefers older
|
||||
extents. This tends to improve locality (decrease fragmentation) when
|
||||
memory grows downward. (@jasone)
|
||||
- Refactor madvise(2) configuration so that MADV_FREE is detected and utilized
|
||||
on Linux 4.5 and newer. (@jasone)
|
||||
- Mark partially purged arena chunks as non-huge-page. This improves
|
||||
interaction with Linux's transparent huge page functionality. (@jasone)
|
||||
|
||||
Bug fixes:
|
||||
- Fix size class computations for edge conditions involving extremely large
|
||||
allocations. This regression was first released in 4.0.0. (@jasone,
|
||||
@ingvarha)
|
||||
- Remove overly restrictive assertions related to the cactive statistic. This
|
||||
regression was first released in 4.1.0. (@jasone)
|
||||
- Implement a more reliable detection scheme for os_unfair_lock on macOS.
|
||||
(@jszakmeister)
|
||||
|
||||
* 4.3.1 (November 7, 2016)
|
||||
|
||||
Bug fixes:
|
||||
- Fix a severe virtual memory leak. This regression was first released in
|
||||
4.3.0. (@interwq, @jasone)
|
||||
- Refactor atomic and prng APIs to restore support for 32-bit platforms that
|
||||
use pre-C11 toolchains, e.g. FreeBSD's mips. (@jasone)
|
||||
|
||||
* 4.3.0 (November 4, 2016)
|
||||
|
||||
This is the first release that passes the test suite for multiple Windows
|
||||
configurations, thanks in large part to @glandium setting up continuous
|
||||
integration via AppVeyor (and Travis CI for Linux and OS X).
|
||||
|
||||
New features:
|
||||
- Add "J" (JSON) support to malloc_stats_print(). (@jasone)
|
||||
- Add Cray compiler support. (@ronawho)
|
||||
|
||||
Optimizations:
|
||||
- Add/use adaptive spinning for bootstrapping and radix tree node
|
||||
initialization. (@jasone)
|
||||
|
||||
Bug fixes:
|
||||
- Fix large allocation to search starting in the optimal size class heap,
|
||||
which can substantially reduce virtual memory churn and fragmentation. This
|
||||
regression was first released in 4.0.0. (@mjp41, @jasone)
|
||||
- Fix stats.arenas.<i>.nthreads accounting. (@interwq)
|
||||
- Fix and simplify decay-based purging. (@jasone)
|
||||
- Make DSS (sbrk(2)-related) operations lockless, which resolves potential
|
||||
deadlocks during thread exit. (@jasone)
|
||||
- Fix over-sized allocation of radix tree leaf nodes. (@mjp41, @ogaun,
|
||||
@jasone)
|
||||
- Fix over-sized allocation of arena_t (plus associated stats) data
|
||||
structures. (@jasone, @interwq)
|
||||
- Fix EXTRA_CFLAGS to not affect configuration. (@jasone)
|
||||
- Fix a Valgrind integration bug. (@ronawho)
|
||||
- Disallow 0x5a junk filling when running in Valgrind. (@jasone)
|
||||
- Fix a file descriptor leak on Linux. This regression was first released in
|
||||
4.2.0. (@vsarunas, @jasone)
|
||||
- Fix static linking of jemalloc with glibc. (@djwatson)
|
||||
- Use syscall(2) rather than {open,read,close}(2) during boot on Linux. This
|
||||
works around other libraries' system call wrappers performing reentrant
|
||||
allocation. (@kspinka, @Whissi, @jasone)
|
||||
- Fix OS X default zone replacement to work with OS X 10.12. (@glandium,
|
||||
@jasone)
|
||||
- Fix cached memory management to avoid needless commit/decommit operations
|
||||
during purging, which resolves permanent virtual memory map fragmentation
|
||||
issues on Windows. (@mjp41, @jasone)
|
||||
- Fix TSD fetches to avoid (recursive) allocation. This is relevant to
|
||||
non-TLS and Windows configurations. (@jasone)
|
||||
- Fix malloc_conf overriding to work on Windows. (@jasone)
|
||||
- Forcibly disable lazy-lock on Windows (was forcibly *enabled*). (@jasone)
|
||||
|
||||
* 4.2.1 (June 8, 2016)
|
||||
|
||||
Bug fixes:
|
||||
- Fix bootstrapping issues for configurations that require allocation during
|
||||
tsd initialization (e.g. --disable-tls). (@cferris1000, @jasone)
|
||||
- Fix gettimeofday() version of nstime_update(). (@ronawho)
|
||||
- Fix Valgrind regressions in calloc() and chunk_alloc_wrapper(). (@ronawho)
|
||||
- Fix potential VM map fragmentation regression. (@jasone)
|
||||
- Fix opt_zero-triggered in-place huge reallocation zeroing. (@jasone)
|
||||
- Fix heap profiling context leaks in reallocation edge cases. (@jasone)
|
||||
|
||||
* 4.2.0 (May 12, 2016)
|
||||
|
||||
New features:
|
||||
- Add the arena.<i>.reset mallctl, which makes it possible to discard all of
|
||||
an arena's allocations in a single operation. (@jasone)
|
||||
- Add the stats.retained and stats.arenas.<i>.retained statistics. (@jasone)
|
||||
- Add the --with-version configure option. (@jasone)
|
||||
- Support --with-lg-page values larger than actual page size. (@jasone)
|
||||
|
||||
Optimizations:
|
||||
- Use pairing heaps rather than red-black trees for various hot data
|
||||
structures. (@djwatson, @jasone)
|
||||
- Streamline fast paths of rtree operations. (@jasone)
|
||||
- Optimize the fast paths of calloc() and [m,d,sd]allocx(). (@jasone)
|
||||
- Decommit unused virtual memory if the OS does not overcommit. (@jasone)
|
||||
- Specify MAP_NORESERVE on Linux if [heuristic] overcommit is active, in order
|
||||
to avoid unfortunate interactions during fork(2). (@jasone)
|
||||
|
||||
Bug fixes:
|
||||
- Fix chunk accounting related to triggering gdump profiles. (@jasone)
|
||||
- Link against librt for clock_gettime(2) if glibc < 2.17. (@jasone)
|
||||
- Scale leak report summary according to sampling probability. (@jasone)
|
||||
|
||||
* 4.1.1 (May 3, 2016)
|
||||
|
||||
This bugfix release resolves a variety of mostly minor issues, though the
|
||||
bitmap fix is critical for 64-bit Windows.
|
||||
|
||||
Bug fixes:
|
||||
- Fix the linear scan version of bitmap_sfu() to shift by the proper amount
|
||||
even when sizeof(long) is not the same as sizeof(void *), as on 64-bit
|
||||
Windows. (@jasone)
|
||||
- Fix hashing functions to avoid unaligned memory accesses (and resulting
|
||||
crashes). This is relevant at least to some ARM-based platforms.
|
||||
(@rkmisra)
|
||||
- Fix fork()-related lock rank ordering reversals. These reversals were
|
||||
unlikely to cause deadlocks in practice except when heap profiling was
|
||||
enabled and active. (@jasone)
|
||||
- Fix various chunk leaks in OOM code paths. (@jasone)
|
||||
- Fix malloc_stats_print() to print opt.narenas correctly. (@jasone)
|
||||
- Fix MSVC-specific build/test issues. (@rustyx, @yuslepukhin)
|
||||
- Fix a variety of test failures that were due to test fragility rather than
|
||||
core bugs. (@jasone)
|
||||
|
||||
* 4.1.0 (February 28, 2016)
|
||||
|
||||
This release is primarily about optimizations, but it also incorporates a lot
|
||||
of portability-motivated refactoring and enhancements. Many people worked on
|
||||
this release, to an extent that even with the omission here of minor changes
|
||||
(see git revision history), and of the people who reported and diagnosed
|
||||
issues, so much of the work was contributed that starting with this release,
|
||||
changes are annotated with author credits to help reflect the collaborative
|
||||
effort involved.
|
||||
|
||||
New features:
|
||||
- Implement decay-based unused dirty page purging, a major optimization with
|
||||
mallctl API impact. This is an alternative to the existing ratio-based
|
||||
unused dirty page purging, and is intended to eventually become the sole
|
||||
purging mechanism. New mallctls:
|
||||
+ opt.purge
|
||||
+ opt.decay_time
|
||||
+ arena.<i>.decay
|
||||
+ arena.<i>.decay_time
|
||||
+ arenas.decay_time
|
||||
+ stats.arenas.<i>.decay_time
|
||||
(@jasone, @cevans87)
|
||||
- Add --with-malloc-conf, which makes it possible to embed a default
|
||||
options string during configuration. This was motivated by the desire to
|
||||
specify --with-malloc-conf=purge:decay , since the default must remain
|
||||
purge:ratio until the 5.0.0 release. (@jasone)
|
||||
- Add MS Visual Studio 2015 support. (@rustyx, @yuslepukhin)
|
||||
- Make *allocx() size class overflow behavior defined. The maximum
|
||||
size class is now less than PTRDIFF_MAX to protect applications against
|
||||
numerical overflow, and all allocation functions are guaranteed to indicate
|
||||
errors rather than potentially crashing if the request size exceeds the
|
||||
maximum size class. (@jasone)
|
||||
- jeprof:
|
||||
+ Add raw heap profile support. (@jasone)
|
||||
+ Add --retain and --exclude for backtrace symbol filtering. (@jasone)
|
||||
|
||||
Optimizations:
|
||||
- Optimize the fast path to combine various bootstrapping and configuration
|
||||
checks and execute more streamlined code in the common case. (@interwq)
|
||||
- Use linear scan for small bitmaps (used for small object tracking). In
|
||||
addition to speeding up bitmap operations on 64-bit systems, this reduces
|
||||
allocator metadata overhead by approximately 0.2%. (@djwatson)
|
||||
- Separate arena_avail trees, which substantially speeds up run tree
|
||||
operations. (@djwatson)
|
||||
- Use memoization (boot-time-computed table) for run quantization. Separate
|
||||
arena_avail trees reduced the importance of this optimization. (@jasone)
|
||||
- Attempt mmap-based in-place huge reallocation. This can dramatically speed
|
||||
up incremental huge reallocation. (@jasone)
|
||||
|
||||
Incompatible changes:
|
||||
- Make opt.narenas unsigned rather than size_t. (@jasone)
|
||||
|
||||
Bug fixes:
|
||||
- Fix stats.cactive accounting regression. (@rustyx, @jasone)
|
||||
- Handle unaligned keys in hash(). This caused problems for some ARM systems.
|
||||
(@jasone, @cferris1000)
|
||||
- Refactor arenas array. In addition to fixing a fork-related deadlock, this
|
||||
makes arena lookups faster and simpler. (@jasone)
|
||||
- Move retained memory allocation out of the default chunk allocation
|
||||
function, to a location that gets executed even if the application installs
|
||||
a custom chunk allocation function. This resolves a virtual memory leak.
|
||||
(@buchgr)
|
||||
- Fix a potential tsd cleanup leak. (@cferris1000, @jasone)
|
||||
- Fix run quantization. In practice this bug had no impact unless
|
||||
applications requested memory with alignment exceeding one page.
|
||||
(@jasone, @djwatson)
|
||||
- Fix LinuxThreads-specific bootstrapping deadlock. (Cosmin Paraschiv)
|
||||
- jeprof:
|
||||
+ Don't discard curl options if timeout is not defined. (@djwatson)
|
||||
+ Detect failed profile fetches. (@djwatson)
|
||||
- Fix stats.arenas.<i>.{dss,lg_dirty_mult,decay_time,pactive,pdirty} for
|
||||
--disable-stats case. (@jasone)
|
||||
|
||||
* 4.0.4 (October 24, 2015)
|
||||
|
||||
This bugfix release fixes another xallocx() regression. No other regressions
|
||||
have come to light in over a month, so this is likely a good starting point
|
||||
for people who prefer to wait for "dot one" releases with all the major issues
|
||||
shaken out.
|
||||
|
||||
Bug fixes:
|
||||
- Fix xallocx(..., MALLOCX_ZERO to zero the last full trailing page of large
|
||||
allocations that have been randomly assigned an offset of 0 when
|
||||
--enable-cache-oblivious configure option is enabled.
|
||||
|
||||
* 4.0.3 (September 24, 2015)
|
||||
|
||||
This bugfix release continues the trend of xallocx() and heap profiling fixes.
|
||||
@ -38,7 +632,7 @@ brevity. Much more detail can be found in the git revision history:
|
||||
these fixes, xallocx() now tries harder to partially fulfill requests for
|
||||
optional extra space. Note that a couple of minor heap profiling
|
||||
optimizations are included, but these are better thought of as performance
|
||||
fixes that were integral to disovering most of the other bugs.
|
||||
fixes that were integral to discovering most of the other bugs.
|
||||
|
||||
Optimizations:
|
||||
- Avoid a chunk metadata read in arena_prof_tctx_set(), since it is in the
|
||||
|
329
deps/jemalloc/INSTALL → deps/jemalloc/INSTALL.md
vendored
329
deps/jemalloc/INSTALL → deps/jemalloc/INSTALL.md
vendored
@ -18,16 +18,19 @@ would create a dependency on xsltproc in packaged releases, hence the
|
||||
requirement to either run 'make dist' or avoid installing docs via the various
|
||||
install_* targets documented below.
|
||||
|
||||
=== Advanced configuration =====================================================
|
||||
|
||||
## Advanced configuration
|
||||
|
||||
The 'configure' script supports numerous options that allow control of which
|
||||
functionality is enabled, where jemalloc is installed, etc. Optionally, pass
|
||||
any of the following arguments (not a definitive list) to 'configure':
|
||||
|
||||
--help
|
||||
* `--help`
|
||||
|
||||
Print a definitive list of options.
|
||||
|
||||
--prefix=<install-root-dir>
|
||||
* `--prefix=<install-root-dir>`
|
||||
|
||||
Set the base directory in which to install. For example:
|
||||
|
||||
./configure --prefix=/usr/local
|
||||
@ -35,11 +38,29 @@ any of the following arguments (not a definitive list) to 'configure':
|
||||
will cause files to be installed into /usr/local/include, /usr/local/lib,
|
||||
and /usr/local/man.
|
||||
|
||||
--with-rpath=<colon-separated-rpath>
|
||||
* `--with-version=(<major>.<minor>.<bugfix>-<nrev>-g<gid>|VERSION)`
|
||||
|
||||
The VERSION file is mandatory for successful configuration, and the
|
||||
following steps are taken to assure its presence:
|
||||
1) If --with-version=<major>.<minor>.<bugfix>-<nrev>-g<gid> is specified,
|
||||
generate VERSION using the specified value.
|
||||
2) If --with-version is not specified in either form and the source
|
||||
directory is inside a git repository, try to generate VERSION via 'git
|
||||
describe' invocations that pattern-match release tags.
|
||||
3) If VERSION is missing, generate it with a bogus version:
|
||||
0.0.0-0-g0000000000000000000000000000000000000000
|
||||
|
||||
Note that --with-version=VERSION bypasses (1) and (2), which simplifies
|
||||
VERSION configuration when embedding a jemalloc release into another
|
||||
project's git repository.
|
||||
|
||||
* `--with-rpath=<colon-separated-rpath>`
|
||||
|
||||
Embed one or more library paths, so that libjemalloc can find the libraries
|
||||
it is linked to. This works only on ELF-based systems.
|
||||
|
||||
--with-mangling=<map>
|
||||
* `--with-mangling=<map>`
|
||||
|
||||
Mangle public symbols specified in <map> which is a comma-separated list of
|
||||
name:mangled pairs.
|
||||
|
||||
@ -52,7 +73,8 @@ any of the following arguments (not a definitive list) to 'configure':
|
||||
--with-jemalloc-prefix, and mangled symbols are then ignored when applying
|
||||
the prefix.
|
||||
|
||||
--with-jemalloc-prefix=<prefix>
|
||||
* `--with-jemalloc-prefix=<prefix>`
|
||||
|
||||
Prefix all public APIs with <prefix>. For example, if <prefix> is
|
||||
"prefix_", API changes like the following occur:
|
||||
|
||||
@ -68,55 +90,46 @@ any of the following arguments (not a definitive list) to 'configure':
|
||||
jemalloc overlays the default malloc zone, but makes no attempt to actually
|
||||
replace the "malloc", "calloc", etc. symbols.
|
||||
|
||||
--without-export
|
||||
* `--without-export`
|
||||
|
||||
Don't export public APIs. This can be useful when building jemalloc as a
|
||||
static library, or to avoid exporting public APIs when using the zone
|
||||
allocator on OSX.
|
||||
|
||||
--with-private-namespace=<prefix>
|
||||
* `--with-private-namespace=<prefix>`
|
||||
|
||||
Prefix all library-private APIs with <prefix>je_. For shared libraries,
|
||||
symbol visibility mechanisms prevent these symbols from being exported, but
|
||||
for static libraries, naming collisions are a real possibility. By
|
||||
default, <prefix> is empty, which results in a symbol prefix of je_ .
|
||||
|
||||
--with-install-suffix=<suffix>
|
||||
* `--with-install-suffix=<suffix>`
|
||||
|
||||
Append <suffix> to the base name of all installed files, such that multiple
|
||||
versions of jemalloc can coexist in the same installation directory. For
|
||||
example, libjemalloc.so.0 becomes libjemalloc<suffix>.so.0.
|
||||
|
||||
--disable-cc-silence
|
||||
Disable code that silences non-useful compiler warnings. This is mainly
|
||||
useful during development when auditing the set of warnings that are being
|
||||
silenced.
|
||||
* `--with-malloc-conf=<malloc_conf>`
|
||||
|
||||
Embed `<malloc_conf>` as a run-time options string that is processed prior to
|
||||
the malloc_conf global variable, the /etc/malloc.conf symlink, and the
|
||||
MALLOC_CONF environment variable. For example, to change the default decay
|
||||
time to 30 seconds:
|
||||
|
||||
--with-malloc-conf=decay_ms:30000
|
||||
|
||||
* `--enable-debug`
|
||||
|
||||
--enable-debug
|
||||
Enable assertions and validation code. This incurs a substantial
|
||||
performance hit, but is very useful during application development.
|
||||
Implies --enable-ivsalloc.
|
||||
|
||||
--enable-code-coverage
|
||||
Enable code coverage support, for use during jemalloc test development.
|
||||
Additional testing targets are available if this option is enabled:
|
||||
* `--disable-stats`
|
||||
|
||||
coverage
|
||||
coverage_unit
|
||||
coverage_integration
|
||||
coverage_stress
|
||||
|
||||
These targets do not clear code coverage results from previous runs, and
|
||||
there are interactions between the various coverage targets, so it is
|
||||
usually advisable to run 'make clean' between repeated code coverage runs.
|
||||
|
||||
--disable-stats
|
||||
Disable statistics gathering functionality. See the "opt.stats_print"
|
||||
option documentation for usage details.
|
||||
|
||||
--enable-ivsalloc
|
||||
Enable validation code, which verifies that pointers reside within
|
||||
jemalloc-owned chunks before dereferencing them. This incurs a minor
|
||||
performance hit.
|
||||
* `--enable-prof`
|
||||
|
||||
--enable-prof
|
||||
Enable heap profiling and leak detection functionality. See the "opt.prof"
|
||||
option documentation for usage details. When enabled, there are several
|
||||
approaches to backtracing, and the configure script chooses the first one
|
||||
@ -126,66 +139,55 @@ any of the following arguments (not a definitive list) to 'configure':
|
||||
+ libgcc (unless --disable-prof-libgcc)
|
||||
+ gcc intrinsics (unless --disable-prof-gcc)
|
||||
|
||||
--enable-prof-libunwind
|
||||
* `--enable-prof-libunwind`
|
||||
|
||||
Use the libunwind library (http://www.nongnu.org/libunwind/) for stack
|
||||
backtracing.
|
||||
|
||||
--disable-prof-libgcc
|
||||
* `--disable-prof-libgcc`
|
||||
|
||||
Disable the use of libgcc's backtracing functionality.
|
||||
|
||||
--disable-prof-gcc
|
||||
* `--disable-prof-gcc`
|
||||
|
||||
Disable the use of gcc intrinsics for backtracing.
|
||||
|
||||
--with-static-libunwind=<libunwind.a>
|
||||
* `--with-static-libunwind=<libunwind.a>`
|
||||
|
||||
Statically link against the specified libunwind.a rather than dynamically
|
||||
linking with -lunwind.
|
||||
|
||||
--disable-tcache
|
||||
Disable thread-specific caches for small objects. Objects are cached and
|
||||
released in bulk, thus reducing the total number of mutex operations. See
|
||||
the "opt.tcache" option for usage details.
|
||||
* `--disable-fill`
|
||||
|
||||
--disable-munmap
|
||||
Disable virtual memory deallocation via munmap(2); instead keep track of
|
||||
the virtual memory for later use. munmap() is disabled by default (i.e.
|
||||
--disable-munmap is implied) on Linux, which has a quirk in its virtual
|
||||
memory allocation algorithm that causes semi-permanent VM map holes under
|
||||
normal jemalloc operation.
|
||||
Disable support for junk/zero filling of memory. See the "opt.junk" and
|
||||
"opt.zero" option documentation for usage details.
|
||||
|
||||
--disable-fill
|
||||
Disable support for junk/zero filling of memory, quarantine, and redzones.
|
||||
See the "opt.junk", "opt.zero", "opt.quarantine", and "opt.redzone" option
|
||||
documentation for usage details.
|
||||
* `--disable-zone-allocator`
|
||||
|
||||
--disable-valgrind
|
||||
Disable support for Valgrind.
|
||||
|
||||
--disable-zone-allocator
|
||||
Disable zone allocator for Darwin. This means jemalloc won't be hooked as
|
||||
the default allocator on OSX/iOS.
|
||||
|
||||
--enable-utrace
|
||||
* `--enable-utrace`
|
||||
|
||||
Enable utrace(2)-based allocation tracing. This feature is not broadly
|
||||
portable (FreeBSD has it, but Linux and OS X do not).
|
||||
|
||||
--enable-xmalloc
|
||||
* `--enable-xmalloc`
|
||||
|
||||
Enable support for optional immediate termination due to out-of-memory
|
||||
errors, as is commonly implemented by "xmalloc" wrapper function for malloc.
|
||||
See the "opt.xmalloc" option documentation for usage details.
|
||||
|
||||
--enable-lazy-lock
|
||||
* `--enable-lazy-lock`
|
||||
|
||||
Enable code that wraps pthread_create() to detect when an application
|
||||
switches from single-threaded to multi-threaded mode, so that it can avoid
|
||||
mutex locking/unlocking operations while in single-threaded mode. In
|
||||
practice, this feature usually has little impact on performance unless
|
||||
thread-specific caching is disabled.
|
||||
|
||||
--disable-tls
|
||||
Disable thread-local storage (TLS), which allows for fast access to
|
||||
thread-local variables via the __thread keyword. If TLS is available,
|
||||
jemalloc uses it for several purposes.
|
||||
* `--disable-cache-oblivious`
|
||||
|
||||
--disable-cache-oblivious
|
||||
Disable cache-oblivious large allocation alignment for large allocation
|
||||
requests with no alignment constraints. If this feature is disabled, all
|
||||
large allocations are page-aligned as an implementation artifact, which can
|
||||
@ -194,56 +196,51 @@ any of the following arguments (not a definitive list) to 'configure':
|
||||
most extreme case increases physical memory usage for the 16 KiB size class
|
||||
to 20 KiB.
|
||||
|
||||
--with-xslroot=<path>
|
||||
* `--disable-syscall`
|
||||
|
||||
Disable use of syscall(2) rather than {open,read,write,close}(2). This is
|
||||
intended as a workaround for systems that place security limitations on
|
||||
syscall(2).
|
||||
|
||||
* `--disable-cxx`
|
||||
|
||||
Disable C++ integration. This will cause new and delete operator
|
||||
implementations to be omitted.
|
||||
|
||||
* `--with-xslroot=<path>`
|
||||
|
||||
Specify where to find DocBook XSL stylesheets when building the
|
||||
documentation.
|
||||
|
||||
--with-lg-page=<lg-page>
|
||||
Specify the base 2 log of the system page size. This option is only useful
|
||||
when cross compiling, since the configure script automatically determines
|
||||
the host's page size by default.
|
||||
* `--with-lg-page=<lg-page>`
|
||||
|
||||
Specify the base 2 log of the allocator page size, which must in turn be at
|
||||
least as large as the system page size. By default the configure script
|
||||
determines the host's page size and sets the allocator page size equal to
|
||||
the system page size, so this option need not be specified unless the
|
||||
system page size may change between configuration and execution, e.g. when
|
||||
cross compiling.
|
||||
|
||||
* `--with-lg-page-sizes=<lg-page-sizes>`
|
||||
|
||||
--with-lg-page-sizes=<lg-page-sizes>
|
||||
Specify the comma-separated base 2 logs of the page sizes to support. This
|
||||
option may be useful when cross-compiling in combination with
|
||||
--with-lg-page, but its primary use case is for integration with FreeBSD's
|
||||
option may be useful when cross compiling in combination with
|
||||
`--with-lg-page`, but its primary use case is for integration with FreeBSD's
|
||||
libc, wherein jemalloc is embedded.
|
||||
|
||||
--with-lg-size-class-group=<lg-size-class-group>
|
||||
Specify the base 2 log of how many size classes to use for each doubling in
|
||||
size. By default jemalloc uses <lg-size-class-group>=2, which results in
|
||||
e.g. the following size classes:
|
||||
* `--with-lg-hugepage=<lg-hugepage>`
|
||||
|
||||
[...], 64,
|
||||
80, 96, 112, 128,
|
||||
160, [...]
|
||||
Specify the base 2 log of the system huge page size. This option is useful
|
||||
when cross compiling, or when overriding the default for systems that do
|
||||
not explicitly support huge pages.
|
||||
|
||||
<lg-size-class-group>=3 results in e.g. the following size classes:
|
||||
* `--with-lg-quantum=<lg-quantum>`
|
||||
|
||||
[...], 64,
|
||||
72, 80, 88, 96, 104, 112, 120, 128,
|
||||
144, [...]
|
||||
|
||||
The minimal <lg-size-class-group>=0 causes jemalloc to only provide size
|
||||
classes that are powers of 2:
|
||||
|
||||
[...],
|
||||
64,
|
||||
128,
|
||||
256,
|
||||
[...]
|
||||
|
||||
An implementation detail currently limits the total number of small size
|
||||
classes to 255, and a compilation error will result if the
|
||||
<lg-size-class-group> you specify cannot be supported. The limit is
|
||||
roughly <lg-size-class-group>=4, depending on page size.
|
||||
|
||||
--with-lg-quantum=<lg-quantum>
|
||||
Specify the base 2 log of the minimum allocation alignment. jemalloc needs
|
||||
to know the minimum alignment that meets the following C standard
|
||||
requirement (quoted from the April 12, 2011 draft of the C11 standard):
|
||||
|
||||
The pointer returned if the allocation succeeds is suitably aligned so
|
||||
> The pointer returned if the allocation succeeds is suitably aligned so
|
||||
that it may be assigned to a pointer to any type of object with a
|
||||
fundamental alignment requirement and then used to access such an object
|
||||
or an array of such objects in the space allocated [...]
|
||||
@ -251,71 +248,82 @@ any of the following arguments (not a definitive list) to 'configure':
|
||||
This setting is architecture-specific, and although jemalloc includes known
|
||||
safe values for the most commonly used modern architectures, there is a
|
||||
wrinkle related to GNU libc (glibc) that may impact your choice of
|
||||
<lg-quantum>. On most modern architectures, this mandates 16-byte alignment
|
||||
(<lg-quantum>=4), but the glibc developers chose not to meet this
|
||||
<lg-quantum>. On most modern architectures, this mandates 16-byte
|
||||
alignment (<lg-quantum>=4), but the glibc developers chose not to meet this
|
||||
requirement for performance reasons. An old discussion can be found at
|
||||
https://sourceware.org/bugzilla/show_bug.cgi?id=206 . Unlike glibc,
|
||||
<https://sourceware.org/bugzilla/show_bug.cgi?id=206> . Unlike glibc,
|
||||
jemalloc does follow the C standard by default (caveat: jemalloc
|
||||
technically cheats if --with-lg-tiny-min is smaller than
|
||||
--with-lg-quantum), but the fact that Linux systems already work around
|
||||
this allocator noncompliance means that it is generally safe in practice to
|
||||
let jemalloc's minimum alignment follow glibc's lead. If you specify
|
||||
--with-lg-quantum=3 during configuration, jemalloc will provide additional
|
||||
size classes that are not 16-byte-aligned (24, 40, and 56, assuming
|
||||
--with-lg-size-class-group=2).
|
||||
technically cheats for size classes smaller than the quantum), but the fact
|
||||
that Linux systems already work around this allocator noncompliance means
|
||||
that it is generally safe in practice to let jemalloc's minimum alignment
|
||||
follow glibc's lead. If you specify `--with-lg-quantum=3` during
|
||||
configuration, jemalloc will provide additional size classes that are not
|
||||
16-byte-aligned (24, 40, and 56).
|
||||
|
||||
--with-lg-tiny-min=<lg-tiny-min>
|
||||
Specify the base 2 log of the minimum tiny size class to support. Tiny
|
||||
size classes are powers of 2 less than the quantum, and are only
|
||||
incorporated if <lg-tiny-min> is less than <lg-quantum> (see
|
||||
--with-lg-quantum). Tiny size classes technically violate the C standard
|
||||
requirement for minimum alignment, and crashes could conceivably result if
|
||||
the compiler were to generate instructions that made alignment assumptions,
|
||||
both because illegal instruction traps could result, and because accesses
|
||||
could straddle page boundaries and cause segmentation faults due to
|
||||
accessing unmapped addresses.
|
||||
* `--with-lg-vaddr=<lg-vaddr>`
|
||||
|
||||
The default of <lg-tiny-min>=3 works well in practice even on architectures
|
||||
that technically require 16-byte alignment, probably for the same reason
|
||||
--with-lg-quantum=3 works. Smaller tiny size classes can, and will, cause
|
||||
crashes (see https://bugzilla.mozilla.org/show_bug.cgi?id=691003 for an
|
||||
example).
|
||||
Specify the number of significant virtual address bits. By default, the
|
||||
configure script attempts to detect virtual address size on those platforms
|
||||
where it knows how, and picks a default otherwise. This option may be
|
||||
useful when cross-compiling.
|
||||
|
||||
This option is rarely useful, and is mainly provided as documentation of a
|
||||
subtle implementation detail. If you do use this option, specify a
|
||||
value in [3, ..., <lg-quantum>].
|
||||
* `--disable-initial-exec-tls`
|
||||
|
||||
Disable the initial-exec TLS model for jemalloc's internal thread-local
|
||||
storage (on those platforms that support explicit settings). This can allow
|
||||
jemalloc to be dynamically loaded after program startup (e.g. using dlopen).
|
||||
Note that in this case, there will be two malloc implementations operating
|
||||
in the same process, which will almost certainly result in confusing runtime
|
||||
crashes if pointers leak from one implementation to the other.
|
||||
|
||||
The following environment variables (not a definitive list) impact configure's
|
||||
behavior:
|
||||
|
||||
CFLAGS="?"
|
||||
Pass these flags to the compiler. You probably shouldn't define this unless
|
||||
you know what you are doing. (Use EXTRA_CFLAGS instead.)
|
||||
* `CFLAGS="?"`
|
||||
* `CXXFLAGS="?"`
|
||||
|
||||
EXTRA_CFLAGS="?"
|
||||
Append these flags to CFLAGS. This makes it possible to add flags such as
|
||||
-Werror, while allowing the configure script to determine what other flags
|
||||
are appropriate for the specified configuration.
|
||||
Pass these flags to the C/C++ compiler. Any flags set by the configure
|
||||
script are prepended, which means explicitly set flags generally take
|
||||
precedence. Take care when specifying flags such as -Werror, because
|
||||
configure tests may be affected in undesirable ways.
|
||||
|
||||
The configure script specifically checks whether an optimization flag (-O*)
|
||||
is specified in EXTRA_CFLAGS, and refrains from specifying an optimization
|
||||
level if it finds that one has already been specified.
|
||||
* `EXTRA_CFLAGS="?"`
|
||||
* `EXTRA_CXXFLAGS="?"`
|
||||
|
||||
Append these flags to CFLAGS/CXXFLAGS, without passing them to the
|
||||
compiler(s) during configuration. This makes it possible to add flags such
|
||||
as -Werror, while allowing the configure script to determine what other
|
||||
flags are appropriate for the specified configuration.
|
||||
|
||||
* `CPPFLAGS="?"`
|
||||
|
||||
CPPFLAGS="?"
|
||||
Pass these flags to the C preprocessor. Note that CFLAGS is not passed to
|
||||
'cpp' when 'configure' is looking for include files, so you must use
|
||||
CPPFLAGS instead if you need to help 'configure' find header files.
|
||||
|
||||
LD_LIBRARY_PATH="?"
|
||||
* `LD_LIBRARY_PATH="?"`
|
||||
|
||||
'ld' uses this colon-separated list to find libraries.
|
||||
|
||||
LDFLAGS="?"
|
||||
* `LDFLAGS="?"`
|
||||
|
||||
Pass these flags when linking.
|
||||
|
||||
PATH="?"
|
||||
* `PATH="?"`
|
||||
|
||||
'configure' uses this to find programs.
|
||||
|
||||
=== Advanced compilation =======================================================
|
||||
In some cases it may be necessary to work around configuration results that do
|
||||
not match reality. For example, Linux 4.5 added support for the MADV_FREE flag
|
||||
to madvise(2), which can cause problems if building on a host with MADV_FREE
|
||||
support and deploying to a target without. To work around this, use a cache
|
||||
file to override the relevant configuration variable defined in configure.ac,
|
||||
e.g.:
|
||||
|
||||
echo "je_cv_madv_free=no" > config.cache && ./configure -C
|
||||
|
||||
|
||||
## Advanced compilation
|
||||
|
||||
To build only parts of jemalloc, use the following targets:
|
||||
|
||||
@ -332,6 +340,7 @@ To install only parts of jemalloc, use the following targets:
|
||||
install_include
|
||||
install_lib_shared
|
||||
install_lib_static
|
||||
install_lib_pc
|
||||
install_lib
|
||||
install_doc_html
|
||||
install_doc_man
|
||||
@ -343,40 +352,51 @@ To clean up build results to varying degrees, use the following make targets:
|
||||
distclean
|
||||
relclean
|
||||
|
||||
=== Advanced installation ======================================================
|
||||
|
||||
## Advanced installation
|
||||
|
||||
Optionally, define make variables when invoking make, including (not
|
||||
exclusively):
|
||||
|
||||
INCLUDEDIR="?"
|
||||
* `INCLUDEDIR="?"`
|
||||
|
||||
Use this as the installation prefix for header files.
|
||||
|
||||
LIBDIR="?"
|
||||
* `LIBDIR="?"`
|
||||
|
||||
Use this as the installation prefix for libraries.
|
||||
|
||||
MANDIR="?"
|
||||
* `MANDIR="?"`
|
||||
|
||||
Use this as the installation prefix for man pages.
|
||||
|
||||
DESTDIR="?"
|
||||
* `DESTDIR="?"`
|
||||
|
||||
Prepend DESTDIR to INCLUDEDIR, LIBDIR, DATADIR, and MANDIR. This is useful
|
||||
when installing to a different path than was specified via --prefix.
|
||||
|
||||
CC="?"
|
||||
* `CC="?"`
|
||||
|
||||
Use this to invoke the C compiler.
|
||||
|
||||
CFLAGS="?"
|
||||
* `CFLAGS="?"`
|
||||
|
||||
Pass these flags to the compiler.
|
||||
|
||||
CPPFLAGS="?"
|
||||
* `CPPFLAGS="?"`
|
||||
|
||||
Pass these flags to the C preprocessor.
|
||||
|
||||
LDFLAGS="?"
|
||||
* `LDFLAGS="?"`
|
||||
|
||||
Pass these flags when linking.
|
||||
|
||||
PATH="?"
|
||||
* `PATH="?"`
|
||||
|
||||
Use this to search for programs used during configuration and building.
|
||||
|
||||
=== Development ================================================================
|
||||
|
||||
## Development
|
||||
|
||||
If you intend to make non-trivial changes to jemalloc, use the 'autogen.sh'
|
||||
script rather than 'configure'. This re-generates 'configure', enables
|
||||
@ -393,7 +413,8 @@ directory, issue configuration and build commands:
|
||||
../configure --enable-autogen
|
||||
make
|
||||
|
||||
=== Documentation ==============================================================
|
||||
|
||||
## Documentation
|
||||
|
||||
The manual page is generated in both html and roff formats. Any web browser
|
||||
can be used to view the html manual. The roff manual page can be formatted
|
329
deps/jemalloc/Makefile.in
vendored
329
deps/jemalloc/Makefile.in
vendored
@ -9,6 +9,7 @@ vpath % .
|
||||
SHELL := /bin/sh
|
||||
|
||||
CC := @CC@
|
||||
CXX := @CXX@
|
||||
|
||||
# Configuration parameters.
|
||||
DESTDIR =
|
||||
@ -23,12 +24,18 @@ abs_srcroot := @abs_srcroot@
|
||||
abs_objroot := @abs_objroot@
|
||||
|
||||
# Build parameters.
|
||||
CPPFLAGS := @CPPFLAGS@ -I$(srcroot)include -I$(objroot)include
|
||||
CFLAGS := @CFLAGS@
|
||||
CPPFLAGS := @CPPFLAGS@ -I$(objroot)include -I$(srcroot)include
|
||||
CONFIGURE_CFLAGS := @CONFIGURE_CFLAGS@
|
||||
SPECIFIED_CFLAGS := @SPECIFIED_CFLAGS@
|
||||
EXTRA_CFLAGS := @EXTRA_CFLAGS@
|
||||
CFLAGS := $(strip $(CONFIGURE_CFLAGS) $(SPECIFIED_CFLAGS) $(EXTRA_CFLAGS))
|
||||
CONFIGURE_CXXFLAGS := @CONFIGURE_CXXFLAGS@
|
||||
SPECIFIED_CXXFLAGS := @SPECIFIED_CXXFLAGS@
|
||||
EXTRA_CXXFLAGS := @EXTRA_CXXFLAGS@
|
||||
CXXFLAGS := $(strip $(CONFIGURE_CXXFLAGS) $(SPECIFIED_CXXFLAGS) $(EXTRA_CXXFLAGS))
|
||||
LDFLAGS := @LDFLAGS@
|
||||
EXTRA_LDFLAGS := @EXTRA_LDFLAGS@
|
||||
LIBS := @LIBS@
|
||||
TESTLIBS := @TESTLIBS@
|
||||
RPATH_EXTRA := @RPATH_EXTRA@
|
||||
SO := @so@
|
||||
IMPORTLIB := @importlib@
|
||||
@ -48,20 +55,24 @@ cfghdrs_out := @cfghdrs_out@
|
||||
cfgoutputs_in := $(addprefix $(srcroot),@cfgoutputs_in@)
|
||||
cfgoutputs_out := @cfgoutputs_out@
|
||||
enable_autogen := @enable_autogen@
|
||||
enable_code_coverage := @enable_code_coverage@
|
||||
enable_prof := @enable_prof@
|
||||
enable_valgrind := @enable_valgrind@
|
||||
enable_zone_allocator := @enable_zone_allocator@
|
||||
MALLOC_CONF := @JEMALLOC_CPREFIX@MALLOC_CONF
|
||||
link_whole_archive := @link_whole_archive@
|
||||
DSO_LDFLAGS = @DSO_LDFLAGS@
|
||||
SOREV = @SOREV@
|
||||
PIC_CFLAGS = @PIC_CFLAGS@
|
||||
CTARGET = @CTARGET@
|
||||
LDTARGET = @LDTARGET@
|
||||
TEST_LD_MODE = @TEST_LD_MODE@
|
||||
MKLIB = @MKLIB@
|
||||
AR = @AR@
|
||||
ARFLAGS = @ARFLAGS@
|
||||
DUMP_SYMS = @DUMP_SYMS@
|
||||
AWK := @AWK@
|
||||
CC_MM = @CC_MM@
|
||||
LM := @LM@
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
ifeq (macho, $(ABI))
|
||||
TEST_LIBRARY_PATH := DYLD_FALLBACK_LIBRARY_PATH="$(objroot)lib"
|
||||
@ -78,18 +89,36 @@ LIBJEMALLOC := $(LIBPREFIX)jemalloc$(install_suffix)
|
||||
# Lists of files.
|
||||
BINS := $(objroot)bin/jemalloc-config $(objroot)bin/jemalloc.sh $(objroot)bin/jeprof
|
||||
C_HDRS := $(objroot)include/jemalloc/jemalloc$(install_suffix).h
|
||||
C_SRCS := $(srcroot)src/jemalloc.c $(srcroot)src/arena.c \
|
||||
$(srcroot)src/atomic.c $(srcroot)src/base.c $(srcroot)src/bitmap.c \
|
||||
$(srcroot)src/chunk.c $(srcroot)src/chunk_dss.c \
|
||||
$(srcroot)src/chunk_mmap.c $(srcroot)src/ckh.c $(srcroot)src/ctl.c \
|
||||
$(srcroot)src/extent.c $(srcroot)src/hash.c $(srcroot)src/huge.c \
|
||||
$(srcroot)src/mb.c $(srcroot)src/mutex.c $(srcroot)src/pages.c \
|
||||
$(srcroot)src/prof.c $(srcroot)src/quarantine.c $(srcroot)src/rtree.c \
|
||||
$(srcroot)src/stats.c $(srcroot)src/tcache.c $(srcroot)src/util.c \
|
||||
$(srcroot)src/tsd.c
|
||||
ifeq ($(enable_valgrind), 1)
|
||||
C_SRCS += $(srcroot)src/valgrind.c
|
||||
endif
|
||||
C_SRCS := $(srcroot)src/jemalloc.c \
|
||||
$(srcroot)src/arena.c \
|
||||
$(srcroot)src/background_thread.c \
|
||||
$(srcroot)src/base.c \
|
||||
$(srcroot)src/bin.c \
|
||||
$(srcroot)src/bitmap.c \
|
||||
$(srcroot)src/ckh.c \
|
||||
$(srcroot)src/ctl.c \
|
||||
$(srcroot)src/div.c \
|
||||
$(srcroot)src/extent.c \
|
||||
$(srcroot)src/extent_dss.c \
|
||||
$(srcroot)src/extent_mmap.c \
|
||||
$(srcroot)src/hash.c \
|
||||
$(srcroot)src/hooks.c \
|
||||
$(srcroot)src/large.c \
|
||||
$(srcroot)src/log.c \
|
||||
$(srcroot)src/malloc_io.c \
|
||||
$(srcroot)src/mutex.c \
|
||||
$(srcroot)src/mutex_pool.c \
|
||||
$(srcroot)src/nstime.c \
|
||||
$(srcroot)src/pages.c \
|
||||
$(srcroot)src/prng.c \
|
||||
$(srcroot)src/prof.c \
|
||||
$(srcroot)src/rtree.c \
|
||||
$(srcroot)src/stats.c \
|
||||
$(srcroot)src/sz.c \
|
||||
$(srcroot)src/tcache.c \
|
||||
$(srcroot)src/ticker.c \
|
||||
$(srcroot)src/tsd.c \
|
||||
$(srcroot)src/witness.c
|
||||
ifeq ($(enable_zone_allocator), 1)
|
||||
C_SRCS += $(srcroot)src/zone.c
|
||||
endif
|
||||
@ -105,6 +134,11 @@ DSOS := $(objroot)lib/$(LIBJEMALLOC).$(SOREV)
|
||||
ifneq ($(SOREV),$(SO))
|
||||
DSOS += $(objroot)lib/$(LIBJEMALLOC).$(SO)
|
||||
endif
|
||||
ifeq (1, $(link_whole_archive))
|
||||
LJEMALLOC := -Wl,--whole-archive -L$(objroot)lib -l$(LIBJEMALLOC) -Wl,--no-whole-archive
|
||||
else
|
||||
LJEMALLOC := $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
|
||||
endif
|
||||
PC := $(objroot)jemalloc.pc
|
||||
MAN3 := $(objroot)doc/jemalloc$(install_suffix).3
|
||||
DOCS_XML := $(objroot)doc/jemalloc$(install_suffix).xml
|
||||
@ -116,53 +150,103 @@ C_TESTLIB_SRCS := $(srcroot)test/src/btalloc.c $(srcroot)test/src/btalloc_0.c \
|
||||
$(srcroot)test/src/mtx.c $(srcroot)test/src/mq.c \
|
||||
$(srcroot)test/src/SFMT.c $(srcroot)test/src/test.c \
|
||||
$(srcroot)test/src/thd.c $(srcroot)test/src/timer.c
|
||||
C_UTIL_INTEGRATION_SRCS := $(srcroot)src/util.c
|
||||
TESTS_UNIT := $(srcroot)test/unit/atomic.c \
|
||||
ifeq (1, $(link_whole_archive))
|
||||
C_UTIL_INTEGRATION_SRCS :=
|
||||
C_UTIL_CPP_SRCS :=
|
||||
else
|
||||
C_UTIL_INTEGRATION_SRCS := $(srcroot)src/nstime.c $(srcroot)src/malloc_io.c
|
||||
C_UTIL_CPP_SRCS := $(srcroot)src/nstime.c $(srcroot)src/malloc_io.c
|
||||
endif
|
||||
TESTS_UNIT := \
|
||||
$(srcroot)test/unit/a0.c \
|
||||
$(srcroot)test/unit/arena_reset.c \
|
||||
$(srcroot)test/unit/atomic.c \
|
||||
$(srcroot)test/unit/background_thread.c \
|
||||
$(srcroot)test/unit/background_thread_enable.c \
|
||||
$(srcroot)test/unit/base.c \
|
||||
$(srcroot)test/unit/bitmap.c \
|
||||
$(srcroot)test/unit/ckh.c \
|
||||
$(srcroot)test/unit/decay.c \
|
||||
$(srcroot)test/unit/div.c \
|
||||
$(srcroot)test/unit/emitter.c \
|
||||
$(srcroot)test/unit/extent_quantize.c \
|
||||
$(srcroot)test/unit/fork.c \
|
||||
$(srcroot)test/unit/hash.c \
|
||||
$(srcroot)test/unit/hooks.c \
|
||||
$(srcroot)test/unit/junk.c \
|
||||
$(srcroot)test/unit/junk_alloc.c \
|
||||
$(srcroot)test/unit/junk_free.c \
|
||||
$(srcroot)test/unit/lg_chunk.c \
|
||||
$(srcroot)test/unit/log.c \
|
||||
$(srcroot)test/unit/mallctl.c \
|
||||
$(srcroot)test/unit/malloc_io.c \
|
||||
$(srcroot)test/unit/math.c \
|
||||
$(srcroot)test/unit/mq.c \
|
||||
$(srcroot)test/unit/mtx.c \
|
||||
$(srcroot)test/unit/pack.c \
|
||||
$(srcroot)test/unit/pages.c \
|
||||
$(srcroot)test/unit/ph.c \
|
||||
$(srcroot)test/unit/prng.c \
|
||||
$(srcroot)test/unit/prof_accum.c \
|
||||
$(srcroot)test/unit/prof_active.c \
|
||||
$(srcroot)test/unit/prof_gdump.c \
|
||||
$(srcroot)test/unit/prof_idump.c \
|
||||
$(srcroot)test/unit/prof_reset.c \
|
||||
$(srcroot)test/unit/prof_tctx.c \
|
||||
$(srcroot)test/unit/prof_thread_name.c \
|
||||
$(srcroot)test/unit/ql.c \
|
||||
$(srcroot)test/unit/qr.c \
|
||||
$(srcroot)test/unit/quarantine.c \
|
||||
$(srcroot)test/unit/rb.c \
|
||||
$(srcroot)test/unit/retained.c \
|
||||
$(srcroot)test/unit/rtree.c \
|
||||
$(srcroot)test/unit/SFMT.c \
|
||||
$(srcroot)test/unit/size_classes.c \
|
||||
$(srcroot)test/unit/slab.c \
|
||||
$(srcroot)test/unit/smoothstep.c \
|
||||
$(srcroot)test/unit/spin.c \
|
||||
$(srcroot)test/unit/stats.c \
|
||||
$(srcroot)test/unit/stats_print.c \
|
||||
$(srcroot)test/unit/ticker.c \
|
||||
$(srcroot)test/unit/nstime.c \
|
||||
$(srcroot)test/unit/tsd.c \
|
||||
$(srcroot)test/unit/util.c \
|
||||
$(srcroot)test/unit/witness.c \
|
||||
$(srcroot)test/unit/zero.c
|
||||
ifeq (@enable_prof@, 1)
|
||||
TESTS_UNIT += \
|
||||
$(srcroot)test/unit/arena_reset_prof.c
|
||||
endif
|
||||
TESTS_INTEGRATION := $(srcroot)test/integration/aligned_alloc.c \
|
||||
$(srcroot)test/integration/allocated.c \
|
||||
$(srcroot)test/integration/sdallocx.c \
|
||||
$(srcroot)test/integration/extent.c \
|
||||
$(srcroot)test/integration/mallocx.c \
|
||||
$(srcroot)test/integration/MALLOCX_ARENA.c \
|
||||
$(srcroot)test/integration/overflow.c \
|
||||
$(srcroot)test/integration/posix_memalign.c \
|
||||
$(srcroot)test/integration/rallocx.c \
|
||||
$(srcroot)test/integration/sdallocx.c \
|
||||
$(srcroot)test/integration/thread_arena.c \
|
||||
$(srcroot)test/integration/thread_tcache_enabled.c \
|
||||
$(srcroot)test/integration/xallocx.c \
|
||||
$(srcroot)test/integration/chunk.c
|
||||
$(srcroot)test/integration/xallocx.c
|
||||
ifeq (@enable_cxx@, 1)
|
||||
CPP_SRCS := $(srcroot)src/jemalloc_cpp.cpp
|
||||
TESTS_INTEGRATION_CPP := $(srcroot)test/integration/cpp/basic.cpp
|
||||
else
|
||||
CPP_SRCS :=
|
||||
TESTS_INTEGRATION_CPP :=
|
||||
endif
|
||||
TESTS_STRESS := $(srcroot)test/stress/microbench.c
|
||||
TESTS := $(TESTS_UNIT) $(TESTS_INTEGRATION) $(TESTS_STRESS)
|
||||
|
||||
TESTS := $(TESTS_UNIT) $(TESTS_INTEGRATION) $(TESTS_INTEGRATION_CPP) $(TESTS_STRESS)
|
||||
|
||||
PRIVATE_NAMESPACE_HDRS := $(objroot)include/jemalloc/internal/private_namespace.h $(objroot)include/jemalloc/internal/private_namespace_jet.h
|
||||
PRIVATE_NAMESPACE_GEN_HDRS := $(PRIVATE_NAMESPACE_HDRS:%.h=%.gen.h)
|
||||
C_SYM_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.sym.$(O))
|
||||
C_SYMS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.sym)
|
||||
C_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.$(O))
|
||||
CPP_OBJS := $(CPP_SRCS:$(srcroot)%.cpp=$(objroot)%.$(O))
|
||||
C_PIC_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.pic.$(O))
|
||||
CPP_PIC_OBJS := $(CPP_SRCS:$(srcroot)%.cpp=$(objroot)%.pic.$(O))
|
||||
C_JET_SYM_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.jet.sym.$(O))
|
||||
C_JET_SYMS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.jet.sym)
|
||||
C_JET_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.jet.$(O))
|
||||
C_TESTLIB_UNIT_OBJS := $(C_TESTLIB_SRCS:$(srcroot)%.c=$(objroot)%.unit.$(O))
|
||||
C_TESTLIB_INTEGRATION_OBJS := $(C_TESTLIB_SRCS:$(srcroot)%.c=$(objroot)%.integration.$(O))
|
||||
@ -172,15 +256,17 @@ C_TESTLIB_OBJS := $(C_TESTLIB_UNIT_OBJS) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_
|
||||
|
||||
TESTS_UNIT_OBJS := $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%.$(O))
|
||||
TESTS_INTEGRATION_OBJS := $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%.$(O))
|
||||
TESTS_INTEGRATION_CPP_OBJS := $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%.$(O))
|
||||
TESTS_STRESS_OBJS := $(TESTS_STRESS:$(srcroot)%.c=$(objroot)%.$(O))
|
||||
TESTS_OBJS := $(TESTS_UNIT_OBJS) $(TESTS_INTEGRATION_OBJS) $(TESTS_STRESS_OBJS)
|
||||
TESTS_CPP_OBJS := $(TESTS_INTEGRATION_CPP_OBJS)
|
||||
|
||||
.PHONY: all dist build_doc_html build_doc_man build_doc
|
||||
.PHONY: install_bin install_include install_lib
|
||||
.PHONY: install_doc_html install_doc_man install_doc install
|
||||
.PHONY: tests check clean distclean relclean
|
||||
|
||||
.SECONDARY : $(TESTS_OBJS)
|
||||
.SECONDARY : $(PRIVATE_NAMESPACE_GEN_HDRS) $(TESTS_OBJS) $(TESTS_CPP_OBJS)
|
||||
|
||||
# Default target.
|
||||
all: build_lib
|
||||
@ -201,18 +287,32 @@ build_doc: $(DOCS)
|
||||
# Include generated dependency files.
|
||||
#
|
||||
ifdef CC_MM
|
||||
-include $(C_SYM_OBJS:%.$(O)=%.d)
|
||||
-include $(C_OBJS:%.$(O)=%.d)
|
||||
-include $(CPP_OBJS:%.$(O)=%.d)
|
||||
-include $(C_PIC_OBJS:%.$(O)=%.d)
|
||||
-include $(CPP_PIC_OBJS:%.$(O)=%.d)
|
||||
-include $(C_JET_SYM_OBJS:%.$(O)=%.d)
|
||||
-include $(C_JET_OBJS:%.$(O)=%.d)
|
||||
-include $(C_TESTLIB_OBJS:%.$(O)=%.d)
|
||||
-include $(TESTS_OBJS:%.$(O)=%.d)
|
||||
-include $(TESTS_CPP_OBJS:%.$(O)=%.d)
|
||||
endif
|
||||
|
||||
$(C_SYM_OBJS): $(objroot)src/%.sym.$(O): $(srcroot)src/%.c
|
||||
$(C_SYM_OBJS): CPPFLAGS += -DJEMALLOC_NO_PRIVATE_NAMESPACE
|
||||
$(C_SYMS): $(objroot)src/%.sym: $(objroot)src/%.sym.$(O)
|
||||
$(C_OBJS): $(objroot)src/%.$(O): $(srcroot)src/%.c
|
||||
$(CPP_OBJS): $(objroot)src/%.$(O): $(srcroot)src/%.cpp
|
||||
$(C_PIC_OBJS): $(objroot)src/%.pic.$(O): $(srcroot)src/%.c
|
||||
$(C_PIC_OBJS): CFLAGS += $(PIC_CFLAGS)
|
||||
$(CPP_PIC_OBJS): $(objroot)src/%.pic.$(O): $(srcroot)src/%.cpp
|
||||
$(CPP_PIC_OBJS): CXXFLAGS += $(PIC_CFLAGS)
|
||||
$(C_JET_SYM_OBJS): $(objroot)src/%.jet.sym.$(O): $(srcroot)src/%.c
|
||||
$(C_JET_SYM_OBJS): CPPFLAGS += -DJEMALLOC_JET -DJEMALLOC_NO_PRIVATE_NAMESPACE
|
||||
$(C_JET_SYMS): $(objroot)src/%.jet.sym: $(objroot)src/%.jet.sym.$(O)
|
||||
$(C_JET_OBJS): $(objroot)src/%.jet.$(O): $(srcroot)src/%.c
|
||||
$(C_JET_OBJS): CFLAGS += -DJEMALLOC_JET
|
||||
$(C_JET_OBJS): CPPFLAGS += -DJEMALLOC_JET
|
||||
$(C_TESTLIB_UNIT_OBJS): $(objroot)test/src/%.unit.$(O): $(srcroot)test/src/%.c
|
||||
$(C_TESTLIB_UNIT_OBJS): CPPFLAGS += -DJEMALLOC_UNIT_TEST
|
||||
$(C_TESTLIB_INTEGRATION_OBJS): $(objroot)test/src/%.integration.$(O): $(srcroot)test/src/%.c
|
||||
@ -223,112 +323,146 @@ $(C_TESTLIB_STRESS_OBJS): CPPFLAGS += -DJEMALLOC_STRESS_TEST -DJEMALLOC_STRESS_T
|
||||
$(C_TESTLIB_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include
|
||||
$(TESTS_UNIT_OBJS): CPPFLAGS += -DJEMALLOC_UNIT_TEST
|
||||
$(TESTS_INTEGRATION_OBJS): CPPFLAGS += -DJEMALLOC_INTEGRATION_TEST
|
||||
$(TESTS_INTEGRATION_CPP_OBJS): CPPFLAGS += -DJEMALLOC_INTEGRATION_CPP_TEST
|
||||
$(TESTS_STRESS_OBJS): CPPFLAGS += -DJEMALLOC_STRESS_TEST
|
||||
$(TESTS_OBJS): $(objroot)test/%.$(O): $(srcroot)test/%.c
|
||||
$(TESTS_CPP_OBJS): $(objroot)test/%.$(O): $(srcroot)test/%.cpp
|
||||
$(TESTS_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include
|
||||
$(TESTS_CPP_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include
|
||||
ifneq ($(IMPORTLIB),$(SO))
|
||||
$(C_OBJS) $(C_JET_OBJS): CPPFLAGS += -DDLLEXPORT
|
||||
$(CPP_OBJS) $(C_SYM_OBJS) $(C_OBJS) $(C_JET_SYM_OBJS) $(C_JET_OBJS): CPPFLAGS += -DDLLEXPORT
|
||||
endif
|
||||
|
||||
ifndef CC_MM
|
||||
# Dependencies.
|
||||
ifndef CC_MM
|
||||
HEADER_DIRS = $(srcroot)include/jemalloc/internal \
|
||||
$(objroot)include/jemalloc $(objroot)include/jemalloc/internal
|
||||
HEADERS = $(wildcard $(foreach dir,$(HEADER_DIRS),$(dir)/*.h))
|
||||
$(C_OBJS) $(C_PIC_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS): $(HEADERS)
|
||||
$(TESTS_OBJS): $(objroot)test/include/test/jemalloc_test.h
|
||||
HEADERS = $(filter-out $(PRIVATE_NAMESPACE_HDRS),$(wildcard $(foreach dir,$(HEADER_DIRS),$(dir)/*.h)))
|
||||
$(C_SYM_OBJS) $(C_OBJS) $(CPP_OBJS) $(C_PIC_OBJS) $(CPP_PIC_OBJS) $(C_JET_SYM_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS) $(TESTS_CPP_OBJS): $(HEADERS)
|
||||
$(TESTS_OBJS) $(TESTS_CPP_OBJS): $(objroot)test/include/test/jemalloc_test.h
|
||||
endif
|
||||
|
||||
$(C_OBJS) $(C_PIC_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS): %.$(O):
|
||||
$(C_OBJS) $(CPP_OBJS) $(C_PIC_OBJS) $(CPP_PIC_OBJS) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(TESTS_INTEGRATION_OBJS) $(TESTS_INTEGRATION_CPP_OBJS): $(objroot)include/jemalloc/internal/private_namespace.h
|
||||
$(C_JET_OBJS) $(C_TESTLIB_UNIT_OBJS) $(C_TESTLIB_STRESS_OBJS) $(TESTS_UNIT_OBJS) $(TESTS_STRESS_OBJS): $(objroot)include/jemalloc/internal/private_namespace_jet.h
|
||||
|
||||
$(C_SYM_OBJS) $(C_OBJS) $(C_PIC_OBJS) $(C_JET_SYM_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS): %.$(O):
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(CFLAGS) -c $(CPPFLAGS) $(CTARGET) $<
|
||||
ifdef CC_MM
|
||||
@$(CC) -MM $(CPPFLAGS) -MT $@ -o $(@:%.$(O)=%.d) $<
|
||||
endif
|
||||
|
||||
$(C_SYMS): %.sym:
|
||||
@mkdir -p $(@D)
|
||||
$(DUMP_SYMS) $< | $(AWK) -f $(objroot)include/jemalloc/internal/private_symbols.awk > $@
|
||||
|
||||
$(C_JET_SYMS): %.sym:
|
||||
@mkdir -p $(@D)
|
||||
$(DUMP_SYMS) $< | $(AWK) -f $(objroot)include/jemalloc/internal/private_symbols_jet.awk > $@
|
||||
|
||||
$(objroot)include/jemalloc/internal/private_namespace.gen.h: $(C_SYMS)
|
||||
$(SHELL) $(srcroot)include/jemalloc/internal/private_namespace.sh $^ > $@
|
||||
|
||||
$(objroot)include/jemalloc/internal/private_namespace_jet.gen.h: $(C_JET_SYMS)
|
||||
$(SHELL) $(srcroot)include/jemalloc/internal/private_namespace.sh $^ > $@
|
||||
|
||||
%.h: %.gen.h
|
||||
@if ! `cmp -s $< $@` ; then echo "cp $< $<"; cp $< $@ ; fi
|
||||
|
||||
$(CPP_OBJS) $(CPP_PIC_OBJS) $(TESTS_CPP_OBJS): %.$(O):
|
||||
@mkdir -p $(@D)
|
||||
$(CXX) $(CXXFLAGS) -c $(CPPFLAGS) $(CTARGET) $<
|
||||
ifdef CC_MM
|
||||
@$(CXX) -MM $(CPPFLAGS) -MT $@ -o $(@:%.$(O)=%.d) $<
|
||||
endif
|
||||
|
||||
ifneq ($(SOREV),$(SO))
|
||||
%.$(SO) : %.$(SOREV)
|
||||
@mkdir -p $(@D)
|
||||
ln -sf $(<F) $@
|
||||
endif
|
||||
|
||||
$(objroot)lib/$(LIBJEMALLOC).$(SOREV) : $(if $(PIC_CFLAGS),$(C_PIC_OBJS),$(C_OBJS))
|
||||
$(objroot)lib/$(LIBJEMALLOC).$(SOREV) : $(if $(PIC_CFLAGS),$(C_PIC_OBJS),$(C_OBJS)) $(if $(PIC_CFLAGS),$(CPP_PIC_OBJS),$(CPP_OBJS))
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(DSO_LDFLAGS) $(call RPATH,$(RPATH_EXTRA)) $(LDTARGET) $+ $(LDFLAGS) $(LIBS) $(EXTRA_LDFLAGS)
|
||||
|
||||
$(objroot)lib/$(LIBJEMALLOC)_pic.$(A) : $(C_PIC_OBJS)
|
||||
$(objroot)lib/$(LIBJEMALLOC).$(A) : $(C_OBJS)
|
||||
$(objroot)lib/$(LIBJEMALLOC)_s.$(A) : $(C_OBJS)
|
||||
$(objroot)lib/$(LIBJEMALLOC)_pic.$(A) : $(C_PIC_OBJS) $(CPP_PIC_OBJS)
|
||||
$(objroot)lib/$(LIBJEMALLOC).$(A) : $(C_OBJS) $(CPP_OBJS)
|
||||
$(objroot)lib/$(LIBJEMALLOC)_s.$(A) : $(C_OBJS) $(CPP_OBJS)
|
||||
|
||||
$(STATIC_LIBS):
|
||||
@mkdir -p $(@D)
|
||||
$(AR) $(ARFLAGS)@AROUT@ $+
|
||||
|
||||
$(objroot)test/unit/%$(EXE): $(objroot)test/unit/%.$(O) $(TESTS_UNIT_LINK_OBJS) $(C_JET_OBJS) $(C_TESTLIB_UNIT_OBJS)
|
||||
$(objroot)test/unit/%$(EXE): $(objroot)test/unit/%.$(O) $(C_JET_OBJS) $(C_TESTLIB_UNIT_OBJS)
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LDFLAGS) $(filter-out -lm,$(LIBS)) -lm $(TESTLIBS) $(EXTRA_LDFLAGS)
|
||||
$(CC) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LDFLAGS) $(filter-out -lm,$(LIBS)) $(LM) $(EXTRA_LDFLAGS)
|
||||
|
||||
$(objroot)test/integration/%$(EXE): $(objroot)test/integration/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(filter -lpthread,$(LIBS))) -lm $(TESTLIBS) $(EXTRA_LDFLAGS)
|
||||
$(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LJEMALLOC) $(LDFLAGS) $(filter-out -lm,$(filter -lrt -lpthread -lstdc++,$(LIBS))) $(LM) $(EXTRA_LDFLAGS)
|
||||
|
||||
$(objroot)test/integration/cpp/%$(EXE): $(objroot)test/integration/cpp/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
|
||||
@mkdir -p $(@D)
|
||||
$(CXX) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(LIBS)) -lm $(EXTRA_LDFLAGS)
|
||||
|
||||
$(objroot)test/stress/%$(EXE): $(objroot)test/stress/%.$(O) $(C_JET_OBJS) $(C_TESTLIB_STRESS_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(LIBS)) -lm $(TESTLIBS) $(EXTRA_LDFLAGS)
|
||||
$(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(LIBS)) $(LM) $(EXTRA_LDFLAGS)
|
||||
|
||||
build_lib_shared: $(DSOS)
|
||||
build_lib_static: $(STATIC_LIBS)
|
||||
build_lib: build_lib_shared build_lib_static
|
||||
|
||||
install_bin:
|
||||
install -d $(BINDIR)
|
||||
$(INSTALL) -d $(BINDIR)
|
||||
@for b in $(BINS); do \
|
||||
echo "install -m 755 $$b $(BINDIR)"; \
|
||||
install -m 755 $$b $(BINDIR); \
|
||||
echo "$(INSTALL) -m 755 $$b $(BINDIR)"; \
|
||||
$(INSTALL) -m 755 $$b $(BINDIR); \
|
||||
done
|
||||
|
||||
install_include:
|
||||
install -d $(INCLUDEDIR)/jemalloc
|
||||
$(INSTALL) -d $(INCLUDEDIR)/jemalloc
|
||||
@for h in $(C_HDRS); do \
|
||||
echo "install -m 644 $$h $(INCLUDEDIR)/jemalloc"; \
|
||||
install -m 644 $$h $(INCLUDEDIR)/jemalloc; \
|
||||
echo "$(INSTALL) -m 644 $$h $(INCLUDEDIR)/jemalloc"; \
|
||||
$(INSTALL) -m 644 $$h $(INCLUDEDIR)/jemalloc; \
|
||||
done
|
||||
|
||||
install_lib_shared: $(DSOS)
|
||||
install -d $(LIBDIR)
|
||||
install -m 755 $(objroot)lib/$(LIBJEMALLOC).$(SOREV) $(LIBDIR)
|
||||
$(INSTALL) -d $(LIBDIR)
|
||||
$(INSTALL) -m 755 $(objroot)lib/$(LIBJEMALLOC).$(SOREV) $(LIBDIR)
|
||||
ifneq ($(SOREV),$(SO))
|
||||
ln -sf $(LIBJEMALLOC).$(SOREV) $(LIBDIR)/$(LIBJEMALLOC).$(SO)
|
||||
endif
|
||||
|
||||
install_lib_static: $(STATIC_LIBS)
|
||||
install -d $(LIBDIR)
|
||||
$(INSTALL) -d $(LIBDIR)
|
||||
@for l in $(STATIC_LIBS); do \
|
||||
echo "install -m 755 $$l $(LIBDIR)"; \
|
||||
install -m 755 $$l $(LIBDIR); \
|
||||
echo "$(INSTALL) -m 755 $$l $(LIBDIR)"; \
|
||||
$(INSTALL) -m 755 $$l $(LIBDIR); \
|
||||
done
|
||||
|
||||
install_lib_pc: $(PC)
|
||||
install -d $(LIBDIR)/pkgconfig
|
||||
$(INSTALL) -d $(LIBDIR)/pkgconfig
|
||||
@for l in $(PC); do \
|
||||
echo "install -m 644 $$l $(LIBDIR)/pkgconfig"; \
|
||||
install -m 644 $$l $(LIBDIR)/pkgconfig; \
|
||||
echo "$(INSTALL) -m 644 $$l $(LIBDIR)/pkgconfig"; \
|
||||
$(INSTALL) -m 644 $$l $(LIBDIR)/pkgconfig; \
|
||||
done
|
||||
|
||||
install_lib: install_lib_shared install_lib_static install_lib_pc
|
||||
|
||||
install_doc_html:
|
||||
install -d $(DATADIR)/doc/jemalloc$(install_suffix)
|
||||
$(INSTALL) -d $(DATADIR)/doc/jemalloc$(install_suffix)
|
||||
@for d in $(DOCS_HTML); do \
|
||||
echo "install -m 644 $$d $(DATADIR)/doc/jemalloc$(install_suffix)"; \
|
||||
install -m 644 $$d $(DATADIR)/doc/jemalloc$(install_suffix); \
|
||||
echo "$(INSTALL) -m 644 $$d $(DATADIR)/doc/jemalloc$(install_suffix)"; \
|
||||
$(INSTALL) -m 644 $$d $(DATADIR)/doc/jemalloc$(install_suffix); \
|
||||
done
|
||||
|
||||
install_doc_man:
|
||||
install -d $(MANDIR)/man3
|
||||
$(INSTALL) -d $(MANDIR)/man3
|
||||
@for d in $(DOCS_MAN3); do \
|
||||
echo "install -m 644 $$d $(MANDIR)/man3"; \
|
||||
install -m 644 $$d $(MANDIR)/man3; \
|
||||
echo "$(INSTALL) -m 644 $$d $(MANDIR)/man3"; \
|
||||
$(INSTALL) -m 644 $$d $(MANDIR)/man3; \
|
||||
done
|
||||
|
||||
install_doc: install_doc_html install_doc_man
|
||||
@ -336,7 +470,7 @@ install_doc: install_doc_html install_doc_man
|
||||
install: install_bin install_include install_lib install_doc
|
||||
|
||||
tests_unit: $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%$(EXE))
|
||||
tests_integration: $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%$(EXE))
|
||||
tests_integration: $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%$(EXE)) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%$(EXE))
|
||||
tests_stress: $(TESTS_STRESS:$(srcroot)%.c=$(objroot)%$(EXE))
|
||||
tests: tests_unit tests_integration tests_stress
|
||||
|
||||
@ -352,71 +486,48 @@ check_unit: tests_unit check_unit_dir
|
||||
$(SHELL) $(objroot)test/test.sh $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%)
|
||||
check_integration_prof: tests_integration check_integration_dir
|
||||
ifeq ($(enable_prof), 1)
|
||||
$(MALLOC_CONF)="prof:true" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%)
|
||||
$(MALLOC_CONF)="prof:true,prof_active:false" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%)
|
||||
$(MALLOC_CONF)="prof:true" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%)
|
||||
$(MALLOC_CONF)="prof:true,prof_active:false" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%)
|
||||
endif
|
||||
check_integration_decay: tests_integration check_integration_dir
|
||||
$(MALLOC_CONF)="dirty_decay_ms:-1,muzzy_decay_ms:-1" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%)
|
||||
$(MALLOC_CONF)="dirty_decay_ms:0,muzzy_decay_ms:0" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%)
|
||||
check_integration: tests_integration check_integration_dir
|
||||
$(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%)
|
||||
$(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%)
|
||||
stress: tests_stress stress_dir
|
||||
$(SHELL) $(objroot)test/test.sh $(TESTS_STRESS:$(srcroot)%.c=$(objroot)%)
|
||||
check: tests check_dir check_integration_prof
|
||||
$(SHELL) $(objroot)test/test.sh $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%)
|
||||
|
||||
ifeq ($(enable_code_coverage), 1)
|
||||
coverage_unit: check_unit
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)src jet $(C_JET_OBJS)
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)test/src unit $(C_TESTLIB_UNIT_OBJS)
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)test/unit unit $(TESTS_UNIT_OBJS)
|
||||
|
||||
coverage_integration: check_integration
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)src pic $(C_PIC_OBJS)
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)src integration $(C_UTIL_INTEGRATION_OBJS)
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)test/src integration $(C_TESTLIB_INTEGRATION_OBJS)
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)test/integration integration $(TESTS_INTEGRATION_OBJS)
|
||||
|
||||
coverage_stress: stress
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)src pic $(C_PIC_OBJS)
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)src jet $(C_JET_OBJS)
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)test/src stress $(C_TESTLIB_STRESS_OBJS)
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)test/stress stress $(TESTS_STRESS_OBJS)
|
||||
|
||||
coverage: check
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)src pic $(C_PIC_OBJS)
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)src jet $(C_JET_OBJS)
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)src integration $(C_UTIL_INTEGRATION_OBJS)
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)test/src unit $(C_TESTLIB_UNIT_OBJS)
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)test/src integration $(C_TESTLIB_INTEGRATION_OBJS)
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)test/src stress $(C_TESTLIB_STRESS_OBJS)
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)test/unit unit $(TESTS_UNIT_OBJS) $(TESTS_UNIT_AUX_OBJS)
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)test/integration integration $(TESTS_INTEGRATION_OBJS)
|
||||
$(SHELL) $(srcroot)coverage.sh $(srcroot)test/stress integration $(TESTS_STRESS_OBJS)
|
||||
endif
|
||||
check: check_unit check_integration check_integration_decay check_integration_prof
|
||||
|
||||
clean:
|
||||
rm -f $(PRIVATE_NAMESPACE_HDRS)
|
||||
rm -f $(PRIVATE_NAMESPACE_GEN_HDRS)
|
||||
rm -f $(C_SYM_OBJS)
|
||||
rm -f $(C_SYMS)
|
||||
rm -f $(C_OBJS)
|
||||
rm -f $(CPP_OBJS)
|
||||
rm -f $(C_PIC_OBJS)
|
||||
rm -f $(CPP_PIC_OBJS)
|
||||
rm -f $(C_JET_SYM_OBJS)
|
||||
rm -f $(C_JET_SYMS)
|
||||
rm -f $(C_JET_OBJS)
|
||||
rm -f $(C_TESTLIB_OBJS)
|
||||
rm -f $(C_SYM_OBJS:%.$(O)=%.d)
|
||||
rm -f $(C_OBJS:%.$(O)=%.d)
|
||||
rm -f $(C_OBJS:%.$(O)=%.gcda)
|
||||
rm -f $(C_OBJS:%.$(O)=%.gcno)
|
||||
rm -f $(CPP_OBJS:%.$(O)=%.d)
|
||||
rm -f $(C_PIC_OBJS:%.$(O)=%.d)
|
||||
rm -f $(C_PIC_OBJS:%.$(O)=%.gcda)
|
||||
rm -f $(C_PIC_OBJS:%.$(O)=%.gcno)
|
||||
rm -f $(CPP_PIC_OBJS:%.$(O)=%.d)
|
||||
rm -f $(C_JET_SYM_OBJS:%.$(O)=%.d)
|
||||
rm -f $(C_JET_OBJS:%.$(O)=%.d)
|
||||
rm -f $(C_JET_OBJS:%.$(O)=%.gcda)
|
||||
rm -f $(C_JET_OBJS:%.$(O)=%.gcno)
|
||||
rm -f $(C_TESTLIB_OBJS:%.$(O)=%.d)
|
||||
rm -f $(C_TESTLIB_OBJS:%.$(O)=%.gcda)
|
||||
rm -f $(C_TESTLIB_OBJS:%.$(O)=%.gcno)
|
||||
rm -f $(TESTS_OBJS:%.$(O)=%$(EXE))
|
||||
rm -f $(TESTS_OBJS)
|
||||
rm -f $(TESTS_OBJS:%.$(O)=%.d)
|
||||
rm -f $(TESTS_OBJS:%.$(O)=%.gcda)
|
||||
rm -f $(TESTS_OBJS:%.$(O)=%.gcno)
|
||||
rm -f $(TESTS_OBJS:%.$(O)=%.out)
|
||||
rm -f $(TESTS_CPP_OBJS:%.$(O)=%$(EXE))
|
||||
rm -f $(TESTS_CPP_OBJS)
|
||||
rm -f $(TESTS_CPP_OBJS:%.$(O)=%.d)
|
||||
rm -f $(TESTS_CPP_OBJS:%.$(O)=%.out)
|
||||
rm -f $(DSOS) $(STATIC_LIBS)
|
||||
rm -f $(objroot)*.gcov.*
|
||||
|
||||
distclean: clean
|
||||
rm -f $(objroot)bin/jemalloc-config
|
||||
|
14
deps/jemalloc/README
vendored
14
deps/jemalloc/README
vendored
@ -3,12 +3,12 @@ fragmentation avoidance and scalable concurrency support. jemalloc first came
|
||||
into use as the FreeBSD libc allocator in 2005, and since then it has found its
|
||||
way into numerous applications that rely on its predictable behavior. In 2010
|
||||
jemalloc development efforts broadened to include developer support features
|
||||
such as heap profiling, Valgrind integration, and extensive monitoring/tuning
|
||||
hooks. Modern jemalloc releases continue to be integrated back into FreeBSD,
|
||||
and therefore versatility remains critical. Ongoing development efforts trend
|
||||
toward making jemalloc among the best allocators for a broad range of demanding
|
||||
applications, and eliminating/mitigating weaknesses that have practical
|
||||
repercussions for real world applications.
|
||||
such as heap profiling and extensive monitoring/tuning hooks. Modern jemalloc
|
||||
releases continue to be integrated back into FreeBSD, and therefore versatility
|
||||
remains critical. Ongoing development efforts trend toward making jemalloc
|
||||
among the best allocators for a broad range of demanding applications, and
|
||||
eliminating/mitigating weaknesses that have practical repercussions for real
|
||||
world applications.
|
||||
|
||||
The COPYING file contains copyright and licensing information.
|
||||
|
||||
@ -17,4 +17,4 @@ jemalloc.
|
||||
|
||||
The ChangeLog file contains a brief summary of changes for each release.
|
||||
|
||||
URL: http://www.canonware.com/jemalloc/
|
||||
URL: http://jemalloc.net/
|
||||
|
129
deps/jemalloc/TUNING.md
vendored
Normal file
129
deps/jemalloc/TUNING.md
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
This document summarizes the common approaches for performance fine tuning with
|
||||
jemalloc (as of 5.1.0). The default configuration of jemalloc tends to work
|
||||
reasonably well in practice, and most applications should not have to tune any
|
||||
options. However, in order to cover a wide range of applications and avoid
|
||||
pathological cases, the default setting is sometimes kept conservative and
|
||||
suboptimal, even for many common workloads. When jemalloc is properly tuned for
|
||||
a specific application / workload, it is common to improve system level metrics
|
||||
by a few percent, or make favorable trade-offs.
|
||||
|
||||
|
||||
## Notable runtime options for performance tuning
|
||||
|
||||
Runtime options can be set via
|
||||
[malloc_conf](http://jemalloc.net/jemalloc.3.html#tuning).
|
||||
|
||||
* [background_thread](http://jemalloc.net/jemalloc.3.html#background_thread)
|
||||
|
||||
Enabling jemalloc background threads generally improves the tail latency for
|
||||
application threads, since unused memory purging is shifted to the dedicated
|
||||
background threads. In addition, unintended purging delay caused by
|
||||
application inactivity is avoided with background threads.
|
||||
|
||||
Suggested: `background_thread:true` when jemalloc managed threads can be
|
||||
allowed.
|
||||
|
||||
* [metadata_thp](http://jemalloc.net/jemalloc.3.html#opt.metadata_thp)
|
||||
|
||||
Allowing jemalloc to utilize transparent huge pages for its internal
|
||||
metadata usually reduces TLB misses significantly, especially for programs
|
||||
with large memory footprint and frequent allocation / deallocation
|
||||
activities. Metadata memory usage may increase due to the use of huge
|
||||
pages.
|
||||
|
||||
Suggested for allocation intensive programs: `metadata_thp:auto` or
|
||||
`metadata_thp:always`, which is expected to improve CPU utilization at a
|
||||
small memory cost.
|
||||
|
||||
* [dirty_decay_ms](http://jemalloc.net/jemalloc.3.html#opt.dirty_decay_ms) and
|
||||
[muzzy_decay_ms](http://jemalloc.net/jemalloc.3.html#opt.muzzy_decay_ms)
|
||||
|
||||
Decay time determines how fast jemalloc returns unused pages back to the
|
||||
operating system, and therefore provides a fairly straightforward trade-off
|
||||
between CPU and memory usage. Shorter decay time purges unused pages faster
|
||||
to reduces memory usage (usually at the cost of more CPU cycles spent on
|
||||
purging), and vice versa.
|
||||
|
||||
Suggested: tune the values based on the desired trade-offs.
|
||||
|
||||
* [narenas](http://jemalloc.net/jemalloc.3.html#opt.narenas)
|
||||
|
||||
By default jemalloc uses multiple arenas to reduce internal lock contention.
|
||||
However high arena count may also increase overall memory fragmentation,
|
||||
since arenas manage memory independently. When high degree of parallelism
|
||||
is not expected at the allocator level, lower number of arenas often
|
||||
improves memory usage.
|
||||
|
||||
Suggested: if low parallelism is expected, try lower arena count while
|
||||
monitoring CPU and memory usage.
|
||||
|
||||
* [percpu_arena](http://jemalloc.net/jemalloc.3.html#opt.percpu_arena)
|
||||
|
||||
Enable dynamic thread to arena association based on running CPU. This has
|
||||
the potential to improve locality, e.g. when thread to CPU affinity is
|
||||
present.
|
||||
|
||||
Suggested: try `percpu_arena:percpu` or `percpu_arena:phycpu` if
|
||||
thread migration between processors is expected to be infrequent.
|
||||
|
||||
Examples:
|
||||
|
||||
* High resource consumption application, prioritizing CPU utilization:
|
||||
|
||||
`background_thread:true,metadata_thp:auto` combined with relaxed decay time
|
||||
(increased `dirty_decay_ms` and / or `muzzy_decay_ms`,
|
||||
e.g. `dirty_decay_ms:30000,muzzy_decay_ms:30000`).
|
||||
|
||||
* High resource consumption application, prioritizing memory usage:
|
||||
|
||||
`background_thread:true` combined with shorter decay time (decreased
|
||||
`dirty_decay_ms` and / or `muzzy_decay_ms`,
|
||||
e.g. `dirty_decay_ms:5000,muzzy_decay_ms:5000`), and lower arena count
|
||||
(e.g. number of CPUs).
|
||||
|
||||
* Low resource consumption application:
|
||||
|
||||
`narenas:1,lg_tcache_max:13` combined with shorter decay time (decreased
|
||||
`dirty_decay_ms` and / or `muzzy_decay_ms`,e.g.
|
||||
`dirty_decay_ms:1000,muzzy_decay_ms:0`).
|
||||
|
||||
* Extremely conservative -- minimize memory usage at all costs, only suitable when
|
||||
allocation activity is very rare:
|
||||
|
||||
`narenas:1,tcache:false,dirty_decay_ms:0,muzzy_decay_ms:0`
|
||||
|
||||
Note that it is recommended to combine the options with `abort_conf:true` which
|
||||
aborts immediately on illegal options.
|
||||
|
||||
## Beyond runtime options
|
||||
|
||||
In addition to the runtime options, there are a number of programmatic ways to
|
||||
improve application performance with jemalloc.
|
||||
|
||||
* [Explicit arenas](http://jemalloc.net/jemalloc.3.html#arenas.create)
|
||||
|
||||
Manually created arenas can help performance in various ways, e.g. by
|
||||
managing locality and contention for specific usages. For example,
|
||||
applications can explicitly allocate frequently accessed objects from a
|
||||
dedicated arena with
|
||||
[mallocx()](http://jemalloc.net/jemalloc.3.html#MALLOCX_ARENA) to improve
|
||||
locality. In addition, explicit arenas often benefit from individually
|
||||
tuned options, e.g. relaxed [decay
|
||||
time](http://jemalloc.net/jemalloc.3.html#arena.i.dirty_decay_ms) if
|
||||
frequent reuse is expected.
|
||||
|
||||
* [Extent hooks](http://jemalloc.net/jemalloc.3.html#arena.i.extent_hooks)
|
||||
|
||||
Extent hooks allow customization for managing underlying memory. One use
|
||||
case for performance purpose is to utilize huge pages -- for example,
|
||||
[HHVM](https://github.com/facebook/hhvm/blob/master/hphp/util/alloc.cpp)
|
||||
uses explicit arenas with customized extent hooks to manage 1GB huge pages
|
||||
for frequently accessed data, which reduces TLB misses significantly.
|
||||
|
||||
* [Explicit thread-to-arena
|
||||
binding](http://jemalloc.net/jemalloc.3.html#thread.arena)
|
||||
|
||||
It is common for some threads in an application to have different memory
|
||||
access / allocation patterns. Threads with heavy workloads often benefit
|
||||
from explicit binding, e.g. binding very active threads to dedicated arenas
|
||||
may reduce contention at the allocator level.
|
2
deps/jemalloc/VERSION
vendored
2
deps/jemalloc/VERSION
vendored
@ -1 +1 @@
|
||||
4.0.3-0-ge9192eacf8935e29fc62fddc2701f7942b1cc02c
|
||||
5.1.0-0-g0
|
||||
|
4
deps/jemalloc/bin/jemalloc-config.in
vendored
4
deps/jemalloc/bin/jemalloc-config.in
vendored
@ -18,6 +18,7 @@ Options:
|
||||
--cc : Print compiler used to build jemalloc.
|
||||
--cflags : Print compiler flags used to build jemalloc.
|
||||
--cppflags : Print preprocessor flags used to build jemalloc.
|
||||
--cxxflags : Print C++ compiler flags used to build jemalloc.
|
||||
--ldflags : Print library flags used to build jemalloc.
|
||||
--libs : Print libraries jemalloc was linked against.
|
||||
EOF
|
||||
@ -67,6 +68,9 @@ case "$1" in
|
||||
--cppflags)
|
||||
echo "@CPPFLAGS@"
|
||||
;;
|
||||
--cxxflags)
|
||||
echo "@CXXFLAGS@"
|
||||
;;
|
||||
--ldflags)
|
||||
echo "@LDFLAGS@ @EXTRA_LDFLAGS@"
|
||||
;;
|
||||
|
172
deps/jemalloc/bin/jeprof.in
vendored
172
deps/jemalloc/bin/jeprof.in
vendored
@ -71,6 +71,7 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
use Getopt::Long;
|
||||
use Cwd;
|
||||
|
||||
my $JEPROF_VERSION = "@jemalloc_version@";
|
||||
my $PPROF_VERSION = "2.0";
|
||||
@ -95,7 +96,7 @@ my @EVINCE = ("evince"); # could also be xpdf or perhaps acroread
|
||||
my @KCACHEGRIND = ("kcachegrind");
|
||||
my @PS2PDF = ("ps2pdf");
|
||||
# These are used for dynamic profiles
|
||||
my @URL_FETCHER = ("curl", "-s");
|
||||
my @URL_FETCHER = ("curl", "-s", "--fail");
|
||||
|
||||
# These are the web pages that servers need to support for dynamic profiles
|
||||
my $HEAP_PAGE = "/pprof/heap";
|
||||
@ -223,12 +224,14 @@ Call-graph Options:
|
||||
--nodefraction=<f> Hide nodes below <f>*total [default=.005]
|
||||
--edgefraction=<f> Hide edges below <f>*total [default=.001]
|
||||
--maxdegree=<n> Max incoming/outgoing edges per node [default=8]
|
||||
--focus=<regexp> Focus on nodes matching <regexp>
|
||||
--focus=<regexp> Focus on backtraces with nodes matching <regexp>
|
||||
--thread=<n> Show profile for thread <n>
|
||||
--ignore=<regexp> Ignore nodes matching <regexp>
|
||||
--ignore=<regexp> Ignore backtraces with nodes matching <regexp>
|
||||
--scale=<n> Set GV scaling [default=0]
|
||||
--heapcheck Make nodes with non-0 object counts
|
||||
(i.e. direct leak generators) more visible
|
||||
--retain=<regexp> Retain only nodes that match <regexp>
|
||||
--exclude=<regexp> Exclude all nodes that match <regexp>
|
||||
|
||||
Miscellaneous:
|
||||
--tools=<prefix or binary:fullpath>[,...] \$PATH for object tool pathnames
|
||||
@ -339,6 +342,8 @@ sub Init() {
|
||||
$main::opt_ignore = '';
|
||||
$main::opt_scale = 0;
|
||||
$main::opt_heapcheck = 0;
|
||||
$main::opt_retain = '';
|
||||
$main::opt_exclude = '';
|
||||
$main::opt_seconds = 30;
|
||||
$main::opt_lib = "";
|
||||
|
||||
@ -410,6 +415,8 @@ sub Init() {
|
||||
"ignore=s" => \$main::opt_ignore,
|
||||
"scale=i" => \$main::opt_scale,
|
||||
"heapcheck" => \$main::opt_heapcheck,
|
||||
"retain=s" => \$main::opt_retain,
|
||||
"exclude=s" => \$main::opt_exclude,
|
||||
"inuse_space!" => \$main::opt_inuse_space,
|
||||
"inuse_objects!" => \$main::opt_inuse_objects,
|
||||
"alloc_space!" => \$main::opt_alloc_space,
|
||||
@ -1160,8 +1167,21 @@ sub PrintSymbolizedProfile {
|
||||
}
|
||||
print '---', "\n";
|
||||
|
||||
$PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash
|
||||
my $profile_marker = $&;
|
||||
my $profile_marker;
|
||||
if ($main::profile_type eq 'heap') {
|
||||
$HEAP_PAGE =~ m,[^/]+$,; # matches everything after the last slash
|
||||
$profile_marker = $&;
|
||||
} elsif ($main::profile_type eq 'growth') {
|
||||
$GROWTH_PAGE =~ m,[^/]+$,; # matches everything after the last slash
|
||||
$profile_marker = $&;
|
||||
} elsif ($main::profile_type eq 'contention') {
|
||||
$CONTENTION_PAGE =~ m,[^/]+$,; # matches everything after the last slash
|
||||
$profile_marker = $&;
|
||||
} else { # elsif ($main::profile_type eq 'cpu')
|
||||
$PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash
|
||||
$profile_marker = $&;
|
||||
}
|
||||
|
||||
print '--- ', $profile_marker, "\n";
|
||||
if (defined($main::collected_profile)) {
|
||||
# if used with remote fetch, simply dump the collected profile to output.
|
||||
@ -1171,6 +1191,12 @@ sub PrintSymbolizedProfile {
|
||||
}
|
||||
close(SRC);
|
||||
} else {
|
||||
# --raw/http: For everything to work correctly for non-remote profiles, we
|
||||
# would need to extend PrintProfileData() to handle all possible profile
|
||||
# types, re-enable the code that is currently disabled in ReadCPUProfile()
|
||||
# and FixCallerAddresses(), and remove the remote profile dumping code in
|
||||
# the block above.
|
||||
die "--raw/http: jeprof can only dump remote profiles for --raw\n";
|
||||
# dump a cpu-format profile to standard out
|
||||
PrintProfileData($profile);
|
||||
}
|
||||
@ -2821,6 +2847,43 @@ sub ExtractCalls {
|
||||
return $calls;
|
||||
}
|
||||
|
||||
sub FilterFrames {
|
||||
my $symbols = shift;
|
||||
my $profile = shift;
|
||||
|
||||
if ($main::opt_retain eq '' && $main::opt_exclude eq '') {
|
||||
return $profile;
|
||||
}
|
||||
|
||||
my $result = {};
|
||||
foreach my $k (keys(%{$profile})) {
|
||||
my $count = $profile->{$k};
|
||||
my @addrs = split(/\n/, $k);
|
||||
my @path = ();
|
||||
foreach my $a (@addrs) {
|
||||
my $sym;
|
||||
if (exists($symbols->{$a})) {
|
||||
$sym = $symbols->{$a}->[0];
|
||||
} else {
|
||||
$sym = $a;
|
||||
}
|
||||
if ($main::opt_retain ne '' && $sym !~ m/$main::opt_retain/) {
|
||||
next;
|
||||
}
|
||||
if ($main::opt_exclude ne '' && $sym =~ m/$main::opt_exclude/) {
|
||||
next;
|
||||
}
|
||||
push(@path, $a);
|
||||
}
|
||||
if (scalar(@path) > 0) {
|
||||
my $reduced_path = join("\n", @path);
|
||||
AddEntry($result, $reduced_path, $count);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub RemoveUninterestingFrames {
|
||||
my $symbols = shift;
|
||||
my $profile = shift;
|
||||
@ -2829,21 +2892,23 @@ sub RemoveUninterestingFrames {
|
||||
my %skip = ();
|
||||
my $skip_regexp = 'NOMATCH';
|
||||
if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
|
||||
foreach my $name ('calloc',
|
||||
foreach my $name ('@JEMALLOC_PREFIX@calloc',
|
||||
'cfree',
|
||||
'malloc',
|
||||
'free',
|
||||
'memalign',
|
||||
'posix_memalign',
|
||||
'aligned_alloc',
|
||||
'@JEMALLOC_PREFIX@malloc',
|
||||
'newImpl',
|
||||
'void* newImpl',
|
||||
'@JEMALLOC_PREFIX@free',
|
||||
'@JEMALLOC_PREFIX@memalign',
|
||||
'@JEMALLOC_PREFIX@posix_memalign',
|
||||
'@JEMALLOC_PREFIX@aligned_alloc',
|
||||
'pvalloc',
|
||||
'valloc',
|
||||
'realloc',
|
||||
'mallocx', # jemalloc
|
||||
'rallocx', # jemalloc
|
||||
'xallocx', # jemalloc
|
||||
'dallocx', # jemalloc
|
||||
'sdallocx', # jemalloc
|
||||
'@JEMALLOC_PREFIX@valloc',
|
||||
'@JEMALLOC_PREFIX@realloc',
|
||||
'@JEMALLOC_PREFIX@mallocx',
|
||||
'@JEMALLOC_PREFIX@rallocx',
|
||||
'@JEMALLOC_PREFIX@xallocx',
|
||||
'@JEMALLOC_PREFIX@dallocx',
|
||||
'@JEMALLOC_PREFIX@sdallocx',
|
||||
'tc_calloc',
|
||||
'tc_cfree',
|
||||
'tc_malloc',
|
||||
@ -2965,6 +3030,9 @@ sub RemoveUninterestingFrames {
|
||||
my $reduced_path = join("\n", @path);
|
||||
AddEntry($result, $reduced_path, $count);
|
||||
}
|
||||
|
||||
$result = FilterFrames($symbols, $result);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@ -3274,7 +3342,7 @@ sub ResolveRedirectionForCurl {
|
||||
# Add a timeout flat to URL_FETCHER. Returns a new list.
|
||||
sub AddFetchTimeout {
|
||||
my $timeout = shift;
|
||||
my @fetcher = shift;
|
||||
my @fetcher = @_;
|
||||
if (defined($timeout)) {
|
||||
if (join(" ", @fetcher) =~ m/\bcurl -s/) {
|
||||
push(@fetcher, "--max-time", sprintf("%d", $timeout));
|
||||
@ -3320,6 +3388,27 @@ sub ReadSymbols {
|
||||
return $map;
|
||||
}
|
||||
|
||||
sub URLEncode {
|
||||
my $str = shift;
|
||||
$str =~ s/([^A-Za-z0-9\-_.!~*'()])/ sprintf "%%%02x", ord $1 /eg;
|
||||
return $str;
|
||||
}
|
||||
|
||||
sub AppendSymbolFilterParams {
|
||||
my $url = shift;
|
||||
my @params = ();
|
||||
if ($main::opt_retain ne '') {
|
||||
push(@params, sprintf("retain=%s", URLEncode($main::opt_retain)));
|
||||
}
|
||||
if ($main::opt_exclude ne '') {
|
||||
push(@params, sprintf("exclude=%s", URLEncode($main::opt_exclude)));
|
||||
}
|
||||
if (scalar @params > 0) {
|
||||
$url = sprintf("%s?%s", $url, join("&", @params));
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
# Fetches and processes symbols to prepare them for use in the profile output
|
||||
# code. If the optional 'symbol_map' arg is not given, fetches symbols from
|
||||
# $SYMBOL_PAGE for all PC values found in profile. Otherwise, the raw symbols
|
||||
@ -3344,9 +3433,11 @@ sub FetchSymbols {
|
||||
my $command_line;
|
||||
if (join(" ", @URL_FETCHER) =~ m/\bcurl -s/) {
|
||||
$url = ResolveRedirectionForCurl($url);
|
||||
$url = AppendSymbolFilterParams($url);
|
||||
$command_line = ShellEscape(@URL_FETCHER, "-d", "\@$main::tmpfile_sym",
|
||||
$url);
|
||||
} else {
|
||||
$url = AppendSymbolFilterParams($url);
|
||||
$command_line = (ShellEscape(@URL_FETCHER, "--post", $url)
|
||||
. " < " . ShellEscape($main::tmpfile_sym));
|
||||
}
|
||||
@ -3427,12 +3518,22 @@ sub FetchDynamicProfile {
|
||||
}
|
||||
$url .= sprintf("seconds=%d", $main::opt_seconds);
|
||||
$fetch_timeout = $main::opt_seconds * 1.01 + 60;
|
||||
# Set $profile_type for consumption by PrintSymbolizedProfile.
|
||||
$main::profile_type = 'cpu';
|
||||
} else {
|
||||
# For non-CPU profiles, we add a type-extension to
|
||||
# the target profile file name.
|
||||
my $suffix = $path;
|
||||
$suffix =~ s,/,.,g;
|
||||
$profile_file .= $suffix;
|
||||
# Set $profile_type for consumption by PrintSymbolizedProfile.
|
||||
if ($path =~ m/$HEAP_PAGE/) {
|
||||
$main::profile_type = 'heap';
|
||||
} elsif ($path =~ m/$GROWTH_PAGE/) {
|
||||
$main::profile_type = 'growth';
|
||||
} elsif ($path =~ m/$CONTENTION_PAGE/) {
|
||||
$main::profile_type = 'contention';
|
||||
}
|
||||
}
|
||||
|
||||
my $profile_dir = $ENV{"JEPROF_TMPDIR"} || ($ENV{HOME} . "/jeprof");
|
||||
@ -3730,6 +3831,8 @@ sub ReadProfile {
|
||||
my $symbol_marker = $&;
|
||||
$PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash
|
||||
my $profile_marker = $&;
|
||||
$HEAP_PAGE =~ m,[^/]+$,; # matches everything after the last slash
|
||||
my $heap_marker = $&;
|
||||
|
||||
# Look at first line to see if it is a heap or a CPU profile.
|
||||
# CPU profile may start with no header at all, and just binary data
|
||||
@ -3756,7 +3859,13 @@ sub ReadProfile {
|
||||
$header = ReadProfileHeader(*PROFILE) || "";
|
||||
}
|
||||
|
||||
if ($header =~ m/^--- *($heap_marker|$growth_marker)/o) {
|
||||
# Skip "--- ..." line for profile types that have their own headers.
|
||||
$header = ReadProfileHeader(*PROFILE) || "";
|
||||
}
|
||||
|
||||
$main::profile_type = '';
|
||||
|
||||
if ($header =~ m/^heap profile:.*$growth_marker/o) {
|
||||
$main::profile_type = 'growth';
|
||||
$result = ReadHeapProfile($prog, *PROFILE, $header);
|
||||
@ -3808,9 +3917,9 @@ sub ReadProfile {
|
||||
# independent implementation.
|
||||
sub FixCallerAddresses {
|
||||
my $stack = shift;
|
||||
if ($main::use_symbolized_profile) {
|
||||
return $stack;
|
||||
} else {
|
||||
# --raw/http: Always subtract one from pc's, because PrintSymbolizedProfile()
|
||||
# dumps unadjusted profiles.
|
||||
{
|
||||
$stack =~ /(\s)/;
|
||||
my $delimiter = $1;
|
||||
my @addrs = split(' ', $stack);
|
||||
@ -3878,12 +3987,7 @@ sub ReadCPUProfile {
|
||||
for (my $j = 0; $j < $d; $j++) {
|
||||
my $pc = $slots->get($i+$j);
|
||||
# Subtract one from caller pc so we map back to call instr.
|
||||
# However, don't do this if we're reading a symbolized profile
|
||||
# file, in which case the subtract-one was done when the file
|
||||
# was written.
|
||||
if ($j > 0 && !$main::use_symbolized_profile) {
|
||||
$pc--;
|
||||
}
|
||||
$pc--;
|
||||
$pc = sprintf("%0*x", $address_length, $pc);
|
||||
$pcs->{$pc} = 1;
|
||||
push @k, $pc;
|
||||
@ -4469,7 +4573,7 @@ sub ParseTextSectionHeader {
|
||||
# Split /proc/pid/maps dump into a list of libraries
|
||||
sub ParseLibraries {
|
||||
return if $main::use_symbol_page; # We don't need libraries info.
|
||||
my $prog = shift;
|
||||
my $prog = Cwd::abs_path(shift);
|
||||
my $map = shift;
|
||||
my $pcs = shift;
|
||||
|
||||
@ -4502,6 +4606,16 @@ sub ParseLibraries {
|
||||
$finish = HexExtend($2);
|
||||
$offset = $zero_offset;
|
||||
$lib = $3;
|
||||
} elsif (($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+)$/i) && ($4 eq $prog)) {
|
||||
# PIEs and address space randomization do not play well with our
|
||||
# default assumption that main executable is at lowest
|
||||
# addresses. So we're detecting main executable in
|
||||
# /proc/self/maps as well.
|
||||
$start = HexExtend($1);
|
||||
$finish = HexExtend($2);
|
||||
$offset = HexExtend($3);
|
||||
$lib = $4;
|
||||
$lib =~ s|\\|/|g; # turn windows-style paths into unix-style paths
|
||||
}
|
||||
# FreeBSD 10.0 virtual memory map /proc/curproc/map as defined in
|
||||
# function procfs_doprocmap (sys/fs/procfs/procfs_map.c)
|
||||
|
@ -1,8 +1,8 @@
|
||||
#! /bin/sh
|
||||
# Attempt to guess a canonical system name.
|
||||
# Copyright 1992-2014 Free Software Foundation, Inc.
|
||||
# Copyright 1992-2016 Free Software Foundation, Inc.
|
||||
|
||||
timestamp='2014-03-23'
|
||||
timestamp='2016-10-02'
|
||||
|
||||
# This file is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
@ -24,12 +24,12 @@ timestamp='2014-03-23'
|
||||
# program. This Exception is an additional permission under section 7
|
||||
# of the GNU General Public License, version 3 ("GPLv3").
|
||||
#
|
||||
# Originally written by Per Bothner.
|
||||
# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
|
||||
#
|
||||
# You can get the latest version of this script from:
|
||||
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
|
||||
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
|
||||
#
|
||||
# Please send patches with a ChangeLog entry to config-patches@gnu.org.
|
||||
# Please send patches to <config-patches@gnu.org>.
|
||||
|
||||
|
||||
me=`echo "$0" | sed -e 's,.*/,,'`
|
||||
@ -50,7 +50,7 @@ version="\
|
||||
GNU config.guess ($timestamp)
|
||||
|
||||
Originally written by Per Bothner.
|
||||
Copyright 1992-2014 Free Software Foundation, Inc.
|
||||
Copyright 1992-2016 Free Software Foundation, Inc.
|
||||
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||
@ -168,19 +168,29 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
# Note: NetBSD doesn't particularly care about the vendor
|
||||
# portion of the name. We always set it to "unknown".
|
||||
sysctl="sysctl -n hw.machine_arch"
|
||||
UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
|
||||
/usr/sbin/$sysctl 2>/dev/null || echo unknown)`
|
||||
UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
|
||||
/sbin/$sysctl 2>/dev/null || \
|
||||
/usr/sbin/$sysctl 2>/dev/null || \
|
||||
echo unknown)`
|
||||
case "${UNAME_MACHINE_ARCH}" in
|
||||
armeb) machine=armeb-unknown ;;
|
||||
arm*) machine=arm-unknown ;;
|
||||
sh3el) machine=shl-unknown ;;
|
||||
sh3eb) machine=sh-unknown ;;
|
||||
sh5el) machine=sh5le-unknown ;;
|
||||
earmv*)
|
||||
arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
|
||||
endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
|
||||
machine=${arch}${endian}-unknown
|
||||
;;
|
||||
*) machine=${UNAME_MACHINE_ARCH}-unknown ;;
|
||||
esac
|
||||
# The Operating System including object format, if it has switched
|
||||
# to ELF recently, or will in the future.
|
||||
# to ELF recently (or will in the future) and ABI.
|
||||
case "${UNAME_MACHINE_ARCH}" in
|
||||
earm*)
|
||||
os=netbsdelf
|
||||
;;
|
||||
arm*|i386|m68k|ns32k|sh3*|sparc|vax)
|
||||
eval $set_cc_for_build
|
||||
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
|
||||
@ -197,6 +207,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
os=netbsd
|
||||
;;
|
||||
esac
|
||||
# Determine ABI tags.
|
||||
case "${UNAME_MACHINE_ARCH}" in
|
||||
earm*)
|
||||
expr='s/^earmv[0-9]/-eabi/;s/eb$//'
|
||||
abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
|
||||
;;
|
||||
esac
|
||||
# The OS release
|
||||
# Debian GNU/NetBSD machines have a different userland, and
|
||||
# thus, need a distinct triplet. However, they do not need
|
||||
@ -207,13 +224,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
release='-gnu'
|
||||
;;
|
||||
*)
|
||||
release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
|
||||
release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
|
||||
;;
|
||||
esac
|
||||
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
|
||||
# contains redundant information, the shorter form:
|
||||
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
|
||||
echo "${machine}-${os}${release}"
|
||||
echo "${machine}-${os}${release}${abi}"
|
||||
exit ;;
|
||||
*:Bitrig:*:*)
|
||||
UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
|
||||
@ -223,6 +240,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
|
||||
echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
|
||||
exit ;;
|
||||
*:LibertyBSD:*:*)
|
||||
UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
|
||||
echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE}
|
||||
exit ;;
|
||||
*:ekkoBSD:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
|
||||
exit ;;
|
||||
@ -235,6 +256,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
*:MirBSD:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
|
||||
exit ;;
|
||||
*:Sortix:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-sortix
|
||||
exit ;;
|
||||
alpha:OSF1:*:*)
|
||||
case $UNAME_RELEASE in
|
||||
*4.0)
|
||||
@ -251,42 +275,42 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
|
||||
case "$ALPHA_CPU_TYPE" in
|
||||
"EV4 (21064)")
|
||||
UNAME_MACHINE="alpha" ;;
|
||||
UNAME_MACHINE=alpha ;;
|
||||
"EV4.5 (21064)")
|
||||
UNAME_MACHINE="alpha" ;;
|
||||
UNAME_MACHINE=alpha ;;
|
||||
"LCA4 (21066/21068)")
|
||||
UNAME_MACHINE="alpha" ;;
|
||||
UNAME_MACHINE=alpha ;;
|
||||
"EV5 (21164)")
|
||||
UNAME_MACHINE="alphaev5" ;;
|
||||
UNAME_MACHINE=alphaev5 ;;
|
||||
"EV5.6 (21164A)")
|
||||
UNAME_MACHINE="alphaev56" ;;
|
||||
UNAME_MACHINE=alphaev56 ;;
|
||||
"EV5.6 (21164PC)")
|
||||
UNAME_MACHINE="alphapca56" ;;
|
||||
UNAME_MACHINE=alphapca56 ;;
|
||||
"EV5.7 (21164PC)")
|
||||
UNAME_MACHINE="alphapca57" ;;
|
||||
UNAME_MACHINE=alphapca57 ;;
|
||||
"EV6 (21264)")
|
||||
UNAME_MACHINE="alphaev6" ;;
|
||||
UNAME_MACHINE=alphaev6 ;;
|
||||
"EV6.7 (21264A)")
|
||||
UNAME_MACHINE="alphaev67" ;;
|
||||
UNAME_MACHINE=alphaev67 ;;
|
||||
"EV6.8CB (21264C)")
|
||||
UNAME_MACHINE="alphaev68" ;;
|
||||
UNAME_MACHINE=alphaev68 ;;
|
||||
"EV6.8AL (21264B)")
|
||||
UNAME_MACHINE="alphaev68" ;;
|
||||
UNAME_MACHINE=alphaev68 ;;
|
||||
"EV6.8CX (21264D)")
|
||||
UNAME_MACHINE="alphaev68" ;;
|
||||
UNAME_MACHINE=alphaev68 ;;
|
||||
"EV6.9A (21264/EV69A)")
|
||||
UNAME_MACHINE="alphaev69" ;;
|
||||
UNAME_MACHINE=alphaev69 ;;
|
||||
"EV7 (21364)")
|
||||
UNAME_MACHINE="alphaev7" ;;
|
||||
UNAME_MACHINE=alphaev7 ;;
|
||||
"EV7.9 (21364A)")
|
||||
UNAME_MACHINE="alphaev79" ;;
|
||||
UNAME_MACHINE=alphaev79 ;;
|
||||
esac
|
||||
# A Pn.n version is a patched version.
|
||||
# A Vn.n version is a released version.
|
||||
# A Tn.n version is a released field test version.
|
||||
# A Xn.n version is an unreleased experimental baselevel.
|
||||
# 1.2 uses "1.2" for uname -r.
|
||||
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
|
||||
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
|
||||
# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
|
||||
exitcode=$?
|
||||
trap '' 0
|
||||
@ -359,16 +383,16 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
exit ;;
|
||||
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
|
||||
eval $set_cc_for_build
|
||||
SUN_ARCH="i386"
|
||||
SUN_ARCH=i386
|
||||
# If there is a compiler, see if it is configured for 64-bit objects.
|
||||
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
|
||||
# This test works for both compilers.
|
||||
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
|
||||
if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
|
||||
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
|
||||
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
|
||||
(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
|
||||
grep IS_64BIT_ARCH >/dev/null
|
||||
then
|
||||
SUN_ARCH="x86_64"
|
||||
SUN_ARCH=x86_64
|
||||
fi
|
||||
fi
|
||||
echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
@ -393,7 +417,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
exit ;;
|
||||
sun*:*:4.2BSD:*)
|
||||
UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
|
||||
test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
|
||||
test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3
|
||||
case "`/bin/arch`" in
|
||||
sun3)
|
||||
echo m68k-sun-sunos${UNAME_RELEASE}
|
||||
@ -579,8 +603,9 @@ EOF
|
||||
else
|
||||
IBM_ARCH=powerpc
|
||||
fi
|
||||
if [ -x /usr/bin/oslevel ] ; then
|
||||
IBM_REV=`/usr/bin/oslevel`
|
||||
if [ -x /usr/bin/lslpp ] ; then
|
||||
IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
|
||||
awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
|
||||
else
|
||||
IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
|
||||
fi
|
||||
@ -617,13 +642,13 @@ EOF
|
||||
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
|
||||
sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
|
||||
case "${sc_cpu_version}" in
|
||||
523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
|
||||
528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
|
||||
523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
|
||||
528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
|
||||
532) # CPU_PA_RISC2_0
|
||||
case "${sc_kernel_bits}" in
|
||||
32) HP_ARCH="hppa2.0n" ;;
|
||||
64) HP_ARCH="hppa2.0w" ;;
|
||||
'') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
|
||||
32) HP_ARCH=hppa2.0n ;;
|
||||
64) HP_ARCH=hppa2.0w ;;
|
||||
'') HP_ARCH=hppa2.0 ;; # HP-UX 10.20
|
||||
esac ;;
|
||||
esac
|
||||
fi
|
||||
@ -662,11 +687,11 @@ EOF
|
||||
exit (0);
|
||||
}
|
||||
EOF
|
||||
(CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
|
||||
(CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
|
||||
test -z "$HP_ARCH" && HP_ARCH=hppa
|
||||
fi ;;
|
||||
esac
|
||||
if [ ${HP_ARCH} = "hppa2.0w" ]
|
||||
if [ ${HP_ARCH} = hppa2.0w ]
|
||||
then
|
||||
eval $set_cc_for_build
|
||||
|
||||
@ -679,12 +704,12 @@ EOF
|
||||
# $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
|
||||
# => hppa64-hp-hpux11.23
|
||||
|
||||
if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
|
||||
if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
|
||||
grep -q __LP64__
|
||||
then
|
||||
HP_ARCH="hppa2.0w"
|
||||
HP_ARCH=hppa2.0w
|
||||
else
|
||||
HP_ARCH="hppa64"
|
||||
HP_ARCH=hppa64
|
||||
fi
|
||||
fi
|
||||
echo ${HP_ARCH}-hp-hpux${HPUX_REV}
|
||||
@ -789,14 +814,14 @@ EOF
|
||||
echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
|
||||
exit ;;
|
||||
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
|
||||
FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
|
||||
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
|
||||
FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
|
||||
FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
|
||||
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
|
||||
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
|
||||
exit ;;
|
||||
5000:UNIX_System_V:4.*:*)
|
||||
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
|
||||
FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
|
||||
FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
|
||||
FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
|
||||
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
|
||||
exit ;;
|
||||
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
|
||||
@ -878,7 +903,7 @@ EOF
|
||||
exit ;;
|
||||
*:GNU/*:*:*)
|
||||
# other systems with GNU libc and userland
|
||||
echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
|
||||
echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
|
||||
exit ;;
|
||||
i*86:Minix:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-minix
|
||||
@ -901,7 +926,7 @@ EOF
|
||||
EV68*) UNAME_MACHINE=alphaev68 ;;
|
||||
esac
|
||||
objdump --private-headers /bin/sh | grep -q ld.so.1
|
||||
if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
|
||||
if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
arc:Linux:*:* | arceb:Linux:*:*)
|
||||
@ -932,6 +957,9 @@ EOF
|
||||
crisv32:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-axis-linux-${LIBC}
|
||||
exit ;;
|
||||
e2k:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
frv:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
@ -944,6 +972,9 @@ EOF
|
||||
ia64:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
k1om:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
m32r*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
@ -969,6 +1000,9 @@ EOF
|
||||
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
|
||||
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
|
||||
;;
|
||||
mips64el:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
openrisc*:Linux:*:*)
|
||||
echo or1k-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
@ -1001,6 +1035,9 @@ EOF
|
||||
ppcle:Linux:*:*)
|
||||
echo powerpcle-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
riscv32:Linux:*:* | riscv64:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
s390:Linux:*:* | s390x:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
|
||||
exit ;;
|
||||
@ -1020,7 +1057,7 @@ EOF
|
||||
echo ${UNAME_MACHINE}-dec-linux-${LIBC}
|
||||
exit ;;
|
||||
x86_64:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
echo ${UNAME_MACHINE}-pc-linux-${LIBC}
|
||||
exit ;;
|
||||
xtensa*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
@ -1099,7 +1136,7 @@ EOF
|
||||
# uname -m prints for DJGPP always 'pc', but it prints nothing about
|
||||
# the processor, so we play safe by assuming i586.
|
||||
# Note: whatever this is, it MUST be the same as what config.sub
|
||||
# prints for the "djgpp" host, or else GDB configury will decide that
|
||||
# prints for the "djgpp" host, or else GDB configure will decide that
|
||||
# this is a cross-build.
|
||||
echo i586-pc-msdosdjgpp
|
||||
exit ;;
|
||||
@ -1248,6 +1285,9 @@ EOF
|
||||
SX-8R:SUPER-UX:*:*)
|
||||
echo sx8r-nec-superux${UNAME_RELEASE}
|
||||
exit ;;
|
||||
SX-ACE:SUPER-UX:*:*)
|
||||
echo sxace-nec-superux${UNAME_RELEASE}
|
||||
exit ;;
|
||||
Power*:Rhapsody:*:*)
|
||||
echo powerpc-apple-rhapsody${UNAME_RELEASE}
|
||||
exit ;;
|
||||
@ -1261,9 +1301,9 @@ EOF
|
||||
UNAME_PROCESSOR=powerpc
|
||||
fi
|
||||
if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
|
||||
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
|
||||
if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
|
||||
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
|
||||
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
|
||||
(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
|
||||
grep IS_64BIT_ARCH >/dev/null
|
||||
then
|
||||
case $UNAME_PROCESSOR in
|
||||
@ -1285,7 +1325,7 @@ EOF
|
||||
exit ;;
|
||||
*:procnto*:*:* | *:QNX:[0123456789]*:*)
|
||||
UNAME_PROCESSOR=`uname -p`
|
||||
if test "$UNAME_PROCESSOR" = "x86"; then
|
||||
if test "$UNAME_PROCESSOR" = x86; then
|
||||
UNAME_PROCESSOR=i386
|
||||
UNAME_MACHINE=pc
|
||||
fi
|
||||
@ -1316,7 +1356,7 @@ EOF
|
||||
# "uname -m" is not consistent, so use $cputype instead. 386
|
||||
# is converted to i386 for consistency with other x86
|
||||
# operating systems.
|
||||
if test "$cputype" = "386"; then
|
||||
if test "$cputype" = 386; then
|
||||
UNAME_MACHINE=i386
|
||||
else
|
||||
UNAME_MACHINE="$cputype"
|
||||
@ -1358,7 +1398,7 @@ EOF
|
||||
echo i386-pc-xenix
|
||||
exit ;;
|
||||
i*86:skyos:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
|
||||
echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'`
|
||||
exit ;;
|
||||
i*86:rdos:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-rdos
|
||||
@ -1369,23 +1409,25 @@ EOF
|
||||
x86_64:VMkernel:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-esx
|
||||
exit ;;
|
||||
amd64:Isilon\ OneFS:*:*)
|
||||
echo x86_64-unknown-onefs
|
||||
exit ;;
|
||||
esac
|
||||
|
||||
cat >&2 <<EOF
|
||||
$0: unable to guess system type
|
||||
|
||||
This script, last modified $timestamp, has failed to recognize
|
||||
the operating system you are using. It is advised that you
|
||||
download the most up to date version of the config scripts from
|
||||
This script (version $timestamp), has failed to recognize the
|
||||
operating system you are using. If your script is old, overwrite
|
||||
config.guess and config.sub with the latest versions from:
|
||||
|
||||
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
|
||||
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
|
||||
and
|
||||
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
|
||||
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
|
||||
|
||||
If the version you run ($0) is already up to date, please
|
||||
send the following data and any information you think might be
|
||||
pertinent to <config-patches@gnu.org> in order to provide the needed
|
||||
information to handle your system.
|
||||
If $0 has already been updated, send the following data and any
|
||||
information you think might be pertinent to config-patches@gnu.org to
|
||||
provide the necessary information to handle your system.
|
||||
|
||||
config.guess timestamp = $timestamp
|
||||
|
@ -1,8 +1,8 @@
|
||||
#! /bin/sh
|
||||
# Configuration validation subroutine script.
|
||||
# Copyright 1992-2014 Free Software Foundation, Inc.
|
||||
# Copyright 1992-2016 Free Software Foundation, Inc.
|
||||
|
||||
timestamp='2014-05-01'
|
||||
timestamp='2016-11-04'
|
||||
|
||||
# This file is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
@ -25,7 +25,7 @@ timestamp='2014-05-01'
|
||||
# of the GNU General Public License, version 3 ("GPLv3").
|
||||
|
||||
|
||||
# Please send patches with a ChangeLog entry to config-patches@gnu.org.
|
||||
# Please send patches to <config-patches@gnu.org>.
|
||||
#
|
||||
# Configuration subroutine to validate and canonicalize a configuration type.
|
||||
# Supply the specified configuration type as an argument.
|
||||
@ -33,7 +33,7 @@ timestamp='2014-05-01'
|
||||
# Otherwise, we print the canonical config type on stdout and succeed.
|
||||
|
||||
# You can get the latest version of this script from:
|
||||
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
|
||||
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
|
||||
|
||||
# This file is supposed to be the same for all GNU packages
|
||||
# and recognize all the CPU types, system types and aliases
|
||||
@ -53,8 +53,7 @@ timestamp='2014-05-01'
|
||||
me=`echo "$0" | sed -e 's,.*/,,'`
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION] CPU-MFR-OPSYS
|
||||
$0 [OPTION] ALIAS
|
||||
Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
|
||||
|
||||
Canonicalize a configuration name.
|
||||
|
||||
@ -68,7 +67,7 @@ Report bugs and patches to <config-patches@gnu.org>."
|
||||
version="\
|
||||
GNU config.sub ($timestamp)
|
||||
|
||||
Copyright 1992-2014 Free Software Foundation, Inc.
|
||||
Copyright 1992-2016 Free Software Foundation, Inc.
|
||||
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||
@ -117,8 +116,8 @@ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
|
||||
case $maybe_os in
|
||||
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
|
||||
linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
|
||||
knetbsd*-gnu* | netbsd*-gnu* | \
|
||||
kopensolaris*-gnu* | \
|
||||
knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
|
||||
kopensolaris*-gnu* | cloudabi*-eabi* | \
|
||||
storm-chaos* | os2-emx* | rtmk-nova*)
|
||||
os=-$maybe_os
|
||||
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
|
||||
@ -255,12 +254,13 @@ case $basic_machine in
|
||||
| arc | arceb \
|
||||
| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
|
||||
| avr | avr32 \
|
||||
| ba \
|
||||
| be32 | be64 \
|
||||
| bfin \
|
||||
| c4x | c8051 | clipper \
|
||||
| d10v | d30v | dlx | dsp16xx \
|
||||
| epiphany \
|
||||
| fido | fr30 | frv \
|
||||
| e2k | epiphany \
|
||||
| fido | fr30 | frv | ft32 \
|
||||
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
|
||||
| hexagon \
|
||||
| i370 | i860 | i960 | ia64 \
|
||||
@ -301,10 +301,12 @@ case $basic_machine in
|
||||
| open8 | or1k | or1knd | or32 \
|
||||
| pdp10 | pdp11 | pj | pjl \
|
||||
| powerpc | powerpc64 | powerpc64le | powerpcle \
|
||||
| pru \
|
||||
| pyramid \
|
||||
| riscv32 | riscv64 \
|
||||
| rl78 | rx \
|
||||
| score \
|
||||
| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
|
||||
| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
|
||||
| sh64 | sh64le \
|
||||
| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
|
||||
| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
|
||||
@ -312,6 +314,7 @@ case $basic_machine in
|
||||
| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
|
||||
| ubicom32 \
|
||||
| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
|
||||
| visium \
|
||||
| we32k \
|
||||
| x86 | xc16x | xstormy16 | xtensa \
|
||||
| z8k | z80)
|
||||
@ -326,6 +329,9 @@ case $basic_machine in
|
||||
c6x)
|
||||
basic_machine=tic6x-unknown
|
||||
;;
|
||||
leon|leon[3-9])
|
||||
basic_machine=sparc-$basic_machine
|
||||
;;
|
||||
m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
|
||||
basic_machine=$basic_machine-unknown
|
||||
os=-none
|
||||
@ -371,12 +377,13 @@ case $basic_machine in
|
||||
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
|
||||
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
|
||||
| avr-* | avr32-* \
|
||||
| ba-* \
|
||||
| be32-* | be64-* \
|
||||
| bfin-* | bs2000-* \
|
||||
| c[123]* | c30-* | [cjt]90-* | c4x-* \
|
||||
| c8051-* | clipper-* | craynv-* | cydra-* \
|
||||
| d10v-* | d30v-* | dlx-* \
|
||||
| elxsi-* \
|
||||
| e2k-* | elxsi-* \
|
||||
| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
|
||||
| h8300-* | h8500-* \
|
||||
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
|
||||
@ -422,13 +429,15 @@ case $basic_machine in
|
||||
| orion-* \
|
||||
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
|
||||
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
|
||||
| pru-* \
|
||||
| pyramid-* \
|
||||
| riscv32-* | riscv64-* \
|
||||
| rl78-* | romp-* | rs6000-* | rx-* \
|
||||
| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
|
||||
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
|
||||
| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
|
||||
| sparclite-* \
|
||||
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
|
||||
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
|
||||
| tahoe-* \
|
||||
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
|
||||
| tile*-* \
|
||||
@ -436,6 +445,7 @@ case $basic_machine in
|
||||
| ubicom32-* \
|
||||
| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
|
||||
| vax-* \
|
||||
| visium-* \
|
||||
| we32k-* \
|
||||
| x86-* | x86_64-* | xc16x-* | xps100-* \
|
||||
| xstormy16-* | xtensa*-* \
|
||||
@ -512,6 +522,9 @@ case $basic_machine in
|
||||
basic_machine=i386-pc
|
||||
os=-aros
|
||||
;;
|
||||
asmjs)
|
||||
basic_machine=asmjs-unknown
|
||||
;;
|
||||
aux)
|
||||
basic_machine=m68k-apple
|
||||
os=-aux
|
||||
@ -632,6 +645,14 @@ case $basic_machine in
|
||||
basic_machine=m68k-bull
|
||||
os=-sysv3
|
||||
;;
|
||||
e500v[12])
|
||||
basic_machine=powerpc-unknown
|
||||
os=$os"spe"
|
||||
;;
|
||||
e500v[12]-*)
|
||||
basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
os=$os"spe"
|
||||
;;
|
||||
ebmon29k)
|
||||
basic_machine=a29k-amd
|
||||
os=-ebmon
|
||||
@ -773,6 +794,9 @@ case $basic_machine in
|
||||
basic_machine=m68k-isi
|
||||
os=-sysv
|
||||
;;
|
||||
leon-*|leon[3-9]-*)
|
||||
basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
|
||||
;;
|
||||
m68knommu)
|
||||
basic_machine=m68k-unknown
|
||||
os=-linux
|
||||
@ -828,6 +852,10 @@ case $basic_machine in
|
||||
basic_machine=powerpc-unknown
|
||||
os=-morphos
|
||||
;;
|
||||
moxiebox)
|
||||
basic_machine=moxie-unknown
|
||||
os=-moxiebox
|
||||
;;
|
||||
msdos)
|
||||
basic_machine=i386-pc
|
||||
os=-msdos
|
||||
@ -1004,7 +1032,7 @@ case $basic_machine in
|
||||
ppc-* | ppcbe-*)
|
||||
basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
ppcle | powerpclittle | ppc-le | powerpc-little)
|
||||
ppcle | powerpclittle)
|
||||
basic_machine=powerpcle-unknown
|
||||
;;
|
||||
ppcle-* | powerpclittle-*)
|
||||
@ -1014,7 +1042,7 @@ case $basic_machine in
|
||||
;;
|
||||
ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
ppc64le | powerpc64little | ppc64-le | powerpc64-little)
|
||||
ppc64le | powerpc64little)
|
||||
basic_machine=powerpc64le-unknown
|
||||
;;
|
||||
ppc64le-* | powerpc64little-*)
|
||||
@ -1360,27 +1388,28 @@ case $os in
|
||||
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
|
||||
| -sym* | -kopensolaris* | -plan9* \
|
||||
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
|
||||
| -aos* | -aros* \
|
||||
| -aos* | -aros* | -cloudabi* | -sortix* \
|
||||
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
|
||||
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
|
||||
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
|
||||
| -bitrig* | -openbsd* | -solidbsd* \
|
||||
| -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
|
||||
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
|
||||
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
|
||||
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
|
||||
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
|
||||
| -chorusos* | -chorusrdb* | -cegcc* \
|
||||
| -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
|
||||
| -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
|
||||
| -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
|
||||
| -linux-newlib* | -linux-musl* | -linux-uclibc* \
|
||||
| -uxpv* | -beos* | -mpeix* | -udk* \
|
||||
| -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
|
||||
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
|
||||
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
|
||||
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
|
||||
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
|
||||
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
|
||||
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
|
||||
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
|
||||
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
|
||||
| -onefs* | -tirtos* | -phoenix* | -fuchsia*)
|
||||
# Remember, each alternative MUST END IN *, to match a version number.
|
||||
;;
|
||||
-qnx*)
|
||||
@ -1404,9 +1433,6 @@ case $os in
|
||||
-mac*)
|
||||
os=`echo $os | sed -e 's|mac|macos|'`
|
||||
;;
|
||||
# Apple iOS
|
||||
-ios*)
|
||||
;;
|
||||
-linux-dietlibc)
|
||||
os=-linux-dietlibc
|
||||
;;
|
||||
@ -1515,6 +1541,8 @@ case $os in
|
||||
;;
|
||||
-nacl*)
|
||||
;;
|
||||
-ios)
|
||||
;;
|
||||
-none)
|
||||
;;
|
||||
*)
|
5882
deps/jemalloc/configure
vendored
5882
deps/jemalloc/configure
vendored
File diff suppressed because it is too large
Load Diff
1369
deps/jemalloc/configure.ac
vendored
1369
deps/jemalloc/configure.ac
vendored
File diff suppressed because it is too large
Load Diff
16
deps/jemalloc/coverage.sh
vendored
16
deps/jemalloc/coverage.sh
vendored
@ -1,16 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
objdir=$1
|
||||
suffix=$2
|
||||
shift 2
|
||||
objs=$@
|
||||
|
||||
gcov -b -p -f -o "${objdir}" ${objs}
|
||||
|
||||
# Move gcov outputs so that subsequent gcov invocations won't clobber results
|
||||
# for the same sources with different compilation flags.
|
||||
for f in `find . -maxdepth 1 -type f -name '*.gcov'` ; do
|
||||
mv "${f}" "${f}.${suffix}"
|
||||
done
|
1
deps/jemalloc/doc/html.xsl.in
vendored
1
deps/jemalloc/doc/html.xsl.in
vendored
@ -1,4 +1,5 @@
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
|
||||
<xsl:import href="@XSLROOT@/html/docbook.xsl"/>
|
||||
<xsl:import href="@abs_srcroot@doc/stylesheet.xsl"/>
|
||||
<xsl:output method="xml" encoding="utf-8"/>
|
||||
</xsl:stylesheet>
|
||||
|
1961
deps/jemalloc/doc/jemalloc.3
vendored
1961
deps/jemalloc/doc/jemalloc.3
vendored
File diff suppressed because it is too large
Load Diff
1825
deps/jemalloc/doc/jemalloc.html
vendored
1825
deps/jemalloc/doc/jemalloc.html
vendored
File diff suppressed because one or more lines are too long
1923
deps/jemalloc/doc/jemalloc.xml.in
vendored
1923
deps/jemalloc/doc/jemalloc.xml.in
vendored
File diff suppressed because it is too large
Load Diff
7
deps/jemalloc/doc/stylesheet.xsl
vendored
7
deps/jemalloc/doc/stylesheet.xsl
vendored
@ -1,7 +1,10 @@
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
|
||||
<xsl:param name="funcsynopsis.style">ansi</xsl:param>
|
||||
<xsl:param name="function.parens" select="1"/>
|
||||
<xsl:param name="function.parens" select="0"/>
|
||||
<xsl:template match="function">
|
||||
<xsl:call-template name="inline.monoseq"/>
|
||||
</xsl:template>
|
||||
<xsl:template match="mallctl">
|
||||
"<xsl:call-template name="inline.monoseq"/>"
|
||||
<quote><xsl:call-template name="inline.monoseq"/></quote>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
|
1347
deps/jemalloc/include/jemalloc/internal/arena.h
vendored
1347
deps/jemalloc/include/jemalloc/internal/arena.h
vendored
File diff suppressed because it is too large
Load Diff
94
deps/jemalloc/include/jemalloc/internal/arena_externs.h
vendored
Normal file
94
deps/jemalloc/include/jemalloc/internal/arena_externs.h
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
#ifndef JEMALLOC_INTERNAL_ARENA_EXTERNS_H
|
||||
#define JEMALLOC_INTERNAL_ARENA_EXTERNS_H
|
||||
|
||||
#include "jemalloc/internal/bin.h"
|
||||
#include "jemalloc/internal/extent_dss.h"
|
||||
#include "jemalloc/internal/pages.h"
|
||||
#include "jemalloc/internal/size_classes.h"
|
||||
#include "jemalloc/internal/stats.h"
|
||||
|
||||
extern ssize_t opt_dirty_decay_ms;
|
||||
extern ssize_t opt_muzzy_decay_ms;
|
||||
|
||||
extern percpu_arena_mode_t opt_percpu_arena;
|
||||
extern const char *percpu_arena_mode_names[];
|
||||
|
||||
extern const uint64_t h_steps[SMOOTHSTEP_NSTEPS];
|
||||
extern malloc_mutex_t arenas_lock;
|
||||
|
||||
void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena,
|
||||
unsigned *nthreads, const char **dss, ssize_t *dirty_decay_ms,
|
||||
ssize_t *muzzy_decay_ms, size_t *nactive, size_t *ndirty, size_t *nmuzzy);
|
||||
void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
||||
const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms,
|
||||
size_t *nactive, size_t *ndirty, size_t *nmuzzy, arena_stats_t *astats,
|
||||
bin_stats_t *bstats, arena_stats_large_t *lstats);
|
||||
void arena_extents_dirty_dalloc(tsdn_t *tsdn, arena_t *arena,
|
||||
extent_hooks_t **r_extent_hooks, extent_t *extent);
|
||||
#ifdef JEMALLOC_JET
|
||||
size_t arena_slab_regind(extent_t *slab, szind_t binind, const void *ptr);
|
||||
#endif
|
||||
extent_t *arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena,
|
||||
size_t usize, size_t alignment, bool *zero);
|
||||
void arena_extent_dalloc_large_prep(tsdn_t *tsdn, arena_t *arena,
|
||||
extent_t *extent);
|
||||
void arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena,
|
||||
extent_t *extent, size_t oldsize);
|
||||
void arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena,
|
||||
extent_t *extent, size_t oldsize);
|
||||
ssize_t arena_dirty_decay_ms_get(arena_t *arena);
|
||||
bool arena_dirty_decay_ms_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_ms);
|
||||
ssize_t arena_muzzy_decay_ms_get(arena_t *arena);
|
||||
bool arena_muzzy_decay_ms_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_ms);
|
||||
void arena_decay(tsdn_t *tsdn, arena_t *arena, bool is_background_thread,
|
||||
bool all);
|
||||
void arena_reset(tsd_t *tsd, arena_t *arena);
|
||||
void arena_destroy(tsd_t *tsd, arena_t *arena);
|
||||
void arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache,
|
||||
cache_bin_t *tbin, szind_t binind, uint64_t prof_accumbytes);
|
||||
void arena_alloc_junk_small(void *ptr, const bin_info_t *bin_info,
|
||||
bool zero);
|
||||
|
||||
typedef void (arena_dalloc_junk_small_t)(void *, const bin_info_t *);
|
||||
extern arena_dalloc_junk_small_t *JET_MUTABLE arena_dalloc_junk_small;
|
||||
|
||||
void *arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size,
|
||||
szind_t ind, bool zero);
|
||||
void *arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
||||
size_t alignment, bool zero, tcache_t *tcache);
|
||||
void arena_prof_promote(tsdn_t *tsdn, const void *ptr, size_t usize);
|
||||
void arena_dalloc_promoted(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
||||
bool slow_path);
|
||||
void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena,
|
||||
extent_t *extent, void *ptr);
|
||||
void arena_dalloc_small(tsdn_t *tsdn, void *ptr);
|
||||
bool arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
||||
size_t extra, bool zero);
|
||||
void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize,
|
||||
size_t size, size_t alignment, bool zero, tcache_t *tcache);
|
||||
dss_prec_t arena_dss_prec_get(arena_t *arena);
|
||||
bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec);
|
||||
ssize_t arena_dirty_decay_ms_default_get(void);
|
||||
bool arena_dirty_decay_ms_default_set(ssize_t decay_ms);
|
||||
ssize_t arena_muzzy_decay_ms_default_get(void);
|
||||
bool arena_muzzy_decay_ms_default_set(ssize_t decay_ms);
|
||||
bool arena_retain_grow_limit_get_set(tsd_t *tsd, arena_t *arena,
|
||||
size_t *old_limit, size_t *new_limit);
|
||||
unsigned arena_nthreads_get(arena_t *arena, bool internal);
|
||||
void arena_nthreads_inc(arena_t *arena, bool internal);
|
||||
void arena_nthreads_dec(arena_t *arena, bool internal);
|
||||
size_t arena_extent_sn_next(arena_t *arena);
|
||||
arena_t *arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks);
|
||||
void arena_boot(void);
|
||||
void arena_prefork0(tsdn_t *tsdn, arena_t *arena);
|
||||
void arena_prefork1(tsdn_t *tsdn, arena_t *arena);
|
||||
void arena_prefork2(tsdn_t *tsdn, arena_t *arena);
|
||||
void arena_prefork3(tsdn_t *tsdn, arena_t *arena);
|
||||
void arena_prefork4(tsdn_t *tsdn, arena_t *arena);
|
||||
void arena_prefork5(tsdn_t *tsdn, arena_t *arena);
|
||||
void arena_prefork6(tsdn_t *tsdn, arena_t *arena);
|
||||
void arena_prefork7(tsdn_t *tsdn, arena_t *arena);
|
||||
void arena_postfork_parent(tsdn_t *tsdn, arena_t *arena);
|
||||
void arena_postfork_child(tsdn_t *tsdn, arena_t *arena);
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_ARENA_EXTERNS_H */
|
57
deps/jemalloc/include/jemalloc/internal/arena_inlines_a.h
vendored
Normal file
57
deps/jemalloc/include/jemalloc/internal/arena_inlines_a.h
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef JEMALLOC_INTERNAL_ARENA_INLINES_A_H
|
||||
#define JEMALLOC_INTERNAL_ARENA_INLINES_A_H
|
||||
|
||||
static inline unsigned
|
||||
arena_ind_get(const arena_t *arena) {
|
||||
return base_ind_get(arena->base);
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_internal_add(arena_t *arena, size_t size) {
|
||||
atomic_fetch_add_zu(&arena->stats.internal, size, ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_internal_sub(arena_t *arena, size_t size) {
|
||||
atomic_fetch_sub_zu(&arena->stats.internal, size, ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
arena_internal_get(arena_t *arena) {
|
||||
return atomic_load_zu(&arena->stats.internal, ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes) {
|
||||
cassert(config_prof);
|
||||
|
||||
if (likely(prof_interval == 0 || !prof_active_get_unlocked())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return prof_accum_add(tsdn, &arena->prof_accum, accumbytes);
|
||||
}
|
||||
|
||||
static inline void
|
||||
percpu_arena_update(tsd_t *tsd, unsigned cpu) {
|
||||
assert(have_percpu_arena);
|
||||
arena_t *oldarena = tsd_arena_get(tsd);
|
||||
assert(oldarena != NULL);
|
||||
unsigned oldind = arena_ind_get(oldarena);
|
||||
|
||||
if (oldind != cpu) {
|
||||
unsigned newind = cpu;
|
||||
arena_t *newarena = arena_get(tsd_tsdn(tsd), newind, true);
|
||||
assert(newarena != NULL);
|
||||
|
||||
/* Set new arena/tcache associations. */
|
||||
arena_migrate(tsd, oldind, newind);
|
||||
tcache_t *tcache = tcache_get(tsd);
|
||||
if (tcache != NULL) {
|
||||
tcache_arena_reassociate(tsd_tsdn(tsd), tcache,
|
||||
newarena);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_ARENA_INLINES_A_H */
|
354
deps/jemalloc/include/jemalloc/internal/arena_inlines_b.h
vendored
Normal file
354
deps/jemalloc/include/jemalloc/internal/arena_inlines_b.h
vendored
Normal file
@ -0,0 +1,354 @@
|
||||
#ifndef JEMALLOC_INTERNAL_ARENA_INLINES_B_H
|
||||
#define JEMALLOC_INTERNAL_ARENA_INLINES_B_H
|
||||
|
||||
#include "jemalloc/internal/jemalloc_internal_types.h"
|
||||
#include "jemalloc/internal/mutex.h"
|
||||
#include "jemalloc/internal/rtree.h"
|
||||
#include "jemalloc/internal/size_classes.h"
|
||||
#include "jemalloc/internal/sz.h"
|
||||
#include "jemalloc/internal/ticker.h"
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE prof_tctx_t *
|
||||
arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr, alloc_ctx_t *alloc_ctx) {
|
||||
cassert(config_prof);
|
||||
assert(ptr != NULL);
|
||||
|
||||
/* Static check. */
|
||||
if (alloc_ctx == NULL) {
|
||||
const extent_t *extent = iealloc(tsdn, ptr);
|
||||
if (unlikely(!extent_slab_get(extent))) {
|
||||
return large_prof_tctx_get(tsdn, extent);
|
||||
}
|
||||
} else {
|
||||
if (unlikely(!alloc_ctx->slab)) {
|
||||
return large_prof_tctx_get(tsdn, iealloc(tsdn, ptr));
|
||||
}
|
||||
}
|
||||
return (prof_tctx_t *)(uintptr_t)1U;
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, UNUSED size_t usize,
|
||||
alloc_ctx_t *alloc_ctx, prof_tctx_t *tctx) {
|
||||
cassert(config_prof);
|
||||
assert(ptr != NULL);
|
||||
|
||||
/* Static check. */
|
||||
if (alloc_ctx == NULL) {
|
||||
extent_t *extent = iealloc(tsdn, ptr);
|
||||
if (unlikely(!extent_slab_get(extent))) {
|
||||
large_prof_tctx_set(tsdn, extent, tctx);
|
||||
}
|
||||
} else {
|
||||
if (unlikely(!alloc_ctx->slab)) {
|
||||
large_prof_tctx_set(tsdn, iealloc(tsdn, ptr), tctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, UNUSED prof_tctx_t *tctx) {
|
||||
cassert(config_prof);
|
||||
assert(ptr != NULL);
|
||||
|
||||
extent_t *extent = iealloc(tsdn, ptr);
|
||||
assert(!extent_slab_get(extent));
|
||||
|
||||
large_prof_tctx_reset(tsdn, extent);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks) {
|
||||
tsd_t *tsd;
|
||||
ticker_t *decay_ticker;
|
||||
|
||||
if (unlikely(tsdn_null(tsdn))) {
|
||||
return;
|
||||
}
|
||||
tsd = tsdn_tsd(tsdn);
|
||||
decay_ticker = decay_ticker_get(tsd, arena_ind_get(arena));
|
||||
if (unlikely(decay_ticker == NULL)) {
|
||||
return;
|
||||
}
|
||||
if (unlikely(ticker_ticks(decay_ticker, nticks))) {
|
||||
arena_decay(tsdn, arena, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
arena_decay_tick(tsdn_t *tsdn, arena_t *arena) {
|
||||
malloc_mutex_assert_not_owner(tsdn, &arena->decay_dirty.mtx);
|
||||
malloc_mutex_assert_not_owner(tsdn, &arena->decay_muzzy.mtx);
|
||||
|
||||
arena_decay_ticks(tsdn, arena, 1);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void *
|
||||
arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero,
|
||||
tcache_t *tcache, bool slow_path) {
|
||||
assert(!tsdn_null(tsdn) || tcache == NULL);
|
||||
assert(size != 0);
|
||||
|
||||
if (likely(tcache != NULL)) {
|
||||
if (likely(size <= SMALL_MAXCLASS)) {
|
||||
return tcache_alloc_small(tsdn_tsd(tsdn), arena,
|
||||
tcache, size, ind, zero, slow_path);
|
||||
}
|
||||
if (likely(size <= tcache_maxclass)) {
|
||||
return tcache_alloc_large(tsdn_tsd(tsdn), arena,
|
||||
tcache, size, ind, zero, slow_path);
|
||||
}
|
||||
/* (size > tcache_maxclass) case falls through. */
|
||||
assert(size > tcache_maxclass);
|
||||
}
|
||||
|
||||
return arena_malloc_hard(tsdn, arena, size, ind, zero);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE arena_t *
|
||||
arena_aalloc(tsdn_t *tsdn, const void *ptr) {
|
||||
return extent_arena_get(iealloc(tsdn, ptr));
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE size_t
|
||||
arena_salloc(tsdn_t *tsdn, const void *ptr) {
|
||||
assert(ptr != NULL);
|
||||
|
||||
rtree_ctx_t rtree_ctx_fallback;
|
||||
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
||||
|
||||
szind_t szind = rtree_szind_read(tsdn, &extents_rtree, rtree_ctx,
|
||||
(uintptr_t)ptr, true);
|
||||
assert(szind != NSIZES);
|
||||
|
||||
return sz_index2size(szind);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE size_t
|
||||
arena_vsalloc(tsdn_t *tsdn, const void *ptr) {
|
||||
/*
|
||||
* Return 0 if ptr is not within an extent managed by jemalloc. This
|
||||
* function has two extra costs relative to isalloc():
|
||||
* - The rtree calls cannot claim to be dependent lookups, which induces
|
||||
* rtree lookup load dependencies.
|
||||
* - The lookup may fail, so there is an extra branch to check for
|
||||
* failure.
|
||||
*/
|
||||
|
||||
rtree_ctx_t rtree_ctx_fallback;
|
||||
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
||||
|
||||
extent_t *extent;
|
||||
szind_t szind;
|
||||
if (rtree_extent_szind_read(tsdn, &extents_rtree, rtree_ctx,
|
||||
(uintptr_t)ptr, false, &extent, &szind)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (extent == NULL) {
|
||||
return 0;
|
||||
}
|
||||
assert(extent_state_get(extent) == extent_state_active);
|
||||
/* Only slab members should be looked up via interior pointers. */
|
||||
assert(extent_addr_get(extent) == ptr || extent_slab_get(extent));
|
||||
|
||||
assert(szind != NSIZES);
|
||||
|
||||
return sz_index2size(szind);
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr) {
|
||||
assert(ptr != NULL);
|
||||
|
||||
rtree_ctx_t rtree_ctx_fallback;
|
||||
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
||||
|
||||
szind_t szind;
|
||||
bool slab;
|
||||
rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr,
|
||||
true, &szind, &slab);
|
||||
|
||||
if (config_debug) {
|
||||
extent_t *extent = rtree_extent_read(tsdn, &extents_rtree,
|
||||
rtree_ctx, (uintptr_t)ptr, true);
|
||||
assert(szind == extent_szind_get(extent));
|
||||
assert(szind < NSIZES);
|
||||
assert(slab == extent_slab_get(extent));
|
||||
}
|
||||
|
||||
if (likely(slab)) {
|
||||
/* Small allocation. */
|
||||
arena_dalloc_small(tsdn, ptr);
|
||||
} else {
|
||||
extent_t *extent = iealloc(tsdn, ptr);
|
||||
large_dalloc(tsdn, extent);
|
||||
}
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
||||
alloc_ctx_t *alloc_ctx, bool slow_path) {
|
||||
assert(!tsdn_null(tsdn) || tcache == NULL);
|
||||
assert(ptr != NULL);
|
||||
|
||||
if (unlikely(tcache == NULL)) {
|
||||
arena_dalloc_no_tcache(tsdn, ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
szind_t szind;
|
||||
bool slab;
|
||||
rtree_ctx_t *rtree_ctx;
|
||||
if (alloc_ctx != NULL) {
|
||||
szind = alloc_ctx->szind;
|
||||
slab = alloc_ctx->slab;
|
||||
assert(szind != NSIZES);
|
||||
} else {
|
||||
rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn));
|
||||
rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx,
|
||||
(uintptr_t)ptr, true, &szind, &slab);
|
||||
}
|
||||
|
||||
if (config_debug) {
|
||||
rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn));
|
||||
extent_t *extent = rtree_extent_read(tsdn, &extents_rtree,
|
||||
rtree_ctx, (uintptr_t)ptr, true);
|
||||
assert(szind == extent_szind_get(extent));
|
||||
assert(szind < NSIZES);
|
||||
assert(slab == extent_slab_get(extent));
|
||||
}
|
||||
|
||||
if (likely(slab)) {
|
||||
/* Small allocation. */
|
||||
tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind,
|
||||
slow_path);
|
||||
} else {
|
||||
if (szind < nhbins) {
|
||||
if (config_prof && unlikely(szind < NBINS)) {
|
||||
arena_dalloc_promoted(tsdn, ptr, tcache,
|
||||
slow_path);
|
||||
} else {
|
||||
tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr,
|
||||
szind, slow_path);
|
||||
}
|
||||
} else {
|
||||
extent_t *extent = iealloc(tsdn, ptr);
|
||||
large_dalloc(tsdn, extent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) {
|
||||
assert(ptr != NULL);
|
||||
assert(size <= LARGE_MAXCLASS);
|
||||
|
||||
szind_t szind;
|
||||
bool slab;
|
||||
if (!config_prof || !opt_prof) {
|
||||
/*
|
||||
* There is no risk of being confused by a promoted sampled
|
||||
* object, so base szind and slab on the given size.
|
||||
*/
|
||||
szind = sz_size2index(size);
|
||||
slab = (szind < NBINS);
|
||||
}
|
||||
|
||||
if ((config_prof && opt_prof) || config_debug) {
|
||||
rtree_ctx_t rtree_ctx_fallback;
|
||||
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn,
|
||||
&rtree_ctx_fallback);
|
||||
|
||||
rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx,
|
||||
(uintptr_t)ptr, true, &szind, &slab);
|
||||
|
||||
assert(szind == sz_size2index(size));
|
||||
assert((config_prof && opt_prof) || slab == (szind < NBINS));
|
||||
|
||||
if (config_debug) {
|
||||
extent_t *extent = rtree_extent_read(tsdn,
|
||||
&extents_rtree, rtree_ctx, (uintptr_t)ptr, true);
|
||||
assert(szind == extent_szind_get(extent));
|
||||
assert(slab == extent_slab_get(extent));
|
||||
}
|
||||
}
|
||||
|
||||
if (likely(slab)) {
|
||||
/* Small allocation. */
|
||||
arena_dalloc_small(tsdn, ptr);
|
||||
} else {
|
||||
extent_t *extent = iealloc(tsdn, ptr);
|
||||
large_dalloc(tsdn, extent);
|
||||
}
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
||||
alloc_ctx_t *alloc_ctx, bool slow_path) {
|
||||
assert(!tsdn_null(tsdn) || tcache == NULL);
|
||||
assert(ptr != NULL);
|
||||
assert(size <= LARGE_MAXCLASS);
|
||||
|
||||
if (unlikely(tcache == NULL)) {
|
||||
arena_sdalloc_no_tcache(tsdn, ptr, size);
|
||||
return;
|
||||
}
|
||||
|
||||
szind_t szind;
|
||||
bool slab;
|
||||
UNUSED alloc_ctx_t local_ctx;
|
||||
if (config_prof && opt_prof) {
|
||||
if (alloc_ctx == NULL) {
|
||||
/* Uncommon case and should be a static check. */
|
||||
rtree_ctx_t rtree_ctx_fallback;
|
||||
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn,
|
||||
&rtree_ctx_fallback);
|
||||
rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx,
|
||||
(uintptr_t)ptr, true, &local_ctx.szind,
|
||||
&local_ctx.slab);
|
||||
assert(local_ctx.szind == sz_size2index(size));
|
||||
alloc_ctx = &local_ctx;
|
||||
}
|
||||
slab = alloc_ctx->slab;
|
||||
szind = alloc_ctx->szind;
|
||||
} else {
|
||||
/*
|
||||
* There is no risk of being confused by a promoted sampled
|
||||
* object, so base szind and slab on the given size.
|
||||
*/
|
||||
szind = sz_size2index(size);
|
||||
slab = (szind < NBINS);
|
||||
}
|
||||
|
||||
if (config_debug) {
|
||||
rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn));
|
||||
rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx,
|
||||
(uintptr_t)ptr, true, &szind, &slab);
|
||||
extent_t *extent = rtree_extent_read(tsdn,
|
||||
&extents_rtree, rtree_ctx, (uintptr_t)ptr, true);
|
||||
assert(szind == extent_szind_get(extent));
|
||||
assert(slab == extent_slab_get(extent));
|
||||
}
|
||||
|
||||
if (likely(slab)) {
|
||||
/* Small allocation. */
|
||||
tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind,
|
||||
slow_path);
|
||||
} else {
|
||||
if (szind < nhbins) {
|
||||
if (config_prof && unlikely(szind < NBINS)) {
|
||||
arena_dalloc_promoted(tsdn, ptr, tcache,
|
||||
slow_path);
|
||||
} else {
|
||||
tcache_dalloc_large(tsdn_tsd(tsdn),
|
||||
tcache, ptr, szind, slow_path);
|
||||
}
|
||||
} else {
|
||||
extent_t *extent = iealloc(tsdn, ptr);
|
||||
large_dalloc(tsdn, extent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_ARENA_INLINES_B_H */
|
237
deps/jemalloc/include/jemalloc/internal/arena_stats.h
vendored
Normal file
237
deps/jemalloc/include/jemalloc/internal/arena_stats.h
vendored
Normal file
@ -0,0 +1,237 @@
|
||||
#ifndef JEMALLOC_INTERNAL_ARENA_STATS_H
|
||||
#define JEMALLOC_INTERNAL_ARENA_STATS_H
|
||||
|
||||
#include "jemalloc/internal/atomic.h"
|
||||
#include "jemalloc/internal/mutex.h"
|
||||
#include "jemalloc/internal/mutex_prof.h"
|
||||
#include "jemalloc/internal/size_classes.h"
|
||||
|
||||
/*
|
||||
* In those architectures that support 64-bit atomics, we use atomic updates for
|
||||
* our 64-bit values. Otherwise, we use a plain uint64_t and synchronize
|
||||
* externally.
|
||||
*/
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
typedef atomic_u64_t arena_stats_u64_t;
|
||||
#else
|
||||
/* Must hold the arena stats mutex while reading atomically. */
|
||||
typedef uint64_t arena_stats_u64_t;
|
||||
#endif
|
||||
|
||||
typedef struct arena_stats_large_s arena_stats_large_t;
|
||||
struct arena_stats_large_s {
|
||||
/*
|
||||
* Total number of allocation/deallocation requests served directly by
|
||||
* the arena.
|
||||
*/
|
||||
arena_stats_u64_t nmalloc;
|
||||
arena_stats_u64_t ndalloc;
|
||||
|
||||
/*
|
||||
* Number of allocation requests that correspond to this size class.
|
||||
* This includes requests served by tcache, though tcache only
|
||||
* periodically merges into this counter.
|
||||
*/
|
||||
arena_stats_u64_t nrequests; /* Partially derived. */
|
||||
|
||||
/* Current number of allocations of this size class. */
|
||||
size_t curlextents; /* Derived. */
|
||||
};
|
||||
|
||||
typedef struct arena_stats_decay_s arena_stats_decay_t;
|
||||
struct arena_stats_decay_s {
|
||||
/* Total number of purge sweeps. */
|
||||
arena_stats_u64_t npurge;
|
||||
/* Total number of madvise calls made. */
|
||||
arena_stats_u64_t nmadvise;
|
||||
/* Total number of pages purged. */
|
||||
arena_stats_u64_t purged;
|
||||
};
|
||||
|
||||
/*
|
||||
* Arena stats. Note that fields marked "derived" are not directly maintained
|
||||
* within the arena code; rather their values are derived during stats merge
|
||||
* requests.
|
||||
*/
|
||||
typedef struct arena_stats_s arena_stats_t;
|
||||
struct arena_stats_s {
|
||||
#ifndef JEMALLOC_ATOMIC_U64
|
||||
malloc_mutex_t mtx;
|
||||
#endif
|
||||
|
||||
/* Number of bytes currently mapped, excluding retained memory. */
|
||||
atomic_zu_t mapped; /* Partially derived. */
|
||||
|
||||
/*
|
||||
* Number of unused virtual memory bytes currently retained. Retained
|
||||
* bytes are technically mapped (though always decommitted or purged),
|
||||
* but they are excluded from the mapped statistic (above).
|
||||
*/
|
||||
atomic_zu_t retained; /* Derived. */
|
||||
|
||||
arena_stats_decay_t decay_dirty;
|
||||
arena_stats_decay_t decay_muzzy;
|
||||
|
||||
atomic_zu_t base; /* Derived. */
|
||||
atomic_zu_t internal;
|
||||
atomic_zu_t resident; /* Derived. */
|
||||
atomic_zu_t metadata_thp;
|
||||
|
||||
atomic_zu_t allocated_large; /* Derived. */
|
||||
arena_stats_u64_t nmalloc_large; /* Derived. */
|
||||
arena_stats_u64_t ndalloc_large; /* Derived. */
|
||||
arena_stats_u64_t nrequests_large; /* Derived. */
|
||||
|
||||
/* Number of bytes cached in tcache associated with this arena. */
|
||||
atomic_zu_t tcache_bytes; /* Derived. */
|
||||
|
||||
mutex_prof_data_t mutex_prof_data[mutex_prof_num_arena_mutexes];
|
||||
|
||||
/* One element for each large size class. */
|
||||
arena_stats_large_t lstats[NSIZES - NBINS];
|
||||
|
||||
/* Arena uptime. */
|
||||
nstime_t uptime;
|
||||
};
|
||||
|
||||
static inline bool
|
||||
arena_stats_init(UNUSED tsdn_t *tsdn, arena_stats_t *arena_stats) {
|
||||
if (config_debug) {
|
||||
for (size_t i = 0; i < sizeof(arena_stats_t); i++) {
|
||||
assert(((char *)arena_stats)[i] == 0);
|
||||
}
|
||||
}
|
||||
#ifndef JEMALLOC_ATOMIC_U64
|
||||
if (malloc_mutex_init(&arena_stats->mtx, "arena_stats",
|
||||
WITNESS_RANK_ARENA_STATS, malloc_mutex_rank_exclusive)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
/* Memory is zeroed, so there is no need to clear stats. */
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_stats_lock(tsdn_t *tsdn, arena_stats_t *arena_stats) {
|
||||
#ifndef JEMALLOC_ATOMIC_U64
|
||||
malloc_mutex_lock(tsdn, &arena_stats->mtx);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_stats_unlock(tsdn_t *tsdn, arena_stats_t *arena_stats) {
|
||||
#ifndef JEMALLOC_ATOMIC_U64
|
||||
malloc_mutex_unlock(tsdn, &arena_stats->mtx);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
arena_stats_read_u64(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||
arena_stats_u64_t *p) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
return atomic_load_u64(p, ATOMIC_RELAXED);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
|
||||
return *p;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_stats_add_u64(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||
arena_stats_u64_t *p, uint64_t x) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
atomic_fetch_add_u64(p, x, ATOMIC_RELAXED);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
|
||||
*p += x;
|
||||
#endif
|
||||
}
|
||||
|
||||
UNUSED static inline void
|
||||
arena_stats_sub_u64(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||
arena_stats_u64_t *p, uint64_t x) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
UNUSED uint64_t r = atomic_fetch_sub_u64(p, x, ATOMIC_RELAXED);
|
||||
assert(r - x <= r);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
|
||||
*p -= x;
|
||||
assert(*p + x >= *p);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Non-atomically sets *dst += src. *dst needs external synchronization.
|
||||
* This lets us avoid the cost of a fetch_add when its unnecessary (note that
|
||||
* the types here are atomic).
|
||||
*/
|
||||
static inline void
|
||||
arena_stats_accum_u64(arena_stats_u64_t *dst, uint64_t src) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
uint64_t cur_dst = atomic_load_u64(dst, ATOMIC_RELAXED);
|
||||
atomic_store_u64(dst, src + cur_dst, ATOMIC_RELAXED);
|
||||
#else
|
||||
*dst += src;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
arena_stats_read_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
return atomic_load_zu(p, ATOMIC_RELAXED);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
|
||||
return atomic_load_zu(p, ATOMIC_RELAXED);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_stats_add_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p,
|
||||
size_t x) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
atomic_fetch_add_zu(p, x, ATOMIC_RELAXED);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
|
||||
size_t cur = atomic_load_zu(p, ATOMIC_RELAXED);
|
||||
atomic_store_zu(p, cur + x, ATOMIC_RELAXED);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_stats_sub_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p,
|
||||
size_t x) {
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
UNUSED size_t r = atomic_fetch_sub_zu(p, x, ATOMIC_RELAXED);
|
||||
assert(r - x <= r);
|
||||
#else
|
||||
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
|
||||
size_t cur = atomic_load_zu(p, ATOMIC_RELAXED);
|
||||
atomic_store_zu(p, cur - x, ATOMIC_RELAXED);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Like the _u64 variant, needs an externally synchronized *dst. */
|
||||
static inline void
|
||||
arena_stats_accum_zu(atomic_zu_t *dst, size_t src) {
|
||||
size_t cur_dst = atomic_load_zu(dst, ATOMIC_RELAXED);
|
||||
atomic_store_zu(dst, src + cur_dst, ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||
szind_t szind, uint64_t nrequests) {
|
||||
arena_stats_lock(tsdn, arena_stats);
|
||||
arena_stats_add_u64(tsdn, arena_stats, &arena_stats->lstats[szind -
|
||||
NBINS].nrequests, nrequests);
|
||||
arena_stats_unlock(tsdn, arena_stats);
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_stats_mapped_add(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t size) {
|
||||
arena_stats_lock(tsdn, arena_stats);
|
||||
arena_stats_add_zu(tsdn, arena_stats, &arena_stats->mapped, size);
|
||||
arena_stats_unlock(tsdn, arena_stats);
|
||||
}
|
||||
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_ARENA_STATS_H */
|
11
deps/jemalloc/include/jemalloc/internal/arena_structs_a.h
vendored
Normal file
11
deps/jemalloc/include/jemalloc/internal/arena_structs_a.h
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef JEMALLOC_INTERNAL_ARENA_STRUCTS_A_H
|
||||
#define JEMALLOC_INTERNAL_ARENA_STRUCTS_A_H
|
||||
|
||||
#include "jemalloc/internal/bitmap.h"
|
||||
|
||||
struct arena_slab_data_s {
|
||||
/* Per region allocated/deallocated bitmap. */
|
||||
bitmap_t bitmap[BITMAP_GROUPS_MAX];
|
||||
};
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_ARENA_STRUCTS_A_H */
|
229
deps/jemalloc/include/jemalloc/internal/arena_structs_b.h
vendored
Normal file
229
deps/jemalloc/include/jemalloc/internal/arena_structs_b.h
vendored
Normal file
@ -0,0 +1,229 @@
|
||||
#ifndef JEMALLOC_INTERNAL_ARENA_STRUCTS_B_H
|
||||
#define JEMALLOC_INTERNAL_ARENA_STRUCTS_B_H
|
||||
|
||||
#include "jemalloc/internal/arena_stats.h"
|
||||
#include "jemalloc/internal/atomic.h"
|
||||
#include "jemalloc/internal/bin.h"
|
||||
#include "jemalloc/internal/bitmap.h"
|
||||
#include "jemalloc/internal/extent_dss.h"
|
||||
#include "jemalloc/internal/jemalloc_internal_types.h"
|
||||
#include "jemalloc/internal/mutex.h"
|
||||
#include "jemalloc/internal/nstime.h"
|
||||
#include "jemalloc/internal/ql.h"
|
||||
#include "jemalloc/internal/size_classes.h"
|
||||
#include "jemalloc/internal/smoothstep.h"
|
||||
#include "jemalloc/internal/ticker.h"
|
||||
|
||||
struct arena_decay_s {
|
||||
/* Synchronizes all non-atomic fields. */
|
||||
malloc_mutex_t mtx;
|
||||
/*
|
||||
* True if a thread is currently purging the extents associated with
|
||||
* this decay structure.
|
||||
*/
|
||||
bool purging;
|
||||
/*
|
||||
* Approximate time in milliseconds from the creation of a set of unused
|
||||
* dirty pages until an equivalent set of unused dirty pages is purged
|
||||
* and/or reused.
|
||||
*/
|
||||
atomic_zd_t time_ms;
|
||||
/* time / SMOOTHSTEP_NSTEPS. */
|
||||
nstime_t interval;
|
||||
/*
|
||||
* Time at which the current decay interval logically started. We do
|
||||
* not actually advance to a new epoch until sometime after it starts
|
||||
* because of scheduling and computation delays, and it is even possible
|
||||
* to completely skip epochs. In all cases, during epoch advancement we
|
||||
* merge all relevant activity into the most recently recorded epoch.
|
||||
*/
|
||||
nstime_t epoch;
|
||||
/* Deadline randomness generator. */
|
||||
uint64_t jitter_state;
|
||||
/*
|
||||
* Deadline for current epoch. This is the sum of interval and per
|
||||
* epoch jitter which is a uniform random variable in [0..interval).
|
||||
* Epochs always advance by precise multiples of interval, but we
|
||||
* randomize the deadline to reduce the likelihood of arenas purging in
|
||||
* lockstep.
|
||||
*/
|
||||
nstime_t deadline;
|
||||
/*
|
||||
* Number of unpurged pages at beginning of current epoch. During epoch
|
||||
* advancement we use the delta between arena->decay_*.nunpurged and
|
||||
* extents_npages_get(&arena->extents_*) to determine how many dirty
|
||||
* pages, if any, were generated.
|
||||
*/
|
||||
size_t nunpurged;
|
||||
/*
|
||||
* Trailing log of how many unused dirty pages were generated during
|
||||
* each of the past SMOOTHSTEP_NSTEPS decay epochs, where the last
|
||||
* element is the most recent epoch. Corresponding epoch times are
|
||||
* relative to epoch.
|
||||
*/
|
||||
size_t backlog[SMOOTHSTEP_NSTEPS];
|
||||
|
||||
/*
|
||||
* Pointer to associated stats. These stats are embedded directly in
|
||||
* the arena's stats due to how stats structures are shared between the
|
||||
* arena and ctl code.
|
||||
*
|
||||
* Synchronization: Same as associated arena's stats field. */
|
||||
arena_stats_decay_t *stats;
|
||||
/* Peak number of pages in associated extents. Used for debug only. */
|
||||
uint64_t ceil_npages;
|
||||
};
|
||||
|
||||
struct arena_s {
|
||||
/*
|
||||
* Number of threads currently assigned to this arena. Each thread has
|
||||
* two distinct assignments, one for application-serving allocation, and
|
||||
* the other for internal metadata allocation. Internal metadata must
|
||||
* not be allocated from arenas explicitly created via the arenas.create
|
||||
* mallctl, because the arena.<i>.reset mallctl indiscriminately
|
||||
* discards all allocations for the affected arena.
|
||||
*
|
||||
* 0: Application allocation.
|
||||
* 1: Internal metadata allocation.
|
||||
*
|
||||
* Synchronization: atomic.
|
||||
*/
|
||||
atomic_u_t nthreads[2];
|
||||
|
||||
/*
|
||||
* When percpu_arena is enabled, to amortize the cost of reading /
|
||||
* updating the current CPU id, track the most recent thread accessing
|
||||
* this arena, and only read CPU if there is a mismatch.
|
||||
*/
|
||||
tsdn_t *last_thd;
|
||||
|
||||
/* Synchronization: internal. */
|
||||
arena_stats_t stats;
|
||||
|
||||
/*
|
||||
* Lists of tcaches and cache_bin_array_descriptors for extant threads
|
||||
* associated with this arena. Stats from these are merged
|
||||
* incrementally, and at exit if opt_stats_print is enabled.
|
||||
*
|
||||
* Synchronization: tcache_ql_mtx.
|
||||
*/
|
||||
ql_head(tcache_t) tcache_ql;
|
||||
ql_head(cache_bin_array_descriptor_t) cache_bin_array_descriptor_ql;
|
||||
malloc_mutex_t tcache_ql_mtx;
|
||||
|
||||
/* Synchronization: internal. */
|
||||
prof_accum_t prof_accum;
|
||||
uint64_t prof_accumbytes;
|
||||
|
||||
/*
|
||||
* PRNG state for cache index randomization of large allocation base
|
||||
* pointers.
|
||||
*
|
||||
* Synchronization: atomic.
|
||||
*/
|
||||
atomic_zu_t offset_state;
|
||||
|
||||
/*
|
||||
* Extent serial number generator state.
|
||||
*
|
||||
* Synchronization: atomic.
|
||||
*/
|
||||
atomic_zu_t extent_sn_next;
|
||||
|
||||
/*
|
||||
* Represents a dss_prec_t, but atomically.
|
||||
*
|
||||
* Synchronization: atomic.
|
||||
*/
|
||||
atomic_u_t dss_prec;
|
||||
|
||||
/*
|
||||
* Number of pages in active extents.
|
||||
*
|
||||
* Synchronization: atomic.
|
||||
*/
|
||||
atomic_zu_t nactive;
|
||||
|
||||
/*
|
||||
* Extant large allocations.
|
||||
*
|
||||
* Synchronization: large_mtx.
|
||||
*/
|
||||
extent_list_t large;
|
||||
/* Synchronizes all large allocation/update/deallocation. */
|
||||
malloc_mutex_t large_mtx;
|
||||
|
||||
/*
|
||||
* Collections of extents that were previously allocated. These are
|
||||
* used when allocating extents, in an attempt to re-use address space.
|
||||
*
|
||||
* Synchronization: internal.
|
||||
*/
|
||||
extents_t extents_dirty;
|
||||
extents_t extents_muzzy;
|
||||
extents_t extents_retained;
|
||||
|
||||
/*
|
||||
* Decay-based purging state, responsible for scheduling extent state
|
||||
* transitions.
|
||||
*
|
||||
* Synchronization: internal.
|
||||
*/
|
||||
arena_decay_t decay_dirty; /* dirty --> muzzy */
|
||||
arena_decay_t decay_muzzy; /* muzzy --> retained */
|
||||
|
||||
/*
|
||||
* Next extent size class in a growing series to use when satisfying a
|
||||
* request via the extent hooks (only if opt_retain). This limits the
|
||||
* number of disjoint virtual memory ranges so that extent merging can
|
||||
* be effective even if multiple arenas' extent allocation requests are
|
||||
* highly interleaved.
|
||||
*
|
||||
* retain_grow_limit is the max allowed size ind to expand (unless the
|
||||
* required size is greater). Default is no limit, and controlled
|
||||
* through mallctl only.
|
||||
*
|
||||
* Synchronization: extent_grow_mtx
|
||||
*/
|
||||
pszind_t extent_grow_next;
|
||||
pszind_t retain_grow_limit;
|
||||
malloc_mutex_t extent_grow_mtx;
|
||||
|
||||
/*
|
||||
* Available extent structures that were allocated via
|
||||
* base_alloc_extent().
|
||||
*
|
||||
* Synchronization: extent_avail_mtx.
|
||||
*/
|
||||
extent_tree_t extent_avail;
|
||||
malloc_mutex_t extent_avail_mtx;
|
||||
|
||||
/*
|
||||
* bins is used to store heaps of free regions.
|
||||
*
|
||||
* Synchronization: internal.
|
||||
*/
|
||||
bin_t bins[NBINS];
|
||||
|
||||
/*
|
||||
* Base allocator, from which arena metadata are allocated.
|
||||
*
|
||||
* Synchronization: internal.
|
||||
*/
|
||||
base_t *base;
|
||||
/* Used to determine uptime. Read-only after initialization. */
|
||||
nstime_t create_time;
|
||||
};
|
||||
|
||||
/* Used in conjunction with tsd for fast arena-related context lookup. */
|
||||
struct arena_tdata_s {
|
||||
ticker_t decay_ticker;
|
||||
};
|
||||
|
||||
/* Used to pass rtree lookup context down the path. */
|
||||
struct alloc_ctx_s {
|
||||
szind_t szind;
|
||||
bool slab;
|
||||
};
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_ARENA_STRUCTS_B_H */
|
43
deps/jemalloc/include/jemalloc/internal/arena_types.h
vendored
Normal file
43
deps/jemalloc/include/jemalloc/internal/arena_types.h
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef JEMALLOC_INTERNAL_ARENA_TYPES_H
|
||||
#define JEMALLOC_INTERNAL_ARENA_TYPES_H
|
||||
|
||||
/* Maximum number of regions in one slab. */
|
||||
#define LG_SLAB_MAXREGS (LG_PAGE - LG_TINY_MIN)
|
||||
#define SLAB_MAXREGS (1U << LG_SLAB_MAXREGS)
|
||||
|
||||
/* Default decay times in milliseconds. */
|
||||
#define DIRTY_DECAY_MS_DEFAULT ZD(10 * 1000)
|
||||
#define MUZZY_DECAY_MS_DEFAULT ZD(10 * 1000)
|
||||
/* Number of event ticks between time checks. */
|
||||
#define DECAY_NTICKS_PER_UPDATE 1000
|
||||
|
||||
typedef struct arena_slab_data_s arena_slab_data_t;
|
||||
typedef struct arena_decay_s arena_decay_t;
|
||||
typedef struct arena_s arena_t;
|
||||
typedef struct arena_tdata_s arena_tdata_t;
|
||||
typedef struct alloc_ctx_s alloc_ctx_t;
|
||||
|
||||
typedef enum {
|
||||
percpu_arena_mode_names_base = 0, /* Used for options processing. */
|
||||
|
||||
/*
|
||||
* *_uninit are used only during bootstrapping, and must correspond
|
||||
* to initialized variant plus percpu_arena_mode_enabled_base.
|
||||
*/
|
||||
percpu_arena_uninit = 0,
|
||||
per_phycpu_arena_uninit = 1,
|
||||
|
||||
/* All non-disabled modes must come after percpu_arena_disabled. */
|
||||
percpu_arena_disabled = 2,
|
||||
|
||||
percpu_arena_mode_names_limit = 3, /* Used for options processing. */
|
||||
percpu_arena_mode_enabled_base = 3,
|
||||
|
||||
percpu_arena = 3,
|
||||
per_phycpu_arena = 4 /* Hyper threads share arena. */
|
||||
} percpu_arena_mode_t;
|
||||
|
||||
#define PERCPU_ARENA_ENABLED(m) ((m) >= percpu_arena_mode_enabled_base)
|
||||
#define PERCPU_ARENA_DEFAULT percpu_arena_disabled
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_ARENA_TYPES_H */
|
56
deps/jemalloc/include/jemalloc/internal/assert.h
vendored
Normal file
56
deps/jemalloc/include/jemalloc/internal/assert.h
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
#include "jemalloc/internal/malloc_io.h"
|
||||
#include "jemalloc/internal/util.h"
|
||||
|
||||
/*
|
||||
* Define a custom assert() in order to reduce the chances of deadlock during
|
||||
* assertion failure.
|
||||
*/
|
||||
#ifndef assert
|
||||
#define assert(e) do { \
|
||||
if (unlikely(config_debug && !(e))) { \
|
||||
malloc_printf( \
|
||||
"<jemalloc>: %s:%d: Failed assertion: \"%s\"\n", \
|
||||
__FILE__, __LINE__, #e); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef not_reached
|
||||
#define not_reached() do { \
|
||||
if (config_debug) { \
|
||||
malloc_printf( \
|
||||
"<jemalloc>: %s:%d: Unreachable code reached\n", \
|
||||
__FILE__, __LINE__); \
|
||||
abort(); \
|
||||
} \
|
||||
unreachable(); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef not_implemented
|
||||
#define not_implemented() do { \
|
||||
if (config_debug) { \
|
||||
malloc_printf("<jemalloc>: %s:%d: Not implemented\n", \
|
||||
__FILE__, __LINE__); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef assert_not_implemented
|
||||
#define assert_not_implemented(e) do { \
|
||||
if (unlikely(config_debug && !(e))) { \
|
||||
not_implemented(); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/* Use to assert a particular configuration, e.g., cassert(config_debug). */
|
||||
#ifndef cassert
|
||||
#define cassert(c) do { \
|
||||
if (unlikely(!(c))) { \
|
||||
not_reached(); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
688
deps/jemalloc/include/jemalloc/internal/atomic.h
vendored
688
deps/jemalloc/include/jemalloc/internal/atomic.h
vendored
@ -1,651 +1,77 @@
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_TYPES
|
||||
#ifndef JEMALLOC_INTERNAL_ATOMIC_H
|
||||
#define JEMALLOC_INTERNAL_ATOMIC_H
|
||||
|
||||
#endif /* JEMALLOC_H_TYPES */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_STRUCTS
|
||||
#define ATOMIC_INLINE static inline
|
||||
|
||||
#endif /* JEMALLOC_H_STRUCTS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_EXTERNS
|
||||
|
||||
#define atomic_read_uint64(p) atomic_add_uint64(p, 0)
|
||||
#define atomic_read_uint32(p) atomic_add_uint32(p, 0)
|
||||
#define atomic_read_p(p) atomic_add_p(p, NULL)
|
||||
#define atomic_read_z(p) atomic_add_z(p, 0)
|
||||
#define atomic_read_u(p) atomic_add_u(p, 0)
|
||||
|
||||
#endif /* JEMALLOC_H_EXTERNS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_INLINES
|
||||
#if defined(JEMALLOC_GCC_ATOMIC_ATOMICS)
|
||||
# include "jemalloc/internal/atomic_gcc_atomic.h"
|
||||
#elif defined(JEMALLOC_GCC_SYNC_ATOMICS)
|
||||
# include "jemalloc/internal/atomic_gcc_sync.h"
|
||||
#elif defined(_MSC_VER)
|
||||
# include "jemalloc/internal/atomic_msvc.h"
|
||||
#elif defined(JEMALLOC_C11_ATOMICS)
|
||||
# include "jemalloc/internal/atomic_c11.h"
|
||||
#else
|
||||
# error "Don't have atomics implemented on this platform."
|
||||
#endif
|
||||
|
||||
/*
|
||||
* All arithmetic functions return the arithmetic result of the atomic
|
||||
* operation. Some atomic operation APIs return the value prior to mutation, in
|
||||
* which case the following functions must redundantly compute the result so
|
||||
* that it can be returned. These functions are normally inlined, so the extra
|
||||
* operations can be optimized away if the return values aren't used by the
|
||||
* callers.
|
||||
* This header gives more or less a backport of C11 atomics. The user can write
|
||||
* JEMALLOC_GENERATE_ATOMICS(type, short_type, lg_sizeof_type); to generate
|
||||
* counterparts of the C11 atomic functions for type, as so:
|
||||
* JEMALLOC_GENERATE_ATOMICS(int *, pi, 3);
|
||||
* and then write things like:
|
||||
* int *some_ptr;
|
||||
* atomic_pi_t atomic_ptr_to_int;
|
||||
* atomic_store_pi(&atomic_ptr_to_int, some_ptr, ATOMIC_RELAXED);
|
||||
* int *prev_value = atomic_exchange_pi(&ptr_to_int, NULL, ATOMIC_ACQ_REL);
|
||||
* assert(some_ptr == prev_value);
|
||||
* and expect things to work in the obvious way.
|
||||
*
|
||||
* <t> atomic_read_<t>(<t> *p) { return (*p); }
|
||||
* <t> atomic_add_<t>(<t> *p, <t> x) { return (*p + x); }
|
||||
* <t> atomic_sub_<t>(<t> *p, <t> x) { return (*p - x); }
|
||||
* bool atomic_cas_<t>(<t> *p, <t> c, <t> s)
|
||||
* {
|
||||
* if (*p != c)
|
||||
* return (true);
|
||||
* *p = s;
|
||||
* return (false);
|
||||
* }
|
||||
* void atomic_write_<t>(<t> *p, <t> x) { *p = x; }
|
||||
* Also included (with naming differences to avoid conflicts with the standard
|
||||
* library):
|
||||
* atomic_fence(atomic_memory_order_t) (mimics C11's atomic_thread_fence).
|
||||
* ATOMIC_INIT (mimics C11's ATOMIC_VAR_INIT).
|
||||
*/
|
||||
|
||||
#ifndef JEMALLOC_ENABLE_INLINE
|
||||
uint64_t atomic_add_uint64(uint64_t *p, uint64_t x);
|
||||
uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x);
|
||||
bool atomic_cas_uint64(uint64_t *p, uint64_t c, uint64_t s);
|
||||
void atomic_write_uint64(uint64_t *p, uint64_t x);
|
||||
uint32_t atomic_add_uint32(uint32_t *p, uint32_t x);
|
||||
uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x);
|
||||
bool atomic_cas_uint32(uint32_t *p, uint32_t c, uint32_t s);
|
||||
void atomic_write_uint32(uint32_t *p, uint32_t x);
|
||||
void *atomic_add_p(void **p, void *x);
|
||||
void *atomic_sub_p(void **p, void *x);
|
||||
bool atomic_cas_p(void **p, void *c, void *s);
|
||||
void atomic_write_p(void **p, const void *x);
|
||||
size_t atomic_add_z(size_t *p, size_t x);
|
||||
size_t atomic_sub_z(size_t *p, size_t x);
|
||||
bool atomic_cas_z(size_t *p, size_t c, size_t s);
|
||||
void atomic_write_z(size_t *p, size_t x);
|
||||
unsigned atomic_add_u(unsigned *p, unsigned x);
|
||||
unsigned atomic_sub_u(unsigned *p, unsigned x);
|
||||
bool atomic_cas_u(unsigned *p, unsigned c, unsigned s);
|
||||
void atomic_write_u(unsigned *p, unsigned x);
|
||||
#endif
|
||||
/*
|
||||
* Pure convenience, so that we don't have to type "atomic_memory_order_"
|
||||
* quite so often.
|
||||
*/
|
||||
#define ATOMIC_RELAXED atomic_memory_order_relaxed
|
||||
#define ATOMIC_ACQUIRE atomic_memory_order_acquire
|
||||
#define ATOMIC_RELEASE atomic_memory_order_release
|
||||
#define ATOMIC_ACQ_REL atomic_memory_order_acq_rel
|
||||
#define ATOMIC_SEQ_CST atomic_memory_order_seq_cst
|
||||
|
||||
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ATOMIC_C_))
|
||||
/******************************************************************************/
|
||||
/* 64-bit operations. */
|
||||
/*
|
||||
* Not all platforms have 64-bit atomics. If we do, this #define exposes that
|
||||
* fact.
|
||||
*/
|
||||
#if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3)
|
||||
# if (defined(__amd64__) || defined(__x86_64__))
|
||||
JEMALLOC_INLINE uint64_t
|
||||
atomic_add_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
uint64_t t = x;
|
||||
|
||||
asm volatile (
|
||||
"lock; xaddq %0, %1;"
|
||||
: "+r" (t), "=m" (*p) /* Outputs. */
|
||||
: "m" (*p) /* Inputs. */
|
||||
);
|
||||
|
||||
return (t + x);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE uint64_t
|
||||
atomic_sub_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
uint64_t t;
|
||||
|
||||
x = (uint64_t)(-(int64_t)x);
|
||||
t = x;
|
||||
asm volatile (
|
||||
"lock; xaddq %0, %1;"
|
||||
: "+r" (t), "=m" (*p) /* Outputs. */
|
||||
: "m" (*p) /* Inputs. */
|
||||
);
|
||||
|
||||
return (t + x);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
atomic_cas_uint64(uint64_t *p, uint64_t c, uint64_t s)
|
||||
{
|
||||
uint8_t success;
|
||||
|
||||
asm volatile (
|
||||
"lock; cmpxchgq %4, %0;"
|
||||
"sete %1;"
|
||||
: "=m" (*p), "=a" (success) /* Outputs. */
|
||||
: "m" (*p), "a" (c), "r" (s) /* Inputs. */
|
||||
: "memory" /* Clobbers. */
|
||||
);
|
||||
|
||||
return (!(bool)success);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
atomic_write_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
|
||||
asm volatile (
|
||||
"xchgq %1, %0;" /* Lock is implied by xchgq. */
|
||||
: "=m" (*p), "+r" (x) /* Outputs. */
|
||||
: "m" (*p) /* Inputs. */
|
||||
: "memory" /* Clobbers. */
|
||||
);
|
||||
}
|
||||
# elif (defined(JEMALLOC_C11ATOMICS))
|
||||
JEMALLOC_INLINE uint64_t
|
||||
atomic_add_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p;
|
||||
return (atomic_fetch_add(a, x) + x);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE uint64_t
|
||||
atomic_sub_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p;
|
||||
return (atomic_fetch_sub(a, x) - x);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
atomic_cas_uint64(uint64_t *p, uint64_t c, uint64_t s)
|
||||
{
|
||||
volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p;
|
||||
return (!atomic_compare_exchange_strong(a, &c, s));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
atomic_write_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p;
|
||||
atomic_store(a, x);
|
||||
}
|
||||
# elif (defined(JEMALLOC_ATOMIC9))
|
||||
JEMALLOC_INLINE uint64_t
|
||||
atomic_add_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
|
||||
/*
|
||||
* atomic_fetchadd_64() doesn't exist, but we only ever use this
|
||||
* function on LP64 systems, so atomic_fetchadd_long() will do.
|
||||
*/
|
||||
assert(sizeof(uint64_t) == sizeof(unsigned long));
|
||||
|
||||
return (atomic_fetchadd_long(p, (unsigned long)x) + x);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE uint64_t
|
||||
atomic_sub_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
|
||||
assert(sizeof(uint64_t) == sizeof(unsigned long));
|
||||
|
||||
return (atomic_fetchadd_long(p, (unsigned long)(-(long)x)) - x);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
atomic_cas_uint64(uint64_t *p, uint64_t c, uint64_t s)
|
||||
{
|
||||
|
||||
assert(sizeof(uint64_t) == sizeof(unsigned long));
|
||||
|
||||
return (!atomic_cmpset_long(p, (unsigned long)c, (unsigned long)s));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
atomic_write_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
|
||||
assert(sizeof(uint64_t) == sizeof(unsigned long));
|
||||
|
||||
atomic_store_rel_long(p, x);
|
||||
}
|
||||
# elif (defined(JEMALLOC_OSATOMIC))
|
||||
JEMALLOC_INLINE uint64_t
|
||||
atomic_add_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
|
||||
return (OSAtomicAdd64((int64_t)x, (int64_t *)p));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE uint64_t
|
||||
atomic_sub_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
|
||||
return (OSAtomicAdd64(-((int64_t)x), (int64_t *)p));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
atomic_cas_uint64(uint64_t *p, uint64_t c, uint64_t s)
|
||||
{
|
||||
|
||||
return (!OSAtomicCompareAndSwap64(c, s, (int64_t *)p));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
atomic_write_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
uint64_t o;
|
||||
|
||||
/*The documented OSAtomic*() API does not expose an atomic exchange. */
|
||||
do {
|
||||
o = atomic_read_uint64(p);
|
||||
} while (atomic_cas_uint64(p, o, x));
|
||||
}
|
||||
# elif (defined(_MSC_VER))
|
||||
JEMALLOC_INLINE uint64_t
|
||||
atomic_add_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
|
||||
return (InterlockedExchangeAdd64(p, x) + x);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE uint64_t
|
||||
atomic_sub_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
|
||||
return (InterlockedExchangeAdd64(p, -((int64_t)x)) - x);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
atomic_cas_uint64(uint64_t *p, uint64_t c, uint64_t s)
|
||||
{
|
||||
uint64_t o;
|
||||
|
||||
o = InterlockedCompareExchange64(p, s, c);
|
||||
return (o != c);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
atomic_write_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
|
||||
InterlockedExchange64(p, x);
|
||||
}
|
||||
# elif (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || \
|
||||
defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_8))
|
||||
JEMALLOC_INLINE uint64_t
|
||||
atomic_add_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
|
||||
return (__sync_add_and_fetch(p, x));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE uint64_t
|
||||
atomic_sub_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
|
||||
return (__sync_sub_and_fetch(p, x));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
atomic_cas_uint64(uint64_t *p, uint64_t c, uint64_t s)
|
||||
{
|
||||
|
||||
return (!__sync_bool_compare_and_swap(p, c, s));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
atomic_write_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
|
||||
__sync_lock_test_and_set(p, x);
|
||||
}
|
||||
# else
|
||||
# error "Missing implementation for 64-bit atomic operations"
|
||||
# endif
|
||||
# define JEMALLOC_ATOMIC_U64
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/* 32-bit operations. */
|
||||
#if (defined(__i386__) || defined(__amd64__) || defined(__x86_64__))
|
||||
JEMALLOC_INLINE uint32_t
|
||||
atomic_add_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
uint32_t t = x;
|
||||
JEMALLOC_GENERATE_ATOMICS(void *, p, LG_SIZEOF_PTR)
|
||||
|
||||
asm volatile (
|
||||
"lock; xaddl %0, %1;"
|
||||
: "+r" (t), "=m" (*p) /* Outputs. */
|
||||
: "m" (*p) /* Inputs. */
|
||||
);
|
||||
/*
|
||||
* There's no actual guarantee that sizeof(bool) == 1, but it's true on the only
|
||||
* platform that actually needs to know the size, MSVC.
|
||||
*/
|
||||
JEMALLOC_GENERATE_ATOMICS(bool, b, 0)
|
||||
|
||||
return (t + x);
|
||||
}
|
||||
JEMALLOC_GENERATE_INT_ATOMICS(unsigned, u, LG_SIZEOF_INT)
|
||||
|
||||
JEMALLOC_INLINE uint32_t
|
||||
atomic_sub_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
uint32_t t;
|
||||
JEMALLOC_GENERATE_INT_ATOMICS(size_t, zu, LG_SIZEOF_PTR)
|
||||
|
||||
x = (uint32_t)(-(int32_t)x);
|
||||
t = x;
|
||||
asm volatile (
|
||||
"lock; xaddl %0, %1;"
|
||||
: "+r" (t), "=m" (*p) /* Outputs. */
|
||||
: "m" (*p) /* Inputs. */
|
||||
);
|
||||
JEMALLOC_GENERATE_INT_ATOMICS(ssize_t, zd, LG_SIZEOF_PTR)
|
||||
|
||||
return (t + x);
|
||||
}
|
||||
JEMALLOC_GENERATE_INT_ATOMICS(uint32_t, u32, 2)
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
atomic_cas_uint32(uint32_t *p, uint32_t c, uint32_t s)
|
||||
{
|
||||
uint8_t success;
|
||||
|
||||
asm volatile (
|
||||
"lock; cmpxchgl %4, %0;"
|
||||
"sete %1;"
|
||||
: "=m" (*p), "=a" (success) /* Outputs. */
|
||||
: "m" (*p), "a" (c), "r" (s) /* Inputs. */
|
||||
: "memory"
|
||||
);
|
||||
|
||||
return (!(bool)success);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
atomic_write_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
|
||||
asm volatile (
|
||||
"xchgl %1, %0;" /* Lock is implied by xchgl. */
|
||||
: "=m" (*p), "+r" (x) /* Outputs. */
|
||||
: "m" (*p) /* Inputs. */
|
||||
: "memory" /* Clobbers. */
|
||||
);
|
||||
}
|
||||
# elif (defined(JEMALLOC_C11ATOMICS))
|
||||
JEMALLOC_INLINE uint32_t
|
||||
atomic_add_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p;
|
||||
return (atomic_fetch_add(a, x) + x);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE uint32_t
|
||||
atomic_sub_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p;
|
||||
return (atomic_fetch_sub(a, x) - x);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
atomic_cas_uint32(uint32_t *p, uint32_t c, uint32_t s)
|
||||
{
|
||||
volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p;
|
||||
return (!atomic_compare_exchange_strong(a, &c, s));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
atomic_write_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p;
|
||||
atomic_store(a, x);
|
||||
}
|
||||
#elif (defined(JEMALLOC_ATOMIC9))
|
||||
JEMALLOC_INLINE uint32_t
|
||||
atomic_add_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
|
||||
return (atomic_fetchadd_32(p, x) + x);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE uint32_t
|
||||
atomic_sub_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
|
||||
return (atomic_fetchadd_32(p, (uint32_t)(-(int32_t)x)) - x);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
atomic_cas_uint32(uint32_t *p, uint32_t c, uint32_t s)
|
||||
{
|
||||
|
||||
return (!atomic_cmpset_32(p, c, s));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
atomic_write_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
|
||||
atomic_store_rel_32(p, x);
|
||||
}
|
||||
#elif (defined(JEMALLOC_OSATOMIC))
|
||||
JEMALLOC_INLINE uint32_t
|
||||
atomic_add_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
|
||||
return (OSAtomicAdd32((int32_t)x, (int32_t *)p));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE uint32_t
|
||||
atomic_sub_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
|
||||
return (OSAtomicAdd32(-((int32_t)x), (int32_t *)p));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
atomic_cas_uint32(uint32_t *p, uint32_t c, uint32_t s)
|
||||
{
|
||||
|
||||
return (!OSAtomicCompareAndSwap32(c, s, (int32_t *)p));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
atomic_write_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
uint32_t o;
|
||||
|
||||
/*The documented OSAtomic*() API does not expose an atomic exchange. */
|
||||
do {
|
||||
o = atomic_read_uint32(p);
|
||||
} while (atomic_cas_uint32(p, o, x));
|
||||
}
|
||||
#elif (defined(_MSC_VER))
|
||||
JEMALLOC_INLINE uint32_t
|
||||
atomic_add_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
|
||||
return (InterlockedExchangeAdd(p, x) + x);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE uint32_t
|
||||
atomic_sub_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
|
||||
return (InterlockedExchangeAdd(p, -((int32_t)x)) - x);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
atomic_cas_uint32(uint32_t *p, uint32_t c, uint32_t s)
|
||||
{
|
||||
uint32_t o;
|
||||
|
||||
o = InterlockedCompareExchange(p, s, c);
|
||||
return (o != c);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
atomic_write_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
|
||||
InterlockedExchange(p, x);
|
||||
}
|
||||
#elif (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || \
|
||||
defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4))
|
||||
JEMALLOC_INLINE uint32_t
|
||||
atomic_add_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
|
||||
return (__sync_add_and_fetch(p, x));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE uint32_t
|
||||
atomic_sub_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
|
||||
return (__sync_sub_and_fetch(p, x));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
atomic_cas_uint32(uint32_t *p, uint32_t c, uint32_t s)
|
||||
{
|
||||
|
||||
return (!__sync_bool_compare_and_swap(p, c, s));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
atomic_write_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
|
||||
__sync_lock_test_and_set(p, x);
|
||||
}
|
||||
#else
|
||||
# error "Missing implementation for 32-bit atomic operations"
|
||||
#ifdef JEMALLOC_ATOMIC_U64
|
||||
JEMALLOC_GENERATE_INT_ATOMICS(uint64_t, u64, 3)
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/* Pointer operations. */
|
||||
JEMALLOC_INLINE void *
|
||||
atomic_add_p(void **p, void *x)
|
||||
{
|
||||
#undef ATOMIC_INLINE
|
||||
|
||||
#if (LG_SIZEOF_PTR == 3)
|
||||
return ((void *)atomic_add_uint64((uint64_t *)p, (uint64_t)x));
|
||||
#elif (LG_SIZEOF_PTR == 2)
|
||||
return ((void *)atomic_add_uint32((uint32_t *)p, (uint32_t)x));
|
||||
#endif
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void *
|
||||
atomic_sub_p(void **p, void *x)
|
||||
{
|
||||
|
||||
#if (LG_SIZEOF_PTR == 3)
|
||||
return ((void *)atomic_add_uint64((uint64_t *)p,
|
||||
(uint64_t)-((int64_t)x)));
|
||||
#elif (LG_SIZEOF_PTR == 2)
|
||||
return ((void *)atomic_add_uint32((uint32_t *)p,
|
||||
(uint32_t)-((int32_t)x)));
|
||||
#endif
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
atomic_cas_p(void **p, void *c, void *s)
|
||||
{
|
||||
|
||||
#if (LG_SIZEOF_PTR == 3)
|
||||
return (atomic_cas_uint64((uint64_t *)p, (uint64_t)c, (uint64_t)s));
|
||||
#elif (LG_SIZEOF_PTR == 2)
|
||||
return (atomic_cas_uint32((uint32_t *)p, (uint32_t)c, (uint32_t)s));
|
||||
#endif
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
atomic_write_p(void **p, const void *x)
|
||||
{
|
||||
|
||||
#if (LG_SIZEOF_PTR == 3)
|
||||
atomic_write_uint64((uint64_t *)p, (uint64_t)x);
|
||||
#elif (LG_SIZEOF_PTR == 2)
|
||||
atomic_write_uint32((uint32_t *)p, (uint32_t)x);
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* size_t operations. */
|
||||
JEMALLOC_INLINE size_t
|
||||
atomic_add_z(size_t *p, size_t x)
|
||||
{
|
||||
|
||||
#if (LG_SIZEOF_PTR == 3)
|
||||
return ((size_t)atomic_add_uint64((uint64_t *)p, (uint64_t)x));
|
||||
#elif (LG_SIZEOF_PTR == 2)
|
||||
return ((size_t)atomic_add_uint32((uint32_t *)p, (uint32_t)x));
|
||||
#endif
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE size_t
|
||||
atomic_sub_z(size_t *p, size_t x)
|
||||
{
|
||||
|
||||
#if (LG_SIZEOF_PTR == 3)
|
||||
return ((size_t)atomic_add_uint64((uint64_t *)p,
|
||||
(uint64_t)-((int64_t)x)));
|
||||
#elif (LG_SIZEOF_PTR == 2)
|
||||
return ((size_t)atomic_add_uint32((uint32_t *)p,
|
||||
(uint32_t)-((int32_t)x)));
|
||||
#endif
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
atomic_cas_z(size_t *p, size_t c, size_t s)
|
||||
{
|
||||
|
||||
#if (LG_SIZEOF_PTR == 3)
|
||||
return (atomic_cas_uint64((uint64_t *)p, (uint64_t)c, (uint64_t)s));
|
||||
#elif (LG_SIZEOF_PTR == 2)
|
||||
return (atomic_cas_uint32((uint32_t *)p, (uint32_t)c, (uint32_t)s));
|
||||
#endif
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
atomic_write_z(size_t *p, size_t x)
|
||||
{
|
||||
|
||||
#if (LG_SIZEOF_PTR == 3)
|
||||
atomic_write_uint64((uint64_t *)p, (uint64_t)x);
|
||||
#elif (LG_SIZEOF_PTR == 2)
|
||||
atomic_write_uint32((uint32_t *)p, (uint32_t)x);
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* unsigned operations. */
|
||||
JEMALLOC_INLINE unsigned
|
||||
atomic_add_u(unsigned *p, unsigned x)
|
||||
{
|
||||
|
||||
#if (LG_SIZEOF_INT == 3)
|
||||
return ((unsigned)atomic_add_uint64((uint64_t *)p, (uint64_t)x));
|
||||
#elif (LG_SIZEOF_INT == 2)
|
||||
return ((unsigned)atomic_add_uint32((uint32_t *)p, (uint32_t)x));
|
||||
#endif
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE unsigned
|
||||
atomic_sub_u(unsigned *p, unsigned x)
|
||||
{
|
||||
|
||||
#if (LG_SIZEOF_INT == 3)
|
||||
return ((unsigned)atomic_add_uint64((uint64_t *)p,
|
||||
(uint64_t)-((int64_t)x)));
|
||||
#elif (LG_SIZEOF_INT == 2)
|
||||
return ((unsigned)atomic_add_uint32((uint32_t *)p,
|
||||
(uint32_t)-((int32_t)x)));
|
||||
#endif
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
atomic_cas_u(unsigned *p, unsigned c, unsigned s)
|
||||
{
|
||||
|
||||
#if (LG_SIZEOF_INT == 3)
|
||||
return (atomic_cas_uint64((uint64_t *)p, (uint64_t)c, (uint64_t)s));
|
||||
#elif (LG_SIZEOF_INT == 2)
|
||||
return (atomic_cas_uint32((uint32_t *)p, (uint32_t)c, (uint32_t)s));
|
||||
#endif
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
atomic_write_u(unsigned *p, unsigned x)
|
||||
{
|
||||
|
||||
#if (LG_SIZEOF_INT == 3)
|
||||
atomic_write_uint64((uint64_t *)p, (uint64_t)x);
|
||||
#elif (LG_SIZEOF_INT == 2)
|
||||
atomic_write_uint32((uint32_t *)p, (uint32_t)x);
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
#endif
|
||||
|
||||
#endif /* JEMALLOC_H_INLINES */
|
||||
/******************************************************************************/
|
||||
#endif /* JEMALLOC_INTERNAL_ATOMIC_H */
|
||||
|
97
deps/jemalloc/include/jemalloc/internal/atomic_c11.h
vendored
Normal file
97
deps/jemalloc/include/jemalloc/internal/atomic_c11.h
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
#ifndef JEMALLOC_INTERNAL_ATOMIC_C11_H
|
||||
#define JEMALLOC_INTERNAL_ATOMIC_C11_H
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
#define ATOMIC_INIT(...) ATOMIC_VAR_INIT(__VA_ARGS__)
|
||||
|
||||
#define atomic_memory_order_t memory_order
|
||||
#define atomic_memory_order_relaxed memory_order_relaxed
|
||||
#define atomic_memory_order_acquire memory_order_acquire
|
||||
#define atomic_memory_order_release memory_order_release
|
||||
#define atomic_memory_order_acq_rel memory_order_acq_rel
|
||||
#define atomic_memory_order_seq_cst memory_order_seq_cst
|
||||
|
||||
#define atomic_fence atomic_thread_fence
|
||||
|
||||
#define JEMALLOC_GENERATE_ATOMICS(type, short_type, \
|
||||
/* unused */ lg_size) \
|
||||
typedef _Atomic(type) atomic_##short_type##_t; \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_load_##short_type(const atomic_##short_type##_t *a, \
|
||||
atomic_memory_order_t mo) { \
|
||||
/* \
|
||||
* A strict interpretation of the C standard prevents \
|
||||
* atomic_load from taking a const argument, but it's \
|
||||
* convenient for our purposes. This cast is a workaround. \
|
||||
*/ \
|
||||
atomic_##short_type##_t* a_nonconst = \
|
||||
(atomic_##short_type##_t*)a; \
|
||||
return atomic_load_explicit(a_nonconst, mo); \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE void \
|
||||
atomic_store_##short_type(atomic_##short_type##_t *a, \
|
||||
type val, atomic_memory_order_t mo) { \
|
||||
atomic_store_explicit(a, val, mo); \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
atomic_memory_order_t mo) { \
|
||||
return atomic_exchange_explicit(a, val, mo); \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE bool \
|
||||
atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
|
||||
type *expected, type desired, atomic_memory_order_t success_mo, \
|
||||
atomic_memory_order_t failure_mo) { \
|
||||
return atomic_compare_exchange_weak_explicit(a, expected, \
|
||||
desired, success_mo, failure_mo); \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE bool \
|
||||
atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \
|
||||
type *expected, type desired, atomic_memory_order_t success_mo, \
|
||||
atomic_memory_order_t failure_mo) { \
|
||||
return atomic_compare_exchange_strong_explicit(a, expected, \
|
||||
desired, success_mo, failure_mo); \
|
||||
}
|
||||
|
||||
/*
|
||||
* Integral types have some special operations available that non-integral ones
|
||||
* lack.
|
||||
*/
|
||||
#define JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, \
|
||||
/* unused */ lg_size) \
|
||||
JEMALLOC_GENERATE_ATOMICS(type, short_type, /* unused */ lg_size) \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_add_##short_type(atomic_##short_type##_t *a, \
|
||||
type val, atomic_memory_order_t mo) { \
|
||||
return atomic_fetch_add_explicit(a, val, mo); \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_sub_##short_type(atomic_##short_type##_t *a, \
|
||||
type val, atomic_memory_order_t mo) { \
|
||||
return atomic_fetch_sub_explicit(a, val, mo); \
|
||||
} \
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_and_##short_type(atomic_##short_type##_t *a, \
|
||||
type val, atomic_memory_order_t mo) { \
|
||||
return atomic_fetch_and_explicit(a, val, mo); \
|
||||
} \
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_or_##short_type(atomic_##short_type##_t *a, \
|
||||
type val, atomic_memory_order_t mo) { \
|
||||
return atomic_fetch_or_explicit(a, val, mo); \
|
||||
} \
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_xor_##short_type(atomic_##short_type##_t *a, \
|
||||
type val, atomic_memory_order_t mo) { \
|
||||
return atomic_fetch_xor_explicit(a, val, mo); \
|
||||
}
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_ATOMIC_C11_H */
|
127
deps/jemalloc/include/jemalloc/internal/atomic_gcc_atomic.h
vendored
Normal file
127
deps/jemalloc/include/jemalloc/internal/atomic_gcc_atomic.h
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
#ifndef JEMALLOC_INTERNAL_ATOMIC_GCC_ATOMIC_H
|
||||
#define JEMALLOC_INTERNAL_ATOMIC_GCC_ATOMIC_H
|
||||
|
||||
#include "jemalloc/internal/assert.h"
|
||||
|
||||
#define ATOMIC_INIT(...) {__VA_ARGS__}
|
||||
|
||||
typedef enum {
|
||||
atomic_memory_order_relaxed,
|
||||
atomic_memory_order_acquire,
|
||||
atomic_memory_order_release,
|
||||
atomic_memory_order_acq_rel,
|
||||
atomic_memory_order_seq_cst
|
||||
} atomic_memory_order_t;
|
||||
|
||||
ATOMIC_INLINE int
|
||||
atomic_enum_to_builtin(atomic_memory_order_t mo) {
|
||||
switch (mo) {
|
||||
case atomic_memory_order_relaxed:
|
||||
return __ATOMIC_RELAXED;
|
||||
case atomic_memory_order_acquire:
|
||||
return __ATOMIC_ACQUIRE;
|
||||
case atomic_memory_order_release:
|
||||
return __ATOMIC_RELEASE;
|
||||
case atomic_memory_order_acq_rel:
|
||||
return __ATOMIC_ACQ_REL;
|
||||
case atomic_memory_order_seq_cst:
|
||||
return __ATOMIC_SEQ_CST;
|
||||
}
|
||||
/* Can't happen; the switch is exhaustive. */
|
||||
not_reached();
|
||||
}
|
||||
|
||||
ATOMIC_INLINE void
|
||||
atomic_fence(atomic_memory_order_t mo) {
|
||||
__atomic_thread_fence(atomic_enum_to_builtin(mo));
|
||||
}
|
||||
|
||||
#define JEMALLOC_GENERATE_ATOMICS(type, short_type, \
|
||||
/* unused */ lg_size) \
|
||||
typedef struct { \
|
||||
type repr; \
|
||||
} atomic_##short_type##_t; \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_load_##short_type(const atomic_##short_type##_t *a, \
|
||||
atomic_memory_order_t mo) { \
|
||||
type result; \
|
||||
__atomic_load(&a->repr, &result, atomic_enum_to_builtin(mo)); \
|
||||
return result; \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE void \
|
||||
atomic_store_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
atomic_memory_order_t mo) { \
|
||||
__atomic_store(&a->repr, &val, atomic_enum_to_builtin(mo)); \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
atomic_memory_order_t mo) { \
|
||||
type result; \
|
||||
__atomic_exchange(&a->repr, &val, &result, \
|
||||
atomic_enum_to_builtin(mo)); \
|
||||
return result; \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE bool \
|
||||
atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
|
||||
type *expected, type desired, atomic_memory_order_t success_mo, \
|
||||
atomic_memory_order_t failure_mo) { \
|
||||
return __atomic_compare_exchange(&a->repr, expected, &desired, \
|
||||
true, atomic_enum_to_builtin(success_mo), \
|
||||
atomic_enum_to_builtin(failure_mo)); \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE bool \
|
||||
atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \
|
||||
type *expected, type desired, atomic_memory_order_t success_mo, \
|
||||
atomic_memory_order_t failure_mo) { \
|
||||
return __atomic_compare_exchange(&a->repr, expected, &desired, \
|
||||
false, \
|
||||
atomic_enum_to_builtin(success_mo), \
|
||||
atomic_enum_to_builtin(failure_mo)); \
|
||||
}
|
||||
|
||||
|
||||
#define JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, \
|
||||
/* unused */ lg_size) \
|
||||
JEMALLOC_GENERATE_ATOMICS(type, short_type, /* unused */ lg_size) \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_add_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
atomic_memory_order_t mo) { \
|
||||
return __atomic_fetch_add(&a->repr, val, \
|
||||
atomic_enum_to_builtin(mo)); \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_sub_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
atomic_memory_order_t mo) { \
|
||||
return __atomic_fetch_sub(&a->repr, val, \
|
||||
atomic_enum_to_builtin(mo)); \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_and_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
atomic_memory_order_t mo) { \
|
||||
return __atomic_fetch_and(&a->repr, val, \
|
||||
atomic_enum_to_builtin(mo)); \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_or_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
atomic_memory_order_t mo) { \
|
||||
return __atomic_fetch_or(&a->repr, val, \
|
||||
atomic_enum_to_builtin(mo)); \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_xor_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
atomic_memory_order_t mo) { \
|
||||
return __atomic_fetch_xor(&a->repr, val, \
|
||||
atomic_enum_to_builtin(mo)); \
|
||||
}
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_ATOMIC_GCC_ATOMIC_H */
|
191
deps/jemalloc/include/jemalloc/internal/atomic_gcc_sync.h
vendored
Normal file
191
deps/jemalloc/include/jemalloc/internal/atomic_gcc_sync.h
vendored
Normal file
@ -0,0 +1,191 @@
|
||||
#ifndef JEMALLOC_INTERNAL_ATOMIC_GCC_SYNC_H
|
||||
#define JEMALLOC_INTERNAL_ATOMIC_GCC_SYNC_H
|
||||
|
||||
#define ATOMIC_INIT(...) {__VA_ARGS__}
|
||||
|
||||
typedef enum {
|
||||
atomic_memory_order_relaxed,
|
||||
atomic_memory_order_acquire,
|
||||
atomic_memory_order_release,
|
||||
atomic_memory_order_acq_rel,
|
||||
atomic_memory_order_seq_cst
|
||||
} atomic_memory_order_t;
|
||||
|
||||
ATOMIC_INLINE void
|
||||
atomic_fence(atomic_memory_order_t mo) {
|
||||
/* Easy cases first: no barrier, and full barrier. */
|
||||
if (mo == atomic_memory_order_relaxed) {
|
||||
asm volatile("" ::: "memory");
|
||||
return;
|
||||
}
|
||||
if (mo == atomic_memory_order_seq_cst) {
|
||||
asm volatile("" ::: "memory");
|
||||
__sync_synchronize();
|
||||
asm volatile("" ::: "memory");
|
||||
return;
|
||||
}
|
||||
asm volatile("" ::: "memory");
|
||||
# if defined(__i386__) || defined(__x86_64__)
|
||||
/* This is implicit on x86. */
|
||||
# elif defined(__ppc__)
|
||||
asm volatile("lwsync");
|
||||
# elif defined(__sparc__) && defined(__arch64__)
|
||||
if (mo == atomic_memory_order_acquire) {
|
||||
asm volatile("membar #LoadLoad | #LoadStore");
|
||||
} else if (mo == atomic_memory_order_release) {
|
||||
asm volatile("membar #LoadStore | #StoreStore");
|
||||
} else {
|
||||
asm volatile("membar #LoadLoad | #LoadStore | #StoreStore");
|
||||
}
|
||||
# else
|
||||
__sync_synchronize();
|
||||
# endif
|
||||
asm volatile("" ::: "memory");
|
||||
}
|
||||
|
||||
/*
|
||||
* A correct implementation of seq_cst loads and stores on weakly ordered
|
||||
* architectures could do either of the following:
|
||||
* 1. store() is weak-fence -> store -> strong fence, load() is load ->
|
||||
* strong-fence.
|
||||
* 2. store() is strong-fence -> store, load() is strong-fence -> load ->
|
||||
* weak-fence.
|
||||
* The tricky thing is, load() and store() above can be the load or store
|
||||
* portions of a gcc __sync builtin, so we have to follow GCC's lead, which
|
||||
* means going with strategy 2.
|
||||
* On strongly ordered architectures, the natural strategy is to stick a strong
|
||||
* fence after seq_cst stores, and have naked loads. So we want the strong
|
||||
* fences in different places on different architectures.
|
||||
* atomic_pre_sc_load_fence and atomic_post_sc_store_fence allow us to
|
||||
* accomplish this.
|
||||
*/
|
||||
|
||||
ATOMIC_INLINE void
|
||||
atomic_pre_sc_load_fence() {
|
||||
# if defined(__i386__) || defined(__x86_64__) || \
|
||||
(defined(__sparc__) && defined(__arch64__))
|
||||
atomic_fence(atomic_memory_order_relaxed);
|
||||
# else
|
||||
atomic_fence(atomic_memory_order_seq_cst);
|
||||
# endif
|
||||
}
|
||||
|
||||
ATOMIC_INLINE void
|
||||
atomic_post_sc_store_fence() {
|
||||
# if defined(__i386__) || defined(__x86_64__) || \
|
||||
(defined(__sparc__) && defined(__arch64__))
|
||||
atomic_fence(atomic_memory_order_seq_cst);
|
||||
# else
|
||||
atomic_fence(atomic_memory_order_relaxed);
|
||||
# endif
|
||||
|
||||
}
|
||||
|
||||
#define JEMALLOC_GENERATE_ATOMICS(type, short_type, \
|
||||
/* unused */ lg_size) \
|
||||
typedef struct { \
|
||||
type volatile repr; \
|
||||
} atomic_##short_type##_t; \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_load_##short_type(const atomic_##short_type##_t *a, \
|
||||
atomic_memory_order_t mo) { \
|
||||
if (mo == atomic_memory_order_seq_cst) { \
|
||||
atomic_pre_sc_load_fence(); \
|
||||
} \
|
||||
type result = a->repr; \
|
||||
if (mo != atomic_memory_order_relaxed) { \
|
||||
atomic_fence(atomic_memory_order_acquire); \
|
||||
} \
|
||||
return result; \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE void \
|
||||
atomic_store_##short_type(atomic_##short_type##_t *a, \
|
||||
type val, atomic_memory_order_t mo) { \
|
||||
if (mo != atomic_memory_order_relaxed) { \
|
||||
atomic_fence(atomic_memory_order_release); \
|
||||
} \
|
||||
a->repr = val; \
|
||||
if (mo == atomic_memory_order_seq_cst) { \
|
||||
atomic_post_sc_store_fence(); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
atomic_memory_order_t mo) { \
|
||||
/* \
|
||||
* Because of FreeBSD, we care about gcc 4.2, which doesn't have\
|
||||
* an atomic exchange builtin. We fake it with a CAS loop. \
|
||||
*/ \
|
||||
while (true) { \
|
||||
type old = a->repr; \
|
||||
if (__sync_bool_compare_and_swap(&a->repr, old, val)) { \
|
||||
return old; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE bool \
|
||||
atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
|
||||
type *expected, type desired, atomic_memory_order_t success_mo, \
|
||||
atomic_memory_order_t failure_mo) { \
|
||||
type prev = __sync_val_compare_and_swap(&a->repr, *expected, \
|
||||
desired); \
|
||||
if (prev == *expected) { \
|
||||
return true; \
|
||||
} else { \
|
||||
*expected = prev; \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
ATOMIC_INLINE bool \
|
||||
atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \
|
||||
type *expected, type desired, atomic_memory_order_t success_mo, \
|
||||
atomic_memory_order_t failure_mo) { \
|
||||
type prev = __sync_val_compare_and_swap(&a->repr, *expected, \
|
||||
desired); \
|
||||
if (prev == *expected) { \
|
||||
return true; \
|
||||
} else { \
|
||||
*expected = prev; \
|
||||
return false; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, \
|
||||
/* unused */ lg_size) \
|
||||
JEMALLOC_GENERATE_ATOMICS(type, short_type, /* unused */ lg_size) \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_add_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
atomic_memory_order_t mo) { \
|
||||
return __sync_fetch_and_add(&a->repr, val); \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_sub_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
atomic_memory_order_t mo) { \
|
||||
return __sync_fetch_and_sub(&a->repr, val); \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_and_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
atomic_memory_order_t mo) { \
|
||||
return __sync_fetch_and_and(&a->repr, val); \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_or_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
atomic_memory_order_t mo) { \
|
||||
return __sync_fetch_and_or(&a->repr, val); \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_xor_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
atomic_memory_order_t mo) { \
|
||||
return __sync_fetch_and_xor(&a->repr, val); \
|
||||
}
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_ATOMIC_GCC_SYNC_H */
|
158
deps/jemalloc/include/jemalloc/internal/atomic_msvc.h
vendored
Normal file
158
deps/jemalloc/include/jemalloc/internal/atomic_msvc.h
vendored
Normal file
@ -0,0 +1,158 @@
|
||||
#ifndef JEMALLOC_INTERNAL_ATOMIC_MSVC_H
|
||||
#define JEMALLOC_INTERNAL_ATOMIC_MSVC_H
|
||||
|
||||
#define ATOMIC_INIT(...) {__VA_ARGS__}
|
||||
|
||||
typedef enum {
|
||||
atomic_memory_order_relaxed,
|
||||
atomic_memory_order_acquire,
|
||||
atomic_memory_order_release,
|
||||
atomic_memory_order_acq_rel,
|
||||
atomic_memory_order_seq_cst
|
||||
} atomic_memory_order_t;
|
||||
|
||||
typedef char atomic_repr_0_t;
|
||||
typedef short atomic_repr_1_t;
|
||||
typedef long atomic_repr_2_t;
|
||||
typedef __int64 atomic_repr_3_t;
|
||||
|
||||
ATOMIC_INLINE void
|
||||
atomic_fence(atomic_memory_order_t mo) {
|
||||
_ReadWriteBarrier();
|
||||
# if defined(_M_ARM) || defined(_M_ARM64)
|
||||
/* ARM needs a barrier for everything but relaxed. */
|
||||
if (mo != atomic_memory_order_relaxed) {
|
||||
MemoryBarrier();
|
||||
}
|
||||
# elif defined(_M_IX86) || defined (_M_X64)
|
||||
/* x86 needs a barrier only for seq_cst. */
|
||||
if (mo == atomic_memory_order_seq_cst) {
|
||||
MemoryBarrier();
|
||||
}
|
||||
# else
|
||||
# error "Don't know how to create atomics for this platform for MSVC."
|
||||
# endif
|
||||
_ReadWriteBarrier();
|
||||
}
|
||||
|
||||
#define ATOMIC_INTERLOCKED_REPR(lg_size) atomic_repr_ ## lg_size ## _t
|
||||
|
||||
#define ATOMIC_CONCAT(a, b) ATOMIC_RAW_CONCAT(a, b)
|
||||
#define ATOMIC_RAW_CONCAT(a, b) a ## b
|
||||
|
||||
#define ATOMIC_INTERLOCKED_NAME(base_name, lg_size) ATOMIC_CONCAT( \
|
||||
base_name, ATOMIC_INTERLOCKED_SUFFIX(lg_size))
|
||||
|
||||
#define ATOMIC_INTERLOCKED_SUFFIX(lg_size) \
|
||||
ATOMIC_CONCAT(ATOMIC_INTERLOCKED_SUFFIX_, lg_size)
|
||||
|
||||
#define ATOMIC_INTERLOCKED_SUFFIX_0 8
|
||||
#define ATOMIC_INTERLOCKED_SUFFIX_1 16
|
||||
#define ATOMIC_INTERLOCKED_SUFFIX_2
|
||||
#define ATOMIC_INTERLOCKED_SUFFIX_3 64
|
||||
|
||||
#define JEMALLOC_GENERATE_ATOMICS(type, short_type, lg_size) \
|
||||
typedef struct { \
|
||||
ATOMIC_INTERLOCKED_REPR(lg_size) repr; \
|
||||
} atomic_##short_type##_t; \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_load_##short_type(const atomic_##short_type##_t *a, \
|
||||
atomic_memory_order_t mo) { \
|
||||
ATOMIC_INTERLOCKED_REPR(lg_size) ret = a->repr; \
|
||||
if (mo != atomic_memory_order_relaxed) { \
|
||||
atomic_fence(atomic_memory_order_acquire); \
|
||||
} \
|
||||
return (type) ret; \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE void \
|
||||
atomic_store_##short_type(atomic_##short_type##_t *a, \
|
||||
type val, atomic_memory_order_t mo) { \
|
||||
if (mo != atomic_memory_order_relaxed) { \
|
||||
atomic_fence(atomic_memory_order_release); \
|
||||
} \
|
||||
a->repr = (ATOMIC_INTERLOCKED_REPR(lg_size)) val; \
|
||||
if (mo == atomic_memory_order_seq_cst) { \
|
||||
atomic_fence(atomic_memory_order_seq_cst); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \
|
||||
atomic_memory_order_t mo) { \
|
||||
return (type)ATOMIC_INTERLOCKED_NAME(_InterlockedExchange, \
|
||||
lg_size)(&a->repr, (ATOMIC_INTERLOCKED_REPR(lg_size))val); \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE bool \
|
||||
atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
|
||||
type *expected, type desired, atomic_memory_order_t success_mo, \
|
||||
atomic_memory_order_t failure_mo) { \
|
||||
ATOMIC_INTERLOCKED_REPR(lg_size) e = \
|
||||
(ATOMIC_INTERLOCKED_REPR(lg_size))*expected; \
|
||||
ATOMIC_INTERLOCKED_REPR(lg_size) d = \
|
||||
(ATOMIC_INTERLOCKED_REPR(lg_size))desired; \
|
||||
ATOMIC_INTERLOCKED_REPR(lg_size) old = \
|
||||
ATOMIC_INTERLOCKED_NAME(_InterlockedCompareExchange, \
|
||||
lg_size)(&a->repr, d, e); \
|
||||
if (old == e) { \
|
||||
return true; \
|
||||
} else { \
|
||||
*expected = (type)old; \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE bool \
|
||||
atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \
|
||||
type *expected, type desired, atomic_memory_order_t success_mo, \
|
||||
atomic_memory_order_t failure_mo) { \
|
||||
/* We implement the weak version with strong semantics. */ \
|
||||
return atomic_compare_exchange_weak_##short_type(a, expected, \
|
||||
desired, success_mo, failure_mo); \
|
||||
}
|
||||
|
||||
|
||||
#define JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, lg_size) \
|
||||
JEMALLOC_GENERATE_ATOMICS(type, short_type, lg_size) \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_add_##short_type(atomic_##short_type##_t *a, \
|
||||
type val, atomic_memory_order_t mo) { \
|
||||
return (type)ATOMIC_INTERLOCKED_NAME(_InterlockedExchangeAdd, \
|
||||
lg_size)(&a->repr, (ATOMIC_INTERLOCKED_REPR(lg_size))val); \
|
||||
} \
|
||||
\
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_sub_##short_type(atomic_##short_type##_t *a, \
|
||||
type val, atomic_memory_order_t mo) { \
|
||||
/* \
|
||||
* MSVC warns on negation of unsigned operands, but for us it \
|
||||
* gives exactly the right semantics (MAX_TYPE + 1 - operand). \
|
||||
*/ \
|
||||
__pragma(warning(push)) \
|
||||
__pragma(warning(disable: 4146)) \
|
||||
return atomic_fetch_add_##short_type(a, -val, mo); \
|
||||
__pragma(warning(pop)) \
|
||||
} \
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_and_##short_type(atomic_##short_type##_t *a, \
|
||||
type val, atomic_memory_order_t mo) { \
|
||||
return (type)ATOMIC_INTERLOCKED_NAME(_InterlockedAnd, lg_size)( \
|
||||
&a->repr, (ATOMIC_INTERLOCKED_REPR(lg_size))val); \
|
||||
} \
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_or_##short_type(atomic_##short_type##_t *a, \
|
||||
type val, atomic_memory_order_t mo) { \
|
||||
return (type)ATOMIC_INTERLOCKED_NAME(_InterlockedOr, lg_size)( \
|
||||
&a->repr, (ATOMIC_INTERLOCKED_REPR(lg_size))val); \
|
||||
} \
|
||||
ATOMIC_INLINE type \
|
||||
atomic_fetch_xor_##short_type(atomic_##short_type##_t *a, \
|
||||
type val, atomic_memory_order_t mo) { \
|
||||
return (type)ATOMIC_INTERLOCKED_NAME(_InterlockedXor, lg_size)( \
|
||||
&a->repr, (ATOMIC_INTERLOCKED_REPR(lg_size))val); \
|
||||
}
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_ATOMIC_MSVC_H */
|
33
deps/jemalloc/include/jemalloc/internal/background_thread_externs.h
vendored
Normal file
33
deps/jemalloc/include/jemalloc/internal/background_thread_externs.h
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef JEMALLOC_INTERNAL_BACKGROUND_THREAD_EXTERNS_H
|
||||
#define JEMALLOC_INTERNAL_BACKGROUND_THREAD_EXTERNS_H
|
||||
|
||||
extern bool opt_background_thread;
|
||||
extern size_t opt_max_background_threads;
|
||||
extern malloc_mutex_t background_thread_lock;
|
||||
extern atomic_b_t background_thread_enabled_state;
|
||||
extern size_t n_background_threads;
|
||||
extern size_t max_background_threads;
|
||||
extern background_thread_info_t *background_thread_info;
|
||||
extern bool can_enable_background_thread;
|
||||
|
||||
bool background_thread_create(tsd_t *tsd, unsigned arena_ind);
|
||||
bool background_threads_enable(tsd_t *tsd);
|
||||
bool background_threads_disable(tsd_t *tsd);
|
||||
void background_thread_interval_check(tsdn_t *tsdn, arena_t *arena,
|
||||
arena_decay_t *decay, size_t npages_new);
|
||||
void background_thread_prefork0(tsdn_t *tsdn);
|
||||
void background_thread_prefork1(tsdn_t *tsdn);
|
||||
void background_thread_postfork_parent(tsdn_t *tsdn);
|
||||
void background_thread_postfork_child(tsdn_t *tsdn);
|
||||
bool background_thread_stats_read(tsdn_t *tsdn,
|
||||
background_thread_stats_t *stats);
|
||||
void background_thread_ctl_init(tsdn_t *tsdn);
|
||||
|
||||
#ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER
|
||||
extern int pthread_create_wrapper(pthread_t *__restrict, const pthread_attr_t *,
|
||||
void *(*)(void *), void *__restrict);
|
||||
#endif
|
||||
bool background_thread_boot0(void);
|
||||
bool background_thread_boot1(tsdn_t *tsdn);
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_BACKGROUND_THREAD_EXTERNS_H */
|
57
deps/jemalloc/include/jemalloc/internal/background_thread_inlines.h
vendored
Normal file
57
deps/jemalloc/include/jemalloc/internal/background_thread_inlines.h
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef JEMALLOC_INTERNAL_BACKGROUND_THREAD_INLINES_H
|
||||
#define JEMALLOC_INTERNAL_BACKGROUND_THREAD_INLINES_H
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE bool
|
||||
background_thread_enabled(void) {
|
||||
return atomic_load_b(&background_thread_enabled_state, ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
background_thread_enabled_set(tsdn_t *tsdn, bool state) {
|
||||
malloc_mutex_assert_owner(tsdn, &background_thread_lock);
|
||||
atomic_store_b(&background_thread_enabled_state, state, ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE background_thread_info_t *
|
||||
arena_background_thread_info_get(arena_t *arena) {
|
||||
unsigned arena_ind = arena_ind_get(arena);
|
||||
return &background_thread_info[arena_ind % ncpus];
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE uint64_t
|
||||
background_thread_wakeup_time_get(background_thread_info_t *info) {
|
||||
uint64_t next_wakeup = nstime_ns(&info->next_wakeup);
|
||||
assert(atomic_load_b(&info->indefinite_sleep, ATOMIC_ACQUIRE) ==
|
||||
(next_wakeup == BACKGROUND_THREAD_INDEFINITE_SLEEP));
|
||||
return next_wakeup;
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
background_thread_wakeup_time_set(tsdn_t *tsdn, background_thread_info_t *info,
|
||||
uint64_t wakeup_time) {
|
||||
malloc_mutex_assert_owner(tsdn, &info->mtx);
|
||||
atomic_store_b(&info->indefinite_sleep,
|
||||
wakeup_time == BACKGROUND_THREAD_INDEFINITE_SLEEP, ATOMIC_RELEASE);
|
||||
nstime_init(&info->next_wakeup, wakeup_time);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE bool
|
||||
background_thread_indefinite_sleep(background_thread_info_t *info) {
|
||||
return atomic_load_b(&info->indefinite_sleep, ATOMIC_ACQUIRE);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
arena_background_thread_inactivity_check(tsdn_t *tsdn, arena_t *arena,
|
||||
bool is_background_thread) {
|
||||
if (!background_thread_enabled() || is_background_thread) {
|
||||
return;
|
||||
}
|
||||
background_thread_info_t *info =
|
||||
arena_background_thread_info_get(arena);
|
||||
if (background_thread_indefinite_sleep(info)) {
|
||||
background_thread_interval_check(tsdn, arena,
|
||||
&arena->decay_dirty, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_BACKGROUND_THREAD_INLINES_H */
|
53
deps/jemalloc/include/jemalloc/internal/background_thread_structs.h
vendored
Normal file
53
deps/jemalloc/include/jemalloc/internal/background_thread_structs.h
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef JEMALLOC_INTERNAL_BACKGROUND_THREAD_STRUCTS_H
|
||||
#define JEMALLOC_INTERNAL_BACKGROUND_THREAD_STRUCTS_H
|
||||
|
||||
/* This file really combines "structs" and "types", but only transitionally. */
|
||||
|
||||
#if defined(JEMALLOC_BACKGROUND_THREAD) || defined(JEMALLOC_LAZY_LOCK)
|
||||
# define JEMALLOC_PTHREAD_CREATE_WRAPPER
|
||||
#endif
|
||||
|
||||
#define BACKGROUND_THREAD_INDEFINITE_SLEEP UINT64_MAX
|
||||
#define MAX_BACKGROUND_THREAD_LIMIT MALLOCX_ARENA_LIMIT
|
||||
|
||||
typedef enum {
|
||||
background_thread_stopped,
|
||||
background_thread_started,
|
||||
/* Thread waits on the global lock when paused (for arena_reset). */
|
||||
background_thread_paused,
|
||||
} background_thread_state_t;
|
||||
|
||||
struct background_thread_info_s {
|
||||
#ifdef JEMALLOC_BACKGROUND_THREAD
|
||||
/* Background thread is pthread specific. */
|
||||
pthread_t thread;
|
||||
pthread_cond_t cond;
|
||||
#endif
|
||||
malloc_mutex_t mtx;
|
||||
background_thread_state_t state;
|
||||
/* When true, it means no wakeup scheduled. */
|
||||
atomic_b_t indefinite_sleep;
|
||||
/* Next scheduled wakeup time (absolute time in ns). */
|
||||
nstime_t next_wakeup;
|
||||
/*
|
||||
* Since the last background thread run, newly added number of pages
|
||||
* that need to be purged by the next wakeup. This is adjusted on
|
||||
* epoch advance, and is used to determine whether we should signal the
|
||||
* background thread to wake up earlier.
|
||||
*/
|
||||
size_t npages_to_purge_new;
|
||||
/* Stats: total number of runs since started. */
|
||||
uint64_t tot_n_runs;
|
||||
/* Stats: total sleep time since started. */
|
||||
nstime_t tot_sleep_time;
|
||||
};
|
||||
typedef struct background_thread_info_s background_thread_info_t;
|
||||
|
||||
struct background_thread_stats_s {
|
||||
size_t num_threads;
|
||||
uint64_t num_runs;
|
||||
nstime_t run_interval;
|
||||
};
|
||||
typedef struct background_thread_stats_s background_thread_stats_t;
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_BACKGROUND_THREAD_STRUCTS_H */
|
24
deps/jemalloc/include/jemalloc/internal/base.h
vendored
24
deps/jemalloc/include/jemalloc/internal/base.h
vendored
@ -1,24 +0,0 @@
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_TYPES
|
||||
|
||||
#endif /* JEMALLOC_H_TYPES */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_STRUCTS
|
||||
|
||||
#endif /* JEMALLOC_H_STRUCTS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_EXTERNS
|
||||
|
||||
void *base_alloc(size_t size);
|
||||
void base_stats_get(size_t *allocated, size_t *resident, size_t *mapped);
|
||||
bool base_boot(void);
|
||||
void base_prefork(void);
|
||||
void base_postfork_parent(void);
|
||||
void base_postfork_child(void);
|
||||
|
||||
#endif /* JEMALLOC_H_EXTERNS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_INLINES
|
||||
|
||||
#endif /* JEMALLOC_H_INLINES */
|
||||
/******************************************************************************/
|
22
deps/jemalloc/include/jemalloc/internal/base_externs.h
vendored
Normal file
22
deps/jemalloc/include/jemalloc/internal/base_externs.h
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef JEMALLOC_INTERNAL_BASE_EXTERNS_H
|
||||
#define JEMALLOC_INTERNAL_BASE_EXTERNS_H
|
||||
|
||||
extern metadata_thp_mode_t opt_metadata_thp;
|
||||
extern const char *metadata_thp_mode_names[];
|
||||
|
||||
base_t *b0get(void);
|
||||
base_t *base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks);
|
||||
void base_delete(tsdn_t *tsdn, base_t *base);
|
||||
extent_hooks_t *base_extent_hooks_get(base_t *base);
|
||||
extent_hooks_t *base_extent_hooks_set(base_t *base,
|
||||
extent_hooks_t *extent_hooks);
|
||||
void *base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment);
|
||||
extent_t *base_alloc_extent(tsdn_t *tsdn, base_t *base);
|
||||
void base_stats_get(tsdn_t *tsdn, base_t *base, size_t *allocated,
|
||||
size_t *resident, size_t *mapped, size_t *n_thp);
|
||||
void base_prefork(tsdn_t *tsdn, base_t *base);
|
||||
void base_postfork_parent(tsdn_t *tsdn, base_t *base);
|
||||
void base_postfork_child(tsdn_t *tsdn, base_t *base);
|
||||
bool base_boot(tsdn_t *tsdn);
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_BASE_EXTERNS_H */
|
13
deps/jemalloc/include/jemalloc/internal/base_inlines.h
vendored
Normal file
13
deps/jemalloc/include/jemalloc/internal/base_inlines.h
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef JEMALLOC_INTERNAL_BASE_INLINES_H
|
||||
#define JEMALLOC_INTERNAL_BASE_INLINES_H
|
||||
|
||||
static inline unsigned
|
||||
base_ind_get(const base_t *base) {
|
||||
return base->ind;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
metadata_thp_enabled(void) {
|
||||
return (opt_metadata_thp != metadata_thp_disabled);
|
||||
}
|
||||
#endif /* JEMALLOC_INTERNAL_BASE_INLINES_H */
|
59
deps/jemalloc/include/jemalloc/internal/base_structs.h
vendored
Normal file
59
deps/jemalloc/include/jemalloc/internal/base_structs.h
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
#ifndef JEMALLOC_INTERNAL_BASE_STRUCTS_H
|
||||
#define JEMALLOC_INTERNAL_BASE_STRUCTS_H
|
||||
|
||||
#include "jemalloc/internal/jemalloc_internal_types.h"
|
||||
#include "jemalloc/internal/mutex.h"
|
||||
#include "jemalloc/internal/size_classes.h"
|
||||
|
||||
/* Embedded at the beginning of every block of base-managed virtual memory. */
|
||||
struct base_block_s {
|
||||
/* Total size of block's virtual memory mapping. */
|
||||
size_t size;
|
||||
|
||||
/* Next block in list of base's blocks. */
|
||||
base_block_t *next;
|
||||
|
||||
/* Tracks unused trailing space. */
|
||||
extent_t extent;
|
||||
};
|
||||
|
||||
struct base_s {
|
||||
/* Associated arena's index within the arenas array. */
|
||||
unsigned ind;
|
||||
|
||||
/*
|
||||
* User-configurable extent hook functions. Points to an
|
||||
* extent_hooks_t.
|
||||
*/
|
||||
atomic_p_t extent_hooks;
|
||||
|
||||
/* Protects base_alloc() and base_stats_get() operations. */
|
||||
malloc_mutex_t mtx;
|
||||
|
||||
/* Using THP when true (metadata_thp auto mode). */
|
||||
bool auto_thp_switched;
|
||||
/*
|
||||
* Most recent size class in the series of increasingly large base
|
||||
* extents. Logarithmic spacing between subsequent allocations ensures
|
||||
* that the total number of distinct mappings remains small.
|
||||
*/
|
||||
pszind_t pind_last;
|
||||
|
||||
/* Serial number generation state. */
|
||||
size_t extent_sn_next;
|
||||
|
||||
/* Chain of all blocks associated with base. */
|
||||
base_block_t *blocks;
|
||||
|
||||
/* Heap of extents that track unused trailing space within blocks. */
|
||||
extent_heap_t avail[NSIZES];
|
||||
|
||||
/* Stats, only maintained if config_stats. */
|
||||
size_t allocated;
|
||||
size_t resident;
|
||||
size_t mapped;
|
||||
/* Number of THP regions touched. */
|
||||
size_t n_thp;
|
||||
};
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_BASE_STRUCTS_H */
|
33
deps/jemalloc/include/jemalloc/internal/base_types.h
vendored
Normal file
33
deps/jemalloc/include/jemalloc/internal/base_types.h
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef JEMALLOC_INTERNAL_BASE_TYPES_H
|
||||
#define JEMALLOC_INTERNAL_BASE_TYPES_H
|
||||
|
||||
typedef struct base_block_s base_block_t;
|
||||
typedef struct base_s base_t;
|
||||
|
||||
#define METADATA_THP_DEFAULT metadata_thp_disabled
|
||||
|
||||
/*
|
||||
* In auto mode, arenas switch to huge pages for the base allocator on the
|
||||
* second base block. a0 switches to thp on the 5th block (after 20 megabytes
|
||||
* of metadata), since more metadata (e.g. rtree nodes) come from a0's base.
|
||||
*/
|
||||
|
||||
#define BASE_AUTO_THP_THRESHOLD 2
|
||||
#define BASE_AUTO_THP_THRESHOLD_A0 5
|
||||
|
||||
typedef enum {
|
||||
metadata_thp_disabled = 0,
|
||||
/*
|
||||
* Lazily enable hugepage for metadata. To avoid high RSS caused by THP
|
||||
* + low usage arena (i.e. THP becomes a significant percentage), the
|
||||
* "auto" option only starts using THP after a base allocator used up
|
||||
* the first THP region. Starting from the second hugepage (in a single
|
||||
* arena), "auto" behaves the same as "always", i.e. madvise hugepage
|
||||
* right away.
|
||||
*/
|
||||
metadata_thp_auto = 1,
|
||||
metadata_thp_always = 2,
|
||||
metadata_thp_mode_limit = 3
|
||||
} metadata_thp_mode_t;
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_BASE_TYPES_H */
|
106
deps/jemalloc/include/jemalloc/internal/bin.h
vendored
Normal file
106
deps/jemalloc/include/jemalloc/internal/bin.h
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
#ifndef JEMALLOC_INTERNAL_BIN_H
|
||||
#define JEMALLOC_INTERNAL_BIN_H
|
||||
|
||||
#include "jemalloc/internal/extent_types.h"
|
||||
#include "jemalloc/internal/extent_structs.h"
|
||||
#include "jemalloc/internal/mutex.h"
|
||||
#include "jemalloc/internal/bin_stats.h"
|
||||
|
||||
/*
|
||||
* A bin contains a set of extents that are currently being used for slab
|
||||
* allocations.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Read-only information associated with each element of arena_t's bins array
|
||||
* is stored separately, partly to reduce memory usage (only one copy, rather
|
||||
* than one per arena), but mainly to avoid false cacheline sharing.
|
||||
*
|
||||
* Each slab has the following layout:
|
||||
*
|
||||
* /--------------------\
|
||||
* | region 0 |
|
||||
* |--------------------|
|
||||
* | region 1 |
|
||||
* |--------------------|
|
||||
* | ... |
|
||||
* | ... |
|
||||
* | ... |
|
||||
* |--------------------|
|
||||
* | region nregs-1 |
|
||||
* \--------------------/
|
||||
*/
|
||||
typedef struct bin_info_s bin_info_t;
|
||||
struct bin_info_s {
|
||||
/* Size of regions in a slab for this bin's size class. */
|
||||
size_t reg_size;
|
||||
|
||||
/* Total size of a slab for this bin's size class. */
|
||||
size_t slab_size;
|
||||
|
||||
/* Total number of regions in a slab for this bin's size class. */
|
||||
uint32_t nregs;
|
||||
|
||||
/*
|
||||
* Metadata used to manipulate bitmaps for slabs associated with this
|
||||
* bin.
|
||||
*/
|
||||
bitmap_info_t bitmap_info;
|
||||
};
|
||||
|
||||
extern const bin_info_t bin_infos[NBINS];
|
||||
|
||||
|
||||
typedef struct bin_s bin_t;
|
||||
struct bin_s {
|
||||
/* All operations on bin_t fields require lock ownership. */
|
||||
malloc_mutex_t lock;
|
||||
|
||||
/*
|
||||
* Current slab being used to service allocations of this bin's size
|
||||
* class. slabcur is independent of slabs_{nonfull,full}; whenever
|
||||
* slabcur is reassigned, the previous slab must be deallocated or
|
||||
* inserted into slabs_{nonfull,full}.
|
||||
*/
|
||||
extent_t *slabcur;
|
||||
|
||||
/*
|
||||
* Heap of non-full slabs. This heap is used to assure that new
|
||||
* allocations come from the non-full slab that is oldest/lowest in
|
||||
* memory.
|
||||
*/
|
||||
extent_heap_t slabs_nonfull;
|
||||
|
||||
/* List used to track full slabs. */
|
||||
extent_list_t slabs_full;
|
||||
|
||||
/* Bin statistics. */
|
||||
bin_stats_t stats;
|
||||
};
|
||||
|
||||
/* Initializes a bin to empty. Returns true on error. */
|
||||
bool bin_init(bin_t *bin);
|
||||
|
||||
/* Forking. */
|
||||
void bin_prefork(tsdn_t *tsdn, bin_t *bin);
|
||||
void bin_postfork_parent(tsdn_t *tsdn, bin_t *bin);
|
||||
void bin_postfork_child(tsdn_t *tsdn, bin_t *bin);
|
||||
|
||||
/* Stats. */
|
||||
static inline void
|
||||
bin_stats_merge(tsdn_t *tsdn, bin_stats_t *dst_bin_stats, bin_t *bin) {
|
||||
malloc_mutex_lock(tsdn, &bin->lock);
|
||||
malloc_mutex_prof_read(tsdn, &dst_bin_stats->mutex_data, &bin->lock);
|
||||
dst_bin_stats->nmalloc += bin->stats.nmalloc;
|
||||
dst_bin_stats->ndalloc += bin->stats.ndalloc;
|
||||
dst_bin_stats->nrequests += bin->stats.nrequests;
|
||||
dst_bin_stats->curregs += bin->stats.curregs;
|
||||
dst_bin_stats->nfills += bin->stats.nfills;
|
||||
dst_bin_stats->nflushes += bin->stats.nflushes;
|
||||
dst_bin_stats->nslabs += bin->stats.nslabs;
|
||||
dst_bin_stats->reslabs += bin->stats.reslabs;
|
||||
dst_bin_stats->curslabs += bin->stats.curslabs;
|
||||
malloc_mutex_unlock(tsdn, &bin->lock);
|
||||
}
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_BIN_H */
|
51
deps/jemalloc/include/jemalloc/internal/bin_stats.h
vendored
Normal file
51
deps/jemalloc/include/jemalloc/internal/bin_stats.h
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
#ifndef JEMALLOC_INTERNAL_BIN_STATS_H
|
||||
#define JEMALLOC_INTERNAL_BIN_STATS_H
|
||||
|
||||
#include "jemalloc/internal/mutex_prof.h"
|
||||
|
||||
typedef struct bin_stats_s bin_stats_t;
|
||||
struct bin_stats_s {
|
||||
/*
|
||||
* Total number of allocation/deallocation requests served directly by
|
||||
* the bin. Note that tcache may allocate an object, then recycle it
|
||||
* many times, resulting many increments to nrequests, but only one
|
||||
* each to nmalloc and ndalloc.
|
||||
*/
|
||||
uint64_t nmalloc;
|
||||
uint64_t ndalloc;
|
||||
|
||||
/*
|
||||
* Number of allocation requests that correspond to the size of this
|
||||
* bin. This includes requests served by tcache, though tcache only
|
||||
* periodically merges into this counter.
|
||||
*/
|
||||
uint64_t nrequests;
|
||||
|
||||
/*
|
||||
* Current number of regions of this size class, including regions
|
||||
* currently cached by tcache.
|
||||
*/
|
||||
size_t curregs;
|
||||
|
||||
/* Number of tcache fills from this bin. */
|
||||
uint64_t nfills;
|
||||
|
||||
/* Number of tcache flushes to this bin. */
|
||||
uint64_t nflushes;
|
||||
|
||||
/* Total number of slabs created for this bin's size class. */
|
||||
uint64_t nslabs;
|
||||
|
||||
/*
|
||||
* Total number of slabs reused by extracting them from the slabs heap
|
||||
* for this bin's size class.
|
||||
*/
|
||||
uint64_t reslabs;
|
||||
|
||||
/* Current number of slabs in this bin. */
|
||||
size_t curslabs;
|
||||
|
||||
mutex_prof_data_t mutex_data;
|
||||
};
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_BIN_STATS_H */
|
165
deps/jemalloc/include/jemalloc/internal/bit_util.h
vendored
Normal file
165
deps/jemalloc/include/jemalloc/internal/bit_util.h
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
#ifndef JEMALLOC_INTERNAL_BIT_UTIL_H
|
||||
#define JEMALLOC_INTERNAL_BIT_UTIL_H
|
||||
|
||||
#include "jemalloc/internal/assert.h"
|
||||
|
||||
#define BIT_UTIL_INLINE static inline
|
||||
|
||||
/* Sanity check. */
|
||||
#if !defined(JEMALLOC_INTERNAL_FFSLL) || !defined(JEMALLOC_INTERNAL_FFSL) \
|
||||
|| !defined(JEMALLOC_INTERNAL_FFS)
|
||||
# error JEMALLOC_INTERNAL_FFS{,L,LL} should have been defined by configure
|
||||
#endif
|
||||
|
||||
|
||||
BIT_UTIL_INLINE unsigned
|
||||
ffs_llu(unsigned long long bitmap) {
|
||||
return JEMALLOC_INTERNAL_FFSLL(bitmap);
|
||||
}
|
||||
|
||||
BIT_UTIL_INLINE unsigned
|
||||
ffs_lu(unsigned long bitmap) {
|
||||
return JEMALLOC_INTERNAL_FFSL(bitmap);
|
||||
}
|
||||
|
||||
BIT_UTIL_INLINE unsigned
|
||||
ffs_u(unsigned bitmap) {
|
||||
return JEMALLOC_INTERNAL_FFS(bitmap);
|
||||
}
|
||||
|
||||
BIT_UTIL_INLINE unsigned
|
||||
ffs_zu(size_t bitmap) {
|
||||
#if LG_SIZEOF_PTR == LG_SIZEOF_INT
|
||||
return ffs_u(bitmap);
|
||||
#elif LG_SIZEOF_PTR == LG_SIZEOF_LONG
|
||||
return ffs_lu(bitmap);
|
||||
#elif LG_SIZEOF_PTR == LG_SIZEOF_LONG_LONG
|
||||
return ffs_llu(bitmap);
|
||||
#else
|
||||
#error No implementation for size_t ffs()
|
||||
#endif
|
||||
}
|
||||
|
||||
BIT_UTIL_INLINE unsigned
|
||||
ffs_u64(uint64_t bitmap) {
|
||||
#if LG_SIZEOF_LONG == 3
|
||||
return ffs_lu(bitmap);
|
||||
#elif LG_SIZEOF_LONG_LONG == 3
|
||||
return ffs_llu(bitmap);
|
||||
#else
|
||||
#error No implementation for 64-bit ffs()
|
||||
#endif
|
||||
}
|
||||
|
||||
BIT_UTIL_INLINE unsigned
|
||||
ffs_u32(uint32_t bitmap) {
|
||||
#if LG_SIZEOF_INT == 2
|
||||
return ffs_u(bitmap);
|
||||
#else
|
||||
#error No implementation for 32-bit ffs()
|
||||
#endif
|
||||
return ffs_u(bitmap);
|
||||
}
|
||||
|
||||
BIT_UTIL_INLINE uint64_t
|
||||
pow2_ceil_u64(uint64_t x) {
|
||||
x--;
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
x |= x >> 32;
|
||||
x++;
|
||||
return x;
|
||||
}
|
||||
|
||||
BIT_UTIL_INLINE uint32_t
|
||||
pow2_ceil_u32(uint32_t x) {
|
||||
x--;
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
x++;
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Compute the smallest power of 2 that is >= x. */
|
||||
BIT_UTIL_INLINE size_t
|
||||
pow2_ceil_zu(size_t x) {
|
||||
#if (LG_SIZEOF_PTR == 3)
|
||||
return pow2_ceil_u64(x);
|
||||
#else
|
||||
return pow2_ceil_u32(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (defined(__i386__) || defined(__amd64__) || defined(__x86_64__))
|
||||
BIT_UTIL_INLINE unsigned
|
||||
lg_floor(size_t x) {
|
||||
size_t ret;
|
||||
assert(x != 0);
|
||||
|
||||
asm ("bsr %1, %0"
|
||||
: "=r"(ret) // Outputs.
|
||||
: "r"(x) // Inputs.
|
||||
);
|
||||
assert(ret < UINT_MAX);
|
||||
return (unsigned)ret;
|
||||
}
|
||||
#elif (defined(_MSC_VER))
|
||||
BIT_UTIL_INLINE unsigned
|
||||
lg_floor(size_t x) {
|
||||
unsigned long ret;
|
||||
|
||||
assert(x != 0);
|
||||
|
||||
#if (LG_SIZEOF_PTR == 3)
|
||||
_BitScanReverse64(&ret, x);
|
||||
#elif (LG_SIZEOF_PTR == 2)
|
||||
_BitScanReverse(&ret, x);
|
||||
#else
|
||||
# error "Unsupported type size for lg_floor()"
|
||||
#endif
|
||||
assert(ret < UINT_MAX);
|
||||
return (unsigned)ret;
|
||||
}
|
||||
#elif (defined(JEMALLOC_HAVE_BUILTIN_CLZ))
|
||||
BIT_UTIL_INLINE unsigned
|
||||
lg_floor(size_t x) {
|
||||
assert(x != 0);
|
||||
|
||||
#if (LG_SIZEOF_PTR == LG_SIZEOF_INT)
|
||||
return ((8 << LG_SIZEOF_PTR) - 1) - __builtin_clz(x);
|
||||
#elif (LG_SIZEOF_PTR == LG_SIZEOF_LONG)
|
||||
return ((8 << LG_SIZEOF_PTR) - 1) - __builtin_clzl(x);
|
||||
#else
|
||||
# error "Unsupported type size for lg_floor()"
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
BIT_UTIL_INLINE unsigned
|
||||
lg_floor(size_t x) {
|
||||
assert(x != 0);
|
||||
|
||||
x |= (x >> 1);
|
||||
x |= (x >> 2);
|
||||
x |= (x >> 4);
|
||||
x |= (x >> 8);
|
||||
x |= (x >> 16);
|
||||
#if (LG_SIZEOF_PTR == 3)
|
||||
x |= (x >> 32);
|
||||
#endif
|
||||
if (x == SIZE_T_MAX) {
|
||||
return (8 << LG_SIZEOF_PTR) - 1;
|
||||
}
|
||||
x++;
|
||||
return ffs_zu(x) - 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef BIT_UTIL_INLINE
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_BIT_UTIL_H */
|
319
deps/jemalloc/include/jemalloc/internal/bitmap.h
vendored
319
deps/jemalloc/include/jemalloc/internal/bitmap.h
vendored
@ -1,83 +1,159 @@
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_TYPES
|
||||
#ifndef JEMALLOC_INTERNAL_BITMAP_H
|
||||
#define JEMALLOC_INTERNAL_BITMAP_H
|
||||
|
||||
#include "jemalloc/internal/arena_types.h"
|
||||
#include "jemalloc/internal/bit_util.h"
|
||||
#include "jemalloc/internal/size_classes.h"
|
||||
|
||||
typedef unsigned long bitmap_t;
|
||||
#define LG_SIZEOF_BITMAP LG_SIZEOF_LONG
|
||||
|
||||
/* Maximum bitmap bit count is 2^LG_BITMAP_MAXBITS. */
|
||||
#define LG_BITMAP_MAXBITS LG_RUN_MAXREGS
|
||||
#define BITMAP_MAXBITS (ZU(1) << LG_BITMAP_MAXBITS)
|
||||
|
||||
typedef struct bitmap_level_s bitmap_level_t;
|
||||
typedef struct bitmap_info_s bitmap_info_t;
|
||||
typedef unsigned long bitmap_t;
|
||||
#define LG_SIZEOF_BITMAP LG_SIZEOF_LONG
|
||||
#if LG_SLAB_MAXREGS > LG_CEIL_NSIZES
|
||||
/* Maximum bitmap bit count is determined by maximum regions per slab. */
|
||||
# define LG_BITMAP_MAXBITS LG_SLAB_MAXREGS
|
||||
#else
|
||||
/* Maximum bitmap bit count is determined by number of extent size classes. */
|
||||
# define LG_BITMAP_MAXBITS LG_CEIL_NSIZES
|
||||
#endif
|
||||
#define BITMAP_MAXBITS (ZU(1) << LG_BITMAP_MAXBITS)
|
||||
|
||||
/* Number of bits per group. */
|
||||
#define LG_BITMAP_GROUP_NBITS (LG_SIZEOF_BITMAP + 3)
|
||||
#define BITMAP_GROUP_NBITS (ZU(1) << LG_BITMAP_GROUP_NBITS)
|
||||
#define BITMAP_GROUP_NBITS_MASK (BITMAP_GROUP_NBITS-1)
|
||||
#define LG_BITMAP_GROUP_NBITS (LG_SIZEOF_BITMAP + 3)
|
||||
#define BITMAP_GROUP_NBITS (1U << LG_BITMAP_GROUP_NBITS)
|
||||
#define BITMAP_GROUP_NBITS_MASK (BITMAP_GROUP_NBITS-1)
|
||||
|
||||
/*
|
||||
* Do some analysis on how big the bitmap is before we use a tree. For a brute
|
||||
* force linear search, if we would have to call ffs_lu() more than 2^3 times,
|
||||
* use a tree instead.
|
||||
*/
|
||||
#if LG_BITMAP_MAXBITS - LG_BITMAP_GROUP_NBITS > 3
|
||||
# define BITMAP_USE_TREE
|
||||
#endif
|
||||
|
||||
/* Number of groups required to store a given number of bits. */
|
||||
#define BITMAP_BITS2GROUPS(nbits) \
|
||||
((nbits + BITMAP_GROUP_NBITS_MASK) >> LG_BITMAP_GROUP_NBITS)
|
||||
#define BITMAP_BITS2GROUPS(nbits) \
|
||||
(((nbits) + BITMAP_GROUP_NBITS_MASK) >> LG_BITMAP_GROUP_NBITS)
|
||||
|
||||
/*
|
||||
* Number of groups required at a particular level for a given number of bits.
|
||||
*/
|
||||
#define BITMAP_GROUPS_L0(nbits) \
|
||||
#define BITMAP_GROUPS_L0(nbits) \
|
||||
BITMAP_BITS2GROUPS(nbits)
|
||||
#define BITMAP_GROUPS_L1(nbits) \
|
||||
#define BITMAP_GROUPS_L1(nbits) \
|
||||
BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(nbits))
|
||||
#define BITMAP_GROUPS_L2(nbits) \
|
||||
#define BITMAP_GROUPS_L2(nbits) \
|
||||
BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits))))
|
||||
#define BITMAP_GROUPS_L3(nbits) \
|
||||
#define BITMAP_GROUPS_L3(nbits) \
|
||||
BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \
|
||||
BITMAP_BITS2GROUPS((nbits)))))
|
||||
#define BITMAP_GROUPS_L4(nbits) \
|
||||
BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \
|
||||
BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits))))))
|
||||
|
||||
/*
|
||||
* Assuming the number of levels, number of groups required for a given number
|
||||
* of bits.
|
||||
*/
|
||||
#define BITMAP_GROUPS_1_LEVEL(nbits) \
|
||||
#define BITMAP_GROUPS_1_LEVEL(nbits) \
|
||||
BITMAP_GROUPS_L0(nbits)
|
||||
#define BITMAP_GROUPS_2_LEVEL(nbits) \
|
||||
#define BITMAP_GROUPS_2_LEVEL(nbits) \
|
||||
(BITMAP_GROUPS_1_LEVEL(nbits) + BITMAP_GROUPS_L1(nbits))
|
||||
#define BITMAP_GROUPS_3_LEVEL(nbits) \
|
||||
#define BITMAP_GROUPS_3_LEVEL(nbits) \
|
||||
(BITMAP_GROUPS_2_LEVEL(nbits) + BITMAP_GROUPS_L2(nbits))
|
||||
#define BITMAP_GROUPS_4_LEVEL(nbits) \
|
||||
#define BITMAP_GROUPS_4_LEVEL(nbits) \
|
||||
(BITMAP_GROUPS_3_LEVEL(nbits) + BITMAP_GROUPS_L3(nbits))
|
||||
#define BITMAP_GROUPS_5_LEVEL(nbits) \
|
||||
(BITMAP_GROUPS_4_LEVEL(nbits) + BITMAP_GROUPS_L4(nbits))
|
||||
|
||||
/*
|
||||
* Maximum number of groups required to support LG_BITMAP_MAXBITS.
|
||||
*/
|
||||
#ifdef BITMAP_USE_TREE
|
||||
|
||||
#if LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS
|
||||
# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_1_LEVEL(nbits)
|
||||
# define BITMAP_GROUPS_MAX BITMAP_GROUPS_1_LEVEL(BITMAP_MAXBITS)
|
||||
#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 2
|
||||
# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_2_LEVEL(nbits)
|
||||
# define BITMAP_GROUPS_MAX BITMAP_GROUPS_2_LEVEL(BITMAP_MAXBITS)
|
||||
#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 3
|
||||
# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_3_LEVEL(nbits)
|
||||
# define BITMAP_GROUPS_MAX BITMAP_GROUPS_3_LEVEL(BITMAP_MAXBITS)
|
||||
#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 4
|
||||
# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_4_LEVEL(nbits)
|
||||
# define BITMAP_GROUPS_MAX BITMAP_GROUPS_4_LEVEL(BITMAP_MAXBITS)
|
||||
#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 5
|
||||
# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_5_LEVEL(nbits)
|
||||
# define BITMAP_GROUPS_MAX BITMAP_GROUPS_5_LEVEL(BITMAP_MAXBITS)
|
||||
#else
|
||||
# error "Unsupported bitmap size"
|
||||
#endif
|
||||
|
||||
/* Maximum number of levels possible. */
|
||||
#define BITMAP_MAX_LEVELS \
|
||||
(LG_BITMAP_MAXBITS / LG_SIZEOF_BITMAP) \
|
||||
+ !!(LG_BITMAP_MAXBITS % LG_SIZEOF_BITMAP)
|
||||
/*
|
||||
* Maximum number of levels possible. This could be statically computed based
|
||||
* on LG_BITMAP_MAXBITS:
|
||||
*
|
||||
* #define BITMAP_MAX_LEVELS \
|
||||
* (LG_BITMAP_MAXBITS / LG_SIZEOF_BITMAP) \
|
||||
* + !!(LG_BITMAP_MAXBITS % LG_SIZEOF_BITMAP)
|
||||
*
|
||||
* However, that would not allow the generic BITMAP_INFO_INITIALIZER() macro, so
|
||||
* instead hardcode BITMAP_MAX_LEVELS to the largest number supported by the
|
||||
* various cascading macros. The only additional cost this incurs is some
|
||||
* unused trailing entries in bitmap_info_t structures; the bitmaps themselves
|
||||
* are not impacted.
|
||||
*/
|
||||
#define BITMAP_MAX_LEVELS 5
|
||||
|
||||
#endif /* JEMALLOC_H_TYPES */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_STRUCTS
|
||||
#define BITMAP_INFO_INITIALIZER(nbits) { \
|
||||
/* nbits. */ \
|
||||
nbits, \
|
||||
/* nlevels. */ \
|
||||
(BITMAP_GROUPS_L0(nbits) > BITMAP_GROUPS_L1(nbits)) + \
|
||||
(BITMAP_GROUPS_L1(nbits) > BITMAP_GROUPS_L2(nbits)) + \
|
||||
(BITMAP_GROUPS_L2(nbits) > BITMAP_GROUPS_L3(nbits)) + \
|
||||
(BITMAP_GROUPS_L3(nbits) > BITMAP_GROUPS_L4(nbits)) + 1, \
|
||||
/* levels. */ \
|
||||
{ \
|
||||
{0}, \
|
||||
{BITMAP_GROUPS_L0(nbits)}, \
|
||||
{BITMAP_GROUPS_L1(nbits) + BITMAP_GROUPS_L0(nbits)}, \
|
||||
{BITMAP_GROUPS_L2(nbits) + BITMAP_GROUPS_L1(nbits) + \
|
||||
BITMAP_GROUPS_L0(nbits)}, \
|
||||
{BITMAP_GROUPS_L3(nbits) + BITMAP_GROUPS_L2(nbits) + \
|
||||
BITMAP_GROUPS_L1(nbits) + BITMAP_GROUPS_L0(nbits)}, \
|
||||
{BITMAP_GROUPS_L4(nbits) + BITMAP_GROUPS_L3(nbits) + \
|
||||
BITMAP_GROUPS_L2(nbits) + BITMAP_GROUPS_L1(nbits) \
|
||||
+ BITMAP_GROUPS_L0(nbits)} \
|
||||
} \
|
||||
}
|
||||
|
||||
struct bitmap_level_s {
|
||||
#else /* BITMAP_USE_TREE */
|
||||
|
||||
#define BITMAP_GROUPS(nbits) BITMAP_BITS2GROUPS(nbits)
|
||||
#define BITMAP_GROUPS_MAX BITMAP_BITS2GROUPS(BITMAP_MAXBITS)
|
||||
|
||||
#define BITMAP_INFO_INITIALIZER(nbits) { \
|
||||
/* nbits. */ \
|
||||
nbits, \
|
||||
/* ngroups. */ \
|
||||
BITMAP_BITS2GROUPS(nbits) \
|
||||
}
|
||||
|
||||
#endif /* BITMAP_USE_TREE */
|
||||
|
||||
typedef struct bitmap_level_s {
|
||||
/* Offset of this level's groups within the array of groups. */
|
||||
size_t group_offset;
|
||||
};
|
||||
} bitmap_level_t;
|
||||
|
||||
struct bitmap_info_s {
|
||||
typedef struct bitmap_info_s {
|
||||
/* Logical number of bits in bitmap (stored at bottom level). */
|
||||
size_t nbits;
|
||||
|
||||
#ifdef BITMAP_USE_TREE
|
||||
/* Number of levels necessary for nbits. */
|
||||
unsigned nlevels;
|
||||
|
||||
@ -86,54 +162,48 @@ struct bitmap_info_s {
|
||||
* bottom to top (e.g. the bottom level is stored in levels[0]).
|
||||
*/
|
||||
bitmap_level_t levels[BITMAP_MAX_LEVELS+1];
|
||||
};
|
||||
#else /* BITMAP_USE_TREE */
|
||||
/* Number of groups necessary for nbits. */
|
||||
size_t ngroups;
|
||||
#endif /* BITMAP_USE_TREE */
|
||||
} bitmap_info_t;
|
||||
|
||||
#endif /* JEMALLOC_H_STRUCTS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_EXTERNS
|
||||
void bitmap_info_init(bitmap_info_t *binfo, size_t nbits);
|
||||
void bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo, bool fill);
|
||||
size_t bitmap_size(const bitmap_info_t *binfo);
|
||||
|
||||
void bitmap_info_init(bitmap_info_t *binfo, size_t nbits);
|
||||
size_t bitmap_info_ngroups(const bitmap_info_t *binfo);
|
||||
size_t bitmap_size(size_t nbits);
|
||||
void bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo);
|
||||
|
||||
#endif /* JEMALLOC_H_EXTERNS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_INLINES
|
||||
|
||||
#ifndef JEMALLOC_ENABLE_INLINE
|
||||
bool bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo);
|
||||
bool bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit);
|
||||
void bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit);
|
||||
size_t bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo);
|
||||
void bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit);
|
||||
#endif
|
||||
|
||||
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_BITMAP_C_))
|
||||
JEMALLOC_INLINE bool
|
||||
bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo)
|
||||
{
|
||||
unsigned rgoff = binfo->levels[binfo->nlevels].group_offset - 1;
|
||||
static inline bool
|
||||
bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo) {
|
||||
#ifdef BITMAP_USE_TREE
|
||||
size_t rgoff = binfo->levels[binfo->nlevels].group_offset - 1;
|
||||
bitmap_t rg = bitmap[rgoff];
|
||||
/* The bitmap is full iff the root group is 0. */
|
||||
return (rg == 0);
|
||||
#else
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < binfo->ngroups; i++) {
|
||||
if (bitmap[i] != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit)
|
||||
{
|
||||
static inline bool
|
||||
bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) {
|
||||
size_t goff;
|
||||
bitmap_t g;
|
||||
|
||||
assert(bit < binfo->nbits);
|
||||
goff = bit >> LG_BITMAP_GROUP_NBITS;
|
||||
g = bitmap[goff];
|
||||
return (!(g & (1LU << (bit & BITMAP_GROUP_NBITS_MASK))));
|
||||
return !(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK)));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit)
|
||||
{
|
||||
static inline void
|
||||
bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) {
|
||||
size_t goff;
|
||||
bitmap_t *gp;
|
||||
bitmap_t g;
|
||||
@ -143,10 +213,11 @@ bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit)
|
||||
goff = bit >> LG_BITMAP_GROUP_NBITS;
|
||||
gp = &bitmap[goff];
|
||||
g = *gp;
|
||||
assert(g & (1LU << (bit & BITMAP_GROUP_NBITS_MASK)));
|
||||
g ^= 1LU << (bit & BITMAP_GROUP_NBITS_MASK);
|
||||
assert(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK)));
|
||||
g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK);
|
||||
*gp = g;
|
||||
assert(bitmap_get(bitmap, binfo, bit));
|
||||
#ifdef BITMAP_USE_TREE
|
||||
/* Propagate group state transitions up the tree. */
|
||||
if (g == 0) {
|
||||
unsigned i;
|
||||
@ -155,45 +226,113 @@ bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit)
|
||||
goff = bit >> LG_BITMAP_GROUP_NBITS;
|
||||
gp = &bitmap[binfo->levels[i].group_offset + goff];
|
||||
g = *gp;
|
||||
assert(g & (1LU << (bit & BITMAP_GROUP_NBITS_MASK)));
|
||||
g ^= 1LU << (bit & BITMAP_GROUP_NBITS_MASK);
|
||||
assert(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK)));
|
||||
g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK);
|
||||
*gp = g;
|
||||
if (g != 0)
|
||||
if (g != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ffu: find first unset >= bit. */
|
||||
static inline size_t
|
||||
bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, size_t min_bit) {
|
||||
assert(min_bit < binfo->nbits);
|
||||
|
||||
#ifdef BITMAP_USE_TREE
|
||||
size_t bit = 0;
|
||||
for (unsigned level = binfo->nlevels; level--;) {
|
||||
size_t lg_bits_per_group = (LG_BITMAP_GROUP_NBITS * (level +
|
||||
1));
|
||||
bitmap_t group = bitmap[binfo->levels[level].group_offset + (bit
|
||||
>> lg_bits_per_group)];
|
||||
unsigned group_nmask = (unsigned)(((min_bit > bit) ? (min_bit -
|
||||
bit) : 0) >> (lg_bits_per_group - LG_BITMAP_GROUP_NBITS));
|
||||
assert(group_nmask <= BITMAP_GROUP_NBITS);
|
||||
bitmap_t group_mask = ~((1LU << group_nmask) - 1);
|
||||
bitmap_t group_masked = group & group_mask;
|
||||
if (group_masked == 0LU) {
|
||||
if (group == 0LU) {
|
||||
return binfo->nbits;
|
||||
}
|
||||
/*
|
||||
* min_bit was preceded by one or more unset bits in
|
||||
* this group, but there are no other unset bits in this
|
||||
* group. Try again starting at the first bit of the
|
||||
* next sibling. This will recurse at most once per
|
||||
* non-root level.
|
||||
*/
|
||||
size_t sib_base = bit + (ZU(1) << lg_bits_per_group);
|
||||
assert(sib_base > min_bit);
|
||||
assert(sib_base > bit);
|
||||
if (sib_base >= binfo->nbits) {
|
||||
return binfo->nbits;
|
||||
}
|
||||
return bitmap_ffu(bitmap, binfo, sib_base);
|
||||
}
|
||||
bit += ((size_t)(ffs_lu(group_masked) - 1)) <<
|
||||
(lg_bits_per_group - LG_BITMAP_GROUP_NBITS);
|
||||
}
|
||||
assert(bit >= min_bit);
|
||||
assert(bit < binfo->nbits);
|
||||
return bit;
|
||||
#else
|
||||
size_t i = min_bit >> LG_BITMAP_GROUP_NBITS;
|
||||
bitmap_t g = bitmap[i] & ~((1LU << (min_bit & BITMAP_GROUP_NBITS_MASK))
|
||||
- 1);
|
||||
size_t bit;
|
||||
do {
|
||||
bit = ffs_lu(g);
|
||||
if (bit != 0) {
|
||||
return (i << LG_BITMAP_GROUP_NBITS) + (bit - 1);
|
||||
}
|
||||
i++;
|
||||
g = bitmap[i];
|
||||
} while (i < binfo->ngroups);
|
||||
return binfo->nbits;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* sfu: set first unset. */
|
||||
JEMALLOC_INLINE size_t
|
||||
bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo)
|
||||
{
|
||||
static inline size_t
|
||||
bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo) {
|
||||
size_t bit;
|
||||
bitmap_t g;
|
||||
unsigned i;
|
||||
|
||||
assert(!bitmap_full(bitmap, binfo));
|
||||
|
||||
#ifdef BITMAP_USE_TREE
|
||||
i = binfo->nlevels - 1;
|
||||
g = bitmap[binfo->levels[i].group_offset];
|
||||
bit = jemalloc_ffsl(g) - 1;
|
||||
bit = ffs_lu(g) - 1;
|
||||
while (i > 0) {
|
||||
i--;
|
||||
g = bitmap[binfo->levels[i].group_offset + bit];
|
||||
bit = (bit << LG_BITMAP_GROUP_NBITS) + (jemalloc_ffsl(g) - 1);
|
||||
bit = (bit << LG_BITMAP_GROUP_NBITS) + (ffs_lu(g) - 1);
|
||||
}
|
||||
|
||||
#else
|
||||
i = 0;
|
||||
g = bitmap[0];
|
||||
while ((bit = ffs_lu(g)) == 0) {
|
||||
i++;
|
||||
g = bitmap[i];
|
||||
}
|
||||
bit = (i << LG_BITMAP_GROUP_NBITS) + (bit - 1);
|
||||
#endif
|
||||
bitmap_set(bitmap, binfo, bit);
|
||||
return (bit);
|
||||
return bit;
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit)
|
||||
{
|
||||
static inline void
|
||||
bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) {
|
||||
size_t goff;
|
||||
bitmap_t *gp;
|
||||
bitmap_t g;
|
||||
bool propagate;
|
||||
UNUSED bool propagate;
|
||||
|
||||
assert(bit < binfo->nbits);
|
||||
assert(bitmap_get(bitmap, binfo, bit));
|
||||
@ -201,10 +340,11 @@ bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit)
|
||||
gp = &bitmap[goff];
|
||||
g = *gp;
|
||||
propagate = (g == 0);
|
||||
assert((g & (1LU << (bit & BITMAP_GROUP_NBITS_MASK))) == 0);
|
||||
g ^= 1LU << (bit & BITMAP_GROUP_NBITS_MASK);
|
||||
assert((g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))) == 0);
|
||||
g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK);
|
||||
*gp = g;
|
||||
assert(!bitmap_get(bitmap, binfo, bit));
|
||||
#ifdef BITMAP_USE_TREE
|
||||
/* Propagate group state transitions up the tree. */
|
||||
if (propagate) {
|
||||
unsigned i;
|
||||
@ -214,17 +354,16 @@ bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit)
|
||||
gp = &bitmap[binfo->levels[i].group_offset + goff];
|
||||
g = *gp;
|
||||
propagate = (g == 0);
|
||||
assert((g & (1LU << (bit & BITMAP_GROUP_NBITS_MASK)))
|
||||
assert((g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK)))
|
||||
== 0);
|
||||
g ^= 1LU << (bit & BITMAP_GROUP_NBITS_MASK);
|
||||
g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK);
|
||||
*gp = g;
|
||||
if (!propagate)
|
||||
if (!propagate) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* BITMAP_USE_TREE */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* JEMALLOC_H_INLINES */
|
||||
/******************************************************************************/
|
||||
#endif /* JEMALLOC_INTERNAL_BITMAP_H */
|
||||
|
114
deps/jemalloc/include/jemalloc/internal/cache_bin.h
vendored
Normal file
114
deps/jemalloc/include/jemalloc/internal/cache_bin.h
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
#ifndef JEMALLOC_INTERNAL_CACHE_BIN_H
|
||||
#define JEMALLOC_INTERNAL_CACHE_BIN_H
|
||||
|
||||
#include "jemalloc/internal/ql.h"
|
||||
|
||||
/*
|
||||
* The cache_bins are the mechanism that the tcache and the arena use to
|
||||
* communicate. The tcache fills from and flushes to the arena by passing a
|
||||
* cache_bin_t to fill/flush. When the arena needs to pull stats from the
|
||||
* tcaches associated with it, it does so by iterating over its
|
||||
* cache_bin_array_descriptor_t objects and reading out per-bin stats it
|
||||
* contains. This makes it so that the arena need not know about the existence
|
||||
* of the tcache at all.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* The count of the number of cached allocations in a bin. We make this signed
|
||||
* so that negative numbers can encode "invalid" states (e.g. a low water mark
|
||||
* of -1 for a cache that has been depleted).
|
||||
*/
|
||||
typedef int32_t cache_bin_sz_t;
|
||||
|
||||
typedef struct cache_bin_stats_s cache_bin_stats_t;
|
||||
struct cache_bin_stats_s {
|
||||
/*
|
||||
* Number of allocation requests that corresponded to the size of this
|
||||
* bin.
|
||||
*/
|
||||
uint64_t nrequests;
|
||||
};
|
||||
|
||||
/*
|
||||
* Read-only information associated with each element of tcache_t's tbins array
|
||||
* is stored separately, mainly to reduce memory usage.
|
||||
*/
|
||||
typedef struct cache_bin_info_s cache_bin_info_t;
|
||||
struct cache_bin_info_s {
|
||||
/* Upper limit on ncached. */
|
||||
cache_bin_sz_t ncached_max;
|
||||
};
|
||||
|
||||
typedef struct cache_bin_s cache_bin_t;
|
||||
struct cache_bin_s {
|
||||
/* Min # cached since last GC. */
|
||||
cache_bin_sz_t low_water;
|
||||
/* # of cached objects. */
|
||||
cache_bin_sz_t ncached;
|
||||
/*
|
||||
* ncached and stats are both modified frequently. Let's keep them
|
||||
* close so that they have a higher chance of being on the same
|
||||
* cacheline, thus less write-backs.
|
||||
*/
|
||||
cache_bin_stats_t tstats;
|
||||
/*
|
||||
* Stack of available objects.
|
||||
*
|
||||
* To make use of adjacent cacheline prefetch, the items in the avail
|
||||
* stack goes to higher address for newer allocations. avail points
|
||||
* just above the available space, which means that
|
||||
* avail[-ncached, ... -1] are available items and the lowest item will
|
||||
* be allocated first.
|
||||
*/
|
||||
void **avail;
|
||||
};
|
||||
|
||||
typedef struct cache_bin_array_descriptor_s cache_bin_array_descriptor_t;
|
||||
struct cache_bin_array_descriptor_s {
|
||||
/*
|
||||
* The arena keeps a list of the cache bins associated with it, for
|
||||
* stats collection.
|
||||
*/
|
||||
ql_elm(cache_bin_array_descriptor_t) link;
|
||||
/* Pointers to the tcache bins. */
|
||||
cache_bin_t *bins_small;
|
||||
cache_bin_t *bins_large;
|
||||
};
|
||||
|
||||
static inline void
|
||||
cache_bin_array_descriptor_init(cache_bin_array_descriptor_t *descriptor,
|
||||
cache_bin_t *bins_small, cache_bin_t *bins_large) {
|
||||
ql_elm_new(descriptor, link);
|
||||
descriptor->bins_small = bins_small;
|
||||
descriptor->bins_large = bins_large;
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void *
|
||||
cache_bin_alloc_easy(cache_bin_t *bin, bool *success) {
|
||||
void *ret;
|
||||
|
||||
if (unlikely(bin->ncached == 0)) {
|
||||
bin->low_water = -1;
|
||||
*success = false;
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* success (instead of ret) should be checked upon the return of this
|
||||
* function. We avoid checking (ret == NULL) because there is never a
|
||||
* null stored on the avail stack (which is unknown to the compiler),
|
||||
* and eagerly checking ret would cause pipeline stall (waiting for the
|
||||
* cacheline).
|
||||
*/
|
||||
*success = true;
|
||||
ret = *(bin->avail - bin->ncached);
|
||||
bin->ncached--;
|
||||
|
||||
if (unlikely(bin->ncached < bin->low_water)) {
|
||||
bin->low_water = bin->ncached;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_CACHE_BIN_H */
|
99
deps/jemalloc/include/jemalloc/internal/chunk.h
vendored
99
deps/jemalloc/include/jemalloc/internal/chunk.h
vendored
@ -1,99 +0,0 @@
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_TYPES
|
||||
|
||||
/*
|
||||
* Size and alignment of memory chunks that are allocated by the OS's virtual
|
||||
* memory system.
|
||||
*/
|
||||
#define LG_CHUNK_DEFAULT 21
|
||||
|
||||
/* Return the chunk address for allocation address a. */
|
||||
#define CHUNK_ADDR2BASE(a) \
|
||||
((void *)((uintptr_t)(a) & ~chunksize_mask))
|
||||
|
||||
/* Return the chunk offset of address a. */
|
||||
#define CHUNK_ADDR2OFFSET(a) \
|
||||
((size_t)((uintptr_t)(a) & chunksize_mask))
|
||||
|
||||
/* Return the smallest chunk multiple that is >= s. */
|
||||
#define CHUNK_CEILING(s) \
|
||||
(((s) + chunksize_mask) & ~chunksize_mask)
|
||||
|
||||
#define CHUNK_HOOKS_INITIALIZER { \
|
||||
NULL, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
NULL \
|
||||
}
|
||||
|
||||
#endif /* JEMALLOC_H_TYPES */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_STRUCTS
|
||||
|
||||
#endif /* JEMALLOC_H_STRUCTS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_EXTERNS
|
||||
|
||||
extern size_t opt_lg_chunk;
|
||||
extern const char *opt_dss;
|
||||
|
||||
extern rtree_t chunks_rtree;
|
||||
|
||||
extern size_t chunksize;
|
||||
extern size_t chunksize_mask; /* (chunksize - 1). */
|
||||
extern size_t chunk_npages;
|
||||
|
||||
extern const chunk_hooks_t chunk_hooks_default;
|
||||
|
||||
chunk_hooks_t chunk_hooks_get(arena_t *arena);
|
||||
chunk_hooks_t chunk_hooks_set(arena_t *arena,
|
||||
const chunk_hooks_t *chunk_hooks);
|
||||
|
||||
bool chunk_register(const void *chunk, const extent_node_t *node);
|
||||
void chunk_deregister(const void *chunk, const extent_node_t *node);
|
||||
void *chunk_alloc_base(size_t size);
|
||||
void *chunk_alloc_cache(arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
void *new_addr, size_t size, size_t alignment, bool *zero,
|
||||
bool dalloc_node);
|
||||
void *chunk_alloc_wrapper(arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit);
|
||||
void chunk_dalloc_cache(arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
void *chunk, size_t size, bool committed);
|
||||
void chunk_dalloc_arena(arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
void *chunk, size_t size, bool zeroed, bool committed);
|
||||
void chunk_dalloc_wrapper(arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
void *chunk, size_t size, bool committed);
|
||||
bool chunk_purge_arena(arena_t *arena, void *chunk, size_t offset,
|
||||
size_t length);
|
||||
bool chunk_purge_wrapper(arena_t *arena, chunk_hooks_t *chunk_hooks,
|
||||
void *chunk, size_t size, size_t offset, size_t length);
|
||||
bool chunk_boot(void);
|
||||
void chunk_prefork(void);
|
||||
void chunk_postfork_parent(void);
|
||||
void chunk_postfork_child(void);
|
||||
|
||||
#endif /* JEMALLOC_H_EXTERNS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_INLINES
|
||||
|
||||
#ifndef JEMALLOC_ENABLE_INLINE
|
||||
extent_node_t *chunk_lookup(const void *chunk, bool dependent);
|
||||
#endif
|
||||
|
||||
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_CHUNK_C_))
|
||||
JEMALLOC_INLINE extent_node_t *
|
||||
chunk_lookup(const void *ptr, bool dependent)
|
||||
{
|
||||
|
||||
return (rtree_get(&chunks_rtree, (uintptr_t)ptr, dependent));
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* JEMALLOC_H_INLINES */
|
||||
/******************************************************************************/
|
||||
|
||||
#include "jemalloc/internal/chunk_dss.h"
|
||||
#include "jemalloc/internal/chunk_mmap.h"
|
@ -1,39 +0,0 @@
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_TYPES
|
||||
|
||||
typedef enum {
|
||||
dss_prec_disabled = 0,
|
||||
dss_prec_primary = 1,
|
||||
dss_prec_secondary = 2,
|
||||
|
||||
dss_prec_limit = 3
|
||||
} dss_prec_t;
|
||||
#define DSS_PREC_DEFAULT dss_prec_secondary
|
||||
#define DSS_DEFAULT "secondary"
|
||||
|
||||
#endif /* JEMALLOC_H_TYPES */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_STRUCTS
|
||||
|
||||
extern const char *dss_prec_names[];
|
||||
|
||||
#endif /* JEMALLOC_H_STRUCTS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_EXTERNS
|
||||
|
||||
dss_prec_t chunk_dss_prec_get(void);
|
||||
bool chunk_dss_prec_set(dss_prec_t dss_prec);
|
||||
void *chunk_alloc_dss(arena_t *arena, void *new_addr, size_t size,
|
||||
size_t alignment, bool *zero, bool *commit);
|
||||
bool chunk_in_dss(void *chunk);
|
||||
bool chunk_dss_boot(void);
|
||||
void chunk_dss_prefork(void);
|
||||
void chunk_dss_postfork_parent(void);
|
||||
void chunk_dss_postfork_child(void);
|
||||
|
||||
#endif /* JEMALLOC_H_EXTERNS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_INLINES
|
||||
|
||||
#endif /* JEMALLOC_H_INLINES */
|
||||
/******************************************************************************/
|
@ -1,21 +0,0 @@
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_TYPES
|
||||
|
||||
#endif /* JEMALLOC_H_TYPES */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_STRUCTS
|
||||
|
||||
#endif /* JEMALLOC_H_STRUCTS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_EXTERNS
|
||||
|
||||
void *chunk_alloc_mmap(size_t size, size_t alignment, bool *zero,
|
||||
bool *commit);
|
||||
bool chunk_dalloc_mmap(void *chunk, size_t size);
|
||||
|
||||
#endif /* JEMALLOC_H_EXTERNS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_INLINES
|
||||
|
||||
#endif /* JEMALLOC_H_INLINES */
|
||||
/******************************************************************************/
|
117
deps/jemalloc/include/jemalloc/internal/ckh.h
vendored
117
deps/jemalloc/include/jemalloc/internal/ckh.h
vendored
@ -1,88 +1,101 @@
|
||||
#ifndef JEMALLOC_INTERNAL_CKH_H
|
||||
#define JEMALLOC_INTERNAL_CKH_H
|
||||
|
||||
#include "jemalloc/internal/tsd.h"
|
||||
|
||||
/* Cuckoo hashing implementation. Skip to the end for the interface. */
|
||||
|
||||
/******************************************************************************/
|
||||
/* INTERNAL DEFINITIONS -- IGNORE */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_TYPES
|
||||
|
||||
typedef struct ckh_s ckh_t;
|
||||
typedef struct ckhc_s ckhc_t;
|
||||
|
||||
/* Typedefs to allow easy function pointer passing. */
|
||||
typedef void ckh_hash_t (const void *, size_t[2]);
|
||||
typedef bool ckh_keycomp_t (const void *, const void *);
|
||||
|
||||
/* Maintain counters used to get an idea of performance. */
|
||||
/* #define CKH_COUNT */
|
||||
/* #define CKH_COUNT */
|
||||
/* Print counter values in ckh_delete() (requires CKH_COUNT). */
|
||||
/* #define CKH_VERBOSE */
|
||||
/* #define CKH_VERBOSE */
|
||||
|
||||
/*
|
||||
* There are 2^LG_CKH_BUCKET_CELLS cells in each hash table bucket. Try to fit
|
||||
* one bucket per L1 cache line.
|
||||
*/
|
||||
#define LG_CKH_BUCKET_CELLS (LG_CACHELINE - LG_SIZEOF_PTR - 1)
|
||||
#define LG_CKH_BUCKET_CELLS (LG_CACHELINE - LG_SIZEOF_PTR - 1)
|
||||
|
||||
#endif /* JEMALLOC_H_TYPES */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_STRUCTS
|
||||
/* Typedefs to allow easy function pointer passing. */
|
||||
typedef void ckh_hash_t (const void *, size_t[2]);
|
||||
typedef bool ckh_keycomp_t (const void *, const void *);
|
||||
|
||||
/* Hash table cell. */
|
||||
struct ckhc_s {
|
||||
const void *key;
|
||||
const void *data;
|
||||
};
|
||||
typedef struct {
|
||||
const void *key;
|
||||
const void *data;
|
||||
} ckhc_t;
|
||||
|
||||
struct ckh_s {
|
||||
/* The hash table itself. */
|
||||
typedef struct {
|
||||
#ifdef CKH_COUNT
|
||||
/* Counters used to get an idea of performance. */
|
||||
uint64_t ngrows;
|
||||
uint64_t nshrinks;
|
||||
uint64_t nshrinkfails;
|
||||
uint64_t ninserts;
|
||||
uint64_t nrelocs;
|
||||
uint64_t ngrows;
|
||||
uint64_t nshrinks;
|
||||
uint64_t nshrinkfails;
|
||||
uint64_t ninserts;
|
||||
uint64_t nrelocs;
|
||||
#endif
|
||||
|
||||
/* Used for pseudo-random number generation. */
|
||||
#define CKH_A 1103515241
|
||||
#define CKH_C 12347
|
||||
uint32_t prng_state;
|
||||
uint64_t prng_state;
|
||||
|
||||
/* Total number of items. */
|
||||
size_t count;
|
||||
size_t count;
|
||||
|
||||
/*
|
||||
* Minimum and current number of hash table buckets. There are
|
||||
* 2^LG_CKH_BUCKET_CELLS cells per bucket.
|
||||
*/
|
||||
unsigned lg_minbuckets;
|
||||
unsigned lg_curbuckets;
|
||||
unsigned lg_minbuckets;
|
||||
unsigned lg_curbuckets;
|
||||
|
||||
/* Hash and comparison functions. */
|
||||
ckh_hash_t *hash;
|
||||
ckh_keycomp_t *keycomp;
|
||||
ckh_hash_t *hash;
|
||||
ckh_keycomp_t *keycomp;
|
||||
|
||||
/* Hash table with 2^lg_curbuckets buckets. */
|
||||
ckhc_t *tab;
|
||||
};
|
||||
ckhc_t *tab;
|
||||
} ckh_t;
|
||||
|
||||
#endif /* JEMALLOC_H_STRUCTS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_EXTERNS
|
||||
/* BEGIN PUBLIC API */
|
||||
/******************************************************************************/
|
||||
|
||||
bool ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *hash,
|
||||
/* Lifetime management. Minitems is the initial capacity. */
|
||||
bool ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *hash,
|
||||
ckh_keycomp_t *keycomp);
|
||||
void ckh_delete(tsd_t *tsd, ckh_t *ckh);
|
||||
size_t ckh_count(ckh_t *ckh);
|
||||
bool ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data);
|
||||
bool ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data);
|
||||
bool ckh_remove(tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key,
|
||||
void ckh_delete(tsd_t *tsd, ckh_t *ckh);
|
||||
|
||||
/* Get the number of elements in the set. */
|
||||
size_t ckh_count(ckh_t *ckh);
|
||||
|
||||
/*
|
||||
* To iterate over the elements in the table, initialize *tabind to 0 and call
|
||||
* this function until it returns true. Each call that returns false will
|
||||
* update *key and *data to the next element in the table, assuming the pointers
|
||||
* are non-NULL.
|
||||
*/
|
||||
bool ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data);
|
||||
|
||||
/*
|
||||
* Basic hash table operations -- insert, removal, lookup. For ckh_remove and
|
||||
* ckh_search, key or data can be NULL. The hash-table only stores pointers to
|
||||
* the key and value, and doesn't do any lifetime management.
|
||||
*/
|
||||
bool ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data);
|
||||
bool ckh_remove(tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key,
|
||||
void **data);
|
||||
bool ckh_search(ckh_t *ckh, const void *seachkey, void **key, void **data);
|
||||
void ckh_string_hash(const void *key, size_t r_hash[2]);
|
||||
bool ckh_string_keycomp(const void *k1, const void *k2);
|
||||
void ckh_pointer_hash(const void *key, size_t r_hash[2]);
|
||||
bool ckh_pointer_keycomp(const void *k1, const void *k2);
|
||||
bool ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data);
|
||||
|
||||
#endif /* JEMALLOC_H_EXTERNS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_INLINES
|
||||
/* Some useful hash and comparison functions for strings and pointers. */
|
||||
void ckh_string_hash(const void *key, size_t r_hash[2]);
|
||||
bool ckh_string_keycomp(const void *k1, const void *k2);
|
||||
void ckh_pointer_hash(const void *key, size_t r_hash[2]);
|
||||
bool ckh_pointer_keycomp(const void *k1, const void *k2);
|
||||
|
||||
#endif /* JEMALLOC_H_INLINES */
|
||||
/******************************************************************************/
|
||||
#endif /* JEMALLOC_INTERNAL_CKH_H */
|
||||
|
162
deps/jemalloc/include/jemalloc/internal/ctl.h
vendored
162
deps/jemalloc/include/jemalloc/internal/ctl.h
vendored
@ -1,81 +1,107 @@
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_TYPES
|
||||
#ifndef JEMALLOC_INTERNAL_CTL_H
|
||||
#define JEMALLOC_INTERNAL_CTL_H
|
||||
|
||||
typedef struct ctl_node_s ctl_node_t;
|
||||
typedef struct ctl_named_node_s ctl_named_node_t;
|
||||
typedef struct ctl_indexed_node_s ctl_indexed_node_t;
|
||||
typedef struct ctl_arena_stats_s ctl_arena_stats_t;
|
||||
typedef struct ctl_stats_s ctl_stats_t;
|
||||
#include "jemalloc/internal/jemalloc_internal_types.h"
|
||||
#include "jemalloc/internal/malloc_io.h"
|
||||
#include "jemalloc/internal/mutex_prof.h"
|
||||
#include "jemalloc/internal/ql.h"
|
||||
#include "jemalloc/internal/size_classes.h"
|
||||
#include "jemalloc/internal/stats.h"
|
||||
|
||||
#endif /* JEMALLOC_H_TYPES */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_STRUCTS
|
||||
/* Maximum ctl tree depth. */
|
||||
#define CTL_MAX_DEPTH 7
|
||||
|
||||
struct ctl_node_s {
|
||||
bool named;
|
||||
};
|
||||
typedef struct ctl_node_s {
|
||||
bool named;
|
||||
} ctl_node_t;
|
||||
|
||||
struct ctl_named_node_s {
|
||||
struct ctl_node_s node;
|
||||
const char *name;
|
||||
typedef struct ctl_named_node_s {
|
||||
ctl_node_t node;
|
||||
const char *name;
|
||||
/* If (nchildren == 0), this is a terminal node. */
|
||||
unsigned nchildren;
|
||||
const ctl_node_t *children;
|
||||
int (*ctl)(const size_t *, size_t, void *, size_t *,
|
||||
void *, size_t);
|
||||
};
|
||||
size_t nchildren;
|
||||
const ctl_node_t *children;
|
||||
int (*ctl)(tsd_t *, const size_t *, size_t, void *, size_t *, void *,
|
||||
size_t);
|
||||
} ctl_named_node_t;
|
||||
|
||||
struct ctl_indexed_node_s {
|
||||
struct ctl_node_s node;
|
||||
const ctl_named_node_t *(*index)(const size_t *, size_t, size_t);
|
||||
};
|
||||
typedef struct ctl_indexed_node_s {
|
||||
struct ctl_node_s node;
|
||||
const ctl_named_node_t *(*index)(tsdn_t *, const size_t *, size_t,
|
||||
size_t);
|
||||
} ctl_indexed_node_t;
|
||||
|
||||
struct ctl_arena_stats_s {
|
||||
bool initialized;
|
||||
unsigned nthreads;
|
||||
const char *dss;
|
||||
ssize_t lg_dirty_mult;
|
||||
size_t pactive;
|
||||
size_t pdirty;
|
||||
arena_stats_t astats;
|
||||
typedef struct ctl_arena_stats_s {
|
||||
arena_stats_t astats;
|
||||
|
||||
/* Aggregate stats for small size classes, based on bin stats. */
|
||||
size_t allocated_small;
|
||||
uint64_t nmalloc_small;
|
||||
uint64_t ndalloc_small;
|
||||
uint64_t nrequests_small;
|
||||
size_t allocated_small;
|
||||
uint64_t nmalloc_small;
|
||||
uint64_t ndalloc_small;
|
||||
uint64_t nrequests_small;
|
||||
|
||||
malloc_bin_stats_t bstats[NBINS];
|
||||
malloc_large_stats_t *lstats; /* nlclasses elements. */
|
||||
malloc_huge_stats_t *hstats; /* nhclasses elements. */
|
||||
bin_stats_t bstats[NBINS];
|
||||
arena_stats_large_t lstats[NSIZES - NBINS];
|
||||
} ctl_arena_stats_t;
|
||||
|
||||
typedef struct ctl_stats_s {
|
||||
size_t allocated;
|
||||
size_t active;
|
||||
size_t metadata;
|
||||
size_t metadata_thp;
|
||||
size_t resident;
|
||||
size_t mapped;
|
||||
size_t retained;
|
||||
|
||||
background_thread_stats_t background_thread;
|
||||
mutex_prof_data_t mutex_prof_data[mutex_prof_num_global_mutexes];
|
||||
} ctl_stats_t;
|
||||
|
||||
typedef struct ctl_arena_s ctl_arena_t;
|
||||
struct ctl_arena_s {
|
||||
unsigned arena_ind;
|
||||
bool initialized;
|
||||
ql_elm(ctl_arena_t) destroyed_link;
|
||||
|
||||
/* Basic stats, supported even if !config_stats. */
|
||||
unsigned nthreads;
|
||||
const char *dss;
|
||||
ssize_t dirty_decay_ms;
|
||||
ssize_t muzzy_decay_ms;
|
||||
size_t pactive;
|
||||
size_t pdirty;
|
||||
size_t pmuzzy;
|
||||
|
||||
/* NULL if !config_stats. */
|
||||
ctl_arena_stats_t *astats;
|
||||
};
|
||||
|
||||
struct ctl_stats_s {
|
||||
size_t allocated;
|
||||
size_t active;
|
||||
size_t metadata;
|
||||
size_t resident;
|
||||
size_t mapped;
|
||||
unsigned narenas;
|
||||
ctl_arena_stats_t *arenas; /* (narenas + 1) elements. */
|
||||
};
|
||||
typedef struct ctl_arenas_s {
|
||||
uint64_t epoch;
|
||||
unsigned narenas;
|
||||
ql_head(ctl_arena_t) destroyed;
|
||||
|
||||
#endif /* JEMALLOC_H_STRUCTS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_EXTERNS
|
||||
/*
|
||||
* Element 0 corresponds to merged stats for extant arenas (accessed via
|
||||
* MALLCTL_ARENAS_ALL), element 1 corresponds to merged stats for
|
||||
* destroyed arenas (accessed via MALLCTL_ARENAS_DESTROYED), and the
|
||||
* remaining MALLOCX_ARENA_LIMIT elements correspond to arenas.
|
||||
*/
|
||||
ctl_arena_t *arenas[2 + MALLOCX_ARENA_LIMIT];
|
||||
} ctl_arenas_t;
|
||||
|
||||
int ctl_byname(const char *name, void *oldp, size_t *oldlenp, void *newp,
|
||||
size_t newlen);
|
||||
int ctl_nametomib(const char *name, size_t *mibp, size_t *miblenp);
|
||||
|
||||
int ctl_bymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
||||
int ctl_byname(tsd_t *tsd, const char *name, void *oldp, size_t *oldlenp,
|
||||
void *newp, size_t newlen);
|
||||
bool ctl_boot(void);
|
||||
void ctl_prefork(void);
|
||||
void ctl_postfork_parent(void);
|
||||
void ctl_postfork_child(void);
|
||||
int ctl_nametomib(tsd_t *tsd, const char *name, size_t *mibp, size_t *miblenp);
|
||||
|
||||
#define xmallctl(name, oldp, oldlenp, newp, newlen) do { \
|
||||
int ctl_bymib(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
||||
size_t *oldlenp, void *newp, size_t newlen);
|
||||
bool ctl_boot(void);
|
||||
void ctl_prefork(tsdn_t *tsdn);
|
||||
void ctl_postfork_parent(tsdn_t *tsdn);
|
||||
void ctl_postfork_child(tsdn_t *tsdn);
|
||||
|
||||
#define xmallctl(name, oldp, oldlenp, newp, newlen) do { \
|
||||
if (je_mallctl(name, oldp, oldlenp, newp, newlen) \
|
||||
!= 0) { \
|
||||
malloc_printf( \
|
||||
@ -85,7 +111,7 @@ void ctl_postfork_child(void);
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define xmallctlnametomib(name, mibp, miblenp) do { \
|
||||
#define xmallctlnametomib(name, mibp, miblenp) do { \
|
||||
if (je_mallctlnametomib(name, mibp, miblenp) != 0) { \
|
||||
malloc_printf("<jemalloc>: Failure in " \
|
||||
"xmallctlnametomib(\"%s\", ...)\n", name); \
|
||||
@ -93,7 +119,7 @@ void ctl_postfork_child(void);
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define xmallctlbymib(mib, miblen, oldp, oldlenp, newp, newlen) do { \
|
||||
#define xmallctlbymib(mib, miblen, oldp, oldlenp, newp, newlen) do { \
|
||||
if (je_mallctlbymib(mib, miblen, oldp, oldlenp, newp, \
|
||||
newlen) != 0) { \
|
||||
malloc_write( \
|
||||
@ -102,10 +128,4 @@ void ctl_postfork_child(void);
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* JEMALLOC_H_EXTERNS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_INLINES
|
||||
|
||||
#endif /* JEMALLOC_H_INLINES */
|
||||
/******************************************************************************/
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_CTL_H */
|
||||
|
41
deps/jemalloc/include/jemalloc/internal/div.h
vendored
Normal file
41
deps/jemalloc/include/jemalloc/internal/div.h
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef JEMALLOC_INTERNAL_DIV_H
|
||||
#define JEMALLOC_INTERNAL_DIV_H
|
||||
|
||||
#include "jemalloc/internal/assert.h"
|
||||
|
||||
/*
|
||||
* This module does the division that computes the index of a region in a slab,
|
||||
* given its offset relative to the base.
|
||||
* That is, given a divisor d, an n = i * d (all integers), we'll return i.
|
||||
* We do some pre-computation to do this more quickly than a CPU division
|
||||
* instruction.
|
||||
* We bound n < 2^32, and don't support dividing by one.
|
||||
*/
|
||||
|
||||
typedef struct div_info_s div_info_t;
|
||||
struct div_info_s {
|
||||
uint32_t magic;
|
||||
#ifdef JEMALLOC_DEBUG
|
||||
size_t d;
|
||||
#endif
|
||||
};
|
||||
|
||||
void div_init(div_info_t *div_info, size_t divisor);
|
||||
|
||||
static inline size_t
|
||||
div_compute(div_info_t *div_info, size_t n) {
|
||||
assert(n <= (uint32_t)-1);
|
||||
/*
|
||||
* This generates, e.g. mov; imul; shr on x86-64. On a 32-bit machine,
|
||||
* the compilers I tried were all smart enough to turn this into the
|
||||
* appropriate "get the high 32 bits of the result of a multiply" (e.g.
|
||||
* mul; mov edx eax; on x86, umull on arm, etc.).
|
||||
*/
|
||||
size_t i = ((uint64_t)n * (uint64_t)div_info->magic) >> 32;
|
||||
#ifdef JEMALLOC_DEBUG
|
||||
assert(i * div_info->d == n);
|
||||
#endif
|
||||
return i;
|
||||
}
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_DIV_H */
|
435
deps/jemalloc/include/jemalloc/internal/emitter.h
vendored
Normal file
435
deps/jemalloc/include/jemalloc/internal/emitter.h
vendored
Normal file
@ -0,0 +1,435 @@
|
||||
#ifndef JEMALLOC_INTERNAL_EMITTER_H
|
||||
#define JEMALLOC_INTERNAL_EMITTER_H
|
||||
|
||||
#include "jemalloc/internal/ql.h"
|
||||
|
||||
typedef enum emitter_output_e emitter_output_t;
|
||||
enum emitter_output_e {
|
||||
emitter_output_json,
|
||||
emitter_output_table
|
||||
};
|
||||
|
||||
typedef enum emitter_justify_e emitter_justify_t;
|
||||
enum emitter_justify_e {
|
||||
emitter_justify_left,
|
||||
emitter_justify_right,
|
||||
/* Not for users; just to pass to internal functions. */
|
||||
emitter_justify_none
|
||||
};
|
||||
|
||||
typedef enum emitter_type_e emitter_type_t;
|
||||
enum emitter_type_e {
|
||||
emitter_type_bool,
|
||||
emitter_type_int,
|
||||
emitter_type_unsigned,
|
||||
emitter_type_uint32,
|
||||
emitter_type_uint64,
|
||||
emitter_type_size,
|
||||
emitter_type_ssize,
|
||||
emitter_type_string,
|
||||
/*
|
||||
* A title is a column title in a table; it's just a string, but it's
|
||||
* not quoted.
|
||||
*/
|
||||
emitter_type_title,
|
||||
};
|
||||
|
||||
typedef struct emitter_col_s emitter_col_t;
|
||||
struct emitter_col_s {
|
||||
/* Filled in by the user. */
|
||||
emitter_justify_t justify;
|
||||
int width;
|
||||
emitter_type_t type;
|
||||
union {
|
||||
bool bool_val;
|
||||
int int_val;
|
||||
unsigned unsigned_val;
|
||||
uint32_t uint32_val;
|
||||
uint64_t uint64_val;
|
||||
size_t size_val;
|
||||
ssize_t ssize_val;
|
||||
const char *str_val;
|
||||
};
|
||||
|
||||
/* Filled in by initialization. */
|
||||
ql_elm(emitter_col_t) link;
|
||||
};
|
||||
|
||||
typedef struct emitter_row_s emitter_row_t;
|
||||
struct emitter_row_s {
|
||||
ql_head(emitter_col_t) cols;
|
||||
};
|
||||
|
||||
static inline void
|
||||
emitter_row_init(emitter_row_t *row) {
|
||||
ql_new(&row->cols);
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_col_init(emitter_col_t *col, emitter_row_t *row) {
|
||||
ql_elm_new(col, link);
|
||||
ql_tail_insert(&row->cols, col, link);
|
||||
}
|
||||
|
||||
typedef struct emitter_s emitter_t;
|
||||
struct emitter_s {
|
||||
emitter_output_t output;
|
||||
/* The output information. */
|
||||
void (*write_cb)(void *, const char *);
|
||||
void *cbopaque;
|
||||
int nesting_depth;
|
||||
/* True if we've already emitted a value at the given depth. */
|
||||
bool item_at_depth;
|
||||
};
|
||||
|
||||
static inline void
|
||||
emitter_init(emitter_t *emitter, emitter_output_t emitter_output,
|
||||
void (*write_cb)(void *, const char *), void *cbopaque) {
|
||||
emitter->output = emitter_output;
|
||||
emitter->write_cb = write_cb;
|
||||
emitter->cbopaque = cbopaque;
|
||||
emitter->item_at_depth = false;
|
||||
emitter->nesting_depth = 0;
|
||||
}
|
||||
|
||||
/* Internal convenience function. Write to the emitter the given string. */
|
||||
JEMALLOC_FORMAT_PRINTF(2, 3)
|
||||
static inline void
|
||||
emitter_printf(emitter_t *emitter, const char *format, ...) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
malloc_vcprintf(emitter->write_cb, emitter->cbopaque, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* Write to the emitter the given string, but only in table mode. */
|
||||
JEMALLOC_FORMAT_PRINTF(2, 3)
|
||||
static inline void
|
||||
emitter_table_printf(emitter_t *emitter, const char *format, ...) {
|
||||
if (emitter->output == emitter_output_table) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
malloc_vcprintf(emitter->write_cb, emitter->cbopaque, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_gen_fmt(char *out_fmt, size_t out_size, const char *fmt_specifier,
|
||||
emitter_justify_t justify, int width) {
|
||||
size_t written;
|
||||
if (justify == emitter_justify_none) {
|
||||
written = malloc_snprintf(out_fmt, out_size,
|
||||
"%%%s", fmt_specifier);
|
||||
} else if (justify == emitter_justify_left) {
|
||||
written = malloc_snprintf(out_fmt, out_size,
|
||||
"%%-%d%s", width, fmt_specifier);
|
||||
} else {
|
||||
written = malloc_snprintf(out_fmt, out_size,
|
||||
"%%%d%s", width, fmt_specifier);
|
||||
}
|
||||
/* Only happens in case of bad format string, which *we* choose. */
|
||||
assert(written < out_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal. Emit the given value type in the relevant encoding (so that the
|
||||
* bool true gets mapped to json "true", but the string "true" gets mapped to
|
||||
* json "\"true\"", for instance.
|
||||
*
|
||||
* Width is ignored if justify is emitter_justify_none.
|
||||
*/
|
||||
static inline void
|
||||
emitter_print_value(emitter_t *emitter, emitter_justify_t justify, int width,
|
||||
emitter_type_t value_type, const void *value) {
|
||||
size_t str_written;
|
||||
#define BUF_SIZE 256
|
||||
#define FMT_SIZE 10
|
||||
/*
|
||||
* We dynamically generate a format string to emit, to let us use the
|
||||
* snprintf machinery. This is kinda hacky, but gets the job done
|
||||
* quickly without having to think about the various snprintf edge
|
||||
* cases.
|
||||
*/
|
||||
char fmt[FMT_SIZE];
|
||||
char buf[BUF_SIZE];
|
||||
|
||||
#define EMIT_SIMPLE(type, format) \
|
||||
emitter_gen_fmt(fmt, FMT_SIZE, format, justify, width); \
|
||||
emitter_printf(emitter, fmt, *(const type *)value); \
|
||||
|
||||
switch (value_type) {
|
||||
case emitter_type_bool:
|
||||
emitter_gen_fmt(fmt, FMT_SIZE, "s", justify, width);
|
||||
emitter_printf(emitter, fmt, *(const bool *)value ?
|
||||
"true" : "false");
|
||||
break;
|
||||
case emitter_type_int:
|
||||
EMIT_SIMPLE(int, "d")
|
||||
break;
|
||||
case emitter_type_unsigned:
|
||||
EMIT_SIMPLE(unsigned, "u")
|
||||
break;
|
||||
case emitter_type_ssize:
|
||||
EMIT_SIMPLE(ssize_t, "zd")
|
||||
break;
|
||||
case emitter_type_size:
|
||||
EMIT_SIMPLE(size_t, "zu")
|
||||
break;
|
||||
case emitter_type_string:
|
||||
str_written = malloc_snprintf(buf, BUF_SIZE, "\"%s\"",
|
||||
*(const char *const *)value);
|
||||
/*
|
||||
* We control the strings we output; we shouldn't get anything
|
||||
* anywhere near the fmt size.
|
||||
*/
|
||||
assert(str_written < BUF_SIZE);
|
||||
emitter_gen_fmt(fmt, FMT_SIZE, "s", justify, width);
|
||||
emitter_printf(emitter, fmt, buf);
|
||||
break;
|
||||
case emitter_type_uint32:
|
||||
EMIT_SIMPLE(uint32_t, FMTu32)
|
||||
break;
|
||||
case emitter_type_uint64:
|
||||
EMIT_SIMPLE(uint64_t, FMTu64)
|
||||
break;
|
||||
case emitter_type_title:
|
||||
EMIT_SIMPLE(char *const, "s");
|
||||
break;
|
||||
default:
|
||||
unreachable();
|
||||
}
|
||||
#undef BUF_SIZE
|
||||
#undef FMT_SIZE
|
||||
}
|
||||
|
||||
|
||||
/* Internal functions. In json mode, tracks nesting state. */
|
||||
static inline void
|
||||
emitter_nest_inc(emitter_t *emitter) {
|
||||
emitter->nesting_depth++;
|
||||
emitter->item_at_depth = false;
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_nest_dec(emitter_t *emitter) {
|
||||
emitter->nesting_depth--;
|
||||
emitter->item_at_depth = true;
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_indent(emitter_t *emitter) {
|
||||
int amount = emitter->nesting_depth;
|
||||
const char *indent_str;
|
||||
if (emitter->output == emitter_output_json) {
|
||||
indent_str = "\t";
|
||||
} else {
|
||||
amount *= 2;
|
||||
indent_str = " ";
|
||||
}
|
||||
for (int i = 0; i < amount; i++) {
|
||||
emitter_printf(emitter, "%s", indent_str);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_json_key_prefix(emitter_t *emitter) {
|
||||
emitter_printf(emitter, "%s\n", emitter->item_at_depth ? "," : "");
|
||||
emitter_indent(emitter);
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_begin(emitter_t *emitter) {
|
||||
if (emitter->output == emitter_output_json) {
|
||||
assert(emitter->nesting_depth == 0);
|
||||
emitter_printf(emitter, "{");
|
||||
emitter_nest_inc(emitter);
|
||||
} else {
|
||||
// tabular init
|
||||
emitter_printf(emitter, "%s", "");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_end(emitter_t *emitter) {
|
||||
if (emitter->output == emitter_output_json) {
|
||||
assert(emitter->nesting_depth == 1);
|
||||
emitter_nest_dec(emitter);
|
||||
emitter_printf(emitter, "\n}\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Note emits a different kv pair as well, but only in table mode. Omits the
|
||||
* note if table_note_key is NULL.
|
||||
*/
|
||||
static inline void
|
||||
emitter_kv_note(emitter_t *emitter, const char *json_key, const char *table_key,
|
||||
emitter_type_t value_type, const void *value,
|
||||
const char *table_note_key, emitter_type_t table_note_value_type,
|
||||
const void *table_note_value) {
|
||||
if (emitter->output == emitter_output_json) {
|
||||
assert(emitter->nesting_depth > 0);
|
||||
emitter_json_key_prefix(emitter);
|
||||
emitter_printf(emitter, "\"%s\": ", json_key);
|
||||
emitter_print_value(emitter, emitter_justify_none, -1,
|
||||
value_type, value);
|
||||
} else {
|
||||
emitter_indent(emitter);
|
||||
emitter_printf(emitter, "%s: ", table_key);
|
||||
emitter_print_value(emitter, emitter_justify_none, -1,
|
||||
value_type, value);
|
||||
if (table_note_key != NULL) {
|
||||
emitter_printf(emitter, " (%s: ", table_note_key);
|
||||
emitter_print_value(emitter, emitter_justify_none, -1,
|
||||
table_note_value_type, table_note_value);
|
||||
emitter_printf(emitter, ")");
|
||||
}
|
||||
emitter_printf(emitter, "\n");
|
||||
}
|
||||
emitter->item_at_depth = true;
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_kv(emitter_t *emitter, const char *json_key, const char *table_key,
|
||||
emitter_type_t value_type, const void *value) {
|
||||
emitter_kv_note(emitter, json_key, table_key, value_type, value, NULL,
|
||||
emitter_type_bool, NULL);
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_json_kv(emitter_t *emitter, const char *json_key,
|
||||
emitter_type_t value_type, const void *value) {
|
||||
if (emitter->output == emitter_output_json) {
|
||||
emitter_kv(emitter, json_key, NULL, value_type, value);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_table_kv(emitter_t *emitter, const char *table_key,
|
||||
emitter_type_t value_type, const void *value) {
|
||||
if (emitter->output == emitter_output_table) {
|
||||
emitter_kv(emitter, NULL, table_key, value_type, value);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_dict_begin(emitter_t *emitter, const char *json_key,
|
||||
const char *table_header) {
|
||||
if (emitter->output == emitter_output_json) {
|
||||
emitter_json_key_prefix(emitter);
|
||||
emitter_printf(emitter, "\"%s\": {", json_key);
|
||||
emitter_nest_inc(emitter);
|
||||
} else {
|
||||
emitter_indent(emitter);
|
||||
emitter_printf(emitter, "%s\n", table_header);
|
||||
emitter_nest_inc(emitter);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_dict_end(emitter_t *emitter) {
|
||||
if (emitter->output == emitter_output_json) {
|
||||
assert(emitter->nesting_depth > 0);
|
||||
emitter_nest_dec(emitter);
|
||||
emitter_printf(emitter, "\n");
|
||||
emitter_indent(emitter);
|
||||
emitter_printf(emitter, "}");
|
||||
} else {
|
||||
emitter_nest_dec(emitter);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_json_dict_begin(emitter_t *emitter, const char *json_key) {
|
||||
if (emitter->output == emitter_output_json) {
|
||||
emitter_dict_begin(emitter, json_key, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_json_dict_end(emitter_t *emitter) {
|
||||
if (emitter->output == emitter_output_json) {
|
||||
emitter_dict_end(emitter);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_table_dict_begin(emitter_t *emitter, const char *table_key) {
|
||||
if (emitter->output == emitter_output_table) {
|
||||
emitter_dict_begin(emitter, NULL, table_key);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_table_dict_end(emitter_t *emitter) {
|
||||
if (emitter->output == emitter_output_table) {
|
||||
emitter_dict_end(emitter);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_json_arr_begin(emitter_t *emitter, const char *json_key) {
|
||||
if (emitter->output == emitter_output_json) {
|
||||
emitter_json_key_prefix(emitter);
|
||||
emitter_printf(emitter, "\"%s\": [", json_key);
|
||||
emitter_nest_inc(emitter);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_json_arr_end(emitter_t *emitter) {
|
||||
if (emitter->output == emitter_output_json) {
|
||||
assert(emitter->nesting_depth > 0);
|
||||
emitter_nest_dec(emitter);
|
||||
emitter_printf(emitter, "\n");
|
||||
emitter_indent(emitter);
|
||||
emitter_printf(emitter, "]");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_json_arr_obj_begin(emitter_t *emitter) {
|
||||
if (emitter->output == emitter_output_json) {
|
||||
emitter_json_key_prefix(emitter);
|
||||
emitter_printf(emitter, "{");
|
||||
emitter_nest_inc(emitter);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_json_arr_obj_end(emitter_t *emitter) {
|
||||
if (emitter->output == emitter_output_json) {
|
||||
assert(emitter->nesting_depth > 0);
|
||||
emitter_nest_dec(emitter);
|
||||
emitter_printf(emitter, "\n");
|
||||
emitter_indent(emitter);
|
||||
emitter_printf(emitter, "}");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_json_arr_value(emitter_t *emitter, emitter_type_t value_type,
|
||||
const void *value) {
|
||||
if (emitter->output == emitter_output_json) {
|
||||
emitter_json_key_prefix(emitter);
|
||||
emitter_print_value(emitter, emitter_justify_none, -1,
|
||||
value_type, value);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
emitter_table_row(emitter_t *emitter, emitter_row_t *row) {
|
||||
if (emitter->output != emitter_output_table) {
|
||||
return;
|
||||
}
|
||||
emitter_col_t *col;
|
||||
ql_foreach(col, &row->cols, link) {
|
||||
emitter_print_value(emitter, col->justify, col->width,
|
||||
col->type, (const void *)&col->bool_val);
|
||||
}
|
||||
emitter_table_printf(emitter, "\n");
|
||||
}
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_EMITTER_H */
|
239
deps/jemalloc/include/jemalloc/internal/extent.h
vendored
239
deps/jemalloc/include/jemalloc/internal/extent.h
vendored
@ -1,239 +0,0 @@
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_TYPES
|
||||
|
||||
typedef struct extent_node_s extent_node_t;
|
||||
|
||||
#endif /* JEMALLOC_H_TYPES */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_STRUCTS
|
||||
|
||||
/* Tree of extents. Use accessor functions for en_* fields. */
|
||||
struct extent_node_s {
|
||||
/* Arena from which this extent came, if any. */
|
||||
arena_t *en_arena;
|
||||
|
||||
/* Pointer to the extent that this tree node is responsible for. */
|
||||
void *en_addr;
|
||||
|
||||
/* Total region size. */
|
||||
size_t en_size;
|
||||
|
||||
/*
|
||||
* The zeroed flag is used by chunk recycling code to track whether
|
||||
* memory is zero-filled.
|
||||
*/
|
||||
bool en_zeroed;
|
||||
|
||||
/*
|
||||
* True if physical memory is committed to the extent, whether
|
||||
* explicitly or implicitly as on a system that overcommits and
|
||||
* satisfies physical memory needs on demand via soft page faults.
|
||||
*/
|
||||
bool en_committed;
|
||||
|
||||
/*
|
||||
* The achunk flag is used to validate that huge allocation lookups
|
||||
* don't return arena chunks.
|
||||
*/
|
||||
bool en_achunk;
|
||||
|
||||
/* Profile counters, used for huge objects. */
|
||||
prof_tctx_t *en_prof_tctx;
|
||||
|
||||
/* Linkage for arena's runs_dirty and chunks_cache rings. */
|
||||
arena_runs_dirty_link_t rd;
|
||||
qr(extent_node_t) cc_link;
|
||||
|
||||
union {
|
||||
/* Linkage for the size/address-ordered tree. */
|
||||
rb_node(extent_node_t) szad_link;
|
||||
|
||||
/* Linkage for arena's huge and node_cache lists. */
|
||||
ql_elm(extent_node_t) ql_link;
|
||||
};
|
||||
|
||||
/* Linkage for the address-ordered tree. */
|
||||
rb_node(extent_node_t) ad_link;
|
||||
};
|
||||
typedef rb_tree(extent_node_t) extent_tree_t;
|
||||
|
||||
#endif /* JEMALLOC_H_STRUCTS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_EXTERNS
|
||||
|
||||
rb_proto(, extent_tree_szad_, extent_tree_t, extent_node_t)
|
||||
|
||||
rb_proto(, extent_tree_ad_, extent_tree_t, extent_node_t)
|
||||
|
||||
#endif /* JEMALLOC_H_EXTERNS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_INLINES
|
||||
|
||||
#ifndef JEMALLOC_ENABLE_INLINE
|
||||
arena_t *extent_node_arena_get(const extent_node_t *node);
|
||||
void *extent_node_addr_get(const extent_node_t *node);
|
||||
size_t extent_node_size_get(const extent_node_t *node);
|
||||
bool extent_node_zeroed_get(const extent_node_t *node);
|
||||
bool extent_node_committed_get(const extent_node_t *node);
|
||||
bool extent_node_achunk_get(const extent_node_t *node);
|
||||
prof_tctx_t *extent_node_prof_tctx_get(const extent_node_t *node);
|
||||
void extent_node_arena_set(extent_node_t *node, arena_t *arena);
|
||||
void extent_node_addr_set(extent_node_t *node, void *addr);
|
||||
void extent_node_size_set(extent_node_t *node, size_t size);
|
||||
void extent_node_zeroed_set(extent_node_t *node, bool zeroed);
|
||||
void extent_node_committed_set(extent_node_t *node, bool committed);
|
||||
void extent_node_achunk_set(extent_node_t *node, bool achunk);
|
||||
void extent_node_prof_tctx_set(extent_node_t *node, prof_tctx_t *tctx);
|
||||
void extent_node_init(extent_node_t *node, arena_t *arena, void *addr,
|
||||
size_t size, bool zeroed, bool committed);
|
||||
void extent_node_dirty_linkage_init(extent_node_t *node);
|
||||
void extent_node_dirty_insert(extent_node_t *node,
|
||||
arena_runs_dirty_link_t *runs_dirty, extent_node_t *chunks_dirty);
|
||||
void extent_node_dirty_remove(extent_node_t *node);
|
||||
#endif
|
||||
|
||||
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_EXTENT_C_))
|
||||
JEMALLOC_INLINE arena_t *
|
||||
extent_node_arena_get(const extent_node_t *node)
|
||||
{
|
||||
|
||||
return (node->en_arena);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void *
|
||||
extent_node_addr_get(const extent_node_t *node)
|
||||
{
|
||||
|
||||
return (node->en_addr);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE size_t
|
||||
extent_node_size_get(const extent_node_t *node)
|
||||
{
|
||||
|
||||
return (node->en_size);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
extent_node_zeroed_get(const extent_node_t *node)
|
||||
{
|
||||
|
||||
return (node->en_zeroed);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
extent_node_committed_get(const extent_node_t *node)
|
||||
{
|
||||
|
||||
assert(!node->en_achunk);
|
||||
return (node->en_committed);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
extent_node_achunk_get(const extent_node_t *node)
|
||||
{
|
||||
|
||||
return (node->en_achunk);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE prof_tctx_t *
|
||||
extent_node_prof_tctx_get(const extent_node_t *node)
|
||||
{
|
||||
|
||||
return (node->en_prof_tctx);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
extent_node_arena_set(extent_node_t *node, arena_t *arena)
|
||||
{
|
||||
|
||||
node->en_arena = arena;
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
extent_node_addr_set(extent_node_t *node, void *addr)
|
||||
{
|
||||
|
||||
node->en_addr = addr;
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
extent_node_size_set(extent_node_t *node, size_t size)
|
||||
{
|
||||
|
||||
node->en_size = size;
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
extent_node_zeroed_set(extent_node_t *node, bool zeroed)
|
||||
{
|
||||
|
||||
node->en_zeroed = zeroed;
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
extent_node_committed_set(extent_node_t *node, bool committed)
|
||||
{
|
||||
|
||||
node->en_committed = committed;
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
extent_node_achunk_set(extent_node_t *node, bool achunk)
|
||||
{
|
||||
|
||||
node->en_achunk = achunk;
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
extent_node_prof_tctx_set(extent_node_t *node, prof_tctx_t *tctx)
|
||||
{
|
||||
|
||||
node->en_prof_tctx = tctx;
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
extent_node_init(extent_node_t *node, arena_t *arena, void *addr, size_t size,
|
||||
bool zeroed, bool committed)
|
||||
{
|
||||
|
||||
extent_node_arena_set(node, arena);
|
||||
extent_node_addr_set(node, addr);
|
||||
extent_node_size_set(node, size);
|
||||
extent_node_zeroed_set(node, zeroed);
|
||||
extent_node_committed_set(node, committed);
|
||||
extent_node_achunk_set(node, false);
|
||||
if (config_prof)
|
||||
extent_node_prof_tctx_set(node, NULL);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
extent_node_dirty_linkage_init(extent_node_t *node)
|
||||
{
|
||||
|
||||
qr_new(&node->rd, rd_link);
|
||||
qr_new(node, cc_link);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
extent_node_dirty_insert(extent_node_t *node,
|
||||
arena_runs_dirty_link_t *runs_dirty, extent_node_t *chunks_dirty)
|
||||
{
|
||||
|
||||
qr_meld(runs_dirty, &node->rd, rd_link);
|
||||
qr_meld(chunks_dirty, node, cc_link);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
extent_node_dirty_remove(extent_node_t *node)
|
||||
{
|
||||
|
||||
qr_remove(&node->rd, rd_link);
|
||||
qr_remove(node, cc_link);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* JEMALLOC_H_INLINES */
|
||||
/******************************************************************************/
|
||||
|
26
deps/jemalloc/include/jemalloc/internal/extent_dss.h
vendored
Normal file
26
deps/jemalloc/include/jemalloc/internal/extent_dss.h
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef JEMALLOC_INTERNAL_EXTENT_DSS_H
|
||||
#define JEMALLOC_INTERNAL_EXTENT_DSS_H
|
||||
|
||||
typedef enum {
|
||||
dss_prec_disabled = 0,
|
||||
dss_prec_primary = 1,
|
||||
dss_prec_secondary = 2,
|
||||
|
||||
dss_prec_limit = 3
|
||||
} dss_prec_t;
|
||||
#define DSS_PREC_DEFAULT dss_prec_secondary
|
||||
#define DSS_DEFAULT "secondary"
|
||||
|
||||
extern const char *dss_prec_names[];
|
||||
|
||||
extern const char *opt_dss;
|
||||
|
||||
dss_prec_t extent_dss_prec_get(void);
|
||||
bool extent_dss_prec_set(dss_prec_t dss_prec);
|
||||
void *extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr,
|
||||
size_t size, size_t alignment, bool *zero, bool *commit);
|
||||
bool extent_in_dss(void *addr);
|
||||
bool extent_dss_mergeable(void *addr_a, void *addr_b);
|
||||
void extent_dss_boot(void);
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_EXTENT_DSS_H */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user