
2 changed files with 249 additions and 223 deletions
@ -0,0 +1,237 @@ |
|||
# pEpACIDLang - Language Mapping Specification for C99 (LMS-C99) |
|||
|
|||
<!-- TOC --> |
|||
* [pEpACIDLang - Language Mapping Specification for C99 (LMS-C99)](#pepacidlang---language-mapping-specification-for-c99-lms-c99) |
|||
* [About This Document](#about-this-document) |
|||
* [IDL-Types](#idl-types) |
|||
* [Type Classes](#type-classes) |
|||
* [IDL-Type Mapping To C](#idl-type-mapping-to-c) |
|||
* [Creation and Destruction](#creation-and-destruction) |
|||
* [Primitive Types](#primitive-types) |
|||
* [Object Types](#object-types) |
|||
* [Allocators](#allocators) |
|||
* [Destructors](#destructors) |
|||
* [Method Parameters](#method-parameters) |
|||
* [Rules For Parameter Allocation](#rules-for-parameter-allocation) |
|||
* [Parameter Passing Modes](#parameter-passing-modes) |
|||
* [Mapping Table for C](#mapping-table-for-c) |
|||
* [Rules For Parameters Of Primitive-Type](#rules-for-parameters-of-primitive-type) |
|||
* [Update](#update) |
|||
* [Rules For Parameters Of Object-Type](#rules-for-parameters-of-object-type) |
|||
* [Read](#read) |
|||
* [Update](#update-1) |
|||
* [Consume](#consume) |
|||
* [Produce](#produce) |
|||
* [Rules For Multithreading](#rules-for-multithreading) |
|||
<!-- TOC --> |
|||
|
|||
This is the document specifying the pEpACIDLang language mapping for C99. |
|||
|
|||
C99, because this is the minimum language level for the generated target code. |
|||
We will use features of a higher language level once there are good reasons to do that. |
|||
|
|||
The interface generator implements parts of the language mapping specification. |
|||
|
|||
|
|||
## About This Document |
|||
|
|||
State: Draft, to be reviewed with fdik and positron. |
|||
|
|||
**ATTENTION, IMPORTANT** |
|||
In this document, all types expressed as T are the IDL-types, not their corresponding c-types. |
|||
An example for clarity: |
|||
If `T` is the type `string`, the IDL-type `string` is meant, so the c-type of `T*` is `char**`. |
|||
|
|||
Usually a variable typename is expressed as `T`. But sometimes `T` is being used to refer to an instance of type `T`. |
|||
This imprecision is used for brevity, but only where the context does not allow for an ambiguity. |
|||
|
|||
## IDL-Types |
|||
|
|||
### Type Classes |
|||
|
|||
There are only two type-classes. |
|||
|
|||
* Primitive Types |
|||
* Object Types |
|||
|
|||
### IDL-Type Mapping To C |
|||
|
|||
| Type-Class | IDL-Type | C-Type | |
|||
|------------|-----------|--------------| |
|||
| Primitive | int | int | |
|||
| Primitive | uint | unsigned int | |
|||
| Primitive | size | size_t | |
|||
| Primitive | bool | bool | |
|||
| Primitive | enum | enum | |
|||
| Object | struct | struct* | |
|||
| Object | string | char* | |
|||
| Object | binary | char* | |
|||
| Object | opaque | void* | |
|||
| Object | list\<T\> | list_T* | |
|||
| Object | pair<F,S> | pair_F_S* | |
|||
|
|||
### Creation and Destruction |
|||
|
|||
#### Primitive Types |
|||
|
|||
* Primitive types are always statically allocated |
|||
* Primitive types are trivially constructable and destroyable |
|||
* All storage classes (auto/static/extern/register) are allowed |
|||
|
|||
#### Object Types |
|||
|
|||
For any object-type `T`, corresponding `new` and `free` methods are being generated. |
|||
|
|||
To create an object of type `T` correctly, there are two ways: |
|||
|
|||
1. Using its allocator-method |
|||
2. Using any method that has a parameter of type `T` with mode `Produce` |
|||
|
|||
To destroy an object of type `T` correctly, the only way is to use its destructor-method. |
|||
|
|||
##### Allocators |
|||
|
|||
The allocator-method has the signature: |
|||
`IDL_STATUS new_T(T*)` |
|||
|
|||
* The memory for `T` has to be dynamically allocated |
|||
* An empty object is being created. Any object-types reachable through `T` are pointing to `NULL`. |
|||
|
|||
Result: |
|||
STATUS_OK - `T*` is pointing to a valid object |
|||
STATUS_ERROR - Dereferencing of `T*` is undefined behaviour |
|||
|
|||
##### Destructors |
|||
|
|||
The destructor-method has the signature: |
|||
`IDL_STATUS free_T(T*)` |
|||
|
|||
1. For all object-type members of `T` itself, their respective destructor-methods are being called |
|||
2. The memory for `T` is freed compatibly to how it was allocated using its allocator-method |
|||
3. `T*` is set to `NULL` |
|||
|
|||
Result: |
|||
STATUS_OK - All memory reachable through `T*` is freed and `T*` is NULL |
|||
STATUS_ERROR - FATAL (most implementations of `free()` can guarantee this will never happen) |
|||
|
|||
## Method Parameters |
|||
|
|||
The main concerns when sharing memory (e.g. in form of parameters) are: |
|||
|
|||
* Ownership: defined as who is allowed and responsible to destroy an object. |
|||
* Mutability: Who is allowed to change the contents of the memory location that is known to several parties. |
|||
|
|||
In environments where memory management is explicit, the lifecycle of data in memory is: |
|||
|
|||
1. Memory being allocated |
|||
2. Memory being shared with producers/consumers (e.g. as a parameter Read/Update/Consume) |
|||
3. Read/write operations by multiple parties (needs synchronization if multithreaded environment) |
|||
3. Make sure this memory will never be accessed again by nobody |
|||
4. Memory has to be freed exactly once and compatibly to how it was allocated |
|||
|
|||
Every such lifecycle must be completed. |
|||
All of this must be guaranteed. |
|||
|
|||
### Rules For Parameter Allocation |
|||
|
|||
Parameters have to be allocated as follows: |
|||
|
|||
* Primitive-types: The general rules outlined under [Creation and Destruction](#creation-and-destruction) apply |
|||
* Object-types: Using the allocator- and destructor-methods outlined under [Creation and Destruction](#creation-and-destruction) |
|||
|
|||
These rules apply regardless of the parameter passing mode. |
|||
|
|||
### Parameter Passing Modes |
|||
|
|||
The modes are named by describing what the callee does, from the perspective of the callee, using one verb. |
|||
|
|||
* `Read` - Immutable, ownership remains with caller |
|||
* `Update` - Mutable, ownership remains with caller |
|||
* `Consume` - Mutable, ownership goes to callee |
|||
* `Produce` - Immutable, ownership goes to caller |
|||
|
|||
#### Mapping Table for C |
|||
|
|||
Type of `T` as a function of type-class and mode. |
|||
Where `T` any of the respective IDL-Types (not their respective c-type, as mentioned in [About This Document](#about-this-document)). |
|||
|
|||
| Mode/Type-Class | READ | UPDATE | CONSUME | PRODUCE | |
|||
|------------------|------|--------|---------|---------| |
|||
| Primitive | T | T* | - (1) | - (1) | |
|||
| Object | T | T* | T | T* | |
|||
|
|||
#### Rules For Parameters Of Primitive-Type |
|||
|
|||
(1) A primitive-type cannot be consumed or produced because it's always statically allocated. |
|||
|
|||
### Update |
|||
|
|||
The caller has to allocate memory for `T*`. |
|||
The callee is allowed to mutate the memory pointed to by `T*`. |
|||
The caller is responsible to free the memory pointed to by `T*`. |
|||
|
|||
#### Rules For Parameters Of Object-Type |
|||
|
|||
##### Read |
|||
|
|||
The caller has to guarantee that either-or: |
|||
|
|||
* `T` is `NULL` |
|||
* `T` is pointing to a valid object of type `*T` (allocated as defined under 'Rules For Parameter Allocation') |
|||
This guarantee applies transitively for all object-type members of `*T`. |
|||
|
|||
The callee is not allowed to mutate or free any memory that can be reached through `T`. |
|||
The caller is responsible to free all the memory that can be reached through `T`. |
|||
|
|||
##### Update |
|||
|
|||
The caller has to guarantee that: |
|||
|
|||
* All object-types reachable through `T*` are either `NULL` or pointing to a valid object |
|||
(allocated as defined under [Rules For Parameter Allocation](#rules-for-parameter-allocation)) |
|||
|
|||
The callee is allowed to mutate the object in two ways: |
|||
|
|||
1. Mutate any primitive-types reachable through `T*` |
|||
2. Free or replace any object-types reachable trough `T*` |
|||
|
|||
The callee has to guarantee, that upon return of the method: |
|||
|
|||
* `T*` is pointing to a valid `*T` (allocated as defined under [Rules For Parameter Allocation](#rules-for-parameter-allocation)) |
|||
* All object-type members reachable through `T*` are either `NULL` or pointing to a valid object of type `*T` (allocated as |
|||
defined under [Rules For Parameter Allocation](#rules-for-parameter-allocation)) |
|||
|
|||
Upon success of the method call: |
|||
The caller must replace all pointers to `*T` and to any of its transitive members by dereferencing `T*` and its respective |
|||
transitive members. |
|||
The caller must free `T` and any of its transitive members. |
|||
|
|||
TODO: Upon any failure of the method call: |
|||
|
|||
##### Consume |
|||
|
|||
The same rules for mode `Read` apply, with the exception that the caller has to guarantee to never access `T` again in |
|||
any way. |
|||
|
|||
##### Produce |
|||
|
|||
The caller is allowed to pass a `T*` with an undefined value. |
|||
TODO... |
|||
|
|||
#### Rules For Multithreading |
|||
|
|||
These rules apply to all memory that can be accessed through a parameter. |
|||
Such memory must be allocated in the calling thread No such memory can be shared with other |
|||
TODO.... |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
Loading…
Reference in new issue