Wednesday 27 April 2016

Interprocess communication - named and unnamed pipes


Unnamed pipes:

1) These are created by the shell automatically.


2) They are opened at the time of creation only.

3) They are unidirectional.


Unnamed pipes may be only used with related processes (parent/child or child/child having the same parent). They exist as long as their descriptors are open.



How pipe is created? pipe() requires array of descriptor as parameter. One for reading and another for writing.




Pipe is shared to exchange info between related processes. Example here is a parent and child exchanging information.






** This example is taken from man pipe



Output:

First parent process is executed, data is written into write end. Child reads it and outputs data stored in buffer.


1) After a new child process is created, both processes will execute the next instruction following the fork() system call. why?

Instruction pointer will be same for child and parent process. So they will start to execute next instruction following the fork system call.

2) Why parent has to wait until child terminates?

A process could go bad, might continue to use up system resources and user might want to kill that process. One effective way to kill such a zombie process is to kill parent process (kill ppid). 

wait(NULL) is used by parent process to wait for child termination.
syntax: int wait (int* childStatus)
If child process is available, PID of child is returned. But if child has already got terminated, 0 is returned. If NULL is passed to wait(), it means that the user is not bothered about debug information.

WEXITSTATUS(childstatus) returns exit status of the child

Named pipes(FIFO)

1) They are created using the command mkfifo.



write shown in above is a blocking system call. The process is put to sleep until read is complete. In other words, if I execute only fifo1, since the process is sleeping there is no output. Once another process reads the myfifo pipe, the process's work is done and is terminated.

2) They exists in the file system with a given file name.





3) They are Bi-directional.

Another process reads the same fifo file which was created earlier:

Executing write and then read, output is "Hi". But if only read process is executed, then output is 0, since no other process has written into the pipe[? I thought read is also blocking system call]



References:
https://delightlylinux.wordpress.com/2012/06/25/what-is-pid-and-ppid/
http://www.ibm.com/support/knowledgecenter/SSB23S_1.1.0.13/gtpc2/cpp_wait.html

http://www.allinterview.com/showanswers/79689/differentiate-between-named-unnamed-pipe.html

Thursday 25 February 2016

High level description of the WiFi control and data path

Came across a nice description in stackoverflow...
  1. It's important to understand there are 2 paths in which userspace communicates with the kernel when we're talking about WiFi:
    • Data path: the data being received is passed from the wireless driver to the netdev core (usually using netif_rx()). From there the net core will pass it through the TCP/IP stack code and will queue it on the relevant sockets from which the userspace process will read it. On the Tx path packets will be sent from the netdev core to the wireless driver using the ndo_start_xmit() callback. The driver registers (like other netdevices such as an ethernet driver) a set of operations callbacks by using the struct net_device_ops.
    • Control path: This path is how userspace controls the WiFi interface/device and performs operations like scan / authentication / association. The userspace interface is based on netlink and called nl80211 (see include/uapi/linux/nl80211.h). You can send commands and get events in response.
  2. When you send an nl80211 command it gets initially handled by cfg80211 kernel module (it's code is under net/wireless and the handlers are in net/wireless/nl80211.c). cfg80211 will usually call a lower level driver. In case of Full MAC hardware the specific HW driver is right below cfg80211. The driver below cfg80211 registers a set of ops with cfg80211 by using cfg80211_ops struct. For example see brcmfmac driver (drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c)
  3. For Soft MAC hardware there's mac80211 which is a kernel module implementing the 802.11 MAC layer. In this case cfg80211 will talk to mac80211 which will in turn use the hardware specific lower level driver. An example of this is iwlwifi (For Intel chips).
  4. mac80211 registers itself with cfg80211 by using the cfg80211_ops (see net/mac80211/cfg.c). The specific HW driver registers itself with mac80211 by using the ieee80211_ops struct (for example drivers/net/wireless/iwlwifi/mvm/mac80211.c).
  5. Initialization of a new NIC you've connected occurs from the bottom up the stack. The HW specific driver will call mac80211's ieee80211_allow_hw() usually after probing the HW. ieee80211_alloc_hw() gets the size of private data struct used by the HW driver. It in turns callscfg80211 wiphy_new() which does the actual allocation of space sufficient for the wiphy struct, the ieee80211_local struct (which is used by mac80211) and the HW driver private data (the layering is seen in ieee80211_alloc_hw code). ieee80211_hw is an embedded struct within ieee80211_local which is "visible" to the the HW driver. All of these (wiphyieee80211_local,ieee80211_hw) represent a single physical device connected.
  6. On top of a single physical device (also referred to as phy) you can set up multiple virtual interfaces. These are essentially what you know as wlan0 or wlan1 which you control with ifconfig. Each such virtual interface is represented by an ieee80211_vif. This struct also contains at the end private structs accessed by the HW driver. Multiple interfaces can be used to run something like a station on wlan0 and an AP on wlan1 (this is possible depending on the HW capabilities).
Link: http://stackoverflow.com/questions/7157181/how-to-learn-the-structure-of-wireless-drivers-mac80211

Wednesday 10 February 2016

My experiments with kernel module

One of the interesting interview questions:

What happens when you build a module in  a particular kernel version and try to insmod in a different kernel?

Thursday 25 June 2015

A quick guide to git clone

I have source code for my project which I want to share with team.

How to create a repository?

In the server,
git init <src directory>


I have created a repository in a folder. If I move source code to another folder will it create any problem?  No



How do I checkout the source code?

Using clone. Every version of every file for the history of the project is pulled down by default when you run git clone.

For example copy the url of linux kernel code,

Check out using:
git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
 
 
 
 
 This downloads to the folder linux-stable. Optionally you can specify the folder in which you want the code to be downloaded.

git clone http://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/  <dir_name>

 

Monday 15 June 2015

Introduction to process scheduling in linux

Process scheduler divides the processor time between runnable processes in the system.Scheduler decides which process runs next.(Source code: kernel/sched)

Linux kernel implements priority based scheduling using two schemes:

1. Based on nice values

nice value is a number from -20 to 19 with a default of 0.When nice value is more the process is nicer (i.e) gives up for other processes. In other words, lesser nice value implies higher priority.

For example RFCOMM (used to setup and maintain bluetooth configuration of in the Linux kernel) sets the nice value of -10 using the function call:


                               set_user_nice(current, -10);  [1]

root@ramapriya:/home/devel/linux-4.0.5# ps -el | grep rfcomm
F S   UID   PID  PPID  C PRI  NI   ADDR SZ WCHAN  TTY          TIME   CMD
5 S     0      723     2     0  70   -10    -         0    rfcomm    ?        00:00:00 krfcommd


As seen above nice value is set to -10 for rfcomm.

Processes with small nice value(high priority) receive a larger proportion of processor timeslice (a slice of processor's time).


Nice value can also be set from the command line while execution. Refer to this link:
http://www.thegeekstuff.com/2013/08/nice-renice-command-examples/

2. Based on real-time priority

Default range is 0 to 99. Higher real time priority value indicate greater priority(Unlike nice values, where small nice value indicate high priority).


Great!! Now how how does the scheduler allocate time slice on the basis of nice/real time priority values?


Scheduler thread removes the highest priority context on the runqueue and schedules it.

        new = grab_runnable_context(ctx->prio + 1, spu->node);
        if (new)
                spu_schedule(spu, new);


spu_schedule() calls spu_set_timeslice to set the time slice using the formula: 
max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_SPU_TIMESLICE) [2]

user-nice values [ -20 ... 0 ... 19 ] are scaled to time slice values [800ms ... 100ms ... 5ms]


[Note: In kernel 4.0.5, time slice values are: Minimum timeslice is 5 msecs, default timeslice is 100 msecs, maximum timeslice is 800 msecs. (Note: values are taken from sched.c)]


(kernel version: 4.0.5)

[1] net/bluetooth/rfcomm/core.c
[2] include/linux/sched/prio.h