wiki:library_locks

Version 15 (modified by alain, 9 years ago) (diff)

--

The user_lock library

The user_lock.c and user_lock.h files define two types of locks:

  • user_lock_t : this lock uses a ticket allocation mechanism to enforce fairness and avoid live-locks. This lock is located in one single cluster, and the placement can be controlled by defining a specific vseg in the application mapping.
  • sqt_lock_t : this distributed lock can be used to avoid quadratic latency, when the protected resource is shared by a large number or threads. The SQT (Synchronization Quad-Tree) is distributed on all clusters of the mesh.

Each lock (user_lock_t object, or distributed sqt_lock_node_t) occupies a complete 64 bytes cache line to avoid false sharing.

The user_lock_t and sqt_lock_t being shared by several threads, should be defined as a global variable in the application code.

Atomic access functions

Both types of locks use the atomic_increment() function, that can be directly used by the applications.

unsigned int atomic_increment( unsigned int* shared, unsigned int increment)

This blocking function uses a LL/SC to atomically increment a shared variable identified by the <ptr> pointer. The <increment> argument define the increment value. It can be a negative value.

Simple lock access functions

void lock_init( user_lock_t * lock )

This function initializes the lock identified by the <lock> pointer. It should be called by one single task.

void lock_acquire( user_lock_t * lock )

This blocking function returns only when the lock identified by the <lock> pointer has been successfully taken.

void lock_release( user_lock_t * lock )

This function releases the lock identified by he <lock> pointer. It must be called by a task after a successful lock_acquire().

Distributed lock access functions

The SQT topology is completely defined by the (x_size / y_size) parameters, with the following constraints:

  • The involved clusters form a mesh(x_size * y_size).
  • The lower left involved cluster is cluster(0,0).
  • All involved clusters must contain a heap_x_y vseg declared in the mapping.
  • The number of involved tasks in a given cluster is the same for all involved clusters.

void sqt_lock_init( sqt_lock_t * lock , unsigned int x_size , unsigned int y_size , unsigned int nthreads )

This function initializes the lock identified by the <lock> pointer. It should be called by one single thread. It allocates both the distributed locks in each cluster (from the distributed heaps), and it initializes the sqt_lock_t variable (that must be allocated in the user application data segment). The <x_size> and <y_size> arguments define the mesh size. The <nthreads> arguments define the number of threads per cluster.

void sqt_lock_acquire( sqt_lock_t * lock )

This blocking function returns only when the distributed lock identified by the <lock> pointer has been successfully taken.

void sqt_lock_release( sqt_lock_t * lock )

This function releases the distributed lock identified by the <lock> pointer. It must be called by a task after a successful lock_acquire().