make #includes consistent
[hiphop-php.git] / hphp / runtime / ext / ext_ipc.cpp
blobf44053379d400e19d62746732f5c9386ced961ac
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
6 | Copyright (c) 1997-2010 The PHP Group |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
18 #include "hphp/runtime/ext/ext_ipc.h"
19 #include "hphp/runtime/ext/ext_variable.h"
20 #include "hphp/runtime/base/variable_unserializer.h"
21 #include "hphp/util/lock.h"
22 #include "hphp/util/alloc.h"
24 #include <memory>
26 #include "sys/types.h"
27 #include "sys/ipc.h"
28 #include "sys/msg.h"
29 #include "sys/sem.h"
30 #include "sys/shm.h"
32 #if defined(__APPLE__) || defined(__FreeBSD__)
33 # include <sys/msgbuf.h>
34 # define MSGBUF_MTYPE(b) (b)->msg_magic
35 # ifdef __APPLE__
36 # define MSGBUF_MTEXT(b) (b)->msg_bufc
37 # else
38 # define MSGBUF_MTEXT(b) (b)->msg_ptr
39 # endif
40 #else
41 # define MSGBUF_MTYPE(b) (b)->mtype
42 # define MSGBUF_MTEXT(b) (b)->mtext
43 #endif
45 using HPHP::Util::ScopedMem;
47 namespace HPHP {
48 IMPLEMENT_DEFAULT_EXTENSION(sysvmsg);
49 IMPLEMENT_DEFAULT_EXTENSION(sysvsem);
50 IMPLEMENT_DEFAULT_EXTENSION(sysvshm);
51 ///////////////////////////////////////////////////////////////////////////////
53 int64_t f_ftok(CStrRef pathname, CStrRef proj) {
54 if (pathname.empty()) {
55 raise_warning("Pathname is empty");
56 return -1;
58 if (proj.length() != 1) {
59 raise_warning("Project identifier has to be one character int64: %s",
60 proj.c_str());
61 return -1;
63 return ftok(pathname.c_str(), (int)proj[0]);
66 ///////////////////////////////////////////////////////////////////////////////
67 // message queue
69 class MessageQueue : public ResourceData {
70 public:
71 DECLARE_OBJECT_ALLOCATION(MessageQueue)
73 int64_t key;
74 int id;
76 static StaticString s_class_name;
77 // overriding ResourceData
78 virtual CStrRef o_getClassNameHook() const { return s_class_name; }
80 IMPLEMENT_OBJECT_ALLOCATION(MessageQueue)
82 StaticString MessageQueue::s_class_name("MessageQueue");
84 Variant f_msg_get_queue(int64_t key, int64_t perms /* = 0666 */) {
85 int id = msgget(key, 0);
86 if (id < 0) {
87 id = msgget(key, IPC_CREAT | IPC_EXCL | perms);
88 if (id < 0) {
89 raise_warning("Failed to create message queue for key 0x%" PRIx64 ": %s",
90 key, Util::safe_strerror(errno).c_str());
91 return false;
94 MessageQueue *q = NEWOBJ(MessageQueue)();
95 q->key = key;
96 q->id = id;
97 return Object(q);
100 bool f_msg_queue_exists(int64_t key) {
101 return msgget(key, 0) >= 0;
104 bool f_msg_remove_queue(CObjRef queue) {
105 MessageQueue *q = queue.getTyped<MessageQueue>();
106 if (!q) {
107 raise_warning("Invalid message queue was specified");
108 return false;
111 return msgctl(q->id, IPC_RMID, NULL) == 0;
114 static const StaticString s_msg_perm_uid("msg_perm.uid");
115 static const StaticString s_msg_perm_gid("msg_perm.gid");
116 static const StaticString s_msg_perm_mode("msg_perm.mode");
117 static const StaticString s_msg_stime("msg_stime");
118 static const StaticString s_msg_rtime("msg_rtime");
119 static const StaticString s_msg_ctime("msg_ctime");
120 static const StaticString s_msg_qnum("msg_qnum");
121 static const StaticString s_msg_qbytes("msg_qbytes");
122 static const StaticString s_msg_lspid("msg_lspid");
123 static const StaticString s_msg_lrpid("msg_lrpid");
125 bool f_msg_set_queue(CObjRef queue, CArrRef data) {
126 MessageQueue *q = queue.getTyped<MessageQueue>();
127 if (!q) {
128 raise_warning("Invalid message queue was specified");
129 return false;
132 struct msqid_ds stat;
133 if (msgctl(q->id, IPC_STAT, &stat) == 0) {
134 Variant value;
135 value = data[s_msg_perm_uid];
136 if (!value.isNull()) stat.msg_perm.uid = (int64_t)value;
137 value = data[s_msg_perm_gid];
138 if (!value.isNull()) stat.msg_perm.uid = (int64_t)value;
139 value = data[s_msg_perm_mode];
140 if (!value.isNull()) stat.msg_perm.uid = (int64_t)value;
141 value = data[s_msg_qbytes];
142 if (!value.isNull()) stat.msg_perm.uid = (int64_t)value;
144 return msgctl(q->id, IPC_SET, &stat) == 0;
147 return false;
150 Array f_msg_stat_queue(CObjRef queue) {
151 MessageQueue *q = queue.getTyped<MessageQueue>();
152 if (!q) {
153 raise_warning("Invalid message queue was specified");
154 return Array();
157 struct msqid_ds stat;
158 if (msgctl(q->id, IPC_STAT, &stat) == 0) {
159 Array data;
160 data.set(s_msg_perm_uid, (int64_t)stat.msg_perm.uid);
161 data.set(s_msg_perm_gid, (int64_t)stat.msg_perm.gid);
162 data.set(s_msg_perm_mode, stat.msg_perm.mode);
163 data.set(s_msg_stime, (int64_t)stat.msg_stime);
164 data.set(s_msg_rtime, (int64_t)stat.msg_rtime);
165 data.set(s_msg_ctime, (int64_t)stat.msg_ctime);
166 data.set(s_msg_qnum, (int64_t)stat.msg_qnum);
167 data.set(s_msg_qbytes, (int64_t)stat.msg_qbytes);
168 data.set(s_msg_lspid, stat.msg_lspid);
169 data.set(s_msg_lrpid, stat.msg_lrpid);
170 return data;
173 return Array();
176 bool f_msg_send(CObjRef queue, int64_t msgtype, CVarRef message,
177 bool serialize /* = true */, bool blocking /* = true */,
178 VRefParam errorcode /* = null */) {
179 MessageQueue *q = queue.getTyped<MessageQueue>();
180 if (!q) {
181 raise_warning("Invalid message queue was specified");
182 return false;
185 struct msgbuf *buffer = NULL;
186 String data;
187 if (serialize) {
188 data = f_serialize(message);
189 } else {
190 data = message.toString();
192 int len = data.length();
193 buffer = (struct msgbuf *)calloc(len + sizeof(struct msgbuf), 1);
194 ScopedMem deleter(buffer);
195 MSGBUF_MTYPE(buffer) = msgtype;
196 memcpy(MSGBUF_MTEXT(buffer), data.c_str(), len + 1);
198 int result = msgsnd(q->id, buffer, len, blocking ? 0 : IPC_NOWAIT);
199 if (result < 0) {
200 int err = errno;
201 raise_warning("Unable to send message: %s",
202 Util::safe_strerror(err).c_str());
203 if (!errorcode.isNull()) {
204 errorcode = err;
206 return false;
208 return true;
211 bool f_msg_receive(CObjRef queue, int64_t desiredmsgtype, VRefParam msgtype,
212 int64_t maxsize, VRefParam message,
213 bool unserialize /* = true */,
214 int64_t flags /* = 0 */, VRefParam errorcode /* = null */) {
215 MessageQueue *q = queue.getTyped<MessageQueue>();
216 if (!q) {
217 raise_warning("Invalid message queue was specified");
218 return false;
221 if (maxsize <= 0) {
222 raise_warning("Maximum size of the message has to be greater than zero");
223 return false;
226 int64_t realflags = 0;
227 if (flags != 0) {
228 #if !defined(__APPLE__) && !defined(__FreeBSD__)
229 if (flags & k_MSG_EXCEPT) realflags |= MSG_EXCEPT;
230 #endif
231 if (flags & k_MSG_NOERROR) realflags |= MSG_NOERROR;
232 if (flags & k_MSG_IPC_NOWAIT) realflags |= IPC_NOWAIT;
235 struct msgbuf *buffer =
236 (struct msgbuf *)calloc(maxsize + sizeof(struct msgbuf), 1);
237 ScopedMem deleter(buffer);
239 int result = msgrcv(q->id, buffer, maxsize, desiredmsgtype, realflags);
240 if (result < 0) {
241 int err = errno;
242 raise_warning("Unable to receive message: %s",
243 Util::safe_strerror(err).c_str());
244 if (!errorcode.isNull()) {
245 errorcode = err;
247 return false;
250 msgtype = (int)MSGBUF_MTYPE(buffer);
251 if (unserialize) {
252 const char *bufText = (const char *)MSGBUF_MTEXT(buffer);
253 uint bufLen = strlen(bufText);
254 VariableUnserializer vu(bufText, bufLen,
255 VariableUnserializer::Serialize);
256 try {
257 message = vu.unserialize();
258 } catch (Exception &e) {
259 raise_warning("Message corrupted");
260 return false;
262 } else {
263 message = (const char *)MSGBUF_MTEXT(buffer);
266 return true;
269 ///////////////////////////////////////////////////////////////////////////////
270 // semaphore
272 /* Semaphore functions using System V semaphores. Each semaphore
273 * actually consists of three semaphores allocated as a unit under the
274 * same key. Semaphore 0 (SYSVSEM_SEM) is the actual semaphore, it is
275 * initialized to max_acquire and decremented as processes acquire it.
276 * The value of semaphore 1 (SYSVSEM_USAGE) is a count of the number
277 * of processes using the semaphore. After calling semget(), if a
278 * process finds that the usage count is 1, it will set the value of
279 * SYSVSEM_SEM to max_acquire. This allows max_acquire to be set and
280 * track the PHP code without having a global init routine or external
281 * semaphore init code. Except see the bug regarding a race condition
282 * php_sysvsem_get(). Semaphore 2 (SYSVSEM_SETVAL) serializes the
283 * calls to GETVAL SYSVSEM_USAGE and SETVAL SYSVSEM_SEM. It can be
284 * acquired only when it is zero.
286 #define SYSVSEM_SEM 0
287 #define SYSVSEM_USAGE 1
288 #define SYSVSEM_SETVAL 2
290 union semun {
291 int val; /* value for SETVAL */
292 struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
293 unsigned short *array; /* array for GETALL, SETALL */
294 /* Linux specific part: */
295 struct seminfo *__buf; /* buffer for IPC_INFO */
298 class Semaphore : public SweepableResourceData {
299 public:
300 int key; // For error reporting.
301 int semid; // Returned by semget()
302 int count; // Acquire count for auto-release.
303 int auto_release; // flag that says to auto-release.
305 static StaticString s_class_name;
306 // overriding ResourceData
307 virtual CStrRef o_getClassNameHook() const { return s_class_name; }
309 bool op(bool acquire) {
310 struct sembuf sop;
312 if (!acquire && count == 0) {
313 raise_warning("SysV semaphore %d (key 0x%x) is not currently acquired",
314 o_getId(), key);
315 return false;
318 sop.sem_num = SYSVSEM_SEM;
319 sop.sem_op = acquire ? -1 : 1;
320 sop.sem_flg = SEM_UNDO;
322 while (semop(semid, &sop, 1) == -1) {
323 if (errno != EINTR) {
324 raise_warning("failed to %s key 0x%x: %s",
325 acquire ? "acquire" : "release",
326 key, Util::safe_strerror(errno).c_str());
327 return false;
331 count -= acquire ? -1 : 1;
332 return true;
335 ~Semaphore() {
336 struct sembuf sop[2];
337 int opcount = 1;
340 * if count == -1, semaphore has been removed
341 * Need better way to handle this
343 if (count == -1 || !auto_release) {
344 return;
347 /* Decrement the usage count. */
348 sop[0].sem_num = SYSVSEM_USAGE;
349 sop[0].sem_op = -1;
350 sop[0].sem_flg = SEM_UNDO;
352 /* Release the semaphore if it has been acquired but not released. */
353 if (count) {
354 sop[1].sem_num = SYSVSEM_SEM;
355 sop[1].sem_op = count;
356 sop[1].sem_flg = SEM_UNDO;
357 opcount++;
360 semop(semid, sop, opcount);
364 StaticString Semaphore::s_class_name("Semaphore");
366 bool f_sem_acquire(CObjRef sem_identifier) {
367 return sem_identifier.getTyped<Semaphore>()->op(true);
370 bool f_sem_release(CObjRef sem_identifier) {
371 return sem_identifier.getTyped<Semaphore>()->op(false);
375 * Return an id for the semaphore with the given key, and allow max_acquire
376 * (default 1) processes to acquire it simultaneously.
378 Variant f_sem_get(int64_t key, int64_t max_acquire /* = 1 */,
379 int64_t perm /* = 0666 */, bool auto_release /* = true */) {
380 /* Get/create the semaphore. Note that we rely on the semaphores
381 * being zeroed when they are created. Despite the fact that
382 * the(?) Linux semget() man page says they are not initialized,
383 * the kernel versions 2.0.x and 2.1.z do in fact zero them.
385 int semid = semget(key, 3, perm|IPC_CREAT);
386 if (semid == -1) {
387 raise_warning("failed for key 0x%" PRIx64 ": %s", key,
388 Util::safe_strerror(errno).c_str());
389 return false;
392 /* Find out how many processes are using this semaphore. Note
393 * that on Linux (at least) there is a race condition here because
394 * semaphore undo on process exit is not atomic, so we could
395 * acquire SYSVSEM_SETVAL before a crashed process has decremented
396 * SYSVSEM_USAGE in which case count will be greater than it
397 * should be and we won't set max_acquire. Fortunately this
398 * doesn't actually matter in practice.
401 /* Wait for sem 1 to be zero . . . */
402 struct sembuf sop[3];
403 sop[0].sem_num = SYSVSEM_SETVAL;
404 sop[0].sem_op = 0;
405 sop[0].sem_flg = 0;
407 /* . . . and increment it so it becomes non-zero . . . */
408 sop[1].sem_num = SYSVSEM_SETVAL;
409 sop[1].sem_op = 1;
410 sop[1].sem_flg = SEM_UNDO;
412 /* . . . and increment the usage count. */
413 sop[2].sem_num = SYSVSEM_USAGE;
414 sop[2].sem_op = 1;
415 sop[2].sem_flg = SEM_UNDO;
417 while (semop(semid, sop, 3) == -1) {
418 if (errno != EINTR) {
419 raise_warning("failed acquiring SYSVSEM_SETVAL for key 0x%" PRIx64 ": %s",
420 key, Util::safe_strerror(errno).c_str());
421 break;
425 /* Get the usage count. */
426 int count = semctl(semid, SYSVSEM_USAGE, GETVAL, NULL);
427 if (count == -1) {
428 raise_warning("failed for key 0x%" PRIx64 ": %s", key,
429 Util::safe_strerror(errno).c_str());
432 /* If we are the only user, then take this opportunity to set the max. */
433 if (count == 1) {
434 union semun semarg;
435 semarg.val = max_acquire;
436 if (semctl(semid, SYSVSEM_SEM, SETVAL, semarg) == -1) {
437 raise_warning("failed for key 0x%" PRIx64 ": %s", key,
438 Util::safe_strerror(errno).c_str());
442 /* Set semaphore 1 back to zero. */
443 sop[0].sem_num = SYSVSEM_SETVAL;
444 sop[0].sem_op = -1;
445 sop[0].sem_flg = SEM_UNDO;
446 while (semop(semid, sop, 1) == -1) {
447 if (errno != EINTR) {
448 raise_warning("failed releasing SYSVSEM_SETVAL for key 0x%" PRIx64 ": %s",
449 key, Util::safe_strerror(errno).c_str());
450 break;
454 Semaphore *sem_ptr = new Semaphore();
455 sem_ptr->key = key;
456 sem_ptr->semid = semid;
457 sem_ptr->count = 0;
458 sem_ptr->auto_release = auto_release;
459 return Object(sem_ptr);
463 * contributed by Gavin Sherry gavin@linuxworld.com.au
464 * Fri Mar 16 00:50:13 EST 2001
466 bool f_sem_remove(CObjRef sem_identifier) {
467 Semaphore *sem_ptr = sem_identifier.getTyped<Semaphore>();
469 union semun un;
470 struct semid_ds buf;
471 un.buf = &buf;
472 if (semctl(sem_ptr->semid, 0, IPC_STAT, un) < 0) {
473 raise_warning("SysV semaphore %d does not (any longer) exist",
474 sem_identifier->o_getId());
475 return false;
478 if (semctl(sem_ptr->semid, 0, IPC_RMID, un) < 0) {
479 raise_warning("failed for SysV sempphore %d: %s",
480 sem_identifier->o_getId(),
481 Util::safe_strerror(errno).c_str());
482 return false;
485 /* let release_sysvsem_sem know we have removed
486 * the semaphore to avoid issues with releasing.
488 sem_ptr->count = -1;
489 return true;
492 ///////////////////////////////////////////////////////////////////////////////
493 // shared memory
495 typedef struct {
496 long key;
497 long length;
498 long next;
499 char mem;
500 } sysvshm_chunk;
502 typedef struct {
503 char magic[8];
504 long start;
505 long end;
506 long free;
507 long total;
508 } sysvshm_chunk_head;
510 class sysvshm_shm {
511 public:
512 key_t key; /* Key set by user */
513 long id; /* Returned by shmget. */
514 sysvshm_chunk_head *ptr; /* memoryaddress of shared memory */
516 ~sysvshm_shm() {
517 shmdt((void *)ptr);
521 class shm_set : public std::set<sysvshm_shm*> {
522 public:
523 ~shm_set() {
524 for (std::set<sysvshm_shm*>::iterator iter = begin(); iter != end();
525 ++iter) {
526 delete *iter;
531 static Mutex g_shm_mutex;
532 static shm_set g_shms;
534 static long check_shm_data(sysvshm_chunk_head *ptr, long key) {
535 long pos;
536 sysvshm_chunk *shm_var;
538 pos = ptr->start;
540 for (;;) {
541 if (pos >= ptr->end) {
542 return -1;
544 shm_var = (sysvshm_chunk*) ((char *) ptr + pos);
545 if (shm_var->key == key) {
546 return pos;
548 pos += shm_var->next;
550 if (shm_var->next <= 0 || pos < ptr->start) {
551 return -1;
554 return -1;
557 static int remove_shm_data(sysvshm_chunk_head *ptr, long shm_varpos) {
558 sysvshm_chunk *chunk_ptr, *next_chunk_ptr;
559 long memcpy_len;
561 chunk_ptr = (sysvshm_chunk *) ((char *) ptr + shm_varpos);
562 next_chunk_ptr =
563 (sysvshm_chunk *) ((char *) ptr + shm_varpos + chunk_ptr->next);
565 memcpy_len = ptr->end-shm_varpos - chunk_ptr->next;
566 ptr->free += chunk_ptr->next;
567 ptr->end -= chunk_ptr->next;
568 if (memcpy_len > 0) {
569 memcpy(chunk_ptr, next_chunk_ptr, memcpy_len);
571 return 0;
574 static int put_shm_data(sysvshm_chunk_head *ptr, long key, char *data,
575 long len) {
576 sysvshm_chunk *shm_var;
577 long total_size;
578 long shm_varpos;
580 total_size = ((long) (len + sizeof(sysvshm_chunk) - 1) / 4) * 4 +
581 4; /* 4-byte alligment */
583 if ((shm_varpos = check_shm_data(ptr, key)) > 0) {
584 remove_shm_data(ptr, shm_varpos);
587 if (ptr->free < total_size) {
588 return -1; /* not enough memeory */
591 shm_var = (sysvshm_chunk *) ((char *) ptr + ptr->end);
592 shm_var->key = key;
593 shm_var->length = len;
594 shm_var->next = total_size;
595 memcpy(&(shm_var->mem), data, len);
596 ptr->end += total_size;
597 ptr->free -= total_size;
598 return 0;
601 Variant f_shm_attach(int64_t shm_key, int64_t shm_size /* = 10000 */,
602 int64_t shm_flag /* = 0666 */) {
603 char *shm_ptr;
604 long shm_id;
606 if (shm_size < 1) {
607 raise_warning("Segment size must be greater then zero.");
608 return false;
611 std::unique_ptr<sysvshm_shm> shm_list_ptr(new sysvshm_shm());
613 /* get the id from a specified key or create new shared memory */
614 if ((shm_id = shmget(shm_key, 0, 0)) < 0) {
615 if (shm_size < (int)sizeof(sysvshm_chunk_head)) {
616 raise_warning("failed for key 0x%" PRIx64 ": memorysize too small", shm_key);
617 return false;
619 if ((shm_id = shmget(shm_key, shm_size, shm_flag | IPC_CREAT | IPC_EXCL))
620 < 0) {
621 raise_warning("failed for key 0x%" PRIx64 ": %s", shm_key,
622 Util::safe_strerror(errno).c_str());
623 return false;
627 if ((shm_ptr = (char*)shmat(shm_id, NULL, 0)) == (char *)-1) {
628 raise_warning("failed for key 0x%" PRIx64 ": %s", shm_key,
629 Util::safe_strerror(errno).c_str());
630 return false;
633 /* check if shm is already initialized */
634 sysvshm_chunk_head *chunk_ptr = (sysvshm_chunk_head *)shm_ptr;
635 if (strcmp((char*) &(chunk_ptr->magic), "PHP_SM") != 0) {
636 strcpy((char*) &(chunk_ptr->magic), "PHP_SM");
637 chunk_ptr->start = sizeof(sysvshm_chunk_head);
638 chunk_ptr->end = chunk_ptr->start;
639 chunk_ptr->total = shm_size;
640 chunk_ptr->free = shm_size-chunk_ptr->end;
643 shm_list_ptr->key = shm_key;
644 shm_list_ptr->id = shm_id;
645 shm_list_ptr->ptr = chunk_ptr;
646 Lock lock(g_shm_mutex);
647 int64_t ret = (int64_t)shm_list_ptr.get();
648 g_shms.insert(shm_list_ptr.release());
649 return ret;
652 bool f_shm_detach(int64_t shm_identifier) {
653 Lock lock(g_shm_mutex);
654 std::set<sysvshm_shm*>::iterator iter =
655 g_shms.find((sysvshm_shm*)shm_identifier);
656 if (iter == g_shms.end()) {
657 raise_warning("%" PRId64 " is not a SysV shared memory index",
658 shm_identifier);
659 return false;
661 g_shms.erase(iter);
662 delete (sysvshm_shm*)shm_identifier;
663 return true;
666 bool f_shm_remove(int64_t shm_identifier) {
667 Lock lock(g_shm_mutex);
668 std::set<sysvshm_shm*>::iterator iter =
669 g_shms.find((sysvshm_shm*)shm_identifier);
670 if (iter == g_shms.end()) {
671 raise_warning("%" PRId64 " is not a SysV shared memory index", shm_identifier);
672 return false;
674 sysvshm_shm *shm_list_ptr = *iter;
676 if (shmctl(shm_list_ptr->id, IPC_RMID,NULL) < 0) {
677 raise_warning("failed for key 0x%x, id %" PRId64 ": %s", shm_list_ptr->key,
678 shm_identifier, Util::safe_strerror(errno).c_str());
679 return false;
681 return true;
684 Variant f_shm_get_var(int64_t shm_identifier, int64_t variable_key) {
685 Lock lock(g_shm_mutex);
686 std::set<sysvshm_shm*>::iterator iter =
687 g_shms.find((sysvshm_shm*)shm_identifier);
688 if (iter == g_shms.end()) {
689 raise_warning("%" PRId64 " is not a SysV shared memory index",
690 shm_identifier);
691 return false;
693 sysvshm_shm *shm_list_ptr = *iter;
695 long shm_varpos = check_shm_data(shm_list_ptr->ptr, variable_key);
696 if (shm_varpos < 0) {
697 return false;
700 sysvshm_chunk *shm_var =
701 (sysvshm_chunk*)((char *)shm_list_ptr->ptr + shm_varpos);
702 return unserialize_from_buffer(&shm_var->mem, shm_var->length);
705 bool f_shm_has_var(int64_t shm_identifier, int64_t variable_key) {
706 Lock lock(g_shm_mutex);
707 std::set<sysvshm_shm*>::iterator iter =
708 g_shms.find((sysvshm_shm*)shm_identifier);
709 if (iter == g_shms.end()) {
710 raise_warning("%" PRId64 " is not a SysV shared memory index",
711 shm_identifier);
712 return false;
714 sysvshm_shm *shm_list_ptr = *iter;
716 long shm_varpos = check_shm_data(shm_list_ptr->ptr, variable_key);
717 return shm_varpos >= 0;
720 bool f_shm_put_var(int64_t shm_identifier, int64_t variable_key,
721 CVarRef variable) {
722 Lock lock(g_shm_mutex);
723 std::set<sysvshm_shm*>::iterator iter =
724 g_shms.find((sysvshm_shm*)shm_identifier);
725 if (iter == g_shms.end()) {
726 raise_warning("%" PRId64 " is not a SysV shared memory index",
727 shm_identifier);
728 return false;
730 sysvshm_shm *shm_list_ptr = *iter;
732 /* setup string-variable and serialize */
733 String serialized = f_serialize(variable);
735 /* insert serialized variable into shared memory */
736 int ret = put_shm_data(shm_list_ptr->ptr, variable_key,
737 (char*)serialized.data(), serialized.size());
738 if (ret == -1) {
739 raise_warning("not enough shared memory left");
740 return false;
742 return true;
745 bool f_shm_remove_var(int64_t shm_identifier, int64_t variable_key) {
746 Lock lock(g_shm_mutex);
747 std::set<sysvshm_shm*>::iterator iter =
748 g_shms.find((sysvshm_shm*)shm_identifier);
749 if (iter == g_shms.end()) {
750 raise_warning("%" PRId64 " is not a SysV shared memory index", shm_identifier);
751 return false;
753 sysvshm_shm *shm_list_ptr = *iter;
755 long shm_varpos = check_shm_data(shm_list_ptr->ptr, variable_key);
756 if (shm_varpos < 0) {
757 raise_warning("variable key %" PRId64 " doesn't exist", variable_key);
758 return false;
760 remove_shm_data(shm_list_ptr->ptr, shm_varpos);
761 return true;
764 ///////////////////////////////////////////////////////////////////////////////