The SharC API consists of a set of type annotations, and a sharing cast operation for converting among these annotated types. This document will describe the meaning of the annotations and give examples of their use along with the sharing cast.
Type Annotations
SPRIVATE
The SPRIVATE annotation on a type indicates that an object of that type is owned by one thread, and is accessible only by that one thread. The annotation is enforced statically by a simple thread-escape analysis, and by a well-formedness condition on types.
The thread-escape analysis determines which unannotated types must be SDYNAMIC. All other unannotated types are given the SPRIVATE annotation. If the SPRIVATE annotation is given by the programmer to an object that the thread-escape analysis would have given the SDYNAMIC annotation, then SharC will ask the programmer for a sharing cast. (This is described in detail below.)
For a type to be well-formed it may not contain references to SPRIVATE data that are not themselves SPRIVATE. So, for example, the type
char SREADONLY* SPRIVATE is permitted, but the type
char SPRIVATE* SREADONLY is not.
SREADONLY
The SREADONLY annotation indicates that an object is readable by any thread, but not writable. This is true with one exception. A SREADONLY field of a SPRIVATE structure may be written. Correct use of this type is enforced by static checks.
SLOCKED(lock)
The SLOCKED annotation indicates that an object is protected by a lock, and is only accessible by the thread that holds the lock. This restriction is enforced by a runtime check. Here, lock is an expression or structure field for the address of a lock, which must be constant. That is, it must involve only unmodified locals or SREADONLY values.
SRACY
The SRACY annotation indicates that there are benign races on an object. No checking is necessary.
SDYNAMIC
The SDYNAMIC annotation indicates that SharC should enforce at runtime that an object is either read-only, or only accessed by one thread. It is usually not necessary for the programmer to make this annotation explicitly.
Strategy Inference
To reduce the annotation burden SharC will make unsurprising guesses for unannotated types.
- As mentioned above, the thread-escape analysis will mark as
SDYNAMIC unannotated objects that might be accessed by multiple threads. All other unannotated objects are marked SPRIVATE.
- A field or variable used in a
SLOCKED qualifier must be SREADONLY.
- Unannotated structure fields are inferred to have the same annotation as the enclosing instance. For this reason, structure fields can't be annotated
SPRIVATE.
- Outside of a structure definition, if the target type of a pointer is unannotated, then it is inferred to have the same annotation as the pointer itself.
- Inside of a structure definition, SharC gives unannotated pointer target types the
SDYNAMIC annotation if the structure is ever involved in a sharing cast. Otherwise, the above rule is followed.
SCAST (the sharing cast)
A sharing cast is used to change the sharing strategy for an object. In particular, when you have a pointer to an object being shared in some way, you can share it in some other way by casting the pointer. For example, in the function below, the thread-escape analysis has determined that the object pointed to by the data parameter must be annotated SDYNAMIC. However, the programmer has annotated the local ldata as SPRIVATE. Therefore, a sharing cast is needed in the assignment, and if one is not provided, SharC will emit a compile-time error.
void foo(char SDYNAMIC* data, ssize_t len) {
char SPRIVATE* ldata;
...
ldata = SCAST(data);
...
}
It is also important to note that it is no longer valid to refer to the object with the old sharing strategy. For that reason SCAST will also null out the old pointer. As a consequence of this, it is only possible to cast pointers that can be nulled out. That is, it is not possible to say SCAST(&obj), for example. Furthermore, a sharing cast can only be used to change the sharing strategy "one level down." For example, casting
from char SREADONLY*SREADONLY*SPRIVATE
to char SREADONLY*SPRIVATE*SPRIVATE is permitted, but casting
from char SREADONLY*SREADONLY*SPRIVATE
to char SPRIVATE*SPRIVATE*SPRIVATE is not.