sharedmem.c

Go to the documentation of this file.
00001 /* $Id: sharedmem.c,v 1.3 2005/02/03 11:02:19 jlaako Exp $ */
00002 
00003 /*
00004 
00005     Shared memory object for POSIX/IEEE-1003.1 compliant systems.
00006 
00007     Copyright (C) 2005-2007 Nokia Corporation.
00008 
00009     Contact: Jussi Laako <jussi.laako@nokia.com>
00010 
00011     This library is free software; you can redistribute it and/or
00012     modify it under the terms of the GNU Lesser General Public
00013     License as published by the Free Software Foundation; either
00014     version 2.1 of the License, or (at your option) any later version.
00015 
00016     This library is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019     Lesser General Public License for more details.
00020 
00021     You should have received a copy of the GNU Lesser General Public
00022     License along with this library; if not, write to the Free Software
00023     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00024 
00025 */
00026 
00027 
00028 /* specify source conformance to include necessary functions */
00029 #define _XOPEN_SOURCE 600
00030 #define _POSIX_C_SOURCE 200112L
00031 
00032 
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include <fcntl.h>
00037 #include <time.h>
00038 #include <signal.h>
00039 #include <unistd.h>
00040 #include <errno.h>
00041 #include <sys/types.h>
00042 #include <sys/stat.h>
00043 #include <sys/mman.h>
00044 #ifdef HAVE_PSHARED
00045 #include <pthread.h>
00046 #else
00047 #include <semaphore.h>
00048 #endif
00049 
00050 #include "sharedmem.h"
00051 #include "sharedmem_private.h"
00052 
00053 
00054 /* --- internal */
00055 
00056 long sharedmem_page_size = 0;
00057 
00058 
00059 /* set error code and message */
00060 void _sharedmem_set_error (sharedmem_t *inst, int error_code,
00061     const char *error_str)
00062 {
00063     char errcodestr[SHAREDMEM_ERROR_SIZE / 2];
00064 
00065     if (inst == NULL)
00066         return;
00067     inst->error.code = error_code;
00068     if (error_str != NULL)
00069     {
00070         if (error_code > 0)
00071         {
00072             strerror_r(error_code, errcodestr, SHAREDMEM_ERROR_SIZE / 2);
00073             snprintf(inst->error.string, SHAREDMEM_ERROR_SIZE, "%s: %s",
00074                 error_str, errcodestr);
00075         }
00076         else
00077         {
00078             snprintf(inst->error.string, SHAREDMEM_ERROR_SIZE, "%s",
00079                 error_str);
00080         }
00081     }
00082     else
00083     {
00084         inst->error.string[0] = '\0';
00085     }
00086 }
00087 
00088 
00089 static void set_error (sharedmem_t *inst, int error_code, const char *error_str)
00090 {
00091     _sharedmem_set_error(inst, error_code, error_str);
00092 }
00093 
00094 
00095 /* get system page size */
00096 static int init_page_size (sharedmem_t *inst)
00097 {
00098     if (sharedmem_page_size > 0)
00099         return 0;
00100     sharedmem_page_size = sysconf(_SC_PAGE_SIZE);
00101     if (sharedmem_page_size <= 0)
00102     {
00103         set_error(inst, errno, "init_page_size(): sysconf()");
00104         return -1;
00105     }
00106     return 0;
00107 }
00108 
00109 
00110 /* round size to nearest page boundary */
00111 static size_t round_to_page_boundary (size_t size)
00112 {
00113     size_t size_res;
00114     
00115     size_res = sharedmem_page_size * 
00116         ((size + (sharedmem_page_size - 1)) / 
00117         sharedmem_page_size);
00118     
00119     return size_res;
00120 }
00121 
00122 
00123 /* map the shared memory blocks */
00124 static int do_maps (sharedmem_t *inst, size_t size)
00125 {
00126     size_t size_ctrl;
00127     size_t size_data;
00128     size_t size_data_n;
00129 
00130     size_ctrl = round_to_page_boundary(sizeof(sharedmem_ctrl_t));
00131     /* map the control block, this is thus protected from the data */
00132     inst->ctrl = (sharedmem_ctrl_t *) mmap(NULL, size_ctrl,
00133         PROT_READ|PROT_WRITE, MAP_SHARED, inst->fd, 0);
00134     if (inst->ctrl == NULL)
00135     {
00136         set_error(inst, errno, "do_maps(): mmap()");
00137         return -1;
00138     }
00139 
00140     size_data_n = (size > 0) ? size : inst->ctrl->size;
00141     size_data = round_to_page_boundary(size_data_n);
00142     /* map the data block */
00143     inst->pdata = mmap(NULL, size_data, PROT_READ|PROT_WRITE, MAP_SHARED,
00144         inst->fd, size_ctrl);
00145     if (inst->pdata == NULL)
00146     {
00147         munmap(inst->ctrl, size_ctrl);
00148         set_error(inst, errno, "do_maps(): mmap()");
00149         return -1;
00150     }
00151     inst->mapped_size = size_data_n;
00152 
00153     return 0;
00154 }
00155 
00156 
00157 /* unmap the shared memory blocks */
00158 static int undo_maps (sharedmem_t *inst)
00159 {
00160     int res, res2;
00161     size_t size_ctrl;
00162     size_t size_data;
00163     
00164     size_ctrl = round_to_page_boundary(sizeof(sharedmem_ctrl_t));
00165     size_data = round_to_page_boundary(inst->mapped_size);
00166     /* unmap the data block */
00167     res = munmap(inst->pdata, size_data);
00168     inst->mapped_size = 0;
00169     inst->pdata = NULL;
00170     /* unmap the control block */
00171     res2 = munmap(inst->ctrl, size_ctrl);
00172     inst->ctrl = NULL;
00173     if (res != 0 || res2 != 0)
00174     {
00175         set_error(inst, errno, "undo_maps(): munmap()");
00176         return -1;
00177     }
00178     
00179     return 0;
00180 }
00181 
00182 
00183 static int init_mutex (sharedmem_t *inst)
00184 {
00185 #ifdef HAVE_PSHARED
00186     pthread_mutexattr_t mutex_attr;
00187 
00188     /* initialize mutex object in shared memory for process shared access */
00189     if (pthread_mutexattr_init(&mutex_attr) != 0)
00190     {
00191         set_error(inst, errno, "init_mutex(): pthread_mutexattr_init()");
00192         return -1;
00193     }
00194     if (pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED) != 0)
00195     {
00196         set_error(inst, errno, "init_mutex(): pthread_mutexattr_setpshared()");
00197         return -1;
00198     }
00199     if (pthread_mutex_init(&inst->ctrl->mutex, &mutex_attr) != 0)
00200     {
00201         set_error(inst, errno, "init_mutex(): pthread_mutex_init()");
00202         return -1;
00203     }
00204     if (pthread_mutexattr_destroy(&mutex_attr) != 0)
00205     {
00206         set_error(inst, errno, "init_mutex(): pthread_mutexattr_destroy()");
00207         return -1;
00208     }
00209 #endif  /* HAVE_PSHARED */
00210     
00211     return 0;
00212 }
00213 
00214 
00215 static int destroy_mutex (sharedmem_t *inst)
00216 {
00217 #ifdef HAVE_PSHARED
00218     return pthread_mutex_destroy(&inst->ctrl->mutex);
00219 #else
00220     return 0;
00221 #endif
00222 }
00223 
00224 
00225 static int init_cond (sharedmem_t *inst)
00226 {
00227 #ifdef HAVE_PSHARED
00228     pthread_condattr_t cond_attr;
00229 
00230     /* initialize condition variable object in shared memory for process shared
00231        access */
00232     if (pthread_condattr_init(&cond_attr) != 0)
00233     {
00234         set_error(inst, errno, "init_cond(): pthread_condattr_init()");
00235         return -1;
00236     }
00237     if (pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED) != 0)
00238     {
00239         set_error(inst, errno, "init_cond(): pthread_condattr_setpshared()");
00240         return -1;
00241     }
00242     if (pthread_cond_init(&inst->ctrl->cond, &cond_attr) != 0)
00243     {
00244         set_error(inst, errno, "init_cond(): pthread_cond_init()");
00245         return -1;
00246     }
00247     if (pthread_condattr_destroy(&cond_attr) != 0)
00248     {
00249         set_error(inst, errno, "init_cond(): pthread_condattr_destroy()");
00250         return -1;
00251     }
00252 #endif  /* HAVE_PSHARED */
00253     
00254     return 0;
00255 }
00256 
00257 
00258 static int destroy_cond (sharedmem_t *inst)
00259 {
00260 #ifdef HAVE_PSHARED
00261     return pthread_cond_destroy(&inst->ctrl->cond);
00262 #else
00263     return 0;
00264 #endif
00265 }
00266 
00267 
00268 static inline int lock_sem (sharedmem_t *inst)
00269 {
00270     if (unlikely(inst == NULL))
00271         return 0;
00272     if (unlikely(inst->sem == NULL))
00273         return 0;
00274     if (unlikely(sem_wait(SHAREDMEM_SEM(inst)) != 0))
00275         return 0;
00276     return 1;
00277 }
00278 
00279 
00280 static inline int unlock_sem (sharedmem_t *inst)
00281 {
00282     if (unlikely(inst == NULL))
00283         return 0;
00284     if (unlikely(inst->sem == NULL))
00285         return 0;
00286     if (unlikely(sem_post(SHAREDMEM_SEM(inst)) != 0))
00287         return 0;
00288     return 1;
00289 }
00290 
00291 
00292 /* --- public */
00293 
00294 
00295 int sharedmem_create (sharedmem_t *inst, const char *name, size_t size)
00296 {
00297     size_t size_real;
00298     
00299     if (inst == NULL)
00300         return -1;
00301     memset(inst, 0x00, sizeof(sharedmem_t));
00302     inst->fd = -1;
00303 
00304     /* initialize page size */
00305     if (init_page_size(inst) != 0)
00306         return -1;
00307     strncpy(inst->name, name, SHAREDMEM_NAME_LENGTH - 1);
00308     /* create named semaphore in locked state */
00309     sem_unlink(inst->name);
00310     inst->sem = sem_open(inst->name, O_CREAT|O_EXCL,
00311         S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, 0);
00312     if (inst->sem == NULL)
00313     {
00314         set_error(inst, errno, "sharedmem_create(): sem_open()");
00315         return -1;
00316     }
00317     /* create named shared memory */
00318     shm_unlink(inst->name);
00319     inst->fd = shm_open(inst->name, O_RDWR|O_CREAT|O_TRUNC, 
00320         S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
00321     if (inst->fd < 0)
00322     {
00323         set_error(inst, errno, "sharedmem_create(): shm_open()");
00324         goto create_exit;
00325     }
00326     /* set the size of the shared memory */
00327     size_real = round_to_page_boundary(sizeof(sharedmem_ctrl_t)) +
00328         round_to_page_boundary(size);
00329     if (ftruncate(inst->fd, size_real) != 0)
00330     {
00331         set_error(inst, errno, "sharedmem_create(): ftruncate()");
00332         goto create_exit;
00333     }
00334     /* map it to process address space */
00335     if (do_maps(inst, size) != 0)
00336         goto create_exit;
00337 
00338     /* initialize mutex object */
00339     if (init_mutex(inst) != 0)
00340         goto create_exit;
00341     /* initialize condition variable object */
00342     if (init_cond(inst) != 0)
00343         goto create_exit;
00344 
00345     /* set size and increase reference count */
00346     inst->ctrl->size = size;
00347     inst->ctrl->ref++;
00348 
00349     set_error(inst, 0, NULL);
00350 
00351     /* unlock the semaphore */
00352     unlock_sem(inst);
00353     return 0;
00354 
00355 create_exit:
00356     /* unlock the semaphore */
00357     unlock_sem(inst);
00358     return -1;
00359 }
00360 
00361 
00362 int sharedmem_open (sharedmem_t *inst, const char *name)
00363 {
00364     if (inst == NULL)
00365         return -1;
00366     memset(inst, 0x00, sizeof(sharedmem_t));
00367     inst->fd = -1;
00368 
00369     /* initialize page size */
00370     if (init_page_size(inst) != 0)
00371         return -1;
00372     strncpy(inst->name, name, SHAREDMEM_NAME_LENGTH - 1);
00373     /* open named semaphore */
00374     inst->sem = sem_open(inst->name, 0);
00375     if (inst->sem == NULL)
00376     {
00377         set_error(inst, errno, "sharedmem_open(): sem_open()");
00378         return -1;
00379     }
00380     /* lock the semaphore */
00381     if (!lock_sem(inst))
00382     {
00383         set_error(inst, errno, "sharedmem_open(): lock_sem()");
00384         return -1;
00385     }
00386     /* open named shared memory */
00387     inst->fd = shm_open(inst->name, O_RDWR, 0);
00388     if (inst->fd < 0)
00389     {
00390         set_error(inst, errno, "sharedmem_open(): shm_open()");
00391         goto open_exit;
00392     }
00393     /* map it to process address space */
00394     if (do_maps(inst, 0) != 0)
00395         goto open_exit;
00396     
00397     /* increase reference count */
00398     inst->ctrl->ref++;
00399 
00400     set_error(inst, 0, NULL);
00401 
00402     /* unlock the semaphore */
00403     unlock_sem(inst);
00404     return 0;
00405 
00406 open_exit:
00407     /* unlock the semaphore */
00408     unlock_sem(inst);
00409     return -1;
00410 }
00411 
00412 
00413 int sharedmem_close (sharedmem_t *inst)
00414 {
00415     int retval = 0;
00416     int destruct = 0;
00417 
00418     if (inst == NULL)
00419         return -1;
00420     if (inst->ctrl == NULL)
00421         return -1;
00422 
00423     set_error(inst, 0, NULL);
00424     /* decrease reference count */
00425     if (!lock_sem(inst))
00426     {
00427         set_error(inst, errno, "sharedmem_close(): lock_sem()");
00428         retval--;
00429     }
00430     inst->ctrl->ref--;
00431     if (inst->ctrl->ref <= 0)
00432         destruct = 1;
00433     if (!unlock_sem(inst))
00434     {
00435         set_error(inst, errno, "sharedmem_close(): unlock_sem()");
00436         retval--;
00437     }
00438     if (!destruct)
00439     {
00440         /* unmap the shared memory */
00441         if (undo_maps(inst) != 0)
00442             retval--;
00443         if (close(inst->fd) != 0)
00444         {
00445             set_error(inst, errno, "sharedmem_close(): close()");
00446             retval--;
00447         }
00448         inst->fd = -1;
00449         if (sem_close(inst->sem) != 0)
00450         {
00451             set_error(inst, errno, "sharedmem_close(): sem_close()");
00452             retval--;
00453         }
00454 
00455         if (retval == 0)
00456             set_error(inst, 0, NULL);
00457         return retval;
00458     }
00459 
00460     /* destroy mutex and condition variable objects */
00461     if (destroy_mutex(inst) != 0)
00462     {
00463         set_error(inst, errno, "sharedmem_close(): destroy_mutex()");
00464         retval--;
00465     }
00466     if (destroy_cond(inst) != 0)
00467     {
00468         set_error(inst, errno, "sharedmem_close(): destroy_cond()");
00469         retval--;
00470     }
00471     /* unmap the shared memory */
00472     if (undo_maps(inst) != 0)
00473         retval--;
00474     /* close the shared memory */
00475     if (close(inst->fd) != 0)
00476     {
00477         set_error(inst, errno, "sharedmem_close(): close()");
00478         retval--;
00479     }
00480     inst->fd = -1;
00481     /* remove named shared memory */
00482     if (shm_unlink(inst->name) != 0)
00483     {
00484         set_error(inst, errno, "sharedmem_close(): shm_unlink()");
00485         retval--;
00486     }
00487     /* close the named semaphore */
00488     if (sem_close(inst->sem) != 0)
00489     {
00490         set_error(inst, errno, "sharedmem_close(): sem_close()");
00491         retval--;
00492     }
00493     /* remove the named semaphore */
00494     if (sem_unlink(inst->name) != 0)
00495     {
00496         set_error(inst, errno, "sharedmem_close(): sem_unlink()");
00497         retval--;
00498     }
00499 
00500     return retval;    
00501 
00502     if (retval == 0)
00503         set_error(inst, 0, NULL);
00504     return retval;
00505 }
00506 
00507 
00508 int sharedmem_resize (sharedmem_t *inst, size_t size)
00509 {
00510     size_t size_ctrl;
00511     size_t size_data;
00512     size_t size_real;
00513 
00514     if (inst == NULL)
00515         return -1;
00516     if (inst->ctrl == NULL)
00517         return -1;
00518 
00519     /* lock the shared memory object */
00520     if (!lock_sem(inst))
00521     {
00522         set_error(inst, errno, "sharedmem_resize(): lock_sem()");
00523         return -1;
00524     }
00525 
00526     /* unmap the data block */
00527     if (munmap(inst->pdata, round_to_page_boundary(inst->mapped_size)) != 0)
00528     {
00529         unlock_sem(inst);
00530         set_error(inst, errno, "sharedmem_resize(): munmap()");
00531         return -1;
00532     }
00533     inst->mapped_size = 0;
00534     inst->pdata = NULL;
00535     /* set the size of the shared memory */
00536     size_ctrl = round_to_page_boundary(sizeof(sharedmem_ctrl_t));
00537     size_data = round_to_page_boundary(size);
00538     size_real = size_ctrl + size_data;
00539     if (ftruncate(inst->fd, size_real) != 0)
00540     {
00541         unlock_sem(inst);
00542         set_error(inst, errno, "sharedmem_resize(): ftruncate()");
00543         return -1;
00544     }
00545     /* map the new data block */
00546     inst->pdata = mmap(NULL, size_data, PROT_READ|PROT_WRITE, MAP_SHARED,
00547         inst->fd, size_ctrl);
00548     if (inst->pdata == NULL)
00549     {
00550         unlock_sem(inst);
00551         set_error(inst, errno, "sharedmem_resize(): mmap()");
00552         return -1;
00553     }
00554     inst->mapped_size = size;
00555     /* set new size to shared memory */
00556     inst->ctrl->size = size;
00557     
00558     /* unlock shared memory */
00559     if (!unlock_sem(inst))
00560     {
00561         set_error(inst, errno, "sharedmem_resize(): unlock_sem()");
00562         return -1;
00563     }
00564 
00565     set_error(inst, 0, NULL);
00566     return 0;
00567 }
00568 
00569 
00570 int sharedmem_resize2 (sharedmem_t *inst)
00571 {
00572     size_t size_ctrl;
00573     size_t size_data;
00574 
00575     if (inst == NULL)
00576         return -1;
00577     if (inst->ctrl == NULL)
00578         return -1;
00579 
00580     /* lock the shared memory object */
00581     if (!lock_sem(inst))
00582     {
00583         set_error(inst, errno, "sharedmem_resize2(): lock_sem()");
00584         return -1;
00585     }
00586 
00587     /* unmap the data block */
00588     if (munmap(inst->pdata, round_to_page_boundary(inst->mapped_size)) != 0)
00589     {
00590         unlock_sem(inst);
00591         set_error(inst, errno, "sharedmem_resize2(): munmap()");
00592         return -1;
00593     }
00594     inst->mapped_size = 0;
00595     inst->pdata = NULL;
00596     size_ctrl = round_to_page_boundary(sizeof(sharedmem_ctrl_t));
00597     size_data = round_to_page_boundary(inst->ctrl->size);
00598     /* map the new data block */
00599     inst->pdata = mmap(NULL, size_data, PROT_READ|PROT_WRITE, MAP_SHARED,
00600         inst->fd, size_ctrl);
00601     if (inst->pdata == NULL)
00602     {
00603         unlock_sem(inst);
00604         set_error(inst, errno, "sharedmem_resize2(): mmap()");
00605         return -1;
00606     }
00607     inst->mapped_size = inst->ctrl->size;
00608     
00609     /* unlock shared memory */
00610     if (!unlock_sem(inst))
00611     {
00612         set_error(inst, errno, "sharedmem_resize2(): unlock_sem()");
00613         return -1;
00614     }
00615 
00616     set_error(inst, 0, NULL);
00617     return 0;
00618 }
00619 
00620 
00621 int sharedmem_size_changed (sharedmem_t *inst)
00622 {
00623     int res;
00624 
00625     if (inst == NULL)
00626         return -1;
00627     if (inst->ctrl == NULL)
00628         return -1;
00629 
00630     /* check for changes in size */
00631     res = (inst->mapped_size == inst->ctrl->size) ? 0 : 1;
00632 
00633     return res;
00634 }
00635 
00636 
00637 int sharedmem_lock (sharedmem_t *inst)
00638 {
00639     return lock_sem(inst);
00640 }
00641 
00642 
00643 int sharedmem_unlock (sharedmem_t *inst)
00644 {
00645     return unlock_sem(inst);
00646 }
00647 
00648 
00649 int sharedmem_get_error_code (sharedmem_t *inst)
00650 {
00651     if (inst == NULL)
00652         return -1;
00653     
00654     return inst->error.code;
00655 }
00656 
00657 
00658 const char * sharedmem_get_error_string (sharedmem_t *inst)
00659 {
00660     if (inst == NULL)
00661         return NULL;
00662     
00663     return inst->error.string;
00664 }

Generated on Thu Sep 13 18:14:21 2007 for libsharedmem by  doxygen 1.5.1