mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-03-26 08:41:47 -07:00
Catch-up merge from master sources at change 193831 to branch/2017-03-04/seg-methods.
Copied from Perforce Change: 193836
This commit is contained in:
commit
de94fe2aa3
84 changed files with 1135 additions and 365 deletions
|
|
@ -193,7 +193,7 @@ static void test_pool(const char *name, mps_pool_t pool, size_t roots_count)
|
|||
size_t condemned = mps_message_gc_condemned_size(arena, msg);
|
||||
size_t not_condemned = mps_message_gc_not_condemned_size(arena, msg);
|
||||
|
||||
printf("\nCollection %lu finished:\n", collections++);
|
||||
printf("\nCollection %lu finished:\n", (unsigned long)collections++);
|
||||
printf("live %"PRIuLONGEST"\n", (ulongest_t)live);
|
||||
printf("condemned %"PRIuLONGEST"\n", (ulongest_t)condemned);
|
||||
printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned);
|
||||
|
|
|
|||
|
|
@ -266,6 +266,7 @@ TEST_TARGETS=\
|
|||
expt825 \
|
||||
finalcv \
|
||||
finaltest \
|
||||
forktest \
|
||||
fotest \
|
||||
gcbench \
|
||||
landtest \
|
||||
|
|
@ -499,6 +500,9 @@ $(PFM)/$(VARIETY)/finalcv: $(PFM)/$(VARIETY)/finalcv.o \
|
|||
$(PFM)/$(VARIETY)/finaltest: $(PFM)/$(VARIETY)/finaltest.o \
|
||||
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/forktest: $(PFM)/$(VARIETY)/forktest.o \
|
||||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/fotest: $(PFM)/$(VARIETY)/fotest.o \
|
||||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* config.h: MPS CONFIGURATION
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001-2017 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2001-2018 Ravenbrook Limited. See end of file for license.
|
||||
* Portions copyright (c) 2002 Global Graphics Software.
|
||||
*
|
||||
* PURPOSE
|
||||
|
|
@ -546,7 +546,7 @@
|
|||
#endif
|
||||
|
||||
|
||||
/* .feature.xc: OS X feature specification
|
||||
/* .feature.xc: macOS feature specification
|
||||
*
|
||||
* The MPS needs the following symbols which are not defined by default
|
||||
*
|
||||
|
|
@ -589,7 +589,7 @@
|
|||
|
||||
#else
|
||||
|
||||
#error "Unknown OS X architecture"
|
||||
#error "Unknown macOS architecture"
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -694,7 +694,7 @@
|
|||
*
|
||||
* TODO: These settings were determined by trial and error, but should
|
||||
* be based on measurement of the protection overhead on each
|
||||
* platform. We know it's extremely different between OS X and
|
||||
* platform. We know it's extremely different between macOS and
|
||||
* Windows, for example. See design.mps.write-barrier.improv.by-os.
|
||||
*
|
||||
* TODO: Consider basing the count on the amount of time that has
|
||||
|
|
@ -712,7 +712,7 @@
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2017 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2001-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eventpy.c: GENERATE PYTHON INTERFACE TO EVENTS
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2016 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2016-2018 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* This command-line program emits Python data structures that can be
|
||||
* used to parse an event stream in text format (as output by the
|
||||
|
|
@ -22,37 +22,37 @@ int main(int argc, char *argv[])
|
|||
printf("__version__ = %d, %d, %d\n", EVENT_VERSION_MAJOR,
|
||||
EVENT_VERSION_MEDIAN, EVENT_VERSION_MINOR);
|
||||
|
||||
puts("EventKind = namedtuple('EventKind', 'name code doc')");
|
||||
puts("class kind:");
|
||||
puts("KindDesc = namedtuple('KindDesc', 'name code doc')");
|
||||
puts("class Kind:");
|
||||
#define ENUM(_, NAME, DOC) \
|
||||
printf(" " #NAME " = EventKind('" #NAME "', %d, \"%s\")\n", \
|
||||
printf(" " #NAME " = KindDesc('" #NAME "', %d, \"%s\")\n", \
|
||||
EventKind ## NAME, DOC);
|
||||
EventKindENUM(ENUM, _);
|
||||
#undef ENUM
|
||||
|
||||
puts("kinds = {");
|
||||
puts("KIND = {");
|
||||
#define ENUM(_, NAME, _1) \
|
||||
printf(" %d: kind." #NAME ",\n", EventKind ## NAME);
|
||||
printf(" %d: Kind." #NAME ",\n", EventKind ## NAME);
|
||||
EventKindENUM(ENUM, _);
|
||||
#undef ENUM
|
||||
puts("}");
|
||||
|
||||
puts("EventParam = namedtuple('EventParam', 'sort, name')");
|
||||
puts("Event = namedtuple('Event', 'name code always kind params')");
|
||||
puts("class event:");
|
||||
puts("EventParam = namedtuple('EventParam', 'sort name')");
|
||||
puts("EventDesc = namedtuple('EventDesc', 'name code always kind params')");
|
||||
puts("class Event:");
|
||||
#define EVENT_PARAM(X, INDEX, SORT, NAME) \
|
||||
puts(" EventParam('" #SORT "', '" #NAME "'),");
|
||||
#define EVENT_DEFINE(X, NAME, CODE, ALWAYS, KIND) \
|
||||
printf(" " #NAME " = Event('" #NAME "', %d, %s, kind." #KIND ", [\n", \
|
||||
printf(" " #NAME " = EventDesc('" #NAME "', %d, %s, Kind." #KIND ", [\n", \
|
||||
CODE, ALWAYS ? "True" : "False"); \
|
||||
EVENT_ ## NAME ## _PARAMS(EVENT_PARAM, X); \
|
||||
puts(" ]);");
|
||||
puts(" ])");
|
||||
EVENT_LIST(EVENT_DEFINE, 0);
|
||||
#undef EVENT
|
||||
|
||||
puts("events = {");
|
||||
puts("EVENT = {");
|
||||
#define EVENT_ITEM(X, NAME, CODE, ALWAYS, KIND) \
|
||||
printf(" %d: event." #NAME ",\n", CODE);
|
||||
printf(" %d: Event." #NAME ",\n", CODE);
|
||||
EVENT_LIST(EVENT_ITEM, 0);
|
||||
#undef EVENT
|
||||
puts("}");
|
||||
|
|
@ -63,7 +63,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (c) 2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (c) 2016-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* fmtdy.c: DYLAN OBJECT FORMAT IMPLEMENTATION
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2001-2018 Ravenbrook Limited. See end of file for license.
|
||||
* Portions copyright (c) 2002 Global Graphics Software.
|
||||
*
|
||||
* .readership: MPS developers, Dylan developers
|
||||
|
|
@ -407,8 +407,11 @@ extern mps_res_t dylan_scan1(mps_ss_t mps_ss, mps_addr_t *object_io)
|
|||
return MPS_RES_OK;
|
||||
}
|
||||
|
||||
res = mps_fix(mps_ss, p); /* fix the wrapper */
|
||||
if ( res != MPS_RES_OK ) return res;
|
||||
MPS_SCAN_BEGIN(mps_ss) {
|
||||
res = MPS_FIX12(mps_ss, p); /* fix the wrapper */
|
||||
} MPS_SCAN_END(mps_ss);
|
||||
if (res != MPS_RES_OK)
|
||||
return res;
|
||||
w = (mps_word_t *)p[0]; /* wrapper is header word */
|
||||
assert(dylan_wrapper_check(w));
|
||||
|
||||
|
|
@ -567,8 +570,11 @@ extern mps_res_t dylan_scan1_weak(mps_ss_t mps_ss, mps_addr_t *object_io)
|
|||
assert((h & 3) == 0);
|
||||
unused(h);
|
||||
|
||||
res = mps_fix(mps_ss, p);
|
||||
if ( res != MPS_RES_OK ) return res;
|
||||
MPS_SCAN_BEGIN(mps_ss) {
|
||||
res = MPS_FIX12(mps_ss, p);
|
||||
} MPS_SCAN_END(mps_ss);
|
||||
if (res != MPS_RES_OK)
|
||||
return res;
|
||||
|
||||
/* w points to wrapper */
|
||||
w = (mps_word_t *)p[0];
|
||||
|
|
@ -852,7 +858,7 @@ mps_res_t dylan_fmt_weak(mps_fmt_t *mps_fmt_o, mps_arena_t arena)
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2001-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
231
mps/code/forktest.c
Normal file
231
mps/code/forktest.c
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
/* forktest.c: FORK SAFETY TEST
|
||||
*
|
||||
* $Id: //info.ravenbrook.com/project/mps/branch/2018-06-13/fork/code/tagtest.c#1 $
|
||||
* Copyright (c) 2018 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .overview: This test case is a regression test for job004062. It
|
||||
* checks that the MPS correctly runs in the child process after a
|
||||
* fork() on FreeBSD, Linux or macOS.
|
||||
*
|
||||
* .format: This test case uses a trivial object format in which each
|
||||
* object contains a single reference.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mps.h"
|
||||
#include "mpsavm.h"
|
||||
#include "mpscamc.h"
|
||||
#include "testlib.h"
|
||||
|
||||
enum {
|
||||
TYPE_REF,
|
||||
TYPE_FWD,
|
||||
TYPE_PAD
|
||||
};
|
||||
|
||||
typedef struct obj_s {
|
||||
unsigned type; /* One of the TYPE_ enums */
|
||||
union {
|
||||
struct obj_s *ref; /* TYPE_REF */
|
||||
mps_addr_t fwd; /* TYPE_FWD */
|
||||
size_t pad; /* TYPE_PAD */
|
||||
} u;
|
||||
} obj_s, *obj_t;
|
||||
|
||||
static void obj_fwd(mps_addr_t old, mps_addr_t new)
|
||||
{
|
||||
obj_t obj = old;
|
||||
obj->type = TYPE_FWD;
|
||||
obj->u.fwd = new;
|
||||
}
|
||||
|
||||
static mps_addr_t obj_isfwd(mps_addr_t addr)
|
||||
{
|
||||
obj_t obj = addr;
|
||||
if (obj->type == TYPE_FWD) {
|
||||
return obj->u.fwd;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void obj_pad(mps_addr_t addr, size_t size)
|
||||
{
|
||||
obj_t obj = addr;
|
||||
obj->type = TYPE_PAD;
|
||||
obj->u.pad = size;
|
||||
}
|
||||
|
||||
static mps_addr_t obj_skip(mps_addr_t addr)
|
||||
{
|
||||
obj_t obj = addr;
|
||||
size_t size;
|
||||
if (obj->type == TYPE_PAD) {
|
||||
size = obj->u.pad;
|
||||
} else {
|
||||
size = sizeof(obj_s);
|
||||
}
|
||||
return (char *)addr + size;
|
||||
}
|
||||
|
||||
static mps_res_t obj_scan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
||||
{
|
||||
MPS_SCAN_BEGIN(ss) {
|
||||
while (base < limit) {
|
||||
obj_t obj = base;
|
||||
if (obj->type == TYPE_REF) {
|
||||
mps_addr_t p = obj->u.ref;
|
||||
mps_res_t res = MPS_FIX12(ss, &p);
|
||||
if (res != MPS_RES_OK) {
|
||||
return res;
|
||||
}
|
||||
obj->u.ref = p;
|
||||
}
|
||||
base = obj_skip(base);
|
||||
}
|
||||
} MPS_SCAN_END(ss);
|
||||
return MPS_RES_OK;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
void *marker = ▮
|
||||
int pid;
|
||||
mps_arena_t arena;
|
||||
mps_fmt_t obj_fmt;
|
||||
mps_pool_t pool;
|
||||
mps_thr_t thread;
|
||||
mps_root_t stack_root;
|
||||
mps_ap_t obj_ap;
|
||||
size_t i;
|
||||
obj_t obj, first;
|
||||
|
||||
testlib_init(argc, argv);
|
||||
|
||||
/* Set the pause time to be very small so that the incremental
|
||||
collector (when it runs) will have to leave a read barrier in
|
||||
place for us to hit. */
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, MPS_KEY_PAUSE_TIME, 0.0);
|
||||
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args),
|
||||
"mps_arena_create");
|
||||
} MPS_ARGS_END(args);
|
||||
mps_arena_park(arena);
|
||||
|
||||
die(mps_thread_reg(&thread, arena), "Couldn't register thread");
|
||||
die(mps_root_create_thread(&stack_root, arena, thread, marker),
|
||||
"Couldn't create thread root");
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, MPS_KEY_FMT_ALIGN, sizeof(obj_s));
|
||||
MPS_ARGS_ADD(args, MPS_KEY_FMT_SCAN, obj_scan);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_FMT_SKIP, obj_skip);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_FMT_FWD, obj_fwd);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_FMT_ISFWD, obj_isfwd);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_FMT_PAD, obj_pad);
|
||||
die(mps_fmt_create_k(&obj_fmt, arena, args), "Couldn't create obj format");
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, MPS_KEY_FORMAT, obj_fmt);
|
||||
die(mps_pool_create_k(&pool, arena, mps_class_amc(), args),
|
||||
"Couldn't create pool");
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
die(mps_ap_create_k(&obj_ap, pool, mps_args_none),
|
||||
"Couldn't create obj allocation point");
|
||||
|
||||
/* Create a linked list of objects. */
|
||||
first = NULL;
|
||||
for (i = 0; i < 100000; ++i) {
|
||||
size_t size = sizeof(obj_s);
|
||||
mps_addr_t addr;
|
||||
do {
|
||||
die(mps_reserve(&addr, obj_ap, size), "Couldn't allocate.");
|
||||
obj = addr;
|
||||
obj->type = TYPE_REF;
|
||||
obj->u.ref = NULL;
|
||||
} while (!mps_commit(obj_ap, addr, size));
|
||||
obj->u.ref = first;
|
||||
first = obj;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
cdie(pid >= 0, "fork failed");
|
||||
|
||||
/* Allow a collection to start, which will cause a read barrier to
|
||||
be applied to any segment containing live objects that was
|
||||
scanned. */
|
||||
mps_arena_release(arena);
|
||||
|
||||
/* Read all the objects, so that if there is read barrier in place
|
||||
we will hit it. */
|
||||
for (obj = first; obj != NULL; obj = obj->u.ref) {
|
||||
Insist(obj->type == TYPE_REF);
|
||||
}
|
||||
|
||||
mps_arena_park(arena);
|
||||
|
||||
if (pid != 0) {
|
||||
/* Parent: wait for child and check that its exit status is zero. */
|
||||
int stat;
|
||||
cdie(pid == waitpid(pid, &stat, 0), "waitpid failed");
|
||||
cdie(WIFEXITED(stat), "child did not exit normally");
|
||||
cdie(WEXITSTATUS(stat) == 0, "child exited with nonzero status");
|
||||
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
|
||||
}
|
||||
|
||||
mps_ap_destroy(obj_ap);
|
||||
mps_pool_destroy(pool);
|
||||
mps_fmt_destroy(obj_fmt);
|
||||
mps_root_destroy(stack_root);
|
||||
mps_thread_dereg(thread);
|
||||
mps_arena_destroy(arena);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (c) 2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. 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.
|
||||
*
|
||||
* 3. Redistributions in any form must be accompanied by information on how
|
||||
* to obtain complete source code for this software and any accompanying
|
||||
* software that uses this software. The source code must either be
|
||||
* included in the distribution or be available for no more than the cost
|
||||
* of distribution plus a nominal fee, and must be freely redistributable
|
||||
* under reasonable conditions. For an executable file, complete source
|
||||
* code means the source code for all modules it contains. It does not
|
||||
* include source code for modules or files that typically accompany the
|
||||
* major components of the operating system on which the executable file
|
||||
* runs.
|
||||
*
|
||||
* 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, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDERS AND 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.
|
||||
*/
|
||||
|
|
@ -53,6 +53,45 @@ static void arenaReleaseRingLock(void)
|
|||
}
|
||||
|
||||
|
||||
/* GlobalsClaimAll -- claim all MPS locks <design/thread-safety/#fork.lock> */
|
||||
|
||||
void GlobalsClaimAll(void)
|
||||
{
|
||||
LockClaimGlobalRecursive();
|
||||
arenaClaimRingLock();
|
||||
GlobalsArenaMap(ArenaEnter);
|
||||
}
|
||||
|
||||
/* GlobalsReleaseAll -- release all MPS locks. GlobalsClaimAll must
|
||||
* previously have been called. <design/thread-safety/#sol.fork.lock> */
|
||||
|
||||
void GlobalsReleaseAll(void)
|
||||
{
|
||||
GlobalsArenaMap(ArenaLeave);
|
||||
arenaReleaseRingLock();
|
||||
LockReleaseGlobalRecursive();
|
||||
}
|
||||
|
||||
/* arenaReinitLock -- reinitialize the lock for an arena */
|
||||
|
||||
static void arenaReinitLock(Arena arena)
|
||||
{
|
||||
AVERT(Arena, arena);
|
||||
ShieldLeave(arena);
|
||||
LockInit(ArenaGlobals(arena)->lock);
|
||||
}
|
||||
|
||||
/* GlobalsReinitializeAll -- reinitialize all MPS locks, and leave the
|
||||
* shield for all arenas. GlobalsClaimAll must previously have been
|
||||
* called. <design/thread-safety/#sol.fork.lock> */
|
||||
|
||||
void GlobalsReinitializeAll(void)
|
||||
{
|
||||
GlobalsArenaMap(arenaReinitLock);
|
||||
LockInitGlobal();
|
||||
}
|
||||
|
||||
|
||||
/* arenaAnnounce -- add a new arena into the global ring of arenas
|
||||
*
|
||||
* On entry, the arena must not be locked (there should be no need,
|
||||
|
|
@ -100,6 +139,21 @@ static void arenaDenounce(Arena arena)
|
|||
}
|
||||
|
||||
|
||||
/* GlobalsArenaMap -- map a function over the arenas. The caller must
|
||||
* have acquired the ring lock. */
|
||||
|
||||
void GlobalsArenaMap(void (*func)(Arena arena))
|
||||
{
|
||||
Ring node, nextNode;
|
||||
AVERT(Ring, &arenaRing);
|
||||
RING_FOR(node, &arenaRing, nextNode) {
|
||||
Globals arenaGlobals = RING_ELT(Globals, globalRing, node);
|
||||
Arena arena = GlobalsArena(arenaGlobals);
|
||||
func(arena);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* GlobalsCheck -- check the arena globals */
|
||||
|
||||
Bool GlobalsCheck(Globals arenaGlobals)
|
||||
|
|
@ -221,7 +275,13 @@ Res GlobalsInit(Globals arenaGlobals)
|
|||
arenaRingInit = TRUE;
|
||||
RingInit(&arenaRing);
|
||||
arenaSerial = (Serial)0;
|
||||
/* The setup functions call pthread_atfork (on the appropriate
|
||||
platforms) and so must be called in the correct order. Here we
|
||||
require the locks to be taken first in the "prepare" case and
|
||||
released last in the "parent" and "child" cases. */
|
||||
ThreadSetup();
|
||||
ProtSetup();
|
||||
LockSetup();
|
||||
}
|
||||
arena = GlobalsArena(arenaGlobals);
|
||||
/* Ensure updates to arenaSerial do not race by doing the update
|
||||
|
|
|
|||
|
|
@ -21,6 +21,11 @@
|
|||
extern size_t LockSize(void);
|
||||
|
||||
|
||||
/* LockInitGlobal -- initialize global locks */
|
||||
|
||||
extern void LockInitGlobal(void);
|
||||
|
||||
|
||||
/* LockInit/Finish
|
||||
*
|
||||
* lock points to the allocated lock structure. A lock has no
|
||||
|
|
@ -128,6 +133,11 @@ extern void LockClaimGlobal(void);
|
|||
extern void LockReleaseGlobal(void);
|
||||
|
||||
|
||||
/* LockSetup -- one-time lock initialization */
|
||||
|
||||
extern void LockSetup(void);
|
||||
|
||||
|
||||
#endif /* lock_h */
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,13 @@ static Lock globalLock = &globalLockStruct;
|
|||
|
||||
static Lock globalRecLock = &globalRecursiveLockStruct;
|
||||
|
||||
void LockInitGlobal(void)
|
||||
{
|
||||
globalLock->claims = 0;
|
||||
LockInit(globalLock);
|
||||
globalRecLock->claims = 0;
|
||||
LockInit(globalRecLock);
|
||||
}
|
||||
|
||||
void (LockClaimGlobalRecursive)(void)
|
||||
{
|
||||
|
|
@ -127,6 +134,11 @@ void (LockReleaseGlobal)(void)
|
|||
LockRelease(globalLock);
|
||||
}
|
||||
|
||||
void LockSetup(void)
|
||||
{
|
||||
/* Nothing to do as ANSI platform does not have fork(). */
|
||||
}
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* lockix.c: RECURSIVE LOCKS FOR POSIX SYSTEMS
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2001-2018 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .posix: The implementation uses a POSIX interface, and should be reusable
|
||||
* for many Unix-like operating systems.
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
* .freebsd: This implementation supports FreeBSD (platform
|
||||
* MPS_OS_FR).
|
||||
*
|
||||
* .darwin: This implementation supports Darwin (OS X) (platform
|
||||
* .darwin: This implementation supports Darwin (macOS) (platform
|
||||
* MPS_OS_XC).
|
||||
*
|
||||
* .design: These locks are implemented using mutexes.
|
||||
|
|
@ -212,7 +212,7 @@ static Lock globalLock = &globalLockStruct;
|
|||
static Lock globalRecLock = &globalRecLockStruct;
|
||||
static pthread_once_t isGlobalLockInit = PTHREAD_ONCE_INIT;
|
||||
|
||||
static void globalLockInit(void)
|
||||
void LockInitGlobal(void)
|
||||
{
|
||||
LockInit(globalLock);
|
||||
LockInit(globalRecLock);
|
||||
|
|
@ -226,7 +226,7 @@ void (LockClaimGlobalRecursive)(void)
|
|||
int res;
|
||||
|
||||
/* Ensure the global lock has been initialized */
|
||||
res = pthread_once(&isGlobalLockInit, globalLockInit);
|
||||
res = pthread_once(&isGlobalLockInit, LockInitGlobal);
|
||||
AVER(res == 0);
|
||||
LockClaimRecursive(globalRecLock);
|
||||
}
|
||||
|
|
@ -247,7 +247,7 @@ void (LockClaimGlobal)(void)
|
|||
int res;
|
||||
|
||||
/* Ensure the global lock has been initialized */
|
||||
res = pthread_once(&isGlobalLockInit, globalLockInit);
|
||||
res = pthread_once(&isGlobalLockInit, LockInitGlobal);
|
||||
AVER(res == 0);
|
||||
LockClaim(globalLock);
|
||||
}
|
||||
|
|
@ -261,6 +261,16 @@ void (LockReleaseGlobal)(void)
|
|||
}
|
||||
|
||||
|
||||
/* LockSetup -- one-time lock initialization */
|
||||
|
||||
void LockSetup(void)
|
||||
{
|
||||
/* Claim all locks before a fork; release in the parent;
|
||||
reinitialize in the child <design/thread-safety/#sol.fork.lock> */
|
||||
pthread_atfork(GlobalsClaimAll, GlobalsReleaseAll, GlobalsReinitializeAll);
|
||||
}
|
||||
|
||||
|
||||
#elif defined(LOCK_NONE)
|
||||
#include "lockan.c"
|
||||
#else
|
||||
|
|
@ -270,7 +280,7 @@ void (LockReleaseGlobal)(void)
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2001-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -127,15 +127,21 @@ static Lock globalLock = &globalLockStruct;
|
|||
static Lock globalRecLock = &globalRecLockStruct;
|
||||
static Bool globalLockInit = FALSE; /* TRUE iff initialized */
|
||||
|
||||
void LockInitGlobal(void)
|
||||
{
|
||||
globalLock->claims = 0;
|
||||
LockInit(globalLock);
|
||||
globalRecLock->claims = 0;
|
||||
LockInit(globalRecLock);
|
||||
globalLockInit = TRUE;
|
||||
}
|
||||
|
||||
static void lockEnsureGlobalLock(void)
|
||||
{
|
||||
/* Ensure both global locks have been initialized. */
|
||||
/* There is a race condition initializing them. */
|
||||
/* There is a race condition initializing them (job004056). */
|
||||
if (!globalLockInit) {
|
||||
LockInit(globalLock);
|
||||
LockInit(globalRecLock);
|
||||
globalLockInit = TRUE;
|
||||
LockInitGlobal();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -165,6 +171,10 @@ void (LockReleaseGlobal)(void)
|
|||
LockRelease(globalLock);
|
||||
}
|
||||
|
||||
void LockSetup(void)
|
||||
{
|
||||
/* Nothing to do as MPS does not support fork() on Windows. */
|
||||
}
|
||||
|
||||
#elif defined(LOCK_NONE)
|
||||
#include "lockan.c"
|
||||
|
|
|
|||
|
|
@ -469,6 +469,10 @@ extern Res GlobalsCompleteCreate(Globals arenaGlobals);
|
|||
extern void GlobalsPrepareToDestroy(Globals arenaGlobals);
|
||||
extern Res GlobalsDescribe(Globals arena, mps_lib_FILE *stream, Count depth);
|
||||
extern Ring GlobalsRememberedSummaryRing(Globals);
|
||||
extern void GlobalsArenaMap(void (*func)(Arena arena));
|
||||
extern void GlobalsClaimAll(void);
|
||||
extern void GlobalsReleaseAll(void);
|
||||
extern void GlobalsReinitializeAll(void);
|
||||
|
||||
#define ArenaGlobals(arena) (&(arena)->globals)
|
||||
#define GlobalsArena(glob) PARENT(ArenaStruct, globals, glob)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
/* mps.c: MEMORY POOL SYSTEM ALL-IN-ONE TRANSLATION UNIT
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (C) 2012-2016 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (C) 2012-2018 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .purpose: This file can be compiled to create the complete MPS library in
|
||||
* a single compilation, allowing the compiler to apply global optimizations
|
||||
* and inlining effectively. On most modern compilers this is also faster
|
||||
* than compiling each file separately.
|
||||
*
|
||||
* .purpose.universal: This file also allows simple building of a Mac OS X
|
||||
* .purpose.universal: This file also allows simple building of a macOS
|
||||
* "universal" (multiple architecture) binary when the set of source files
|
||||
* differs by architecture. It may work for other platforms in a similar
|
||||
* manner.
|
||||
|
|
@ -111,33 +111,33 @@
|
|||
#include "span.c" /* generic stack probe */
|
||||
#include "ssan.c" /* generic stack scanner */
|
||||
|
||||
/* Mac OS X on 32-bit Intel built with Clang or GCC */
|
||||
/* macOS on 32-bit Intel built with Clang or GCC */
|
||||
|
||||
#elif defined(MPS_PF_XCI3LL) || defined(MPS_PF_XCI3GC)
|
||||
|
||||
#include "lockix.c" /* Posix locks */
|
||||
#include "thxc.c" /* OS X Mach threading */
|
||||
#include "thxc.c" /* macOS Mach threading */
|
||||
#include "vmix.c" /* Posix virtual memory */
|
||||
#include "protix.c" /* Posix protection */
|
||||
#include "protxc.c" /* OS X Mach exception handling */
|
||||
#include "protxc.c" /* macOS Mach exception handling */
|
||||
#include "prmci3.c" /* 32-bit Intel mutator context decoding */
|
||||
#include "prmcxc.c" /* Mac OS X mutator context */
|
||||
#include "prmcxci3.c" /* 32-bit Intel for Mac OS X mutator context */
|
||||
#include "prmcxc.c" /* macOS mutator context */
|
||||
#include "prmcxci3.c" /* 32-bit Intel for macOS mutator context */
|
||||
#include "span.c" /* generic stack probe */
|
||||
#include "ssixi3.c" /* Posix on 32-bit Intel stack scan */
|
||||
|
||||
/* Mac OS X on 64-bit Intel build with Clang or GCC */
|
||||
/* macOS on 64-bit Intel build with Clang or GCC */
|
||||
|
||||
#elif defined(MPS_PF_XCI6LL) || defined(MPS_PF_XCI6GC)
|
||||
|
||||
#include "lockix.c" /* Posix locks */
|
||||
#include "thxc.c" /* OS X Mach threading */
|
||||
#include "thxc.c" /* macOS Mach threading */
|
||||
#include "vmix.c" /* Posix virtual memory */
|
||||
#include "protix.c" /* Posix protection */
|
||||
#include "protxc.c" /* OS X Mach exception handling */
|
||||
#include "protxc.c" /* macOS Mach exception handling */
|
||||
#include "prmci6.c" /* 64-bit Intel mutator context decoding */
|
||||
#include "prmcxc.c" /* Mac OS X mutator context */
|
||||
#include "prmcxci6.c" /* 64-bit Intel for Mac OS X mutator context */
|
||||
#include "prmcxc.c" /* macOS mutator context */
|
||||
#include "prmcxci6.c" /* 64-bit Intel for macOS mutator context */
|
||||
#include "span.c" /* generic stack probe */
|
||||
#include "ssixi6.c" /* Posix on 64-bit Intel stack scan */
|
||||
|
||||
|
|
@ -275,7 +275,7 @@
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2012-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2012-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@
|
|||
2291A5E8175CB20E001D4920 /* PBXTargetDependency */,
|
||||
3114A5CC156E932C001E0AA3 /* PBXTargetDependency */,
|
||||
3114A5EA156E93C4001E0AA3 /* PBXTargetDependency */,
|
||||
22EA3F4820D2B23F0065F5B6 /* PBXTargetDependency */,
|
||||
224CC79D175E187C002FF81B /* PBXTargetDependency */,
|
||||
22B2BC3F18B643B700C33E63 /* PBXTargetDependency */,
|
||||
3114A65B156E95B4001E0AA3 /* PBXTargetDependency */,
|
||||
|
|
@ -172,6 +173,9 @@
|
|||
22C2ACA718BE400A006B3677 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
|
||||
22C2ACA918BE400A006B3677 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
|
||||
22C2ACB018BE4049006B3677 /* nailboardtest.c in Sources */ = {isa = PBXBuildFile; fileRef = 22C2ACA018BE3FEC006B3677 /* nailboardtest.c */; };
|
||||
22EA3F3D20D2B0D90065F5B6 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
|
||||
22EA3F3F20D2B0D90065F5B6 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
|
||||
22EA3F4620D2B0FD0065F5B6 /* forktest.c in Sources */ = {isa = PBXBuildFile; fileRef = 22EA3F3720D2B0730065F5B6 /* forktest.c */; };
|
||||
22F846B518F437B900982BA7 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
|
||||
22F846B718F437B900982BA7 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
|
||||
22F846BE18F437D700982BA7 /* lockut.c in Sources */ = {isa = PBXBuildFile; fileRef = 22F846AF18F4379C00982BA7 /* lockut.c */; };
|
||||
|
|
@ -531,6 +535,20 @@
|
|||
remoteGlobalIDString = 3104AFF1156D37A0000A585A;
|
||||
remoteInfo = all;
|
||||
};
|
||||
22EA3F3A20D2B0D90065F5B6 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 31EEABFA156AAF9D00714D05;
|
||||
remoteInfo = mps;
|
||||
};
|
||||
22EA3F4720D2B23F0065F5B6 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 22EA3F3820D2B0D90065F5B6;
|
||||
remoteInfo = forktest;
|
||||
};
|
||||
22F846B218F437B900982BA7 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
|
||||
|
|
@ -1098,6 +1116,15 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
};
|
||||
22EA3F4020D2B0D90065F5B6 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = /usr/share/man/man1/;
|
||||
dstSubfolderSpec = 0;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
};
|
||||
22F846B818F437B900982BA7 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
|
@ -1491,6 +1518,8 @@
|
|||
22DD93E218ED815F00240DD2 /* land.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = land.txt; path = ../design/land.txt; sourceTree = "<group>"; };
|
||||
22E30E821886FF1400D98EA9 /* nailboard.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nailboard.c; sourceTree = "<group>"; };
|
||||
22E30E831886FF1400D98EA9 /* nailboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nailboard.h; sourceTree = "<group>"; };
|
||||
22EA3F3720D2B0730065F5B6 /* forktest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = forktest.c; sourceTree = "<group>"; };
|
||||
22EA3F4520D2B0D90065F5B6 /* forktest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = forktest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
22F846AF18F4379C00982BA7 /* lockut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lockut.c; sourceTree = "<group>"; };
|
||||
22F846BD18F437B900982BA7 /* lockut */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lockut; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
22FA177516E8D6FC0098B23F /* amcssth */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = amcssth; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
|
@ -1569,6 +1598,7 @@
|
|||
31160D971899540D0071EB17 /* buffer.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = buffer.txt; path = ../design/buffer.txt; sourceTree = "<group>"; };
|
||||
31160D981899540D0071EB17 /* cbs.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = cbs.txt; path = ../design/cbs.txt; sourceTree = "<group>"; };
|
||||
31160D991899540D0071EB17 /* check.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = check.txt; path = ../design/check.txt; sourceTree = "<group>"; };
|
||||
31160D9A1899540D0071EB17 /* pool.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = pool.txt; path = ../design/pool.txt; sourceTree = "<group>"; };
|
||||
31160D9B1899540D0071EB17 /* collection.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = collection.txt; path = ../design/collection.txt; sourceTree = "<group>"; };
|
||||
31160D9C1899540D0071EB17 /* config.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = config.txt; path = ../design/config.txt; sourceTree = "<group>"; };
|
||||
31160D9D1899540D0071EB17 /* critical-path.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "critical-path.txt"; path = "../design/critical-path.txt"; sourceTree = "<group>"; };
|
||||
|
|
@ -1588,7 +1618,6 @@
|
|||
31160DAB1899540D0071EB17 /* message-gc.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "message-gc.txt"; path = "../design/message-gc.txt"; sourceTree = "<group>"; };
|
||||
31160DAC1899540D0071EB17 /* message.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = message.txt; path = ../design/message.txt; sourceTree = "<group>"; };
|
||||
31160DAD1899540D0071EB17 /* object-debug.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "object-debug.txt"; path = "../design/object-debug.txt"; sourceTree = "<group>"; };
|
||||
31160D9A1899540D0071EB17 /* pool.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "pool.txt"; path = "../design/pool.txt"; sourceTree = "<group>"; };
|
||||
31160DAF1899540D0071EB17 /* poolamc.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = poolamc.txt; path = ../design/poolamc.txt; sourceTree = "<group>"; };
|
||||
31160DB01899540D0071EB17 /* poolams.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = poolams.txt; path = ../design/poolams.txt; sourceTree = "<group>"; };
|
||||
31160DB11899540D0071EB17 /* poolawl.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = poolawl.txt; path = ../design/poolawl.txt; sourceTree = "<group>"; };
|
||||
|
|
@ -1852,6 +1881,14 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
22EA3F3E20D2B0D90065F5B6 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
22EA3F3F20D2B0D90065F5B6 /* libmps.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
22F846B618F437B900982BA7 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
|
@ -2324,6 +2361,7 @@
|
|||
22FACED5188807FF000FDBC1 /* fmtno.h */,
|
||||
22FACED6188807FF000FDBC1 /* fmtscheme.c */,
|
||||
22FACED7188807FF000FDBC1 /* fmtscheme.h */,
|
||||
22EA3F3720D2B0730065F5B6 /* forktest.c */,
|
||||
224CC79E175E3202002FF81B /* fotest.c */,
|
||||
2291A5E9175CB4EC001D4920 /* landtest.c */,
|
||||
2231BB6818CA9834002D6322 /* locbwcss.c */,
|
||||
|
|
@ -2442,6 +2480,7 @@
|
|||
22F846BD18F437B900982BA7 /* lockut */,
|
||||
31108A471C6B90E900E728EA /* tagtest */,
|
||||
223E796519EAB00B00DC26A6 /* sncss */,
|
||||
22EA3F4520D2B0D90065F5B6 /* forktest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -2789,6 +2828,24 @@
|
|||
productReference = 22C2ACAF18BE400A006B3677 /* nailboardtest */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
22EA3F3820D2B0D90065F5B6 /* forktest */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 22EA3F4120D2B0D90065F5B6 /* Build configuration list for PBXNativeTarget "forktest" */;
|
||||
buildPhases = (
|
||||
22EA3F3B20D2B0D90065F5B6 /* Sources */,
|
||||
22EA3F3E20D2B0D90065F5B6 /* Frameworks */,
|
||||
22EA3F4020D2B0D90065F5B6 /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
22EA3F3920D2B0D90065F5B6 /* PBXTargetDependency */,
|
||||
);
|
||||
name = forktest;
|
||||
productName = mv2test;
|
||||
productReference = 22EA3F4520D2B0D90065F5B6 /* forktest */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
22F846B018F437B900982BA7 /* lockut */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 22F846B918F437B900982BA7 /* Build configuration list for PBXNativeTarget "lockut" */;
|
||||
|
|
@ -3549,6 +3606,7 @@
|
|||
2291A5C1175CAFCA001D4920 /* expt825 */,
|
||||
3114A5BC156E9315001E0AA3 /* finalcv */,
|
||||
3114A5D5156E93A0001E0AA3 /* finaltest */,
|
||||
22EA3F3820D2B0D90065F5B6 /* forktest */,
|
||||
224CC78C175E1821002FF81B /* fotest */,
|
||||
6313D46718A400B200EB03EF /* gcbench */,
|
||||
3114A64B156E9596001E0AA3 /* landtest */,
|
||||
|
|
@ -3748,6 +3806,15 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
22EA3F3B20D2B0D90065F5B6 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
22EA3F4620D2B0FD0065F5B6 /* forktest.c in Sources */,
|
||||
22EA3F3D20D2B0D90065F5B6 /* testlib.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
22F846B318F437B900982BA7 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
|
@ -4303,6 +4370,16 @@
|
|||
target = 3104AFF1156D37A0000A585A /* all */;
|
||||
targetProxy = 22CDE92D16E9EB9300366D0A /* PBXContainerItemProxy */;
|
||||
};
|
||||
22EA3F3920D2B0D90065F5B6 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 31EEABFA156AAF9D00714D05 /* mps */;
|
||||
targetProxy = 22EA3F3A20D2B0D90065F5B6 /* PBXContainerItemProxy */;
|
||||
};
|
||||
22EA3F4820D2B23F0065F5B6 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 22EA3F3820D2B0D90065F5B6 /* forktest */;
|
||||
targetProxy = 22EA3F4720D2B23F0065F5B6 /* PBXContainerItemProxy */;
|
||||
};
|
||||
22F846B118F437B900982BA7 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 31EEABFA156AAF9D00714D05 /* mps */;
|
||||
|
|
@ -4917,6 +4994,27 @@
|
|||
};
|
||||
name = Release;
|
||||
};
|
||||
22EA3F4220D2B0D90065F5B6 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
22EA3F4320D2B0D90065F5B6 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
22EA3F4420D2B0D90065F5B6 /* RASH */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = RASH;
|
||||
};
|
||||
22F846BA18F437B900982BA7 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
|
|
@ -6133,6 +6231,16 @@
|
|||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
22EA3F4120D2B0D90065F5B6 /* Build configuration list for PBXNativeTarget "forktest" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
22EA3F4220D2B0D90065F5B6 /* Debug */,
|
||||
22EA3F4320D2B0D90065F5B6 /* Release */,
|
||||
22EA3F4420D2B0D90065F5B6 /* RASH */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
22F846B918F437B900982BA7 /* Build configuration list for PBXNativeTarget "lockut" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* mpsi.c: MEMORY POOL SYSTEM C INTERFACE LAYER
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2001-2018 Ravenbrook Limited. See end of file for license.
|
||||
* Portions copyright (c) 2002 Global Graphics Software.
|
||||
*
|
||||
* .purpose: This code bridges between the MPS interface to C,
|
||||
|
|
@ -1697,7 +1697,7 @@ mps_res_t mps_fix(mps_ss_t mps_ss, mps_addr_t *ref_io)
|
|||
mps_res_t res;
|
||||
|
||||
MPS_SCAN_BEGIN(mps_ss) {
|
||||
res = MPS_FIX(mps_ss, ref_io);
|
||||
res = MPS_FIX12(mps_ss, ref_io);
|
||||
} MPS_SCAN_END(mps_ss);
|
||||
|
||||
return res;
|
||||
|
|
@ -2159,7 +2159,7 @@ void _mps_args_set_key(mps_arg_s args[MPS_ARGS_MAX], unsigned i,
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2001-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* prmcxc.c: MUTATOR CONTEXT INTEL 386 (MAC OS X)
|
||||
/* prmcxc.c: MUTATOR CONTEXT (macOS)
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2016 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2016-2018 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .purpose: Implement the mutator context module. See <design/prmc/>.
|
||||
*
|
||||
|
|
@ -88,7 +88,7 @@ Res MutatorContextScan(ScanState ss, MutatorContext context,
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2016-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* prmcxc.h: MUTATOR CONTEXT FOR OS X MACH
|
||||
/* prmcxc.h: MUTATOR CONTEXT (macOS)
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2001-2018 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .readership: MPS developers.
|
||||
*/
|
||||
|
|
@ -32,7 +32,7 @@ extern void MutatorContextInitThread(MutatorContext context, THREAD_STATE_S *thr
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2001-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* prmcxci3.c: MUTATOR CONTEXT INTEL 386 (MAC OS X)
|
||||
/* prmcxci3.c: MUTATOR CONTEXT (macOS, IA-32)
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2001-2018 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .purpose: Implement the mutator context module. See <design/prmc/>.
|
||||
*
|
||||
|
|
@ -102,7 +102,7 @@ Addr MutatorContextSP(MutatorContext context)
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2001-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* prmcxci6.c: MUTATOR CONTEXT x64 (OS X)
|
||||
/* prmcxci6.c: MUTATOR CONTEXT (macOS, x86-64)
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2001-2018 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .purpose: Implement the mutator context module. See <design/prmc/>.
|
||||
*
|
||||
|
|
@ -107,7 +107,7 @@ Addr MutatorContextSP(MutatorContext context)
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2001-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
/* protix.c: PROTECTION FOR UNIX
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2001-2018 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* Somewhat generic across different Unix systems. Shared between
|
||||
* OS X, FreeBSD, and Linux.
|
||||
* macOS, FreeBSD, and Linux.
|
||||
*
|
||||
*
|
||||
* SOURCES
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
* be safely passed as a void *. Single UNIX Specification Version 2 (aka
|
||||
* X/OPEN XSH5) says that the parameter is a void *. Some Unix-likes may
|
||||
* declare this parameter as a caddr_t. FreeBSD used to do this (on the now
|
||||
* very obsolete FreeBSD 2.2.x series), as did OS X, but both now implement
|
||||
* very obsolete FreeBSD 2.2.x series), as did macOS, but both now implement
|
||||
* it correctly as void *. caddr_t is usually char *.
|
||||
*
|
||||
* .assume.write-only: More of an anti-assumption really. We
|
||||
|
|
@ -119,7 +119,7 @@ Size ProtGranularity(void)
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2001-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
/* protxc.c: PROTECTION EXCEPTION HANDLER FOR OS X MACH
|
||||
/* protxc.c: PROTECTION EXCEPTION HANDLER (macOS)
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2013-2016 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2013-2018 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* This is the protection exception handling code for OS X using the
|
||||
* This is the protection exception handling code for macOS using the
|
||||
* Mach interface (not pthreads).
|
||||
*
|
||||
* In Mach, a thread that hits protected memory is suspended, and a message
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
* at the next level out (the levels are thread, task, host) by sending a
|
||||
* "fail" reply.
|
||||
*
|
||||
* In OS X, pthreads are implemented by Mach threads. (The implementation is
|
||||
* In macOS, pthreads are implemented by Mach threads. (The implementation is
|
||||
* part of the XNU source code at opensource.apple.com. [copy to import?]) So
|
||||
* we can use some pthread interfaces (pthread_create, pthread_once) for
|
||||
* convenience in setting up threads.
|
||||
|
|
@ -47,7 +47,7 @@
|
|||
* TRANSGRESSIONS
|
||||
*
|
||||
* .trans.stdlib: It's OK to use the C library from here because we know
|
||||
* we're on OS X and not freestanding. In particular, we use memcpy.
|
||||
* we're on macOS and not freestanding. In particular, we use memcpy.
|
||||
*
|
||||
* .trans.must: Various OS calls are asserted to succeed, since there isn't
|
||||
* really a dynamic reason they should fail, so it must be a static error.
|
||||
|
|
@ -74,7 +74,7 @@
|
|||
#include <mach/exc.h>
|
||||
|
||||
#if !defined(MPS_OS_XC)
|
||||
#error "protxc.c is OS X specific"
|
||||
#error "protxc.c is macOS specific"
|
||||
#endif
|
||||
|
||||
SRCID(protxc, "$Id$");
|
||||
|
|
@ -178,7 +178,7 @@ static void protMustSend(mach_msg_header_t *head)
|
|||
|
||||
/* protCatchOne -- catch one EXC_BAD_ACCESS exception message.
|
||||
*
|
||||
* OS X provides a function exc_server (in
|
||||
* macOS provides a function exc_server (in
|
||||
* /usr/lib/system/libsystem_kernel.dylib) that's documented in the XNU
|
||||
* sources <http://www.opensource.apple.com/source/xnu/xnu-2050.22.13/osfmk/man/exc_server.html>
|
||||
* and generated by the Mach Interface Generator (mig). It unpacks
|
||||
|
|
@ -288,7 +288,7 @@ static void *protCatchThread(void *p) {
|
|||
|
||||
/* ProtThreadRegister -- register a thread for protection exception handling */
|
||||
|
||||
extern void ProtThreadRegister(Bool setup)
|
||||
extern void ProtThreadRegister(void)
|
||||
{
|
||||
kern_return_t kr;
|
||||
mach_msg_type_number_t old_exception_count = 1;
|
||||
|
|
@ -298,24 +298,10 @@ extern void ProtThreadRegister(Bool setup)
|
|||
exception_behavior_t old_behaviors;
|
||||
thread_state_flavor_t old_flavors;
|
||||
mach_port_t self;
|
||||
static mach_port_t setupThread = MACH_PORT_NULL;
|
||||
|
||||
self = mach_thread_self();
|
||||
AVER(MACH_PORT_VALID(self));
|
||||
|
||||
/* Avoid setting up the exception handler for the thread that calls
|
||||
ProtSetup twice, in the case where the mutator registers that thread
|
||||
explicitly. We need a special case because we don't require thread
|
||||
registration of the sole thread of a single-threaded mutator. */
|
||||
if (setup) {
|
||||
AVER(setupThread == MACH_PORT_NULL);
|
||||
setupThread = self;
|
||||
} else {
|
||||
AVER(setupThread != MACH_PORT_NULL);
|
||||
if (self == setupThread)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Ask to receive EXC_BAD_ACCESS exceptions on our port, complete
|
||||
with thread state and identity information in the message.
|
||||
The MACH_EXCEPTION_CODES flag causes the code fields to be
|
||||
|
|
@ -342,14 +328,17 @@ extern void ProtThreadRegister(Bool setup)
|
|||
}
|
||||
|
||||
|
||||
/* ProtSetup -- set up protection exception handling */
|
||||
/* protExcThreadStart -- create exception port, register the current
|
||||
* thread with that port, and create a thread to handle exception
|
||||
* messages.
|
||||
*/
|
||||
|
||||
static void protSetupInner(void)
|
||||
static void protExcThreadStart(void)
|
||||
{
|
||||
kern_return_t kr;
|
||||
int pr;
|
||||
pthread_t excThread;
|
||||
mach_port_t self;
|
||||
pthread_t excThread;
|
||||
int pr;
|
||||
|
||||
/* Create a port to send and receive exceptions. */
|
||||
self = mach_task_self();
|
||||
|
|
@ -373,18 +362,49 @@ static void protSetupInner(void)
|
|||
if (kr != KERN_SUCCESS)
|
||||
mach_error("ERROR: MPS mach_port_insert_right", kr); /* .trans.must */
|
||||
|
||||
ProtThreadRegister(TRUE);
|
||||
/* We don't require the mutator to register the sole thread in a
|
||||
* single-threaded program, so register it automatically now. */
|
||||
ProtThreadRegister();
|
||||
|
||||
/* Launch the exception handling thread. We use pthread_create because
|
||||
it's much simpler than setting up a thread from scratch using Mach,
|
||||
and that's basically what it does. See [Libc]
|
||||
<http://www.opensource.apple.com/source/Libc/Libc-825.26/pthreads/pthread.c> */
|
||||
/* Launch the exception handling thread. We use pthread_create
|
||||
* because it's much simpler than setting up a thread from scratch
|
||||
* using Mach, and that's basically what it does. See [Libc]
|
||||
* <http://www.opensource.apple.com/source/Libc/Libc-825.26/pthreads/pthread.c> */
|
||||
pr = pthread_create(&excThread, NULL, protCatchThread, NULL);
|
||||
AVER(pr == 0);
|
||||
if (pr != 0)
|
||||
fprintf(stderr, "ERROR: MPS pthread_create: %d\n", pr); /* .trans.must */
|
||||
}
|
||||
|
||||
|
||||
/* atfork handlers -- support for fork(). See <design/thread-safety/> */
|
||||
|
||||
static void protAtForkPrepare(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void protAtForkParent(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void protAtForkChild(void)
|
||||
{
|
||||
/* Restart the exception handling thread
|
||||
<design/thread-safety/#sol.fork.exc-thread>. */
|
||||
protExcThreadStart();
|
||||
}
|
||||
|
||||
|
||||
/* ProtSetup -- set up protection exception handling */
|
||||
|
||||
static void protSetupInner(void)
|
||||
{
|
||||
protExcThreadStart();
|
||||
|
||||
/* Install fork handlers <design/thread-safety/#sol.fork.atfork>. */
|
||||
pthread_atfork(protAtForkPrepare, protAtForkParent, protAtForkChild);
|
||||
}
|
||||
|
||||
void ProtSetup(void)
|
||||
{
|
||||
int pr;
|
||||
|
|
@ -401,7 +421,7 @@ void ProtSetup(void)
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2013-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2013-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
/* protxc.h: PROTECTION EXCPETION HANDLER FOR OS X MACH
|
||||
/* protxc.h: PROTECTION EXCEPTION HANDLER (macOS)
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2013 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2013-2018 Ravenbrook Limited. See end of file for license.
|
||||
*/
|
||||
|
||||
#ifndef protxc_h
|
||||
#define protxc_h
|
||||
|
||||
extern void ProtThreadRegister(Bool setup);
|
||||
extern void ProtThreadRegister(void);
|
||||
|
||||
#endif /* protxc_h */
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2013 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2013-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* sc.h: STACK CONTEXT
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2012 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2012-2018 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* Provides a context to hold the registers and stack pointer
|
||||
*
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
*/
|
||||
|
||||
|
||||
/* Mac OS X on 32-bit Intel built with Clang or GCC */
|
||||
/* macOS on IA-32 built with Clang or GCC */
|
||||
|
||||
#if defined(MPS_PF_XCI3LL) || defined(MPS_PF_XCI3GC)
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ typedef struct StackContextStruct {
|
|||
|
||||
#define StackContextSP(sc) ((Addr *)(sc)->jumpBuffer[JB_ESP/sizeof(int)])
|
||||
|
||||
/* On MacOS X the stackPointer can end up pointing above the StackContext
|
||||
/* On macOS the stackPointer can end up pointing above the StackContext
|
||||
* which we assume to be stored on the stack because it is no longer
|
||||
* needed once we have _longjmp()ed back. So take the minimum of the
|
||||
* SP and the base of the StackContext structure. */
|
||||
|
|
@ -72,7 +72,7 @@ typedef struct StackContextStruct {
|
|||
(StackContextSP(sc) < (Addr*)(sc) ? StackContextSP(sc) : (Addr*)(sc))
|
||||
|
||||
|
||||
/* Mac OS X on 64-bit Intel build with Clang or GCC */
|
||||
/* macOS on x86-64 built with Clang or GCC */
|
||||
|
||||
#elif defined(MPS_PF_XCI6LL) || defined(MPS_PF_XCI6GC)
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ typedef struct StackContextStruct {
|
|||
#define StackContextSP(sc) \
|
||||
(*(Addr **)((char *)(sc)->jumpBuffer+JB_RSP))
|
||||
|
||||
/* On MacOS X the stackPointer can end up pointing above the StackContext
|
||||
/* On macOS the stackPointer can end up pointing above the StackContext
|
||||
* which we assume to be stored on the stack because it is no longer
|
||||
* needed once we have _longjmp()ed back. So take the minimum of the
|
||||
* SP and the base of the StackContext structure. */
|
||||
|
|
@ -165,7 +165,7 @@ typedef struct StackContextStruct {
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2012 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2001-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* shield.c: SHIELD IMPLEMENTATION
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001-2017 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2001-2018 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* See: idea.shield, design.mps.shield.
|
||||
*
|
||||
|
|
@ -381,7 +381,7 @@ static Compare shieldQueueEntryCompare(void *left, void *right, void *closure)
|
|||
*
|
||||
* Sort the shield queue into address order, then iterate over it
|
||||
* coalescing protection work, in order to reduce the number of system
|
||||
* calls to a minimum. This is very important on OS X, where
|
||||
* calls to a minimum. This is very important on macOS, where
|
||||
* protection calls are extremely inefficient, but has no net gain on
|
||||
* Windows.
|
||||
*
|
||||
|
|
@ -762,7 +762,7 @@ void (ShieldCover)(Arena arena, Seg seg)
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2017 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2001-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
/* ssixi3.c: UNIX/INTEL STACK SCANNING
|
||||
/* ssixi3.c: STACK SCANNING (POSIX, IA-32)
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2001-2018 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* This scans the stack and fixes the registers which may contain
|
||||
* roots. See <design/thread-manager/>
|
||||
*
|
||||
* This code was originally developed and tested on Linux, and then
|
||||
* copied to the FreeBSD and Darwin (OS X) operating systems where it
|
||||
* also seems to work. Note that on FreeBSD and Darwin it has not
|
||||
* copied to the FreeBSD and Darwin (macOS) operating systems where
|
||||
* it also seems to work. Note that on FreeBSD and Darwin it has not
|
||||
* been indepently verified with respect to any ABI documentation.
|
||||
*
|
||||
* This code is common to more than one Unix implementation on
|
||||
|
|
@ -71,7 +71,7 @@ Res StackScan(ScanState ss, Word *stackCold,
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2001-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
/* ssixi6.c: UNIX/x64 STACK SCANNING
|
||||
/* ssixi6.c: STACK SCANNING (POSIX, x86-64)
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2001-2018 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* This scans the stack and fixes the registers which may contain
|
||||
* roots. See <design/thread-manager/>
|
||||
*
|
||||
* This code was branched from ssixi3.c (32-bit Intel) initially for the
|
||||
* port to XCI6LL (Mac OS X on x86_64 with Clang).
|
||||
* This code was branched from ssixi3.c (POSIX, IA-32) initially for
|
||||
* the port to XCI6LL (macOS, x86-64, Clang/LLVM).
|
||||
*
|
||||
* This code is common to more than one Unix implementation on
|
||||
* Intel hardware (but is not portable Unix code). According to Wikipedia,
|
||||
* all the non-Windows platforms use the System V AMD64 ABI. See
|
||||
* This code is common to more than one Unix implementation on Intel
|
||||
* hardware (but is not portable Unix code). According to Wikipedia,
|
||||
* all the non-Windows platforms use the System V AMD64 ABI. See
|
||||
* .sources.callees.saves.
|
||||
*
|
||||
* SOURCES
|
||||
|
|
@ -71,7 +71,7 @@ Res StackScan(ScanState ss, Word *stackCold,
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2001-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -388,7 +388,7 @@ void error(const char *format, ...)
|
|||
|
||||
va_start(args, format);
|
||||
verror(format, args);
|
||||
va_end(args);
|
||||
/* va_end(args); */ /* provokes "unreachable code" error from MSVC */
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ extern Res ThreadScan(ScanState ss, Thread thread, Word *stackCold,
|
|||
mps_area_scan_t scan_area,
|
||||
void *closure);
|
||||
|
||||
extern void ThreadSetup(void);
|
||||
|
||||
|
||||
#endif /* th_h */
|
||||
|
||||
|
|
|
|||
|
|
@ -142,6 +142,12 @@ Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth)
|
|||
}
|
||||
|
||||
|
||||
void ThreadSetup(void)
|
||||
{
|
||||
/* Nothing to do as ANSI platform does not have fork(). */
|
||||
}
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
|
|
|
|||
|
|
@ -133,30 +133,26 @@ void ThreadDeregister(Thread thread, Arena arena)
|
|||
|
||||
|
||||
/* mapThreadRing -- map over threads on ring calling a function on
|
||||
* each one except the current thread.
|
||||
* each one.
|
||||
*
|
||||
* Threads that are found to be dead (that is, if func returns FALSE)
|
||||
* are moved to deadRing, in order to implement
|
||||
* are marked as dead and moved to deadRing, in order to implement
|
||||
* design.thread-manager.sol.thread.term.attempt.
|
||||
*/
|
||||
|
||||
static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread))
|
||||
{
|
||||
Ring node, next;
|
||||
pthread_t self;
|
||||
|
||||
AVERT(Ring, threadRing);
|
||||
AVERT(Ring, deadRing);
|
||||
AVER(FUNCHECK(func));
|
||||
|
||||
self = pthread_self();
|
||||
RING_FOR(node, threadRing, next) {
|
||||
Thread thread = RING_ELT(Thread, arenaRing, node);
|
||||
AVERT(Thread, thread);
|
||||
AVER(thread->alive);
|
||||
if (!pthread_equal(self, thread->id) /* .thread.id */
|
||||
&& !(*func)(thread))
|
||||
{
|
||||
if (!(*func)(thread)) {
|
||||
thread->alive = FALSE;
|
||||
RingRemove(&thread->arenaRing);
|
||||
RingAppend(deadRing, &thread->arenaRing);
|
||||
|
|
@ -171,9 +167,14 @@ static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread))
|
|||
|
||||
static Bool threadSuspend(Thread thread)
|
||||
{
|
||||
Res res;
|
||||
pthread_t self;
|
||||
self = pthread_self();
|
||||
if (pthread_equal(self, thread->id)) /* .thread.id */
|
||||
return TRUE;
|
||||
|
||||
/* .error.suspend: if PThreadextSuspend fails, we assume the thread
|
||||
* has been terminated. */
|
||||
Res res;
|
||||
AVER(thread->context == NULL);
|
||||
res = PThreadextSuspend(&thread->thrextStruct, &thread->context);
|
||||
AVER(res == ResOK);
|
||||
|
|
@ -196,6 +197,11 @@ void ThreadRingSuspend(Ring threadRing, Ring deadRing)
|
|||
static Bool threadResume(Thread thread)
|
||||
{
|
||||
Res res;
|
||||
pthread_t self;
|
||||
self = pthread_self();
|
||||
if (pthread_equal(self, thread->id)) /* .thread.id */
|
||||
return TRUE;
|
||||
|
||||
/* .error.resume: If PThreadextResume fails, we assume the thread
|
||||
* has been terminated. */
|
||||
AVER(thread->context != NULL);
|
||||
|
|
@ -307,6 +313,33 @@ Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth)
|
|||
}
|
||||
|
||||
|
||||
/* threadAtForkChild -- for each arena, move threads except for the
|
||||
* current thread to the dead ring <design/thread-safety/#sol.fork.thread>.
|
||||
*/
|
||||
|
||||
static Bool threadForkChild(Thread thread)
|
||||
{
|
||||
AVERT(Thread, thread);
|
||||
return pthread_equal(pthread_self(), thread->id); /* .thread.id */
|
||||
}
|
||||
|
||||
static void threadRingForkChild(Arena arena)
|
||||
{
|
||||
AVERT(Arena, arena);
|
||||
mapThreadRing(ArenaThreadRing(arena), ArenaDeadRing(arena), threadForkChild);
|
||||
}
|
||||
|
||||
static void threadAtForkChild(void)
|
||||
{
|
||||
GlobalsArenaMap(threadRingForkChild);
|
||||
}
|
||||
|
||||
void ThreadSetup(void)
|
||||
{
|
||||
pthread_atfork(NULL, NULL, threadAtForkChild);
|
||||
}
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
|
|
|
|||
|
|
@ -312,6 +312,12 @@ Res ThreadScan(ScanState ss, Thread thread, Word *stackCold,
|
|||
}
|
||||
|
||||
|
||||
void ThreadSetup(void)
|
||||
{
|
||||
/* Nothing to do as MPS does not support fork() on Windows. */
|
||||
}
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
|
|
|
|||
147
mps/code/thxc.c
147
mps/code/thxc.c
|
|
@ -1,7 +1,7 @@
|
|||
/* thxc.c: OS X MACH THREADS MANAGER
|
||||
/* thxc.c: THREAD MANAGER (macOS)
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2001-2018 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .design: See <design/thread-manager/>.
|
||||
*
|
||||
|
|
@ -26,17 +26,19 @@
|
|||
#include <mach/task.h>
|
||||
#include <mach/thread_act.h>
|
||||
#include <mach/thread_status.h>
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
SRCID(thxc, "$Id$");
|
||||
|
||||
|
||||
typedef struct mps_thr_s { /* OS X / Mach thread structure */
|
||||
typedef struct mps_thr_s { /* macOS thread structure */
|
||||
Sig sig; /* <design/sig/> */
|
||||
Serial serial; /* from arena->threadSerial */
|
||||
Arena arena; /* owning arena */
|
||||
RingStruct arenaRing; /* attaches to arena */
|
||||
Bool alive; /* thread believed to be alive? */
|
||||
Bool forking; /* thread currently calling fork? */
|
||||
thread_port_t port; /* thread kernel port */
|
||||
} ThreadStruct;
|
||||
|
||||
|
|
@ -48,6 +50,7 @@ Bool ThreadCheck(Thread thread)
|
|||
CHECKL(thread->serial < thread->arena->threadSerial);
|
||||
CHECKD_NOSIG(Ring, &thread->arenaRing);
|
||||
CHECKL(BoolCheck(thread->alive));
|
||||
CHECKL(BoolCheck(thread->forking));
|
||||
CHECKL(MACH_PORT_VALID(thread->port));
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -80,11 +83,13 @@ Res ThreadRegister(Thread *threadReturn, Arena arena)
|
|||
thread->serial = arena->threadSerial;
|
||||
++arena->threadSerial;
|
||||
thread->alive = TRUE;
|
||||
thread->forking = FALSE;
|
||||
thread->port = mach_thread_self();
|
||||
AVER(MACH_PORT_VALID(thread->port));
|
||||
thread->sig = ThreadSig;
|
||||
AVERT(Thread, thread);
|
||||
|
||||
ProtThreadRegister(FALSE);
|
||||
ProtThreadRegister();
|
||||
|
||||
ring = ArenaThreadRing(arena);
|
||||
|
||||
|
|
@ -99,6 +104,7 @@ void ThreadDeregister(Thread thread, Arena arena)
|
|||
{
|
||||
AVERT(Thread, thread);
|
||||
AVERT(Arena, arena);
|
||||
AVER(!thread->forking);
|
||||
|
||||
RingRemove(&thread->arenaRing);
|
||||
|
||||
|
|
@ -111,7 +117,7 @@ void ThreadDeregister(Thread thread, Arena arena)
|
|||
|
||||
|
||||
/* mapThreadRing -- map over threads on ring calling a function on
|
||||
* each one except the current thread.
|
||||
* each one.
|
||||
*
|
||||
* Threads that are found to be dead (that is, if func returns FALSE)
|
||||
* are marked as dead and moved to deadRing, in order to implement
|
||||
|
|
@ -121,21 +127,16 @@ void ThreadDeregister(Thread thread, Arena arena)
|
|||
static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread))
|
||||
{
|
||||
Ring node, next;
|
||||
mach_port_t self;
|
||||
|
||||
AVERT(Ring, threadRing);
|
||||
AVERT(Ring, deadRing);
|
||||
AVER(FUNCHECK(func));
|
||||
|
||||
self = mach_thread_self();
|
||||
AVER(MACH_PORT_VALID(self));
|
||||
RING_FOR(node, threadRing, next) {
|
||||
Thread thread = RING_ELT(Thread, arenaRing, node);
|
||||
AVERT(Thread, thread);
|
||||
AVER(thread->alive);
|
||||
if (thread->port != self
|
||||
&& !(*func)(thread))
|
||||
{
|
||||
if (!(*func)(thread)) {
|
||||
thread->alive = FALSE;
|
||||
RingRemove(&thread->arenaRing);
|
||||
RingAppend(deadRing, &thread->arenaRing);
|
||||
|
|
@ -147,6 +148,11 @@ static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread))
|
|||
static Bool threadSuspend(Thread thread)
|
||||
{
|
||||
kern_return_t kern_return;
|
||||
mach_port_t self = mach_thread_self();
|
||||
AVER(MACH_PORT_VALID(self));
|
||||
if (thread->port == self)
|
||||
return TRUE;
|
||||
|
||||
kern_return = thread_suspend(thread->port);
|
||||
/* No rendezvous is necessary: thread_suspend "prevents the thread
|
||||
* from executing any more user-level instructions" */
|
||||
|
|
@ -157,18 +163,6 @@ static Bool threadSuspend(Thread thread)
|
|||
return kern_return == KERN_SUCCESS;
|
||||
}
|
||||
|
||||
static Bool threadResume(Thread thread)
|
||||
{
|
||||
kern_return_t kern_return;
|
||||
kern_return = thread_resume(thread->port);
|
||||
/* Mach has no equivalent of EAGAIN. */
|
||||
AVER(kern_return == KERN_SUCCESS);
|
||||
/* Experimentally, values other then KERN_SUCCESS indicate the thread has
|
||||
terminated <https://info.ravenbrook.com/mail/2014/10/25/18-12-36/0/>. */
|
||||
/* design.thread-manager.sol.thread.term.attempt */
|
||||
return kern_return == KERN_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* ThreadRingSuspend -- suspend all threads on a ring, except the
|
||||
* current one.
|
||||
|
|
@ -178,6 +172,24 @@ void ThreadRingSuspend(Ring threadRing, Ring deadRing)
|
|||
mapThreadRing(threadRing, deadRing, threadSuspend);
|
||||
}
|
||||
|
||||
|
||||
static Bool threadResume(Thread thread)
|
||||
{
|
||||
kern_return_t kern_return;
|
||||
mach_port_t self = mach_thread_self();
|
||||
AVER(MACH_PORT_VALID(self));
|
||||
if (thread->port == self)
|
||||
return TRUE;
|
||||
|
||||
kern_return = thread_resume(thread->port);
|
||||
/* Mach has no equivalent of EAGAIN. */
|
||||
AVER(kern_return == KERN_SUCCESS);
|
||||
/* Experimentally, values other then KERN_SUCCESS indicate the thread has
|
||||
terminated <https://info.ravenbrook.com/mail/2014/10/25/18-12-36/0/>. */
|
||||
/* design.thread-manager.sol.thread.term.attempt */
|
||||
return kern_return == KERN_SUCCESS;
|
||||
}
|
||||
|
||||
/* ThreadRingResume -- resume all threads on a ring, except the
|
||||
* current one.
|
||||
*/
|
||||
|
|
@ -186,6 +198,7 @@ void ThreadRingResume(Ring threadRing, Ring deadRing)
|
|||
mapThreadRing(threadRing, deadRing, threadResume);
|
||||
}
|
||||
|
||||
|
||||
Thread ThreadRingThread(Ring threadRing)
|
||||
{
|
||||
Thread thread;
|
||||
|
|
@ -291,9 +304,95 @@ Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth)
|
|||
}
|
||||
|
||||
|
||||
/* threadAtForkPrepare -- for each arena, mark the current thread as
|
||||
* forking <design/thread-safety/#sol.fork.thread>.
|
||||
*/
|
||||
|
||||
static Bool threadForkPrepare(Thread thread)
|
||||
{
|
||||
mach_port_t self;
|
||||
AVERT(Thread, thread);
|
||||
AVER(!thread->forking);
|
||||
self = mach_thread_self();
|
||||
AVER(MACH_PORT_VALID(self));
|
||||
thread->forking = (thread->port == self);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void threadRingForkPrepare(Arena arena)
|
||||
{
|
||||
AVERT(Arena, arena);
|
||||
mapThreadRing(ArenaThreadRing(arena), ArenaDeadRing(arena), threadForkPrepare);
|
||||
}
|
||||
|
||||
static void threadAtForkPrepare(void)
|
||||
{
|
||||
GlobalsArenaMap(threadRingForkPrepare);
|
||||
}
|
||||
|
||||
|
||||
/* threadAtForkParent -- for each arena, clear the forking flag for
|
||||
* all threads <design/thread-safety/#sol.fork.thread>.
|
||||
*/
|
||||
|
||||
static Bool threadForkParent(Thread thread)
|
||||
{
|
||||
AVERT(Thread, thread);
|
||||
thread->forking = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void threadRingForkParent(Arena arena)
|
||||
{
|
||||
AVERT(Arena, arena);
|
||||
mapThreadRing(ArenaThreadRing(arena), ArenaDeadRing(arena), threadForkParent);
|
||||
}
|
||||
|
||||
static void threadAtForkParent(void)
|
||||
{
|
||||
GlobalsArenaMap(threadRingForkParent);
|
||||
}
|
||||
|
||||
|
||||
/* threadAtForkChild -- For each arena, move all threads to the dead
|
||||
* ring, except for the thread that was marked as forking by the
|
||||
* prepare handler <design/thread-safety/#sol.fork.thread>, for which
|
||||
* update its mach port <design/thread-safety/#sol.fork.mach-port>.
|
||||
*/
|
||||
|
||||
static Bool threadForkChild(Thread thread)
|
||||
{
|
||||
AVERT(Thread, thread);
|
||||
if (thread->forking) {
|
||||
thread->port = mach_thread_self();
|
||||
AVER(MACH_PORT_VALID(thread->port));
|
||||
thread->forking = FALSE;
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void threadRingForkChild(Arena arena)
|
||||
{
|
||||
AVERT(Arena, arena);
|
||||
mapThreadRing(ArenaThreadRing(arena), ArenaDeadRing(arena), threadForkChild);
|
||||
}
|
||||
|
||||
static void threadAtForkChild(void)
|
||||
{
|
||||
GlobalsArenaMap(threadRingForkChild);
|
||||
}
|
||||
|
||||
void ThreadSetup(void)
|
||||
{
|
||||
pthread_atfork(threadAtForkPrepare, threadAtForkParent, threadAtForkChild);
|
||||
}
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2001-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* vmix.c: VIRTUAL MEMORY MAPPING FOR UNIX (ISH)
|
||||
/* vmix.c: VIRTUAL MEMORY MAPPING (POSIX)
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2001-2018 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .purpose: This is the implementation of the virtual memory mapping
|
||||
* interface (vm.h) for Unix-like operating systems. It was created
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
* copied from vli.c (Linux) which was itself copied from vmo1.c (OSF/1
|
||||
* / DIGITAL UNIX / Tru64).
|
||||
*
|
||||
* .deployed: Currently used on Darwin (OS X) and FreeBSD.
|
||||
* .deployed: Currently used on Darwin (macOS) and FreeBSD.
|
||||
*
|
||||
* .design: See <design/vm/>. .design.mmap: mmap(2) is used to
|
||||
* reserve address space by creating a mapping with page access none.
|
||||
|
|
@ -225,7 +225,7 @@ void VMUnmap(VM vm, Addr base, Addr limit)
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2001-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
# -*- makefile -*-
|
||||
#
|
||||
# xci3gc.gmk: BUILD FOR MACOS X (CARBON)/INTEL IA32/GCC PLATFORM
|
||||
# xci3gc.gmk: BUILD FOR macOS/IA-32/GCC PLATFORM
|
||||
#
|
||||
# $Id$
|
||||
# Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
|
||||
# Copyright (c) 2001-2018 Ravenbrook Limited. See end of file for license.
|
||||
#
|
||||
# Naively copied from xcppgc.gmk, could do with going over properly.
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ include comm.gmk
|
|||
|
||||
# C. COPYRIGHT AND LICENSE
|
||||
#
|
||||
# Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
# Copyright (C) 2001-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
# All rights reserved. This is an open source license. Contact
|
||||
# Ravenbrook for commercial licensing options.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
# -*- makefile -*-
|
||||
#
|
||||
# xci3ll.gmk: BUILD FOR MAC OS X/i386/Clang PLATFORM
|
||||
# xci3ll.gmk: BUILD FOR macOS/IA-32/Clang/LLVM PLATFORM
|
||||
#
|
||||
# $Id$
|
||||
# Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
|
||||
# Copyright (c) 2001-2018 Ravenbrook Limited. See end of file for license.
|
||||
#
|
||||
# .prefer.xcode: The documented and preferred way to develop the MPS
|
||||
# for this platform is to use the Xcode project (mps.xcodeproj). This
|
||||
|
|
@ -34,7 +34,7 @@ include comm.gmk
|
|||
|
||||
# C. COPYRIGHT AND LICENSE
|
||||
#
|
||||
# Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
# Copyright (C) 2001-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
# All rights reserved. This is an open source license. Contact
|
||||
# Ravenbrook for commercial licensing options.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
# -*- makefile -*-
|
||||
#
|
||||
# xci6gc.gmk: BUILD FOR MAC OS X/x86_64/GCC PLATFORM
|
||||
# xci6gc.gmk: BUILD FOR macOS/x86-64/GCC PLATFORM
|
||||
#
|
||||
# $Id$
|
||||
# Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
|
||||
# Copyright (c) 2001-2018 Ravenbrook Limited. See end of file for license.
|
||||
#
|
||||
# .prefer.xcode: The documented and preferred way to develop the MPS
|
||||
# for this platform is to use the Xcode project (mps.xcodeproj). This
|
||||
|
|
@ -31,7 +31,7 @@ include comm.gmk
|
|||
|
||||
# C. COPYRIGHT AND LICENSE
|
||||
#
|
||||
# Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
# Copyright (C) 2001-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
# All rights reserved. This is an open source license. Contact
|
||||
# Ravenbrook for commercial licensing options.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
# -*- makefile -*-
|
||||
#
|
||||
# xci6ll.gmk: BUILD FOR MAC OS X/x86_64/Clang PLATFORM
|
||||
# xci6ll.gmk: BUILD FOR macOS/x86-64/Clang/LLVM PLATFORM
|
||||
#
|
||||
# $Id$
|
||||
# Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
|
||||
# Copyright (c) 2001-2018 Ravenbrook Limited. See end of file for license.
|
||||
#
|
||||
# .prefer.xcode: The documented and preferred way to develop the MPS
|
||||
# for this platform is to use the Xcode project (mps.xcodeproj). This
|
||||
|
|
@ -31,7 +31,7 @@ include comm.gmk
|
|||
|
||||
# C. COPYRIGHT AND LICENSE
|
||||
#
|
||||
# Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
# Copyright (C) 2001-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
# All rights reserved. This is an open source license. Contact
|
||||
# Ravenbrook for commercial licensing options.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -68,24 +68,18 @@ is typically embedded in another structure.
|
|||
External classes
|
||||
................
|
||||
|
||||
``CLASS(CBS)``
|
||||
_`.class.cbs`: ``CLASS(CBS)`` is the CBS class, a subclass of
|
||||
``CLASS(Land)`` suitable for passing to ``LandInit()``.
|
||||
|
||||
_`.class.cbs`: The CBS class, a subclass of ``CLASS(Land)`` suitable
|
||||
for passing to ``LandInit()``.
|
||||
|
||||
``CLASS(CBSFast)``
|
||||
|
||||
_`.class.fast`: A subclass of ``CLASS(CBS)`` that maintains, for each
|
||||
subtree, the size of the largest block in that subtree. This enables
|
||||
the ``LandFindFirst()``, ``LandFindLast()``, and ``LandFindLargest()``
|
||||
generic functions.
|
||||
|
||||
``CLASS(CBSZoned)``
|
||||
|
||||
_`.class.zoned`: A subclass of ``CLASS(CBSFast)`` that maintains, for
|
||||
each subtree, the union of the zone sets of all ranges in that
|
||||
subtree. This enables the ``LandFindInZones()`` generic function.
|
||||
_`.class.fast`: ``CLASS(CBSFast)`` is subclass of ``CLASS(CBS)`` that
|
||||
maintains, for each subtree, the size of the largest block in that
|
||||
subtree. This enables the ``LandFindFirst()``, ``LandFindLast()``, and
|
||||
``LandFindLargest()`` generic functions.
|
||||
|
||||
_`.class.zoned`: ``CLASS(CBSZoned)`` is a subclass of
|
||||
``CLASS(CBSFast)`` that maintains, for each subtree, the union of the
|
||||
zone sets of all ranges in that subtree. This enables the
|
||||
``LandFindInZones()`` generic function.
|
||||
|
||||
|
||||
Keyword arguments
|
||||
|
|
@ -279,7 +273,7 @@ Document History
|
|||
Copyright and License
|
||||
---------------------
|
||||
|
||||
Copyright © 1998-2016 Ravenbrook Limited. All rights reserved.
|
||||
Copyright © 1998-2018 Ravenbrook Limited. All rights reserved.
|
||||
<http://www.ravenbrook.com/>. This is an open source license. Contact
|
||||
Ravenbrook for commercial licensing options.
|
||||
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ Very briefly, the critical path consists of five stages:
|
|||
write a good scanner. Then that could be linked from here.
|
||||
|
||||
#. The first-stage fix, which filters out pointers inline in the
|
||||
scanner. This is implemented in ``MPS_FIX()`` macros in
|
||||
scanner. This is implemented in the ``MPS_FIX1()`` macro in
|
||||
mps.h_.
|
||||
|
||||
.. _mps.h: ../code/mps.h
|
||||
|
|
@ -371,7 +371,7 @@ Document History
|
|||
Copyright and License
|
||||
---------------------
|
||||
|
||||
Copyright © 2012-2014 Ravenbrook Limited. All rights reserved.
|
||||
Copyright © 2012-2018 Ravenbrook Limited. All rights reserved.
|
||||
<http://www.ravenbrook.com/>. This is an open source license. Contact
|
||||
Ravenbrook for commercial licensing options.
|
||||
|
||||
|
|
|
|||
|
|
@ -136,6 +136,15 @@ corresponding ``LockClaimRecursive()`` call.
|
|||
Return true if the lock is held by any thread, false otherwise. Note
|
||||
that this function need not be thread-safe (see `.req.held`_).
|
||||
|
||||
``void LockInitGlobal(void)``
|
||||
|
||||
Initialize (or re-initialize) the global locks. This should only be
|
||||
called in the following circumstances: the first time either of the
|
||||
global locks is claimed; and in the child process after a ``fork()``.
|
||||
See design.mps.thread-safety.sol.fork.lock_.
|
||||
|
||||
.. _design.mps.thread-safety.sol.fork.lock: thread-safety#sol-fork-lock
|
||||
|
||||
``void LockClaimGlobal(void)``
|
||||
|
||||
Claims ownership of the binary global lock which was previously not
|
||||
|
|
@ -155,6 +164,11 @@ to the current thread and claims the lock (if not already held).
|
|||
Restores the previous state of the recursive global lock remembered by
|
||||
the corresponding ``LockClaimGlobalRecursive()`` call.
|
||||
|
||||
``void LockSetup(void)``
|
||||
|
||||
One-time initialization function, intended for calling
|
||||
``pthread_atfork()`` on the appropriate platforms: see design.mps.thread-safety.sol.fork.lock_.
|
||||
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
|
|
@ -278,6 +292,8 @@ Document History
|
|||
|
||||
- 2014-10-21 GDR_ Brought up to date.
|
||||
|
||||
- 2018-06-14 GDR_ Added ``LockInitGlobal()``.
|
||||
|
||||
.. _RB: http://www.ravenbrook.com/consultants/rb/
|
||||
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
|
||||
|
||||
|
|
|
|||
|
|
@ -263,8 +263,8 @@ _`.impl.w3.context.sp`: The stack pointer is obtained from
|
|||
``CONTEXT.Esp`` (on IA-32) or ``CONTEXT.Rsp`` (on x86-64).
|
||||
|
||||
|
||||
OS X implementation
|
||||
...................
|
||||
macOS implementation
|
||||
....................
|
||||
|
||||
_`.impl.xc`: In ``prmcix.c`` and ``prmcxc.c``, with processor-specific
|
||||
parts in ``prmci3.c`` and ``prmci6.c``, and other platform-specific
|
||||
|
|
@ -311,7 +311,7 @@ Document History
|
|||
Copyright and License
|
||||
---------------------
|
||||
|
||||
Copyright © 2014-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
Copyright © 2014-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
All rights reserved. This is an open source license. Contact
|
||||
Ravenbrook for commercial licensing options.
|
||||
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ _`.impl.ix`: POSIX implementation. See design.mps.protix_.
|
|||
|
||||
_`.impl.w3`: Windows implementation.
|
||||
|
||||
_`.impl.xc`: OS X implementation.
|
||||
_`.impl.xc`: macOS implementation.
|
||||
|
||||
|
||||
Document History
|
||||
|
|
@ -163,7 +163,7 @@ Document History
|
|||
Copyright and License
|
||||
---------------------
|
||||
|
||||
Copyright © 2013-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
Copyright © 2013-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
All rights reserved. This is an open source license. Contact
|
||||
Ravenbrook for commercial licensing options.
|
||||
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ This hysteresis allows the MPS to proceed with garbage collection
|
|||
during a pause without actually setting hardware protection until it
|
||||
returns to the mutator. This is particularly important on operating
|
||||
systems where the protection is expensive and poorly implemented, such
|
||||
as OS X.
|
||||
as macOS.
|
||||
|
||||
The queue also ensures that no memory protection system calls will be
|
||||
needed for incremental garbage collection if a complete collection
|
||||
|
|
@ -362,7 +362,7 @@ Theoretically we can do this, but:
|
|||
non-moving collection.
|
||||
|
||||
2. The main cost of protection is changing it at all, not whether we
|
||||
change just read or write. On OS X, the main cost seems to be the
|
||||
change just read or write. On macOS, the main cost seems to be the
|
||||
TLB flush, which affects wall-clock time of everything on the
|
||||
processor!
|
||||
|
||||
|
|
@ -406,7 +406,7 @@ Document History
|
|||
Copyright and License
|
||||
---------------------
|
||||
|
||||
Copyright © 2013-2017 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
Copyright © 2013-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
All rights reserved. This is an open source license. Contact
|
||||
Ravenbrook for commercial licensing options.
|
||||
|
||||
|
|
|
|||
|
|
@ -279,8 +279,8 @@ _`.impl.w3.scan.suspended`: Otherwise, ``ThreadScan()`` calls
|
|||
pointer.
|
||||
|
||||
|
||||
OS X implementation
|
||||
...................
|
||||
macOS implementation
|
||||
....................
|
||||
|
||||
_`.impl.xc`: In ``thxc.c``.
|
||||
|
||||
|
|
@ -335,7 +335,7 @@ Document History
|
|||
Copyright and License
|
||||
---------------------
|
||||
|
||||
Copyright © 2013-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
Copyright © 2013-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
All rights reserved. This is an open source license. Contact
|
||||
Ravenbrook for commercial licensing options.
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,11 @@ updated at most once (that is, the protocol classes).
|
|||
|
||||
_`.req.deadlock`: The MPS must not deadlock.
|
||||
|
||||
_`.req.fork`: On Unix platforms, the MPS should be able to continue in
|
||||
the child process after a ``fork()``. (Source: job004062_.)
|
||||
|
||||
.. _job004062: https://www.ravenbrook.com/project/mps/issue/job004062/
|
||||
|
||||
_`.req.perf`: Performance should not be unreasonably hindered.
|
||||
|
||||
|
||||
|
|
@ -131,6 +136,38 @@ easiest to implement first, but could be evolved into a `.binary`_
|
|||
strategy. (That evolution has now happened. tony 1999-08-31).
|
||||
|
||||
|
||||
Fork safety
|
||||
...........
|
||||
|
||||
In order to support ``fork()``, we need to solve the following problems:
|
||||
|
||||
_`.anal.fork.lock`: Any MPS lock might be held by another thread at
|
||||
the point where ``fork()`` is called. The lock would be protecting the
|
||||
integrity of some data structure. But in the child the thread holding
|
||||
the lock no longer exists, and so there is no way to restore the
|
||||
integrity.
|
||||
|
||||
_`.anal.fork.threads`: In the child process after a ``fork()``, there
|
||||
is only one thread, which is a copy of the thread that called
|
||||
``fork()`` in the parent process. All other threads no longer exist.
|
||||
But the MPS maintains references to these threads, via the
|
||||
``ThreadStruct`` object` created by calls to ``mps_thread_reg()``. If
|
||||
we try to communicate with these threads it will fail or crash.
|
||||
|
||||
_`.anal.fork.exc-thread`: On macOS, the MPS handles protection faults
|
||||
using a dedicated thread. But in the child process after a ``fork()``,
|
||||
this dedicated thread no longer exists. Also, the Mach port on which
|
||||
the dedicated thread receives its messages does not exist in the child
|
||||
either.
|
||||
|
||||
_`.anal.fork.mach-port`: On macOS, the MPS identifies threads via
|
||||
their Mach port numbers, which are stashed in the ``ThreadStruct`` and
|
||||
used to identify the current thread, for example in
|
||||
``ThreadSuspend()``. But in the child process after ``fork()`` the
|
||||
running thread has a different Mach port number than it did in the
|
||||
parent.
|
||||
|
||||
|
||||
Design
|
||||
------
|
||||
|
||||
|
|
@ -209,6 +246,44 @@ design.mps.sig.check.arg.unlocked_).
|
|||
.. _design.mps.sig.check.arg.unlocked: sig#check-arg-unlocked
|
||||
|
||||
|
||||
Fork safety
|
||||
-----------
|
||||
|
||||
_`.sol.fork.atfork`: The MPS solves the fork-safety problems by
|
||||
calling |pthread_atfork|_ to install handler functions that are
|
||||
called in the parent process just before fork (the "prepare" handler),
|
||||
and in the parent and child processes just after fork (the "parent"
|
||||
and "child" handlers respectively).
|
||||
|
||||
.. |pthread_atfork| replace:: ``pthread_atfork()``
|
||||
.. _pthread_atfork: http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_atfork.html
|
||||
|
||||
_`.sol.fork.lock`: In the prepare handler, the MPS takes all the
|
||||
locks: that is, the global locks, and then the arena lock for every
|
||||
arena. Note that a side-effect of this is that the shield is entered
|
||||
for each arena. In the parent handler, the MPS releases all the locks.
|
||||
In the child handler, the MPS would like to release the locks but this
|
||||
does not work on any supported platform, so instead it reinitializes
|
||||
them, by calling ``LockInitGlobal()``.
|
||||
|
||||
_`.sol.fork.thread`: On macOS, in the prepare handler, the MPS
|
||||
identifies for each arena the current thread, that is, the one calling
|
||||
``fork()`` which will survive into the child process, and marks this
|
||||
thread by setting a flag in the appropriate ``ThreadStruct``. In the
|
||||
parent handler, this flag is cleared. On all Unix platforms, in the
|
||||
child handler, all threads (except for the current thread) are marked
|
||||
as dead and transferred to the ring of dead threads. (The MPS can't
|
||||
destroy the thread structures at this point because they are owned by
|
||||
the client program.)
|
||||
|
||||
_`.sol.fork.exc-thread`: On macOS, in the child handler, the exception
|
||||
port and dedicated thread are re-created, and the current thread
|
||||
re-registered with the exception port.
|
||||
|
||||
_`.sol.fork.mach-port`: On macOS, in the child handler, the thread
|
||||
flagged as forking gets its port number updated.
|
||||
|
||||
|
||||
Document History
|
||||
----------------
|
||||
|
||||
|
|
@ -218,6 +293,8 @@ Document History
|
|||
|
||||
- 2013-05-22 GDR_ Converted to reStructuredText.
|
||||
|
||||
- 2018-06-14 GDR_ Added fork safety design.
|
||||
|
||||
.. _RB: http://www.ravenbrook.com/consultants/rb/
|
||||
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
|
||||
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ passing ``PROT_NONE`` and ``MAP_PRIVATE | MAP_ANON``.
|
|||
|
||||
_`.impl.ix.anon.trans`: Note that ``MAP_ANON`` ("map anonymous
|
||||
memory not associated with any specific file") is an extension to
|
||||
POSIX, but it is supported by FreeBSD, Linux, and OS X. A work-around
|
||||
POSIX, but it is supported by FreeBSD, Linux, and macOS. A work-around
|
||||
that was formerly used on systems lacking ``MAP_ANON`` was to map
|
||||
the file ``/dev/zero``.
|
||||
|
||||
|
|
@ -369,7 +369,7 @@ Document History
|
|||
Copyright and License
|
||||
---------------------
|
||||
|
||||
Copyright © 2013-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
Copyright © 2013-2018 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
All rights reserved. This is an open source license. Contact
|
||||
Ravenbrook for commercial licensing options.
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ Improvements
|
|||
|
||||
.improv.by-os: The overheads hardware barriers varies widely between
|
||||
operating systems. On Windows it is very cheap to change memory
|
||||
protection and to handle protecion faults. On OS X it is very
|
||||
protection and to handle protecion faults. On macOS it is very
|
||||
expensive. The balance between barriers and scanning work is
|
||||
different. We should measure the relative costs and tune the deferral
|
||||
for each separately.
|
||||
|
|
@ -138,7 +138,7 @@ Document History
|
|||
Copyright and License
|
||||
---------------------
|
||||
|
||||
Copyright © 2016 Ravenbrook Limited <http://www.ravenbrook.com/>. All
|
||||
Copyright © 2016-2018 Ravenbrook Limited <http://www.ravenbrook.com/>. All
|
||||
rights reserved. This is an open source license. Contact Ravenbrook
|
||||
for commercial licensing options.
|
||||
|
||||
|
|
|
|||
|
|
@ -34,14 +34,14 @@ Compiling for production
|
|||
|
||||
In the simplest case, you can compile the MPS to an object file with just::
|
||||
|
||||
cc -c mps.c (Unix/Mac OS X)
|
||||
cc -c mps.c (Unix/macOS)
|
||||
cl /c mps.c (Windows)
|
||||
|
||||
This will build a "hot" variety (for production) object file for use
|
||||
with ``mps.h``. You can greatly improve performance by allowing global
|
||||
optimization, for example::
|
||||
|
||||
cc -O2 -c mps.c (Unix/Mac OS X)
|
||||
cc -O2 -c mps.c (Unix/macOS)
|
||||
cl /O2 /c mps.c (Windows)
|
||||
|
||||
|
||||
|
|
@ -51,7 +51,7 @@ Compiling for debugging
|
|||
You can get a "cool" variety MPS (with more internal checking, for
|
||||
debugging and development) with::
|
||||
|
||||
cc -g -DCONFIG_VAR_COOL -c mps.c (Unix/Mac OS X)
|
||||
cc -g -DCONFIG_VAR_COOL -c mps.c (Unix/macOS)
|
||||
cl /Zi /DCONFIG_VAR_COOL /c mps.c (Windows)
|
||||
|
||||
|
||||
|
|
@ -68,7 +68,7 @@ between it and the MPS. So if your format implementation is in, say,
|
|||
|
||||
then::
|
||||
|
||||
cc -O2 -c mymps.c (Unix/Mac OS X)
|
||||
cc -O2 -c mymps.c (Unix/macOS)
|
||||
cl /O2 /c mymps.c (Windows)
|
||||
|
||||
This will get your format code inlined with the MPS garbage collector.
|
||||
|
|
@ -111,7 +111,7 @@ with ``pkg_add -r gmake``.
|
|||
On Windows platforms the NMAKE tool is used. This comes with Microsoft
|
||||
Visual Studio C++ or the Microsoft Windows SDK.
|
||||
|
||||
On Mac OS X the MPS is built using Xcode, either by opening
|
||||
On macOS the MPS is built using Xcode, either by opening
|
||||
``mps.xcodeproj`` with the Xcode app, or using the command-line
|
||||
"xcodebuild" tool, installed from Xcode → Preferences → Downloads →
|
||||
Components → Command Line Tools.
|
||||
|
|
@ -137,15 +137,15 @@ Platform OS Architecture Compiler Makefile
|
|||
========== ========= ============= ============ =================
|
||||
``fri3gc`` FreeBSD IA-32 GCC ``fri3gc.gmk``
|
||||
``fri3ll`` FreeBSD IA-32 Clang ``fri3ll.gmk``
|
||||
``fri6gc`` FreeBSD x86_64 GCC ``fri6gc.gmk``
|
||||
``fri6ll`` FreeBSD x86_64 Clang ``fri6ll.gmk``
|
||||
``fri6gc`` FreeBSD x86-64 GCC ``fri6gc.gmk``
|
||||
``fri6ll`` FreeBSD x86-64 Clang ``fri6ll.gmk``
|
||||
``lii3gc`` Linux IA-32 GCC ``lii3gc.gmk``
|
||||
``lii6gc`` Linux x86_64 GCC ``lii6gc.gmk``
|
||||
``lii6ll`` Linux x86_64 Clang ``lii6ll.gmk``
|
||||
``lii6gc`` Linux x86-64 GCC ``lii6gc.gmk``
|
||||
``lii6ll`` Linux x86-64 Clang ``lii6ll.gmk``
|
||||
``w3i3mv`` Windows IA-32 Microsoft C ``w3i3mv.nmk``
|
||||
``w3i6mv`` Windows x86_64 Microsoft C ``w3i6mv.nmk``
|
||||
``xci3ll`` Mac OS X IA-32 Clang ``mps.xcodeproj``
|
||||
``xci6ll`` Mac OS X x86_64 Clang ``mps.xcodeproj``
|
||||
``w3i6mv`` Windows x86-64 Microsoft C ``w3i6mv.nmk``
|
||||
``xci3ll`` macOS IA-32 Clang ``mps.xcodeproj``
|
||||
``xci6ll`` macOS x86-64 Clang ``mps.xcodeproj``
|
||||
========== ========= ============= ============ =================
|
||||
|
||||
Historically, the MPS worked on a much wider variety of platforms, and
|
||||
|
|
@ -195,13 +195,13 @@ To build just one target, run one of these commands::
|
|||
nmake /f w3i3mv.nmk <target> (32-bit)
|
||||
nmake /f w3i6mv.nmk <target> (64-bit)
|
||||
|
||||
On Mac OS X, you can build from the command line with::
|
||||
On macOS, you can build from the command line with::
|
||||
|
||||
xcodebuild
|
||||
|
||||
On most platforms, the output of the build goes to a directory named
|
||||
after the platform (e.g. ``lii6ll``) so that you can share the source
|
||||
tree across platforms. On Mac OS X the output goes in a directory
|
||||
tree across platforms. On macOS the output goes in a directory
|
||||
called ``xc``. Building generates ``mps.a`` or ``mps.lib`` or
|
||||
equivalent, a library of object code which you can link with your
|
||||
application, subject to the :ref:`MPS licensing conditions <license>`.
|
||||
|
|
@ -241,7 +241,7 @@ loads a diagnostic stream of events into a `SQLite3
|
|||
<http://www.sqlite.org/>`_ database for processing. In order to build
|
||||
this program, you need to install the SQLite3 development resources.
|
||||
|
||||
* On Mac OS X, SQLite3 is pre-installed, so this tool builds by
|
||||
* On macOS, SQLite3 is pre-installed, so this tool builds by
|
||||
default.
|
||||
|
||||
* On Linux, you need to install the ``libsqlite3-dev`` package::
|
||||
|
|
|
|||
|
|
@ -180,17 +180,17 @@ prmcw3.c Mutator context implementation for Windows.
|
|||
prmcw3.h Mutator context interface for Windows.
|
||||
prmcw3i3.c Mutator context implementation for Windows, IA-32.
|
||||
prmcw3i6.c Mutator context implementation for Windows, x86-64.
|
||||
prmcxc.c Mutator context implementation for OS X.
|
||||
prmcxc.h Mutator context interface for OS X.
|
||||
prmcxci3.c Mutator context implementation for OS X, IA-32.
|
||||
prmcxci6.c Mutator context implementation for OS X, x86-64.
|
||||
prmcxc.c Mutator context implementation for macOS.
|
||||
prmcxc.h Mutator context interface for macOS.
|
||||
prmcxci3.c Mutator context implementation for macOS, IA-32.
|
||||
prmcxci6.c Mutator context implementation for macOS, x86-64.
|
||||
prot.h Protection interface. See design.mps.prot_.
|
||||
protan.c Protection implementation for standard C.
|
||||
protix.c Protection implementation for POSIX.
|
||||
protsgix.c Protection implementation for POSIX (signals part).
|
||||
protw3.c Protection implementation for Windows.
|
||||
protxc.c Protection implementation for OS X.
|
||||
protxc.h Protection interface for OS X.
|
||||
protxc.c Protection implementation for macOS.
|
||||
protxc.h Protection interface for macOS.
|
||||
pthrdext.c Protection implementation for POSIX (threads part).
|
||||
pthrdext.h Protection interface for POSIX (threads part).
|
||||
sp.h Stack probe interface. See design.mps.sp_.
|
||||
|
|
@ -210,7 +210,7 @@ th.h Threads interface. See design.mps.thread-manager_.
|
|||
than.c Threads implementation for standard C.
|
||||
thix.c Threads implementation for POSIX.
|
||||
thw3.c Threads implementation for Windows.
|
||||
thxc.c Threads implementation for OS X.
|
||||
thxc.c Threads implementation for macOS.
|
||||
vm.c Virtual memory implementation (common part).
|
||||
vm.h Virtual memory interface. See design.mps.vm_.
|
||||
vman.c Virtual memory implementation for standard C.
|
||||
|
|
@ -349,6 +349,7 @@ expt825.c Regression test for job000825_.
|
|||
fbmtest.c Free block manager (CBS and Freelist) test.
|
||||
finalcv.c :ref:`topic-finalization` coverage test.
|
||||
finaltest.c :ref:`topic-finalization` test.
|
||||
forktest.c :ref:`topic-thread-fork` test.
|
||||
fotest.c Failover allocator test.
|
||||
landtest.c Land test.
|
||||
locbwcss.c Locus backwards compatibility stress test.
|
||||
|
|
|
|||
|
|
@ -144,10 +144,6 @@ html_static_path = ['images']
|
|||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
html_use_smartypants = True
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
|
|
|||
|
|
@ -6,17 +6,40 @@ See <http://sphinx-doc.org/extensions.html>
|
|||
from collections import defaultdict
|
||||
from inspect import isabstract, isclass
|
||||
import re
|
||||
from . import designs
|
||||
import warnings
|
||||
|
||||
from docutils import nodes, transforms
|
||||
from docutils.parsers.rst import Directive
|
||||
from docutils.parsers.rst.directives.admonitions import BaseAdmonition
|
||||
from sphinx import addnodes
|
||||
from sphinx.directives.other import VersionChange
|
||||
from sphinx.domains import Domain
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.util.compat import Directive, make_admonition
|
||||
from sphinx.util.nodes import set_source_info, process_index_entry
|
||||
from sphinx.locale import versionlabels
|
||||
versionlabels['deprecatedstarting'] = 'Deprecated starting with version %s'
|
||||
from sphinx.locale import admonitionlabels, versionlabels
|
||||
|
||||
from . import designs
|
||||
|
||||
versionlabels['deprecatedstarting'] = "Deprecated starting with version %s"
|
||||
admonitionlabels.update(
|
||||
aka="Also known as",
|
||||
bibref="Related publication",
|
||||
bibrefs="Related publications",
|
||||
deprecated="Deprecated",
|
||||
historical="Historical note",
|
||||
link="Related link",
|
||||
links="Related links",
|
||||
note="Note",
|
||||
notes="Notes",
|
||||
opposite="Opposite term",
|
||||
opposites="Opposite terms",
|
||||
relevance="Relevance to memory management",
|
||||
see="See",
|
||||
similar="Similar term",
|
||||
similars="Similar terms",
|
||||
specific="In the MPS",
|
||||
topics="Topic",
|
||||
topicss="Topics"),
|
||||
|
||||
class MpsDomain(Domain):
|
||||
label = 'MPS'
|
||||
|
|
@ -25,12 +48,15 @@ class MpsDomain(Domain):
|
|||
class MpsDirective(Directive):
|
||||
@classmethod
|
||||
def add_to_app(cls, app):
|
||||
if hasattr(cls, 'name'): name = cls.name
|
||||
elif hasattr(cls, 'nodecls'): name = cls.nodecls.__name__
|
||||
else: return
|
||||
if hasattr(cls, 'nodecls') and hasattr(cls, 'visit'):
|
||||
app.add_node(cls.nodecls, html = cls.visit, latex = cls.visit,
|
||||
text = cls.visit, man = cls.visit)
|
||||
if hasattr(cls, 'name'):
|
||||
name = cls.name
|
||||
elif hasattr(cls, 'node_class') and cls.node_class is not None:
|
||||
name = cls.node_class.__name__
|
||||
else:
|
||||
return
|
||||
if hasattr(cls, 'node_class') and hasattr(cls, 'visit'):
|
||||
app.add_node(cls.node_class, html=cls.visit, latex=cls.visit,
|
||||
text=cls.visit, man=cls.visit)
|
||||
if hasattr(cls, 'domain'):
|
||||
app.add_directive_to_domain(cls.domain, name, cls)
|
||||
else:
|
||||
|
|
@ -82,143 +108,110 @@ def mps_ref_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
|||
return [refnode], []
|
||||
|
||||
class Admonition(nodes.Admonition, nodes.Element):
|
||||
pass
|
||||
plural = False
|
||||
|
||||
def visit_admonition_node(self, node):
|
||||
self.visit_admonition(node)
|
||||
name = type(node).__name__ + ('s' if node.plural else '')
|
||||
self.visit_admonition(node, name=name)
|
||||
|
||||
def depart_admonition_node(self, node):
|
||||
self.depart_admonition(node)
|
||||
|
||||
class AdmonitionDirective(MpsDirective):
|
||||
label = 'Admonition'
|
||||
class AdmonitionDirective(MpsDirective, BaseAdmonition):
|
||||
has_content = True
|
||||
visit = visit_admonition_node, depart_admonition_node
|
||||
|
||||
@classmethod
|
||||
def add_to_app(cls, app):
|
||||
if not hasattr(cls, 'nodecls'): return
|
||||
super(AdmonitionDirective, cls).add_to_app(app)
|
||||
|
||||
def run(self):
|
||||
ad = make_admonition(self.nodecls, self.name, [self.label],
|
||||
self.options, self.content, self.lineno,
|
||||
self.content_offset, self.block_text,
|
||||
self.state, self.state_machine)
|
||||
return ad
|
||||
|
||||
class PluralDirective(AdmonitionDirective):
|
||||
def run(self):
|
||||
ad = super(PluralDirective, self).run()
|
||||
refs = sum(1 for node in ad[0][1]
|
||||
if isinstance(node, addnodes.pending_xref)
|
||||
or isinstance(node, nodes.Referential))
|
||||
refs = sum(1 for node in ad[0][0]
|
||||
if isinstance(node, (addnodes.pending_xref,
|
||||
nodes.Referential)))
|
||||
if refs > 1:
|
||||
assert(isinstance(ad[0][0], nodes.title))
|
||||
ad[0][0][0] = nodes.Text(self.plural)
|
||||
ad[0].plural = True
|
||||
return ad
|
||||
|
||||
class aka(Admonition):
|
||||
pass
|
||||
|
||||
class AkaDirective(AdmonitionDirective):
|
||||
nodecls = aka
|
||||
label = 'Also known as'
|
||||
node_class = aka
|
||||
|
||||
class bibref(Admonition):
|
||||
pass
|
||||
|
||||
class BibrefDirective(PluralDirective):
|
||||
nodecls = bibref
|
||||
label = 'Related publication'
|
||||
plural = 'Related publications'
|
||||
node_class = bibref
|
||||
|
||||
class deprecated(Admonition):
|
||||
pass
|
||||
|
||||
class DeprecatedDirective(AdmonitionDirective):
|
||||
nodecls = deprecated
|
||||
label = 'Deprecated'
|
||||
node_class = deprecated
|
||||
|
||||
class historical(Admonition):
|
||||
pass
|
||||
|
||||
class HistoricalDirective(AdmonitionDirective):
|
||||
nodecls = historical
|
||||
label = 'Historical note'
|
||||
node_class = historical
|
||||
|
||||
class link(Admonition):
|
||||
pass
|
||||
|
||||
class LinkDirective(PluralDirective):
|
||||
nodecls = link
|
||||
label = 'Related link'
|
||||
plural = 'Related links'
|
||||
node_class = link
|
||||
|
||||
class note(Admonition):
|
||||
pass
|
||||
|
||||
class NoteDirective(AdmonitionDirective):
|
||||
nodecls = note
|
||||
label = 'Note'
|
||||
plural = 'Notes'
|
||||
node_class = note
|
||||
|
||||
def run(self):
|
||||
ad = super(NoteDirective, self).run()
|
||||
assert(isinstance(ad[0][0], nodes.title))
|
||||
if len(ad[0]) == 1: return ad
|
||||
if (isinstance(ad[0][1], nodes.enumerated_list)
|
||||
and sum(1 for _ in ad[0][1].traverse(nodes.list_item)) > 1
|
||||
or isinstance(ad[0][1], nodes.footnote)
|
||||
if (isinstance(ad[0][0], nodes.enumerated_list)
|
||||
and sum(1 for _ in ad[0][0].traverse(nodes.list_item)) > 1
|
||||
or isinstance(ad[0][0], nodes.footnote)
|
||||
and sum(1 for _ in ad[0].traverse(nodes.footnote)) > 1):
|
||||
ad[0][0][0] = nodes.Text(self.plural)
|
||||
ad[0].plural = True
|
||||
return ad
|
||||
|
||||
class opposite(Admonition):
|
||||
pass
|
||||
|
||||
class OppositeDirective(PluralDirective):
|
||||
nodecls = opposite
|
||||
label = 'Opposite term'
|
||||
plural = 'Opposite terms'
|
||||
node_class = opposite
|
||||
|
||||
class relevance(Admonition):
|
||||
pass
|
||||
|
||||
class RelevanceDirective(AdmonitionDirective):
|
||||
nodecls = relevance
|
||||
label = 'Relevance to memory management'
|
||||
node_class = relevance
|
||||
|
||||
class see(Admonition):
|
||||
pass
|
||||
|
||||
class SeeDirective(AdmonitionDirective):
|
||||
nodecls = see
|
||||
label = 'See'
|
||||
node_class = see
|
||||
|
||||
class similar(Admonition):
|
||||
pass
|
||||
|
||||
class SimilarDirective(PluralDirective):
|
||||
nodecls = similar
|
||||
label = 'Similar term'
|
||||
plural = 'Similar terms'
|
||||
node_class = similar
|
||||
|
||||
class specific(Admonition):
|
||||
pass
|
||||
|
||||
class SpecificDirective(AdmonitionDirective):
|
||||
domain = 'mps'
|
||||
nodecls = specific
|
||||
label = 'In the MPS'
|
||||
node_class = specific
|
||||
|
||||
class topics(Admonition):
|
||||
pass
|
||||
|
||||
class TopicsDirective(PluralDirective):
|
||||
nodecls = topics
|
||||
label = 'Topic'
|
||||
plural = 'Topics'
|
||||
node_class = topics
|
||||
|
||||
class GlossaryTransform(transforms.Transform):
|
||||
"""
|
||||
|
|
@ -329,8 +322,6 @@ class GlossaryTransform(transforms.Transform):
|
|||
print('{}:{}: WARNING: cross-reference to {}.'
|
||||
.format(doc, line, i))
|
||||
|
||||
|
||||
|
||||
def setup(app):
|
||||
designs.convert_updated(app)
|
||||
app.add_domain(MpsDomain)
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ Memory Management Glossary: M
|
|||
but faster and more expensive than :term:`backing store`.
|
||||
|
||||
It is common to refer only to the main memory of a computer;
|
||||
for example, "This server has 128 GB of memory" and "OS X 10.8
|
||||
requires at least 2 GB of memory".
|
||||
for example, "This server has 128 GB of memory" and "macOS
|
||||
High Sierra requires at least 2 GB of memory".
|
||||
|
||||
.. historical::
|
||||
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ General debugging advice
|
|||
On these operating systems, you can add this command to your
|
||||
``.gdbinit`` if you always want it to be run.
|
||||
|
||||
On OS X, barrier hits do not use signals and so do not enter the
|
||||
On macOS, barrier hits do not use signals and so do not enter the
|
||||
debugger.
|
||||
|
||||
#. .. index::
|
||||
|
|
@ -155,7 +155,7 @@ program (data segment, text segment, stack and heap):
|
|||
}
|
||||
|
||||
When ASLR is turned on, running this program outputs different
|
||||
addresses on each run. For example, here are four runs on OS X
|
||||
addresses on each run. For example, here are four runs on macOS
|
||||
10.9.3::
|
||||
|
||||
data: 0x10a532020 text: 0x10a531ed0 stack: 0x7fff556ceb1c heap: 0x7f9f80c03980
|
||||
|
|
@ -196,7 +196,7 @@ Here's the situation on each of the operating systems supported by the MPS:
|
|||
|
||||
$ setarch $(uname -m) -R ./myprogram
|
||||
|
||||
* On **OS X** (10.7 or later), ASLR can be disabled for a single
|
||||
* On **macOS** (10.7 or later), ASLR can be disabled for a single
|
||||
process by starting the process using :c:func:`posix_spawn`, passing
|
||||
the undocumented attribute ``0x100``, like this:
|
||||
|
||||
|
|
@ -213,7 +213,7 @@ Here's the situation on each of the operating systems supported by the MPS:
|
|||
|
||||
The MPS provides the source code for a command-line tool
|
||||
implementing this (``tool/noaslr.c``). We've confirmed that this
|
||||
works on OS X 10.9.3, but since the technique is undocumented, it
|
||||
works on macOS 10.9.3, but since the technique is undocumented, it
|
||||
may well break in future releases. (If you know of a documented way
|
||||
to achieve this, please :ref:`contact us <contact>`.)
|
||||
|
||||
|
|
|
|||
|
|
@ -976,8 +976,8 @@ as a root by calling :c:func:`mps_root_create_thread`::
|
|||
|
||||
void *marker = ▮
|
||||
mps_root_t stack_root;
|
||||
res = mps_root_create_thread(®_root, arena, thread, marker);
|
||||
if (res != MPS_RES_OK) error("Couldn't create root");
|
||||
res = mps_root_create_thread(&stack_root, arena, thread, marker);
|
||||
if (res != MPS_RES_OK) error("Couldn't create stack root");
|
||||
|
||||
In order to scan the control stack, the MPS needs to know where the
|
||||
:term:`cold end` of the stack is, and that's the role of the
|
||||
|
|
@ -1175,13 +1175,13 @@ before destroying the arena, and so on.
|
|||
|
||||
For example::
|
||||
|
||||
mps_arena_park(arena); /* ensure no collection is running */
|
||||
mps_ap_destroy(obj_ap); /* destroy ap before pool */
|
||||
mps_pool_destroy(obj_pool); /* destroy pool before fmt */
|
||||
mps_root_destroy(reg_root); /* destroy root before thread */
|
||||
mps_thread_dereg(thread); /* deregister thread before arena */
|
||||
mps_fmt_destroy(obj_fmt); /* destroy fmt before arena */
|
||||
mps_arena_destroy(arena); /* last of all */
|
||||
mps_arena_park(arena); /* ensure no collection is running */
|
||||
mps_ap_destroy(obj_ap); /* destroy ap before pool */
|
||||
mps_pool_destroy(obj_pool); /* destroy pool before fmt */
|
||||
mps_root_destroy(stack_root); /* destroy root before thread */
|
||||
mps_thread_dereg(thread); /* deregister thread before arena */
|
||||
mps_fmt_destroy(obj_fmt); /* destroy fmt before arena */
|
||||
mps_arena_destroy(arena); /* last of all */
|
||||
|
||||
|
||||
What next?
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ for details.
|
|||
single: Memory Pool System; supported target platforms
|
||||
single: platforms; supported
|
||||
|
||||
.. _guide-overview-platforms:
|
||||
|
||||
Supported target platforms
|
||||
--------------------------
|
||||
|
||||
|
|
@ -53,9 +55,9 @@ The MPS is currently supported for deployment on:
|
|||
- Linux 2.6 or later, on IA-32 using GCC and on x86-64 using GCC or
|
||||
Clang/LLVM;
|
||||
|
||||
- FreeBSD 7 or later, on IA-32 and x86-64, using GCC;
|
||||
- FreeBSD 7 or later, on IA-32 and x86-64, using GCC or Clang/LLVM;
|
||||
|
||||
- OS X 10.4 or later, on IA-32 and x86-64, using Clang/LLVM.
|
||||
- macOS 10.4 or later, on IA-32 and x86-64, using Clang/LLVM.
|
||||
|
||||
The MPS is highly portable and has run on many other processors and
|
||||
operating systems in the past (see :ref:`guide-build`). Most of the
|
||||
|
|
|
|||
|
|
@ -539,7 +539,7 @@ Memory management in various languages
|
|||
|
||||
.. link::
|
||||
|
||||
`Borland Delphi Home Page <http://www.borland.com/delphi/>`_,
|
||||
`Embarcadero (formely Borland) Delphi <https://www.embarcadero.com/products/delphi>`_,
|
||||
`Pascal standardization <http://www.open-std.org/JTC1/sc22/docs/oldwgs/wg2.html>`_.
|
||||
|
||||
Perl
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ following are true:
|
|||
|
||||
#. The MPS is running on Linux/IA-32 or Windows/IA-32. Extending this
|
||||
list to new (reasonable) operating systems should be tolerable (for
|
||||
example, OS X/IA-32). Extending this to new processor architectures
|
||||
example, macOS/IA-32). Extending this to new processor architectures
|
||||
requires more work.
|
||||
|
||||
#. The processor instruction that is accessing the object is of a
|
||||
|
|
|
|||
|
|
@ -4,6 +4,18 @@ Release notes
|
|||
=============
|
||||
|
||||
|
||||
.. _release-notes-1.117:
|
||||
|
||||
Release 1.117.0
|
||||
---------------
|
||||
|
||||
New features
|
||||
............
|
||||
|
||||
#. On FreeBSD, Linux and macOS, the MPS is now able to run in the
|
||||
child process after ``fork()``. See :ref:`topic-thread-fork`.
|
||||
|
||||
|
||||
.. _release-notes-1.116:
|
||||
|
||||
Release 1.116.0
|
||||
|
|
@ -21,7 +33,8 @@ New features
|
|||
#. The MPS no longer supports Linux 2.4 and 2.5. (These versions used
|
||||
LinuxThreads_ instead of POSIX threads; all major distributions
|
||||
have long since ceased to support these versions and so it is no
|
||||
longer convenient to test against them.)
|
||||
longer convenient to test against them.) See
|
||||
:ref:`guide-overview-platforms`.
|
||||
|
||||
.. _LinuxThreads: http://pauillac.inria.fr/~xleroy/linuxthreads/
|
||||
|
||||
|
|
|
|||
|
|
@ -1024,3 +1024,10 @@ Arena introspection and debugging
|
|||
return storage to the operating system). For reliable results
|
||||
call this function and interpret the result while the arena is
|
||||
in the :term:`parked state`.
|
||||
|
||||
.. seealso::
|
||||
|
||||
To find out which :term:`pool` the address belongs to, use
|
||||
:c:func:`mps_addr_pool`, and to find out which :term:`object
|
||||
format` describes the object at the address, use
|
||||
:c:func:`mps_addr_fmt`.
|
||||
|
|
|
|||
|
|
@ -228,7 +228,8 @@ Cautions
|
|||
|
||||
Therefore, the format methods must be able to be run at any time,
|
||||
including asynchronously or in parallel with the rest of the
|
||||
program.
|
||||
program. On POSIX systems, this means that format methods must be
|
||||
async-signal-safe.
|
||||
|
||||
#. Format methods must be re-entrant.
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ six-character code breaks down into three pairs of characters:
|
|||
``fr`` FreeBSD :c:macro:`MPS_OS_FR`
|
||||
``li`` Linux :c:macro:`MPS_OS_LI`
|
||||
``w3`` Windows :c:macro:`MPS_OS_W3`
|
||||
``xc`` OS X :c:macro:`MPS_OS_XC`
|
||||
``xc`` macOS :c:macro:`MPS_OS_XC`
|
||||
====== ================ ====================
|
||||
|
||||
The second pair of characters names the processor architecture:
|
||||
|
|
@ -126,7 +126,7 @@ Platform interface
|
|||
.. c:macro:: MPS_OS_XC
|
||||
|
||||
A :term:`C` preprocessor macro that indicates, if defined, that
|
||||
the MPS was compiled on an OS X operating system.
|
||||
the MPS was compiled on an macOS operating system.
|
||||
|
||||
|
||||
.. c:macro:: MPS_PF_ALIGN
|
||||
|
|
@ -209,28 +209,28 @@ Platform interface
|
|||
.. c:macro:: MPS_PF_XCI3GC
|
||||
|
||||
A :term:`C` preprocessor macro that indicates, if defined, that
|
||||
the :term:`platform` consists of the OS X operating system, the
|
||||
the :term:`platform` consists of the macOS operating system, the
|
||||
IA-32 processor architecture, and the GCC compiler.
|
||||
|
||||
|
||||
.. c:macro:: MPS_PF_XCI3LL
|
||||
|
||||
A :term:`C` preprocessor macro that indicates, if defined, that
|
||||
the :term:`platform` consists of the OS X operating system, the
|
||||
the :term:`platform` consists of the macOS operating system, the
|
||||
IA-32 processor architecture, and the Clang/LLVM compiler.
|
||||
|
||||
|
||||
.. c:macro:: MPS_PF_XCI6GC
|
||||
|
||||
A :term:`C` preprocessor macro that indicates, if defined, that
|
||||
the :term:`platform` consists of the OS X operating system, the
|
||||
the :term:`platform` consists of the macOS operating system, the
|
||||
x86-64 processor architecture, and the GCC compiler.
|
||||
|
||||
|
||||
.. c:macro:: MPS_PF_XCI6LL
|
||||
|
||||
A :term:`C` preprocessor macro that indicates, if defined, that
|
||||
the :term:`platform` consists of the OS X operating system, the
|
||||
the :term:`platform` consists of the macOS operating system, the
|
||||
x86-64 processor architecture, and the Clang/LLVM compiler.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ for useful advice.)
|
|||
If this preprocessor constant is defined, exclude the ANSI plinth
|
||||
(``mpsioan.c`` and ``mpsliban.c``) from the MPS. For example::
|
||||
|
||||
cc -DCONFIG_PLINTH_NONE -c mps.c (Unix/OS X)
|
||||
cc -DCONFIG_PLINTH_NONE -c mps.c (Unix/macOS)
|
||||
cl /Gs /DCONFIG_PLINTH_NONE /c mps.c (Windows)
|
||||
|
||||
Having excluded the ANSI plinth, you must of course supply your
|
||||
|
|
|
|||
|
|
@ -163,3 +163,10 @@ Pool introspection
|
|||
may immediately become invalidated. For reliable results call
|
||||
this function and interpret the result while the arena is in
|
||||
the :term:`parked state`.
|
||||
|
||||
.. seealso::
|
||||
|
||||
To find out which :term:`object format` describes the object
|
||||
at the address, use :c:func:`mps_addr_fmt`. If you only care
|
||||
whether the address belongs to a particular :term:`arena`, use
|
||||
:c:func:`mps_arena_has_addr`.
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ usable.
|
|||
|
||||
See :ref:`design-prot` for the design, and ``prot.h`` for the
|
||||
interface. There are implementations for POSIX in ``protix.c`` plus
|
||||
``protsgix.c``, Windows in ``protw3.c``, and OS X using Mach in
|
||||
``protsgix.c``, Windows in ``protw3.c``, and macOS using Mach in
|
||||
``protix.c`` plus ``protxc.c``.
|
||||
|
||||
There is a generic implementation in ``protan.c``, which can't
|
||||
|
|
@ -76,7 +76,7 @@ usable.
|
|||
stack` can be scanned.
|
||||
|
||||
See :ref:`design-prmc` for the design, and ``prmc.h`` for the
|
||||
interface. There are implementations on Unix, Windows, and OS X for
|
||||
interface. There are implementations on Unix, Windows, and macOS for
|
||||
IA-32 and x86-64.
|
||||
|
||||
There is a generic implementation in ``prmcan.c``, which can't
|
||||
|
|
@ -117,7 +117,7 @@ usable.
|
|||
|
||||
See :ref:`design-thread-manager` for the design, and ``th.h`` for
|
||||
the interface. There are implementations for POSIX in ``thix.c``
|
||||
plus ``pthrdext.c``, OS X using Mach in ``thxc.c``, Windows in
|
||||
plus ``pthrdext.c``, macOS using Mach in ``thxc.c``, Windows in
|
||||
``thw3.c``.
|
||||
|
||||
There is a generic implementation in ``than.c``, which necessarily
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ determine the address of allocated structures.
|
|||
There is currently no workaround for this issue. If this affects you,
|
||||
please :ref:`contact us <contact>`.
|
||||
|
||||
Other supported platforms are unaffected by this issue: Linux and OS X
|
||||
Other supported platforms are unaffected by this issue: Linux and macOS
|
||||
randomize the addresses allocated by :c:func:`mmap`, and Windows
|
||||
randomizes the addresses allocated by :c:func:`VirtualAlloc`.
|
||||
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ Signal and exception handling issues
|
|||
|
||||
* On Windows, you must not install a first-chance exception handler.
|
||||
|
||||
* On OS X, you must not install a thread-local Mach exception handler
|
||||
* On macOS, you must not install a thread-local Mach exception handler
|
||||
for ``EXC_BAD_ACCESS`` exceptions.
|
||||
|
||||
All of these things are, in fact, possible, but your program must
|
||||
|
|
@ -113,6 +113,43 @@ Signal and exception handling issues
|
|||
us <contact>`.
|
||||
|
||||
|
||||
.. index::
|
||||
single: fork safety
|
||||
|
||||
.. _topic-thread-fork:
|
||||
|
||||
Fork safety
|
||||
-----------
|
||||
|
||||
On Linux, FreeBSD and macOS, the MPS makes a best-effort attempt to
|
||||
continue running in the child process after a call to :c:func:`fork`,
|
||||
even if the :term:`client program` was running multiple
|
||||
:term:`threads` at the point where the call is made to :c:func:`fork`.
|
||||
|
||||
.. warning::
|
||||
|
||||
POSIX offers little or nothing in the way of guarantees about the
|
||||
situation of a child process running after a multi-threaded parent
|
||||
forked. The specification_ says:
|
||||
|
||||
.. _specification: http://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html
|
||||
|
||||
A process shall be created with a single thread. If a
|
||||
multi-threaded process calls :c:func:`fork`, the new process shall
|
||||
contain a replica of the calling thread and its entire address
|
||||
space, possibly including the states of mutexes and other
|
||||
resources. Consequently, to avoid errors, the child process may
|
||||
only execute async-signal-safe operations until such time as one
|
||||
of the :c:func:`exec` functions is called.
|
||||
|
||||
.. note::
|
||||
|
||||
Although only one thread is created in the child process, any
|
||||
threads in the parent process that were registered with the MPS by
|
||||
calling :c:func:`mps_thread_reg` must still be deregistered, by
|
||||
calling :c:func:`mps_thread_dereg`, before the arena is destroyed.
|
||||
|
||||
|
||||
.. index::
|
||||
single: thread; interface
|
||||
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ the branch. A typical invocation looks like this::
|
|||
release name according to the variant, for example,
|
||||
``mps-cet-1.110.0.zip``
|
||||
|
||||
On a Unix (including OS X) machine:
|
||||
On a Unix (including macOS) machine:
|
||||
|
||||
#. Create a fresh Perforce client workspace::
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ using it. The basic case is straightforward on supported platforms
|
|||
(see below)::
|
||||
|
||||
cd code
|
||||
cc -O2 -c mps.c Unix / Mac OS X (with Xcode command line)
|
||||
cc -O2 -c mps.c Unix / macOS (with Xcode command line)
|
||||
cl /O2 /c mps.c Windows (with Microsoft SDK or Visual Studio 2010)
|
||||
|
||||
This will produce an object file you can link with your project. For
|
||||
|
|
@ -79,7 +79,7 @@ The MPS is currently supported for deployment on:
|
|||
|
||||
- FreeBSD 7 or later, on IA-32 and x86-64, using GCC or Clang/LLVM;
|
||||
|
||||
- OS X 10.4 or later, on IA-32 and x86-64, using Clang/LLVM.
|
||||
- macOS 10.4 or later, on IA-32 and x86-64, using Clang/LLVM.
|
||||
|
||||
The MPS is highly portable and has run on many other processors and
|
||||
operating systems in the past (see `Building the MPS
|
||||
|
|
@ -144,7 +144,7 @@ Document History
|
|||
Copyright and Licence
|
||||
---------------------
|
||||
|
||||
Copyright (C) 2001-2016 Ravenbrook Limited. All rights reserved.
|
||||
Copyright (C) 2001-2018 Ravenbrook Limited. All rights reserved.
|
||||
<http://www.ravenbrook.com/>. This is an open source license. Contact
|
||||
Ravenbrook for commercial licensing options.
|
||||
|
||||
|
|
|
|||
|
|
@ -221,7 +221,9 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
|||
the pun would probably work fine almost everywhere)
|
||||
*/
|
||||
comment("About to fix with null scan state...");
|
||||
res = mps_fix(NULL, (mps_addr_t *) &p);
|
||||
MPS_SCAN_BEGIN(ss) {
|
||||
res = MPS_FIX12(NULL, (mps_addr_t *) &p);
|
||||
} MPS_SCAN_END(ss);
|
||||
error("fix with NULL scan state");
|
||||
if (res != MPS_RES_OK) return res;
|
||||
obj->data.ref[i].addr = p;
|
||||
|
|
|
|||
|
|
@ -222,7 +222,9 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
|||
the pun would probably work fine almost everywhere)
|
||||
*/
|
||||
comment("About to fix with unaligned scan state...");
|
||||
res = mps_fix(UNALIGNED, (mps_addr_t *) &p);
|
||||
MPS_SCAN_BEGIN(ss) {
|
||||
res = MPS_FIX12(UNALIGNED, (mps_addr_t *) &p);
|
||||
} MPS_SCAN_END(ss);
|
||||
error("fix with unaligned scan state");
|
||||
if (res != MPS_RES_OK) return res;
|
||||
obj->data.ref[i].addr = p;
|
||||
|
|
|
|||
|
|
@ -221,7 +221,9 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
|||
the pun would probably work fine almost everywhere)
|
||||
*/
|
||||
comment("About to fix with null pointer...");
|
||||
res = mps_fix(ss, NULL);
|
||||
MPS_SCAN_BEGIN(ss) {
|
||||
res = MPS_FIX2(ss, NULL);
|
||||
} MPS_SCAN_END(ss);
|
||||
error("fix with null pointer");
|
||||
if (res != MPS_RES_OK) return res;
|
||||
obj->data.ref[i].addr = p;
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
|||
*/
|
||||
comment("About to fix with null pointer...");
|
||||
p = NULL;
|
||||
res = mps_fix(ss, (mps_addr_t *) &p);
|
||||
res = MPS_FIX12(ss, (mps_addr_t *) &p);
|
||||
error("fix with null pointer");
|
||||
if (res != MPS_RES_OK) return res;
|
||||
obj->data.ref[i].addr = p;
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
|||
the pun would probably work fine almost everywhere)
|
||||
*/
|
||||
comment("About to fix on unaligned addr...");
|
||||
res = mps_fix(ss, UNALIGNED);
|
||||
res = MPS_FIX12(ss, (mps_addr_t *) UNALIGNED);
|
||||
error("unaligned fix");
|
||||
if (res != MPS_RES_OK) return res;
|
||||
obj->data.ref[i].addr = p;
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
|||
*/
|
||||
comment("About to fix with unaligned pointer...");
|
||||
p = UNALIGNED;
|
||||
res = mps_fix(ss, &p);
|
||||
res = MPS_FIX2(ss, &p);
|
||||
error("fix with unaligned pointer");
|
||||
if (res != MPS_RES_OK) return res;
|
||||
obj->data.ref[i].addr = p;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
# Set lots of variables correctly, depending on the platform
|
||||
# (which was determined in 'options')
|
||||
#
|
||||
# Currently, it should work correctly on Windows, Linux, MacOS X,
|
||||
# Currently, it should work correctly on Windows, Linux, macOS,
|
||||
# FreeBSD.
|
||||
#
|
||||
|
||||
|
|
|
|||
|
|
@ -33,4 +33,4 @@ $HARNESS_VERSION="3.5";
|
|||
# 3.3.1: fix bug in reporting compiler errors when compilation
|
||||
# _succeeds_
|
||||
# 3.4 -- Added P= (pathname equality) operator
|
||||
# 3.5 -- Platform detection based on uname; Linux and Mac OS X stuff
|
||||
# 3.5 -- Platform detection based on uname; Linux and macOS stuff
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
|||
p = obj->data.assoc;
|
||||
if (p != NULL) {
|
||||
commentif(fixcomments, "fix %li[assoc]", obj->data.id);
|
||||
res = MPS_FIX(ss, (mps_addr_t *) &p);
|
||||
res = MPS_FIX12(ss, (mps_addr_t *) &p);
|
||||
if (res != MPS_RES_OK) return res;
|
||||
if (p == NULL) {
|
||||
commentif(deathcomments, "fixed %li[assoc] to NULL", obj->data.id);
|
||||
|
|
@ -250,7 +250,7 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
|||
*/
|
||||
commentif(fixcomments, "fix %li[%i] -> %li",
|
||||
obj->data.id, i, obj->data.ref[i].id);
|
||||
res = MPS_FIX(ss, (mps_addr_t *) &p);
|
||||
res = MPS_FIX12(ss, (mps_addr_t *) &p);
|
||||
if (p == NULL) {
|
||||
commentif(deathcomments, "fixed %li[%i] to NULL", obj->data.id, i);
|
||||
INCCOUNTIF(obj->data.countflag, DYING_REFERENCE_COUNT);
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
|||
p = obj->data.assoc;
|
||||
if (p != NULL) {
|
||||
commentif(fixcomments, "fix %li[assoc]", obj->data.id);
|
||||
res = MPS_FIX(ss, (mps_addr_t *) &p);
|
||||
res = MPS_FIX12(ss, (mps_addr_t *) &p);
|
||||
if (res != MPS_RES_OK) return res;
|
||||
if (p == NULL) {
|
||||
commentif(deathcomments, "fixed %li[assoc] to NULL", obj->data.id);
|
||||
|
|
@ -236,7 +236,7 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
|||
*/
|
||||
commentif(fixcomments, "fix %li[%i] -> %li",
|
||||
obj->data.id, i, obj->data.ref[i].id);
|
||||
res = MPS_FIX(ss, (mps_addr_t *) &p);
|
||||
res = MPS_FIX12(ss, (mps_addr_t *) &p);
|
||||
if (p == NULL) {
|
||||
commentif(deathcomments, "fixed %li[%i] to NULL", obj->data.id, i);
|
||||
INCCOUNTIF(obj->data.countflag, DYING_REFERENCE_COUNT);
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
|||
/* make sure to fix the assoc pointer first */
|
||||
p = obj->data.assoc;
|
||||
if (p != NULL) {
|
||||
res = MPS_FIX(ss, (mps_addr_t *) &p);
|
||||
res = MPS_FIX12(ss, (mps_addr_t *) &p);
|
||||
if (res != MPS_RES_OK) return res;
|
||||
obj->data.assoc = p;
|
||||
}
|
||||
|
|
@ -161,7 +161,7 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
|||
p = obj->data.ref[i].addr;
|
||||
if (p != NULL)
|
||||
{
|
||||
res = MPS_FIX(ss, (mps_addr_t *) &p);
|
||||
res = MPS_FIX12(ss, (mps_addr_t *) &p);
|
||||
if (res != MPS_RES_OK) return res;
|
||||
obj->data.ref[i].addr = p;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
|||
if (obj->ref[0] != NULL)
|
||||
{
|
||||
if (formatcomments) printf("Fix: %p.\n", (void*)&(obj->ref[0]));
|
||||
res = MPS_FIX(ss, (mps_addr_t *) &(obj->ref[0])); /* pun! */
|
||||
res = MPS_FIX12(ss, (mps_addr_t *) &(obj->ref[0])); /* pun! */
|
||||
if (res != MPS_RES_OK)
|
||||
{
|
||||
return res;
|
||||
|
|
@ -112,7 +112,7 @@ mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
|||
if (obj->ref[1] != NULL)
|
||||
{
|
||||
if (formatcomments) printf("Fix: %p.\n", (void*)&(obj->ref[1]));
|
||||
res = MPS_FIX(ss, (mps_addr_t *) &(obj->ref[1])); /* pun! */
|
||||
res = MPS_FIX12(ss, (mps_addr_t *) &(obj->ref[1])); /* pun! */
|
||||
if (res != MPS_RES_OK)
|
||||
{
|
||||
return res;
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
|||
*/
|
||||
commentif(fixcomments, "fix %li[%i] -> %li",
|
||||
obj->data.id, i, obj->data.ref[i].id);
|
||||
res = MPS_FIX(ss, (mps_addr_t *) &p);
|
||||
res = MPS_FIX12(ss, (mps_addr_t *) &p);
|
||||
if (res != MPS_RES_OK) return res;
|
||||
obj->data.ref[i].addr = p;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -362,7 +362,7 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
|||
if (p != NULL) {
|
||||
commentif(fixcomments, "fix %li[assoc]", obj->data.id);
|
||||
q = p;
|
||||
res = MPS_FIX(ss, (mps_addr_t *) &p);
|
||||
res = MPS_FIX12(ss, (mps_addr_t *) &p);
|
||||
if (res != MPS_RES_OK) return res;
|
||||
if (p == NULL) {
|
||||
asserts(rank == mps_rank_weak(),
|
||||
|
|
@ -387,7 +387,7 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
|||
commentif(fixcomments, "fix %li[%i] -> %li",
|
||||
obj->data.id, i, obj->data.ref[i].id);
|
||||
q = p;
|
||||
res = MPS_FIX(ss, (mps_addr_t *) &p);
|
||||
res = MPS_FIX12(ss, (mps_addr_t *) &p);
|
||||
if (p == NULL) {
|
||||
asserts(rank == mps_rank_weak(),
|
||||
"non-weak reference fixed to NULL at %p[i]", obj);
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ This document is not confidential.
|
|||
`testrun.bat`_ Implements the ``testrun`` make target on Windows, where
|
||||
it is invoked from ``commpost.nmk``.
|
||||
`testrun.sh`_ Implements the ``testrun`` make target on FreeBSD and
|
||||
Linux, it is invoked from ``comm.gmk``, and on OS X, where
|
||||
it is invoked from the Xcode project.
|
||||
Linux, it is invoked from ``comm.gmk``, and on macOS,
|
||||
where it is invoked from the Xcode project.
|
||||
================= ==========================================================
|
||||
|
||||
.. _branch: branch
|
||||
|
|
@ -75,7 +75,7 @@ B. Document History
|
|||
C. Copyright and License
|
||||
------------------------
|
||||
|
||||
Copyright © 2002-2014 Ravenbrook Limited. All rights reserved.
|
||||
Copyright © 2002-2018 Ravenbrook Limited. All rights reserved.
|
||||
<http://www.ravenbrook.com/> This is an open source license. Contact
|
||||
Ravenbrook for commercial licensing options.
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ exposet0 =P
|
|||
expt825
|
||||
finalcv =P
|
||||
finaltest =P
|
||||
forktest =X
|
||||
fotest
|
||||
gcbench =N benchmark
|
||||
landtest
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue