Monday, 29 July 2019

strtok vs strtok_r - extract tokens from strings

Name

strtok, strtok_r - extract tokens from strings

Synopsis

       #include <string.h>

       char *strtok(char *str, const char *delim);
       char *strtok_r(char *str, const char *delim, char **saveptr);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
       strtok_r(): _POSIX_C_SOURCE
           || /* Glibc versions <= 2.19: */ _BSD_SOURCE || _SVID_SOURCE

Note:

1. Don't use original string pointer because, it will replace the
   delimiters with '\0'.
2. Suppose Original string is constant then crash will be hit.
3. strtok will use the global pointer, so could not use in thread & 
   2 strtok simultaneously.
4. strtok_r is a thread save, because it use the local pointer for
   next iteration.

Description:

  • strtok() and strtok_r() for splitting a string by some delimiter.
  • The strtok() function breaks a string into a sequence of zero or more nonempty tokens.
  • On the first call to strtok(), the string to be parsed should be specified in str.
  • In  each subsequent call that should parse the same string, str must be NULL.
  •  
  • The  delim argument specifies a set of bytes that delimit the tokens in the parsed string.
  • The strtok_r() function is a reentrant  version  strtok().
  • The  saveptr  argument  is a pointer  to  a  char * variable that is used internally by strtok_r() in order to maintain context between successive calls that parse the same string.

 Return:

  • Return a pointer to the next token, or NULL if there are no more tokens.

Program:

/* strtok vs strtok_r by Velraj.K
   Check : http://velrajcoding.blogspot.in
 */

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

int main(int argc, char *argv[])
{
    char *str1, *str2, *token, *subtoken;
    char *saveptr1, *saveptr2;
    char str_second[256] = {'\0'};
   // *str_second = "VelrajKutralam Indian";
    int j;

    if (argc != 4) {
        fprintf(stderr, "Usage: %s  <1st delim="">  <2nd subdelim="">\n",
                argv[0]);
        exit(EXIT_FAILURE);
    }

    /* The original string will be replaced with null in delimiter places */
    strncpy(str_second, argv[1], sizeof(str_second));

    printf("\n\n\t\t Do the token using strtok_r \n");

    /* use strtok_r */
    for (j = 1, str1 = argv[1]; ; j++, str1 = NULL) {
        token = strtok_r(str1, argv[2], &saveptr1);
        if (token == NULL)
            break;
        printf("%d: %s\n", j, token);

        for (str2 = token; ; str2 = NULL) {
            subtoken = strtok_r(str2, argv[3], &saveptr2);
            if (subtoken == NULL)
                break;
            printf(" --> %s\n", subtoken);
        }
    }
   printf("Original value = %s \n", argv[1]);

    printf("\n\n\t\tDo the token using strtok str_second = %s \n", str_second);
    /* Initialize the variable to NULL to start token again with strtok */
    str1 = NULL;
    str2 = NULL;
    token = NULL;
    subtoken = NULL;
    saveptr1 = NULL;
    saveptr2 = NULL;

    /* use strtok */
    for (j = 1, str1 = str_second; ; j++, str1 = NULL) {
        token = strtok(str1, argv[2]);
        if (token == NULL)
            break;
        printf("%d: %s\n", j, token);

       /*
        *  Could not use the 2nd strtok with different delim because it uses the global pointer
        *  to process the next token.
        */
#if 0
        for (str2 = token; ; str2 = NULL) {
            subtoken = strtok(str2, argv[3]);
            if (subtoken == NULL)
                break;
            printf(" --> %s\n", subtoken);
        }
#endif
    }

    exit(EXIT_SUCCESS);
}

 

Output:

:~/velrajk/sample/learn$ ./a.out  velrajkutralamindia l v


                 Do the token using strtok_r
1: ve
 --> e
2: rajkutra
 --> rajkutra
3: amindia
 --> amindia
Original value = ve


                Do the token using strtok str_second = velrajkutralamindia
1: ve
2: rajkutra
3: amindia

Tuesday, 23 July 2019

Dynamic loading lib(run time load or patch update)

dlopen:

void * dlopen(const char *filename, int flag);
Flag:
  RTLD_LAZY --> ``resolve undefined symbols as code from the dynamic library is
                  executed''
  RTLD_NOW  --> ``resolve all undefined symbols before dlopen() returns and 
                  fail if this cannot be done''
                  opening the library take slightly longer (but it speeds up 
                  lookups later);  
  RTLD_GLOBAL --> Optional -> external symbols defined in the library will be made
                  available to subsequently loaded libraries

  • If the libraries depend on each other (e.g., X depends on Y), then you need to load the dependees first (in this example, load Y first, and then X).

Return:

  • ``handle'' that should be considered an opaque value to be used by the other DL library routines.
  • Return NULL On error.

dlerror:

  • which returns a string describing the error from the last call to dlopen(), dlsym(), or dlclose().
  • Return null if there is no error.
  • Call dlerror() first (to clear any error condition that may have existed), then call dlsym() to request a symbol, then call dlerror() again to see if an error occurred.

dlsym:

void * dlsym(void *handle, char *symbol);
      handle -> value returned from dlopen
      symbol -> NIL-terminated string.

Note:

For Run time patch(Dynamic loading the .so file):
   We must close the old handler & re open the library again,if there is
   any change in library. Otherwise changes won't be loaded.
   Hence for Run time patch, we must close & open the library again.

Return:

  • Return a NULL result if the symbol wasn't found.   

dlclose:

  • Closes a DL library.
  •  The dl library maintains link counts for dynamic file handles, so a dynamic library is not actually deallocated until dlclose has been called on it as many times as dlopen has succeeded on it.
  •  It's not a problem for the same program to load the same library multiple times.

Return:

  • Returns 0 on success, and non-zero on error

Program:

Program 1: create shared library:

 

/* Dynamic loading lib(run time load or patch update)
 * Check : http://velrajcoding.blogspot.in
 */

#include <stdio.h>

void run_load()
{
    printf("Velraj Run time loading 1st \n");


    return;
}
 

Program 2: Dynamic loader program:

 
/* Dynamic loading lib(run time load or patch update)
 * Check : http://velrajcoding.blogspot.in
 */

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

#define LIB_USR_DEF   "~/velrajk/sample/learn/librunlib.so"

enum {
    DL_LOAD_LIB = 1,
    DL_CALL_FUN,
    DL_EXIT,
};

void hline(char ch)
{
    int i = 0;

    for ( ; i < 80; printf("%c", ch), i++);
    printf("\n");

    return;
}
int main(int argc, char **argv)
{
    void *handle = NULL;
    void (*fun_symbol)();
    char *ret = NULL;
    int  ch = 0;

    while (1) {
        printf("\n\n");
        hline('*');
        printf("Find the DL library options:  \n\t 1. Load the library\n\t 2.Call the function\n\t 3.Exit\n Enter your choice:   ");
        scanf("%d", &ch);

        switch (ch) {
            case DL_LOAD_LIB:
                /*
                 * For Run time path:
                 *       We must close the old handler & re open the library again, if there is any change in library.
                 *       Otherwise changes won't be loaded.
                 *       Hence for Run time patch, we must close & open the library again.
                 */
                if (handle) {
                    dlclose(handle);
                }
                handle = dlopen(LIB_USR_DEF, RTLD_LAZY);
                if (!handle) {
                    fputs (dlerror(), stderr);
                    continue;
                }
                printf("Successfully opened an library \n");
                break;
            case DL_CALL_FUN:
                /* clear error code */
                dlerror();
                fun_symbol = dlsym(handle, "run_load");
                if ((ret = dlerror()) != NULL)  {
                    /* handle error, the symbol wasn't found */
                    printf("dlerror return error msg as:%s \n", ret);
                    continue;
                }

                /* symbol found, calling the symbol */
                (*fun_symbol)();
                break;
            case DL_EXIT:
                exit(1);
                break;
            default:
                printf("Choose the correct choice \n");
                break;
        }
    }

    dlclose(handle);

    return 0;
}
 

Output:

Program 1: Create Library

   :~/velrajk/sample/learn$ gcc -fPIC -shared -o librunlib.so dl_run_lib.c

Program 2: Dynamic loading

   :~/velrajk/sample/learn$ gcc dlopen.c -ldl


:~/velrajk/sample/learn$ ./a.out


********************************************************************************
Find the DL library options:
         1. Load the library
         2.Call the function
         3.Exit
 Enter your choice:   1
Successfully opened an library


********************************************************************************
Find the DL library options:
         1. Load the library
         2.Call the function
         3.Exit
 Enter your choice:   2
Velraj Run time loading 1st


********************************************************************************
Find the DL library options:
         1. Load the library
         2.Call the function
         3.Exit
 Enter your choice:



<!-- Here itself changed the library content as 2nd but without dlclose & dlopen, new value won't effect -->

2
Velraj Run time loading 1st


********************************************************************************
Find the DL library options:
         1. Load the library
         2.Call the function
         3.Exit
 Enter your choice:   2
Velraj Run time loading 1st


********************************************************************************
Find the DL library options:
         1. Load the library
         2.Call the function
         3.Exit
 Enter your choice:   2
Velraj Run time loading 1st


********************************************************************************
Find the DL library options:
         1. Load the library
         2.Call the function
         3.Exit
 Enter your choice:   1
Successfully opened an library


********************************************************************************
Find the DL library options:
         1. Load the library
         2.Call the function
         3.Exit
 Enter your choice:   2
Velraj Run time loading 2nd


********************************************************************************
Find the DL library options:
         1. Load the library
         2.Call the function
         3.Exit
 Enter your choice:   3

Reference:
    http://tldp.org/HOWTO/Program-Library-HOWTO/dl-libraries.html
    https://developer.ibm.com/tutorials/l-dynamic-libraries/
 

Shared library program:   Shared Libraries with GCC on linux


Monday, 22 July 2019

File based Database using Gunzip


  • zlib is a software library used for data compression.
  • The zlib library provides Deflate compression and decompression code for use by zip, gzip, png (which uses the zlib wrapper on deflate data).
  • gzread decompresses as you read it.

Program:

 
/* File based Database using Gunzip
 * Check : http://velrajcoding.blogspot.in
 */

#include <stdio.h>
#include <zlib.h>    // For gunzip

enum {
    TAG_VER = 1,
    TAG_DATA,
};

#define FILE_PATH_TMP     "file_gz_db.gz.tmp"
#define FILE_PATH         "file_gz_db.gz"
#define VERSION_1         1
#define STU_ID            100
#define STU_NAME          "Velraj"
#define STU_TOTAL         500

void save_db()
{
    char buf[256] = {0};
    int  len = 0;
    gzFile gz_file = NULL;

    if (!(gz_file = gzopen(FILE_PATH_TMP, "wb"))) {
        printf("Failed gzopen !");
        return;
    }

    len = snprintf(buf, sizeof(buf), "%d\a%d\n", TAG_VER, VERSION_1);
    if (len != gzwrite(gz_file, buf, len)) {
        printf("Failed to writing db header!");
        goto end;
    }

    len = snprintf(buf, sizeof(buf), "%d\a%d\a%s\a%d\n", TAG_DATA,
                   STU_ID, STU_NAME, STU_TOTAL);
    if (len != gzwrite(gz_file, buf, len)) {
        printf("Failed to writing db header!");
        goto end;
    }
    rename(FILE_PATH_TMP, FILE_PATH);

end:
    gzclose(gz_file);
    return;
}

void read_db()
{
    gzFile gz_file = NULL;
    char   buf[256] = {0}, str_tag[16] = {0}, str_stu_id[12] = {0}, str_name[64] = {0}, str_total[12] = {0};
    int    tag = 0, version = 0, ret = 0;

    if (!(gz_file = gzopen(FILE_PATH, "rb"))) {
        printf("gzopen is failed to open the file");
        return;
    }
    if (gzgets(gz_file, buf, sizeof(buf)) == NULL) {
        printf("File is doesn't have any content");
        goto end;
    }

    sscanf(buf, "%d\a%d", &tag, &version);
    if ((tag != TAG_VER) || (version != VERSION_1)) {
        printf("Failed tag or version");
        goto end;
    }

    while (gzgets(gz_file, buf, sizeof(buf))) {
        ret = sscanf(buf, "%d", &tag);
        if (tag != TAG_DATA) {
            continue;
        }

        ret = sscanf(buf, "%*[^\a]\a%[^\a]\a%[^\a]\a%[^\n]", str_stu_id, str_name, str_total);
        if (ret != 3) {
            printf("Failed to read student details ret:%d", ret);
            continue;
        }
        printf("Read the data : ID:%s, Name:%s, Total:%s \n", str_stu_id, str_name, str_total);
    }

end:
    gzclose(gz_file);
    return;
}

int main()
{
    save_db();
    read_db();

    return 0;
}
 

Output:

:~/velrajk/sample$ gcc file_list_of_data.c  -lz
:~/velrajk/sample$ ls -l file_gz_db.gz
ls: cannot access file_gz_db.gz: No such file or directory
:~/velrajk/sample$ ./a.out
Read the data : ID:100, Name:Velraj, Total:500
:~/velrajk/sample$ ls -l file_gz_db.gz
-rw-rw-r-- 1 labuser labuser 41 Jul 22 14:44 file_gz_db.gz
:~/velrajk/sample$ gunzip file_gz_db.gz
:~/velrajk/sample$ cat file_gz_db
11
2100Velraj500
:~/velrajk/sample$





Reference:
https://www.lemoda.net/c/gzfile-read/
https://stackoverflow.com/questions/39233004/zlib-gzopen-returns-a-compressed-file-stream-does-it-decompress-the-file
https://github.com/madler/zlib

Friday, 19 July 2019

Write binary(struct) data to the file using fread, fwrite

NAME

       fread, fwrite - binary stream input/output

SYNOPSIS

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);


Note:

 3rd Argument is sizeof nmemb:
      nmemb -> number of size to be written into fiile.
              Eg: if 1 then only one node will be written into file.
                  if 2 then two nodes will be written into the file.

DESCRIPTION

  • The function fread() reads nmemb elements of data, each size bytes long, from the stream pointed to by stream, storing them at the location given by ptr.
  • The function fwrite() writes nmemb elements of data, each size bytes long, to the stream pointed to by stream, obtaining them from the location given by ptr.

RETURN VALUE

  • On  success, fread() and fwrite() return the number of items read or written.  This number equals the number of bytes transferred only when size is 1.
  • If an error occurs, or the end of the file is reached, the return value is a short item count (or zero).
  • fread() does not distinguish between end-of-file and error, and callers must use feof(3) and ferror(3) to determine which occurred.
  • Note: To verify error need to use ferror() API, could not use return value.

Program:

 

/* Write binary(struct) data to the file using fread, fwrite
 * Check : http://velrajcoding.blogspot.in
 */

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

#define FILE_NAME       "binary_fil"
#define FILE_NAME_2     "binary_fil2"
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif

typedef struct node {
    int   value1;
    int   value2;
    char  name[64];
} node_t;

void display_node(node_t *node, char *msg)
{
    if (!node || !msg) {
        printf("Node or msg is null \n");
        return;
    }
    printf("Node %s Value 1:%d Value2:%d name:%s \n", msg, node->value1, node->value2, node->name);

    return;
}

int file_write_struct(node_t *node, const char *file, size_t num_node)
{
    FILE        *fp = NULL;

    if (!(fp = fopen(file, "w"))) {
        printf("Error in open an file, error no:%d:<%s> \n", errno, strerror(errno));
        return FALSE;
    }

    /*
     * 3rd Argument is sizeof nmemb:
     *     nmemb -> number of size to be written into fiile.
     *              Eg: if 1 then only one node will be written into file.
     *                  if 2 then two nodes will be written into the file.
     */
    fwrite(node, sizeof(node_t), num_node, fp);
    if (ferror(fp)) {
        printf("Error in write to the file, error no:%d:<%s> \n", errno, strerror(errno));
        return FALSE;
    }
    fclose(fp);

    return TRUE;
}

int file_read_struct(node_t *node)
{
    FILE        *fp = NULL;

    if (!(fp = fopen(FILE_NAME, "r"))) {
        printf("Error in open an file, error no:%d:<%s> \n", errno, strerror(errno));
        return FALSE;
    }

    fread(node, sizeof(node_t), 1, fp);
    if (ferror(fp)) {
        printf("Error in write to the file, error no:%d:<%s> \n", errno, strerror(errno));
        return FALSE;
    }
    fclose(fp);

    return TRUE;
}

int main()
{
    node_t      node[] = { {100, 200, "Velraj Kutralam"},
                           {20, 35, "Kutralam S"} };
    node_t      node_read = {0};

    display_node(node, "before save");
    file_write_struct(node, FILE_NAME, 1);
    file_write_struct(node, FILE_NAME_2, 2);

    file_read_struct(&node_read);
    display_node(node, "after save");

    return 0;
}

 

Output:

:~/velrajk/sample$ ./a.out
Node before save Value 1:100 Value2:200 name:Velraj Kutralam
Node after save Value 1:100 Value2:200 name:Velraj Kutralam
:~/velrajk/sample$ cat binary_fil
d▒Velraj Kutralam:~/velrajk/sample$
:~/velrajk/sample$ cat binary_fil2
d▒Velraj Kutralam#Kutralam S:~/velrajk/sample$


Vim of binary_fil:

d^@^@^@È^@^@^@Velraj Kutralam^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@

Vim of binary_fil2:

^@^@^@È^@^@^@Velraj Kutralam^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^T^@^@^@#^@^@^@Kutralam S^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@


Wednesday, 17 July 2019

Increase socket buffer size using SO_RCVBUF & SO_SNDBUF

SO_RCVBUF

  • The "SO_" prefix is for "socket option"
  • Settings for the per-socket buffers.
  • It is the size of the buffer, the kernel allocates to hold the data arriving into the given socket during the time between it arrives over the network and when it is read by the program that owns this socket.
  • For TCP:
    • If data arrives and you aren't reading it, the buffer will fill up, and the sender will be told to slow down (using TCP window adjustment mechanism).
  • For UDP:
    • once the buffer is full, new packets will just be discarded.

SO_SNDBUF

  • Similary to SO_RCVBUF this is for send buffer.


This is limited at system level by the below file
    # cat /proc/sys/net/core/wmem_max

Note: 

  • In real time, Used TCP local socket for IPC & faced below buffer issue:
  • Process A working on the data & send the value to process B, Process B process this data & response the result back to Process A to update his db.
  • Usually Process A will do only 1 data, at a time, so never faced any issue.
  • Some corner case, process A processing bulk data, and send the data to Process B and not processing the process B response.
  • Hence response from process B is got full & process B start discarding the value due to socket full message.

Solution 1:

  • Increase the socket buffer size using SO_SNDBUF, but could not increase double the system max size "core/wmem_max".
  • Partially issue fixed without increase the system max "core/wmem_max", full complete fix need to increase the system max memory.

Solution 2:

  • Instead of process only bulk data, process A can process 200 bulk data & give few second gap to process the Process B response.
  • And the process the next set of message, batching the bulk data.

Conclusion:

  • Instead of increase the system wide memory, its good to do the batching. Hence batching is selected.

Program:

Makefile:

CC = gcc
SO_FLAGS = -fPIC -shared

exe:libsock.so
        gcc select_stream_cli.c -L . -l sock -o cli -lpthread
        gcc select_stream_ser.c -L . -l sock -o ser

libsock.so:
        $(CC) ../socket_buf_inc.c $(SO_FLAGS) -o ../libsock.so

clean:
        rm libsock.so cli ser


socket_buf_inc.h:

#ifndef __SOCKET_BUF_INC__H__
#define __SOCKET_BUF_INC__H__

void socket_non_blocking(int soc_fd);
void soc_get_so_rcv_buf(int sock_fd, char *msg);
void soc_set_so_rcv_buf(int sock_fd, size_t size);

#endif /* __SOCKET_BUF_INC__H__ */


"../socket_buf_inc.c":


/* Increase socket buffer size using SO_RCVBUF & SO_SNDBUF
 * Check : http://velrajcoding.blogspot.in
 */
#include <stdio .h>
// Below 2 for getsockopt & setsockopt
#include <sys/types.h>
#include <sys/socket.h>

#include <errno.h>  // for errno

#include <unistd.h>  // For fcntl
#include <fcntl.h>   //  For fcntl
#include <string.h>  // For strerror


//#define SO_RCV_BUFFER_SIZE        425984

/******************************************************************************
 * FUNCTION NAME: socket_non_blocking
 *
 * DESCRIPTION  : Set the socket fd as non blocking socket
 *
 * RETURNS      : None
 ******************************************************************************/
void socket_non_blocking(int soc_fd)
{
    int        flags_non_blk = 0;

    if ((flags_non_blk =  fcntl(soc_fd, F_GETFL)) == -1) {
        printf("Failed to get flags, so didn't set the block buffer errno <%d>(%s) \n", errno, strerror(errno));
        return;
    }
    if (fcntl(soc_fd, F_SETFL, (flags_non_blk | O_NONBLOCK)) == -1) {
        printf("Failed to set the block buffer errno <%d>(%s) \n", errno, strerror(errno));
    }
    printf("The socket:%d is set as non-blocking socket \n", soc_fd);

    return;
}


/******************************************************************************
 * FUNCTION NAME: soc_get_so_rcv_buf
 *
 * DESCRIPTION  : Retrieve the socket receive buffer size
 *
 * RETURNS      : None
 ******************************************************************************/
void soc_get_so_rcv_buf(int sock_fd, char *msg)
{
    unsigned int size = 0;
    socklen_t socklen = sizeof(size);

    getsockopt(sock_fd, SOL_SOCKET, SO_RCVBUF, &size, &socklen);
    printf("Socket receive buffer %s size:%u \n", msg, size);


}

/******************************************************************************
 * FUNCTION NAME: soc_get_so_snd_buf
 *
 * DESCRIPTION  : Retrieve the socket receive buffer size
 *
 * RETURNS      : None
 ******************************************************************************/
void soc_get_so_snd_buf(int sock_fd, char *msg)
{
    unsigned int size = 0;
    socklen_t socklen = sizeof(size);

    getsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, &size, &socklen);
    printf("Socket send buffer %s size:%u \n", msg, size);

    return;
}


/******************************************************************************
 * FUNCTION NAME: soc_set_so_rcv_buf
 *
 * DESCRIPTION  : Set the socket receive buffer size
 *
 * RETURNS      : None
 ******************************************************************************/
void soc_set_so_rcv_buf(int sock_fd, size_t size)
{
//    unsigned int size = SO_RCV_BUFFER_SIZE;
    socklen_t socklen = sizeof(size);

    soc_get_so_rcv_buf(sock_fd, "Before set the value");
    if (setsockopt(sock_fd, SOL_SOCKET, SO_RCVBUF, &size, socklen) == -1) {
        printf("Failed to set the socket receive buffer as %zu, errno <%d>(%s)", size, errno, strerror(errno));
    }
    soc_get_so_rcv_buf(sock_fd, "After set the value");

    return;
}

/******************************************************************************
 * FUNCTION NAME: soc_set_so_rcv_buf
 *
 * DESCRIPTION  : Set the socket receive buffer size
 *
 * RETURNS      : None
 ******************************************************************************/
void soc_set_so_snd_buf(int sock_fd, size_t size)
{
    socklen_t socklen = sizeof(size);

    soc_get_so_snd_buf(sock_fd, "Before set the value");
    if (setsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, &size, socklen) == -1) {
        printf("Failed to set the socket send buffer as %zu, errno <%d>(%s)", size, errno, strerror(errno));
    }
    soc_get_so_snd_buf(sock_fd, "After set the value");

    return;
}


Server program: select_stream_ser.c

/* Increase socket buffer size using SO_RCVBUF & SO_SNDBUF
 * Check : http://velrajcoding.blogspot.in
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>    // for bool data type
#include <math.h>
#include <signal.h>


#include <sys/ioctl.h>   //* Ioctl & FION
#define ADDRESS         "/home/labuser/highPriority"  /* addr to connect */
#define ADDRESS_LOW     "/home/labuser/lowPriority"  /* addr to connect */

#define FALSE 0
#define TRUE  1
#define SO_RCV_BUFFER_SIZE        425984

struct sock_db;

typedef struct sock_db sock_db_t;

typedef void (*fd_callback_t) (int fd, void *data);

struct sock_db{
    sock_db_t *next;
    int    fd;
    int    sock_domain;
    char   name[128];
    bool   isHighPriority;
    fd_callback_t read_callback;
};

// Globle Declaratoin
int lock = 0;
int gtotal_db = 0;
sock_db_t *top = NULL;
int gDestroyed = 0;

int max(int firstValue, int secondValue)
{
    int result = 0;

    if(firstValue > secondValue)
        result = firstValue;
    else
        result = secondValue;

    return result;
}


int lock_acquire()
{
    lock = 1;
}

int lock_release()
{
    lock = 0;
}

int lock_check_and_wait()
{
    while(lock)
    {
        printf("Vel %s inside lock sleep for 200 milli second  \n", __FUNCTION__);
        usleep(200);
    }
}



void insert_node(sock_db_t *node)
{

    if(!top)
    {
        top = node;
        top->next = NULL;
    }
    else
    {
        node->next = top;
        top = node;
    }
}

sock_db_t *create_entry(char *name, int sock_domain)
{
    sock_db_t *node;

    node = (sock_db_t *)calloc(1, sizeof(sock_db_t));
    if(node == NULL)
    {
        printf("No memory to allocate \n");
        exit(1);
    }

    strcpy(node->name, name);
    node->next = NULL;
    node->sock_domain = sock_domain;

    lock_check_and_wait();
    lock_acquire();

    insert_node(node);

    gtotal_db++;
    lock_release();

    return node;
}

int ipc_init_unix(char *path, fd_callback_t callback)
{
    int flags = 1; /*to set to non-blocking*/
    int len;
    struct sockaddr_un saun, clun;
    sock_db_t *sock_entry = NULL;



    sock_entry = create_entry("db_un", AF_UNIX);

    /*
     * get a socket to work with.  this socket will
     * be in the unix domain, and will be a
     * stream socket.
     */

    sock_entry->fd = socket(AF_UNIX, SOCK_STREAM, 0);

    if ((sock_entry->fd) < 0) {
        perror("server: socket");
        exit(1);
    }

   /*Set it to non-blocking fd*/
    ioctl(sock_entry->fd, FIONBIO, &flags);

    saun.sun_family = AF_UNIX;
    strcpy(saun.sun_path, path);

    unlink(path);
    len = sizeof(saun.sun_family) + strlen(saun.sun_path);

    if(!strcmp(path, ADDRESS))
        sock_entry->isHighPriority = 1;
    else
        sock_entry->isHighPriority = 0;

    if (bind(sock_entry->fd, (struct sockaddr *) &saun, len) < 0) {
        perror("server: bind");
        exit(1);
    }

    soc_get_so_rcv_buf(sock_entry->fd, "Socket");
    if (listen(sock_entry->fd, 4) < 0)
    {
        return -1;
    }
    sock_entry->read_callback = callback;

    return sock_entry->fd;
}

sock_db_t *find_entry(int fd)
{
    sock_db_t *sock_entry = top;

    while(sock_entry)
    {
        if(sock_entry->fd == fd)
            return sock_entry;
        sock_entry = sock_entry->next;
    }

    return NULL;

}


int  destroy(int des_fd)
{
    sock_db_t *temp = top, *prev = NULL;

    lock_check_and_wait();
    lock_acquire();

    prev = temp;
//    printf("Vel %s %p %p %p \n", __FUNCTION__, top, temp, prev);
    while(temp)
    {
        if(temp->fd == des_fd)
        {
            if(temp == top)
            {
                top = top->next;
                free(temp);
            }
            else
            {
                prev->next = temp->next;
                free(temp);
            }
            gDestroyed = 1;

            gtotal_db--;
            goto end;
        }
        prev = temp;
        temp = temp->next;
    }

end:
    lock_release();

}
void client_recv(int cli_fd, void *data)
{
    char str[128] = {0};

    sock_db_t *sock_entry = NULL;
    int nbyteRec = 0;

    sock_entry = find_entry(cli_fd);

    if(!sock_entry)
    {
        printf("Error Count not find the fd = %d \n",cli_fd);
        return;
    }

    printf("Sleep for 4 second before process the msg \n");
    sleep(4);

    memset(str, 0, sizeof(str));
    nbyteRec = read(cli_fd, str, sizeof(str));
    str[nbyteRec] = '\0';

    *(int*)data = nbyteRec;

    if(nbyteRec)
        printf("Msg Received:: Fd = %d Name= %s, Msg= %s ", cli_fd, sock_entry->name, str);
    else if(nbyteRec ==0)
    {
        printf("Vel %s Received byte is 0. Destory the Fd = %d \n", __FUNCTION__, cli_fd);
        destroy(cli_fd);
    }
    else
        perror("Read failure ");

    fflush(stdout);
}

void client_accept(int listen_fd, void *data)
{
     sock_db_t *server, *cli;
     struct sockaddr_un client_addr;
     int addrlen = 0, flags = 1, fd = 0;

     server = find_entry(listen_fd);

     addrlen = sizeof(client_addr);
     fd = accept(listen_fd, (struct sockaddr *)&client_addr, &addrlen);
     if(fd < 0)
         return;

     cli = create_entry("db", server->sock_domain);

     cli->isHighPriority = server->isHighPriority;
     cli->fd = fd;

     /*
      * Since the send is got failed, so needed to increase only the buffer in sender side,
      * Don't need to increase in receiver side. Hence commented below line
      */
     //soc_set_so_rcv_buf(cli->fd, SO_RCV_BUFFER_SIZE);

    /*Set it to non-blocking fd*/
     ioctl(cli->fd, FIONBIO, &flags);


     *(int *) data = cli->fd;
     printf("Vel %s Find new clinet = %d \n", __FUNCTION__, cli->fd);
     cli->read_callback = client_recv;
}

char gFdList[256] = {0};
int fdset_prepare(fd_set *read_fd_set)
{
     int maxfd = -1, nOfClient = 0;
     sock_db_t *sock_entry = top;
     char temp[16];

     FD_ZERO(read_fd_set);

     memset(gFdList, 0, sizeof(gFdList));

     while(sock_entry)
     {
         if(sock_entry->read_callback)
         {
             FD_SET(sock_entry->fd, read_fd_set);
             maxfd = max(sock_entry->fd, maxfd);
             sprintf(temp,"%d, ",sock_entry->fd);
             strcat(gFdList, temp);
         }
         sock_entry = sock_entry->next;
         nOfClient++;
     }

     return maxfd;
}
//#define DEBUG

int fdset_process(fd_set *read_fd_set, int *nready)
{
    sock_db_t *db_high = top, *db_low = top;
    int countHigh = 0, countLow = 0;
    int high_read_cout = 0, low_read_count = 0;
    int recv_count = 0, count_not_high = 0, count_not_low = 0;

    bool isFlagHighEndDB = FALSE, isFlagLowEndDB = FALSE;

    high_read_cout = 6;
    low_read_count = 3;

        //countHigh = 1;
        //countLow = 1;
    while((db_high || db_low)&& ((isFlagHighEndDB == FALSE) || (isFlagLowEndDB == FALSE)))
    {

#ifdef DEBUG
        printf("Vel %s inside while  \n", __FUNCTION__);
#endif
        while(countHigh < high_read_cout && db_high)
        {
//    printf("Vel %s inside while  fd= %d Lw fd = %d is-Hi = %d  \n", __FUNCTION__, db_high->fd,db_low->fd, (int) FD_ISSET(db_high->fd, read_fd_set));
            if(FD_ISSET(db_high->fd, read_fd_set) && db_high->read_callback && db_high->isHighPriority)
            {
                db_high->read_callback(db_high->fd, &recv_count);

                if(gDestroyed == 1)
                {
                    printf("Stop processing the Client Since the Database is modified \n");
                    return 0;
                }

                if(recv_count <=0)
                {
                    int temp = db_high->fd;
                    FD_CLR(temp, read_fd_set);
                }

                (*nready)--;
                /* Here using 2 loop for single database. So if there is any change in database(EG: Client disconnect the link)
                   then 2nd loop will be affected. Used gDestoryed to stop looping.
                   Need to check this condition in our  if we use the 2 while loop. */

                countHigh++;
            }
            else
                count_not_high++;
                                         

            db_high = db_high->next;
            if(db_high == NULL)
            {
//                printf("Vel %s Start again High priority from Top gtotal_db = %d countNot = %d \n", __FUNCTION__, gtotal_db, count_not_high);
                if(count_not_high != gtotal_db)
                    db_high = top;
                count_not_high = 0;
                isFlagHighEndDB = TRUE;
            }

        }

//#ifdef DEBUG
#if 0
        printf("Vel %s inside while after high prir= %d  H= %p L= %p\n", __FUNCTION__, countHigh, db_high, db_low);
#endif
        while(countLow < low_read_count && db_low)
        {
//    printf("Vel %s  LFd= %d   is -low= %d \n", __FUNCTION__, db_low->fd, (int) FD_ISSET(db_low->fd, read_fd_set));
            if(FD_ISSET(db_low->fd, read_fd_set) && db_low->read_callback && (db_low->isHighPriority == 0))
            {
                db_low->read_callback(db_low->fd, &recv_count);
                if(gDestroyed == 1)
                {
                    printf("Stop processing the Client Since the Database is modified \n");
                    return 0;
                }

                if(recv_count <=0)
                {
                    int temp = db_low->fd;
                    FD_CLR(temp, read_fd_set);
                }

                (*nready)--;
                countLow++;
            }
            else
               count_not_low++;

            db_low = db_low->next;
//            printf("Vel %s Start again low priority from Top gtotal = %d countlow = %d \n", __FUNCTION__, gtotal_db, count_not_low);
            if(db_low == NULL)
            {
                if(count_not_low != gtotal_db)
                    db_low= top;
                count_not_low = 0;
                isFlagLowEndDB = TRUE;
            }
        }
    }

//    printf("Vel %s End *** \n", __FUNCTION__);

}

int ipc_handle_input(unsigned int wait_sec, unsigned int wait_usec)
{
    struct timeval timeout;
    int max_fd = 0, nready = 0;
    fd_set rd_fds;

    timeout.tv_sec = wait_sec;
    timeout.tv_usec = wait_usec;


    max_fd = fdset_prepare(&rd_fds);

    nready = select(max_fd+1, &rd_fds, NULL, NULL, &timeout);
    if (nready < 0)
    {
        printf("Vel Error in reading Select \n");
        return 2;
    }
    else if (nready == 0)
    {
         printf("Timed out !! Available Client FD list = %s \r\n", gFdList);
         timeout.tv_sec = 300;
         timeout.tv_usec = 0;
    }
    else
    {
//        printf("Vel %s process \n", __FUNCTION__);
        fdset_process(&rd_fds, &nready);
    }

    return 0;
}

main()
{
    int sock= 0, sockHigh= 0;

    sock = ipc_init_unix(ADDRESS_LOW, client_accept);
    sockHigh = ipc_init_unix(ADDRESS, client_accept);


    while(1)
    {
        gDestroyed = 0;
        ipc_handle_input(300,0);
    }

   /*
     * We can simply use close() to terminate the
     * connection, since we're done with both sides.
     */
    close(sock);
    close(sockHigh);

    exit(0);
}



Client program: select_stream_cli.c

/* Increase socket buffer size using SO_RCVBUF & SO_SNDBUF
 * Check : http://velrajcoding.blogspot.in
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h> // for pthread
#include <sys/ioctl.h>
#include <signal.h>
#include <errno.h>

#define NSTRS         3           /* no. of strings  */
#define ADDRESS       "/home/labuser/highPriority"  /* addr to connect */
#define ADDRESS_LOW   "/home/labuser/lowPriority"  /* addr to connect */
#define SO_SND_BUFFER_SIZE        425984

int connectToIPCconnection(char *path)
{
    int s;
    struct sockaddr_un sockaddun = {0};

    /*
     * Get a socket to work with.  This socket will
     * be in the UNIX domain, and will be a
     * stream socket.
     */
    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
        perror("client: socket");
        exit(1);
    }

    /*
     * Create the address we will be connecting to.
     */
    sockaddun.sun_family = AF_UNIX;
    strcpy(sockaddun.sun_path, path);

    if(connect(s, (struct sockaddr *)&sockaddun, sizeof(struct sockaddr_un)) < 0)
    {
        printf("Vel Error connectiong \n");
    }


//    soc_set_so_snd_buf(s, SO_SND_BUFFER_SIZE);
    return s;
}
struct sockidstruct
{
    int sockId;
    char  name[128];
};

void *thread_send_high_message(void *sockDetails)
{
    int i, iSendBytes = 0;
    struct sockidstruct *saunDet = NULL;
    char str[128];

    saunDet = sockDetails;

    /* Send high priority message to server */
    for (i = 0; i < 800; i++)
    {
      //  if(i == 40)
        //    usleep(1);
        memset(str, 0, sizeof(str));
        snprintf(str, sizeof(str), "HIGH priority Msg from client = \"%s\" Number of message = %d \n", saunDet->name, i+1);
        iSendBytes = sendto(saunDet->sockId, str, sizeof(str) /* strlen(str)*/, 0 /*MSG_DONTWAIT */,NULL, 0);

        if(iSendBytes > 0)
        {
            printf("Send High Msg byte = %d Msg count = %d \n", iSendBytes, i+1);
        } else {
            printf("Error in sending errno %d:%s\n", errno, strerror(errno));
        }

    }
    return NULL;
}

void *thread_send_low_message(void *sockDetails)
{
    int i, iSendBytes = 0;
    struct sockidstruct *saunDet = NULL;
    char str[128];

    saunDet = sockDetails;

    /* Send Low priority message to server */
    for (i = 0; i < 40; i++)
    {
///        if(i == 20)
   //         usleep(1);
        memset(str, 0, sizeof(str));
        snprintf(str, sizeof(str), "LOW priority Msg from client = \"%s\" Number of message = %d \n", saunDet->name, i+1);
        iSendBytes = sendto(saunDet->sockId, str, sizeof(str) /*strlen(str)*/, 0 /*MSG_DONTWAIT */, NULL, 0);
        if(iSendBytes > 0 )
            printf("Send Low Msg Byte = %d msg count = %d \n", iSendBytes, i+1);
    }

    return NULL;
}

int main(int argc , char **argv)
{
    char c;
    int i, sockHigh, sockLow;
    pthread_t thread_id_high, thread_id_low;
    struct sockidstruct saunIdDet, saunIdDetLow;
    /*
     * Flags:
     *     1 -> For non blocking
     *     0 -> For blocking
     */

    int flags = 1, HighLowOrBoth = 0;


//    printf("vel argc = %d 1= %s 2 = %s  \n", argc, argv[0], argv[1]);
    if(argc >1 )
    {
        strcpy(saunIdDet.name, argv[1]);
        strcpy(saunIdDetLow.name, argv[1]);

        if(argc >2)
        {
            HighLowOrBoth = atoi(argv[2]);
        }
    }

    sockHigh = connectToIPCconnection(ADDRESS);
    sockLow = connectToIPCconnection(ADDRESS_LOW);

        /*Set it to non-blocking fd*/
     ioctl(sockLow, FIONBIO, &flags);
     ioctl(sockHigh, FIONBIO, &flags);

  //  socket_non_blocking(sockHigh);
  //  socket_non_blocking(sockLow);

    saunIdDet.sockId = sockHigh;
    saunIdDetLow.sockId = sockLow;

    //sleep(1);
    if(HighLowOrBoth == 0)
    {
        pthread_create(&thread_id_low, NULL, &thread_send_low_message, &saunIdDetLow);
        pthread_create(&thread_id_high, NULL, &thread_send_high_message, &saunIdDet);
        printf("Vel High & LOW both Message will be send... \n");
    }
    else if(HighLowOrBoth == 1)
    {
        pthread_create(&thread_id_high, NULL, &thread_send_high_message, &saunIdDet);
        printf("Vel Only High Message will be send");

    }
    else
    {
        pthread_create(&thread_id_low, NULL, &thread_send_low_message, &saunIdDetLow);
        printf("Vel Only Low Message will be send");
    }

    pthread_join(thread_id_high, NULL);
//    pthread_join(thread_id_low, NULL);
//    sleep(20);

    /*
     * We can simply use close() to terminate the
     * connection, since we're done with both sides.
     */
    close(sockHigh);
    close(sockLow);

    exit(0);
}



Output:


Without Increase the buffer:


Server:

 set_soc_buffer/tcp$ ./ser
Socket receive buffer Socket size:212992
Socket receive buffer Socket size:212992
Vel client_accept Find new clinet = 5
Vel client_accept Find new clinet = 6
Sleep for 4 second before process the msg
Msg Received:: Fd = 6 Name= db, Msg= LOW priority Msg from client = "" Number of message = 1
 Sleep for 4 second before process the msg

^C

Client:


set_soc_buffer/tcp$ ./cli
Vel High & LOW both Message will be send...
Send Low Msg Byte = 128 msg count = 1
Send Low Msg Byte = 128 msg count = 2
Send Low Msg Byte = 128 msg count = 3
Send Low Msg Byte = 128 msg count = 4
Send Low Msg Byte = 128 msg count = 5
Send Low Msg Byte = 128 msg count = 6
Send Low Msg Byte = 128 msg count = 7
Send Low Msg Byte = 128 msg count = 8
Send Low Msg Byte = 128 msg count = 9
Send Low Msg Byte = 128 msg count = 10
Send Low Msg Byte = 128 msg count = 11
Send Low Msg Byte = 128 msg count = 12
Send Low Msg Byte = 128 msg count = 13
Send Low Msg Byte = 128 msg count = 14
Send Low Msg Byte = 128 msg count = 15
Send Low Msg Byte = 128 msg count = 16
Send High Msg byte = 128 Msg count = 1
Send Low Msg Byte = 128 msg count = 17
Send Low Msg Byte = 128 msg count = 18
Send Low Msg Byte = 128 msg count = 19
Send Low Msg Byte = 128 msg count = 20
Send Low Msg Byte = 128 msg count = 21
Send Low Msg Byte = 128 msg count = 22
Send Low Msg Byte = 128 msg count = 23
Send Low Msg Byte = 128 msg count = 24
Send Low Msg Byte = 128 msg count = 25
Send Low Msg Byte = 128 msg count = 26
Send Low Msg Byte = 128 msg count = 27
Send Low Msg Byte = 128 msg count = 28
Send Low Msg Byte = 128 msg count = 29
Send Low Msg Byte = 128 msg count = 30
Send Low Msg Byte = 128 msg count = 31

.
.
.
-----Same mesage just icnremnet upto 276 ----
Send High Msg byte = 128 Msg count = 277
Send High Msg byte = 128 Msg count = 278
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable


Increment the send buffer alone and check:



Server Output:

 set_soc_buffer/tcp$ ./ser
Socket receive buffer Socket size:212992
Socket receive buffer Socket size:212992
Socket receive buffer Before set the value size:212992
Socket receive buffer After set the value size:425984
Vel client_accept Find new clinet = 5
Socket receive buffer Before set the value size:212992
Socket receive buffer After set the value size:425984
Vel client_accept Find new clinet = 6
Sleep for 4 second before process the msg
Msg Received:: Fd = 6 Name= db, Msg= LOW priority Msg from client = "" Number of message = 1
 Sleep for 4 second before process the msg
Msg Received:: Fd = 6 Name= db, Msg= LOW priority Msg from client = "" Number of message = 2
 Sleep for 4 second before process the msg
Msg Received:: Fd = 6 Name= db, Msg= LOW priority Msg from client = "" Number of message = 3
 Sleep for 4 second before process the msg
Msg Received:: Fd = 5 Name= db, Msg= HIGH priority Msg from client = "" Number of message = 1
 Sleep for 4 second before process the msg
Msg Received:: Fd = 5 Name= db, Msg= HIGH priority Msg from client = "" Number of message = 2
 Sleep for 4 second before process the msg
Msg Received:: Fd = 5 Name= db, Msg= HIGH priority Msg from client = "" Number of message = 3
 Sleep for 4 second before process the msg
Msg Received:: Fd = 5 Name= db, Msg= HIGH priority Msg from client = "" Number of message = 4
 Sleep for 4 second before process the msg
Msg Received:: Fd = 5 Name= db, Msg= HIGH priority Msg from client = "" Number of message = 5
 Sleep for 4 second before process the msg
Msg Received:: Fd = 5 Name= db, Msg= HIGH priority Msg from client = "" Number of message = 6
 Sleep for 4 second before process the msg
Msg Received:: Fd = 6 Name= db, Msg= LOW priority Msg from client = ""


Client Output:

set_soc_buffer/tcp$ ./cli
Socket send buffer Before set the value size:212992
Socket send buffer After set the value size:425984
Socket send buffer Before set the value size:212992
Socket send buffer After set the value size:425984
Vel High & LOW both Message will be send...
Send Low Msg Byte = 128 msg count = 1
Send Low Msg Byte = 128 msg count = 2
Send Low Msg Byte = 128 msg count = 3
Send Low Msg Byte = 128 msg count = 4
Send Low Msg Byte = 128 msg count = 5
Send Low Msg Byte = 128 msg count = 6
Send Low Msg Byte = 128 msg count = 7
Send Low Msg Byte = 128 msg count = 8
Send Low Msg Byte = 128 msg count = 9
Send Low Msg Byte = 128 msg count = 10
Send Low Msg Byte = 128 msg count = 11
.
.
.
-----Same mesage just icnremnet upto 551 ---- Send High Msg byte = 128 Msg count = 552
Send High Msg byte = 128 Msg count = 553
Send High Msg byte = 128 Msg count = 554
Send High Msg byte = 128 Msg count = 555
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sending errno 11:Resource temporarily unavailable
Error in sendin

 
Reference:
    https://stackoverflow.com/questions/4257410/what-are-so-sndbuf-and-so-recvbuf

Friday, 12 July 2019

restrict keyword

Restrict keyword


  • restrict keyword is mainly used in pointer declarations as a type qualifier for pointers.
  • The compiler will optimize the code if restrict.
  • When we use restrict with a pointer ptr, it tells the compiler that ptr is the only way to access the object pointed by it and compiler doesn’t need to add any additional checks.
  • If a programmer uses restrict keyword and violate the above condition, result is undefined behavior.
  • GCC's and Clang's __restrict__,
  • restrict says that the pointer is the only thing that accesses the underlying object. It eliminates the potential for pointer aliasing, enabling better optimization by the compiler.

Note: I have checked __restrict__ is compiling in Gcc, but could not found difference between restrict & normal in assembly file.

In code somewhere found this below line:

/* Be friend of both C90 and C99 compilers */
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
    /* "inline" and "restrict" are keywords */
#else
#   define inline           /* inline */
#   define restrict         /* restrict */
#endif

Example:


int foo(int *a, int *b)
{
    *a = 5;
    *b = 6;
    return *a + *b;
}
 
int rfoo(int *restrict a, int *restrict b)
{
    *a = 5;
    *b = 6;
    return *a + *b;
}

Possible output:

# generated code on 64bit Intel platform:
foo:
    movl    $5, (%rdi)    # store 5 in *a
    movl    $6, (%rsi)    # store 6 in *b
    movl    (%rdi), %eax  # read back from *a in case previous store modified it
    addl    $6, %eax      # add 6 to the value read from *a
    ret
 
rfoo:
    movl      $11, %eax   # the result is 11, a compile-time constant
    movl      $5, (%rdi)  # store 5 in *a
    movl      $6, (%rsi)  # store 6 in *b
    ret 


Reference:
     https://www.geeksforgeeks.org/restrict-keyword-c/
     https://en.cppreference.com/w/c/language/restrict

Wednesday, 10 July 2019

Makefile variable assign difference between ?= vs =.

Makefile diff between ?= vs =.


  • If you’d like a variable to be set to a value only if it’s not already set,
  • then you can use the shorthand operator ‘?=’ instead of ‘=’.
Note: Got the comment as "Can you make this ?= so that it can be overriden in the invocation of the makefile?", so it will be good to use?=

These below two settings of the variable ‘FOO’ are identical

FOO ?= bar

and

ifeq ($(origin FOO), undefined)
FOO = bar
endif 

Program:

 # ?= indicates to set the KDIR variable only if it's not set/doesn't have a value.
KDIR ?= "?=foo"
KDIR ?= "?=bar"

EDIR = "=foo"
EDIR = "=bar"

test:
        echo $(KDIR)
        echo
        echo $(EDIR)
 

Output:


~/velrajk/sample/makefile/make_?=$ make
echo "?=foo"
?=foo
echo

echo "=bar"
=bar
 

Reference:
     https://www.gnu.org/software/make/manual/html_node/Setting.html
     https://stackoverflow.com/questions/24777289/what-is-in-makefile


Tuesday, 9 July 2019

Makefile variable assign difference between := vs =

makefile difference between := vs =



There are two ways that a variable in GNU make can have a value:

Note: Got the comment as "Can you use early evaluation here with :=", so it will be good to use :=

The Two Flavors of Variables:  recursively expanded

  • The first flavor of variable is a recursively expanded variable.
  • Variables of this sort are defined by lines using ‘=’ or  Defining Multi-Line Variables
  • if it contains references to other variables, these references are expanded whenever this variable is substituted (in the course of expanding some other string). When this happens, it is called recursive expansion.
For Example,

foo = $(bar)
bar = $(ugh)
ugh = Huh?

all:;echo $(foo)

Second flavor of variable: simply expanded variables.

  • Simply expanded variables are defined by lines using ‘:=’ or ‘::=’ (see Setting Variables). Both forms are equivalent in GNU make;
  • The value of a simply expanded variable is scanned once and for all, expanding any references to other variables and functions, when the variable is defined.
  • It does not contain any references to other variables.
  • it contains their values as of the time this variable was defined
  • its value is substituted verbatim.
For example,
       
x := foo
y := $(x) bar
x := later

is equivalent to

y := foo bar
x := later
 

Program:

# Simply expanded variables:
x := foo
# y is assigned with 'foo bar' value, so in future x value changes also won't affect y
# y use value of x not an variable of x.
y := $(x) bar
x := later

# Recursively expanded variable:
a = foo
# y is assgined with '$(a) bar', so in future x value changes also will reflect in y.
# Because y always use variable x not an value of x.
b = $(a) bar
a = later

Test:
        echo $(x)
        echo $(y)
        echo '-----------------------'
        echo $(a)
        echo $(b)

Output:


~/velrajk/sample/makefile/make_:=$ make
echo later
later
echo foo  bar
foo bar
echo '-----------------------'
-----------------------
echo later
later
echo later bar
later bar




Reference: https://www.gnu.org/software/make/manual/make.html#Flavors
 

Wednesday, 3 July 2019

How to compile 32 bit binary on 64 bit machine



GCC option to compile 32 bit binary on 64 bit machine:


Generate code for a 32-bit or 64-bit environment.
  • -m32 
    • sets "int", "long", and pointer types to 32 bits, and generates code that runs on any i386 system.
  • -m64
    •  sets "int" to 32 bits and "long" and pointer types to 64 bits, and generates code for the x86-64 architecture.
    • For Darwin only the -m64 option also turns off the -fno-pic and -mdynamic-no-pic options.
  • -mx32
    • sets "int", "long", and pointer types to 32 bits, and generates code for the x86-64 architecture.


Compile:

velrajk/sample$ gcc sizeof.c
velrajk/sample$ gcc -m32 sizeof.c -o 32_bit
velrajk/sample$

Output:

velrajk/sample$ ./32_bit
size of vel = 4 int= 4 float = 4double= 8 0 = 4 NULL = 4  "" = 1 int * = 4 unsigned long = 4 Unsigned int = 4
velrajk/sample$ ./a.out
size of vel = 4 int= 4 float = 4double= 8 0 = 4 NULL = 8  "" = 1 int * = 8 unsigned long = 8 Unsigned int = 4
velrajk/sample$


File lock using fcntl()

File lock:


File lock using fcntl()

NAME

       fcntl - manipulate file descriptor

SYNOPSIS

#include <unistd.h>
#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */ );

DESCRIPTION

  • fcntl() performs one of the operations described below on the open file descriptor fd.  The operation is determined by cmd.
  •  fcntl()  can  take  an optional third argument.  Whether or not this argument is required is determined by cmd.  The required argument type is indicated in parentheses after each cmd        name (in most cases, the required type is int, and we identify the argument using the name arg), or void is specified if the argument is not required.


   struct flock {
               ...
               short l_type;    /* Type of lock: F_RDLCK,
                                   F_WRLCK, F_UNLCK */
               short l_whence;  /* How to interpret l_start:
                                   SEEK_SET, SEEK_CUR, SEEK_END */
               off_t l_start;   /* Starting offset for lock */
               off_t l_len;     /* Number of bytes to lock */
               pid_t l_pid;     /* PID of process blocking our lock
                                   (F_GETLK only) */
               ...
           };

  • The l_whence, l_start, and l_len fields of this structure specify the range of bytes we wish to lock.  Bytes past the end of the file may be locked, but not bytes before the start of  the file.
  • F_SETLK (struct flock *)
    • Acquire  a lock (when l_type is F_RDLCK or F_WRLCK) or release a lock (when l_type is F_UNLCK) on the bytes specified by the l_whence, l_start, and l_len fields of lock.  
    • If a conflicting lock is held by another process, this call returns -1 and sets errno to EACCES or EAGAIN.
  • F_SETLKW (struct flock *)
    • As for F_SETLK, but if a conflicting lock is held on the file, then wait for that lock to be released.  If a signal is caught while waiting, then the call is  interrupted  and (after the signal handler has returned) returns immediately (with return value -1 and errno set to EINTR;
    • Note: currently we are using F_SETLKW
  • F_GETLK (struct flock *)
    • On  input  to this call, lock describes a lock we would like to place on the file.  If the lock could be placed, fcntl() does not actually place it, but returns F_UNLCK in the l_type field of lock and leaves the other fields of the structure unchanged. 
    • If one or more incompatible locks would prevent this lock  being  placed,  then  fcntl()  returns details about one of these locks in the l_type, l_whence, l_start, and l_len fields of lock and sets l_pid to be the PID of the process holding that lock.
Note: In order to place a read lock, fd must be open for reading.  In order to place a write lock, fd must be open for writing.  To place both types of lock, open a file read-write.

RETURN VALUE

    On Success return 0, otherwise retun -1 and errno is set appropriately.

My Understand:

  • Read lock: 
    • Read lock will be blocked if already this file is locked.
    • After unlock it won't reeceive value, but next call it will get
  • Write lock:
    • Write lock will be blocked if already this file is locked with write lock on another process.  
    • After unlock, it exeepcted to overwrite the old value, but reality it won't overwrite the value the output file file contain both value, need to handle this if 2 differect process take the write lock.  

Program:

 
/* File lock using fcntl()
 * Check : http://velrajcoding.blogspot.in
 */
#include <stdio.h>
#include <unistd.h>  // For fcntl
#include <fcntl.h>   // For  struct flock, F_WRLCK & F_SETLKW
#include <errno.h>   // For errno


enum {
    FILE_LOCK,
    FILE_UNLOCK,
};


int file_lock_and_ulock(int fd, const char *path, int is_lock, char ch)
{
    char         str[128] = {0};
    struct flock lock;

    lock.l_type = (is_lock == FILE_LOCK) ? ((ch == 'r') ? F_RDLCK : F_WRLCK) : F_UNLCK;
    lock.l_start = 0;
    lock.l_whence = SEEK_SET;
    lock.l_len = 0;
    lock.l_pid = getpid();

    /*
     * Read lock: read lock will be blocked if already this file is locked.
     *            After unlock it won't reeceive value, but next call it will get
     * Write lock: Write lock will be blocked if already this file is locked with write lock on another process.
     *             After unlock, it exeepcted to overwrite the old value, but reality it won't overwrite the value
     *             the output file file contain both value, need to handle this if 2 differect process take the write lock
     */
    if (fcntl(fd, F_SETLKW, &lock) < 0) {
        strerror_r(errno, str, sizeof(str));
        printf("Error to lock the file errno:%d err des:%s \n", errno, str);
        return 0;
    }
    printf("File %s  is %s \n", path, (is_lock == FILE_LOCK) ? "Locked" : "Unlocked");

    return 1;

}

int file_read()
{
    FILE *fp = NULL;
    int  ret = 0, value = 0;
    unsigned long value_l = 0;
    char str[128] = {0};
    char str_2[128] = {0};


    fp = fopen("test.txt", "r");
    if (!fp) {
        printf("File open is failed errno:%d  ENOENT:<%d>\n", errno, ENOENT);
        return 1;
    }
    ret = file_lock_and_ulock(fileno(fp), "test.txt", FILE_LOCK, 'r');
    if (ret == 0) {
        printf("Error in locking \n");
        return 1;
    }

    fgets(str, sizeof(str), fp);
    fseek(fp, 0, SEEK_SET);
    fscanf(fp, "%s %d", str, &value);
    file_lock_and_ulock(fileno(fp), "test.txt", FILE_UNLOCK, 'r');
    printf("File content on filst line:<%s> & fscan read:%d \n", str, value);

    fseek(fp, 0, SEEK_SET);
    if (fgets(str, sizeof(str), fp) == NULL) {
        printf("Error in retrienve \n");
    }
    memset(str_2, 0, sizeof(str));
    value_l = 0;
    if ((ret = sscanf(str, "%s %lu", str_2, &value_l)) != 2) {
        printf("Error in sscanf: %d  \n", ret);
    }
    printf("File content using fgets & sscanf line:<%s> & fscan read:%d  ret:%d \n", str, value_l, ret);
    return 0;

}

int main()
{
    FILE *fp = NULL;
    int  ret = 0, choose = 0;

    printf("Option for file operation:   \n\t\t 1. Read \n\t\t 2.Write \n Choose your option: ");
    scanf("%d", &choose);

    switch (choose) {
        case 1:
            file_read();
            break;
        case 2:
            fp = fopen("test.txt", "w");
            ret = file_lock_and_ulock(fileno(fp), "test.txt", FILE_LOCK, 'w');
#if defined (AVOID_OVERRIGHT)
            fflush(fp);
            fsync(fileno(fp));
#endif

            if (ret == 0) {
                printf("Error in locking \n");
                return 1;
            }

            //sleep(5);
            fprintf(fp, "file_w_lock_b.c 2nd\n");
            fflush(fp);
            fsync(fileno(fp));
            file_lock_and_ulock(fileno(fp), "test.txt", FILE_UNLOCK, 'w');

            fclose(fp);
            break;
       default:
            printf("Wrong option \n");
    }

    return 0;
}


 

Program 2:

 
/* File lock using fcntl()
 * Check : http://velrajcoding.blogspot.in
 */

#include <stdio.h>
#include <unistd.h>  // For fcntl
#include <fcntl.h>   // For  struct flock, F_WRLCK & F_SETLKW
#include <errno.h>   // For errno

enum {
    FILE_LOCK,
    FILE_UNLOCK,
};


int file_lock_and_ulock(int fd, const char *path, int is_lock)
{
    char         str[128] = {0};
    struct flock lock;

    lock.l_type = (is_lock == FILE_LOCK) ? F_WRLCK : F_UNLCK;
    lock.l_start = 0;
    lock.l_whence = SEEK_SET;
    lock.l_len = 0;
    lock.l_pid = getpid();

    if (fcntl(fd, F_SETLKW, &lock) < 0) {
        strerror_r(errno, str, sizeof(str));
        printf("Error to lock the file errno:%d err des:%s \n", errno, str);
        return 0;
    }
    printf("File %s  is %s \n", path, (is_lock == FILE_LOCK) ? "Locked" : "Unlocked");

    return 1;

}

int file_check_back_slan_n()
{
    FILE     *fp = NULL;
    int      temp = 0;
    char     str[128] = {0};

    if (!(fp = fopen("test_2.txt", "w+"))) {
        printf("Error in open a file \n");
        return 1;
    }

    fprintf(fp, "velraj \n serte %d", 100);
    fflush(fp);
    fsync(fileno(fp));

    fseek(fp, 0, SEEK_SET);
    fscanf(fp, "%d", &temp);

    fseek(fp, 0, SEEK_SET);
    fgets(str, sizeof(str), fp);
    printf("Vel fscanf int:<%d> fgets:<%s> \n", temp, str);
    fclose(fp);

    return 0;
}

int main()
{
    FILE    *fp;
    char         str[128] = {0};

    /*
     *  w      Truncate file to zero length or create text file for writing.  The stream is positioned at the beginning of the file.
     *  w+     Open for reading and writing.  The file is created if it does not exist, otherwise it is truncated.  The stream is positioned at the beginning of the file.
     */
    if ((fp = fopen("test.txt", "w"))) {
        file_lock_and_ulock(fileno(fp), "test.txt", FILE_LOCK);
    } else {
        strerror_r(errno, str, sizeof(str));
        printf("Error to open a file errno:%d err des:%s \n", errno, str);
        return 1;
    }

    fprintf(fp, "file_w_lock.c: 1 This is testing for fprintf...\n");
//    fputs("This is testing for fputs...\n", fp);

#if defined (FLUSH_SYNC_AFTER_SLEEP)
    printf("Going to sleep and flush flush & sync after sleep");
    sleep(10);
#endif
    fflush(fp);
    fsync(fileno(fp));
#if !defined (FLUSH_SYNC_AFTER_SLEEP)
    printf("flush & sync donw now gonig to sleep ");
    /* After flush & sync the file */
    sleep(10);
#endif
    file_lock_and_ulock(fileno(fp), "test.txt", FILE_UNLOCK);
    fclose(fp);

    return 0;
    if ((fp = fopen("test.txt", "w"))) {
        file_lock_and_ulock(fileno(fp), "test.txt", FILE_LOCK);
    } else {
        strerror_r(errno, str, sizeof(str));
        printf("Error to open a file errno:%d err des:%s \n", errno, str);
        return 1;
    }



    fflush(fp);
    fsync(fileno(fp));
    file_lock_and_ulock(fileno(fp), "test.txt", FILE_UNLOCK);
    fclose(fp);

    file_check_back_slan_n();

    return 0;
} 

Output: 

   Lock & lock from first terminal 1st terminal:
           abuser@labuser-virtual-machine:~/velrajk/sample$ ./a.out
           File test.txt  is Locked
           File test.txt  is Unlocked
           labuser@labuser-virtual-machine:~/velrajk/sample$
           labuser@labuser-virtual-machine:~/velrajk/sample$



   Not using lock on second file 2nd terminal:
           abuser@labuser-virtual-machine:~/velrajk/sample$
           labuser@labuser-virtual-machine:~/velrajk/sample$
           labuser@labuser-virtual-machine:~/velrajk/sample$ cat test.txt
           from_2
           labuser@labuser-virtual-machine:~/velrajk/sample$ === now antoher progr is still inlocking  ======
           ===: command not found
           labuser@labuser-virtual-machine:~/velrajk/sample$
           labuser@labuser-virtual-machine:~/velrajk/sample$
           labuser@labuser-virtual-machine:~/velrajk/sample$ ==== that is over unlcoked here not used lock ====
           ====: command not found
           labuser@labuser-virtual-machine:~/velrajk/sample$ cat test.txt
           This is testing for fprintf...
           This is testing for fputs...
           labuser@labuser-virtual-machine:~/velrajk/sample$

  issue:
  ------
   Lock on process 1 process 2 is got hanged due to process 1 lock, after process 1 release, process 2 write on first still process 1 data also present.


   labuser@labuser-virtual-machine:~/velrajk/sample$ cat test.txt
   from_2
   testing for fprintf...
   This is testing for fputs...
   labuser@labuser-virtual-machine:~/velrajk/sample$