2 * Copyright (c) 2012 Carsten Munk <carsten.munk@gmail.com>
3 * Copyright (c) 2013 Christophe Chapuis <chris.chapuis@gmail.com>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 #include "hooks_shm.h"
36 #define LOGD(message, ...) HYBRIS_DEBUG_LOG(HOOKS, message, ##__VA_ARGS__)
38 #define HYBRIS_DATA_SIZE 4000
39 #define HYBRIS_SHM_MASK 0xFF000000UL
40 #define HYBRIS_SHM_PATH "/hybris_shm_data"
42 /* Structure of a shared memory region */
43 typedef struct _hybris_shm_data_t
{
44 pthread_mutex_t access_mutex
;
50 /* A helper to switch between the size of the data and the size of the shm object */
51 const int HYBRIS_SHM_DATA_HEADER_SIZE
= (sizeof(hybris_shm_data_t
) - sizeof(unsigned char));
53 /* pointer to the shared memory region */
54 static hybris_shm_data_t
*_hybris_shm_data
= NULL
;
56 /* the SHM mem_id of the shared memory region */
57 static int _hybris_shm_fd
= -1;
59 /* the size of the shared memory region that is currently mmap'ed to this process */
60 static int _current_mapped_size
= 0;
62 /* forward-declare the internal static methods */
63 static void _release_shm(void);
64 static void _sync_mmap_with_shm(void);
65 static void _hybris_shm_init(void);
66 static void _hybris_shm_extend_region(void);
69 * Detach the allocated memory region, and mark it for deletion
71 static void _release_shm(void)
73 if (_hybris_shm_data
) {
74 munmap(_hybris_shm_data
, _current_mapped_size
); /* unmap from this process */
75 _hybris_shm_data
= NULL
; /* pointer is no more valid */
77 if (_hybris_shm_fd
>= 0) {
78 close(_hybris_shm_fd
); /* close the shm file descriptor */
81 shm_unlink(HYBRIS_SHM_PATH
); /* request the deletion of the shm region */
85 * Synchronize the size of the mmap with the size of the shm region
87 static void _sync_mmap_with_shm()
89 if (_hybris_shm_fd
>= 0 && _hybris_shm_data
) {
90 if (_current_mapped_size
< _hybris_shm_data
->max_offset
+ HYBRIS_SHM_DATA_HEADER_SIZE
) {
91 /* Note that mremap may change the address pointed by _hybris_shm_data.
92 * But as we never point directly into _hybris_shm_data, it's fine.
94 _hybris_shm_data
= (hybris_shm_data_t
*)mremap( _hybris_shm_data
, _current_mapped_size
,
95 _hybris_shm_data
->max_offset
+ HYBRIS_SHM_DATA_HEADER_SIZE
,
98 _current_mapped_size
= _hybris_shm_data
->max_offset
+ HYBRIS_SHM_DATA_HEADER_SIZE
;
104 * Initialize the shared memory region for hybris, in order to store
105 * pshared mutex, condition and rwlock
107 static void _hybris_shm_init()
109 if (_hybris_shm_fd
< 0) {
110 const size_t size_to_map
= HYBRIS_SHM_DATA_HEADER_SIZE
+ HYBRIS_DATA_SIZE
; /* 4000 bytes for the data, plus the header size */
112 /* initialize or get shared memory segment */
113 _hybris_shm_fd
= shm_open(HYBRIS_SHM_PATH
, O_RDWR
, 0660);
114 if (_hybris_shm_fd
>= 0) {
115 /* Map the memory object */
116 _hybris_shm_data
= (hybris_shm_data_t
*)mmap( NULL
, size_to_map
,
117 PROT_READ
| PROT_WRITE
, MAP_SHARED
,
119 _current_mapped_size
= size_to_map
;
121 _sync_mmap_with_shm();
124 LOGD("Creating a new shared memory segment.");
126 _hybris_shm_fd
= shm_open(HYBRIS_SHM_PATH
, O_RDWR
| O_CREAT
, 0660);
127 if (_hybris_shm_fd
>= 0) {
128 ftruncate( _hybris_shm_fd
, size_to_map
);
129 /* Map the memory object */
130 _hybris_shm_data
= (hybris_shm_data_t
*)mmap( NULL
, size_to_map
,
131 PROT_READ
| PROT_WRITE
, MAP_SHARED
,
133 if (_hybris_shm_data
== MAP_FAILED
) {
134 HYBRIS_ERROR_LOG(HOOKS
, "ERROR: mmap failed: %s\n", strerror(errno
));
138 _current_mapped_size
= size_to_map
;
139 /* Initialize the memory object */
140 memset((void*)_hybris_shm_data
, 0, size_to_map
);
141 _hybris_shm_data
->max_offset
= HYBRIS_DATA_SIZE
;
143 pthread_mutexattr_t attr
;
144 pthread_mutexattr_init(&attr
);
145 pthread_mutexattr_setpshared(&attr
, PTHREAD_PROCESS_SHARED
);
146 pthread_mutex_init(&_hybris_shm_data
->access_mutex
, &attr
);
147 pthread_mutexattr_destroy(&attr
);
149 atexit(_release_shm
);
153 HYBRIS_ERROR_LOG(HOOKS
, "ERROR: Couldn't create shared memory segment !");
160 * Extend the SHM region's size
162 static void _hybris_shm_extend_region()
164 ftruncate( _hybris_shm_fd
, _current_mapped_size
+ HYBRIS_DATA_SIZE
);
165 _hybris_shm_data
->max_offset
+= HYBRIS_DATA_SIZE
;
167 _sync_mmap_with_shm();
170 /************ public functions *******************/
173 * Determine if the pointer that has been extracted by hybris is
174 * pointing to an address in the shared memory
176 int hybris_is_pointer_in_shm(void *ptr
)
178 if ((unsigned int)ptr
>= HYBRIS_SHM_MASK
)
185 * Convert this offset pointer to the shared memory to an
186 * absolute pointer that can be used in user space
188 void *hybris_get_shmpointer(hybris_shm_pointer_t handle
)
190 void *realpointer
= NULL
;
191 if (hybris_is_pointer_in_shm((void*)handle
)) {
192 if (_hybris_shm_fd
< 0) {
193 /* if we are not yet attached to any shm region, then do it now */
197 pthread_mutex_lock(&_hybris_shm_data
->access_mutex
);
199 _sync_mmap_with_shm(); /* make sure our mmap is sync'ed */
201 if (_hybris_shm_data
!= NULL
) {
202 unsigned int offset
= handle
& (~HYBRIS_SHM_MASK
);
203 realpointer
= &(_hybris_shm_data
->data
) + offset
;
205 /* Be careful when activating this trace: this method is called *a lot* !
206 LOGD("handle = %x, offset = %d, realpointer = %x)", handle, offset, realpointer);
210 pthread_mutex_unlock(&_hybris_shm_data
->access_mutex
);
217 * Allocate a space in the shared memory region of hybris
219 hybris_shm_pointer_t
hybris_shm_alloc(size_t size
)
221 hybris_shm_pointer_t location
= 0;
223 if (_hybris_shm_fd
< 0) {
224 /* if we are not yet attached to any shm region, then do it now */
228 pthread_mutex_lock(&_hybris_shm_data
->access_mutex
);
230 /* Make sure our mmap is sync'ed */
231 _sync_mmap_with_shm();
233 if (_hybris_shm_data
== NULL
|| _hybris_shm_fd
< 0)
236 if (_hybris_shm_data
->current_offset
+ size
>= _hybris_shm_data
->max_offset
) {
237 /* the current buffer if full: extend it a little bit more */
238 _hybris_shm_extend_region();
239 _sync_mmap_with_shm();
242 /* there is now enough place in this pool */
243 location
= _hybris_shm_data
->current_offset
| HYBRIS_SHM_MASK
;
244 LOGD("Allocated a shared object (size = %d, at offset %d)", size
, _hybris_shm_data
->current_offset
);
246 _hybris_shm_data
->current_offset
+= size
;
248 pthread_mutex_unlock(&_hybris_shm_data
->access_mutex
);