Showing posts with label Advance C. Show all posts
Showing posts with label Advance C. Show all posts

Friday, 28 August 2020

Shared Libraries with GCC on linux

 

  •  Create an .so file and run that file, link the .so from the same path to the executable.

Program:

Program file 1 Header file  (foo.h):

/* Shared Libraries with GCC on linux
 * Check : http://velrajcoding.blogspot.in
 */
#ifndef foo_h__
#define foo_h__

extern void foo(void);

#endif  // foo_h__

Program file 2 foo.c:
 
/* Shared Libraries with GCC on linux
 * Check : http://velrajcoding.blogspot.in
 */

#include <stdio.h>


void foo(void)
{
        printf("Hello, I am a shared library");
}

Program file 3 Main file (main.h):
/* Shared Libraries with GCC on linux
 * Check : http://velrajcoding.blogspot.in
 */
#include <stdio.h>
#include "foo.h"

int main(void)
{
    puts("This is a shared library test...");
    foo();
    return 0;
}

Compile & execute:

Step 1: Compiling with Position Independent Code

[so_crete]$ ls
foo.c foo.h main.c
[so_crete]$
[so_crete]$ gcc -c -Wall -Werror -fpic foo.c
[so_crete]$ ls
foo.c foo.h foo.o main.c
[so_crete]$

Step 2: Creating a shared library from an object file

[so_crete]$ gcc -shared -o libfoo.so foo.o
[so_crete]$ ls
foo.c foo.h foo.o libfoo.so main.c
[so_crete]$

Step 3: Linking with a shared library

[so_crete]$ gcc -Wall -o test main.c -lfoo
/bin/ld: cannot find -lfoo
collect2: error: ld returned 1 exit status
[so_crete]$

Tell GCC where to find the shared library
[so_crete]$ pwd
/users/vkutrala/vel/sample/so_crete
[so_crete]$ gcc -L /users/vkutrala/vel/sample/so_crete -Wall -o test main.c -lfoo
[so_crete]$ ls
foo.c foo.h foo.o libfoo.so main.c test
[so_crete]$

Step 4: Making the library available at runtime

[so_crete]$ ./test
./test: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory
[so_crete]$

Using LD_LIBRARY_PATH

[so_crete]$ echo $LD_LIBRARY_PATH

[so_crete]$ LD_LIBRARY_PATH=/users/vkutrala/vel/sample/so_crete:$LD_LIBRARY_PATH
[so_crete]$ ./test
./test: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory
[so_crete]$
[so_crete]$
[so_crete]$
What happened? Our directory is in LD_LIBRARY_PATH, but we did not export it. In Linux, if you do not export the changes to an environment variable, they will not be inherited by the child processes
[so_crete]$ export LD_LIBRARY_PATH=/users/vkutrala/vel/sample/so_crete:$LD_LIBRARY_PATH
[so_crete]$ ./test
This is a shared library test...
Hello, I am a shared library
[so_crete]$

Reference:
     https://www.cprogramming.com/tutorial/shared-libraries-linux-gcc.html

 

Read About Dynamic loading lib(run time load or patch update)

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


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^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@


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, 3 July 2019

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$

Sunday, 24 February 2019

Difference between uint32_t vs unsigned int

Difference between uint32_t vs unsigned int



  • uint32_t is defined in stdint.h header file, so we have to include this header file if we want to use uint32_t
  • It is guaranteed to be a 32-bit unsigned integer
  • unsigned int
    •  Like int, unsigned int typically is an integer that is fast to manipulate for the current architecture
    • so it's to be used when a "normal", fast integer is required.
    •  For example, on a 16 bit-processor unsigned int will typically be 16 bits wide, while uint32_t will have to be 32 bits wide.


Program:

/* Difference between uint32_t vs unsigned int by Velraj.K
 * Check : http://velrajcoding.blogspot.in
 */


#include <stdio.h>
#include <stdint.h>  /* For uint32_t */

int main()
{

        /* It is guaranteed to be a 32-bit unsigned integer */
        uint32_t int32_val = 0;
        /* Like int, unsigned int typically is an integer that is fast to manipulate for the current architecture.
         * so it's to be used when a "normal", fast integer is required.
         * For example, on a 16 bit-processor unsigned int will typically be 16 bits wide, while uint32_t
         * will have to be 32 bits wide.
         */
        unsigned int uint_val = 0;

        printf("Vel value int32_val:size <%u:%zu> uint_val:size <%u:%zu> \n", int32_val, sizeof(int32_val), uint_val, sizeof(uint_val));

        return 0;
}



Output:

velraj@velraj-H310M-H:~/velraj/cLang$ ./a.out
Vel value int32_val:size <0:4> uint_val:size <0:4>

Thursday, 17 January 2019

Analysis select timeout, read fd not disturb timeout if tv.sec is not disturbed

SYNOPSIS

       /* According to POSIX.1-2001 */
       #include <sys/select.h>
       /* According to earlier standards */
       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>
       int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);
       void FD_CLR(int fd, fd_set *set);
       int  FD_ISSET(int fd, fd_set *set);
       void FD_SET(int fd, fd_set *set);
       void FD_ZERO(fd_set *set);

Timeout working flow:

  • The select last argument is timeout it receive a struct timeval with second & microsect.
  • The select return is based on below value:
    •  return 0 if timeout happen
    •  return number of FD read if one or multiple FD is ready
    •  return -1 if an error is occured and errno is set.
  • If select is waiting for both read fd & timeout and read fd is ready then select will update the remaining time to the timeout variable.
  • So that next time user should pass the same timeout variable without modify, it will continue the time when it stoped instead of starting fresh.
  • Hence select timeout will be continue paralley, ready FD won't affect the tiemout.

Example:

  • Select is waiting for read fd & timeout for 300 second.
  • 100th second read fd is ready then select return 1 as 1 fd  is ready and remaining second 200 is updated in the timeout variable.
  • After process the read fd call the select timeout without modifiy the remaining timeout.
  • Now select continue the remaining timeout 200 second.
  • 200th second select will be timeout and return 0.
  • Hence Timeout = 300 + time taken by read fd (if few millisecond then its ok).

Note: 

  • The select update the remaining time in the timeout value and start the time after process the FD.
  • The time taken by read FD process is not calculate in  the select timeout, suppose if we use alarm then alarm will run simultaneously and should not face this issue.
  • Suppose read FD is taking more then 1 second and more time then select timeout for 300 second won't be timeout exacatly
  • EG: Timeout = 300 + time taken by read fd (if fd is receiving continuously then problem in timeout).

Server program:

/* Analysis select timeout by Velraj.K
 * Check : http://velrajcoding.blogspot.in
 */
#include "stdio.h"
#include "unistd.h"
#include "signal.h"
#include "sys/socket.h"
#include "sys/select.h"
#include "sys/un.h"
#include "string.h"
#include "fcntl.h"
#include <time.h>   /* For localtime */
#define SELECT_TIMEOUT 300
#define TIMESTAMP_BUF_LEN   25
#define TIMESTAMP_FORMAT    "%a %b %d %H:%M:%S %Y"
int get_time_string(char *str_time, unsigned int length, char *time_format)
{
    time_t    time_sec = 0;
    struct tm *time_local = NULL;
    size_t    bytes = 0;
    if ((str_time == NULL) || (time_format == NULL)) {
        printf("Error: The joined time or time format is NULL");
        return 1;
    }
    /* Get value of time in seconds */
    time_sec = time(NULL);
    if (time_sec == -1) {
        printf("Error: Failed to get time in seconds");
        return 2;
    }
    /* Convert a time value to a broken-down local time */
    time_local = localtime(&time_sec);
    if (time_local == NULL) {
        printf("Error: Failed to convert the time value into a broken-down local time");
        return 3;
    }
    /* Format date and time */
    bytes = strftime(str_time, length, time_format, time_local);
    if (bytes == 0) {
        printf("Error: Error in format the data and time");
        return 4;
    }

    return 0;
}
int main() {
    int sock, ret;
    struct sockaddr_un servaddr;
    char buf [20];
    fd_set read_fd_set;
    int fromlen;
    long socketFlags = 0;
    struct timeval timeout;
    char   str_cur_time[TIMESTAMP_BUF_LEN] = {'\0'};
    timeout.tv_sec = SELECT_TIMEOUT;
    timeout.tv_usec = 0;
    // Create Unix domain socket to communicate with client
    if ((sock = socket (AF_UNIX, SOCK_DGRAM, 0)) < 0) {
        perror ("socket failed to open");
        return 1;
    }
    /* Forcefully rebind if already bind and still active.
     * Suppose if already bind and kill the process using ctrl + c, then
     * bind value won't be released by the process. Rebuind will throw error
     * To avoid this error forcefully remove.
     */
    unlink("serversock");
    // Bind socket
    servaddr.sun_family = AF_UNIX;
    strcpy(servaddr.sun_path, "serversock");
    if (bind (sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
        perror ("socket failed to bind");
        close (sock);
        return 1;
    }
    socketFlags |= O_NONBLOCK;
    if(fcntl(sock, F_SETFL, socketFlags) <0){
        perror ("fcntl failed");
        return 1;
    }
    while (1) {
        FD_ZERO(&read_fd_set);
        FD_SET(sock, &read_fd_set);
        get_time_string(str_cur_time, TIMESTAMP_BUF_LEN, TIMESTAMP_FORMAT);
        printf("\nGoing to select. Will timeout in %d seconds time = %s\r\n", SELECT_TIMEOUT, str_cur_time);
        ret = select (sock + 1, &read_fd_set, NULL, NULL, &timeout);
        printf("Found something\r\n");
        if (ret < 0) { // Error
            perror ("select failed");
            return 1;
        } else if (ret == 0){ // Timeout
            get_time_string(str_cur_time, TIMESTAMP_BUF_LEN, TIMESTAMP_FORMAT);
            printf("Timed out !! current time = %s \r\n", str_cur_time);
            timeout.tv_sec = SELECT_TIMEOUT;
            timeout.tv_usec = 0;
        } else { // Message on FD
           get_time_string(str_cur_time, TIMESTAMP_BUF_LEN, TIMESTAMP_FORMAT);
            printf("FD is read to read so the timeout is tv_sec = %ld tv_usec = %ld time = %s \n", timeout.tv_sec, timeout.tv_usec, str_cur_time);
            if (FD_ISSET(sock, &read_fd_set)){
                printf("FD is set\r\n");
                fromlen = sizeof(servaddr);
                ret = recvfrom(sock, &buf, 20, 0, (struct sockaddr*)&servaddr, (socklen_t*)&fromlen);
                printf("'%s' recieved in buffer of size %d\r\n", buf, ret);
            }
        }
    }
    return 0;
}


Client Program:

/* Analysis select timeout for client by Velraj.K
 * Check : http://velrajcoding.blogspot.in
 */
#include "stdio.h"
#include "unistd.h"
#include "signal.h"
#include "sys/socket.h"
#include "sys/select.h"
#include "sys/un.h"
#include "string.h"
int sock;
struct sockaddr_un servaddr;
char buf [20] = "Hello Server";
void sighandler() {
    int len = -1;
    // Doing all this in a sighandler as a test is maybe alright....
    printf("\nSending 'Hello Server' to server from pid %d..\r\n", getpid());
    len = sendto(sock, &buf, 20, 0, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_un));
    if (len < 0) {
        printf("Error. len = %d\r\n", len);
    }
}

int main() {
    struct sigaction new_action, old_action;
    int len = -1;
    // Setting the signal handler
    // Will send a message to server on SIGUSR1
    new_action.sa_handler = sighandler;
    sigemptyset(&new_action.sa_mask);
    new_action.sa_flags = 0;
    sigaction(SIGUSR1, NULL, &old_action);
    if (old_action.sa_handler != SIG_IGN)
        sigaction(SIGUSR1, &new_action, NULL);
    // Create Unix domain socket to communicate with server
    if ((sock = socket (AF_UNIX, SOCK_DGRAM, 0)) < 0) {
        perror ("socket failed to open");
        return 1;
    }
    // Setting server address
    servaddr.sun_family = AF_UNIX;
    strcpy(servaddr.sun_path, "serversock");
    while (1) {
        // Do nothing. Just wait for the SIGUSR1 to send a message to server
//    len = sendto(sock, &buf, 20, 0, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_un));
    sleep(1);
    }
    return 0;
}


Output:

Server:
labuser@labuser-virtual-machine:~/velrajk/sample/select$ ./ser
Going to select. Will timeout in 300 seconds time = Thu Jan 17 18:50:18 2019
Found something
FD is read to read so the timeout is tv_sec = 196 tv_usec = 207733 time = Thu Jan 17 18:52:02 2019
FD is set
'Hello Server' recieved in buffer of size 20
Going to select. Will timeout in 300 seconds time = Thu Jan 17 18:52:02 2019
Found something
FD is read to read so the timeout is tv_sec = 120 tv_usec = 832029 time = Thu Jan 17 18:53:17 2019
FD is set
'Hello Server' recieved in buffer of size 20
Going to select. Will timeout in 300 seconds time = Thu Jan 17 18:53:17 2019



Found something
Timed out !! current time = Thu Jan 17 18:55:18 2019
Going to select. Will timeout in 300 seconds time = Thu Jan 17 18:55:18 2019


Client:

labuser@labuser-virtual-machine:~/velrajk/sample/select$ ./a.out
Sending 'Hello Server' to server from pid 11052..
Sending 'Hello Server' to server from pid 11052..

Send signal to client from other console:
ps -aux | grep a.out
kill -s SIGUSR1 <Pid>




Sunday, 11 November 2018

static use on other file compile together throws error

Static file:


  • Even if we give 2 .c file into the gcc, it will compile upto Assembler as a single .c file.
  • The below output shows that Preprocessor gave .i for 2 files.
    • Compiler gave the .s for 2 files.
    • Assembler gave the .o for 2 fileHence linker only combine these 2 .o files into a single executable file.
    • Hence we could not use the static variable in other .c file because each .c file compile separately upto .o
    • NO_STAT flag is used to remove the extern on 2nd file and make an global variable,
      • so that 2 variable are different variable even with the same name.
  • ------------ snip ---------------
  •  -r-- 1 manirathinam manirathinam   197 Nov 11 03:28 static_1.c
    -rw-rw-r-- 1 manirathinam manirathinam   171 Nov 11 03:30 static_2.c
    -rw-rw-r-- 1 manirathinam manirathinam 18382 Nov 11 03:30 static_1.i
    -rw-rw-r-- 1 manirathinam manirathinam  1174 Nov 11 03:30 static_1.s
    -rw-rw-r-- 1 manirathinam manirathinam  1392 Nov 11 03:30 static_1.o
    -rw-rw-r-- 1 manirathinam manirathinam 18398 Nov 11 03:30 static_2.i
    -rw-rw-r-- 1 manirathinam manirathinam   853 Nov 11 03:30 static_2.s
    -rw-rw-r-- 1 manirathinam manirathinam  1244 Nov 11 03:30 static_2.o
    -rwxrwxr-x 1 manirathinam manirathinam  7312 Nov 11 03:30 a.out
    manirathinam@manirathinam-Aspire-E1-431:~/velraj/clan$
  •  
  • ---------------- snip --------------


Program:

File 1: static_1.c


/* static on 2 file compile together by Velraj.K
   Check : http://velrajcoding.blogspot.in
 */

#include <stdio.h>

static int stat_value = 0;
// we can inclide the .c file it can able to compile successfuly.
//#include "static_2.c"



int main()
{
        printf("Inside main \n");

        return 0;
}


/* Compile :
 * Gcc working for 2 .c file:
 *     Even if we give 2 .c file into the gcc, it will compile upto Assembler as a single .c file.
 *     The below output shows that Preprocessor gave .i for 2 files.
 *                                 Compiler gave the .s for 2 files.
 *                                 Assembler gave the .o for 2 files
 *                                 Hence linker only combine these 2 .o files into a single executable file.
 *                   Hence we could not use the static variable in other .c file because each .c file compile separately upto .o
 *                   NO_STAT flag is used to remove the extern on 2nd file and make an global variable,
 *                       so that 2 variable are different variable even with the same name.
 *
 manirathinam@manirathinam-Aspire-E1-431:~/velraj/clan$ ls -ltr
total 16
-rw-rw-r-- 1 manirathinam manirathinam  197 Nov 11 03:28 static_1.c
-rw-rw-r-- 1 manirathinam manirathinam  171 Nov 11 03:30 static_2.c
-rwxrwxr-x 1 manirathinam manirathinam 7312 Nov 11 03:30 a.out
manirathinam@manirathinam-Aspire-E1-431:~/velraj/clan$ gcc static_1.c static_2.c --save-temp
manirathinam@manirathinam-Aspire-E1-431:~/velraj/clan$  ls -ltr
total 72
-rw-rw-r-- 1 manirathinam manirathinam   197 Nov 11 03:28 static_1.c
-rw-rw-r-- 1 manirathinam manirathinam   171 Nov 11 03:30 static_2.c
-rw-rw-r-- 1 manirathinam manirathinam 18382 Nov 11 03:30 static_1.i
-rw-rw-r-- 1 manirathinam manirathinam  1174 Nov 11 03:30 static_1.s
-rw-rw-r-- 1 manirathinam manirathinam  1392 Nov 11 03:30 static_1.o
-rw-rw-r-- 1 manirathinam manirathinam 18398 Nov 11 03:30 static_2.i
-rw-rw-r-- 1 manirathinam manirathinam   853 Nov 11 03:30 static_2.s
-rw-rw-r-- 1 manirathinam manirathinam  1244 Nov 11 03:30 static_2.o
-rwxrwxr-x 1 manirathinam manirathinam  7312 Nov 11 03:30 a.out
manirathinam@manirathinam-Aspire-E1-431:~/velraj/clan$
manirathinam@manirathinam-Aspire-E1-431:~/velraj/clan$ gcc static_1.c static_2.c --save-temp -DNO_STAT
static_2.o: In function `add':
static_2.c:(.text+0x19): undefined reference to `stat_value'
collect2: error: ld returned 1 exit status
manirathinam@manirathinam-Aspire-E1-431:~/velraj/clan$
*/


File 2: static_2.c


/* static on 2 file compile together by Velraj.K
   Check : http://velrajcoding.blogspot.in
 */

#include <stdio.h>


#ifdef NO_STAT
extern int stat_value;
#else
int stat_value;
#endif


int add()
{
        int value = 100;
        value = stat_value + value;

        return value;
}

Friday, 9 November 2018

pthread mutux deadlock for cancel handling




Program:

// C program to demonstrates cancellation of self thread
// using thread id
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>  // For memset
static pthread_mutex_t cfglock = PTHREAD_MUTEX_INITIALIZER;
int is_thread_cancel = 0, is_cleanup_push = 0;
void line_80(char ch)
{
    char str[81] = {'\0'};
    memset(str, ch, sizeof(str));
    str[80] = '\0';
    printf("%s\n", str);
    return;
}
void *calls(void* ptr)
{
    int oldtype = 0;
    printf("\nThread: Entrying into the thread %s \n", __func__);
    line_80('-');

    /* If 2 argument try then do the clean up */
    /* Add setcanceltype & cleanup into the if loop throws below error:
           error: expected ‘while’ before ‘printf’
       Reason is pthread_cleanup_push is not a function, it is a macro it cotain the below.
       So it add the d0 { on start and pthread_cleanup_pop macro contain ending while, so we could not put inside the if condition
             if (is_cleanup_push) {
     pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);
     do { __pthread_unwind_buf_t __cancel_buf; void (*__cancel_routine) (void *) = (pthread_mutex_unlock); void *__cancel_arg = ((void *) &cfglock); int __not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *) __cancel_buf.__cancel_jmp_buf, 0); if (__builtin_expect ((__not_first_call), 0)) { __cancel_routine (__cancel_arg); __pthread_unwind_next (&__cancel_buf); } __pthread_register_cancel (&__cancel_buf); do {;
        }
        pthread_cleanup_pop macro definition is:
        do { } while (0); } while (0); __pthread_unregister_cancel (&__cancel_buf); if (0) __cancel_routine (__cancel_arg); } while (0);
         pthread_setcanceltype(oldtype, ((void *)0));

      */
 //  if (is_cleanup_push) {
        pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);
        pthread_cleanup_push(pthread_mutex_unlock, (void *) &cfglock);
  //  }
    printf("Thread: Going to accquire the lock\n");
    pthread_mutex_lock(&cfglock);
    printf("Thread: Lock is accquired \n");
    printf("Thread: Going to sleep 10 second \n");
    sleep(7);
    printf("Thread: After the sleep of 10 second\n");
    /* If 2 argument try then do the clean up */
  //  if (is_cleanup_push) {
        pthread_mutex_unlock(&cfglock);
        pthread_cleanup_pop(0);
        pthread_setcanceltype(oldtype, NULL);
    //}
    printf("\nThread: Returning from thread %s \n", __func__);
    line_80('-');
    return NULL;
}

int main(int argc, char *argv[])
{
    // NULL when no attribute
    pthread_t thread = 0;
    int ret = 0;
    void *thread_ret = NULL;
    // calls is a function name
    pthread_create(&thread, NULL, calls, NULL);
    /* Argument and his valuel
          Arg 1. if 0 then no cancel, if 1 then it will call pthread_cancel.
                     Scenario: if 0 then, no cancel, thread in lock, process also try to lock, Dead lock
                     scenario 2: if 1 then , cancel kill the thread but lock is not cleaned, so proacess try to lock, hence Dead lock.
          Arg  2. if 0 then no cleanup_push for lock,
                  if 1 then do cleanup_push for lock

      */
    printf("Process: going to sleep for 3  \n");
    sleep(3);
    printf("\t\tProcess: After sleep of 3 second  \n");
    is_thread_cancel = atoi(argv[1]);
    is_cleanup_push = atoi(argv[2]);
    if (is_thread_cancel == 1) {
        /* cancelled threads do not unlock mutexes they hold */
        printf("Process: called the pthread_cancel \n");
        ret = pthread_cancel(thread);
        if (ret == 0) {
            printf("Process: Canceled the thread with ID <%ld> \n", thread);
        } else {
            printf("Process: Error in cancel while try to cancel the thread <%ld>, ret = %d \n",
                    thread, ret);
        }
    }
  //  printf("After cancel \n");

    /* Already taken the lock in thread, so this lock will be blocked */
    printf("Process: Going to acquire the Mutux  \n");
    pthread_mutex_lock(&cfglock);
    printf("\t\tProcess: Lock is acquired \n");
    pthread_mutex_unlock(&cfglock);
    printf("\t\tProcess: Mutux lock is released \n");
    printf("Process: going to sleep for 15  \n");
    sleep(10);
    printf("\t\tProcess: After sleep of 15 second  \n");
    /* The pthread_join() function waits for the thread specified by thread to terminate.
     * If that thread has already terminated, then pthread_join() returns immediately.
     * If the target thread was canceled, then PTHREAD_CANCELED is placed in *retval.
     * As per out PTHREAD_CANCELED value is 0xfffff
       */
    // Waiting for when thread is completed
//    ret = pthread_join(thread, NULL);  // Just  wati
    ret = pthread_join(thread, &thread_ret);  // Just  wati
    if (ret !=0) {
        printf("Process: Error in pthread_join errno = %d \n", ret);
    }
    printf("Process: The return value from thread is = %p \n", thread_ret);
    if (thread_ret == PTHREAD_CANCELED) {
        printf("Process: The thread is already canceled, value of PTHREAD_CANCELED  <%p>\n", PTHREAD_CANCELED);
    }
    return 0;
}

/* Ref:
        For Dedlock release lock, Solution:
                https://stackoverflow.com/questions/14268080/cancelling-a-thread-that-has-a-mutex-locked-does-not-unlock-the-mutex
       Solution method 2: For pthread_mutexattr_setrobust to releace lock:
               http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_setrobust.html
               https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization
        Solution Method 1:
               https://sector7.xray.aps.anl.gov/~dohnarms/programming/glibc/html/Cleanup-Handlers.html
               https://linux.die.net/man/3/pthread_cleanup_push
*/

Tuesday, 2 October 2018

Stack function argumen & local variable declaration order in stack

Program:


/*  Stack function argumen & local variable declaration order in stackprogram by Velraj.K
    Check : http://velrajcoding.blogspot.in
  */
#include <stdio.h>
#include <stdlib.h>

int global = 0;

int stack_no_argument()
{
        return 6;
}

void stack_no_arg_declar_call(int arg)
{
        int a;
        int b;

        printf("\n\t\t%s &argc = %p &a = %p &b = %p \n\t\t", __func__, &arg, &a, &b);
}

oid stack_no_arg_declar(int arg)
{
        int a[100];
        int b[200];
        int c[300];
        char chr[100];   /* Seems stack also it is taking extra bye, use only int is continue.
                          * but mixing char inbetween get extra bye on first a int and then this variable */
        int d[100];
        void *ptr = NULL;
        int *ptr_int;

        ptr = malloc(100);
        ptr_int = b;

        *(ptr_int + 200) = 1;
        printf("\n\t\t &a[0] = %p &a[99] = %p \n\t\t &b[0] = %p &b[199] = %p\n\t\t &c[0] = %p &c[299] = %p\n\t\t",
                        &a[0], &a[99], &b[0], &b[199], &c[0], &c[299]);

        printf("\n\t\t chr[0] = %p, &chr[99] = %p\n\t\t &d[0] = %p &d[99] = %p\n\t\t global = %p\n\t\t malloc= %p\n\t\t",
                        &chr[0], &chr[99], &d[0], &d[99],
                        &global, ptr);
        printf("\n\t\t &ptr = %p \n\t\t &ptr_int = %p \n\t\t",
                        &ptr, &ptr_int);
        printf("\n\t\t argc = %p \n\t\t a[0] = %d c[0] = %d \n\n",
                        &arg, a[0], c[0]);
       stack_no_arg_declar_call(100);
}

int stack_argument_seque(int a, int b, char ch, float *flo)
{
        b = a + ch;
        printf("Inside the function \n");
        return 10;
}



int main()
{
        float value = 0.0;
        int ret = 0;
/*
        ---- snip -----
        fstps   -20(%ebp)
        movl    $0, -16(%ebp)
        leal    -20(%ebp), %eax
        pushl   %eax
        pushl   $99   
        pushl   $2
        pushl   $1
        call    stack_argument_seque
        ---- snip -----
        Argument pushed into stack from right to left.
        Note: ASCII value of 'c' is 99.
*/

int stack_argument_seque(int a, int b, char ch, float *flo)
{
        b = a + ch;
        printf("Inside the function \n");
        return 10;
}



int main()
{
        float value = 0.0;
        int ret = 0;
/*
        ---- snip -----
        fstps   -20(%ebp)
        movl    $0, -16(%ebp)
        leal    -20(%ebp), %eax
        pushl   %eax
        pushl   $99   
        pushl   $2
        pushl   $1
        call    stack_argument_seque
        ---- snip -----
        Argument pushed into stack from right to left.
        Note: ASCII value of 'c' is 99.
*/

int stack_argument_seque(int a, int b, char ch, float *flo)
{
        b = a + ch;
        printf("Inside the function \n");
        return 10;
}



int main()
{
        float value = 0.0;
        int ret = 0;
/*
        ---- snip -----
        fstps   -20(%ebp)
        movl    $0, -16(%ebp)
        leal    -20(%ebp), %eax
        pushl   %eax
        pushl   $99   
        pushl   $2
        pushl   $1
        call    stack_argument_seque
        ---- snip -----
        Argument pushed into stack from right to left.
        Note: ASCII value of 'c' is 99.
*/


        ret = stack_argument_seque(1, 2, 'c', &value);
        stack_no_argument();
        stack_no_arg_declar(10);
}


Output:
   ------
   velraj@velraj-HEC41:~/CProgram$ ./a.out
Inside the function

                 &a[0] = 0xbfdd319c &a[99] = 0xbfdd3328
                 &b[0] = 0xbfdd332c &b[199] = 0xbfdd3648
                 &c[0] = 0xbfdd364c
                global = 0x804a02c
                  malloc= 0x942c410
                a[0] = 0 c[0] = 0


After add the char inbetween:
--------------------------
velraj@velraj-HEC41:~/CProgram$ ./a.out
Inside the function
Output:
   ------
   velraj@velraj-HEC41:~/CProgram$ ./a.out
Inside the function

                 &a[0] = 0xbfdd319c &a[99] = 0xbfdd3328
                 &b[0] = 0xbfdd332c &b[199] = 0xbfdd3648
                 &c[0] = 0xbfdd364c
                global = 0x804a02c
                  malloc= 0x942c410
                a[0] = 0 c[0] = 0


After add the char inbetween:
--------------------------
velraj@velraj-HEC41:~/CProgram$ ./a.out
Inside the function


                 &a[0] = 0xbfed0ac8 &a[99] = 0xbfed0c54
                 &b[0] = 0xbfed0de8 &b[199] = 0xbfed1104
                 &c[0] = 0xbfed1108 &c[299] = 0xbfed15b4
                 chr[0] = 0xbfed15b8, &chr[99] = 0xbfed161b
                 &d[0] = 0xbfed0c58 &d[99] = 0xbfed0de4
                 global = 0x804a02c
                 malloc= 0x855b410
                 a[0] = 0 c[0] = 1

        Here we are wring b+200 but it write on c[0], hece a first b second and 3rd is c, since stack botton start on top, hence address wise c a is long from stack.

        Output current:
        --------------
velraj@velraj-HEC41:~/CProgram$ ./a.out
Inside the function


                 &a[0] = 0xbf85fa58 &a[99] = 0xbf85fbe4
                 &b[0] = 0xbf85fd78 &b[199] = 0xbf860094
                 &c[0] = 0xbf860098 &c[299] = 0xbf860544
               
                 chr[0] = 0xbf860548, &chr[99] = 0xbf8605ab
                 &d[0] = 0xbf85fbe8 &d[99] = 0xbf85fd74
                 global = 0x804a02c
                 malloc= 0x80e9410
               
                 &ptr = 0xbf85fa50
                 &ptr_int = 0xbf85fa54
               
                 argc = 0xbf8605c0
                 a[0] = 0 c[0] = 1


                stack_no_arg_declar_call &argc = 0xbf85fa40 &a = 0xbf85fa24 &b = 0xbf85fa28


Diagram to understand: