Showing posts with label Operating System. Show all posts
Showing posts with label Operating System. Show all posts

Monday, April 25, 2016

printf, fprintf, sprintf and printk..... whats the difference ?

There are basically 3 standard "streams"

  1. stdin - standard input stream
  2. stdout - standard output stream
  3. stderr - standard error stream
fprintf(standard stream, "message");  //message is sent to the mentioned stream

printf("message"); //message is sent to stdout. so it is as good as writing fprintf(stdout, "message")

#define BUFFER_SIZE 50
char *ch_arr = (char *)malloc(sizeof(char) * BUFFER_SIZE);
sprintf(ch_arr,  "message"); //message is sent to char buffer whose pointer is passed as argument

printk(KERN_IMERG "message");  
//used to print message to kernel log file. Hence it can only be called from kernel only

IPC: Process communication using PIPE

Pipes are basically used for communicating information between two processes.



There are two types of pipes:
  1. ordinary pipe
  2. Named pipe

Ordinary Pipe:

  • simple pipes are unidirectional in nature (one-way comm)
  • two-way communication can be achieved by creating 2 pipes
  • pipe cannot be accessed from the outside the process that creates it
  • Hence it is used mostly for parent and child process communication

creation and use:


  • pipe() function is used to create a pipe. This actually creates special file
  • read(), write(), close() system calls can be used to access this file
  • int file_descriptor[2] array is used as file_descriptor to access file.
    • file_descriptor[0] = read from file
    • file_descriptor[1] = write to file
  • one of the file descriptor(read/write) should be closed in the respective process to make it unidirectional. This is done to avoid Deadlock condition and exploit parallelism

Named Pipes:

  • named pipes are like FIFOs
  • created using mkfifo() system calls and opereated using open, read, write and close(0 system calls
  • they appear as files in file system once created
  • they remain as it is until they are deleted explicitly
  • multiple process on same machine can use named pipe
  • For communication over network, socket wrapper need to be used
Named pipe Example:
$mkfifo demo_fifo
$exec 3<> demo_fifo
$ls -l >&3
$cat demo_fifo

mkfifo - create named pipe
exec - to a assigned 3 as file descriptor for named pipe
$ls -l >&3  add output of ls -l to named pipe
cat - read the data from named pipe

Following is example of Ordinary pipe:
---------------------------------------------------------------------------------
linux_pipe.c
---------------------------------------------------------------------------------

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

#define BUFFER_SIZE 50
#define READ_END 0
#define WRITE_END 1

int main(int argc, char *argv[]){
char write_msg[BUFFER_SIZE] = "message over pipe";
char read_msg[BUFFER_SIZE];
int file_descriptor[2];

pid_t pid;

// create pipe
if (pipe(file_descriptor) == -1){
fprintf(stderr, "ERROR: Pipe creation failed");
return 1;
}

pid = fork(); // fork process
if (pid < 0){ // process forking failure
fprintf(stderr, "ERROR: Process forking failure");
}
else if (pid == 0){ //this is child process
printf("Inside child process\n");
close(file_descriptor[WRITE_END]); //close the write end of the pipe
read(file_descriptor[READ_END], read_msg, BUFFER_SIZE); //read message from pipe. wait until message is received
printf("Read data = %s", read_msg);
close(file_descriptor[READ_END]); //close read end of the pipe
}
else { //this is parent process
sleep(5); //Too verify child waits at read() for 5sec until it receives message
close(file_descriptor[READ_END]); //close read end of the pipe
write(file_descriptor[WRITE_END], write_msg, strlen(write_msg) + 1); //writing message to pipe
printf("Task of writing message to pipe completed\n");
close(file_descriptor[WRITE_END]); //close write end of the pipe
}

return 0;
}


---------------------------------------------------------------------------------
output
---------------------------------------------------------------------------------

Inside child process

Task of writing message to pipe completed
Read data = message over pipe

Wednesday, April 20, 2016

IPC: Message queue with example

Message queue

Message queue is a type of inter process communication. It is used to transfer data between processes. It is asynchronous communication as in, sender can dump data in queue, and receiver can get the data out at its convenience.

Parameters of queue:

  1. Queue ID
  2. Key
  3. Message structure:
    • type
    • text

Method calls:

  1. msgget()
  2. msgsnd()
  3. msgrcv()

Applications:

  1. VxWorks and QNX encourage the use of message queue for inter-process & inter-thread communication
  2. It provides resilience functionality as the message dont get "lost" in communication in case of system failure.

Example:

Sender code - creates queue and enter message into it with a particular key
Receiver code - Access the queue, gets the message and prints the text. If while receiver process execution data is not available in queue, it waits at msgrcv(), and proceeds when it gets some data.

Shell command to view the queue IPC
$ipcs -q

*******************************
sender.c
*******************************
/*
 * sender.c
 *
 *  Created on: 19-Apr-2016
 *      Author: root
 */

//IPC_msgq_send.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXSIZE     128

void die(char *s)
{
  perror(s);
  exit(1);
}

struct msgbuf
{
    long    mtype;
    char    mtext[MAXSIZE];
};

main()
{
int count = 0;
//char data[3][MAXSIZE] = {"first", "second", "third"};
    int msqid;
    int msgflg = IPC_CREAT | 0666;
    key_t key;
    struct msgbuf sbuf;
    size_t buflen;

    key = 1234;

    if ((msqid = msgget(key, msgflg )) < 0)   //Get the message queue ID for the given key
      die("msgget");

    //Message Type
    sbuf.mtype = 1;

    printf("Enter a message to add to message queue : ");
    scanf("%[^\n]",sbuf.mtext);
    getchar();

    buflen = strlen(sbuf.mtext) + 1 ;

    while (count < 3){
    //*sbuf.mtext = data[count];
    //buflen = strlen(sbuf.mtext) + 1 ;
if (msgsnd(msqid, &sbuf, buflen, IPC_NOWAIT) < 0)
{
printf ("%d, %d, %s, %d\n", msqid, sbuf.mtype, sbuf.mtext, buflen);
die("msgsnd");
}
else
{
printf("Message Sent\n");
}
count++;
    }
    exit(0);
}

*******************************
receiver.c
*******************************
/*
 * receiver.c
 *
 *  Created on: 19-Apr-2016
 *      Author: root
 */

//IPC_msgq_rcv.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE     128

void die(char *s)
{
  perror(s);
  exit(1);
}

typedef struct msgbuf
{
    long    mtype;
    char    mtext[MAXSIZE];
} ;


main()
{
    int msqid;
    key_t key;
    struct msgbuf rcvbuffer;

    key = 1234;

    if ((msqid = msgget(key, 0666)) < 0)
      die("msgget()");


     //Receive an answer of message type 1.
    if (msgrcv(msqid, &rcvbuffer, MAXSIZE, 1, 0) < 0)
      die("msgrcv");

    printf("%s\n", rcvbuffer.mtext);
    exit(0);
}

--------------------------------------------------------------------------------------------------

OUTPUT:

$ ipcs -q

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    


$./sender
Enter a message to add to message queue : text data to trasmit
Message Sent
Message Sent
Message Sent

$ ipcs -q

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0x000004d2 0          root       666        63           3           

$./receiver
text data to trasmit

$ ipcs -q

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0x000004d2 0          root       666        42           2           

$./receiver
text data to trasmit

$ ipcs -q

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0x000004d2 0          root       666        21           1           

$./receiver
text data to trasmit

$ ipcs -q

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0x000004d2 0          root       666        0            0           


Friday, January 29, 2016

Operating system: Process vs Threads


Differences
  1. Creation of thread faster than creation of process
  2. Switching between threads faster than switching between processes
  3. Variables can be shared between threads of same process hence data sharing in threads is easy as compared to process. Processes don't share a common memory space hence schemes like Pipes and Queues need to be used for data communication

Applications

Threads
  1. Almost all softwares that we run on PC, like microsoft office, adobe pdf reader, eclipse etc. they create a single process and inside process they create multiple threads - GUI handling, back end processing, event handling etc.
  2. This is because processes as slower in all aspect as mentioned above and eventually application will be slow performing. Hence in these cases multi-thread creation is a better option as compared to multi-process creation
  3. There are two types of threads:
    • Kernel level thread (Thread model - One to one)
      • Advantages: 
        • Best suited when thread blocking comes into play
        • One blocked thread does not block the whole process. Multithreading and multiprocessing hardware is actually used in this case
      • Disadvantage:
        • Slow as compared to User level threads
        • Overhead of thread management
      • Example: PThread
    • User level thread (Thread model - Many to one)
      • Adavantges:
        • Best suited for non-blocking thread
        • Fast execution as compared to kernel threads
        • Fast thread creation, switching, synchronization etc.
        • Kernel is not aware of threads created in user level
      • Disadvantages:
        • Mutlithreading and multiprocessing hardware is not used
        • If one thread blocks the process is blocked
  4. Protecting shared resources
    • Mutex(Mutual Exclusion) - Thread resource sharing serialization
    • Probable problems - 
      • Deadlock - Thread1 acquire lockA, and demands lockB. Thread2 acquire lockB and demand lockA. This is the scenario where deadlock occurs.
      • Race condition - Unsynchronizaed access to shared resource can cause inconsitency in the shared data
      • Priority Inversion - When a LOW priority thread acquires a lockA, and is doing some operation. At teh same time if HIGH priority thread want to acquire the same lockA, then is halts at the point waiting to get lockA. Here, even though the demanding thread is of HIGH priority it has to wait until LOW priority thread release the lockA. Thus the problem of Priority Inversion. In the mean time, if a MEDIUM priority thread want to execute and that doesnt need lockA, then it takes over and LOW thread is halted, which is even a more twist in the story. To avoid this, Priority inheritance and Priority Ceiling are used.
  5. Thread synchronization primitives
    • Join
    • Condition Variable
    • Barrier
    • Spinlocks
    • Semaphores
Processes
  1. Multiple process creation is a better option in scenarios where completely separate memory areas for task as required. Example: The chromium project. its a web browser, where separate processes are created for every tab you create. This is to protect the overall application from bugs and glitches in the rendering engine. This brings to web browsing the benefits that memory protection and access control brought to operating systems.
  2. If your application will consist of separate, individually-usable components that communicate through well-defined protocols, each of which performs jobs that can individually succeed or fail without complicating the logic of the other components, then it's perfectly reasonable to write an application that utilizes multiple processes.

PROFILE

My photo
India
Design Engineer ( IFM Engineering Private Limited )

Followers