Monthly Archives: August 2015

Concurrency Management Part – 3

<< Previous Article

In the last two articles, we have discussed some of the commonly used synchronization mechanisms in kernel. It was observed that these synchronization mechanisms restrict the access to the resource, irrespective of the operation which thread/process wants to perform on the resource. This in turn, mean that even though one thread has acquired the resource for read access, another thread can’t access the  same resource for reading. In most of the cases, it is quite desirable to have two or more threads having the read access to the resource as far as they are not modifying the resource data structure.  This will result into the improved system performance. Read on to find out the mechanism provided by kernel to achieve this.

Reader / Writer Semaphore

This is the type of semaphore, which provides the access depending on operation which thread/process wants to perform on the data structure. With this, multiple readers can have the access to the resource at the same time, while only one writer gets access at a time. So, will reader be allowed if write operation is in progress? Definitely not. At a time, there can be either read or write operation in progress as usual, but there can be multiple read operations. So, let’s look at the data structures associated with the reader / writer semaphores:

#include <linux/rwsem.h>

// Data Structure
structure rw_semaphore rw_sem;

// Initialization
void init_rwsem(&rw_sem);

// Operations for reader
void down_read(&rw_sem);
void up_read(&rw_sem);

// Operations for writer
void down_write(&rw_sem);
void up_write(&rw_sem);

As seen above, initialization operation is similar to what we do with the regular semaphore, but key difference lies in the fact that we have separate operations for readers and writers.

Below is an example usage of reader / writer semaphore:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h> 
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <linux/semaphore.h>
#include <linux/sched.h>
#include <linux/delay.h>

#define FIRST_MINOR 0
#define MINOR_CNT 1

static dev_t dev;
static struct cdev c_dev;
static struct class *cl;
static struct task_struct *task;
static struct rw_semaphore rwsem;

int open(struct inode *inode, struct file *filp)
{
    printk(KERN_INFO "Inside open\n");
    task = current;
    return 0;
}

int release(struct inode *inode, struct file *filp)
{
    printk(KERN_INFO "Inside close\n");
    return 0;
}

ssize_t read(struct file *filp, char *buff, size_t count, loff_t *offp)
{
    printk("Inside read\n");
    down_read(&rwsem);
    printk(KERN_INFO "Got the Semaphore in Read\n");
    printk("Going to Sleep\n");
    ssleep(30);
    up_read(&rwsem);
    return 0;
}

ssize_t write(struct file *filp, const char *buff, size_t count, loff_t *offp)
{
    printk(KERN_INFO "Inside write. Waiting for Semaphore...\n");
    down_write(&rwsem);
    printk(KERN_INFO "Got the Semaphore in Write\n");
    up_write(&rwsem);
    return count;
}

struct file_operations fops =
{
    read:    read,
    write:   write,
    open:    open,
    release: release
};

int rw_sem_init(void)
{
    int ret;
    struct device *dev_ret;

    if ((ret = alloc_chrdev_region(&dev, FIRST_MINOR, MINOR_CNT, "rws")) < 0)
    {
        return ret;
    }
    printk("Major Nr: %d\n", MAJOR(dev));

    cdev_init(&c_dev, &fops);

    if ((ret = cdev_add(&c_dev, dev, MINOR_CNT)) < 0)
    {
        unregister_chrdev_region(dev, MINOR_CNT);
        return ret;
    }

    if (IS_ERR(cl = class_create(THIS_MODULE, "chardrv")))
    {
        cdev_del(&c_dev);
        unregister_chrdev_region(dev, MINOR_CNT);
        return PTR_ERR(cl);
    }
    if (IS_ERR(dev_ret = device_create(cl, NULL, dev, NULL, "mychar%d", 0)))
    {
        class_destroy(cl);
        cdev_del(&c_dev);
        unregister_chrdev_region(dev, MINOR_CNT);
        return PTR_ERR(dev_ret);
    }

    init_rwsem(&rwsem);

    return 0;
}

void rw_sem_cleanup(void)
{
    printk(KERN_INFO "Inside cleanup_module\n");
    device_destroy(cl, dev);
    class_destroy(cl);
    cdev_del(&c_dev);
    unregister_chrdev_region(dev, MINOR_CNT);
}

module_init(rw_sem_init);
module_exit(rw_sem_cleanup);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("SysPlay Workshops <workshop@sysplay.in>");
MODULE_DESCRIPTION("Reader Writer Semaphore Demo");

Below is the sample run:

cat /dev/mychar0
Inside Open
Inside Read
Got the Semaphore in Read
Going to sleep

cat /dev/mychar0 (In different shell)
Inside Open
Inside Read
Got the Semaphore in Read
Going to sleep

echo 1 > /dev/mychar0 (In different shell)
Inside Write. Waiting for semaphore...

As seen above, multiple reader processes are able to access the resource simultaneously. However, writer process gets blocked, while the readers are accessing the resource.

Conclusion

With this, we have covered most of the commonly used synchronization mechanisms in the kernel. Apart from these, kernel provides some atomic operations, which provides instructions that execute atomically without interruption. Atomic operators are indivisible instructions. These are useful when we need to do some operations on integers and bits.

Next Article >>

   Send article as PDF   

PC based Oscilloscope

This 7th article in the series of “Do It Yourself: Electronics”, guides you to use your laptop as an oscilloscope for 0-5V 100Hz-20kHz range waveforms.

<< Previous Article

Based on his learnings till now and ideas which keeps on coming to his head, Pugs was building some circuit to understand the workings of resistor-inductor-capacitor (RLC) circuits. He had already done similar experiments in his semester lab. But what he wanted to do is all in his room, to be specific without any lab equipment like function generator, CRO, etc. With a function generator, one could straight away generate the required waveform – specifically sine wave of specific frequencies. With CRO, one can straight away see the various specific input / output waveforms, their magnitudes, phase differences. But how to do that without any of those expensive equipment.

Till now he has been using the digital multimeter (DMM) for all kinds of measurements. If it is a known waveform like sine wave, checking its magnitude and frequency is possible using DMM. But how to check phase difference between two such waveforms, or for that matter how to know whether it is really a sine wave or not.

Pugs was lost in all these thoughts with a basic RC circuit in front of him, when his friend Vinay arrived in the Innovation Garage.

“Hey Pugs! What experiment are you planning today?”, questioned Vinay.

No response came from Pugs.

Vinay shook Pugs, “Pugs, where are you?”

“Ya! what happened”, came out Pugs from his lost world.

“What are you doing?”, asked Vinay.

“I was thinking …”, slowly started Pugs.

“Yes that I could see”, interrupted Vinay, “Thinking what?”

“See, I want to measure the phase difference between the input and output of a given circuit. How do I do that?”

“Simple. Use an oscilloscope.”

“Without using any expensive equipment.”

“What are your voltage levels?”

“Say between 0 & 5 volts.”

“Okay, then make your own oscilloscope using your laptop.”

“Oscilloscope using a laptop?”, asked Pugs surprisingly.

“Yes.”

“That would be cool. But how?”

“Think and tell me which interface of your laptop is an analog one.”

Pugs thinks for a while. “Hmmm! Audio may be.”

“Why may be? That’s the one. You’d just need an audio cable and using your audio mic input, you can feed analog input to your laptop.”

“What connections do we need to do? We have 3 lines in an audio cable, right?”

“Yes. Connect the ground to the base of the connector. Other two could be your two inputs – the two channels of stereo.”

“How do I connect to the cable? Do I solder on it?”

“Not really. You may use crocodile clips.”

“Just a doubt. Wouldn’t it have frequency limitations because of the audio card?”

“Yes. It would work only for frequencies in audio range, say 100Hz to 20kHz. What is your requirement?”

“Nothing specific right now. I want to just start playing with RC circuits. Give some input, and compare with the output.”

“In that case, the audio range should be good enough to start with.”

“Okay, hardware-wise understood. I feed the input. But how to view it. Then do I write a program which reads audio input and displays that as a waveform.”

“Yes. But you don’t need to write one. There’s already many software available for it. You may just do a google. Or, may be try the open source software (OSS) called xoscope.”

“Does it come pre-installed?”

“In general not. Just install it using your distro’s installer. Or, you can download the latest source code from http://xoscope.sourceforge.net and build yourself.”

“That I can take care of.”

“Once you run it, select the input as the sound card to make your laptop an oscilloscope. That’s all.”

“Then, we must also be able to generate a sine wave from our audio output?”

“Yes. You are correct.”

“How do we do that?”

“Let’s go for lunch now. We’ll talk about it, later.”

Next Article >>

Note

  1. In general, MIC input voltage is expected to be in the range of around ±10mV and LINE input voltage is expected to be in the range of around ±1V. However, they typically have in-built protection and hence giving voltages upto 5V also doesn’t damage them. However, note that in case the input is beyond the corresponding range, the waveforms would show as saturated to the highest level possible, and one may not get the actual voltage levels.
   Send article as PDF