Linux-Kernel-Internals - Linux Kernel Internals: https://ankitkdev.com/blog/ - Char Driver: https://ankitkdev.com/blog/linux-kernel/device-driver/char-driver/ - Ioctl Interface: https://ankitkdev.com/blog/linux-kernel/device-driver/ioctl/ - Proc-Interface: https://ankitkdev.com/blog/linux-kernel/device-driver/proc/ - Completion-Variable: https://ankitkdev.com/blog/linux-kernel/concurrency/completion-variable/ - container_of(): https://ankitkdev.com/blog/linux-kernel/macros/container_of/ - Module Parameters: https://ankitkdev.com/blog/linux-kernel/macros/kernel-module/ - pr_fmt(): https://ankitkdev.com/blog/linux-kernel/macros/pr-family/ - Stringification: https://ankitkdev.com/blog/linux-kernel/macros/string/ - Debugging Macros: https://ankitkdev.com/blog/linux-kernel/macros/debug/ - Error Handling with Pointers: https://ankitkdev.com/blog/kernal-internals/error-handling/ - Kbuild Makefile: https://ankitkdev.com/blog/kernal-internals/kbuild/ - SLUB debug: https://ankitkdev.com/blog/kernel-debugging/debug-slub-memory/ - unsigned :\ 0 Bit-Fields in c: https://ankitkdev.com/blog/c/zero-width-bit-field/ - do { ... } while (0): https://ankitkdev.com/blog/c/do-while-loop/ - Error Handling: https://ankitkdev.com/blog/c/error-handling/ - C Memory Layout: https://ankitkdev.com/blog/c/c-memory-layout/ - Forward Declarations: https://ankitkdev.com/blog/c/forward-declaration-in-c/ - Return value by Macro: https://ankitkdev.com/blog/c/return-by-macro/ - Variadic Macro: https://ankitkdev.com/blog/c/variadic-macro/ - programming concepts: https://ankitkdev.com/blog/theory/ - Build & Install Linux Kernel for BBB: https://ankitkdev.com/blog/misc/build-linux-kernel-BBB/ - Configure U-boot for BBB: https://ankitkdev.com/blog/misc/configure-uboot-bbb/ - Install Ubuntu Server on Qemu: https://ankitkdev.com/blog/misc/install-ubuntu-server-on-qemu/ - Linux Kernel Mentorship Program: https://ankitkdev.com/blog/misc/linux-kernel-mentorship-program/ # Completion-Variable Completions are a simple synchronization mechanism that is preferable to sleeping and waking up in some situations. If you have a task that must simply sleep until some process has run its course, completions can do it easily and without race conditions ```c #include struct completion_dev { struct cdev cdev; struct completion completion; }; struct completion_dev completion_dev; static int completion_open(struct inode *inode, struct file *filp) { filp->private_data = container_of(inode->i_cdev, struct completion_dev, cdev); return 0; } static ssize_t completion_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { struct completion_dev *dev = filp->private_data; pr_debug("process %d(%s) going to sleep\n", current->pid, current->comm); wait_for_completion(&dev->completion); pr_debug("awoken %d(%s)\n", current->pid, current->comm); return 0; } static ssize_t completion_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos) { struct completion_dev *dev = filp->private_data; pr_debug("process %d(%s) awakening the readers...\n", current->pid, current->comm); complete(&dev->completion); return count; } static const struct file_operations completion_fops = { .owner = THIS_MODULE, .open = completion_open, .read = completion_read, .write = completion_write, }; static int __init m_init(void) { int ret; init_completion(&completion_dev.completion); ret = alloc_chrdev_region(&dev__t, 0, 1, MODULE_NAME); if (ret) { pr_debug("Error: %d -Cant't get major\n", ret); return ret; } cdev_init(&completion_dev.cdev, &completion_fops); ret = cdev_add(&completion_dev.cdev, dev__t, 1); [...], } ``` **References**: - https://elixir.bootlin.com/linux/v7.1.2/source/include/linux/completion.h