00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
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
00055
00056 long sharedmem_page_size = 0;
00057
00058
00059
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
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
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
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
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
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
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
00167 res = munmap(inst->pdata, size_data);
00168 inst->mapped_size = 0;
00169 inst->pdata = NULL;
00170
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
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
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
00231
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
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
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
00305 if (init_page_size(inst) != 0)
00306 return -1;
00307 strncpy(inst->name, name, SHAREDMEM_NAME_LENGTH - 1);
00308
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
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
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
00335 if (do_maps(inst, size) != 0)
00336 goto create_exit;
00337
00338
00339 if (init_mutex(inst) != 0)
00340 goto create_exit;
00341
00342 if (init_cond(inst) != 0)
00343 goto create_exit;
00344
00345
00346 inst->ctrl->size = size;
00347 inst->ctrl->ref++;
00348
00349 set_error(inst, 0, NULL);
00350
00351
00352 unlock_sem(inst);
00353 return 0;
00354
00355 create_exit:
00356
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
00370 if (init_page_size(inst) != 0)
00371 return -1;
00372 strncpy(inst->name, name, SHAREDMEM_NAME_LENGTH - 1);
00373
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
00381 if (!lock_sem(inst))
00382 {
00383 set_error(inst, errno, "sharedmem_open(): lock_sem()");
00384 return -1;
00385 }
00386
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
00394 if (do_maps(inst, 0) != 0)
00395 goto open_exit;
00396
00397
00398 inst->ctrl->ref++;
00399
00400 set_error(inst, 0, NULL);
00401
00402
00403 unlock_sem(inst);
00404 return 0;
00405
00406 open_exit:
00407
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
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
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
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
00472 if (undo_maps(inst) != 0)
00473 retval--;
00474
00475 if (close(inst->fd) != 0)
00476 {
00477 set_error(inst, errno, "sharedmem_close(): close()");
00478 retval--;
00479 }
00480 inst->fd = -1;
00481
00482 if (shm_unlink(inst->name) != 0)
00483 {
00484 set_error(inst, errno, "sharedmem_close(): shm_unlink()");
00485 retval--;
00486 }
00487
00488 if (sem_close(inst->sem) != 0)
00489 {
00490 set_error(inst, errno, "sharedmem_close(): sem_close()");
00491 retval--;
00492 }
00493
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
00520 if (!lock_sem(inst))
00521 {
00522 set_error(inst, errno, "sharedmem_resize(): lock_sem()");
00523 return -1;
00524 }
00525
00526
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
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
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
00556 inst->ctrl->size = size;
00557
00558
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
00581 if (!lock_sem(inst))
00582 {
00583 set_error(inst, errno, "sharedmem_resize2(): lock_sem()");
00584 return -1;
00585 }
00586
00587
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
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
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
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 }