2 +----------------------------------------------------------------------+
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"
26 #include "sys/types.h"
32 #if defined(__APPLE__) || defined(__FreeBSD__)
33 # include <sys/msgbuf.h>
34 # define MSGBUF_MTYPE(b) (b)->msg_magic
36 # define MSGBUF_MTEXT(b) (b)->msg_bufc
38 # define MSGBUF_MTEXT(b) (b)->msg_ptr
41 # define MSGBUF_MTYPE(b) (b)->mtype
42 # define MSGBUF_MTEXT(b) (b)->mtext
45 using HPHP::Util::ScopedMem
;
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");
58 if (proj
.length() != 1) {
59 raise_warning("Project identifier has to be one character int64: %s",
63 return ftok(pathname
.c_str(), (int)proj
[0]);
66 ///////////////////////////////////////////////////////////////////////////////
69 class MessageQueue
: public ResourceData
{
71 DECLARE_OBJECT_ALLOCATION(MessageQueue
)
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);
87 id
= msgget(key
, IPC_CREAT
| IPC_EXCL
| perms
);
89 raise_warning("Failed to create message queue for key 0x%" PRIx64
": %s",
90 key
, Util::safe_strerror(errno
).c_str());
94 MessageQueue
*q
= NEWOBJ(MessageQueue
)();
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
>();
107 raise_warning("Invalid message queue was specified");
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
>();
128 raise_warning("Invalid message queue was specified");
132 struct msqid_ds stat
;
133 if (msgctl(q
->id
, IPC_STAT
, &stat
) == 0) {
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;
150 Array
f_msg_stat_queue(CObjRef queue
) {
151 MessageQueue
*q
= queue
.getTyped
<MessageQueue
>();
153 raise_warning("Invalid message queue was specified");
157 struct msqid_ds stat
;
158 if (msgctl(q
->id
, IPC_STAT
, &stat
) == 0) {
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
);
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
>();
181 raise_warning("Invalid message queue was specified");
185 struct msgbuf
*buffer
= NULL
;
188 data
= f_serialize(message
);
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
);
201 raise_warning("Unable to send message: %s",
202 Util::safe_strerror(err
).c_str());
203 if (!errorcode
.isNull()) {
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
>();
217 raise_warning("Invalid message queue was specified");
222 raise_warning("Maximum size of the message has to be greater than zero");
226 int64_t realflags
= 0;
228 #if !defined(__APPLE__) && !defined(__FreeBSD__)
229 if (flags
& k_MSG_EXCEPT
) realflags
|= MSG_EXCEPT
;
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
);
242 raise_warning("Unable to receive message: %s",
243 Util::safe_strerror(err
).c_str());
244 if (!errorcode
.isNull()) {
250 msgtype
= (int)MSGBUF_MTYPE(buffer
);
252 const char *bufText
= (const char *)MSGBUF_MTEXT(buffer
);
253 uint bufLen
= strlen(bufText
);
254 VariableUnserializer
vu(bufText
, bufLen
,
255 VariableUnserializer::Serialize
);
257 message
= vu
.unserialize();
258 } catch (Exception
&e
) {
259 raise_warning("Message corrupted");
263 message
= (const char *)MSGBUF_MTEXT(buffer
);
269 ///////////////////////////////////////////////////////////////////////////////
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
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
{
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
) {
312 if (!acquire
&& count
== 0) {
313 raise_warning("SysV semaphore %d (key 0x%x) is not currently acquired",
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());
331 count
-= acquire
? -1 : 1;
336 struct sembuf sop
[2];
340 * if count == -1, semaphore has been removed
341 * Need better way to handle this
343 if (count
== -1 || !auto_release
) {
347 /* Decrement the usage count. */
348 sop
[0].sem_num
= SYSVSEM_USAGE
;
350 sop
[0].sem_flg
= SEM_UNDO
;
352 /* Release the semaphore if it has been acquired but not released. */
354 sop
[1].sem_num
= SYSVSEM_SEM
;
355 sop
[1].sem_op
= count
;
356 sop
[1].sem_flg
= SEM_UNDO
;
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
);
387 raise_warning("failed for key 0x%" PRIx64
": %s", key
,
388 Util::safe_strerror(errno
).c_str());
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
;
407 /* . . . and increment it so it becomes non-zero . . . */
408 sop
[1].sem_num
= SYSVSEM_SETVAL
;
410 sop
[1].sem_flg
= SEM_UNDO
;
412 /* . . . and increment the usage count. */
413 sop
[2].sem_num
= SYSVSEM_USAGE
;
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());
425 /* Get the usage count. */
426 int count
= semctl(semid
, SYSVSEM_USAGE
, GETVAL
, NULL
);
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. */
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
;
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());
454 Semaphore
*sem_ptr
= new Semaphore();
456 sem_ptr
->semid
= semid
;
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
>();
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());
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());
485 /* let release_sysvsem_sem know we have removed
486 * the semaphore to avoid issues with releasing.
492 ///////////////////////////////////////////////////////////////////////////////
508 } sysvshm_chunk_head
;
512 key_t key
; /* Key set by user */
513 long id
; /* Returned by shmget. */
514 sysvshm_chunk_head
*ptr
; /* memoryaddress of shared memory */
521 class shm_set
: public std::set
<sysvshm_shm
*> {
524 for (std::set
<sysvshm_shm
*>::iterator iter
= begin(); iter
!= end();
531 static Mutex g_shm_mutex
;
532 static shm_set g_shms
;
534 static long check_shm_data(sysvshm_chunk_head
*ptr
, long key
) {
536 sysvshm_chunk
*shm_var
;
541 if (pos
>= ptr
->end
) {
544 shm_var
= (sysvshm_chunk
*) ((char *) ptr
+ pos
);
545 if (shm_var
->key
== key
) {
548 pos
+= shm_var
->next
;
550 if (shm_var
->next
<= 0 || pos
< ptr
->start
) {
557 static int remove_shm_data(sysvshm_chunk_head
*ptr
, long shm_varpos
) {
558 sysvshm_chunk
*chunk_ptr
, *next_chunk_ptr
;
561 chunk_ptr
= (sysvshm_chunk
*) ((char *) ptr
+ shm_varpos
);
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
);
574 static int put_shm_data(sysvshm_chunk_head
*ptr
, long key
, char *data
,
576 sysvshm_chunk
*shm_var
;
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
);
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
;
601 Variant
f_shm_attach(int64_t shm_key
, int64_t shm_size
/* = 10000 */,
602 int64_t shm_flag
/* = 0666 */) {
607 raise_warning("Segment size must be greater then zero.");
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
);
619 if ((shm_id
= shmget(shm_key
, shm_size
, shm_flag
| IPC_CREAT
| IPC_EXCL
))
621 raise_warning("failed for key 0x%" PRIx64
": %s", shm_key
,
622 Util::safe_strerror(errno
).c_str());
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());
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());
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",
662 delete (sysvshm_shm
*)shm_identifier
;
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
);
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());
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",
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) {
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",
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
,
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",
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());
739 raise_warning("not enough shared memory left");
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
);
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
);
760 remove_shm_data(shm_list_ptr
->ptr
, shm_varpos
);
764 ///////////////////////////////////////////////////////////////////////////////