The Linux Channel

TUTORIALS :: Linux user-space Atomic Operations via GCC Atomic builtins

Written by: Ramin Farajpour, Kiran Kankipati, edited by Kiran Kankipati - Published: 22-Mar-2017


Atomic operations provide instructions that execute atomically without interruption. We all know the existence and significance of ATOMIC operations in Linux Kernel context (refer: atomic.h source). This is a part of kernel space can not work on user-space.

Watch Video: There is also a video I shot titled: Linux Kernel atomic_t datatype - atomic variables and APIs:

* Click the image above to watch this video on Youtube ↗

User space Atomic Operations :: GCC Atomic builtins: Not many are aware of the feasibility of Linux user-space Atomic operations. If you investigate you find what is known as GCC inbuilts. For example: /usr/include/glib-2.0/glib/gatomic.h
/usr/include/glib-2.0/glib/gatomic.h

So you got what is called as Built-in functions for atomic memory access. You can refer the official GCC online doc on the same: 5.44 Built-in functions for atomic memory access. You can get deep if you do a grep of one of these APIs in /usr/include as shown below:
$ grep sync_fetch_and_add * -R


Article: Atomic Operations - Where did atomic.h go?!? There is an author who did abstraction of these GCC Atomic builtins and wrote high-level abstraction to use the same with ease. Here is his article titled Atomic Operations - Where did atomic.h go?!?

Here is the copy-paste of his source (atomic.h) for quick reference:

//Source: http://golubenco.org/atomic-operations.html
#ifndef _ATOMIC_H
#define _ATOMIC_H

/* Check GCC version, just to be safe */
#if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC_MINOR__ < 1)
# error atomic.h works only with GCC newer than version 4.1
#endif /* GNUC >= 4.1 */

/**
 * Atomic type.
 */
typedef struct {
	volatile int counter;
} atomic_t;

#define ATOMIC_INIT(i)  { (i) }

/**
 * Read atomic variable
 * @param v pointer of type atomic_t
 *
 * Atomically reads the value of @v.
 */
#define atomic_read(v) ((v)->counter)

/**
 * Set atomic variable
 * @param v pointer of type atomic_t
 * @param i required value
 */
#define atomic_set(v,i) (((v)->counter) = (i))

/**
 * Add to the atomic variable
 * @param i integer value to add
 * @param v pointer of type atomic_t
 */
static inline void atomic_add( int i, atomic_t *v )
{
	(void)__sync_add_and_fetch(&v->counter, i);
}

/**
 * Subtract the atomic variable
 * @param i integer value to subtract
 * @param v pointer of type atomic_t
 *
 * Atomically subtracts @i from @v.
 */
static inline void atomic_sub( int i, atomic_t *v )
{
	(void)__sync_sub_and_fetch(&v->counter, i);
}

/**
 * Subtract value from variable and test result
 * @param i integer value to subtract
 * @param v pointer of type atomic_t
 *
 * Atomically subtracts @i from @v and returns
 * true if the result is zero, or false for all
 * other cases.
 */
static inline int atomic_sub_and_test( int i, atomic_t *v )
{
	return !(__sync_sub_and_fetch(&v->counter, i));
}

/**
 * Increment atomic variable
 * @param v pointer of type atomic_t
 *
 * Atomically increments @v by 1.
 */
static inline void atomic_inc( atomic_t *v )
{
	(void)__sync_fetch_and_add(&v->counter, 1);
}

/**
 * @brief decrement atomic variable
 * @param v: pointer of type atomic_t
 *
 * Atomically decrements @v by 1.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
static inline void atomic_dec( atomic_t *v )
{
	(void)__sync_fetch_and_sub(&v->counter, 1);
}

/**
 * @brief Decrement and test
 * @param v pointer of type atomic_t
 *
 * Atomically decrements @v by 1 and
 * returns true if the result is 0, or false for all other
 * cases.
 */
static inline int atomic_dec_and_test( atomic_t *v )
{
	return !(__sync_sub_and_fetch(&v->counter, 1));
}

/**
 * @brief Increment and test
 * @param v pointer of type atomic_t
 *
 * Atomically increments @v by 1
 * and returns true if the result is zero, or false for all
 * other cases.
 */
static inline int atomic_inc_and_test( atomic_t *v )
{
	return !(__sync_add_and_fetch(&v->counter, 1));
}

/**
 * @brief add and test if negative
 * @param v pointer of type atomic_t
 * @param i integer value to add
 *
 * Atomically adds @i to @v and returns true
 * if the result is negative, or false when
 * result is greater than or equal to zero.
 */
static inline int atomic_add_negative( int i, atomic_t *v )
{
	return (__sync_add_and_fetch(&v->counter, i) < 0);
}

#endif

You can download the above source (atomic.h) HERE.

Ramin (one of my students), who solely did this entire study/research and to confirm the GCC Atomic built-ins and the atomic.h abstraction layer, wrote the below sample code to test some of the APIs/features:

//Author : Ramin Farajpour Cami

#include "atomic.h"
#include <stdio.h>

int main(){

	atomic_t v;                   /* define v */
	atomic_t u = ATOMIC_INIT(0);  /* define u and initialize it to zero */

	atomic_set(&v, 4);     /* v = 4 (atomically) */
	printf("%d\n", atomic_read(&v));

	atomic_add(2, &v);     /* v = v + 2 = 6 (atomically) */
	printf("%d\n", atomic_read(&v));

	atomic_inc(&v);        /* v = v + 1 = 7 (atomically) */
	printf("%d\n", atomic_read(&v));

	return 0;
}

You can download the above source (main.c) HERE.

You can now compile and test the same as shown below:

kiran@WD-1TB2:/backups/Ramin/atomic_t$ ls
atomic.h  main.c
kiran@WD-1TB2:/backups/Ramin/atomic_t$ gcc -o main main.c
kiran@WD-1TB2:/backups/Ramin/atomic_t$ ls
atomic.h  main  main.c
kiran@WD-1TB2:/backups/Ramin/atomic_t$ ./main 
4
6
7
kiran@WD-1TB2:/backups/Ramin/atomic_t$

Run-time performance of various synchronization mechanism: A random find by Saravanan (one of my students), found an article where the author Alexander Demin, a Russian programmer, did interesting research on performance of various synchronization mechanisms. You can read his detailed article/research titled: Comparing the performance of atomic, spinlock and mutex. And here is his benchmarks:

MethodTime (sec.)
No synchronization0.070
LOCK0.481
Atomic0.457
Spinlock0.541
Mutex22.667

So this way you can use Atomic variables either directly or via abstraction layer in regular user-space Linux C programming. You can further experiment atomic operations in your concurrent multi-threaded applications where synchronization and data-integrity is critical.


Featured Video:


* Click the image above to watch this video on Youtube ↗


Suggested Topics:


Network Software Development:
 Bufferbloat in a Networking Device or an Appliance ↗
27-Jun-2018


 UDP sample socket code for Systems and Network software developers ↗
02-Feb-2017


 Tail Drop - by Network Schedulers to Drop Packets in Network Appliances ↗
27-Jun-2018


 iPerf tool - for network channel analysis, bandwidth tests and system & network benchmarking ↗
04-Jul-2018


 C code to check valid IP Address (IPv4) - Live Demo and Example ↗
18-Jun-2018



Research and Projects:
 Data Profiling and Visual Analysis tool for Deep Learning and AI - VLOG - The Linux Channel ↗
21-Jun-2018


 CYRIL ING√ČNIERIE - CoreFreq Linux CPU monitoring software ↗
19-Jun-2018


 Difference between Intel Xeon Server vs Desktop Core i7 vs Intel Mobile Atom vs ARM Processors ↗
19-Jun-2018


 Research Socket overhead in Linux vs Message Queues and benchmarking ↗
21-Jun-2017


 Tour of my new Home Networking Lab within VirtualBox VM ↗
16-May-2017



Linux (user-space), Systems Architecture:
 A Linux system call in C without a standard library ↗
10-Mar-2017


 Synchronization in Linux user-space - Architecting multi-process and multi-threads ↗
18-Sep-2018


 Coding a simple look-up-table in C - without Linked lists and a binary search ↗
17-Jun-2018


 Linux user-space Atomic Operations via GCC Atomic builtins ↗
22-Mar-2017


 Dynamic linking without STDLIB in Linux user-space C programming ↗
05-May-2017


 C code to read a /proc file in Linux user-space - Live Demo and Example ↗
11-Jun-2018


 Linux user-space - Shared Memory IPC - Live Demo and Example ↗
18-Jul-2018


 Linux user-space Pthread Synchronization via Mutex - Live Demo and Example ↗
03-Jun-2018



Linux Kernel Software Development:
 Tracking Linux Kernel bugs in Kernel.org Bugzilla (or Bugzee as we call it in the Industry) ↗
24-Sep-2018


 Kernel customization via make menuconfig - Linux Kernel Compilation (or a Kernel Build) ↗
11-Jul-2018


 How to submit your Linux Kernel Patch ↗
07-Feb-2017


 How to upgrade or install a latest current release Linux Kernel version manually in Ubuntu? ↗
05-Jan-2018


 Linux Networking Stack :: RFS: Receive Flow Steering ↗
09-Dec-2017



Software Development (Programming) Tools:
 Kompare GUI patch and diff tool in Linux ↗
19-Jun-2018


 Bluefish IDE - a simple versatile light-weight best editor to edit kernel source files, html files, c source code, text files, SQL schema and so on. ↗
19-Jun-2018



Embedded Projects:
 GPS Geo-tracking system using LinkIt ONE ↗
11-Jan-2017


 Using a GPS Sensor ↗
28-Jul-2017


 

Join The Linux Channel :: Facebook Group


Join a course:

💎 Linux Kernel and Systems Software: PDF Brochure

💎 Linux and Network Software Developer: PDF Brochure


💗 Help shape the future: Sponsor/Donate


Recommended Topics:
Featured Video:

* Click the image above to watch this video on Youtube ↗


Trending Video:

* Click the image above to watch this video on Youtube ↗

TUTORIALS :: Research Socket overhead in Linux vs Message Queues and benchmarking:


Linux Kernel Programming - Device Drivers:


Research :: Content Delivery Networks (CDN):
CDN Networks


Recommended Video:

* Click the image above to watch this video on Youtube ↗

The TOFFEE Project - v10.7 :: Updated: 10-Nov-2018 :: © 2018 :: Author: Kiran Kankipati
Your IP: 54.147.142.16 :: Browser: CCBot/2.0 (https://commoncrawl.org/faq/)