00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "defs.h"
00022 #include "smi_shm.h"
00023 #include <sys/sem.h>
00024 #include <sys/shm.h>
00025
00026 #define SEMI_READ 0
00027 #define SEMI_WRITE 1
00028 #define SEMI_POST 1
00029 #define SEMI_WAIT -1
00030
00031 typedef struct {
00032 SMIENTITY sq_entity;
00033 int sq_semid_server;
00034 int sq_semid_client;
00035 int sq_shmid_server;
00036 int sq_shmid_client;
00037 struct smi_msg *msg_server;
00038 struct smi_msg *msg_client;
00039 char sq_name[SERVER_NAME_MAX];
00040 struct client_id sq_client;
00041 } SMIQ_SHM;
00042
00043 #ifndef BSD_DERIVED
00044 union semun {
00045 int val;
00046 struct semid_ds *buf;
00047 unsigned short *array;
00048 };
00049 #endif
00050
00051
00052 static void mkshm_name_server(const SMIQ_SHM *p, char *shmname,
00053 size_t shmname_max)
00054 {
00055 snprintf(shmname, shmname_max, "/tmp/smishm-%s", p->sq_name);
00056 }
00057
00058 static int op_semi(int semid, int sem_num, int sem_op)
00059 {
00060 struct sembuf sbuf;
00061 int r;
00062
00063 sbuf.sem_num = sem_num;
00064 sbuf.sem_op = sem_op;
00065 sbuf.sem_flg = 0;
00066 ec_neg1( r = semop(semid, &sbuf, 1) )
00067 return r;
00068
00069 EC_CLEANUP_BGN
00070 return -1;
00071 EC_CLEANUP_END
00072 }
00073
00074 static int init_semi(int semid)
00075 {
00076 union semun arg;
00077 int r;
00078
00079 arg.val = 0;
00080 semctl(semid, SEMI_WRITE, SETVAL, arg);
00081 semctl(semid, SEMI_READ, SETVAL, arg);
00082
00083 ec_neg1( r = op_semi(semid, SEMI_WRITE, SEMI_POST) )
00084 return r;
00085
00086 EC_CLEANUP_BGN
00087 return -1;
00088 EC_CLEANUP_END
00089 }
00090
00091
00092
00093
00094
00095 #define MAX_ATTACHED 20
00096
00097 static void *getaddr(int shmid)
00098 {
00099 static struct {
00100 int shmid;
00101 void *addr;
00102 long time;
00103 } mapped[MAX_ATTACHED];
00104 static long clock;
00105 int i, avail, oldest, r;
00106 static bool first = true;
00107
00108 if (first) {
00109 first = false;
00110 for (i = 0; i < MAX_ATTACHED; i++)
00111 mapped[i].shmid = -1;
00112 }
00113 if (shmid == -1) {
00114 for (i = 0; i < MAX_ATTACHED; i++)
00115 if (mapped[i].shmid != -1) {
00116 (void)shmdt(mapped[i].addr);
00117 mapped[i].shmid = -1;
00118 }
00119 return NULL;
00120 }
00121 clock++;
00122 avail = -1;
00123 for (i = 0; i < MAX_ATTACHED; i++) {
00124 if (mapped[i].shmid == shmid) {
00125 mapped[i].time = clock;
00126 return mapped[i].addr;
00127 }
00128 if (mapped[i].shmid == -1 && avail == -1)
00129 avail = i;
00130 }
00131 if (avail == -1) {
00132 oldest = -1;
00133 for (i = 0; i < MAX_ATTACHED; i++)
00134 if (oldest == -1 || mapped[i].time < oldest) {
00135 oldest = mapped[i].time;
00136 avail = i;
00137 }
00138 r = shmdt(mapped[avail].addr);
00139 ec_neg1( r )
00140 }
00141 mapped[avail].addr = shmat(shmid, NULL, 0);
00142 ec_neg1( mapped[avail].addr )
00143 mapped[avail].time = clock;
00144 mapped[avail].shmid = shmid;
00145 return mapped[avail].addr;
00146
00147 EC_CLEANUP_BGN
00148 return NULL;
00149 EC_CLEANUP_END
00150 }
00151
00152
00153
00154 SMIQ *smi_open_shm(const char *name, SMIENTITY entity, size_t msgsize)
00155 {
00156 SMIQ_SHM *p = NULL;
00157 char shmname[FILENAME_MAX];
00158 int i;
00159 key_t key;
00160
00161 ec_null( p = calloc(1, sizeof(SMIQ_SHM)) )
00162 p->sq_entity = entity;
00163 if (strlen(name) >= SERVER_NAME_MAX) {
00164 errno = ENAMETOOLONG;
00165 EC_FAIL
00166 }
00167 strcpy(p->sq_name, name);
00168 mkshm_name_server(p, shmname, sizeof(shmname));
00169 (void)close(open(shmname, O_WRONLY | O_CREAT, 0));
00170 ec_neg1( key = ftok(shmname, 1) )
00171 if (p->sq_entity == SMI_SERVER) {
00172 if ((p->sq_semid_server = semget(key, 2, PERM_FILE)) != -1)
00173 (void)shmctl(p->sq_semid_server, IPC_RMID, NULL);
00174 ec_neg1( p->sq_semid_server = semget(key, 2,
00175 PERM_FILE | IPC_CREAT) )
00176 p->sq_semid_client = -1;
00177 if ((p->sq_shmid_server = shmget(key, 0, PERM_FILE)) != -1)
00178 (void)shmctl(p->sq_shmid_server, IPC_RMID, NULL);
00179 ec_neg1( p->sq_shmid_server = shmget(key, msgsize,
00180 PERM_FILE | IPC_CREAT) )
00181 p->sq_shmid_client = -1;
00182 ec_neg1( init_semi(p->sq_semid_server) )
00183 }
00184 else {
00185 ec_neg1( p->sq_semid_server = semget(key, 2, PERM_FILE) )
00186 ec_neg1( p->sq_semid_client = semget(IPC_PRIVATE, 2,
00187 PERM_FILE | IPC_CREAT) )
00188 ec_neg1( p->sq_shmid_server = shmget(key, msgsize, PERM_FILE) )
00189 ec_neg1( p->sq_shmid_client = shmget(IPC_PRIVATE, msgsize,
00190 PERM_FILE | IPC_CREAT) )
00191 ec_neg1( p->msg_client = shmat(p->sq_shmid_client, NULL, 0) )
00192 ec_neg1( init_semi(p->sq_semid_client) )
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207 for (i = 0; !smi_client_nowait && i < 10; i++) {
00208 union semun arg;
00209 struct semid_ds ds;
00210
00211 arg.buf = &ds;
00212 ec_neg1( semctl(p->sq_semid_server, SEMI_WRITE, IPC_STAT,
00213 arg) )
00214 if (ds.sem_otime > 0)
00215 break;
00216 sleep(1);
00217 }
00218 }
00219 ec_neg1( p->msg_server = shmat(p->sq_shmid_server, NULL, 0) )
00220 return (SMIQ *)p;
00221
00222 EC_CLEANUP_BGN
00223 free(p);
00224 return NULL;
00225 EC_CLEANUP_END
00226 }
00227
00228 bool smi_close_shm(SMIQ *sqp)
00229 {
00230 SMIQ_SHM *p = (SMIQ_SHM *)sqp;
00231
00232 if (p->sq_entity == SMI_SERVER) {
00233 char shmname[FILENAME_MAX];
00234
00235 (void)getaddr(-1);
00236 #ifdef DARWIN
00237 {
00238 union semun dummy;
00239 ec_neg1( semctl(p->sq_semid_server, 0, IPC_RMID, dummy) )
00240 }
00241 #else
00242 ec_neg1( semctl(p->sq_semid_server, 0, IPC_RMID) )
00243 #endif
00244 (void)shmdt(p->msg_server);
00245 (void)shmctl(p->sq_shmid_server, IPC_RMID, NULL);
00246 mkshm_name_server(p, shmname, sizeof(shmname));
00247 (void)unlink(shmname);
00248 }
00249 else {
00250
00251 #ifndef FREEBSD
00252 #ifdef DARWIN
00253 {
00254 union semun dummy;
00255 ec_neg1( semctl(p->sq_semid_client, 0, IPC_RMID, dummy) )
00256 }
00257 #else
00258 ec_neg1( semctl(p->sq_semid_client, 0, IPC_RMID) )
00259 #endif
00260 #endif
00261 (void)shmdt(p->msg_server);
00262 (void)shmdt(p->msg_client);
00263 (void)shmctl(p->sq_shmid_client, IPC_RMID, NULL);
00264 }
00265 free(p);
00266 return true;
00267
00268 EC_CLEANUP_BGN
00269 return false;
00270 EC_CLEANUP_END
00271 }
00272
00273
00274 bool smi_send_getaddr_shm(SMIQ *sqp, struct client_id *client, void **addr)
00275 {
00276 SMIQ_SHM *p = (SMIQ_SHM *)sqp;
00277 int semid_receiver;
00278
00279 if (p->sq_entity == SMI_SERVER) {
00280 semid_receiver = client->c_id2;
00281 p->sq_client = *client;
00282 }
00283 else
00284 semid_receiver = p->sq_semid_server;
00285 ec_neg1( op_semi(semid_receiver, SEMI_WRITE, SEMI_WAIT) )
00286 if (p->sq_entity == SMI_SERVER)
00287 ec_null( *addr = getaddr(client->c_id1) )
00288 else {
00289 *addr = p->msg_server;
00290 ((struct smi_msg *)*addr)->smi_client.c_id1 = p->sq_shmid_client;
00291 ((struct smi_msg *)*addr)->smi_client.c_id2 = p->sq_semid_client;
00292 }
00293 return true;
00294
00295 EC_CLEANUP_BGN
00296 return false;
00297 EC_CLEANUP_END
00298 }
00299
00300 bool smi_send_release_shm(SMIQ *sqp)
00301 {
00302 SMIQ_SHM *p = (SMIQ_SHM *)sqp;
00303 int semid_receiver;
00304
00305 if (p->sq_entity == SMI_SERVER)
00306 semid_receiver = p->sq_client.c_id2;
00307 else
00308 semid_receiver = p->sq_semid_server;
00309 ec_neg1( op_semi(semid_receiver, SEMI_READ, SEMI_POST) )
00310 return true;
00311
00312 EC_CLEANUP_BGN
00313 return false;
00314 EC_CLEANUP_END
00315 }
00316
00317 bool smi_receive_getaddr_shm(SMIQ *sqp, void **addr)
00318 {
00319 SMIQ_SHM *p = (SMIQ_SHM *)sqp;
00320 int semid_receiver;
00321
00322 if (p->sq_entity == SMI_SERVER)
00323 semid_receiver = p->sq_semid_server;
00324 else
00325 semid_receiver = p->sq_semid_client;
00326 ec_neg1( op_semi(semid_receiver, SEMI_READ, SEMI_WAIT) )
00327 if (p->sq_entity == SMI_SERVER)
00328 *addr = p->msg_server;
00329 else
00330 *addr = p->msg_client;
00331 return true;
00332
00333 EC_CLEANUP_BGN
00334 return false;
00335 EC_CLEANUP_END
00336 }
00337
00338 bool smi_receive_release_shm(SMIQ *sqp)
00339 {
00340 SMIQ_SHM *p = (SMIQ_SHM *)sqp;
00341 int semid_receiver;
00342
00343 if (p->sq_entity == SMI_SERVER)
00344 semid_receiver = p->sq_semid_server;
00345 else
00346 semid_receiver = p->sq_semid_client;
00347 ec_neg1( op_semi(semid_receiver, SEMI_WRITE, SEMI_POST) )
00348 return true;
00349
00350 EC_CLEANUP_BGN
00351 return false;
00352 EC_CLEANUP_END
00353 }
00354