©2004 by Marc J. Rochkind. All rights reserved. Portions marked "Open Source" may be copied under license.

 

Main Page   Modules   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

c7/smi_pshm.c

Go to the documentation of this file.
00001 /*
00002     SMI - POSIX shared memory
00003     AUP2, Sec. 7.14.2
00004 
00005     Copyright 2003 by Marc J. Rochkind. All rights reserved.
00006     May be copied only for purposes and under conditions described
00007     on the Web page www.basepath.com/aup/copyright.htm.
00008 
00009     The Example Files are provided "as is," without any warranty;
00010     without even the implied warranty of merchantability or fitness
00011     for a particular purpose. The author and his publisher are not
00012     responsible for any damages, direct or incidental, resulting
00013     from the use or non-use of these Example Files.
00014 
00015     The Example Files may contain defects, and some contain deliberate
00016     coding mistakes that were included for educational reasons.
00017     You are responsible for determining if and how the Example Files
00018     are to be used.
00019 
00020 */
00021 #include "defs.h"
00022 #include "smi_pshm.h"
00023 /*
00024     There may exist a POSIX semaphore implementation for these systems,
00025     but I haven't located it yet. Change next line if you find one.
00026     and then please email me at aup@basepath.com.
00027 */
00028 #if !defined(FREEBSD) && !defined(LINUX)
00029 
00030 #include <semaphore.h>
00031 #define _P1003_1B_VISIBLE
00032 #include <sys/mman.h>
00033 
00034 /*
00035     Shared memory with separate memory segment for server and all clients.
00036     Uses POSIX memory-based semaphores and POSIX shared memory.
00037 
00038     Missing is a way for a client to tell the server to make its slot available. It isn't possible for a client's slot to be dropped and then reused, as the memory semaphores have to persist undisturbed.
00039 */
00040 
00041 /* Structure must contain no pointers. */
00042 /*[shared_mem]*/
00043 struct shared_mem {
00044     sem_t sm_sem_w;
00045     sem_t sm_sem_r;
00046     struct smi_msg sm_msg; /* variable size -- must be last */
00047 };
00048 /*[SMIQ_PSHM]*/
00049 #define MAX_CLIENTS 50
00050 
00051 typedef struct {
00052     SMIENTITY sq_entity;            /* entity */
00053     char sq_name[SERVER_NAME_MAX];  /* server name */
00054     int sq_srv_fd;                  /* server shm file descriptor */
00055     struct shared_mem *sq_srv_mem;  /* server mapped shm segment */
00056     struct client {
00057         pid_t cl_pid;               /* client process ID */
00058         int cl_fd;                  /* client shm file descriptor */
00059         struct shared_mem *cl_mem;  /* client mapped shm segment */
00060     } sq_clients[MAX_CLIENTS];      /* client uses only [0] */
00061     struct client_id sq_client;     /* client ident. (server only)*/
00062     size_t sq_msgsize;              /* message size */
00063 } SMIQ_PSHM;
00064 /*[MEM_SIZE]*/
00065 #define MEM_SIZE(s)\
00066   (sizeof(struct shared_mem) - sizeof(struct smi_msg) + (s))
00067 /*[mkshm_name]*/
00068 static void mkshm_name_server(const SMIQ_PSHM *p, char *shmname,
00069   size_t shmname_max)
00070 {
00071     snprintf(shmname, shmname_max, "/smipshm-%s", p->sq_name);
00072 }
00073 
00074 static void mkshm_name_client(pid_t pid, char *shmname,
00075   size_t shmname_max)
00076 {
00077     snprintf(shmname, shmname_max, "/smipshm-%d", pid);
00078 }
00079 /*[op_semi]*/
00080 #define SEMI_READ       0
00081 #define SEMI_WRITE      1
00082 #define SEMI_DESTROY    2
00083 #define SEMI_POST       1
00084 #define SEMI_WAIT       -1
00085 
00086 static int op_semi(struct shared_mem *m, int sem_num, int sem_op)
00087 {
00088     sem_t *sem_p = NULL;
00089 
00090     if (sem_num == SEMI_WRITE)
00091         sem_p = &m->sm_sem_w;
00092     else
00093         sem_p = &m->sm_sem_r;
00094     switch (sem_op) {
00095     case SEMI_WAIT:
00096         ec_neg1( sem_wait(sem_p) )
00097         break;
00098     case SEMI_POST:
00099         ec_neg1( sem_post(sem_p) )
00100         break;
00101     case SEMI_DESTROY:
00102         ec_neg1( sem_destroy(sem_p) )
00103     }
00104     return 0;
00105 
00106 EC_CLEANUP_BGN
00107     return -1;
00108 EC_CLEANUP_END
00109 }
00110 /*[get_client]*/
00111 static struct client *get_client(SMIQ_PSHM *p, pid_t pid)
00112 {
00113     int i, avail = -1;
00114     char shmname[SERVER_NAME_MAX + 50];
00115 
00116     for (i = 0; i < MAX_CLIENTS; i++) {
00117         if (p->sq_clients[i].cl_pid == pid)
00118             return &p->sq_clients[i];
00119         if (p->sq_clients[i].cl_pid == 0 && avail == -1)
00120             avail = i;
00121     }
00122     if (avail == -1) {
00123         errno = EADDRNOTAVAIL;
00124         EC_FAIL
00125     }
00126     p->sq_clients[avail].cl_pid = pid;
00127     mkshm_name_client(pid, shmname, sizeof(shmname));
00128     ec_neg1( p->sq_clients[avail].cl_fd = shm_open(shmname, O_RDWR,
00129       PERM_FILE) )
00130     p->sq_clients[avail].cl_mem = mmap(NULL, MEM_SIZE(p->sq_msgsize),
00131       PROT_READ | PROT_WRITE, MAP_SHARED, p->sq_clients[avail].cl_fd,
00132       0);
00133     ec_cmp(p->sq_clients[avail].cl_mem, MAP_FAILED)
00134     return &p->sq_clients[avail];
00135 
00136 EC_CLEANUP_BGN
00137     return NULL;
00138 EC_CLEANUP_END
00139 }
00140 /*[]*/
00141 /* cleanup needs to be more complete than just free(p) */
00142 /*[smi_open_pshm]*/
00143 SMIQ *smi_open_pshm(const char *name, SMIENTITY entity, size_t msgsize)
00144 {
00145     SMIQ_PSHM *p = NULL;
00146     char shmname[SERVER_NAME_MAX + 50];
00147 
00148     ec_null( p = calloc(1, sizeof(SMIQ_PSHM)) )
00149     p->sq_entity = entity;
00150     p->sq_msgsize = msgsize;
00151     if (strlen(name) >= SERVER_NAME_MAX) {
00152         errno = ENAMETOOLONG;
00153         EC_FAIL
00154     }
00155     strcpy(p->sq_name, name);
00156     mkshm_name_server(p, shmname, sizeof(shmname));
00157     if (p->sq_entity == SMI_SERVER) {
00158         if ((p->sq_srv_fd = shm_open(shmname, O_RDWR, PERM_FILE)) != -1) {
00159             (void)shm_unlink(shmname);
00160             (void)close(p->sq_srv_fd);
00161         }
00162         ec_neg1( p->sq_srv_fd = shm_open(shmname, O_RDWR | O_CREAT,
00163           PERM_FILE) )
00164         ec_neg1( ftruncate(p->sq_srv_fd, MEM_SIZE(msgsize)) )
00165         p->sq_srv_mem = mmap(NULL, MEM_SIZE(msgsize),
00166           PROT_READ | PROT_WRITE, MAP_SHARED, p->sq_srv_fd, 0);
00167         ec_cmp(p->sq_srv_mem, MAP_FAILED)
00168         ec_neg1( sem_init(&p->sq_srv_mem->sm_sem_w, true, 1) )
00169         ec_neg1( sem_init(&p->sq_srv_mem->sm_sem_r, true, 0) )
00170     }
00171     else {
00172         ec_neg1( p->sq_srv_fd = shm_open(shmname, O_RDWR, PERM_FILE) )
00173         p->sq_srv_mem = mmap(NULL, MEM_SIZE(msgsize),
00174           PROT_READ | PROT_WRITE, MAP_SHARED, p->sq_srv_fd, 0);
00175         ec_cmp(p->sq_srv_mem, MAP_FAILED)
00176         mkshm_name_client(getpid(), shmname, sizeof(shmname));
00177         if ((p->sq_clients[0].cl_fd = shm_open(shmname, O_RDWR, PERM_FILE))
00178           != -1) {
00179             (void)shm_unlink(shmname);
00180             (void)close(p->sq_clients[0].cl_fd);
00181         }
00182         ec_neg1( p->sq_clients[0].cl_fd = shm_open(shmname,
00183           O_RDWR | O_CREAT, PERM_FILE) )
00184         ec_neg1( ftruncate(p->sq_clients[0].cl_fd, MEM_SIZE(msgsize)) )
00185         p->sq_clients[0].cl_mem = mmap(NULL, MEM_SIZE(msgsize),
00186           PROT_READ | PROT_WRITE, MAP_SHARED, p->sq_clients[0].cl_fd, 0);
00187         ec_cmp(p->sq_clients[0].cl_mem, MAP_FAILED)
00188         ec_neg1( sem_init(&p->sq_clients[0].cl_mem->sm_sem_w, true,
00189           1) ) // not sure if 1 is correct
00190         ec_neg1( sem_init(&p->sq_clients[0].cl_mem->sm_sem_r, true,
00191           0) )
00192     }
00193     return (SMIQ *)p;
00194 
00195 EC_CLEANUP_BGN
00196     if (p != NULL)
00197         (void)smi_close_pshm((SMIQ *)p);
00198     return NULL;
00199 EC_CLEANUP_END
00200 }
00201 /*[smi_close_pshm]*/
00202 bool smi_close_pshm(SMIQ *sqp)
00203 {
00204     SMIQ_PSHM *p = (SMIQ_PSHM *)sqp;
00205     int i;
00206     char shmname[SERVER_NAME_MAX + 50];
00207 
00208     if (p->sq_entity == SMI_SERVER) {
00209         (void)op_semi(p->sq_srv_mem, SEMI_WRITE, SEMI_DESTROY);
00210         (void)op_semi(p->sq_srv_mem, SEMI_READ, SEMI_DESTROY);
00211     }
00212     (void)munmap(p->sq_srv_mem, MEM_SIZE(p->sq_msgsize));
00213     if (p->sq_srv_fd > 0)
00214         (void)close(p->sq_srv_fd);
00215     if (p->sq_entity == SMI_SERVER) {
00216         mkshm_name_server(p, shmname, sizeof(shmname));
00217         (void)shm_unlink(shmname);
00218     }
00219     for (i = 0; i < MAX_CLIENTS; i++)
00220         if (p->sq_clients[i].cl_mem != NULL) {
00221             if (p->sq_entity == SMI_CLIENT) {
00222                 (void)op_semi(p->sq_clients[i].cl_mem, SEMI_WRITE,
00223                   SEMI_DESTROY);
00224                 (void)op_semi(p->sq_clients[i].cl_mem, SEMI_READ,
00225                   SEMI_DESTROY);
00226             }
00227             (void)munmap(p->sq_clients[i].cl_mem, MEM_SIZE(p->sq_msgsize));
00228             if (p->sq_clients[i].cl_fd > 0)
00229                 (void)close(p->sq_clients[i].cl_fd);
00230             if (p->sq_entity == SMI_CLIENT) {
00231                 mkshm_name_client(p->sq_clients[i].cl_pid, shmname,
00232                   sizeof(shmname));
00233                 (void)shm_unlink(shmname);
00234             }
00235         }
00236     free(p);
00237     return true;
00238 }
00239 /*[]*/
00240 /*[smi_send_getaddr_pshm]*/
00241 bool smi_send_getaddr_pshm(SMIQ *sqp, struct client_id *client,
00242   void **addr)
00243 {
00244     SMIQ_PSHM *p = (SMIQ_PSHM *)sqp;
00245     struct client *cp;
00246     struct shared_mem *sm;
00247 
00248     if (p->sq_entity == SMI_SERVER) {
00249         p->sq_client = *client;
00250         ec_null( cp = get_client(p, client->c_id1) )
00251         sm = cp->cl_mem;
00252     }
00253     else
00254         sm = p->sq_srv_mem;
00255     ec_neg1( op_semi(sm, SEMI_WRITE, SEMI_WAIT) )
00256     if (p->sq_entity == SMI_CLIENT)
00257         sm->sm_msg.smi_client.c_id1 = getpid();
00258     *addr = &sm->sm_msg;
00259     return true;
00260 
00261 EC_CLEANUP_BGN
00262     return false;
00263 EC_CLEANUP_END
00264 }
00265 /*[smi_send_release_pshm]*/
00266 bool smi_send_release_pshm(SMIQ *sqp)
00267 {
00268     SMIQ_PSHM *p = (SMIQ_PSHM *)sqp;
00269     struct client *cp;
00270     struct shared_mem *sm;
00271 
00272     if (p->sq_entity == SMI_SERVER) {
00273         ec_null( cp = get_client(p, p->sq_client.c_id1) )
00274         sm = cp->cl_mem;
00275     }
00276     else
00277         sm = p->sq_srv_mem;
00278     ec_neg1( op_semi(sm, SEMI_READ, SEMI_POST) )
00279     return true;
00280 
00281 EC_CLEANUP_BGN
00282     return false;
00283 EC_CLEANUP_END
00284 }
00285 /*[smi_receive_getaddr_pshm]*/
00286 bool smi_receive_getaddr_pshm(SMIQ *sqp, void **addr)
00287 {
00288     SMIQ_PSHM *p = (SMIQ_PSHM *)sqp;
00289     struct shared_mem *sm;
00290 
00291     if (p->sq_entity == SMI_SERVER)
00292         sm = p->sq_srv_mem;
00293     else
00294         sm = p->sq_clients[0].cl_mem;
00295     ec_neg1( op_semi(sm, SEMI_READ, SEMI_WAIT) )
00296     *addr = &sm->sm_msg;
00297     return true;
00298 
00299 EC_CLEANUP_BGN
00300     return false;
00301 EC_CLEANUP_END
00302 }
00303 /*[smi_receive_release_pshm]*/
00304 bool smi_receive_release_pshm(SMIQ *sqp)
00305 {
00306     SMIQ_PSHM *p = (SMIQ_PSHM *)sqp;
00307     struct shared_mem *sm;
00308 
00309     if (p->sq_entity == SMI_SERVER)
00310         sm = p->sq_srv_mem;
00311     else
00312         sm = p->sq_clients[0].cl_mem;
00313     ec_neg1( op_semi(sm, SEMI_WRITE, SEMI_POST) )
00314     return true;
00315 
00316 EC_CLEANUP_BGN
00317     return false;
00318 EC_CLEANUP_END
00319 }
00320 /*[]*/
00321 
00322 #else /* FREEBSD or LINUX */
00323 
00324 SMIQ *smi_open_pshm(const char *name, SMIENTITY entity, size_t msgsize)
00325 {
00326     errno = ENOSYS;
00327     return NULL;
00328 }
00329 
00330 bool smi_close_pshm(SMIQ *sqp)
00331 {
00332     return true;
00333 }
00334 
00335 bool smi_send_getaddr_pshm(SMIQ *sqp, struct client_id *client,
00336   void **addr)
00337 {
00338     errno = ENOSYS;
00339     return false;
00340 }
00341 
00342 bool smi_send_release_pshm(SMIQ *sqp)
00343 {
00344     errno = ENOSYS;
00345     return false;
00346 }
00347 
00348 bool smi_receive_getaddr_pshm(SMIQ *sqp, void **addr)
00349 {
00350     errno = ENOSYS;
00351     return false;
00352 }
00353 
00354 bool smi_receive_release_pshm(SMIQ *sqp)
00355 {
00356     errno = ENOSYS;
00357     return false;
00358 }
00359 
00360 #endif /* FREEBSD or LINUX */

Generated on Fri Apr 23 10:57:00 2004 for AUP2 Example Source by doxygen 1.3.1