
| Current Path : /usr/share/gap/doc/hpc/ |
Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 |
| Current File : //usr/share/gap/doc/hpc/chap3.txt |
[1X3 [33X[0;0YHow HPC-GAP organizes shared memory: Regions[133X[101X
[33X[0;0YHPC-GAP allows multiple threads to access data shared between them; to avoid
common concurrency errors, such as race conditions, it partitions GAP
objects into regions. Access to regions is regulated so that no two threads
can modify objects in the same region at the same time and so that objects
that are being read by one thread cannot concurrently be modified by
another.[133X
[1X3.1 [33X[0;0YThread-local regions[133X[101X
[33X[0;0YEach thread has an associated thread-local region. When a thread implicitly
or explicitly creates a new object, that object initially belongs to the
thread's thread-local region.[133X
[33X[0;0YOnly the thread can read or modify objects in its thread-local region. For
other threads to access an object, that object has to be migrated into a
different region first.[133X
[1X3.2 [33X[0;0YShared regions[133X[101X
[33X[0;0YShared regions are explicitly created through the [2XShareObj[102X ([14X3.9-9[114X) and
[2XShareSingleObj[102X ([14X3.9-15[114X) primitives (see below). Multiple threads can access
them concurrently, but accessing them requires that a thread uses an [10Xatomic[110X
statement to acquire a read or write lock beforehand.[133X
[33X[0;0YSee the section on [10Xatomic[110X statements ([14X3.9-43[114X) for details.[133X
[1X3.3 [33X[0;0YOrdering of shared regions[133X[101X
[33X[0;0YShared regions are by default ordered; each shared region has an associated
numeric precedence level. Regions can generally only be locked in order of
descending precedence. The purpose of this mechanism is to avoid accidental
deadlocks.[133X
[33X[0;0YThe ordering requirement can be overridden in two ways: regions with a
negative precedence are excluded from it. This exception should be used with
care, as it can lead to deadlocks.[133X
[33X[0;0YAlternatively, two or more regions can be locked simultaneously via the
[10Xatomic[110X statement. In this case, the ordering of these regions relative to
each other can be arbitrary.[133X
[1X3.4 [33X[0;0YThe public region[133X[101X
[33X[0;0YA special public region contains objects that only permit atomic operations.
These include, in particular, all immutable objects (immutable in the sense
that their in-memory representation cannot change).[133X
[33X[0;0YAll threads can access objects in the public region at all times without
needing to acquire a read- or write-lock beforehand.[133X
[1X3.5 [33X[0;0YThe read-only region[133X[101X
[33X[0;0YThe read-only region is another special region that contains objects that
are only meant to be read; attempting to modify an object in that region
will result in a runtime error. To obtain a modifiable copy of such an
object, the [2XCopyRegion[102X ([14X3.9-29[114X) primitive can be used.[133X
[1X3.6 [33X[0;0YMigrating objects between regions[133X[101X
[33X[0;0YObjects can be migrated between regions using a number of functions. In
order to migrate an object, the current thread must have exclusive access to
that object; the object must be in its thread-local region or it must be in
a shared region for which the current thread holds a write lock.[133X
[33X[0;0YThe [2XShareObj[102X ([14X3.9-9[114X) and [2XShareSingleObj[102X ([14X3.9-15[114X) functions create a new
shared region and migrate their respective argument to that region; [10XShareObj[110X
will also migrate all subobjects that are within the same region, while
[10XShareSingleObj[110X will leave the subobjects unaffected.[133X
[33X[0;0YThe [2XMigrateObj[102X ([14X3.9-21[114X) and [2XMigrateSingleObj[102X ([14X3.9-22[114X) functions migrate
objects to an existing region. The first argument of either function is the
object to be migrated; the second is either a region (as returned by the
[2XRegionOf[102X ([14X3.9-7[114X) function) or an object whose containing region the first
argument is to be migrated to.[133X
[33X[0;0YThe current thread needs exclusive access to the target region (denoted by
the second argument) for the operation to succeed. If successful, the first
argument will be in the same region as the second argument afterwards. In
the case of [2XMigrateObj[102X ([14X3.9-21[114X), all subobjects within the same region as
the first argument will also be migrated to the target region.[133X
[33X[0;0YFinally, [2XAdoptObj[102X ([14X3.9-26[114X) and [2XAdoptSingleObj[102X ([14X3.9-27[114X) are special cases of
[2XMigrateObj[102X ([14X3.9-21[114X) and [2XMigrateSingleObj[102X ([14X3.9-22[114X), where the target region
is the thread-local region of the current thread.[133X
[33X[0;0YTo migrate objects to the read-only region, one can use [2XMakeReadOnlyObj[102X
([14X3.9-35[114X) and [2XMakeReadOnlySingleObj[102X ([14X3.9-36[114X). The first migrates its argument
and all its subjobjects that are within the same region to the read-only
region; the second migrates only the argument itself, but not its
subobjects.[133X
[33X[0;0YIt is generally not possible to migrate objects explicitly to the public
region; only objects with purely atomic operations can be made public and
that is done automatically when they are created.[133X
[33X[0;0YThe exception are immutable objects. When [2XMakeImmutable[102X ([14XReference:
MakeImmutable[114X) is used, its argument is automatically moved to the public
region.[133X
[4X[32X Example [32X[104X
[4X[25Xgap>[125X [27XRegionOf(MakeImmutable([1,2,3]));[127X[104X
[4X[28X<public region>[128X[104X
[4X[32X[104X
[1X3.7 [33X[0;0YRegion names[133X[101X
[33X[0;0YRegions can be given names, either explicitly via [2XSetRegionName[102X ([14X3.9-38[114X) or
when they are created via [2XShareObj[102X ([14X3.9-9[114X) and [2XShareSingleObj[102X ([14X3.9-15[114X).
Thread-local regions, the public, and the readonly region are given names by
default.[133X
[33X[0;0YMultiple regions can have the same name.[133X
[1X3.8 [33X[0;0YControlling access to regions[133X[101X
[33X[0;0YIf either GAP code or a kernel primitive attempts to access an object that
it is not allowed to access according to these semantics, either a "write
guard error" (for a failed write access) or a "read guard error" (for a
failed read access) will be raised. The global variable [10XLastInaccessible[110X
will contain the object that caused such an error.[133X
[33X[0;0YOne exception is that threads can modify objects in regions that they have
only read access (but not write access) to using write-once functions - see
section [14X3.11[114X.[133X
[33X[0;0YTo inspect objects whose contents lie in other regions (and therefore cannot
be displayed by [2XPrintObj[102X ([14XReference: PrintObj[114X) or [2XViewObj[102X ([14XReference:
ViewObj[114X), the functions [2XViewShared[102X ([14X3.9-41[114X) and [2XUNSAFE_VIEW[102X ([14X3.9-42[114X) can be
used.[133X
[1X3.9 [33X[0;0YFunctions relating to regions[133X[101X
[1X3.9-1 NewRegion[101X
[33X[1;0Y[29X[2XNewRegion[102X( [[3Xname[103X, ][3Xprec[103X ) [32X function[133X
[33X[0;0YThe function [2XNewRegion[102X creates a new shared region. If the optional argument
[3Xname[103X is provided, then the name of the new region will be set to [3Xname[103X.[133X
[4X[32X Example [32X[104X
[4X[25Xgap>[125X [27XNewRegion("example region");[127X[104X
[4X[28X<region: example region>[128X[104X
[4X[32X[104X
[33X[0;0Y[2XNewRegion[102X will create a region with a high precedence level. It is intended
to be called by user code. The exact precedence level can be adjusted with
[3Xprec[103X, which must be an integer in the range [10X[-1000..1000][110X; [3Xprec[103X will be
added to the normal precedence level.[133X
[1X3.9-2 NewLibraryRegion[101X
[33X[1;0Y[29X[2XNewLibraryRegion[102X( [[3Xname[103X, ][3Xprec[103X ) [32X function[133X
[33X[0;0Y[2XNewLibraryRegion[102X functions like [2XNewRegion[102X ([14X3.9-1[114X), except that the
precedence of the region it creates is below that of [2XNewRegion[102X ([14X3.9-1[114X). It
is intended to be used by user libraries and GAP packages.[133X
[1X3.9-3 NewSystemRegion[101X
[33X[1;0Y[29X[2XNewSystemRegion[102X( [[3Xname[103X, ][3Xprec[103X ) [32X function[133X
[33X[0;0Y[2XNewSystemRegion[102X functions like [2XNewRegion[102X ([14X3.9-1[114X), except that the precedence
of the region it creates is below that of [2XNewLibraryRegion[102X ([14X3.9-2[114X). It is
intended to be used by the standard GAP library.[133X
[1X3.9-4 NewKernelRegion[101X
[33X[1;0Y[29X[2XNewKernelRegion[102X( [[3Xname[103X, ][3Xprec[103X ) [32X function[133X
[33X[0;0Y[2XNewKernelRegion[102X functions like [2XNewRegion[102X ([14X3.9-1[114X), except that the precedence
of the region it creates is below that of [2XNewSystemRegion[102X ([14X3.9-3[114X). It is
intended to be used by the GAP kernel, and GAP library code that interacts
closely with the kernel.[133X
[1X3.9-5 NewInternalRegion[101X
[33X[1;0Y[29X[2XNewInternalRegion[102X( [[3Xname[103X] ) [32X function[133X
[33X[0;0Y[2XNewInternalRegion[102X functions like [2XNewRegion[102X ([14X3.9-1[114X), except that the
precedence of the region it creates is the lowest available. It is intended
to be used for regions that are self-contained; i.e. no function that uses
such a region may lock another region while accessing it. The precedence
level of an internal region cannot be adjusted.[133X
[1X3.9-6 NewSpecialRegion[101X
[33X[1;0Y[29X[2XNewSpecialRegion[102X( [[3Xname[103X] ) [32X function[133X
[33X[0;0Y[2XNewLibraryRegion[102X ([14X3.9-2[114X) functions like [2XNewRegion[102X ([14X3.9-1[114X), except that the
precedence of the region it creates is negative. It is thus exempt from
normal ordering and deadlock checks.[133X
[1X3.9-7 RegionOf[101X
[33X[1;0Y[29X[2XRegionOf[102X( [3Xobj[103X ) [32X function[133X
[4X[32X Example [32X[104X
[4X[25Xgap>[125X [27XRegionOf(1/2);[127X[104X
[4X[28X<public region>[128X[104X
[4X[25Xgap>[125X [27XRegionOf([1,2,3]);[127X[104X
[4X[28X<region: thread region #0>[128X[104X
[4X[25Xgap>[125X [27XRegionOf(ShareObj([1,2,3]));[127X[104X
[4X[28X<region 0x45deaa0>[128X[104X
[4X[25Xgap>[125X [27XRegionOf(ShareObj([1,2,3]));[127X[104X
[4X[28X<region 0x45deaa0>[128X[104X
[4X[25Xgap>[125X [27XRegionOf(ShareObj([1,2,3], "test region"));[127X[104X
[4X[28X<region: test region>[128X[104X
[4X[32X[104X
[33X[0;0YNote that the unique number that each region is identified with is
system-specific and can change each time the code is being run. Region
objects returned by [10XRegionOf[110X can be compared:[133X
[4X[32X Example [32X[104X
[4X[25Xgap>[125X [27XRegionOf([1,2,3]) = RegionOf([4,5,6]);[127X[104X
[4X[28Xtrue[128X[104X
[4X[32X[104X
[33X[0;0YThe result in this example is true because both lists are in the same
thread-local region.[133X
[1X3.9-8 RegionPrecedence[101X
[33X[1;0Y[29X[2XRegionPrecedence[102X( [3Xobj[103X ) [32X function[133X
[33X[0;0Y[2XRegionPrecedence[102X will return the precedence of the region of [3Xobj[103X.[133X
[4X[32X Example [32X[104X
[4X[25Xgap>[125X [27XRegionPrecedence(NewRegion("Test"));[127X[104X
[4X[28X30000[128X[104X
[4X[25Xgap>[125X [27XRegionPrecedence(NewRegion("Test2", 1));[127X[104X
[4X[28X30001[128X[104X
[4X[25Xgap>[125X [27XRegionPrecedence(NewLibraryRegion("LibTest", -1));[127X[104X
[4X[28X19999[128X[104X
[4X[32X[104X
[1X3.9-9 ShareObj[101X
[33X[1;0Y[29X[2XShareObj[102X( [3Xobj[103X[[, [3Xname[103X], [3Xprec[103X] ) [32X function[133X
[33X[0;0YThe [2XShareObj[102X function creates a new shared region and migrates the object
and all its subobjects to that region. If the optional argument [3Xname[103X is
provided, then the name of the new region is set to [3Xname[103X.[133X
[33X[0;0Y[2XShareObj[102X will create a region with a high precedence level. It is intended
to be called by user code. The actual precedence level can be adjusted by
the optional [3Xprec[103X argument in the same way as for [2XNewRegion[102X ([14X3.9-1[114X).[133X
[1X3.9-10 ShareLibraryObj[101X
[33X[1;0Y[29X[2XShareLibraryObj[102X( [3Xobj[103X[[, [3Xname[103X], [3Xprec[103X] ) [32X function[133X
[33X[0;0Y[2XShareLibraryObj[102X functions like [2XShareObj[102X ([14X3.9-9[114X), except that the precedence
of the region it creates is below that of [2XShareObj[102X ([14X3.9-9[114X). It is intended
to be used by user libraries and GAP packages.[133X
[1X3.9-11 ShareSystemObj[101X
[33X[1;0Y[29X[2XShareSystemObj[102X( [3Xobj[103X[[, [3Xname[103X], [3Xprec[103X] ) [32X function[133X
[33X[0;0Y[2XShareSystemObj[102X functions like [2XShareObj[102X ([14X3.9-9[114X), except that the precedence
of the region it creates is below that of [2XShareLibraryObj[102X ([14X3.9-10[114X). It is
intended to be used by the standard GAP library.[133X
[1X3.9-12 ShareKernelObj[101X
[33X[1;0Y[29X[2XShareKernelObj[102X( [3Xobj[103X[[, [3Xname[103X], [3Xprec[103X] ) [32X function[133X
[33X[0;0Y[2XShareKernelObj[102X functions like [2XShareObj[102X ([14X3.9-9[114X), except that the precedence
of the region it creates is below that of [2XShareSystemObj[102X ([14X3.9-11[114X). It is
intended to be used by the GAP kernel, and GAP library code that interacts
closely with the kernel.[133X
[1X3.9-13 ShareInternalObj[101X
[33X[1;0Y[29X[2XShareInternalObj[102X( [3Xobj[103X[, [3Xname[103X] ) [32X function[133X
[33X[0;0Y[2XShareInternalObj[102X functions like [2XShareObj[102X ([14X3.9-9[114X), except that the precedence
of the region it creates is the lowest available. It is intended to be used
for regions that are self-contained; i.e. no function that uses such a
region may lock another region while accessing it.[133X
[1X3.9-14 ShareSpecialObj[101X
[33X[1;0Y[29X[2XShareSpecialObj[102X( [3Xobj[103X[, [3Xname[103X] ) [32X function[133X
[33X[0;0Y[2XShareLibraryObj[102X ([14X3.9-10[114X) functions like [2XShareObj[102X ([14X3.9-9[114X), except that the
precedence of the region it creates is negative. It is thus exempt from
normal ordering and deadlock checks.[133X
[1X3.9-15 ShareSingleObj[101X
[33X[1;0Y[29X[2XShareSingleObj[102X( [3Xobj[103X[[, [3Xname[103X], [3Xprec[103X] ) [32X function[133X
[33X[0;0YThe [2XShareSingleObj[102X function creates a new shared region and migrates the
object, but not its subobjects, to that region. If the optional argument
[3Xname[103X is provided, then the name of the new region is set to [3Xname[103X.[133X
[4X[32X Example [32X[104X
[4X[25Xgap>[125X [27Xm := [ [1, 2], [3, 4] ];;[127X[104X
[4X[25Xgap>[125X [27XShareSingleObj(m);;[127X[104X
[4X[25Xgap>[125X [27Xatomic readonly m do[127X[104X
[4X[25X>[125X [27X Display([ IsShared(m), IsShared(m[1]), IsShared(m[2]) ]);[127X[104X
[4X[25X>[125X [27X od;[127X[104X
[4X[28X[ true, false, false ][128X[104X
[4X[32X[104X
[33X[0;0Y[2XShareSingleObj[102X will create a region with a high precedence level. It is
intended to be called by user code. The actual precedence level can be
adjusted by the optional [3Xprec[103X argument in the same way as for [2XNewRegion[102X
([14X3.9-1[114X).[133X
[1X3.9-16 ShareSingleLibraryObj[101X
[33X[1;0Y[29X[2XShareSingleLibraryObj[102X( [3Xobj[103X[[, [3Xname[103X], [3Xprec[103X] ) [32X function[133X
[33X[0;0Y[2XShareSingleLibraryObj[102X functions like [2XShareSingleObj[102X ([14X3.9-15[114X), except that
the precedence of the region it creates is below that of [2XShareSingleObj[102X
([14X3.9-15[114X). It is intended to be used by user libraries and GAP packages.[133X
[1X3.9-17 ShareSingleSystemObj[101X
[33X[1;0Y[29X[2XShareSingleSystemObj[102X( [3Xobj[103X[[, [3Xname[103X], [3Xprec[103X] ) [32X function[133X
[33X[0;0Y[2XShareSingleSystemObj[102X functions like [2XShareSingleObj[102X ([14X3.9-15[114X), except that the
precedence of the region it creates is below that of [2XShareSingleLibraryObj[102X
([14X3.9-16[114X). It is intended to be used by the standard GAP library.[133X
[1X3.9-18 ShareSingleKernelObj[101X
[33X[1;0Y[29X[2XShareSingleKernelObj[102X( [3Xobj[103X[[, [3Xname[103X], [3Xprec[103X] ) [32X function[133X
[33X[0;0Y[2XShareSingleKernelObj[102X functions like [2XShareSingleObj[102X ([14X3.9-15[114X), except that the
precedence of the region it creates is below that of [2XShareSingleSystemObj[102X
([14X3.9-17[114X). It is intended to be used by the GAP kernel, and GAP library code
that interacts closely with the kernel.[133X
[1X3.9-19 ShareSingleInternalObj[101X
[33X[1;0Y[29X[2XShareSingleInternalObj[102X( [3Xobj[103X[, [3Xname[103X] ) [32X function[133X
[33X[0;0Y[2XShareSingleInternalObj[102X functions like [2XShareSingleObj[102X ([14X3.9-15[114X), except that
the precedence of the region it creates is the lowest available. It is
intended to be used for regions that are self-contained; i.e. no function
that uses such a region may lock another region while accessing it.[133X
[1X3.9-20 ShareSingleSpecialObj[101X
[33X[1;0Y[29X[2XShareSingleSpecialObj[102X( [3Xobj[103X[, [3Xname[103X] ) [32X function[133X
[33X[0;0Y[2XShareSingleLibraryObj[102X ([14X3.9-16[114X) functions like [2XShareSingleObj[102X ([14X3.9-15[114X),
except that the precedence of the region it creates is negative. It is thus
exempt from normal ordering and deadlock checks.[133X
[1X3.9-21 MigrateObj[101X
[33X[1;0Y[29X[2XMigrateObj[102X( [3Xobj[103X, [3Xtarget[103X ) [32X function[133X
[33X[0;0YThe [2XMigrateObj[102X function migrates [3Xobj[103X (and all subobjects contained within
the same region) to the region denoted by the [3Xtarget[103X argument. Here, [3Xtarget[103X
can either be a region object returned by [2XRegionOf[102X ([14X3.9-7[114X) or a normal gap
object. If [3Xtarget[103X is a normal gap object, [3Xobj[103X will be migrated to the region
containing [10Xtarget[110X.[133X
[33X[0;0YFor the operation to succeed, the current thread must have exclusive access
to the target region and the object being migrated.[133X
[1X3.9-22 MigrateSingleObj[101X
[33X[1;0Y[29X[2XMigrateSingleObj[102X( [3Xobj[103X, [3Xtarget[103X ) [32X function[133X
[33X[0;0YThe [2XMigrateSingleObj[102X function works like [2XMigrateObj[102X ([14X3.9-21[114X), except that it
does not migrate the subobjects of [10Xobj[110X.[133X
[1X3.9-23 LockAndMigrateObj[101X
[33X[1;0Y[29X[2XLockAndMigrateObj[102X( [3Xobj[103X, [3Xtarget[103X ) [32X function[133X
[33X[0;0YThe [2XLockAndMigrateObj[102X function works like [2XMigrateObj[102X ([14X3.9-21[114X), except that
it will automatically try to acquire a lock for the region containing [3Xtarget[103X
if it does not have one already.[133X
[1X3.9-24 IncorporateObj[101X
[33X[1;0Y[29X[2XIncorporateObj[102X( [3Xtarget[103X, [3Xindex[103X, [3Xvalue[103X ) [32X function[133X
[33X[0;0YThe [2XIncorporateObj[102X function allows convenient migration to a shared list or
record. If [3Xtarget[103X is a list, then [2XIncorporateObj[102X is equivalent to:[133X
[4X[32X Example [32X[104X
[4X[28XIncorporateObj := function(target, index, value)[128X[104X
[4X[28X atomic value do[128X[104X
[4X[28X target[index] := MigrateObj(value, target)[128X[104X
[4X[28X od;[128X[104X
[4X[28Xend;[128X[104X
[4X[32X[104X
[33X[0;0YIf [3Xtarget[103X is a record, then it is equivalent to:[133X
[4X[32X Example [32X[104X
[4X[28XIncorporateObj := function(target, index, value)[128X[104X
[4X[28X atomic value do[128X[104X
[4X[28X target.(index) := MigrateObj(value, target)[128X[104X
[4X[28X od;[128X[104X
[4X[28Xend;[128X[104X
[4X[32X[104X
[33X[0;0YThe intended purpose is the population of a shared list or record with
values after its creation. Example:[133X
[4X[32X Example [32X[104X
[4X[25Xgap>[125X [27Xlist := ShareObj([]);[127X[104X
[4X[25Xgap>[125X [27Xatomic list do[127X[104X
[4X[25X>[125X [27X IncorporateObj(list, 1, [1,2,3]);[127X[104X
[4X[25X>[125X [27X IncorporateObj(list, 2, [4,5,6]);[127X[104X
[4X[25X>[125X [27X IncorporateObj(list, 3, [7,8,9]);[127X[104X
[4X[25X>[125X [27X od;[127X[104X
[4X[25Xgap>[125X [27XViewShared(list);[127X[104X
[4X[28X[ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ][128X[104X
[4X[32X[104X
[33X[0;0YUsing plain assignment would leave the newly created lists in the
thread-local region.[133X
[1X3.9-25 AtomicIncorporateObj[101X
[33X[1;0Y[29X[2XAtomicIncorporateObj[102X( [3Xtarget[103X, [3Xindex[103X, [3Xvalue[103X ) [32X function[133X
[33X[0;0Y[2XAtomicIncorporateObj[102X extends [2XIncorporateObj[102X ([14X3.9-24[114X) by also locking the
target. I.e., for a list, it is equivalent to:[133X
[4X[32X Example [32X[104X
[4X[28XAtomicIncorporateObj := function(target, index, value)[128X[104X
[4X[28X atomic target, value do[128X[104X
[4X[28X target[index] := MigrateObj(value, target)[128X[104X
[4X[28X od;[128X[104X
[4X[28Xend;[128X[104X
[4X[32X[104X
[33X[0;0YIf [10Xtarget[110X is a record, then it is equivalent to:[133X
[4X[32X Example [32X[104X
[4X[28XAtomicIncorporateObj := function(target, index, value)[128X[104X
[4X[28X atomic value do[128X[104X
[4X[28X target.(index) := MigrateObj(value, target)[128X[104X
[4X[28X od;[128X[104X
[4X[28Xend;[128X[104X
[4X[32X[104X
[1X3.9-26 AdoptObj[101X
[33X[1;0Y[29X[2XAdoptObj[102X( [3Xobj[103X ) [32X function[133X
[33X[0;0YThe [2XAdoptObj[102X function migrates [3Xobj[103X (and all its subobjects contained within
the same region) to the thread's current region. It requires exclusive
access to [3Xobj[103X.[133X
[4X[32X Example [32X[104X
[4X[25Xgap>[125X [27Xl := ShareObj([1,2,3]);;[127X[104X
[4X[25Xgap>[125X [27XIsThreadLocal(l);[127X[104X
[4X[28Xfalse[128X[104X
[4X[25Xgap>[125X [27Xatomic l do AdoptObj(l); od;[127X[104X
[4X[25Xgap>[125X [27XIsThreadLocal(l);[127X[104X
[4X[28Xtrue[128X[104X
[4X[32X[104X
[1X3.9-27 AdoptSingleObj[101X
[33X[1;0Y[29X[2XAdoptSingleObj[102X( [3Xobj[103X ) [32X function[133X
[33X[0;0YThe [2XAdoptSingleObj[102X function works like [2XAdoptObj[102X ([14X3.9-26[114X), except that it
does not migrate the subobjects of [3Xobj[103X.[133X
[1X3.9-28 LockAndAdoptObj[101X
[33X[1;0Y[29X[2XLockAndAdoptObj[102X( [3Xobj[103X ) [32X function[133X
[33X[0;0YThe [2XLockAndAdoptObj[102X function works like [2XAdoptObj[102X ([14X3.9-26[114X), except that it
will attempt acquire an exclusive lock for the region containing [3Xobj[103X if it
does not have one already.[133X
[1X3.9-29 CopyRegion[101X
[33X[1;0Y[29X[2XCopyRegion[102X( [3Xobj[103X ) [32X function[133X
[33X[0;0YThe [2XCopyRegion[102X function performs a structural copy of [3Xobj[103X. The resulting
objects will be located in the current thread's thread-local region. The
function returns the copy as its result.[133X
[4X[32X Example [32X[104X
[4X[25Xgap>[125X [27Xl := MakeReadOnlyObj([1,2,3]);[127X[104X
[4X[28X[ 1, 2, 3 ][128X[104X
[4X[25Xgap>[125X [27Xl2 := CopyRegion(l);[127X[104X
[4X[28X[ 1, 2, 3 ][128X[104X
[4X[25Xgap>[125X [27XRegionOf(l) = RegionOf(l2);[127X[104X
[4X[28Xfalse[128X[104X
[4X[25Xgap>[125X [27XIsIdenticalObj(l, l2);[127X[104X
[4X[28Xfalse[128X[104X
[4X[25Xgap>[125X [27Xl = l2;[127X[104X
[4X[28Xtrue[128X[104X
[4X[32X[104X
[1X3.9-30 IsPublic[101X
[33X[1;0Y[29X[2XIsPublic[102X( [3Xobj[103X ) [32X function[133X
[33X[0;0YThe [2XIsPublic[102X function returns true if its argument is an object in the
public region, false otherwise.[133X
[4X[32X Example [32X[104X
[4X[25Xgap>[125X [27XIsPublic(1/2);[127X[104X
[4X[28Xtrue[128X[104X
[4X[25Xgap>[125X [27XIsPublic([1,2,3]);[127X[104X
[4X[28Xfalse[128X[104X
[4X[25Xgap>[125X [27XIsPublic(ShareObj([1,2,3]));[127X[104X
[4X[28Xfalse[128X[104X
[4X[25Xgap>[125X [27XIsPublic(MakeImmutable([1,2,3]));[127X[104X
[4X[28Xtrue[128X[104X
[4X[32X[104X
[1X3.9-31 IsThreadLocal[101X
[33X[1;0Y[29X[2XIsThreadLocal[102X( [3Xobj[103X ) [32X function[133X
[33X[0;0YThe [2XIsThreadLocal[102X function returns true if its argument is an object in the
current thread's thread-local region, false otherwise.[133X
[4X[32X Example [32X[104X
[4X[25Xgap>[125X [27XIsThreadLocal([1,2,3]);[127X[104X
[4X[28Xtrue[128X[104X
[4X[25Xgap>[125X [27XIsThreadLocal(ShareObj([1,2,3]));[127X[104X
[4X[28Xfalse[128X[104X
[4X[25Xgap>[125X [27XIsThreadLocal(1/2);[127X[104X
[4X[28Xfalse[128X[104X
[4X[25Xgap>[125X [27XRegionOf(1/2);[127X[104X
[4X[28X<public region>[128X[104X
[4X[32X[104X
[1X3.9-32 IsShared[101X
[33X[1;0Y[29X[2XIsShared[102X( [3Xobj[103X ) [32X function[133X
[33X[0;0YThe [2XIsShared[102X function returns true if its argument is an object in a shared
region. Note that if the current thread does not hold a lock on that shared
region, another thread can migrate [3Xobj[103X to a different region before the
result is being evaluated; this can lead to race conditions. The function is
intended primarily for debugging, not to build actual program logic around.[133X
[1X3.9-33 HaveReadAccess[101X
[33X[1;0Y[29X[2XHaveReadAccess[102X( [3Xobj[103X ) [32X function[133X
[33X[0;0YThe [2XHaveReadAccess[102X function returns true if the current thread has read
access to [3Xobj[103X.[133X
[4X[32X Example [32X[104X
[4X[25Xgap>[125X [27XHaveReadAccess([1,2,3]);[127X[104X
[4X[28Xtrue[128X[104X
[4X[25Xgap>[125X [27Xl := ShareObj([1,2,3]);;[127X[104X
[4X[25Xgap>[125X [27XHaveReadAccess(l);[127X[104X
[4X[28Xfalse[128X[104X
[4X[25Xgap>[125X [27Xatomic readonly l do t := HaveReadAccess(l); od;; t;[127X[104X
[4X[28Xtrue[128X[104X
[4X[32X[104X
[1X3.9-34 HaveWriteAccess[101X
[33X[1;0Y[29X[2XHaveWriteAccess[102X( [3Xobj[103X ) [32X function[133X
[33X[0;0YThe [2XHaveWriteAccess[102X function returns true if the current thread has write
access to [3Xobj[103X.[133X
[4X[32X Example [32X[104X
[4X[25Xgap>[125X [27XHaveWriteAccess([1,2,3]);[127X[104X
[4X[28Xtrue[128X[104X
[4X[25Xgap>[125X [27Xl := ShareObj([1,2,3]);;[127X[104X
[4X[25Xgap>[125X [27XHaveWriteAccess(l);[127X[104X
[4X[28Xfalse[128X[104X
[4X[25Xgap>[125X [27Xatomic readwrite l do t := HaveWriteAccess(l); od;; t;[127X[104X
[4X[28Xtrue[128X[104X
[4X[32X[104X
[1X3.9-35 MakeReadOnlyObj[101X
[33X[1;0Y[29X[2XMakeReadOnlyObj[102X( [3Xobj[103X ) [32X function[133X
[33X[0;0YThe [2XMakeReadOnlyObj[102X function migrates [3Xobj[103X and all its subobjects that are
within the same region as [3Xobj[103X to the read-only region. It returns [3Xobj[103X.[133X
[1X3.9-36 MakeReadOnlySingleObj[101X
[33X[1;0Y[29X[2XMakeReadOnlySingleObj[102X( [3Xobj[103X ) [32X function[133X
[33X[0;0YThe [2XMakeReadOnlySingleObj[102X function migrates [3Xobj[103X, but not any of its
subobjects, to the read-only region. It returns [3Xobj[103X.[133X
[1X3.9-37 IsReadOnlyObj[101X
[33X[1;0Y[29X[2XIsReadOnlyObj[102X( [3Xobj[103X ) [32X function[133X
[33X[0;0YThe [2XIsReadOnlyObj[102X function returns [9Xtrue[109X if [3Xobj[103X is in the read-only region,
[9Xfalse[109X otherwise.[133X
[4X[32X Example [32X[104X
[4X[25Xgap>[125X [27XIsReadOnlyObj([1,2,3]);[127X[104X
[4X[28Xfalse[128X[104X
[4X[25Xgap>[125X [27XIsReadOnlyObj(MakeImmutable([1,2,3]));[127X[104X
[4X[28Xfalse[128X[104X
[4X[25Xgap>[125X [27XIsReadOnlyObj(MakeReadOnlyObj([1,2,3]));[127X[104X
[4X[28Xtrue[128X[104X
[4X[32X[104X
[1X3.9-38 SetRegionName[101X
[33X[1;0Y[29X[2XSetRegionName[102X( [3Xobj[103X, [3Xname[103X ) [32X function[133X
[33X[0;0YThe [2XSetRegionName[102X function sets the name of the region of [3Xobj[103X to [3Xname[103X.[133X
[1X3.9-39 ClearRegionName[101X
[33X[1;0Y[29X[2XClearRegionName[102X( [3Xobj[103X ) [32X function[133X
[33X[0;0YThe [2XClearRegionName[102X function clears the name of the region of [3Xobj[103X to [3Xname[103X.[133X
[1X3.9-40 RegionName[101X
[33X[1;0Y[29X[2XRegionName[102X( [3Xobj[103X ) [32X function[133X
[33X[0;0YThe [2XRegionName[102X function returns the name of the region of [3Xobj[103X. If that
region does not have a name, [9Xfail[109X will be returned.[133X
[1X3.9-41 ViewShared[101X
[33X[1;0Y[29X[2XViewShared[102X( [3Xobj[103X ) [32X function[133X
[33X[0;0YThe [2XViewShared[102X function allows the inspection of objects in shared regions.
It will try to lock the region and then call [10XViewObj(obj)[110X. If it cannot
acquire a lock for the region, it will simply display the normal description
of the object.[133X
[1X3.9-42 UNSAFE_VIEW[101X
[33X[1;0Y[29X[2XUNSAFE_VIEW[102X( [3Xobj[103X ) [32X function[133X
[33X[0;0YThe [2XUNSAFE_VIEW[102X function allows the inspection of any object in the system,
regardless of whether the current thread has access to the region containing
it. It should be used with care: If the object inspected is being modified
by another thread concurrently, the resulting behavior is undefined.[133X
[33X[0;0YMoreover, the function works by temporarily disabling read and write guards
for regions, so other threads may corrupt memory rather than producing
errors.[133X
[33X[0;0YIt is generally safe to use if all threads but the current one are paused.[133X
[1X3.9-43 [33X[0;0YThe [10Xatomic[110X[101X[1X statement.[133X[101X
[33X[0;0YThe [10Xatomic[110X statement ensures exclusive or read-only access to one or more
shared regions for statements within its scope. It has the following syntax:[133X
[4X[32X Example [32X[104X
[4X[28Xatomic ([readwrite|readonly] expr (, expr)* )* do[128X[104X
[4X[28X statements[128X[104X
[4X[28Xod;[128X[104X
[4X[32X[104X
[33X[0;0YEach expression is evaluated and the region containing the resulting object
is locked with either a read-write or read-only lock, depending on the
keyword preceding the expression. If neither the [10Xreadwrite[110X nor the [10Xreadonly[110X
keyword was provided, read-write locks are used by default. Examples:[133X
[4X[32X Example [32X[104X
[4X[25Xgap>[125X [27Xl := ShareObj([1,2,3]);;[127X[104X
[4X[25Xgap>[125X [27Xatomic readwrite l do l[3] := 9; od;[127X[104X
[4X[25Xgap>[125X [27Xatomic l do l[2] := 4; od;[127X[104X
[4X[25Xgap>[125X [27Xatomic readonly l do Display(l); od;[127X[104X
[4X[28X[ 1, 4, 9 ][128X[104X
[4X[32X[104X
[4X[32X Example [32X[104X
[4X[25Xgap>[125X [27Xl := ShareObj([1,2,3,4,5]);;[127X[104X
[4X[25Xgap>[125X [27Xl2 := ShareObj([6,7,8]);;[127X[104X
[4X[25Xgap>[125X [27Xatomic readwrite l, readonly l2 do[127X[104X
[4X[25X>[125X [27X for i in [1..3] do l[i] := l2[i]; od;[127X[104X
[4X[25X>[125X [27X l3 := AdoptObj(l);[127X[104X
[4X[25X>[125X [27X od;[127X[104X
[4X[25Xgap>[125X [27Xl3;[127X[104X
[4X[28X[ 6, 7, 8, 4, 5 ][128X[104X
[4X[32X[104X
[33X[0;0YAtomic statements must observe region ordering. That means that the highest
precedence level of a region locked by an atomic statement must be less than
the lowest precedene level of a region that is locked by the same thread at
the time the atomic statement is executed.[133X
[1X3.10 [33X[0;0YAtomic functions[133X[101X
[33X[0;0YInstead of atomic regions, entire functions can be declared to be atomic.
This has the same effect as though the function's body were enclosed in an
atomic statement. Function arguments can be declared either [10Xreadwrite[110X or
[10Xreadonly[110X; they will be locked in the same way as for a lock statement. If a
function argument is preceded by neither [10Xreadwrite[110X nor [10Xreadonly[110X, the
corresponding object will not be locked. Example:[133X
[4X[32X Example [32X[104X
[4X[25Xgap>[125X [27XAddAtomic := atomic function(readwrite list, readonly item)[127X[104X
[4X[25X>[125X [27X Add(list, item);[127X[104X
[4X[25X>[125X [27X end;[127X[104X
[4X[32X[104X
[1X3.11 [33X[0;0YWrite-once functionality[133X[101X
[33X[0;0YThere is an exception to the rule that objects can only be modified if a
thread has write access to a region. A limited sets of objects can be
modified using the "bind once" family of functions. These allow the
modifications of objects to which a thread has read access in a limited
fashion.[133X
[33X[0;0YFor reasons of implementation symmetry, these functions can also be used on
the atomic versions of these objects.[133X
[33X[0;0YImplementation note: The functionality is not currently available for
component objects.[133X
[1X3.11-1 BindOnce[101X
[33X[1;0Y[29X[2XBindOnce[102X( [3Xobj[103X, [3Xindex[103X, [3Xvalue[103X ) [32X function[133X
[33X[0;0Y[2XBindOnce[102X modifies [3Xobj[103X, which can be a positional object, atomic positional
object, component object, or atomic component object. It inspects
[10Xobj![index][110X for the positional versions or [10Xobj!.(index)[110X for the component
versions. If the respective element is not yet bound, [3Xvalue[103X is assigned to
that element. Otherwise, no modification happens. The test and modification
occur as one atomic step. The function returns the value of the element;
i.e. the old value if the element was bound and [3Xvalue[103X if it was unbound.[133X
[33X[0;0YThe intent of this function is to allow concurrent initialization of
objects, where multiple threads may attempt to set a value concurrently.
Only one will succeed; all threads can then use the return value of [2XBindOnce[102X
as the definitive value of the element. It also allows for the lazy
initialization of objects in the read-only region.[133X
[33X[0;0YThe current thread needs to have at least read access to [3Xobj[103X, but does not
require write access.[133X
[1X3.11-2 TestBindOnce[101X
[33X[1;0Y[29X[2XTestBindOnce[102X( [3Xobj[103X, [3Xindex[103X, [3Xvalue[103X ) [32X function[133X
[33X[0;0Y[2XTestBindOnce[102X works like [2XBindOnce[102X ([14X3.11-1[114X), except that it returns [9Xtrue[109X if
the value could be bound and [9Xfalse[109X otherwise.[133X
[1X3.11-3 BindOnceExpr[101X
[33X[1;0Y[29X[2XBindOnceExpr[102X( [3Xobj[103X, [3Xindex[103X, [3Xexpr[103X ) [32X function[133X
[33X[0;0Y[2XBindOnceExpr[102X works like [2XBindOnce[102X ([14X3.11-1[114X), except that it evaluates the
parameterless function [3Xexpr[103X to determine the value. It will only evaluate
[3Xexpr[103X if the element is not bound.[133X
[33X[0;0YFor positional objects, the implementation works as follows:[133X
[4X[32X Example [32X[104X
[4X[28XBindOnceExprPosObj := function(obj, index, expr)[128X[104X
[4X[28X if not IsBound(obj![index]) then[128X[104X
[4X[28X return BindOnce(obj, index, expr());[128X[104X
[4X[28X else[128X[104X
[4X[28X return obj![index]);[128X[104X
[4X[28X fi;[128X[104X
[4X[28Xend;[128X[104X
[4X[32X[104X
[33X[0;0YThe implementation for component objects works analogously.[133X
[33X[0;0YThe intent is to avoid unnecessary computations if the value is already
bound. Note that this cannot be avoided entirely, because [10Xobj![index][110X or
[10Xobj!.(index)[110X can be bound while [3Xexpr[103X is evaluated, but it can minimize such
occurrences.[133X
[1X3.11-4 TestBindOnceExpr[101X
[33X[1;0Y[29X[2XTestBindOnceExpr[102X( [3Xobj[103X, [3Xindex[103X, [3Xexpr[103X ) [32X function[133X
[33X[0;0Y[2XTestBindOnceExpr[102X works like [2XBindOnceExpr[102X ([14X3.11-3[114X), except that it returns
[9Xtrue[109X if the value could be bound and [9Xfalse[109X otherwise.[133X
[1X3.11-5 StrictBindOnce[101X
[33X[1;0Y[29X[2XStrictBindOnce[102X( [3Xobj[103X, [3Xindex[103X, [3Xexpr[103X ) [32X function[133X
[33X[0;0Y[2XStrictBindOnce[102X works like [2XBindOnce[102X ([14X3.11-1[114X), except that it raises an error
if the element is already bound. This is intended for cases where a
read-only object is initialized, but where another thread trying to
initialize it concurrently would be an error.[133X