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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
|
/*
* The MIT License
*
* Copyright (C) 2010-2017 Alexander Saprykin <saprykin.spb@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file pshm.h
* @brief Shared memory
* @author Alexander Saprykin
*
* Shared memory is a memory segment which can be accessed from several threads
* or processes. It provides an efficient way to transfer large blocks of data
* between processes. It can be used as any other regular memory segment in an
* application.
*
* Shared memory acts like an inter-process communication method. This memory
* exchange implementation is process-wide so you can transfer data not only
* between the threads. But it makes this IPC method (actually like any other
* IPC method, as well) relatively heavy. Consider using other approaches
* instead if you do not need to cross the process boundary.
*
* A shared memory segment doesn't provide any synchronization primitives itself
* which means that several processes or threads can concurrently write and read
* from it. This can lead to data consistency problems. To avoid such situations
* a locking mechanism is provided: use p_shm_lock() before entering a critical
* section on the memory segment and p_shm_unlock() when leaving this section.
* The locking mechanism is working across the process boundary.
*
* A process-wide shared memory segment is identified by its name across the
* system, thus it is also called a named memory segment. Use p_shm_new() to
* open the named shared memory segment and p_shm_free() to close it.
*
* Please note the following platform specific differences:
*
* - Windows and OS/2 don't own IPC objects (processes own them), which means
* that a shared memory segment will be removed after the last process or thread
* detaches (or after terminating all the processes and threads attached to the
* segment) it.
*
* - UNIX systems own IPC objects. Because of that UNIX IPC objects can survive
* an application crash: the attached shared memory segment can contain data
* from the previous working session. This could happen if you have not detached
* from all the shared memory segments explicitly before terminating the
* application.
*
* - HP-UX has limitations due to its MPAS/MGAS features, so you couldn't attach
* to the same memory segment twice from the same process.
*
* - IRIX allows to open several instances of the same buffer within the single
* process, but it will close the object after the first close call from any of
* the threads within the process.
*
* - OpenVMS (as of 8.4 release) has broken implementation of process-wide named
* semaphores which leads to the broken shared memory also.
*
* - Syllable lacks support for process-wide named semaphores which leads to the
* absence of shared memory.
*
* - BeOS lacks support for process-wide named semaphores which leads to the
* absence of shared memory.
*
* You can take ownership of the shared memory segment with
* p_shm_take_ownership() to explicitly remove it from the system after closing.
*/
#if !defined (PLIBSYS_H_INSIDE) && !defined (PLIBSYS_COMPILATION)
# error "Header files shouldn't be included directly, consider using <plibsys.h> instead."
#endif
#ifndef PLIBSYS_HEADER_PSHM_H
#define PLIBSYS_HEADER_PSHM_H
#include <pmacros.h>
#include <ptypes.h>
#include <perror.h>
P_BEGIN_DECLS
/** Enum with shared memory access permissions. */
typedef enum PShmAccessPerms_ {
P_SHM_ACCESS_READONLY = 0, /**< Read-only access. */
P_SHM_ACCESS_READWRITE = 1 /**< Read/write access. */
} PShmAccessPerms;
/** Shared memory opaque data structure. */
typedef struct PShm_ PShm;
/**
* @brief Creates a new #PShm object.
* @param name Shared memory name.
* @param size Size of the memory segment in bytes, can't be changed later.
* @param perms Memory segment permissions, see #PShmAccessPerms.
* @param[out] error Error report object, NULL to ignore.
* @return Pointer to a newly created #PShm object in case of success, NULL
* otherwise.
* @since 0.0.1
*/
P_LIB_API PShm * p_shm_new (const pchar *name,
psize size,
PShmAccessPerms perms,
PError **error);
/**
* @brief Takes ownership of a shared memory segment.
* @param shm Shared memory segment.
* @since 0.0.1
*
* If you take ownership of the shared memory object, p_shm_free() will try to
* completely unlink it and remove from the system. This is useful on UNIX
* systems where shared memory can survive an application crash. On the Windows
* and OS/2 platforms this call has no effect.
*
* The common usage of this call is upon application startup to ensure that the
* memory segment from the previous crash will be unlinked from the system. To
* do that, call p_shm_new() and check if its condition is normal (the segment
* size, the data). If not, take ownership of the shared memory object and
* remove it with the p_shm_free() call. After that, create it again.
*/
P_LIB_API void p_shm_take_ownership (PShm *shm);
/**
* @brief Frees #PShm object.
* @param shm #PShm to free.
* @since 0.0.1
*
* It doesn't unlock a given shared memory segment, be careful to not to make a
* deadlock or a segfault while freeing the memory segment which is under usage.
*/
P_LIB_API void p_shm_free (PShm *shm);
/**
* @brief Locks #PShm object for usage.
* @param shm #PShm to lock.
* @param[out] error Error report object, NULL to ignore.
* @return TRUE in case of success, FALSE otherwise.
* @since 0.0.1
*
* If the object is already locked then the thread will be suspended until the
* object becomes unlocked.
*/
P_LIB_API pboolean p_shm_lock (PShm *shm,
PError **error);
/**
* @brief Unlocks #PShm object.
* @param shm #PShm to unlock.
* @param[out] error Error report object, NULL to ignore.
* @return TRUE in case of success, FALSE otherwise.
* @since 0.0.1
*/
P_LIB_API pboolean p_shm_unlock (PShm *shm,
PError **error);
/**
* @brief Gets a starting address of a #PShm memory segment.
* @param shm #PShm to get the address for.
* @return Pointer to the starting address in case of success, NULL otherwise.
* @since 0.0.1
*/
P_LIB_API ppointer p_shm_get_address (const PShm *shm);
/**
* @brief Gets the size of a #PShm memory segment.
* @param shm #PShm to get the size for.
* @return Size of the given memory segment in case of success, 0 otherwise.
* @since 0.0.1
*
* Note that the returned size would be a slightly larger than specified during
* the p_shm_new() call due to service information stored inside.
*/
P_LIB_API psize p_shm_get_size (const PShm *shm);
P_END_DECLS
#endif /* PLIBSYS_HEADER_PSHM_H */
|