summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjcej <jcej@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1999-01-06 19:30:06 +0000
committerjcej <jcej@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1999-01-06 19:30:06 +0000
commit3d62c941ce203469633f5bbbcfc666c07754f09f (patch)
tree5a81122e423b584f5fde883795606c0c1936dd41
parent100360c6c2079c5971aa6a14b282980659083414 (diff)
downloadATCD-3d62c941ce203469633f5bbbcfc666c07754f09f.tar.gz
*** empty log message ***
-rw-r--r--ChangeLog-98b9
-rw-r--r--docs/tutorials/021/client.cpp64
-rw-r--r--docs/tutorials/021/combine.shar228
-rw-r--r--docs/tutorials/021/mpool.cpp31
-rw-r--r--docs/tutorials/021/mpool.h28
-rw-r--r--docs/tutorials/021/page01.html28
-rw-r--r--docs/tutorials/021/page02.html172
-rw-r--r--docs/tutorials/021/page03.html132
-rw-r--r--docs/tutorials/021/page04.html88
-rw-r--r--docs/tutorials/021/page05.html91
-rw-r--r--docs/tutorials/021/page06.html32
-rw-r--r--docs/tutorials/021/server.cpp83
-rw-r--r--docs/tutorials/online-tutorials.html2
13 files changed, 936 insertions, 52 deletions
diff --git a/ChangeLog-98b b/ChangeLog-98b
index 9733d2f9131..714490c5317 100644
--- a/ChangeLog-98b
+++ b/ChangeLog-98b
@@ -1,3 +1,12 @@
+Wed Jan 6 14:27:24 EST 1999 James CE Johnson <jcej@lads.com
+
+ * docs/tutorials/021/*:
+ Completed the ACE_Malloc<> tutorial. It could be a lot better
+ than it is but I'm still new to ACE_Malloc...
+
+ * docs/tutorials/021/online-tutorials.html:
+ Added the link for #21
+
Tue Jan 05 22:55:07 1999 Irfan Pyarali <irfan@cs.wustl.edu>
* ace/Strategies_T.cpp (cleanup_hint_i and check_hint_i): Since we
diff --git a/docs/tutorials/021/client.cpp b/docs/tutorials/021/client.cpp
index 10d8cd99859..d5d80b58a91 100644
--- a/docs/tutorials/021/client.cpp
+++ b/docs/tutorials/021/client.cpp
@@ -5,42 +5,84 @@
int main (int, char *[])
{
+ /*
+ Use the same pool name used by the server when we create our
+ Allocator. This assures us that we don't create a whole new
+ pool.
+ */
Allocator allocator(Constants::PoolName);
-
+
+ /*
+ You can put anything in the memory pool. Not just the
+ character array we want. The find() method till, therefore,
+ return a void* that we will have to cast.
+ */
void * region;
-
+
+ /*
+ We use find() to locate a named region in the pool. This is
+ the counterpart to bind() used in the server.
+ Here, we go try to find the region that the server has created
+ and filled with data. If there was a problem getting the pool
+ or finding the region, we'll get back -1 from find().
+ */
if( allocator.pool().find(Constants::RegionName,region) == -1 )
{
ACE_ERROR_RETURN ((LM_ERROR, "Cannot find the name '%s'\n",
Constants::RegionName), 100 );
}
-
+
+ /*
+ Since find() returns us a void*, we cast it here to the char*
+ that we want.
+ */
char *shm = (char *)region;
ACE_DEBUG ((LM_INFO, "Shared memory is at 0x%x\n", shm ));
+ /*
+ The same pair of semaphores as used by the server are created
+ here. We probably don't need the CREATE flag since the server
+ should have already done that. There may be some very small
+ windows, however, where the server would have created the
+ memory pool but not yet gotten to the semaphores.
+ */
ACE_SV_Semaphore_Complex mutex;
- // This semaphore is initially created with a count of 0, i.e., it
- // is "locked."
ACE_ASSERT (mutex.open (Constants::SEM_KEY_1,
ACE_SV_Semaphore_Complex::ACE_CREATE, 0) != -1);
ACE_SV_Semaphore_Complex synch;
- // This semaphore is initially created with a count of 0, i.e., it
- // is "locked."
ACE_ASSERT (synch.open (Constants::SEM_KEY_2,
ACE_SV_Semaphore_Complex::ACE_CREATE, 0) != -1);
+ /*
+ It doesn't matter if we created 'mutex' or if the server did.
+ In either case, it was created in a locked state and we will
+ block here until somebody unlocks it. In our scenario, that
+ will have to be the server.
+ */
if (mutex.acquire () == -1)
{
ACE_ERROR_RETURN ((LM_ERROR, "(%P) client mutex.acquire"), 1);
}
-
+
+ /*
+ Now that we know it is safe to access the data, we'll run
+ through and make sure that it contains what we think the server
+ supplied.
+ */
for (int i = 0; i < Constants::SHMSZ; i++)
{
ACE_ASSERT (Constants::SHMDATA[i] == shm[i]);
}
-
+
+ /*
+ Look back at the server. After filling the region, it will
+ attempt to acquire the lock on 'synch'. It will wait there
+ until we release() the semaphore. That will allow it to remove
+ the pool and cleanup. We can simply exit once we perform the
+ release. (Ok, a free() of the region would probably be polite...)
+ */
if (synch.release () == -1)
{
ACE_ERROR_RETURN ((LM_ERROR, "(%P) client synch.release"), 1);
@@ -49,6 +91,10 @@ int main (int, char *[])
return 0;
}
+/*
+ Again, we have the necessary explicit template instantiations
+ because I based this on an ACE example instead of creating it from scratch.
+ */
#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
template class ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_SV_Semaphore_Simple>;
template class ACE_Guard<ACE_SV_Semaphore_Simple>;
diff --git a/docs/tutorials/021/combine.shar b/docs/tutorials/021/combine.shar
index 78ee347ba71..5b92de500be 100644
--- a/docs/tutorials/021/combine.shar
+++ b/docs/tutorials/021/combine.shar
@@ -3,17 +3,22 @@
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
-# Made on 1999-01-02 23:53 EST by <root@chiroptera.tragus.org>.
-# Source directory was `/var/home/jcej/projects/ACE_wrappers/docs/tutorials/021'.
+# Made on 1999-01-06 14:26 EST by <jcej@caldera.lads.com>.
+# Source directory was `/scsiA/home/jcej/projects/ACE_wrappers/docs/tutorials/021'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
-# 426 -rw-rw-r-- hdr
-# 69 -rw-rw-r-- bodies
-# 509 -rw-rw-r-- page01.pre
+# 409 -rw-rw-r-- hdr
+# 47 -rw-rw-r-- bodies
+# 562 -rw-rw-r-- page01.pre
+# 281 -rw-rw-r-- page02.pre
+# 201 -rw-rw-r-- page03.pre
+# 287 -rw-rw-r-- page04.pre
+# 287 -rw-rw-r-- page05.pre
+# 604 -rw-rw-r-- page06.pre
#
save_IFS="${IFS}"
IFS="${IFS}:"
@@ -60,7 +65,7 @@ else
fi
rm -f 1231235999 $$.touch
#
-if mkdir _sh26726; then
+if mkdir _sh07125; then
$echo 'x -' 'creating lock directory'
else
$echo 'failed to create lock directory'
@@ -76,30 +81,30 @@ else
<HEAD>
X <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
X <META NAME="Author" CONTENT="James CE Johnson">
-X <TITLE>ACE Tutorial 020</TITLE>
+X <TITLE>ACE Tutorial 021</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
X
-<CENTER><B><FONT SIZE=+2>ACE Tutorial 020</FONT></B></CENTER>
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 021</FONT></B></CENTER>
X
-<CENTER><B><FONT SIZE=+2>Sharing your Memories with persistence</FONT></B></CENTER>
+<CENTER><B><FONT SIZE=+2>Pooling your memories</FONT></B></CENTER>
X
<P>
<HR WIDTH="100%">
SHAR_EOF
- $shar_touch -am 1228173698 'hdr' &&
+ $shar_touch -am 0103180599 'hdr' &&
chmod 0664 'hdr' ||
$echo 'restore of' 'hdr' 'failed'
if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
&& ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|| $echo 'hdr:' 'MD5 check failed'
-edd6dc67f13434391cf73b7604485b80 hdr
+9ffa6eb1308f4872f390b30f74a6de3b hdr
SHAR_EOF
else
shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'hdr'`"
- test 426 -eq "$shar_count" ||
- $echo 'hdr:' 'original size' '426,' 'current size' "$shar_count!"
+ test 409 -eq "$shar_count" ||
+ $echo 'hdr:' 'original size' '409,' 'current size' "$shar_count!"
fi
fi
# ============= bodies ==============
@@ -111,22 +116,22 @@ else
PAGE=2
server.cpp
client.cpp
-server2.cpp client2.cpp
-mmap.h mmap.cpp
+mpool.h
+mpool.cpp
SHAR_EOF
- $shar_touch -am 1228174898 'bodies' &&
+ $shar_touch -am 0106135399 'bodies' &&
chmod 0664 'bodies' ||
$echo 'restore of' 'bodies' 'failed'
if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
&& ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|| $echo 'bodies:' 'MD5 check failed'
-a5d087bf1c11cf431c082ba146f3c6aa bodies
+470abefc6e5e401ad9ffdfa76e3ca143 bodies
SHAR_EOF
else
shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'bodies'`"
- test 69 -eq "$shar_count" ||
- $echo 'bodies:' 'original size' '69,' 'current size' "$shar_count!"
+ test 47 -eq "$shar_count" ||
+ $echo 'bodies:' 'original size' '47,' 'current size' "$shar_count!"
fi
fi
# ============= page01.pre ==============
@@ -135,31 +140,190 @@ if test -f 'page01.pre' && test "$first_param" != -c; then
else
$echo 'x -' extracting 'page01.pre' '(text)'
sed 's/^X//' << 'SHAR_EOF' > 'page01.pre' &&
-X This tutorial mirrors the previous. Instead of using shared memory,
-X this time we'll be using a memory-mapped file.
+X The previous two tutorials were very primitive & basic. They
+X showed very simple uses of shared memory and memory mapped
+X files.
X <p>
-X The cool thing about doing it this way is that we gain
-X persistence of memory even across reboots. I wonder if you
-X could memory map a file that's mounted via NFS?
+X If we move the level of abstraction up just a bit, the next
+X thing we encounter is memory pools. ACE_Malloc&lt;&gt; provides
+X this to us.
X <p>
-X Like the shared memory tutorial, this one is also very basic and
-X primitive. I'm assuming you've read that one, so I'll just hit
-X the high points this time through..
+X In this tutorial, we'll use ACE_Malloc&lt;&gt; to create a
+X memory pool that is sharable between a client and server. We'll
+X use a memory mapped file to provide the physical storage but
+X shared memory works just as well.
SHAR_EOF
- $shar_touch -am 1228173898 'page01.pre' &&
+ $shar_touch -am 0103180499 'page01.pre' &&
chmod 0664 'page01.pre' ||
$echo 'restore of' 'page01.pre' 'failed'
if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
&& ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|| $echo 'page01.pre:' 'MD5 check failed'
-333a5e5f8be0a5b8dc66424a50e5b4bd page01.pre
+83956a1b05e5f8823afbdb8a84d8ac11 page01.pre
SHAR_EOF
else
shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page01.pre'`"
- test 509 -eq "$shar_count" ||
- $echo 'page01.pre:' 'original size' '509,' 'current size' "$shar_count!"
+ test 562 -eq "$shar_count" ||
+ $echo 'page01.pre:' 'original size' '562,' 'current size' "$shar_count!"
fi
fi
-rm -fr _sh26726
+# ============= page02.pre ==============
+if test -f 'page02.pre' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page02.pre' '(file already exists)'
+else
+ $echo 'x -' extracting 'page02.pre' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page02.pre' &&
+X The key components for creating the memory pool are:
+X <ul>
+X <li>Create and name the pool
+X <li>Allocate a chunk (region) of memory from the pool
+X <li>Name the allocated region
+X </ul>
+X The rest of it is just critical sections and data manipulation.
+<hr>
+SHAR_EOF
+ $shar_touch -am 0103180899 'page02.pre' &&
+ chmod 0664 'page02.pre' ||
+ $echo 'restore of' 'page02.pre' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page02.pre:' 'MD5 check failed'
+1bde237d2082c2f88f4802965e0b393d page02.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page02.pre'`"
+ test 281 -eq "$shar_count" ||
+ $echo 'page02.pre:' 'original size' '281,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page03.pre ==============
+if test -f 'page03.pre' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page03.pre' '(file already exists)'
+else
+ $echo 'x -' extracting 'page03.pre' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page03.pre' &&
+X The client side is a little simpler than the server. Mainly
+X because we don't try to delete the pool:
+X <ul>
+X <li>Create an Allocator to access the pool
+X <li>Find the named region
+X </ul>
+<hr>
+SHAR_EOF
+ $shar_touch -am 0106135499 'page03.pre' &&
+ chmod 0664 'page03.pre' ||
+ $echo 'restore of' 'page03.pre' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page03.pre:' 'MD5 check failed'
+bd3bbfe6dbece827f8259d394d89ff58 page03.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page03.pre'`"
+ test 201 -eq "$shar_count" ||
+ $echo 'page03.pre:' 'original size' '201,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page04.pre ==============
+if test -f 'page04.pre' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page04.pre' '(file already exists)'
+else
+ $echo 'x -' extracting 'page04.pre' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page04.pre' &&
+X Everything common the server & client is kept here. In
+X particular, the Constants class where we keep the names &
+X semaphore keys.
+X <p>
+X The Allocator class is just a thin wrapper around
+X ACE_Malloc&lt;&gt; that moves some of the details out of the
+X application logic.
+<hr>
+SHAR_EOF
+ $shar_touch -am 0106135699 'page04.pre' &&
+ chmod 0664 'page04.pre' ||
+ $echo 'restore of' 'page04.pre' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page04.pre:' 'MD5 check failed'
+a95d570fb8b7aca15802d9abdba84b81 page04.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pre'`"
+ test 287 -eq "$shar_count" ||
+ $echo 'page04.pre:' 'original size' '287,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page05.pre ==============
+if test -f 'page05.pre' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page05.pre' '(file already exists)'
+else
+ $echo 'x -' extracting 'page05.pre' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page05.pre' &&
+X Everything common the server & client is kept here. In
+X particular, the Constants class where we keep the names &
+X semaphore keys.
+X <p>
+X The Allocator class is just a thin wrapper around
+X ACE_Malloc&lt;&gt; that moves some of the details out of the
+X application logic.
+<hr>
+SHAR_EOF
+ $shar_touch -am 0106140399 'page05.pre' &&
+ chmod 0664 'page05.pre' ||
+ $echo 'restore of' 'page05.pre' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page05.pre:' 'MD5 check failed'
+a95d570fb8b7aca15802d9abdba84b81 page05.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page05.pre'`"
+ test 287 -eq "$shar_count" ||
+ $echo 'page05.pre:' 'original size' '287,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= page06.pre ==============
+if test -f 'page06.pre' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'page06.pre' '(file already exists)'
+else
+ $echo 'x -' extracting 'page06.pre' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'page06.pre' &&
+X As you can see, using a memory pool is really rather easy. The
+X most difficult part, as always, is with the synch mechanisms.
+X <P>
+X The other nice thing about ACE_Malloc&lt;> is that you can swap
+X between System V shared memory and memory mapped files just by
+X changing the template parameters. The truly adventurous will
+X likely find a runtime way of doing this.
+X <p>
+X
+X <ul>
+X <li><A HREF="Makefile">Makefile</A>
+X <li><A HREF="server.cpp">server.cpp</A>
+X <li><A HREF="client.cpp">client.cpp</A>
+X <li><A HREF="mpool.h">mpool.h</A>
+X <li><A HREF="mpool.cpp">mpool.cpp</A>
+X </ul>
+SHAR_EOF
+ $shar_touch -am 0106142499 'page06.pre' &&
+ chmod 0664 'page06.pre' ||
+ $echo 'restore of' 'page06.pre' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'page06.pre:' 'MD5 check failed'
+68fa5365d4add68561720a1f24bb980f page06.pre
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page06.pre'`"
+ test 604 -eq "$shar_count" ||
+ $echo 'page06.pre:' 'original size' '604,' 'current size' "$shar_count!"
+ fi
+fi
+rm -fr _sh07125
exit 0
diff --git a/docs/tutorials/021/mpool.cpp b/docs/tutorials/021/mpool.cpp
index 13d88a576b6..c65b3a6c664 100644
--- a/docs/tutorials/021/mpool.cpp
+++ b/docs/tutorials/021/mpool.cpp
@@ -3,6 +3,10 @@
#include "mpool.h"
+/*
+ Set the values of all of the constants. This guarantees that client
+ and server don't get confused.
+ */
const int Constants::SEM_KEY_1 = ACE_DEFAULT_SEM_KEY + 1;
const int Constants::SEM_KEY_2 = ACE_DEFAULT_SEM_KEY + 2;
@@ -12,6 +16,11 @@ const char * Constants::SHMDATA = "abcdefghijklmnopqrstuvwxyz";
const char * Constants::PoolName = "SharedMemoryPool";
const char * Constants::RegionName = "Alphabet";
+/*
+ We have to create a copy of the _name parameter in case the caller
+ has dynamically allocated it. The pool_ is set to NULL & will be
+ allocated by the accessor.
+ */
Allocator::Allocator( const char * _name )
: name_(ACE_OS::strdup(_name)),
pool_(0)
@@ -25,12 +34,27 @@ Allocator::Allocator( const char * _name )
Allocator::~Allocator(void)
{
- if( pool_ )
+ /*
+ strdup() uses malloc(), so we must use free() to clean up.
+ */
+ if( name_ )
{
- free(pool_);
+ free(name_);
}
+
+ // delete doesn't really care if you give it a NULL pointer.
+ delete pool_;
}
+/*
+ Allocate the pool. Since we return a reference, we'll be in really
+ bad shape if the new fails. This is a great place to throw an
+ exception!
+ The other concern is thread safety. If two threads call here at
+ about the same time, we may create the pool twice. We can't use a
+ Singleton because we want to have multiple Allocator instances. The
+ Singleton techniques can be used though.
+ */
Allocator::pool_t & Allocator::pool(void)
{
if( ! pool_ )
@@ -38,8 +62,5 @@ Allocator::pool_t & Allocator::pool(void)
pool_ = new pool_t( name_ );
}
- // Obviously, we're assuming that the new above was
- // successful.
-
return *pool_;
}
diff --git a/docs/tutorials/021/mpool.h b/docs/tutorials/021/mpool.h
index 6530afefbd8..29b64437cdb 100644
--- a/docs/tutorials/021/mpool.h
+++ b/docs/tutorials/021/mpool.h
@@ -4,34 +4,58 @@
#ifndef MPOOL_H
#define MPOOL_H
+// Everything else we need is in this one header
#include "ace/Malloc.h"
-#include "ace/Singleton.h"
+/*
+ With this we will abstract away some of the details of the memory
+ pool. Note that we don't treat this as a singleton because an
+ application may need more than one pool. Each would have a
+ different name and be used for different purposes.
+ */
class Allocator
{
public:
+ // The pool name will be used to create a unique semaphore to
+ // keep this pool separate from others.
Allocator( const char * _name = "MemoryPool" );
~Allocator(void);
typedef ACE_Malloc<ACE_MMAP_Memory_Pool, ACE_SV_Semaphore_Simple> pool_t;
+ // Provide an accessor to the pool. This will also allocate the
+ // pool when first invoked.
pool_t & pool(void);
protected:
+ // The name we gave to the pool
char * name_;
+
pool_t * pool_;
};
+/*
+ The client and server need to agree on a certain set of values. By
+ placing them in the Constants class we can eliminate a bit of confusion.
+ */
class Constants
{
public:
+ // The semaphore keys are needed for the two semaphores that
+ // synch access to the shared memory area.
static const int SEM_KEY_1;
static const int SEM_KEY_2;
-
+
+ // How big the pool will be and what we'll put into it. A real
+ // app wouldn't need SHMDATA of course.
static const int SHMSZ;
static const char * SHMDATA;
+ // The name assigned to the memory pool by the server is needed
+ // by the client. Without it, the pool cannot be found.
+ // Likewise, the name the server will bind() to the region of the
+ // pool must be available to the client.
static const char * PoolName;
static const char * RegionName;
};
diff --git a/docs/tutorials/021/page01.html b/docs/tutorials/021/page01.html
new file mode 100644
index 00000000000..262bdeac5cc
--- /dev/null
+++ b/docs/tutorials/021/page01.html
@@ -0,0 +1,28 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 021</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 021</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Pooling your memories</FONT></B></CENTER>
+
+<P>
+<HR WIDTH="100%">
+ The previous two tutorials were very primitive & basic. They
+ showed very simple uses of shared memory and memory mapped
+ files.
+ <p>
+ If we move the level of abstraction up just a bit, the next
+ thing we encounter is memory pools. ACE_Malloc&lt;&gt; provides
+ this to us.
+ <p>
+ In this tutorial, we'll use ACE_Malloc&lt;&gt; to create a
+ memory pool that is sharable between a client and server. We'll
+ use a memory mapped file to provide the physical storage but
+ shared memory works just as well.
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page02.html">Continue This Tutorial</A>]</CENTER>
diff --git a/docs/tutorials/021/page02.html b/docs/tutorials/021/page02.html
new file mode 100644
index 00000000000..0321bae2b66
--- /dev/null
+++ b/docs/tutorials/021/page02.html
@@ -0,0 +1,172 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 021</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 021</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Pooling your memories</FONT></B></CENTER>
+
+<P>
+<HR WIDTH="100%">
+ The key components for creating the memory pool are:
+ <ul>
+ <li>Create and name the pool
+ <li>Allocate a chunk (region) of memory from the pool
+ <li>Name the allocated region
+ </ul>
+ The rest of it is just critical sections and data manipulation.
+<hr><PRE>
+
+<font color=red>// $Id$</font>
+
+<font color=red>/*
+ I've hidden the details in an Allocator class declared in mpool.h
+ We'll come to that a little later.
+*/</font>
+<font color=blue>#include</font> "<font color=green>mpool.h</font>"
+
+int main (int, char *[])
+{
+ <font color=red>/*
+ Construction of an Allocator will create the memory pool and
+ provide it with a name. The Constants class is also
+ declared in mpool.h to keep server and client on the same
+ page. The name is used to generate a unique semaphore which
+ prevents simultaneous access to the pools housekeeping
+ information. (Note that you still have to provide your own
+ synch mechanisms for the data *you* put in the poo.)
+ */</font>
+ Allocator allocator(<font color=#008888>Constants::PoolName</font>);
+
+ <font color=red>/*
+ The Allocator class provides the pool() member so that you
+ have access to the actual memory pool. A more robust
+ implementation would behave more as a bridge class but this
+ is good enough for what we're doing here.
+ Once you have a reference to the pool, the malloc() method
+ can be used to get some bytes. If successful, shm will
+ point to the data. Otherwise, it will be zero.
+ */</font>
+ char *shm = (char *) allocator.pool().malloc (27);
+
+ ACE_ASSERT( shm != 0 );
+
+ <font color=red>/// FYI</font>
+ ACE_DEBUG ((LM_INFO, "<font color=green>Shared memory is at 0x%x\n</font>", shm ));
+
+ <font color=red>/*
+ Something that we can do with a memory pool is map a name to
+ a region provided by malloc. By doing this, we can
+ communicate that name to the client as a rendezvous
+ location. Again, a member of Constants is used to keep the
+ client and server coordinated.
+ */</font>
+ if( allocator.pool().bind(<font color=#008888>Constants::RegionName</font>,shm) == -1 )
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>Cannot bind the name '%s' to the pointer 0x%x\n</font>",
+ <font color=#008888>Constants::RegionName</font>,shm), 100 );
+ }
+
+ <font color=red>/*
+ One of the best ways to synch between different processes is
+ through the use of semaphores. ACE_SV_Semaphore_Complex
+ hides the gory details and lets us use them rather easily.
+
+ Here, we'll create two semaphores: mutex and synch. mutex
+ will be used to provide mutually exclusive access to the
+ shared region for writting/reading. synch will be used to
+ prevent the server from removing the memory pool before the
+ client is done with it.
+
+ Both semaphores are created in an initially locked state.
+ */</font>
+
+ ACE_SV_Semaphore_Complex mutex;
+ ACE_ASSERT (mutex.open (<font color=#008888>Constants::SEM_KEY_1</font>,
+ <font color=#008888>ACE_SV_Semaphore_Complex::ACE_CREATE</font>, 0) != -1);
+
+ ACE_SV_Semaphore_Complex synch;
+ ACE_ASSERT (synch.open (<font color=#008888>Constants::SEM_KEY_2</font>,
+ <font color=#008888>ACE_SV_Semaphore_Complex::ACE_CREATE</font>, 0) != -1);
+
+ <font color=red>/*
+ We know the mutex is locked because we created it that way.
+ Take a moment to write some data into the shared region.
+ */</font>
+ for (int i = 0; i &lt; <font color=#008888>Constants::SHMSZ</font>; i++)
+ {
+ shm[i] = <font color=#008888>Constants::SHMDATA</font>[i];
+ }
+
+ <font color=red>/*
+ The client will be blocking on an acquire() of mutex. By
+ releasing it here, the client can go look at the shared data.
+ */</font>
+ if (mutex.release () == -1)
+ {
+ ACE_ERROR ((LM_ERROR, "<font color=green>(%P) %p</font>", "<font color=green>server mutex.release</font>"));
+ }
+ <font color=red>/*
+ Even though we created the synch semaphore in a locked
+ state, if we attempt to acquire() it, we will block. Our
+ design requires that the client release() synch when it is
+ OK for us to remove the shared memory.
+ */</font>
+ else if (synch.acquire () == -1)
+ {
+ ACE_ERROR ((LM_ERROR, "<font color=green>(%P) %p</font>", "<font color=green>server synch.acquire</font>"));
+ }
+
+ <font color=red>/*
+ This will remove all of the memory pool's resources. In the
+ case where a memory mapped file is used, the physical file
+ will also be removed.
+ */</font>
+ if (allocator.pool ().remove () == -1)
+ {
+ ACE_ERROR ((LM_ERROR, "<font color=green>(%P) %p\n</font>", "<font color=green>server allocator.remove</font>"));
+ }
+
+ <font color=red>/*
+ We now have to cleanup the semaphores we created. Use the
+ ipcs command to see that they did, indeed, go away after the
+ server exits.
+ */</font>
+
+ if (mutex.remove () == -1)
+ {
+ ACE_ERROR ((LM_ERROR, "<font color=green>(%P) %p\n</font>", "<font color=green>server mutex.remove</font>"));
+ }
+
+ if (synch.remove () == -1)
+ {
+ ACE_ERROR ((LM_ERROR, "<font color=green>(%P) %p\n</font>", "<font color=green>server synch.remove</font>"));
+ }
+
+ return 0;
+
+}
+
+<font color=red>/*
+ This tutorial was created by shamelessly modifying one of the ACE
+ examples. Someone there had already created the necessary explicit
+ template instantiations & I don't want them to go to waste...
+ */</font>
+<font color=blue>#if defined</font> (<font color=purple>ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION</font>)
+template class ACE_Malloc&lt;ACE_MMAP_MEMORY_POOL, ACE_SV_Semaphore_Simple>;
+template class ACE_Guard&lt;ACE_SV_Semaphore_Simple>;
+template class ACE_Write_Guard&lt;ACE_SV_Semaphore_Simple>;
+template class ACE_Read_Guard&lt;ACE_SV_Semaphore_Simple>;
+<font color=blue>#elif defined</font> (<font color=purple>ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA</font>)
+<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Malloc&lt;ACE_MMAP_MEMORY_POOL, ACE_SV_Semaphore_Simple>
+<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Guard&lt;ACE_SV_Semaphore_Simple>
+<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Write_Guard&lt;ACE_SV_Semaphore_Simple>
+<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Read_Guard&lt;ACE_SV_Semaphore_Simple>
+<font color=blue>#endif</font> <font color=red>/* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */</font>
+</PRE>
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page03.html">Continue This Tutorial</A>]</CENTER>
diff --git a/docs/tutorials/021/page03.html b/docs/tutorials/021/page03.html
new file mode 100644
index 00000000000..017134a55e5
--- /dev/null
+++ b/docs/tutorials/021/page03.html
@@ -0,0 +1,132 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 021</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 021</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Pooling your memories</FONT></B></CENTER>
+
+<P>
+<HR WIDTH="100%">
+ The client side is a little simpler than the server. Mainly
+ because we don't try to delete the pool:
+ <ul>
+ <li>Create an Allocator to access the pool
+ <li>Find the named region
+ </ul>
+<hr><PRE>
+
+<font color=red>// $Id$</font>
+
+<font color=blue>#include</font> "<font color=green>mpool.h</font>"
+
+int main (int, char *[])
+{
+ <font color=red>/*
+ Use the same pool name used by the server when we create our
+ Allocator. This assures us that we don't create a whole new
+ pool.
+ */</font>
+ Allocator allocator(<font color=#008888>Constants::PoolName</font>);
+
+ <font color=red>/*
+ You can put anything in the memory pool. Not just the
+ character array we want. The find() method till, therefore,
+ return a void* that we will have to cast.
+ */</font>
+ void * region;
+
+ <font color=red>/*
+ We use find() to locate a named region in the pool. This is
+ the counterpart to bind() used in the server.
+ Here, we go try to find the region that the server has created
+ and filled with data. If there was a problem getting the pool
+ or finding the region, we'll get back -1 from find().
+ */</font>
+ if( allocator.pool().find(<font color=#008888>Constants::RegionName</font>,region) == -1 )
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>Cannot find the name '%s'\n</font>",
+ <font color=#008888>Constants::RegionName</font>), 100 );
+ }
+
+ <font color=red>/*
+ Since find() returns us a void*, we cast it here to the char*
+ that we want.
+ */</font>
+ char *shm = (char *)region;
+
+ ACE_DEBUG ((LM_INFO, "<font color=green>Shared memory is at 0x%x\n</font>", shm ));
+
+ <font color=red>/*
+ The same pair of semaphores as used by the server are created
+ here. We probably don't need the CREATE flag since the server
+ should have already done that. There may be some very small
+ windows, however, where the server would have created the
+ memory pool but not yet gotten to the semaphores.
+ */</font>
+ ACE_SV_Semaphore_Complex mutex;
+ ACE_ASSERT (mutex.open (<font color=#008888>Constants::SEM_KEY_1</font>,
+ <font color=#008888>ACE_SV_Semaphore_Complex::ACE_CREATE</font>, 0) != -1);
+
+ ACE_SV_Semaphore_Complex synch;
+ ACE_ASSERT (synch.open (<font color=#008888>Constants::SEM_KEY_2</font>,
+ <font color=#008888>ACE_SV_Semaphore_Complex::ACE_CREATE</font>, 0) != -1);
+
+ <font color=red>/*
+ It doesn't matter if we created 'mutex' or if the server did.
+ In either case, it was created in a locked state and we will
+ block here until somebody unlocks it. In our scenario, that
+ will have to be the server.
+ */</font>
+ if (mutex.acquire () == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P) client mutex.acquire</font>"), 1);
+ }
+
+ <font color=red>/*
+ Now that we know it is safe to access the data, we'll run
+ through and make sure that it contains what we think the server
+ supplied.
+ */</font>
+ for (int i = 0; i &lt; <font color=#008888>Constants::SHMSZ</font>; i++)
+ {
+ ACE_ASSERT (<font color=#008888>Constants::SHMDATA</font>[i] == shm[i]);
+ }
+
+ <font color=red>/*
+ Look back at the server. After filling the region, it will
+ attempt to acquire the lock on 'synch'. It will wait there
+ until we release() the semaphore. That will allow it to remove
+ the pool and cleanup. We can simply exit once we perform the
+ release. (Ok, a free() of the region would probably be polite...)
+ */</font>
+ if (synch.release () == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P) client synch.release</font>"), 1);
+ }
+
+ return 0;
+}
+
+<font color=red>/*
+ Again, we have the necessary explicit template instantiations
+ because I based this on an ACE example instead of creating it from scratch.
+ */</font>
+<font color=blue>#if defined</font> (<font color=purple>ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION</font>)
+template class ACE_Malloc&lt;ACE_MMAP_MEMORY_POOL, ACE_SV_Semaphore_Simple>;
+template class ACE_Guard&lt;ACE_SV_Semaphore_Simple>;
+template class ACE_Write_Guard&lt;ACE_SV_Semaphore_Simple>;
+template class ACE_Read_Guard&lt;ACE_SV_Semaphore_Simple>;
+<font color=blue>#elif defined</font> (<font color=purple>ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA</font>)
+<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Malloc&lt;ACE_MMAP_MEMORY_POOL, ACE_SV_Semaphore_Simple>
+<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Guard&lt;ACE_SV_Semaphore_Simple>
+<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Write_Guard&lt;ACE_SV_Semaphore_Simple>
+<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Read_Guard&lt;ACE_SV_Semaphore_Simple>
+<font color=blue>#endif</font> <font color=red>/* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */</font>
+</PRE>
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page04.html">Continue This Tutorial</A>]</CENTER>
diff --git a/docs/tutorials/021/page04.html b/docs/tutorials/021/page04.html
new file mode 100644
index 00000000000..cc6d3c0fa17
--- /dev/null
+++ b/docs/tutorials/021/page04.html
@@ -0,0 +1,88 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 021</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 021</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Pooling your memories</FONT></B></CENTER>
+
+<P>
+<HR WIDTH="100%">
+ Everything common the server & client is kept here. In
+ particular, the Constants class where we keep the names &
+ semaphore keys.
+ <p>
+ The Allocator class is just a thin wrapper around
+ ACE_Malloc&lt;&gt; that moves some of the details out of the
+ application logic.
+<hr><PRE>
+
+<font color=red>// $Id$</font>
+
+<font color=blue>#ifndef</font> <font color=purple>MPOOL_H</font>
+<font color=blue>#define</font> <font color=purple>MPOOL_H</font>
+
+<font color=red>// Everything else we need is in this one header</font>
+<font color=blue>#include</font> "<font color=green>ace/Malloc.h</font>"
+
+<font color=red>/*
+ With this we will abstract away some of the details of the memory
+ pool. Note that we don't treat this as a singleton because an
+ application may need more than one pool. Each would have a
+ different name and be used for different purposes.
+ */</font>
+class Allocator
+{
+public:
+ <font color=red>// The pool name will be used to create a unique semaphore to</font>
+ <font color=red>// keep this pool separate from others.</font>
+ Allocator( const char * _name = "<font color=green>MemoryPool</font>" );
+ ~Allocator(void);
+
+ typedef ACE_Malloc&lt;ACE_MMAP_Memory_Pool, ACE_SV_Semaphore_Simple> pool_t;
+
+ <font color=red>// Provide an accessor to the pool. This will also allocate the</font>
+ <font color=red>// pool when first invoked.</font>
+ pool_t & pool(void);
+
+protected:
+
+ <font color=red>// The name we gave to the pool</font>
+ char * name_;
+
+ pool_t * pool_;
+};
+
+<font color=red>/*
+ The client and server need to agree on a certain set of values. By
+ placing them in the Constants class we can eliminate a bit of confusion.
+ */</font>
+class Constants
+{
+public:
+ <font color=red>// The semaphore keys are needed for the two semaphores that</font>
+ <font color=red>// synch access to the shared memory area.</font>
+ static const int SEM_KEY_1;
+ static const int SEM_KEY_2;
+
+ <font color=red>// How big the pool will be and what we'll put into it. A real</font>
+ <font color=red>// app wouldn't need SHMDATA of course.</font>
+ static const int SHMSZ;
+ static const char * SHMDATA;
+
+ <font color=red>// The name assigned to the memory pool by the server is needed</font>
+ <font color=red>// by the client. Without it, the pool cannot be found.</font>
+ <font color=red>// Likewise, the name the server will bind() to the region of the </font>
+ <font color=red>// pool must be available to the client.</font>
+ static const char * PoolName;
+ static const char * RegionName;
+};
+
+<font color=blue>#endif</font>
+</PRE>
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page05.html">Continue This Tutorial</A>]</CENTER>
diff --git a/docs/tutorials/021/page05.html b/docs/tutorials/021/page05.html
new file mode 100644
index 00000000000..6e238fcc85b
--- /dev/null
+++ b/docs/tutorials/021/page05.html
@@ -0,0 +1,91 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 021</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 021</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Pooling your memories</FONT></B></CENTER>
+
+<P>
+<HR WIDTH="100%">
+ Everything common the server & client is kept here. In
+ particular, the Constants class where we keep the names &
+ semaphore keys.
+ <p>
+ The Allocator class is just a thin wrapper around
+ ACE_Malloc&lt;&gt; that moves some of the details out of the
+ application logic.
+<hr><PRE>
+
+<font color=red>// $Id$ </font>
+
+<font color=blue>#include</font> "<font color=green>mpool.h</font>"
+
+<font color=red>/*
+ Set the values of all of the constants. This guarantees that client
+ and server don't get confused.
+ */</font>
+const int <font color=#008888>Constants::SEM_KEY_1</font> = ACE_DEFAULT_SEM_KEY + 1;
+const int <font color=#008888>Constants::SEM_KEY_2</font> = ACE_DEFAULT_SEM_KEY + 2;
+
+const int <font color=#008888>Constants::SHMSZ</font> = 27;
+const char * <font color=#008888>Constants::SHMDATA</font> = "<font color=green>abcdefghijklmnopqrstuvwxyz</font>";
+
+const char * <font color=#008888>Constants::PoolName</font> = "<font color=green>SharedMemoryPool</font>";
+const char * <font color=#008888>Constants::RegionName</font> = "<font color=green>Alphabet</font>";
+
+<font color=red>/*
+ We have to create a copy of the _name parameter in case the caller
+ has dynamically allocated it. The pool_ is set to NULL & will be
+ allocated by the accessor.
+ */</font>
+<font color=#008888>Allocator::Allocator</font>( const char * _name )
+ : name_(<font color=#008888>ACE_OS::strdup</font>(_name)),
+ pool_(0)
+{
+ if( ! name_ )
+ {
+ ACE_ERROR ((LM_ERROR, "<font color=green>(%P) %p</font>",
+ "<font color=green><font color=#008888>Allocator::Allocator</font> cannot strdup pool name</font>" ));
+ }
+}
+
+<font color=#008888>Allocator::~Allocator</font>(void)
+{
+ <font color=red>/*
+ strdup() uses malloc(), so we must use free() to clean up.
+ */</font>
+ if( name_ )
+ {
+ free(name_);
+ }
+
+ <font color=red>// delete doesn't really care if you give it a NULL pointer.</font>
+ delete pool_;
+}
+
+<font color=red>/*
+ Allocate the pool. Since we return a reference, we'll be in really
+ bad shape if the new fails. This is a great place to throw an
+ exception!
+ The other concern is thread safety. If two threads call here at
+ about the same time, we may create the pool twice. We can't use a
+ Singleton because we want to have multiple Allocator instances. The
+ Singleton techniques can be used though.
+ */</font>
+<font color=#008888>Allocator::pool_t</font> & Allocator::pool(void)
+{
+ if( ! pool_ )
+ {
+ pool_ = new pool_t( name_ );
+ }
+
+ return *pool_;
+}
+</PRE>
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page06.html">Continue This Tutorial</A>]</CENTER>
diff --git a/docs/tutorials/021/page06.html b/docs/tutorials/021/page06.html
new file mode 100644
index 00000000000..6b2b67963ef
--- /dev/null
+++ b/docs/tutorials/021/page06.html
@@ -0,0 +1,32 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 021</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 021</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Pooling your memories</FONT></B></CENTER>
+
+<P>
+<HR WIDTH="100%">
+ As you can see, using a memory pool is really rather easy. The
+ most difficult part, as always, is with the synch mechanisms.
+ <P>
+ The other nice thing about ACE_Malloc&lt;> is that you can swap
+ between System V shared memory and memory mapped files just by
+ changing the template parameters. The truly adventurous will
+ likely find a runtime way of doing this.
+ <p>
+
+ <ul>
+ <li><A HREF="Makefile">Makefile</A>
+ <li><A HREF="server.cpp">server.cpp</A>
+ <li><A HREF="client.cpp">client.cpp</A>
+ <li><A HREF="mpool.h">mpool.h</A>
+ <li><A HREF="mpool.cpp">mpool.cpp</A>
+ </ul>
+<P><HR WIDTH="100%">
+<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] </CENTER>
diff --git a/docs/tutorials/021/server.cpp b/docs/tutorials/021/server.cpp
index 84618985cff..15ced695af0 100644
--- a/docs/tutorials/021/server.cpp
+++ b/docs/tutorials/021/server.cpp
@@ -1,23 +1,67 @@
// $Id$
+/*
+ I've hidden the details in an Allocator class declared in mpool.h
+ We'll come to that a little later.
+*/
#include "mpool.h"
int main (int, char *[])
{
+ /*
+ Construction of an Allocator will create the memory pool and
+ provide it with a name. The Constants class is also
+ declared in mpool.h to keep server and client on the same
+ page. The name is used to generate a unique semaphore which
+ prevents simultaneous access to the pools housekeeping
+ information. (Note that you still have to provide your own
+ synch mechanisms for the data *you* put in the poo.)
+ */
Allocator allocator(Constants::PoolName);
-
+
+ /*
+ The Allocator class provides the pool() member so that you
+ have access to the actual memory pool. A more robust
+ implementation would behave more as a bridge class but this
+ is good enough for what we're doing here.
+ Once you have a reference to the pool, the malloc() method
+ can be used to get some bytes. If successful, shm will
+ point to the data. Otherwise, it will be zero.
+ */
char *shm = (char *) allocator.pool().malloc (27);
ACE_ASSERT( shm != 0 );
+ /// FYI
ACE_DEBUG ((LM_INFO, "Shared memory is at 0x%x\n", shm ));
+ /*
+ Something that we can do with a memory pool is map a name to
+ a region provided by malloc. By doing this, we can
+ communicate that name to the client as a rendezvous
+ location. Again, a member of Constants is used to keep the
+ client and server coordinated.
+ */
if( allocator.pool().bind(Constants::RegionName,shm) == -1 )
{
ACE_ERROR_RETURN ((LM_ERROR, "Cannot bind the name '%s' to the pointer 0x%x\n",
Constants::RegionName,shm), 100 );
}
+
+ /*
+ One of the best ways to synch between different processes is
+ through the use of semaphores. ACE_SV_Semaphore_Complex
+ hides the gory details and lets us use them rather easily.
+
+ Here, we'll create two semaphores: mutex and synch. mutex
+ will be used to provide mutually exclusive access to the
+ shared region for writting/reading. synch will be used to
+ prevent the server from removing the memory pool before the
+ client is done with it.
+
+ Both semaphores are created in an initially locked state.
+ */
ACE_SV_Semaphore_Complex mutex;
ACE_ASSERT (mutex.open (Constants::SEM_KEY_1,
@@ -26,26 +70,51 @@ int main (int, char *[])
ACE_SV_Semaphore_Complex synch;
ACE_ASSERT (synch.open (Constants::SEM_KEY_2,
ACE_SV_Semaphore_Complex::ACE_CREATE, 0) != -1);
-
+
+ /*
+ We know the mutex is locked because we created it that way.
+ Take a moment to write some data into the shared region.
+ */
for (int i = 0; i < Constants::SHMSZ; i++)
{
shm[i] = Constants::SHMDATA[i];
}
-
+
+ /*
+ The client will be blocking on an acquire() of mutex. By
+ releasing it here, the client can go look at the shared data.
+ */
if (mutex.release () == -1)
{
ACE_ERROR ((LM_ERROR, "(%P) %p", "server mutex.release"));
}
+ /*
+ Even though we created the synch semaphore in a locked
+ state, if we attempt to acquire() it, we will block. Our
+ design requires that the client release() synch when it is
+ OK for us to remove the shared memory.
+ */
else if (synch.acquire () == -1)
{
ACE_ERROR ((LM_ERROR, "(%P) %p", "server synch.acquire"));
}
-
+
+ /*
+ This will remove all of the memory pool's resources. In the
+ case where a memory mapped file is used, the physical file
+ will also be removed.
+ */
if (allocator.pool ().remove () == -1)
{
ACE_ERROR ((LM_ERROR, "(%P) %p\n", "server allocator.remove"));
}
+ /*
+ We now have to cleanup the semaphores we created. Use the
+ ipcs command to see that they did, indeed, go away after the
+ server exits.
+ */
+
if (mutex.remove () == -1)
{
ACE_ERROR ((LM_ERROR, "(%P) %p\n", "server mutex.remove"));
@@ -55,10 +124,16 @@ int main (int, char *[])
{
ACE_ERROR ((LM_ERROR, "(%P) %p\n", "server synch.remove"));
}
+
return 0;
}
+/*
+ This tutorial was created by shamelessly modifying one of the ACE
+ examples. Someone there had already created the necessary explicit
+ template instantiations & I don't want them to go to waste...
+ */
#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
template class ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_SV_Semaphore_Simple>;
template class ACE_Guard<ACE_SV_Semaphore_Simple>;
diff --git a/docs/tutorials/online-tutorials.html b/docs/tutorials/online-tutorials.html
index c6b0ef0bb6a..7aa97414562 100644
--- a/docs/tutorials/online-tutorials.html
+++ b/docs/tutorials/online-tutorials.html
@@ -128,6 +128,8 @@ Do you remember...</H4>
<A HREF="019/page01.html">Using System V Shared Memory for telepathy</A>
<LI>
<A HREF="020/page01.html">Never forget anything else again!</A>
+<LI>
+<A HREF="021/page01.html">Pooling your memories via ACE_Malloc</A>
</OL>
<HR>