IPC Shared Memory
Amongst all the three IPC Resources, the most useful IPC
resource is the shared memory segment. Shared memory allows two
or more processes to access some common data structures by
placing them in a shared memory segment. Each process that wants
to access the data structures included in a shared memory segment
must add to its address space a new memory region, which maps the
page frames associated with the shared memory segment. Each such
frame can thus be easily handled by the Kernel through demand
paging. The shmget()
function is
invoked to get the IPC Identifier of a shared memory segment,
optionally creating it if it does not already exist. Then, shmat()
function is invoked to
"attach" a shared memory segment to a process, it then
receives as its parameter the identifier of the IPC shared memory
resource and tries to add a shared memory region to the address
space of the calling process. The calling process can require a
specific starting linear address for the memory region, but the
address is usually unimportant, and each process accessing the
shared memory segment can use a different address in its own
address space. The function shmat()
however, leaves the process's page tables unchanged. Another
function, shmdt()
is invoked to
"detach" a shared memory segment specified by its IPC
Identifier, that is, to remove the corresponding memory region
from the process's adddress space. All readers should note the
following very important points:
- Detaching a shared memory segment using
shmdt()
function DOES NOT delete
the shared memory segment! It just makes it unavailable
for the current process. When I started learning all this, I made this "mistakes" : I assumed using the shmdt()
function deletes the shared memory segment. So, I want to
warn all readers at this point. No, it does NOT ever
"delete" the shared memory segment. Invoking shmdt()
"detach"-es a
shared memory segment. That's it.
- By itself, shared memory does NOT provide any sort of
synchronization facilities. In other words, there are no
automatic facilities to prevent a second process starting
to read the shared memory before the first process has
finished writing to it. It's the sole responsibility of
the programmer to synchronize access to a shared memory
segment.
An IPC shared memory segment descriptor, used primarily
identifying shared memory segments, is a shmid_kernel
data structure. So, let's see what this shmid_kernel
data structure has in store for us. The shmid_kernel
data structure may be represented as:
Type |
Field |
Description |
struct ipc_perm |
u.shm_perm |
ipc_perm data structure |
int |
u.shm_segsz |
Size of shared memory region (in
bytes) |
long |
u.shm_atime |
Last attach time |
long |
u.shm_dtime |
Last detach time |
long |
u.shm_ctime |
Last change time |
unsigned short |
u.shm_cpid |
PID of creator |
unsigned short |
u.shm_lpid |
PID of last accessing process |
unsigned short |
u.shm_nattch |
Number of current attaches |
unsigned long |
shm_npages |
Size of shared memory region
(pages) |
unsigned long * |
shm_pages |
Pointer to array of page frame
PTEs |
struct vm_area_struct * |
attaches |
Pointer to VMA descriptor list |
Those fields which are accessible to User Mode processes are
included within a shmid_ds
data
structure named u
inside the
descriptor. Their contents are accessed using the shmctl()
function. The u.shm_segsz
and shm_npages
fields store the size
of the shared memory segment in bytes and in pages, respectively.
Although User Mode processes can require a shared memory segment
of any length, the length of the allocated segment is a multiple
of the page size, since the Kernel must map the shared memory
segment with a memory region. The shm_pages
field points to an array that contains one element for each page
of the segment. The attached field points to the first element of
a doubly linked list that includes the vm_area_struct
descriptors of all memory regions associated with the shared
memory segment. When mapping IPC shared memory segments, some
fields of vm_area_struct
descriptors
have a special meaning. Let's now look at a code snippet
illustrating shared memory segments in action.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, int size, int
shmflg);
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
IPC_STAT
IPC_SET
IPC_RMID
struct shmid_ds;
For creating a shared memory segment, we use the shmget
system call.
It takes a key, a size, and a flag paramater and returns an
integer id for our segment. The flag can be combinations of
IPC_CREAT and IPC_EXCL, as well as the permissions bits on the
segment as described above. Once the segment is created and we
have its id, we must attach it, or map it into memory. This is
done with shmat
.
shmat
works
much the same as (in
BSD) in that we can specify an address to map to, but the address
must be a multiple of SHMLBA, unless we specify SHM_RND in the
flags paramater. Various operations can be performed using shmctl
. IPC_STAT
can be used to fill in the struct shmid_ds
structure. We can then set various fields (including changing
ownership and premissions of ipc_perm) using IPC_SET
.
When all of our programs are done using a segment, we MUST shmctl
it with IPC_RMID
(the
shmid_ds structure may be NULL), or else the segment will remain
in memory forever. This is how a shared memory segments operates.
Thus, this brings us to the end of this section, which in turn
brings us to the end of this article too.
Thus, in this article we have seen what we mean by terms like
IPC, IPC Resources, System V IPC, and different IPC mechanisms
and resources; and more importantly how Unix Systems (more
specifically GNU/Linux systems) implement them in reality. As the
famous English poet, John Keats once mentioned: "A thing of
beauty is joy forever". He was right. Linux, which forms the
core of the GNU (GNU's Not Unix) operating system (which
unfortunately everyone nowadays refers to as simply the
"Linux OS"), is definitely a thing of beauty. And for
enjoying this beauty, one needs to be passionate about 'Open
Source Technologies' and especially towards Linux. Linux is far
more advanced than it's many commercial competitors in so many
ways. Just to name one, it is possible to fit both the Linux
Kernel image and full root filesystem, including all fundamental
system programs, on just one 1.44 MB floppy disk! No commercial
Unix variants, to date, as far as I know, are able to boot from
a single floppy boot diskette. In my next article, I will deal
with Linux Memory Management, in other words, how and in what
ways, does Linux implement Memory and other related features. So,
get a Linux distribution today, learn some C coding; and if you
are lucky and passionate, and like doing everything in
life with all your heart and soul,
becoming a Linux expert is just a matter of time... Take care
all...
About the Author: My name is Subhasish
Ghosh. I'm 20 years old, currently a computer-systems engineering
student in India; a Microsoft Certified Professional (MCP), MCSD,
MCP certified on NT 4.0, recently completed Red Hat Linux
Certified Engineer (RHCE) Training & cleared Brainbench.com
"Linux General Administration" certification exam. Have
been installing, configuring and developing on Linux patform for
a long time now, have had programmed using C, C++, VC++, VB, COM,
DCOM, MFC, ATL 3.0, PERL, Python, POSIX Threads and Linux Kernel
programming; currently holding a total of 8 International
Industry Certifications. For a list of all my articles at
Linux.com (and other sites), click here.
Latest News: My new friend from St.
Petersburg, Russia, Annette (I call her Ann!), unfortunately
refers to "Linux" as "Lunix"; my room
resembles an O'Reilly & Wrox warehouse, my mom has warned me,
either to clean my room by next week, or get out of the house
along with my Compaq PC, Linux CDs and books! Looks like I need a
new place real soon! E-mail: subhasish_ghosh@linuxmail.org