LinuxQuestions.org
Help answer threads with 0 replies.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 03-25-2017, 04:23 PM   #1
mrigendra
LQ Newbie
 
Registered: Dec 2014
Posts: 22

Rep: Reputation: Disabled
How to use semaphore in linux driver and is it a spinlock mechanism?


I have written a simple semaphore to understand how to use it,

Code:
    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/fs.h>
    #include <linux/uaccess.h>
    #include <linux/semaphore.h>
    #include <linux/device.h>
    #include <linux/cdev.h>
    
    MODULE_LICENSE("GPL");
    #define CLASS_NAME "myclass"
    #define MINOR_NUM 0
    #define MINOR_CNT 1
    static struct class *myclass=NULL;
    static struct device *mydevice=NULL;
    static dev_t mycdevt;
    static struct cdev *mycdev;
    static struct semaphore *sem=NULL; 
    //allow only one app to open the device node
    static int myopen(struct inode *inod, struct file *fp)
    {
    down(&sem);
    printk(KERN_INFO "critical section\n");
    
    return 0;
    }
    //on close call release semaphore, now other apps can open this device.
    static int myclose(struct inode *inod, struct file *fp )
    {
    up(&sem);
    printk(KERN_INFO "critical section freed\n");
    return 0;
    }
    
    static ssize_t myread(struct file *fp, char *buf, size_t len, loff_t *off)
    {
    return 0;
    }
    
    static ssize_t mywrite(struct file *fp, char *buf, size_t len, loff_t *off)
    {
    return 0;
    }
    
    static struct file_operations fops = 
    {
    	.open = myopen,
    	.release = myclose,
    	.read = myread,
    	.write = mywrite,
    };
    
    static int __init myinit(void)
    {
    int ret;
    
    ret = alloc_chrdev_region ( &mycdevt, MINOR_NUM, MINOR_CNT, "mycdevt");
    if(ret<0)
    {
    	printk(KERN_INFO "chardev can't be allocated\n");
    //	goto label;//todo
    }
    
    mycdev = cdev_alloc();//instead of cdev_alloc, we can use cdev_init(&mycdev, &fops);
    if(mycdev == NULL)
    {
    	printk(KERN_INFO"cdev_alloc failed\n");
    //	goto label;//todo
    }
    mycdev->ops = &fops;
    
    ret = cdev_add(mycdev, mycdevt, 1);
    if(ret < 0)
    {
    	printk(KERN_INFO"cdev_add failed\n");
    //	goto label;//todo
    }
    
    myclass = class_create(THIS_MODULE, CLASS_NAME);
    if(myclass == NULL)
    {
    	printk(KERN_INFO"class create failed\n");
    //	goto label;//todo
    }
    
    
    mydevice = device_create(myclass, NULL, mycdevt, NULL, "mydevice");
    if(mydevice == NULL)
    {
    	printk(KERN_INFO"device create failed\n");
    //	goto label;//todo
    }
    
    sema_init(&sem, 1);//here is the problem
    printk(KERN_INFO"myinit done\n");
    return 0;
    
    }
    
    static void __exit myexit(void)
    {
    device_destroy(myclass, mycdevt);
    class_unregister(myclass);
    class_destroy(myclass);
    cdev_del(mycdev);
    unregister_chrdev(MAJOR(mycdevt), "mycdevt");
    printk(KERN_INFO "exited\n");
    }  
    
    module_init(myinit);
    module_exit(myexit);
This is my app code,
Code:
    #include <stdio.h>
    #include <fcntl.h>
    //#include <linux/ioctl.h>
    //#include "ioctl_cmds.h"
    int main()
    {
    
    int fp, arg = 54, ret;
    char buff[] = "hello";
    fp = open ("/dev/mydevice", O_RDWR);
    if(fp < 0)
    printf("file can't be opened %d\n", fp);
    else
    printf("file opened\n");
    
    //close(fp);//don't release , run another same app. open call should fail maybe??
    
    return 0;
    }
I wanted to open the device file one at a time. When the app calls close, then only the node should be allowed to be used by another app.
Here is what observed,

1)After open call, release gets called even if I comment close system call.

2)If I remove down(&sem), and try to open the device node, Kernel crashes.

3)What is the proper way to do it?

4)I saw internally sema_init uses some spinlock mechanism to make a semaphore. So semaphore is a spinlock?
from semaphore.h

Code:
        struct semaphore {
    	raw_spinlock_t		lock;
    	unsigned int		count;
    	struct list_head	wait_list;
    };
    
    #define __SEMAPHORE_INITIALIZER(name, n)				\
    {									\
    	.lock		= __RAW_SPIN_LOCK_UNLOCKED((name).lock),	\
    	.count		= n,						\
    	.wait_list	= LIST_HEAD_INIT((name).wait_list),		\
    }

Last edited by mrigendra; 03-26-2017 at 09:58 AM.
 
Old 03-25-2017, 04:50 PM   #2
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=15, FreeBSD_12{.0|.1}
Posts: 6,264
Blog Entries: 24

Rep: Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195
Please place your code snippets inside [CODE]...[/CODE] tags for better readability. You may type those yourself or click the "#" button in the edit controls.
 
Old 03-26-2017, 09:25 AM   #3
smallpond
Senior Member
 
Registered: Feb 2011
Location: Massachusetts, USA
Distribution: Fedora
Posts: 4,140

Rep: Reputation: 1263Reputation: 1263Reputation: 1263Reputation: 1263Reputation: 1263Reputation: 1263Reputation: 1263Reputation: 1263Reputation: 1263
Where do you malloc sem?
 
Old 03-26-2017, 09:58 AM   #4
mrigendra
LQ Newbie
 
Registered: Dec 2014
Posts: 22

Original Poster
Rep: Reputation: Disabled
I did some change in init and myopen and myclose function, so that sem points to a permissible address

Code:
+#include <linux/slab.h>
+down(sem);
+up(sem);

+sem = (struct semaphore *)kzalloc(sizeof(struct semaphore), GFP_KERNEL);
+if(sem == NULL)
+	printk("sem uninitialized\n");
sema_init(sem, 1);
One improvement happened. While rmmod this driver I am no more getting crashes.

But still I see that when app calls open, myopen prints came followed by myclose prints in dmesg

Quote:
[33932.206392] myinit done
[33939.644741] critical section
[33939.644822] critical section freed
 
Old 03-27-2017, 08:14 AM   #5
smallpond
Senior Member
 
Registered: Feb 2011
Location: Massachusetts, USA
Distribution: Fedora
Posts: 4,140

Rep: Reputation: 1263Reputation: 1263Reputation: 1263Reputation: 1263Reputation: 1263Reputation: 1263Reputation: 1263Reputation: 1263Reputation: 1263
close is called on all open filehandles when a program exits.
 
Old 03-27-2017, 10:24 AM   #6
sundialsvcs
LQ Guru
 
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 10,659
Blog Entries: 4

Rep: Reputation: 3941Reputation: 3941Reputation: 3941Reputation: 3941Reputation: 3941Reputation: 3941Reputation: 3941Reputation: 3941Reputation: 3941Reputation: 3941Reputation: 3941
Within the Linux kernel, some locks are spinlocks. These are used to coordinate activities between multiple CPUs or cores.

Specifically: a "spinlock" uses a hardware mechanism (appropriate to the hardware platform in question ...) which atomically seeks to set a certain memory-location to a certain value, such that no other core or CPU can attempt to do the same thing simultaneously. As long as the CPU/core finds that it is prevented from doing to, it "spins its wheels" (uselessly) until it finally can. This mechanism is tolerable only for the tiniest of "races" which are presumed to have a very high probability of immediate success and a low probability of actually "spinning." It is used only for synchronization between otherwise-independent CPUs/cores.

"Opening" and "closing" a semaphore provides basic access to it. The "up" and "down" actions are analogous to raising or lowering a flag. The purpose of any [kernel] semaphore is to enable a [kernel] process to efficiently "go to sleep" until a certain event occurs, as indicated by a change in the status of the semaphore by someone else. (Or, as the case may be, "to spin its wheels.") The same concepts also exist in "user-land" albeit implemented differently. (User-land processes never "spin.")

Last edited by sundialsvcs; 03-27-2017 at 07:23 PM.
 
  


Reply

Tags
device driver, linux kernels, semaphores



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
In depth explanation of Spinlock, Semaphore, Mutex ram619 Linux - Kernel 7 09-23-2013 05:13 AM
serial 8250 loopback mechanism in driver code,bypassing the hardware layer completely abhijit.lamsoge Linux - Kernel 2 10-28-2012 11:53 PM
How to test the effect of a semaphore in a driver read function? AustinMarton Linux - Kernel 1 12-02-2010 02:24 PM
spinlock semaphore question 2.6.32 mac80211 GurgleSpuge Linux - Kernel 4 10-04-2010 09:07 PM
Driver Development - Semaphore problem! Help please! 7.e.Q Programming 1 11-10-2004 10:57 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 07:20 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration