GAP (hpc) - Chapter 11: Low-level functionality

Goto Chapter: Top 1 2 3 4 5 6 7 8 9 10 11 Ind
[Top of Book] [Contents] [Previous Chapter] [Next Chapter]

[MathJax on]

11 Low-level functionality
11.1 Explicit lock and unlock primitives
11.1-1 LOCK
11.1-2 TRYLOCK
11.1-3 UNLOCK
11.2 Hash locks
11.2-1 HASH_LOCK
11.2-2 HASH_UNLOCK
11.2-3 HASH_LOCK_SHARED
11.2-4 HASH_UNLOCK_SHARED
11.3 Migration to the public region
11.3-1 MAKE_PUBLIC
11.3-2 MAKE_PUBLIC_NORECURSE
11.4 Memory barriers
11.4-1 ORDERED_WRITE
11.4-2 ORDERED_READ
11.5 Object manipulation
11.5-1 SWITCH_OBJ
11.5-2 FORCE_SWITCH_OBJ

### 11 Low-level functionality

The functionality described in this section should only be used by experts, and even by those only with caution (especially the parts that relate to the memory model).

Not only is it possible to crash or hang the GAP kernel, it can happen in ways that are very difficult to reproduce, leading to software defects that are discovered only long after deployment of a package and then become difficult to correct.

The performance benefit of using these primitives is generally minimal; while concurrency can induce some overhead, the benefit from micromanaging concurrency in an interpreted language such as GAP is likely to be small.

These low-level primitives exist primarily for the benefit of kernel programmers; it allows them to prototype new kernel functionality in GAP before implementing it in C.

#### 11.1 Explicit lock and unlock primitives

The `LOCK` (11.1-1) operation combined with `UNLOCK` (11.1-3) is a low-level interface for the functionality of the statement.

##### 11.1-1 LOCK

`‣ LOCK`( [arg_1, ..., arg_n] ) | ( function )

`LOCK` takes zero or more pairs of parameters, where each is either an object or a boolean value. If an argument is an object, the region containing it will be locked. If an argument is the boolean value `false`, all subsequent locks will be read locks; if it is the boolean value `true`, all subsequent locks will be write locks. If the first argument is not a boolean value, all locks until the first boolean value will be write locks.

Locks are managed internally as a stack of locked regions; `LOCK` returns an integer indicating a pointer to the top of the stack; this integer is used later by the `UNLOCK` (11.1-3) operation to unlock locks on the stack up to that position. If `LOCK` should fail for some reason, it will return `fail`.

Calling `LOCK` with no parameters returns the current lock stack pointer.

##### 11.1-2 TRYLOCK

`‣ TRYLOCK`( [arg_1, ..., arg_n] ) | ( function )

`TRYLOCK` works similarly to `LOCK` (11.1-1). If it cannot acquire all region locks, it returns `fail` and does not lock any regions. Otherwise, its semantics are identical to `LOCK` (11.1-1).

##### 11.1-3 UNLOCK

`‣ UNLOCK`( stackpos ) | ( function )

`UNLOCK` unlocks all regions on the stack at stackpos or higher and sets the stack pointer to stackpos.

    gap> l1 := ShareObj([1,2,3]);;
    gap> l2 := ShareObj([4,5,6]);;
    gap> p := LOCK(l1);
    0
    gap> LOCK(l2);
    1
    gap> UNLOCK(p); # unlock both RegionOf(l1) and RegionOf(l2)
    gap> LOCK(); # current stack pointer
    0

#### 11.2 Hash locks

HPC-GAP supports hash locks; internally, the kernel maintains a fixed size array of locks; objects are mapped to a lock via hash function. The hash function is based on the object reference, not its contents (except for short integers and finite field elements).

    gap> l := [ 1, 2, 3];;
    gap> f := l -> Sum(l);;
    gap> HASH_LOCK(l);   # lock 'l'
    gap> f(l);           # do something with 'l'
    6
    gap> HASH_UNLOCK(l); # unlock 'l'

Hash locks should only be used for very short operations, since there is a chance that two concurrently locked objects map to the same hash value, leading to unnecessary contention.

Hash locks are unrelated to the locks used by the `atomic` statements and the `LOCK` (11.1-1) and `UNLOCK` (11.1-3) primitives.

##### 11.2-1 HASH_LOCK

`‣ HASH_LOCK`( obj ) | ( function )

`HASH_LOCK` obtains the read-write lock for the hash value associated with `obj`.

##### 11.2-2 HASH_UNLOCK

`‣ HASH_UNLOCK`( obj ) | ( function )

`HASH_UNLOCK` releases the read-write lock for the hash value associated with `obj`.

##### 11.2-3 HASH_LOCK_SHARED

`‣ HASH_LOCK_SHARED`( obj ) | ( function )

`HASH_LOCK_SHARED` obtains the read-only lock for the hash value associated with `obj`.

##### 11.2-4 HASH_UNLOCK_SHARED

`‣ HASH_UNLOCK_SHARED`( obj ) | ( function )

`HASH_UNLOCK_SHARED` releases the read-only lock for the hash value associated with `obj`.

#### 11.3 Migration to the public region

HPC-GAP allows migration of arbitrary objects to the public region. This functionality is potentially dangerous; for example, if two threads try resize a plain list simultaneously, this can result in memory corruption.

Accordingly, such data should never be accessed except through operations that protect accesses through locks, memory barriers, or other mechanisms.

##### 11.3-1 MAKE_PUBLIC

`‣ MAKE_PUBLIC`( obj ) | ( function )

`MAKE_PUBLIC` makes obj and all its subobjects members of the public region.

##### 11.3-2 MAKE_PUBLIC_NORECURSE

`‣ MAKE_PUBLIC_NORECURSE`( obj ) | ( function )

`MAKE_PUBLIC_NORECURSE` makes obj, but not any of its subobjects members of the public region.

#### 11.4 Memory barriers

The memory models of some processors do no guarantee that read and writes reflect accesses to main memory in the same order in which the processor performed them; for example, code may write variable `v1` first, and `v2` second; but the cache line containing `v2` is flushed to main memory first so that other processors see the change to `v2` before the change to `v1`.

Memory barriers can be used to prevent such counter-intuitive reordering of memory accesses.

##### 11.4-1 ORDERED_WRITE

`‣ ORDERED_WRITE`( expr ) | ( function )

The `ORDERED_WRITE` function guarantees that all writes that occur prior to its execution or during the evaluation of expr become visible to other processors before any of the code executed after.

Example:

    gap> y:=0;; f := function() y := 1; return 2; end;;
    gap> x := ORDERED_WRITE(f());
    2

Here, the write barrier ensure that the assignment to `y` that occurs during the call of `f()` becomes visible to other processors before or at the same time as the assignment to `x`.

This can also be done differently, with the same semantics:

    gap> t := f();; # temporary variable
    gap> ORDERED_WRITE(0);; # dummy argument
    gap> x := t;
    2

##### 11.4-2 ORDERED_READ

`‣ ORDERED_READ`( expr ) | ( function )

Conversely, the `ORDERED_READ` function ensures that reads that occur before its call or during the evaluation of expr are not reordered with respects to memory reads occurring after it.

#### 11.5 Object manipulation

There are two new functions to exchange a pair of objects.

##### 11.5-1 SWITCH_OBJ

`‣ SWITCH_OBJ`( obj1, obj2 ) | ( function )

`SWITCH_OBJ` exchanges its two arguments. All variables currently referencing obj1 will reference obj2 instead after the operation completes, and vice versa. Both objects stay within their previous regions.

    gap> a := [ 1, 2, 3];;
    gap> b := [ 4, 5, 6];;
    gap> SWITCH_OBJ(a, b);
    gap> a;
    [ 4, 5, 6 ]
    gap> b;
    [ 1, 2, 3 ]

The function requires exclusive access to both objects, which may necessitate using an atomic statement, e.g.:

    gap> a := ShareObj([ 1, 2, 3]);;
    gap> b := ShareObj([ 4, 5, 6]);;
    gap> atomic a, b do SWITCH_OBJ(a, b); od;
    gap> atomic readonly a do Display(a); od;
    [ 4, 5, 6 ]
    gap> atomic readonly b do Display(b); od;
    [ 1, 2, 3 ]

##### 11.5-2 FORCE_SWITCH_OBJ

`‣ FORCE_SWITCH_OBJ`( obj1, obj2 ) | ( function )

`FORCE_SWITCH_OBJ` works like `SWITCH_OBJ` (11.5-1), except that it can also exchange objects in the public region:

    gap> a := ShareObj([ 1, 2, 3]);;
    gap> b := MakeImmutable([ 4, 5, 6]);;
    gap> atomic a do FORCE_SWITCH_OBJ(a, b); od;
    gap> a;
    [ 4, 5, 6 ]

This function should be used with extreme caution and only with public objects for which only the current thread has a reference. Otherwise, undefined behavior and crashes can result from other threads accessing the public object concurrently.

[Top of Book] [Contents] [Previous Chapter] [Next Chapter]
Goto Chapter: Top 1 2 3 4 5 6 7 8 9 10 11 Ind

generated by GAPDoc2HTML