Thursday 28 November 2013

Tasklets Vs Work queues in the kernel

Tasklets Vs Work queues in the kernel

Tasklets and work queues used to implement deferrable functionality in the kernel. Using the Tasklets and Work queues, we can schedule a function to run at later point of time.

Deferrable functions:

It is a mechanism for supporting delayed execution of functions (not urgent functions), used in interrupt handlers.
Types of deferrable functions
1.       Tasklets
2.       Work queues
Mostly, we use these functions in Interrupt Handlers. Because some or majority of the interrupts are disabled in interrupt context. So, if the functions take more time for execution in this context then the latency to handle other hardware interrupts. Generally, we enter into interrupt context when a hardware interrupt is raised.
If we add Deferrable function in the interrupt handlers then this function will be executed in Kernel Context where the all hardware interrupts are in enable mode. So, we move function of code which can later be executed without any harm using deferrable function. And, hence we are minimizing the latency to handle hardware interrupts.
Generally the processing of work done in interrupt handler called as Top Half.
And, the processing of work done in kernel context called as Bottom Half.
Aim: Reduce work (execution time of handler code) in Top Half
We can achieve this using Tasklets method or Work queue.

Using Tasklets:

As already mentioned, the main job of the Tasklets is to schedule the work (function) to run later point of time so that we can decrease the amount of work done in interrupt handlers.

/* Declaring Tasklet */

void tasklet_function(unsigned long data);
DECLARE_TASKLET(tasklet_name, tasklet_function, tasklet_data);

/* Scheduling Tasklet */

tasklet_schedule(&tasklet_name);

Tasklets are represented by tasklet_struct structure.
struct tasklet_struct {
                struct tasklet_struct *next; /*pointing to next tasklet structure */
                unsigned long state; /* state = TASKLET_STATE_SCHED or TASKLET_STATE_RUN */
                atomic count; /* 0 = Enable; !0 = Disable */
unsigned long data;
void (*func) (unsigned long); /*func(data) */
}
Tasklets are defined using a macro DECLARE _TASKLET, which initializes the tasklet_struct using its arguments tasklet_name, tasklet_func and data.
Tasklets are enabled by default when defined using DECLARE_TASKLET macro, so that we can schedule it directly without using any other APIs.
But, if we declare tasklet using DECLARE_TASKLET_DISABLED macro then we should explicitly call tasklet_enable() API before scheduling this tasklet.

Tasklet APIs:

/* Defining Tasklet using macros */
DECLARE_TASKLET(name, func, data);
DECLARE_TASKLET_DISABLED(name, func, data);

void tasklet_init(struct tasklet_struct *, void (*func) (unsigned long), unsigned long data); /*initializes the tasklet structure with user provided info */


/* Enabling and Disabling a tasklet using enable() and disable() */
void tasklet_enable(struct tasklet_struct *); /* Enable normal priority scheduling */
void tasklet_disable(struct tasklet_struct *); /* returns after disabling the tasklet */
void tasklet_hi_enable(struct tasklet_struct *); /* Enabling High priority scheduling */
void tasklet_disable_nosync(struct tasklet_struct *); /* may returns before termination */


/* Schedule a tasklet*/
void tasklet_schedule (struct tasklet_struct *); /* Normal priority scheduling */
void tasklet_hi_schedule (struct tasklet_struct *); /* Higher priority scheduling */


CPU maintains the normal and high priority softirq vectors lists (normal priority vector list and high priority vector list) where these functions are queued.
If the function is higher priority function then it is enqueued in higher priority softirq vector list and similar case for normal priority functions.


The below two functions are used to kill a tasklet
void tasklet_kill(struct tasklet_struct *);
void tasklet_hi_kill(struct tasklet_struct *); /* Kill the tasklet and ensure they would never run */

Sample Program: tasklet.c

#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/interrupt.h>
char tasklet_data[] = "tasklet function was called";
void my_tasklet_function (unsigned long data) {
        printk("%s: in %s\n", (char*)data, __func__);
}
DECLARE_TASKLET(my_first_tasklet, my_tasklet_function, (unsigned long)&tasklet_data);
int init_module()
{
        /* schedule our my_tasklet_function */
        tasklet_schedule(&my_first_tasklet);
        return 0;
}
void cleanup_module(void)
{
        tasklet_kill(&my_first_tasklet);
        return;
}

Makefile:

obj-m += tasklet.o
KDIR = /usr/src/linux-headers-2.6.32-28-generic
all:
        $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
        rm -rf *.o *.ko *.mod.* *.symvers *.order

Execution:

sudo insmod tasklet.ko

Output: dmesg


[3302661.097630] tasklet function was called: in my_tasklet_function

Next: Will cover work queues also...

Saturday 23 November 2013

[C programming] Storage classes in C

Storage classes in C

C supports four different storage classes. These are auto, register, static and extern storage classes.

C compiler automatically assigns auto storage class when we declare a variable without any storage class.

<syntax of storage class in c>

<storage_class> <data_type> <variable_name>;


<storage_class> gives the information about where the variable is stored in memory, default initial value, scope of the variable and it’s life time.

AutoRegisterStaticExtern
Default storage class.
int variable;
/*Above Declaration is same as below one */
auto int variable;
/*Declaration*/
register int variable;
/*Declaration*/
static int variable;
/* Declaration */
extern int variable;
Stored in stack memoryStored in CPU registersStored in Data segmentStored in Data segment
Default initial value: Contains garbage value by default.Default initial value: Contains garbage value by default.Default initial value: Default initial value of variable is 0Default initial value: Default initial value of variable is 0
Scope: local to the functionScope: local to the functionScope: local to the functionScope: visible to the outside of the file.
Value of variable persists in function.Value of variable persists in function.Value of variable persists between function callsVariable can be shared between multiple files
Lifetime: Variable is de-allocated when the function (where the variable is declared) execution is overLifetime: Variable is de-allocated when the function execution is overLifetime: Variable is de-allocated when the program is terminated after completion of job. So, lifetime doesn’t dependent on function execution.Lifetime: Variable is de-allocated when the program is terminated after completion of job.

Extern variable vs Global variable:

The scope of the global variable is limited to the file where it is declared. But, in case of extern variable, it can be shared among functions. So, variable visibility is more compared to global variable.

Both global and extern variables are stored in data segment and have default initial value is 0.

References:


Saturday 9 November 2013

What is Google ?

Today, I read a article "What Makes Google Services Work So Fast ?" at googlersays.com. This articles reveals something new and interesting facts about Google and its services.

We know that Google services are very fast, reliable, robust and trustworthy. We store our confidential information in Google services like Docs, gmail etc.

Google uses proprietary software which keeps its services at No.1 position.

Google File System: Google uses its own file system named as GFS (Google File System), provides reliable and efficient access to data.

Chubby: Google developed a lock services called Chubby, used for Shared resource management system. Heavily used as Domain Name Server.

BigTable: Google uses a Non-Relational Database called BigTable

Google also uses a OpenSource software for processing data

MapReduce: is s/w framework for processing large amount of unstructured data.

Linux Operating System: Majority of the Google servers/computers runs with Linux OS.

Please read the article What Makes Google Services Work So Fast ? for more details.


Thursday 7 November 2013

[C Programming] Check if two strings are anagrams

Anagram: Two strings S1 and S2 are called anagrams when string S2 can be formed if we rearrange the letters in string S1 and vice-versa.


Example: S1 = god, S2 = dog

Solution:
------------
If we apply XOR property here then we can easily find the given strings are anagrams or not.

1 XOR 1 = 0
1 XOR 0 = 1
a XOR z = 1
s XOR s = 0

If Inputs to the XOR operator are equal then result would be ZERO.

Apply XOR for each alphabet in both strings. If the result is ZERO then the strings are anagrams else not anagrams. It may not be sufficient condition since the strings "aaa" and "bbb" are not anagrams but still the XOR of these two strings is ZERO. Hence, one more check was needed to eliminate these usecases. Compute the sum of ascii value of two strings and check if they are equal. If equal then the two given strings are anagrams.

Sample code (anagram_string.c):
--------------------------------------
  #include<stdio.h>
  #include<string.h>

  void main(int argc, char *argv[])
  {
          char *str1, *str2;
          int xor, i;
          int sum1 = 0, sum2 = 0;


          if ( argc != 3 ) /* argc should be 3 for correct execution */
          {
                  /* argv[0] is the program name */
                  printf( "usage: %s string1 string2\n", argv[0] );
                  return;
          }

          str1 = argv[1];
          str2 = argv[2];

          printf("Entered strings \"%s\" and \"%s\"\n", str1, str2);

          if (strlen(str1) != strlen(str2)) {
                  printf("Given Strings are not anagrams\n");
                  return;
          }

          for (i = 0; i < strlen(str1); i++) {
                  xor ^= str1[i];
                  xor ^= str2[i];
                  sum1 += str1[i];
                  sum2 += str2[i];
          }

          if (!xor && (sum1 == sum2))
                  printf("Given Strings are anagrams\n");
          else
                  printf("Given Strings are not anagrams\n");

  }

Output:
======
gcc anagram_string.c
./a.out ram arm

Entered strings "ram" and "arm"
Given Strings are anagrams

Wednesday 6 November 2013

[C programming] Reverse an array in place (Do not use additional array)

Reverse an array in-place i.e you cannot use any additional array or
in other words, space complexity of the solution should be O(1)

#include<stdio.h>
#include<stdlib.h>

void main()
{
int size, i, temp;
int *array;

printf("Enter size of an array:\n");
scanf("%d", &size);

array = (int*)malloc(sizeof(int) * size);

printf("Enter %d elements\n", size);
for (i = 0; i < size; i++)
scanf("%d", &array[i]);

printf("List elements are..\n");
for (i = 0; i < size; i++)
printf("%d\n", array[i]);

for (i = 0; i <= (size - 1) / 2; i++) {
temp = array[i];
array[i] = array[size-1-i];
array[size-1-i] = temp;
}

printf("After Reversing the list,  elements are..\n");
for (i = 0; i < size; i++)
printf("%d\n", array[i]);
}

Tuesday 5 November 2013

[Ubuntu] How to use ctags

ctags with vim editor are very helpful for code walk-through. Navigation is very easy in the large code bases like kernel, where we can jump to
function/identifier definition directly using simple keys.

ctags installation:
=============
ctags can be installed in ubuntu by

sudo apt-get install exuberant-ctags

How to use ctags:
==============

1. Generate tag file for the required code base.

change your current working directory to desired code base directory using cd command.
Now, run below command

ctages -R .

Output: We see "tags" file in the current working directory after successful.
It will store all index information of functions or identifiers in the tag file.

2. Now, open any file in the current working directory using vim editor.
   Place cursor on any funtion/identifier.

3. Press ctrl + ] together. We will redirect to the file where this function/identifier is defined.

If there are multiple entries for this definition, we can check one by one by following way

Goto vim's command mode by typing ":" and type tnext (goes to next tag)

4. Once you see the required definition, use ctrl+t to go back to your base point where you did step-3


Note: Instead of step-2, we can use vim’s command mode to jump to function/identifier definition:

:tag function_name
:ta function_name

The below commands will be used to accept regular expressions.

Example, :tag /^asserts_* would find all tags that start with ‘asserts_’.
By default vim will jump to the first result, but a number of commands can be used to sort through the list of tags:

:ts or :tselect shows the list
:tn or :tnext goes to the next tag in that list
:tp or :tprev goes to the previous tag in that list
:tf or :tfirst goes to the first tag of the list
:tl or :tlast goes to the last tag of the list
To show the tags you’ve traversed since you opened vim, run :tags.

For more info on ctags, please check here

You might also like

Related Posts Plugin for WordPress, Blogger...