Wednesday, September 10, 2014

How to use shared memory for process intercommunication on Linux?

On Linux intercommunication with using shared memory API is more elegant than on Windows.

Shared memory server


Example sequence of calls for shared memory server is:
  1. Call ftok function and receive key for shared memory segment.
  2. Call shmget with IPC_CREAT to create new shared memory segment.
  3. Call shmat to attach to shared memory array. Do some operations with shared memory.
  4. Call shmdt to detach from shared memory array.
  5. Call shmctl with IPC_RMID to remove shared memory segment.
Here is an example of shared memory server which writes Hello World message to shared memory and waits for pressing of any key:

#include <stdio.h>

#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <cstring>
#include <fcntl.h>

int main(int argc, char ** argv)
{
        key_t key = ftok(argv[0], 1);
        if (key < 0)
        {
                perror("ftok"); /*Displays the error message*/
                return -1;
        }

        printf("Key for shared memory: '%s'\n", argv[0]);

        int shmid = shmget(key, 4096,  IPC_CREAT | O_EXCL | S_IRUSR | S_IWUSR);
        if(shmid == -1)
        {
                fprintf(stderr, "Failed to create memory segment. %s\n", 
                        strerror(errno));
                return -1;
        }

        void * pAddr = shmat(shmid, NULL, 0);
        if((long long )pAddr == -1)
        {
                if(shmctl(shmid, IPC_RMID, NULL) == -1)
                {
                        fprintf(stderr, "Failed to remove shared memory segment. %s\n", 
                                strerror(errno));
                        return -1;
                }

                fprintf(stderr, "Failed to attach to shared memory. %s\n", 
                        strerror(errno));
                return -1;
        }

        const char * szcServerMessage = "Hello world!";
        strcpy((char *) pAddr, szcServerMessage);

        printf("Server put message to shared memory.\n");
        printf("Press any key for exit ...\n");
        getchar();

        if(shmdt(pAddr) == -1)
        {
                fprintf(stderr, "Failed to detach from shared memory segment. %s\n", 
                        strerror(errno));
                return -1;
        }

        if(shmctl(shmid, IPC_RMID, NULL) == -1)
        {
                fprintf(stderr, "Failed to remove shared memory segment. %s\n", 
                        strerror(errno));
                return -1;
        }

        return 0;
}

Shared memory client

Example sequence of calls for shared memory client is:
  1. Call ftok function and receive key for shared memory segment.
  2. Call shmget to obtain pointer to existing shared memory segment descriptor.
    Don't set IPC_CREAT flag, besides instead memory size you can simply pass 0.
  3. Call shmat to attach to shared memory array. Do some operations with shared memory.
  4. Call shmdt to detach from shared memory array.
Please notice that on client side you shouldn't call shmctl with IPC_RMID, because shared segment was created on server side, but not on client.

Here is implementation of shared memory client that attaches to the shared memory segment and then reads message:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <cstring>
#include <fcntl.h>

int main(int argc, char ** argv)
{
        key_t key = ftok("./server", 1);
        if (key < 0)
        {
                perror("ftok"); /*Displays the error message*/
                return -1;
        }

        int shmid = shmget(key, 0,  S_IRUSR | S_IWUSR);
        if(shmid == -1)
        {
                fprintf(stderr, "Failed to create memory segment. %s\n", 
                        strerror(errno));
                return -1;
        }

        void * pAddr = shmat(shmid, NULL, 0);
        if((long long )pAddr == -1)
        {
                fprintf(stderr, "Failed to attach to shared memory. %s\n", 
                        strerror(errno));
                return -1;
        }

        char szcBufferMessage[4096];
        strcpy(szcBufferMessage, (char *) pAddr);

        printf("Client read message from shared memory: %s \n", szcBufferMessage);
        printf("Press any key for exit ...\n");
        getchar();

        if(shmdt(pAddr) == -1)
        {
                fprintf(stderr, "Failed to detach from shared memory segment. %s\n", 
                        strerror(errno));
                return -1;
        }

        /* In client we shouldn't delete any segment, because it is allocated by server */

        return 0;
}

Server's output example:

$ ./server
Key for shared memory: './server'
Server put message to shared memory.
Press any key for exit ...

Client's output example:

$ ./client
Client read message from shared memory: Hello world! 
Press any key for exit ...

As you can see client successfully reads the message from server.
Hope this post is useful. Good luck!

Friday, September 5, 2014

How to use shared memory for process intercommunication on Windows?

Introduction
Shared memory is the fastest way for process intercommunication. In the other hand it is the most danger. One mistake in code will crash your program at once.

Shared memory server
Here is an example of shared memory server that allocates shared memory and writes there a message.
#include <windows.h>
#include <conio.h>
#include <stdio.h>

const unsigned int c_uiSharedMemorySegmentSize = 512;

const char * szcSharedMemorySegmentName = "Global\\HelloMessage";

int main()
{
 printf("Shared memory server has been started successfully.\n");

 HANDLE hMapFile = CreateFileMapping(
    INVALID_HANDLE_VALUE,   // use paging file
    NULL,       // default security
    PAGE_READWRITE,     // read/write access
    0,        // maximum object size (high-order DWORD)
    c_uiSharedMemorySegmentSize, // maximum object size (low-order DWORD)
    szcSharedMemorySegmentName); // name of mapping object

 if (hMapFile == NULL)
 {
  fprintf(stderr, "Could not create file mapping object (%d).\n", GetLastError());
  return 1;
 }

 char * pcBuf = (char *) MapViewOfFile(hMapFile,   // handle to map object
  FILE_MAP_ALL_ACCESS, // read/write permission
  0,
  0,
  c_uiSharedMemorySegmentSize);

 if (pcBuf == NULL)
 {
  fprintf(stderr, "Could not map view of file (%d).\n", GetLastError());
  CloseHandle(hMapFile);
  return 2;
 }

 // Set memory for child process
 const char * szcMessageHelloWorld = "Hello world!";
 strcpy(pcBuf, szcMessageHelloWorld);

 printf("Message has been written to shared memory segment.\n");
 printf("You can start the client to read it.\n");
 printf("Press any key to remove shared memory segment and exit ...\n");

 getch();

 UnmapViewOfFile(pcBuf);

 CloseHandle(hMapFile);

 return 0;
}

Shared memory client
Here is an example of shared memory client that attaches to the shared memory and reads the message from the server.
#include <windows.h>
#include <stdio.h>
#include <conio.h>

const unsigned int c_uiSharedMemorySegmentSize = 512;
const char *  szcSharedMemorySegmentName = "Global\\HelloMessage";

int main()
{
 printf("Shared memory client has been started.\n");
 printf("Press any key to read the message from shared memory.\n");
 getch();

 HANDLE hMapFile = OpenFileMapping(
     FILE_MAP_ALL_ACCESS,   // read/write access
     FALSE,       // do not inherit the name
     szcSharedMemorySegmentName); // name of mapping object

 if (hMapFile == NULL)
 {
  fprintf(stderr, "Could not open file mapping object (%d).\n", GetLastError());
  return 1;
 }

 const char * pcBuf = static_cast<char *> (MapViewOfFile(hMapFile, // handle to map object
  FILE_MAP_ALL_ACCESS,           // read/write permission
  0,
  0,
  c_uiSharedMemorySegmentSize));

 if (pcBuf == NULL)
 {
  fprintf(stderr, "Could not map view of file (%d).\n", GetLastError());
  CloseHandle(hMapFile);
  return 2;
 }

 printf("Message from shared memory server: '%s'\n", pcBuf);
 printf("Press any key to exit ...");
 getch();

 UnmapViewOfFile(pcBuf);
 CloseHandle(hMapFile);

 return 0;
}
After you successfully built both examples you can start server at first:

Then start shared memory client and press any key:

As you can see client successfully reads the message from server.

Hope this post is useful. Good luck!


Thursday, September 4, 2014

How to do performance profiling of server process on Linux?

Suppose you have a server process on Linux and you want to investigate its performance.
To do performance profiling you need to run your server with using valgrind:

valgrind --tool=callgrind --dump-instr=yes --simulate-cache=yes --collect-jumps=yes ./path_to_server arg1 arg2

After you started the server you needed to wait some time while your server processed data.
As soon as data has been processed you may stop server.
As the result valgrind should generate file(s) with names like that: callgrind.out.58575.

Now the biggest part of job has been done already.
Next step is to open generated callgrind.out.* file(s) by using kcachegrind.

If you are interested in performance profiling child processes I'll bring you good news.
You can achieve it just by adding --trace-children=yes argument to valgring command line:

valgrind --tool=callgrind --dump-instr=yes --simulate-cache=yes --collect-jumps=yes --trace-children=yes ./path_to_server arg1 arg2

Hope this post is helpful. Good luck!

How connect to oracle database without using entry in tnsnames.ora?

Lets suppose you want to connect to database service with next description:

HOLE =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = 192.108.1.1)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = hole.service)
    )
  )

Instead of adding it to tnsnames.ora you may write it instead of database name in your application :



If you don't want to write a long description you can use another format:
<host>:<port>/<service_name>

For example:
192.108.1.1:1521/hole.service

It will work as well as first case. Both examples represent the subset of valid oracle connection strings.

Moreover, you can use these connection strings in Oracle API methods instead of TNS names.
For example, one of these methods is OCISessionPoolCreate.

Good luck!