Saturday, November 15, 2014

Unix Prog: IPC Shared Memory(1)

1. Shared Memory Overview
Shared memory allows two or more processes to share a given region of memory. This is fastest form of IPC, because the data doesn't need to be copied between the client and the server.

But accessing to a given shared region among multiple processes need synchronization. Often, semaphores are used to synchronize shared memory access.

The kernel maintains a structure with at least the following members for each shared memory segment:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/bits/shm.h  
 ......  
 /* Data structure describing a shared memory segment. */  
 struct shmid_ds  
  {  
   struct ipc_perm shm_perm;      /* operation permission struct */  
   size_t shm_segsz;          /* size of segment in bytes */  
   __time_t shm_atime;         /* time of last shmat() */  
 #ifndef __x86_64__  
   unsigned long int __glibc_reserved1;  
 #endif  
   __time_t shm_dtime;         /* time of last shmdt() */  
 #ifndef __x86_64__  
   unsigned long int __glibc_reserved2;  
 #endif  
   __time_t shm_ctime;         /* time of last change by shmctl() */  
 #ifndef __x86_64__  
   unsigned long int __glibc_reserved3;  
 #endif  
   __pid_t shm_cpid;          /* pid of creator */  
   __pid_t shm_lpid;          /* pid of last shmop */  
   shmatt_t shm_nattch;        /* number of current attaches */  
   __syscall_ulong_t __glibc_reserved4;  
   __syscall_ulong_t __glibc_reserved5;  
  };  
 ......  

2. System Calls:
1) shmget
shmget is used to create a new shared memory or obtain an existing shared memory.
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/sys/shm.h  
 ......  
 /* Get shared memory segment. */  
 extern int shmget (key_t __key, size_t __size, int __shmflg) __THROW;  
 ......  

When a new segment is created, the following members of the shmid_ds structure are initialized:
ipc_perm structure is initialized. shm_lpid, shm_nattach, shm_atime, and shm_dtime are all set to 0. shm_ctime is set to the current time. shm_segsz is set to the size requested.

The size parameter is the size of the shared memory segment in bytes. Implementation will usually round up the size to a multiple of the system's page size.But if size is not the multiple of page size, the remainder of the last page will be unavailable. If creating the new shared memory segment, we must specify the size. If we are referencing the existing segment, we can specify the size to 0.

2) shmctl
shmctl is the catchall for various shared memory operations.
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/sys/shm.h  
 ......  
 /* Shared memory control operation. */  
 extern int shmctl (int __shmid, int __cmd, struct shmid_ds *__buf) __THROW;  
 ......  

Unix supports following commands:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/bits/ipc.h  
 ......  
 /* Control commands for `msgctl', `semctl', and `shmctl'. */  
 #define IPC_RMID    0        /* Remove identifier. */  
 #define IPC_SET     1        /* Set `ipc_perm' options. */  
 #define IPC_STAT    2        /* Get `ipc_perm' options. */  
 ......  
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/bits/shm.h  
 ......  
 /* Commands for `shmctl'. */  
 #define SHM_LOCK    11       /* lock segment (root only) */  
 #define SHM_UNLOCK   12       /* unlock segment (root only) */  
 ......  

IPC_STAT: Fetch the shmid_ds structure for this segment, storing it in the structure pointed to by buf.
IPC_SET: Set the following three fields from the structure pointed to by buf in the shmid_ds structure associated with this shared memory segment: shm_perm.uid, shm_perm.gid, and shm_perm.mode. It can only be executed by a process whose effective user ID equals shm_perm.cuid or shm_perm.uid or by a process with superuser privileges.
IPC_RMID: Remove the shared memory segment set from the system. The segment is not removed until the last process using the segment terminates or detaches it. It can only be executed by a process whose effective user ID equals shm_perm.cuid or shm_perm.uid or by a process with superuser privileges.
SHM_LOCK: Lock the shared memory segment in memory. only can be executed by super user.
SHM_UNLOCK: Unlock the shared memory segment. only can be executed by super user

3) shmat:
shmat is used to help process attach the shared memory segment to its own address space.

 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/sys/shm.h  
 ......  
 /* Attach shared memory segment. */  
 extern void *shmat (int __shmid, const void *__shmaddr, int __shmflg)  
    __THROW;  
 ......  

a) If addr is 0, the segment is attached at the first available address selected by the kernel. This is the recommended technique.
b) If addr is nonzero and SHM_RND is not specified, the segment is attached at the address given by addr.
c) If addr is nonzero and SHM_RND is specified, the segment is attached at the address given by (addr - (addr % SHMLBA)). It round the address down to the next multiple of SHMLBA.

 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/bits/shm.h  
 ......  
 /* Flags for `shmat'. */  
 #define SHM_RDONLY   010000     /* attach read-only else read-write */  
 #define SHM_RND     020000     /* round attach address to SHMLBA */  
 #define SHM_REMAP    040000     /* take-over region on attach */  
 #define SHM_EXEC    0100000     /* execution access */  
 ......  
 /* Segment low boundary address multiple. */  
 #define SHMLBA     (__getpagesize ())  
 extern int __getpagesize (void) __THROW __attribute__ ((__const__));  
 ......  

d) if SHM_RDONLY bit is set, the segment is attached read-only, otherwise, the segment is attached read-write.
e) shmat return the address at which the segment is attached, or -1 if an error occured. If shmat succeeds, the kernel will increment the shm_nattach counter in the shmid_ds structure associated with the shared memory segment.

4) shmdt:
shmdt is used to detach the memory segment from the local address.
Note: this doesn't remove the shared memory segment from the system. It still exists until some process specifically removes it by calling shmctl with a command of IPC_RMID.
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/sys/shm.h  
 ......  
 /usr/include/x86_64-linux-gnu/sys/shm.h:extern int shmdt (const void *__shmaddr) __THROW;  
 ......  

The addr argument is the value that was returned by a previous call to shmat. If successful, shmdt will decrement the shm_nattch counter in the associated shmid_ds structure.

No comments:

Post a Comment