1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
/*
* rocks/shm.c
*
* Routines for managing rocks shared memory.
*
* Copyright (C) 2001 Victor Zandy
* See COPYING for distribution terms.
*/
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include "rs.h"
#include "log.h"
static int
init_shm_lock(shm_t shm)
{
char tmp[] = "/tmp/rocksXXXXXX";
shm->lfd = mkstemp(tmp);
if (0 > shm->lfd) {
rs_log("cannot create lockfile");
return -1;
}
if (0 > unlink(tmp)) {
rs_log("cannot unlink lockfile");
return -1;
}
return 0;
}
static int
fini_shm_lock(shm_t shm)
{
close(shm->lfd);
return 0;
}
static int
do_lock(int fd, int type)
{
struct flock lk;
retry:
lk.l_type = type;
lk.l_start = 0;
lk.l_whence = SEEK_SET;
lk.l_len = 1;
if (0 > fcntl(fd, F_SETLKW, &lk)) {
if (EINTR == errno)
goto retry;
else {
rs_log("fcntl set lock failed: %s", strerror(errno));
return -1;
}
}
return 0;
}
void
rs_shm_lock(shm_t shm)
{
assert(shm);
if (0 > do_lock(shm->lfd, F_WRLCK))
assert(0);
}
void
rs_shm_unlock(shm_t shm)
{
assert(shm);
if (0 > do_lock(shm->lfd, F_UNLCK))
assert(0);
}
int
rs_rock_is_shared(rs_t rs)
{
return rs->shm != NULL;
}
int
rs_shm_has_one_owner(rs_t rs)
{
struct shmid_ds buf;
assert(rs->shm);
if (0 > shmctl(rs->shmid, IPC_STAT, &buf))
assert(0);
return buf.shm_nattch == 1;
}
int
rs_shm_attach(rs_t rs)
{
rs->shm = shmat(rs->shmid, 0, 0);
if ((void *) -1 == rs->shm) {
rs_log("shmat failed!");
return -1;
}
return 0;
}
int
rs_shm_create(rs_t rs)
{
int rv;
rs_log("<%d:%p> shm create", rs->sd, rs);
rs->shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT|SHM_R|SHM_W);
if (-1 == rs->shmid) {
rs_log("shmget failed!");
return -1;
}
rv = rs_shm_attach(rs);
if (0 > rv)
return -1;
if (0 > init_shm_lock(rs->shm)) {
rs_log("cannot initialize shm lock");
return -1;
}
/* mark for deletion now so that it automatically goes away
with last detach */
rv = shmctl(rs->shmid, IPC_RMID, NULL);
if (0 > rv) {
rs_log("shmctl failed!");
return -1;
}
if (rs_opt_hb)
rs_hb_init_shm(rs);
rs->shm->refcnt = rs->refcnt;
return 0;
}
/* Because we mark for deletion in shm_create, unreferenced shared
memory will be destroyed automatically. */
void
rs_shm_detach(rs_t rs)
{
rs_log("<%d:%p> shm detach", rs->sd, rs);
assert(rs->shm);
rs->refcnt = rs->shm->refcnt;
fini_shm_lock(rs->shm);
shmdt(rs->shm);
rs->shm = NULL;
}
|