= The user_lock library = [[PageOutline]] The [source:soft/giet_vm/giet_libs/user_lock.c user_lock.c] and [source:soft/giet_vm/giet_libs/user_lock.h 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 pointer. The 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 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 pointer has been successfully taken. === '''void lock_release'''( user_lock_t * lock ) === This function releases the lock identified by he 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 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 and arguments define the mesh size. The 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 pointer has been successfully taken. === '''void sqt_lock_release'''( sqt_lock_t * lock ) === This function releases the distributed lock identified by the pointer. It must be called by a task after a successful lock_acquire().