Table of Contents
Concurrency
source
Adverse effects on the program
avoid concurrency
Atomic integer operation interface
Atomic integer variable
ATOMIC_INIT() macro
atomic_set()
atomic_read()
atomic_add()/atomic_sub()
atomic_inc() / atomic_dec()
Bit atomic operation function
set_bit()
clear_bit()
change_bit()
Experimental session
dts_led.c file
app.c file
Makefile
Implementation process
Concurrency
root
Multi-thread, multi-process scheduling
various interruptions
Adverse impact on the program
Tampering with shared data
Incomplete action
Synchronization, deadlock, data competition, system scheduling overhead, etc.
Avoid concurrency
Hardware synchronization primitives: A set of atomic operations provided by computer hardware, which are indivisible and avoid parallel operation execution errors.
Atomic Integer Operation Interface
Atomic integer variable
typedef struct { int counter; } atomic_t;
ATOMIC_INIT() macro
//Define an atomic integer variable and initialize the assignment atomic_t data = ATOMIC_INIT(int i);
atomic_set()
//Used to set the value of integer atomic variable atomic_set(atomic_t *v, int i);
atomic_read()
//Get the value of the atomic variable int atomic_read(atomic_t *v);
atomic_add()/atomic_sub()
//Add i to integer atomic variable static inline void atomic_add(int i, atomic_t *v); // Subtract i from the integer atomic variable static inline void atomic_sub(int i, atomic_t *v);
atomic_inc() / atomic_dec()
//Integer atomic variable increases by 1 static inline void atomic_inc(atomic_t *v); //Integer atomic variable decreases by 1 static inline void atomic_dec(atomic_t *v);
Bit atomic operation function
set_bit()
/* * Set a certain position to 1 * nr: Which position of the operand is to be used? * addr: the address of the number to be operated on */ set_bit(int nr, unsigned long *addr);
clear_bit()
/* * Set a certain position to 0 * nr: Which position of the operand is to be used? * addr: the address of the number to be operated on */ clear_bit(int nr, unsigned long *addr);
change_bit()
/* * Reverse a bit * nr: Which position of the operand is to be used? * addr: the address of the number to be operated on */ int test_bit(int nr, unsigned long *addr);
Experimental session
dts_led.c file
#include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/uaccess.h> #include <linux/string.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/ide.h> #include <linux/errno.h> #include <linux/gpio.h> #include <linux/device.h> #include <linux/platform_device.h> #include <asm/mach/map.h> #include <asm/io.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_gpio.h> #define DEV_NAME "rgb_led" #define DEV_CNT (1) int rgb_led_red; int rgb_led_green; int rgb_led_blue; static atomic_t test_atomic = ATOMIC_INIT(1); /* Define the device number of the character device */ static dev_t led_devno; /* Define character device structure */ static struct cdev led_chrdev; /* Save the created class */ struct class *class_led; /* Save the created device */ struct device *device; /* rgb_led device tree node structure */ struct device_node *rgb_led_device_node; static int led_chrdev_open(struct inode *inode, struct file *filp) { if(atomic_read( & amp;test_atomic)){ atomic_set( & amp;test_atomic, 0); }else{ printk("driver on using! open failed!!!\ "); return -EBUSY; } printk("open form driver\ "); return 0; } static ssize_t led_chrdev_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) { int ret, error; unsigned char receive_data[10]; //Used to save received data unsigned int write_data = 0; if(cnt > 10) cnt = 10; error = copy_from_user(receive_data, buf, cnt); if(error < 0) return -1; ret = kstrtoint(receive_data, 16, & amp;write_data); if(ret) return -1; /* Set GPIO1_04 output level */ if(write_data & 0x04){ gpio_set_value(rgb_led_red, 0); }else{ gpio_set_value(rgb_led_red, 1); } /* Set GPIO4_20 output level */ if(write_data & 0x02){ gpio_set_value(rgb_led_green, 0); }else{ gpio_set_value(rgb_led_green, 1); } /* Set GPIO4_19 output level */ if(write_data & 0x01){ gpio_set_value(rgb_led_blue, 0); }else{ gpio_set_value(rgb_led_blue, 1); } return cnt; } static int led_chrdev_release(struct inode *inode, struct file *filp) { atomic_set( & amp;test_atomic, 1); printk(KERN_ALERT "finished!!!\ "); return 0; } static struct file_operations led_chrdev_fops = { .owner = THIS_MODULE, .open = led_chrdev_open, .write = led_chrdev_write, .release = led_chrdev_release, }; static int led_probe(struct platform_device *pdv) { int ret = -1; //Save error status code unsigned int register_data = 0; printk(KERN_ALERT "match successful!\ "); /* Get the device tree node of rgb_led */ rgb_led_device_node = of_find_node_by_path("/rgb_led"); if(rgb_led_device_node == NULL){ printk(KERN_ERR "get rgb_led failed!\ "); return -1; } /* Get the red led GPIO pin number */ rgb_led_red = of_get_named_gpio(rgb_led_device_node, "rgb_led_red", 0); if(rgb_led_red < 0){ printk(KERN_ERR "rgb_led_red failed!\ "); return -1; } /* Get the green led GPIO pin number */ rgb_led_green = of_get_named_gpio(rgb_led_device_node, "rgb_led_green", 0); if(rgb_led_green < 0){ printk(KERN_ERR "rgb_led_green failed!\ "); return -1; } /* Get the blue led GPIO pin number */ rgb_led_blue = of_get_named_gpio(rgb_led_device_node, "rgb_led_blue", 0); if(rgb_led_blue < 0){ printk(KERN_ERR "rgb_led_blue failed!\ "); return -1; } /* Set GPIO to output mode and default to high level */ gpio_direction_output(rgb_led_red, 1); gpio_direction_output(rgb_led_green, 1); gpio_direction_output(rgb_led_blue, 1); /* first step * Use dynamic allocation to obtain the device number, the secondary device number is 0 * The device name is rgb-leds, which can be viewed through the command cat /proc/devices * DEV_CNT is 1, currently only one device number is applied for */ ret = alloc_chrdev_region( & amp;led_devno, 0, DEV_CNT, DEV_NAME); if(ret < 0){ printk("fail to alloc led_devno\ "); goto alloc_err; } /* second step * Associated character device structure cdev and file operation structure file_operations */ led_chrdev.owner = THIS_MODULE; cdev_init( & amp;led_chrdev, & amp;led_chrdev_fops); /* third step * Add device to cdev_map hash table */ ret = cdev_add( & amp;led_chrdev, led_devno, DEV_CNT); if(ret < 0){ printk("fail to add cdev\ "); goto add_err; } /* Step 4: Create class */ class_led = class_create(THIS_MODULE, DEV_NAME); /* Step 5: Create device */ device = device_create(class_led, NULL, led_devno, NULL, DEV_NAME); return 0; alloc_err: return -1; add_err: //When adding a device fails, you need to log out the device number unregister_chrdev_region(led_devno, DEV_CNT); printk("error!\ "); } static const struct of_device_id rgb_led[] = { {.compatible = "fire,rgb_led"}, {/* sentinel */} }; /* Define platform device structure */ struct platform_driver led_platform_driver = { .probe = led_probe, .driver = { .name = "rgb-leds-platform", .owner = THIS_MODULE, .of_match_table = rgb_led, } }; static int __init led_platform_driver_init(void) { int DriverState; DriverState = platform_driver_register( & amp;led_platform_driver); printk(KERN_ALERT "DriverState is %d\ ", DriverState); return 0; } static void __exit led_platform_driver_exit(void){ /* Destroy device */ device_destroy(class_led, led_devno); /* Delete device number */ cdev_del( & amp;led_chrdev); /* Unregister character device */ unregister_chrdev_region(led_devno, DEV_CNT); /* Destroy class */ class_destroy(class_led); platform_driver_unregister( & amp;led_platform_driver); printk(KERN_ALERT "led_platform_driver exit\ "); } module_init(led_platform_driver_init); module_exit(led_platform_driver_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("couvrir"); MODULE_DESCRIPTION("led module"); MODULE_ALIAS("led module");
app.c file
#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <string.h> int main(int argc, char *argv[]) { if(argc != 2){ printf("commend error!\ "); return -1; } int fd = open("/dev/rgb_led", O_RDWR); if(fd < 0){ printf("open file:/dev/rgb_led failed!!!\ "); return -1; } int error = write(fd, argv[1], sizeof(argv[1])); if(error < 0){ printf("write file error!\ "); close(fd); } sleep(10); error = close(fd); if(error < 0){ printf("close file error!\ "); } return 0; }
Makefile
KERNEL_DIR=/home/couvrir/Desktop/ebf_linux_kernel_6ull_depth1/build_image/build ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- export ARCH CROSS_COMPILE obj-m:=dts_led.o all:app $(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules app: arm-linux-gnueabihf-gcc app.c -o App .PHONY:clean copy clean: $(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean sudo rm /home/couvrir/desktop/sharedir/*.ko App copy: sudo cp *.ko App /home/couvrir/Desktop/sharedir
Execution process
virtual machine:
Execute make and make copy. Generate .ko file.
Development board (executed in the mounting directory):
sudo insmod dts_led.ko
ls /dev/rgb_led
sudo /mnt/App 1 &
sudo /mnt/App 2
sudo /mnt/App 1 &
sudo /mnt/App 2
sudo rmmod dts_led.ko
The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. CS entry skill treeLinux introductionFirst introduction to Linux 34948 people are learning the system