Monday, 27 May 2013

What is EPOLL? Epoll vs Poll vs Select call ? And How to implement UDP server in Linux using EPOLL?



Today in internet world, as the number of users are increasing day to day and to support these users it needs more efficient HTTP servers.

A common problem in HTTP server scalability is how to ensure that the server handles a large number of connections simultaneously without degrading the performance.

An event-driven approach is often implemented in high-performance network servers to multiplex a large number of concurrent connections over a few server processes. 

In event-driven servers it is important that the server focuses on connections that can be serviced without blocking its main process.

What is EPOLL?
===========
epoll - I/O event notification facility

Select Vs poll Vs Epoll
==================
The Epoll event mechanism  is designed to scale to larger numbers of connections than select and poll.

One of the problems with select and poll is that in a single call they must both inform the kernel of all of the events of interest and obtain new events.
This can result in large overheads, particularly in environments with large numbers of connections and relatively few new events occurring.

However, if your server application is network-intensive (e.g., 1000s of concurrent connections and/or a high connection rate), you should get really serious about performance.
This situation is often called the c10k problem. With select() or poll(), your network server will hardly perform any useful things but wasting precious CPU cycles under such high load.

c10k Problem
===========
Suppose that there are 10,000 concurrent connections. Typically, only a small number of file descriptors among them, say 10, are ready to read.
The rest 9,990 file descriptors are copied and scanned for no reason, for every select()/poll() call.

Another Example as :

The cost of  Epoll is closer to the number of file descriptors that actually have events on them.
If you're monitoring 200 file descriptors, but only 100 of them have events on them, then you're (very roughly) only paying for those 100 active file descriptors.
This is where Epoll tends to offer one of its major advantages over select. If you have a thousand clients that are mostly idle,
then when you use select you're still paying for all one thousands of them. However, with Epoll, it's like you've only got a few - you're only paying for the ones that are active at any given time.

All this means that epoll will lead to less CPU usage for most workloads

Time Complexity
=============

Select  -> O(n)   Epoll -> O(1)

Select calls, which are O(n), epoll is an O(1) algorithm – this means that it scales well as the number of watched file descriptors increase.
select uses a linear search through the list of watched file descriptors, which causes its O(n) behaviour, whereas epoll uses callbacks in the kernel file structure.

Another fundamental difference of epoll is that it can be used in an edge-triggered, as opposed to level-triggered, fashion.
 This means that you receive “hints” when the kernel believes the file descriptor has become ready for I/O, as opposed to being told “I/O can be carried out on this file descriptor”.

No of clients support is a Limitation in Select Call
==============================================
Using Select() call, Max number of clients it handle is 1024 (1k).

In other words, server is able to handle only 1024 client after which connections are failing.
Increased per process max open files (1024) to 100000 and still the connections failed at 1024.

select limitation

select fails after 1024 fds as FD_SETSIZE max to 1024.
As a natural progression poll was tried next to overcome max open fd issue.

poll limitation
poll solves the max fd issue. But as the number of concurrent clients started increasing, performance dropped drastically.
Poll implementation does O(n) operations internally and performance drops as number of fds increases.

epoll
Epoll solved both problems and gave awesome performance.

Triggering modes
=============

  • Edge Triggered Mode
  •  Level Triggered Mode

Epoll provides both edge-triggered and level-triggered modes. 

In edge-triggered mode, a call to epoll_wait will return only when a new event is en queued with the epoll object, while in level-triggered mode, epoll_wait will return as long as the condition holds.

For instance, if a pipe, registered with epoll, has received data, a call to epoll_wait will return, signaling the presence of data to be read.
Suppose the reader only consumed part of data from the buffer. In level-triggered mode, further calls to epoll_wait will return immediately, as long as the pipe's buffer contains data to be read.
In edge-triggered mode, however, epoll_wait will return only once new data is written to the pipe

To Understand Better…..

When an FD becomes read or write ready, you might not want necessarily want to read (or write) all the data immediately.

Level-triggered epoll will keep nagging you as long as the FD remains ready, whereas edge-triggered won't bother you again until the next time you get an EAGAIN
(so it's more complicated to code around, but can be more efficient depending on what you need to do).

Say you're writing from a resource to an FD. If you register your interest for that FD becoming write ready as level-triggered, you'll get constant notification that the FD is still ready for writing.
If the resource isn't yet available, that's a waste of a wake-up, because you can't write any more anyway.

If you were to add it as edge-triggered instead, you'd get notification that the FD was write ready once, then when the other resource becomes ready you write as much as you can.
Then if write(2) returns EAGAIN, you stop writing and wait for the next notification.

The same applies for reading, because you might not want to pull all the data into user-space before you're ready to do whatever you want to do with it
 (thus having to buffer it, etc etc). With edge-triggered epoll you get told when it's ready to read, and then can remember that and do the actual reading "as and when".

EPOLL SYSTEM Calls
==================

The Epoll interface consists of three system calls:

int epoll_create(int size);

Creates an epoll object and returns its file descriptor. size is obsolete since kernel 2.6.8 but must be greater than zero for backwards compatibility.

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

Controls (configures) which file descriptors are watched by this object, and for which events. op can be ADD, MODIFY or DELETE.

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

Waits for any of the events registered for with epoll_ctl, until at least one occurs or the timeout elapses. Returns the occurred events in events, up to maxevents at once.


 UDP SERVER IMPLEMENTED USING EPOLL
==========================================


#include <stdio.h>          // for printf() and fprintf()
#include <sys/socket.h>     // for socket(), bind(), and connect()
#include <arpa/inet.h>      // for sockaddr_in and inet_ntoa()
#include <stdlib.h>         // for atoi() and exit()
#include <string.h>         // for memset()
#include <unistd.h>         // for close()
#include <fcntl.h>          // for fcntl()
#include <errno.h>
#include <sys/epoll.h>

#define MAX_EVENTS 100

#define BUFFSIZE 5096

unsigned char buf[BUFFSIZE];

/*
 * Dump Data
 */
void dumpData(unsigned char *data,  unsigned int len)
{
  unsigned int uIndx;

  if(data)
    {
      for(uIndx=0; uIndx<len; ++uIndx)
        {
          if(uIndx%32 == 0)
            {
              printf("\n%4d:", uIndx);
            }
          if(uIndx%4 == 0)
            {
              printf(" ");
            }
          printf("%02x", data[uIndx]);
        }
    }
  printf(" Length of Bytes: %d\n", len);
  printf("\n");
}


/*
 * make_socket_non_blocking :
 *   This Function makes socket as Non blocking
 */
static int make_socket_non_blocking(int sockFd)
{
  int getFlag, setFlag;
 
  getFlag = fcntl(sockFd, F_GETFL, 0);
 
  if(getFlag == -1)
  {
    perror("fnctl");
    return -1;
  }
 
  /* Set the Flag as Non Blocking Socket */
  getFlag |= O_NONBLOCK;
 
  setFlag = fcntl(sockFd, F_GETFL, getFlag);
 
  if(setFlag == -1)
  {
    perror("fnctl");
    return -1;
  }
 
  return 0;
}

/*
 *  Main Routine
 */
int main()
{
  int i, length, receivelen;

  /* Socket Parameters */
  int sockFd;
  int optval = 1;   // Socket Option Always = 1

  /* Server Address */
  struct sockaddr_in serverAddr, receivesocket;

  /* Epoll File Descriptor */
  int epollFd;      

  /* EPOLL Event structures */
  struct epoll_event  ev;                  
  struct epoll_event  events[MAX_EVENTS];               
  int numEvents;    
             
  int ctlFd; 
  // Step 1: First Create UDP Socket 
 
  /* Create UDP socket
   * socket(protocol_family, sock_type, IPPROTO_UDP);
   */
  sockFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

  /* Check socket is successful or not */
  if (sockFd == -1)
  {
    perror(" Create SockFd Fail \n");
    return -1;
  }

  // Step 2: Make Socket as Non Blocking Socket.
  //         To handle multiple clients Asychronously, required to
  //         configure socket as Non Blocking socket

  /* Make Socket as Non Blocking Socket */
  make_socket_non_blocking(sockFd);

  // Step 3: Set socket options
  //    One can set different sock Options as RE-USE ADDR, 

  //    BROADCAST etc.
 
  /*  In this Program, the socket is set to RE-USE ADDR
   *  So this gives flexibilty to other sockets to BIND to the 

      same port Num */

  if(setsockopt(sockFd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))== -1)
  {
     perror("setsockopt Fail\n");
     return -1;
  }

  // Step 4: Bind to the Recieve socket
  /* Bind to its own port Num  ( Listen on Port Number) */
  
  /* Setup the addresses */
 
   /* my address or Parameters
     ( These are required for Binding the Port and IP Address )
      Bind to my own port and Address */
  memset(&receivesocket, 0, sizeof(receivesocket));
  receivesocket.sin_family = AF_INET;
  receivesocket.sin_addr.s_addr = htonl(INADDR_ANY);
  receivesocket.sin_port = htons(2905);

  receivelen = sizeof(receivesocket);

  /* Bind the my Socket */
  if (bind(sockFd, (struct sockaddr *) &receivesocket, receivelen) < 0)
  {
    perror("bind");
    return -1;
  }

  // EPOLL Implementation Starts
  // Step 5: Create Epoll Instance
             /* paramater is Optional */
 
  epollFd = epoll_create(6);

  if(epollFd == -1)
  {
     perror("epoll_create");
     return -1;
  }

  /* Add the udp Sock File Descriptor to Epoll Instance */
  ev.data.fd = sockFd;
 
  /* Events are Read Only and Edge-Triggered */
  ev.events = EPOLLIN | EPOLLET;

 
  // Step 6: control interface for an epoll descriptor
  /* EPOLL_CTL_ADD
      Register the target file descriptor fd on the epoll instance
      referred to by the file descriptor epfd and
      associate the event event with the internal file linked to fd.
  */


  /* Add the sock Fd to the EPOLL */
  ctlFd  = epoll_ctl (epollFd, EPOLL_CTL_ADD, sockFd, &ev);
 
  if (ctlFd == -1)
  {
    perror ("epoll_ctl");
    return -1;
  }

 // Step 7: Start the Event Loop using epoll_wait() in while Loop.

 /* Event Loop */
 while(1)
 {
     /*  Wait for events.
      *  int epoll_wait(int epfd, struct epoll_event *events, int
      *  maxevents, int timeout);
      *  Specifying a timeout of -1 makes epoll_wait() wait
      *  indefinitely.
      */
    
     /* Epoll Wait Indefently since Time Out is -1 */
     numEvents = epoll_wait(epollFd, events, MAX_EVENTS, -1);

     for (i = 0; i < numEvents; i++)
     {
       if ((events[i].events & EPOLLERR) ||
           (events[i].events & EPOLLHUP) ||
           (!(events[i].events & EPOLLIN)))
        {
           /* An error has occured on this fd, or  the socket is not
            * ready for reading (why were we notified then?)
            */
           fprintf (stderr, "epoll error\n");
           close (events[i].data.fd);
           continue;
        }
       /* We have data on the fd waiting to be read. Read and
        * display it. We must read whatever data is available
        * completely, as we are running in edge-triggered mode
        * and won't get a notification again for the same data.
        */
       else if ( (events[i].events & EPOLLIN) &&
           (sockFd == events[i].data.fd) )
       {
         while (1)
         {

           memset(buf, 0, BUFFSIZE);
           /* Recieve the Data from Other system */
           if ((length = recvfrom(sockFd, buf, BUFFSIZE, 0, NULL, NULL)) < 0)
            {
                perror("recvfrom");
                return -1;
            }

           else if(length == 0)
             {
               printf( " The Return Value is 0\n");
               break;
             }
           else
             {
               /* Print The data */
               printf("Recvd Byte length : %d",  length);
               dumpData(buf, length);
             }
          }
       }
     }
  }

close( sockFd );
close( epollFd );
return 0;
}



==============================================================================
UDP CLIENT -> udpclient.c
==============================================================================

#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
#include<stdlib.h>
#include <sys/unistd.h>
#include <sys/fcntl.h>


#define BUFFSIZE 5096
#define MAX_LEN 100000

int sendlen, receivelen;
int received = 0, i,count, rcvCnt=0, sentCnt=0;
unsigned char buffer[BUFFSIZE];
struct sockaddr_in receivesocket;
struct sockaddr_in sendsocket;
int sock;
unsigned int ch;
unsigned int noOfTimes;
   
int sendUDPData();  
   
int main(int argc, char *argv[]) {
   
    int ret = 0;
  int optval = 1;

    /* Create the UDP socket */
    if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
        perror("socket");
        return -1;
    }

    /* my address */
    memset(&receivesocket, 0, sizeof(receivesocket));
    receivesocket.sin_family = AF_INET;
    receivesocket.sin_addr.s_addr = htonl(INADDR_ANY);
    receivesocket.sin_port = htons(2905);

    receivelen = sizeof(receivesocket);

 if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))== -1)
  {
     perror("setsockopt Fail\n");
     return -1;
  }
  if (bind(sock, (struct sockaddr *) &receivesocket, receivelen) < 0) 

    {
        perror("bind");
        return -1;      
    } 
    /* kernel address */
    memset(&sendsocket, 0, sizeof(sendsocket));
    sendsocket.sin_family = AF_INET;
    sendsocket.sin_addr.s_addr = inet_addr("10.12.7.95");
    sendsocket.sin_port = htons(2905);

   do
    {
       printf("\n");
       printf(" Enter your choice:\t");
       printf(" 1. Send UDP Data \n");
       printf(" 2. exit \n");
       scanf("%d", &ch);
       printf("\n");

       switch(ch)
       {

           case 1:
                   printf("Enter the Length of the Payload \n");
                   scanf("%d", &sendlen);
                   printf("Enter How many times you want to send data \n");
                   scanf("%d", &noOfTimes);
                   sendUDPData();
                   break;

           default:
                  printf("Invalid Choice\n");
                  break;
       }
    }while(ch!=2);
return 0;
}
int sendUDPData()
{
    int count=0;
        memset(buffer, 0x31, sendlen);
       
        for(count=0; count< noOfTimes;  count++)
        {
       if (sendto(sock, buffer, sendlen, 0, (struct sockaddr *) &sendsocket,
                        sizeof(sendsocket)) != sendlen)      
       {
        perror("sendto");
        return -1;
       }

    printf("\n");
    }
    return 0;
}

Monday, 13 May 2013

Simple Memory pool Implementation for Real Time Applications

Dear readers,

   In this post, I would like to introduce about the Simple Memory Pool Implementation which can be used for real time applications.

Before looking in to actual Implementation, first know about what is memory pool and why is required in real time applications.

In real time applications, performance plays a very important role. That means any real time system should have high performance to get desirable results else it is considered as useless system.

Hence, when ever a developer writing any code, he/she should keep in mind that how much code optimization and performance that is going to achieve with the implementation.

In the code often developers allocate the memory using dynamic allocation macros such as MALLOC in 
case of C and NEW in case of C++. 

Suppose, you have packet receptor system which receives the packets from other device. And this receptor system responsibility to add a extra header to the received packet and sends the modified packet out to the end device. 

What happens when code allocates/dellocates memory using malloc/free for every packet. 

Do you think there is a performance degradation? Yes, obviously there is performance degradation. 

Then what is the solution? Solution is Memory pools.
   A more efficient solution is preallocating a number of memory blocks with the same size called the memory pool. The application can allocate, access, and free blocks represented by handles at run time.

What is Memory Pool?
   Memory pool is pre-allocation of fixed size of memory or it also defined as fixed size of memory allocated using MALLOC or New during initialization of the system.

Why it is required?
   To avoid the performance degradation in real time systems.

How it is implemented?

Step 1 :  Create a memory Pool. 
Application needs to initialize a pool. Application allocates the memory required during initialization time using MALLOC/NEW.
Step 2:    Get memory from Pool
Whenever a memory is required and the same memory would be fetched from the Pool.              
Step3:   Add memory to Pool
Once the Memory is no more used then add the same memory to Pool.
Step4:  Destroy/Deallocate memory Pool
And finally, before application quits, it should de-allocate the pool, to make sure that all memory blocks allocated by the factory are released back to the operating system. After this, of course no more memory pool allocation can be requested.

Simple Program for Memory Pool:



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

#define MAX_MEMORY_POOL_NODES 10

/* Node */
typedef struct node
{
    int    data;
    int    nodeAllocated;
}NODE;

typedef struct Memorypool
{
    NODE       *array[MAX_MEMORY_POOL_NODES];
    int        nodeCounter;
}MEMORYPOOL;

MEMORYPOOL allocNode;

/*
 * initialiseMemoryPool()
 */
void initialiseMemoryPool()
{
   unsigned char uIndx;
   
   /* Initialise the Memory for the Nodes */      
   for(uIndx = 0; uIndx<MAX_MEMORY_POOL_NODES; uIndx++)
   {
      allocNode.array[uIndx]= (NODE *)malloc(sizeof(NODE));
      allocNode.array[uIndx]->nodeAllocated = 0;

      allocNode.nodeCounter++;
   }
}

NODE *getTheFreeNodeFromPool()
{
  int uIndx;
  
   /* Get the Memory from the Pool of Nodes */
   for(uIndx = 0; uIndx<MAX_MEMORY_POOL_NODES; uIndx++)
   {
      if(allocNode.array[uIndx]->nodeAllocated == 0) 
      {
          allocNode.array[uIndx]->nodeAllocated = 1;
          allocNode.nodeCounter--; 
          break;
      }
   }  

  if(uIndx == MAX_MEMORY_POOL_NODES) 
  {
     printf(" No Free Nodes are available \n");
     return NULL;
  }
  return allocNode.array[uIndx];
}

/* 
 *  Add the Node to Memory pool
 */
void addTheNodeToMemoryPool(unsigned char uIndx)
{
   /* Add the Node to Pool */
   if(allocNode.array[uIndx]->nodeAllocated == 1 )
   {
         allocNode.array[uIndx]->data = 0;
         allocNode.array[uIndx]->nodeAllocated = 0; 
         allocNode.nodeCounter++;
    }
   else
   {
      printf("No Nodes are there Add \n");
      return;
   }
}

/*
 * deallocateTheMemoryPool-  Deallocate the Memory Pool
 */
void deallocateTheMemoryPool(void)
{
  unsigned char uIndx;

  /* De-allocate the Memory Pool */
  for(uIndx = 0; uIndx<MAX_MEMORY_POOL_NODES; uIndx++)
    {
        free(allocNode.array[uIndx]);
    }
}
              
/* Main */
int main()
{
    unsigned char uIndx, index;
   
   // Step 1:
   /* Initialise the Memory Pool */
   initialiseMemoryPool();

   // Step 2:
   /* Get the Node from the Memory Pool */
   for(uIndx=0 ; uIndx< MAX_MEMORY_POOL_NODES; uIndx++)
   { 
      NODE *node= NULL; 
      int data;
      
      node = getTheFreeNodeFromPool();

      if(node)
      {
          printf("Enter the Data to be added in the Linklist \n");
          scanf("%d", &data);
    
          node->data = data;
      }
   }
  
   /* Display the Data */
   printf(" Display Data \n");
   for (uIndx=0 ; uIndx<MAX_MEMORY_POOL_NODES; uIndx++)
    {
      printf("%d\n", allocNode.array[uIndx]->data);
    }

   
   //Step 3:
   /* Add the Node to Memory Pool */   
   printf(" Enter the Node to be added to memory pool \n");
   scanf("%d", &index);
   
   addTheNodeToMemoryPool(index);

   /* Display the Data */
   printf(" Display Data after adding Node to Free Pool \n");
   for (uIndx=0 ; uIndx<MAX_MEMORY_POOL_NODES; uIndx++)
    {
      printf("%d\n", allocNode.array[uIndx]->data);
    }

   //Step 4:
   /* De Allocate the Memory Pool */
   deallocateTheMemoryPool();
   return 0;
}








Saturday, 19 January 2013

How to Implement the Debug Logging Mechanisms for Real Time Applications

In this post, I would like to introduce with the "DEBUG LOGGING MECHANISM" for real time applications.

To debug any code, Developer always depend on the LOGS (i.e. prints) which gives useful info about that application.

In case of real time applications, displaying too many LOGS while running the application is not a good idea. ( In real time traffic applications, having too many prints may lead application to CRASH.)

Then what is the way to LOG the prints in real time applications? Solution is that all prints(LOGS) should be under some DEBUG MACROS and it get enabled whenever user need to debug the issue.

Developer can enable the prints based on the Levels ( In other words user can get selective prints).

I have written sample program to demonstrate the "DEBUG LOG MECHANISM" . There are two files debug.h and sample_program.cc.  debug.h contains the debug LOG Mechanism logic. 

Compile sample_program.cc using  " c++  sample_program.cc -o test.exe" 

 
debug.h

/* Initialized to Zero , It can extended as unsigned long*/
unsigned char application_debug;


#define ENABLE_DEBUG_FLAG_LEVEL_0       (1 << 0)
#define ENABLE_DEBUG_FLAG_LEVEL_1       (1 << 1)

/*  Generally LOGS are enabled during RUN TIME
 *  ENABLE DEBUG LOGS */
#define MUNI_DEBUG_ON(value)  (application_debug |= ENABLE_DEBUG_FLAG_ ##value)

/* OFF DEBUG LOGS */
#define MUNI_DEBUG_OFF(value) (application_debug &= ~ENABLE_DEBUG_FLAG_ ##value)

/* Here application_debug is initialized to Zero.

*  When code calls this Macro MUNI_DEBUG(LEVEL_0) leads to  application_debug &         
*   ENABLE_DEBUG_FLAG_ ## =  application_debug & ENABLE_DEBUG_FLAG_LEVEL_0 
*   (##" concatenates the Value given in Macro)
*/
 
#define MUNI_DEBUG(value)  (application_debug & ENABLE_DEBUG_FLAG_ ## value)


/* Define LOG_DEBUG */
#define LOG_DEBUG(fmt, args...)  \
    printf(fmt, ##args)



sample_program.cc


#include<iostream.h>
#include "debug.h"
int main()
{
    int X, level;  
 do
  { 
    cout<<endl<<" Enter The Value of X"<<endl;
    cin>>X;

    cout<<endl<<"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"<<endl;
    cout<<" Enter which debug Level LOG to be Enable/Disable in application"<<endl;
    cout<<" HELP : ON  : level == 1 = LEVEL_0, level == 2 = LEVEL_1 "<<endl;
    cout<<"        OFF : level == 3 = LEVEL_0, level == 4 = LEVEL_1" <<endl;
    cout<<"        EXIT: Enter the value as 100"<<endl;
    cout<<endl<<"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"<<endl;
    cin>>level;
   
    // LOGGING LOGIC
    if(level == 1)
    {
       MUNI_DEBUG_ON(LEVEL_0);
    }
    else if(level == 2)
    {
       MUNI_DEBUG_ON(LEVEL_1);
    }
    else if(level == 3)
    {
       MUNI_DEBUG_OFF(LEVEL_0);
    }
    else if(level == 4)
    {
       MUNI_DEBUG_OFF(LEVEL_1);
    }
    else
    {
       cout<<" Invalid Input"<<endl;
    }
    // END LOGGING LOGIC
   
    // CHECK the value of X
    if(X==0)
      {
         // If DEBUG_LEVEL_0 is enabled then only print the LOG
         if(MUNI_DEBUG(LEVEL_0))
         {
            LOG_DEBUG(" LEVEL 0 LOG: The value of X is ZERO");
         }
        
         cout<<endl;
        
         // If DEBUG_LEVEL_1 is enabled then only print the LOG
         if(MUNI_DEBUG(LEVEL_1))
         {
            LOG_DEBUG(" LEVEL 1 LOG: The value of X is ZERO");
         }

         if(!(MUNI_DEBUG(LEVEL_0)) && !(MUNI_DEBUG(LEVEL_1)))
         {
           LOG_DEBUG(" NO DEBUG LEVEL LOGS (LEVEL_0 and LEVEL_1) ARE ENABLED");
         }
         cout<<endl;
      }
    else
      {         
          // If DEBUG_LEVEL_0 is enabled then only print the LOG
          if(MUNI_DEBUG(LEVEL_0))
          {
             LOG_DEBUG(" LEVEL 0 LOG: The value of X is NOT ZERO and its value: %d", X);
          }
           cout<<endl;

          // If DEBUG_LEVEL_1 is enabled then only print the LOG
          if(MUNI_DEBUG(LEVEL_1))
          {
             LOG_DEBUG(" LEVEL 1 LOG: The value of X is NOT ZERO and its value:%d", X);
          }

          if(!(MUNI_DEBUG(LEVEL_0)) && !(MUNI_DEBUG(LEVEL_1)))
          {
             LOG_DEBUG(" NO DEBUG LEVELS(LEVEL_0 and LEVEL_1) LOGS ARE ENABLED");
          }
      }

  } while(level!= 100); //Exit
  return 0;
}


Thursday, 27 December 2012

What is Static Library and Dynamic Library? How to generate the static and dynamic library?



How to Generate Static Library and Dynamic Library(Shared Libaries) Using Makefile:

First of all i would like give some introduction about static library and dynamic library.

The difference between static and dynamic libraries can be viewed as how you get to work. You can drive your car or you can take a train. Driving your own car is kinda like a static library. Taking the train is kinda like a shared library.

When you drive your car all you need is the car. When you take the train there is usually more than one train car by itself. Usually there's a locomotive, and then some passenger cars, and maybe a caboose to boot. As long as all the cars are working in harmony you continue to get to work. If any of the cars has a problem your chances of getting to work diminish.

When you compile a program with static libraries statically linked libraries are linked into the final executable by the linker. This increases the size of the executable. Likewise when a library needs to be updated you'll need to compile the new library and then recompile the application to take advantage of the new library. Ok, so why do we have static libraries then? Well if you're booting your system into maintenance mode static libraries can be beneficial.


What is Static Library?

Static libraries are simply a collection of ordinary object files; conventionally, static libraries end with the ``.a'' suffix. This collection is created using the ar (archiver) program.  

In static linking, the size of the executable becomes greater than in dynamic linking, as the library code is stored within the executable rather than in separate files

Static libraries permit users to link to programs without having to recompile its code, saving recompilation time. Note that recompilation time is less important given today's faster compilers, so this reason is not as strong as it once was. Static libraries are often useful for developers if they wish to permit programmers to link to their library, but don't want to give the library source code.

To create a static library, or to add additional object files to an existing static library, use a command like this:

                   ar rcs library.a File1.o File2.o
or 
                   ar -qcs library.a File1.o File2.o 



Makefile to Generate Static Library.

Let's take small example, suppose there are two files and generate the static library and link it to main file.

file1.c

int fun1(int a, int b)
{
  int c;

  /* add the Two Variables */
  c= a+b;
  return(c);
}

file2.c

int fun2(int a, int b)
{
  int c;

  /* add the Two Variables */
  c= a+b;
  return(c);
}
 Above there are two files, here you can find the Makefile to generate the library using file1.o and file2.o

Makefile to generate MyLibrary.a using file1.o and file2.o

CC = gcc

CFLAGS = -g -Wall

# .a extension for static library
# .so extension for dynamic library
# step 1:
# it goes to step2:

all: libMylibrary.a


#step 3:
# Return to step 2
# Declare this OBJS before it is used, Here OBJS is a variable.

OBJS = $(PWD)/file1.o \
       $(PWD)/file2.o

#step 2:

libMylibrary.a : $(OBJS)
        ar -qcs libMylibrary.a $(OBJS)


# step 4:
# Return to step 3

$(PWD)/%.o : %.c
        $(CC) $(CFLAGS) -c $< -o $@

clean:
        rm -f *.o
        rm -f *.a


How to Link this library to the Main function file to get .exe

mainFile.c

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

extern int fun1(int a, int b);
extern int fun2(int a, int b);

int main()
{

  printf("The value of Function1: %d", fun1(4,5));
  printf("The value of Function2: %d", fun2(6,7));

  return 0;
}

Makefile links library and generate the test.exe

CC = gcc

CFLAGS = -g -Wall

# .a extension for static library
# .so extension for dynamic library
# step 1:
# it goes to step2:

all: test


#step 3:
# Return to step 2

OBJS = $(PWD)/mainFile.o \

#step 2:

test : $(OBJS)
        $(CC) $(CFLAGS) $(OBJS) $(LIBDIR) $(LIBLOG) -o test.exe


#step 4:
# Return to Step 3

$(PWD)/mainFile.o : mainFile.c
        $(CC) $(CFLAGS) -c mainFile.c

# Step 5:
# For static library, always include LIB DIR
# This is Mandatory
LIBDIR =  -L./
LIBLOG = -lMylibrary

clean:
        rm -f *.o
        rm -f *.a

 Important Point:
When ever you are linking static library to mainFile,  it is mandatory to mention the LIBDIR( where the library is present) using -L option. This $(LIBDIR) should be included when generating .exe file. 

Note: How to run your own makefile, suppose i have makefile as Makefile_org, then run using the below command.
make -f Makefile_org
clean :
 make -f Makefile_org clean

Real Time Example.
Suppose there are three modules BMODULE, CMODULE , DMODULE. BMODULE  is having dependency upon other two modules i.e. CMODULE , DMODULE
Hence, first compile CMODULE  and DMODULE and link their objects to BMODULE to generate the .exe.
Here  DMODULE generates the static library and CMODULE generates the object files(o's)

Step1:  Create Directories of BModule, DModule, CModule

-bash-3.2#  mkdir mreddya
-bash-3.2#  mkdir MAKEFILE_EXERCISE  

create directories under /root/mreddya/MAKEFILE_EXERCISE/as shown below.
-bash-3.2#  mkdir BMODULE
-bash-3.2#  mkdir CMODULE 
-bash-3.2#  mkdir DMODULE
 
Step2:  Create sub-directories of BModule, DModule, CModule
create sub directories under each module as shown below.
-bash-3.2# cd DMODULE/
-bash-3.2#  mkdir src
-bash-3.2#  mkdir inc
-bash-3.2#  mkdir obj 

-bash-3.2# cd CMODULE/
-bash-3.2#  mkdir src
-bash-3.2#  mkdir inc
-bash-3.2#  mkdir obj 

-bash-3.2# cd BMODULE/
-bash-3.2#  mkdir src
-bash-3.2#  mkdir inc
-bash-3.2#  mkdir obj 

Step 3:  Generate Library for DModule for the below files

-bash-3.2# cd DMODULE/
-bash-3.2# cd
Create four files under source directory, dModulefile1.c  dModulefile2.c  dModulefile3.c, Makefile
-bash-3.2# cd DMODULE/
-bash-3.2# cd inc
Create three files under inc,dModulefile1.h  dModulefile2.h  dModulefile3.h


dModulefile1.c

#include "dModulefile1.h"

int DModuleFunction1(int a)
{
   printf("I am in DModuleFunction1 and its Value:%d", a);
   a = a + FUNC_VALUE4;
   return(a);
}

dModulefile2.c

#include "dModulefile2.h"

int DModuleFunction2(int b)
{
   printf("I am in DModuleFunction2 and its Value:%d", b);
   b = b + FUNC_VALUE5;
   return(b);
}

dModulefile3.c

#include "dModulefile3.h"

int DModuleFunction3(int c)
{
   printf("I am in DModuleFunction3 and its Value:%d", c);
   c = c + FUNC_VALUE6;
   return(c);
}

dModulefile1.h
#include<stdio.h>
#define FUNC_VALUE4 14

dModulefile2.h
#include<stdio.h>
#define FUNC_VALUE5 11

dModulefile3.h
#include<stdio.h>
#define FUNC_VALUE6 13

Step 4:  Makefile for DMODULE (Makefile place in src directory)

# define the Compiler as gcc
CC = gcc

# define compiler flags "CFLAGS"  if you -g option it is for GDB, -wall to display all
# warnings

CFLAGS= -g -Wall

# TO include Directories, To include any directories give -I/Path Directory
# e.g: INCLUDEDIR = -I/VOBS/CMODULE/INC/, to include one more directory
# then Syntax will be INCLUDEDIR += -I/VOBS/CMODULE/INC/
#                     INCLUDEDIR  = -I/VOBS/BMODULE/INC/

INCLUDEDIR = -I/root/mreddya/MAKEFILE_EXERCISE/DMODULE/inc

# define MACRO for OBJECT DIRETORY
OBJ-DIR = /root/mreddya/MAKEFILE_EXERCISE/DMODULE/obj

# copy all .o( Objects) in to object directory
# All Objects are stored in OBJ-DIR
#
OBJS = $(OBJ-DIR)/dModulefile1.o \
        $(OBJ-DIR)/dModulefile2.o \
        $(OBJ-DIR)/dModulefile3.o \


# First whenever we give Make, it comes here, and Check OBJS
# Then It will check what and all .o are required from 
# OBJS directory
# then it will go Command to generate the .o's.

all:    libDmodule.a

# Generate the Library

libDmodule.a: $(OBJS)
        ar -qcs libDmodule.a $(OBJS)

#To Generate %.o means same directory.
# target ( It tells $(OBJ-DIR)/%.o : %.c, generate the %.c files # to .o files using command.)
# To get the Target the below command should be executed, 
# otherwise Linker error will be there.

$(OBJ-DIR)/%.o : %.c
        $(CC) $(CFLAGS) $(INCLUDEDIR) -c $< -o $@


clean:
        rm -f $(OBJ-DIR)/*.o
        rm -f *.a

Step 5:  Run the Makefile and check the results

-bash-3.2# pwd
/root/mreddya/MAKEFILE_EXERCISE/DMODULE/src
-bash-3.2# make
gcc -g -Wall -I/root/mreddya/MAKEFILE_EXERCISE/DMODULE/inc -c dModulefile1.c -o /root/mreddya/MAKEFILE_EXERCISE/DMODULE/obj/dModulefile1.o
gcc -g -Wall -I/root/mreddya/MAKEFILE_EXERCISE/DMODULE/inc -c dModulefile2.c -o /root/mreddya/MAKEFILE_EXERCISE/DMODULE/obj/dModulefile2.o
gcc -g -Wall -I/root/mreddya/MAKEFILE_EXERCISE/DMODULE/inc -c dModulefile3.c -o /root/mreddya/MAKEFILE_EXERCISE/DMODULE/obj/dModulefile3.o
ar -qcs libDmodule.a /root/mreddya/MAKEFILE_EXERCISE/DMODULE/obj/dModulefile1.o /root/mreddya/MAKEFILE_EXERCISE/DMODULE/obj/dModulefile2.o /root/mreddya/MAKEFILE_EXERCISE/DMODULE/obj/dModulefile3.o

-bash-3.2# ls
dModulefile1.c  dModulefile2.c  dModulefile3.c  libDmodule.a  Makefile

-bash-3.2# pwd
/root/mreddya/MAKEFILE_EXERCISE/DMODULE/obj
-bash-3.2# ls
dModulefile1.o  dModulefile2.o  dModulefile3.o
Step 6:  Generate objects for CMODULE

-bash-3.2# cd CMODULE/
-bash-3.2# cd
Create four files under source directory, cModulefile1.c  cModulefile2.c  cModulefile3.c, Makefile
-bash-3.2# cd CMODULE/
-bash-3.2# cd inc
Create three files under inc,cModulefile1.h  cModulefile2.h  cModulefile3.h

cModulefile1.c

#include "cModulefile1.h"

int CModuleFunction1(int a)
{
   printf("I am in CModuleFunction1 and its Value:%d", a);
   a = a + FUNC_VALUE1;
   return(a);
}
cModulefile2.c

#include "cModulefile2.h"

int CModuleFunction2(int b)
{
   printf("I am in CModuleFunction2 and its Value:%d", b);
   b = b + FUNC_VALUE2;
   return(b);
}

dModulefile3.c

#include "cModulefile3.h"

int CModuleFunction3(int c)
{
   printf("I am in CModuleFunction3 and its Value:%d", c);
   c = c + FUNC_VALUE3;
   return(c);
}

cModulefile1.h
#include<stdio.h>
#define FUNC_VALUE1 10

cModulefile2.h
#include<stdio.h>
#define FUNC_VALUE2 11

cModulefile2.h
#include<stdio.h>
#define FUNC_VALUE3 11


Step 7:  Makefile for CMODULE (Makefile place in src directory)

# define the Compiler as gcc
CC = gcc

# define compiler flags "CFLAGS"  if you -g option it is for GDB, -wall to display all
# warnings

CFLAGS= -g -Wall

# TO include Directories, To include any directories give -I/Path Directory
# e.g: INCLUDEDIR = -I/VOBS/CMODULE/INC/, to include one more directory
# then Syntax will be INCLUDEDIR += -I/VOBS/CMODULE/INC/
#                     INCLUDEDIR  = -I/VOBS/BMODULE/INC/

INCLUDEDIR = -I/root/mreddya/MAKEFILE_EXERCISE/CMODULE/inc

# define MACRO for OBJECT DIRETORY
OBJ-DIR = /root/mreddya/MAKEFILE_EXERCISE/CMODULE/obj

# copy all .o( Objects) in to object directory
# All Objects are stored in OBJ-DIR
#
OBJS = $(OBJ-DIR)/cModulefile1.o \
        $(OBJ-DIR)/cModulefile2.o \
        $(OBJ-DIR)/cModulefile3.o \


# First whenever we give Make, it comes here, and Check OBJS
# Then It will check what and all .o are required from 
# OBJS directory
# then it will go Command to generate the .o's.

all: $(OBJS)

#To Generate %.o means same directory.
# target ( It tells $(OBJ-DIR)/%.o : %.c, generate the %.c files to .o files using command.)
#    command.
#To Generate %.o means same directory.
# target ( It tells $(OBJ-DIR)/%.o : %.c, generate the %.c files to .o files using command.)
#    command.
# To get the Target the below command should be executed, otherwise
# Linker error will be there.

$(OBJ-DIR)/%.o : %.c
        $(CC) $(CFLAGS) $(INCLUDEDIR) -c $< -o $@


clean:
        rm -f $(OBJ-DIR)/*.o


Step 8:  Run the Makefile and check the results

-bash-3.2# pwd
/root/mreddya/MAKEFILE_EXERCISE/CMODULE/src

-bash-3.2# make clean
rm -f /root/mreddya/MAKEFILE_EXERCISE/CMODULE/obj/*.o

-bash-3.2# make
gcc -g -Wall -I/root/mreddya/MAKEFILE_EXERCISE/CMODULE/inc -c cModulefile1.c -o /root/mreddya/MAKEFILE_EXERCISE/CMODULE/obj/cModulefile1.o
gcc -g -Wall -I/root/mreddya/MAKEFILE_EXERCISE/CMODULE/inc -c cModulefile2.c -o /root/mreddya/MAKEFILE_EXERCISE/CMODULE/obj/cModulefile2.o
gcc -g -Wall -I/root/mreddya/MAKEFILE_EXERCISE/CMODULE/inc -c cModulefile3.c -o /root/mreddya/MAKEFILE_EXERCISE/CMODULE/obj/cModulefile3.o
-bash-3.2# pwd
/root/mreddya/MAKEFILE_EXERCISE/CMODULE/obj

-bash-3.2# ls
cModulefile1.o  cModulefile2.o  cModulefile3.o

Step 9: Get .exe by Linking the CMODULE and DMODULE to BMODULE 

-bash-3.2# cd BMODULE/
-bash-3.2# cd
Create two files under source directory, bModulefile.c,  Makefile
-bash-3.2# cd BMODULE/
-bash-3.2# cd inc
Create one file under inc,bModulefile.h

bModulefile.c

#include<stdio.h>

#include "bModulefile.h"

/* extern the Functions */
extern int CModuleFunction1(int );
extern int CModuleFunction2(int );
extern int CModuleFunction3(int );
extern int DModuleFunction1(int );
extern int DModuleFunction2(int );
extern int DModuleFunction3(int );


void getFunValue(void)
{
  int result = 0;

  result = CModuleFunction1(3)* FUNC_VALUE8;
  printf("The Result value with CModuleFunction1:%d\n", result);
  result = CModuleFunction2(4)* FUNC_VALUE8;
  printf("The Result value with CModuleFunction2:%d\n", result);
  result = CModuleFunction3(5)* FUNC_VALUE8;
  printf("The Result value with CModuleFunction3:%d\n", result);
  result = DModuleFunction1(3)* FUNC_VALUE8;
  printf("The Result value with DModuleFunction1:%d\n", result);
  result = DModuleFunction2(4)* FUNC_VALUE8;
  printf("The Result value with DModuleFunction2:%d\n", result);
  result = DModuleFunction3(5)* FUNC_VALUE8;
  printf("The Result value with DModuleFunction3:%d\n", result);
}
int main()
{
   /* call the getFunValue Function */
   getFunValue();
   return 0;
}

bModulefile.h


#define FUNC_VALUE8 1

Step 10:  Makefile for BMODULE (Makefile place in src directory)
This Makefile links both CMODULE and DMODULE and generates the test.exe


Some points to be Noted here:
Before compiling BMODULE, first it is mandate to compile CMODULE and DMODULE.
Once CMODULE and DMODULE compiled and run the Makefile of BMODULE.

Step 11:  Makefile compiles first CMODULE and DMODULE then BMODULE
Run this Makefile using make all command


# This is the Main Make file which incorporates all the files and
# generates the .exe file.

# define the Compiler Macro as gcc
CC = gcc

# define any Flags whether to compile as 64 bit(-m64) or with -g option
# to debug in gdb and also to show file name with warnings.
CFLAGS = -g -Wall

# Include the Directories which you want to link here.
# Include the .h directories.
# Whenever multiple directories are included then use +=  with -I option
INCL_DIR += -I/root/mreddya/MAKEFILE_EXERCISE/BMODULE/inc

# define MACRO for OBJECT DIRETORY
OBJ-DIR = /root/mreddya/MAKEFILE_EXERCISE/BMODULE/obj

EXE-DIR = /root/mreddya/MAKEFILE_EXERCISE/BMODULE/src

COBJ-DIR = /root/mreddya/MAKEFILE_EXERCISE/CMODULE/obj

DLIB_DIR = /root/mreddya/MAKEFILE_EXERCISE/DMODULE/src


OBJS = $(OBJ-DIR)/bModulefile.o

COBJS = $(COBJ-DIR)/cModulefile1.o \
        $(COBJ-DIR)/cModulefile2.o \
       $(COBJ-DIR)/cModulefile3.o \


EXTERNALLIBS = -L$(DLIB_DIR)
LIBLOG       = -lDmodule



CMODULE_COMPILE:
        cd /root/mreddya/MAKEFILE_EXERCISE/CMODULE/src && make
DMODULE_COMPILE:
        cd /root/mreddya/MAKEFILE_EXERCISE/DMODULE/src && make
BMODULE_COMPILE:
        $(CC) $(CFLAGS) $(INCL_DIR) -c *.c -o $(OBJS)

all:
        make all_modules

all_modules:
        make CMODULE_COMPILE
        make DMODULE_COMPILE
        make BMODULE_COMPILE
        $(CC) -o test.exe $(OBJS) $(EXTERNALLIBS) $(LIBLOG) $(COBJS)


clean:
        rm -f $(OBJ-DIR)/*.o
        rm -f $(EXE-DIR)/*.exe
        rm -f $(COBJ-DIR)/*.o
        rm -f $(DOBJ-DIR)/*.o

There are several ways to write make files, this is one way.
write small script and compile the Makefiles like show below.

build.sh script

cd /root/mreddya/MAKEFILE_EXERCISE/CMODULE/src
make
cd /root/mreddya/MAKEFILE_EXERCISE/DMODULE/src
make

cd /root/mreddya/MAKEFILE_EXERCISE/BMODULE/src
make

What is Dynamic Library or Shared Library (.so)?

Dynamic library is also called as Shared Library. 
Shared Library is a binary file(.so file) contains object (.o) files. All object files form as shared library  and this library can be loaded or unloaded dynamically.

By using shared library concept, one can make the code is position-independent, meaning that the code may be loaded anywhere in memory. Applications linked to shared objects at run time.
 
How to generate a shared library:

Step 1: Create object code, it means generate object files (.o files) 

 gcc -fPIC -c <filename.c>

The -fPIC option tells gcc to create position independent code which is necessary for shared libraries.
  e.g: gcc -fPIC -c myfilename.c

Step 2: Create shared library 

 gcc -g -Wall -shared -o  <library Name>  <objectfile1.o,  objectfile2.o>

 It will create the library with .so extension.
e.g: gcc -g -Wall -shared -o  libMyfuncs.so file1.o  file2.o


How to use the shared library to your application

Step 1:
Set the environment for Library using 
 export LD_LIBRARY_PATH=.

The above indicates the path directory where the library is present. ./ or  .  indicates the present directory

Step 3:
Compile your Main file and generate the object code.
e.g: gcc -c mainFile

And then Link the shared library  to the main file as mentioned below.


 e.g: gcc  -L./ -lMyfuncs mainFile.o -o test.exe

 Notes:
suppose if  "-L/opt/exp", means library is present in this directory and link the library using -llibName. The name of the library is Myfuncs.so.
The libraries will NOT be included in the executable but will be dynamically linked during run time execution.
That's reason size of .exe is small when we compare with static library.

How to check the list of shared libraries using by the application.

Use simple command.
ldd <.exe>

 -bash-3.2# ldd test.exe
        libMyFun.so => ./libMyFun.so (0x00002ab25d70f000)
        libc.so.6 => /lib64/libc.so.6 (0x0000003ef7c00000)
        /lib64/ld-linux-x86-64.so.2 (0x0000003ef6c00000)



Simple Makefile to generate shared library

file1.c

int func1(int a, int b)
{
    int c;
    /* Add */
    c= a+b;
    return(c);
}

file2.c

 int func1(int a, int b)
{
    int c;
    /* Add */
    c= a+b;
    return(c);
}

Makefile to generate shared library as lib

CC = gcc

CFLAGS = -g -Wall

OBJS = $(PWD)/file1.o \
        $(PWD)/file2.o

all: libMyFun.so

libMyFun.so : $(OBJS)
        $(CC) $(CFLAGS) -shared -o libMyFun.so $(OBJS)

$(PWD)/%.o : %.c
        $(CC) $(CFLAGS) -fPIC -c *.c
clean:
        rm -f *.o
        rm -f *.so


 How to Link this shared library to the mainFile.c

mainFile.c


#include<stdio.h>

extern int func1(int, int);
extern int func2(int, int);

int main()
{

  printf("The result of Function 1 is: %d\n", func1(4,5));
  printf("The result of Function 1 is: %d\n", func2(10,20));
  return 0;
}


Build.sh  <Generate the test.exe using small script>

#step 1: clean the Library
make clean

#step 2: Generated the Library
make

#step 3: Generates the mainFile.o

gcc -c mainFile.c

#step 4: clean the .exe
rm -f *.exe

#step 5: Link the Shared library to mainFile.o and
#generates the test.exe file.

gcc -L./ -lMyFun mainFile.o -o test.exe


Run the Build.sh

chmod +x Build.sh
./Build.sh