picotm  0.2.0
The Transactional Memory Module

The Transactional Memory module provides transactional semantics when accessing main memory. You can load and store variables in main memory, or adopt memory regions into a transactions. More...


file  picotm-tm.h
 Public interfaces of picotm's Transactional Memory module.

Detailed Description

The Transactional Memory module provides load and store operations for main memory. In order to avoid conflicting access to shared memory locations, picotm has to know which transaction uses which location. The Transactional Memory module maintains these information.

Call load_tx() to load a memory location into your transaction.

int x;
int x_tx;
load_tx(&x, &x_tx, sizeof(x));
// The value of 'x' is now stored in 'x_tx'.

This copies the value of 'x' into your transaction's variable 'x_tx' and puts the memory location of 'x' under control of the transaction manager. You're free to change the value of 'x_tx' at will, since it's transaction local. If you change it, the original, non-transactional value in 'x' remains unchanged.

Similarly, you can store a copy of a transactional variable in a memory location. This is done with store_tx().

int x;
int x_tx;
store_tx(&x, &x_tx, sizeof(x));
// The value of 'x_tx' will be committed into 'x'.

As with all transactional modifications, the store will not be executed immediately, but only become permament after the transaction successfully committed.

You don't have to deal with all these addresses yourself. The TM module comes with helper functions for various basic C types are provided. With load_int_tx() and store_int_tx() we can rewrite the example tranactions as shown below.

int x;
int x_tx = load_int_tx(&x);
// The value of 'x' is now stored in 'x_tx'.
store_int_tx(&x, x_tx);
// The value of 'x_tx' will be committed into 'x'.

Since address and pointer handling can be tricky, there are also helpers for loading and storing pointers. Note that these functions load and store the address stored in a pointer variable, but not the value stored at that address.

int* x_ptr;
int* x_ptr_tx = load_ptr_tx(&x_ptr);
// The value of 'x_ptr' is now stored in 'x_ptr_tx'.
store_ptr_tx(&x_ptr, &x_ptr_tx);
// The value of 'x_ptr_tx' will be committed into 'x_ptr'.

Loads and stores always copy value into or out of a transaction. There are cases where you don't want a copy, but the exact memory location of a value. This is called privatization. For example, the function memcpy() loads and stores an indefinite amount of data between memory buffers. The actual buffer size is often not known in advance. It would be wasteful to first load the data into a transaction-local buffer and then further store it in another buffer.

The functions privatize_tx() and privatize_c_tx() offer privatization of memory locations.

int x;
// The memory location of 'x' is now available within the transaction.
// Changes to 'x' will be committed into the memory location of 'x'.

This privatizes 'x' for transactional access from within the transaction. The number of bytes is given in the second argument. The flags argument is a bitmask of PICOTM_TM_PRIVATIZE_LOAD and PICOTM_TM_PRIVATIZE_STORE. These flags control how picotm handles the memory location. If you only privatized a memory location for loading or storing, you should execute the other operation.

There can be cases where you don't know in advance how long the privatized buffer is going to be. For example, when you privatize a C string, the length is not always given, but given by the location of the terminating \0 character. To privatize a memory region up to and including a specific character, use privatize_c_tx().

char* str = "foo";
// The string in 'str' is now available within the transaction.
// Changes to 'str' will be committed into the string of 'str'.

Using private_c_tx() with strings is the most common use case, but arbitrary characters are possible.

Finally, there is loadstore_tx(). Even through the name suggests load-and-store, the function is a mixture of load, store and privatization. It privatizes an input buffer for loading and an output buffer for storing, and copies the input buffer's content into the output buffer.

int ibuf[20];
int obuf[20];
loadstore_tx(ibuf, obuf, sizeof(obuf));
// The data in 'ibuf' will be committed into the memory of 'obuf'.