1 /* Cairo - a vector graphics library with display and print output
3 * Copyright © 2007 Chris Wilson
4 * Copyright © 2009 Intel Corporation
6 * This library is free software; you can redistribute it and/or
7 * modify it either under the terms of the GNU Lesser General Public
8 * License version 2.1 as published by the Free Software Foundation
9 * (the "LGPL") or, at your option, under the terms of the Mozilla
10 * Public License Version 1.1 (the "MPL"). If you do not alter this
11 * notice, a recipient may use your version of this file under either
12 * the MPL or the LGPL.
14 * You should have received a copy of the LGPL along with this library
15 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17 * You should have received a copy of the MPL along with this library
18 * in the file COPYING-MPL-1.1
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License at
23 * http://www.mozilla.org/MPL/
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 * the specific language governing rights and limitations.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is Red Hat, Inc.
34 * Chris Wilson <chris@chris-wilson.co.uk>
39 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
41 #include "cairo-xcb-private.h"
42 #include "cairo-list-inline.h"
43 #include "cairo-mempool-private.h"
50 #define CAIRO_MAX_SHM_MEMORY (16*1024*1024)
52 /* a simple buddy allocator for memory pools
53 * XXX fragmentation? use Doug Lea's malloc?
56 typedef struct _cairo_xcb_shm_mem_block cairo_xcb_shm_mem_block_t
;
63 struct _cairo_xcb_shm_mem_pool
{
74 _cairo_xcb_shm_mem_pool_destroy (cairo_xcb_shm_mem_pool_t
*pool
)
76 cairo_list_del (&pool
->link
);
79 _cairo_mempool_fini (&pool
->mem
);
85 _cairo_xcb_shm_info_finalize (cairo_xcb_shm_info_t
*shm_info
)
87 cairo_xcb_connection_t
*connection
= shm_info
->connection
;
89 assert (CAIRO_MUTEX_IS_LOCKED (connection
->shm_mutex
));
91 _cairo_mempool_free (&shm_info
->pool
->mem
, shm_info
->mem
);
92 _cairo_freepool_free (&connection
->shm_info_freelist
, shm_info
);
94 /* scan for old, unused pools - hold at least one in reserve */
95 if (! cairo_list_is_singular (&connection
->shm_pools
))
97 cairo_xcb_shm_mem_pool_t
*pool
, *next
;
100 cairo_list_init (&head
);
101 cairo_list_move (connection
->shm_pools
.next
, &head
);
103 cairo_list_foreach_entry_safe (pool
, next
, cairo_xcb_shm_mem_pool_t
,
104 &connection
->shm_pools
, link
)
106 if (pool
->mem
.free_bytes
== pool
->mem
.max_bytes
) {
107 _cairo_xcb_connection_shm_detach (connection
, pool
->shmseg
);
108 _cairo_xcb_shm_mem_pool_destroy (pool
);
112 cairo_list_move (head
.next
, &connection
->shm_pools
);
117 _cairo_xcb_shm_process_pending (cairo_xcb_connection_t
*connection
, shm_wait_type_t wait
)
119 cairo_xcb_shm_info_t
*info
, *next
;
120 xcb_get_input_focus_reply_t
*reply
;
122 assert (CAIRO_MUTEX_IS_LOCKED (connection
->shm_mutex
));
123 cairo_list_foreach_entry_safe (info
, next
, cairo_xcb_shm_info_t
,
124 &connection
->shm_pending
, pending
)
128 reply
= xcb_wait_for_reply (connection
->xcb_connection
,
129 info
->sync
.sequence
, NULL
);
132 if (! xcb_poll_for_reply (connection
->xcb_connection
,
134 (void **) &reply
, NULL
))
135 /* We cannot be sure the server finished with this image yet, so
136 * try again later. All other shm info are guaranteed to have a
137 * larger sequence number and thus don't have to be checked. */
141 /* silence Clang static analyzer warning */
147 cairo_list_del (&info
->pending
);
148 _cairo_xcb_shm_info_finalize (info
);
153 _cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t
*connection
,
155 cairo_bool_t might_reuse
,
156 cairo_xcb_shm_info_t
**shm_info_out
)
158 cairo_xcb_shm_info_t
*shm_info
;
159 cairo_xcb_shm_mem_pool_t
*pool
, *next
;
160 size_t bytes
, maxbits
= 16, minbits
= 8;
161 size_t shm_allocated
= 0;
163 cairo_status_t status
;
165 assert (connection
->flags
& CAIRO_XCB_HAS_SHM
);
167 CAIRO_MUTEX_LOCK (connection
->shm_mutex
);
168 _cairo_xcb_shm_process_pending (connection
, PENDING_POLL
);
171 cairo_list_foreach_entry (shm_info
, cairo_xcb_shm_info_t
,
172 &connection
->shm_pending
, pending
) {
173 if (shm_info
->size
>= size
) {
174 cairo_list_del (&shm_info
->pending
);
175 CAIRO_MUTEX_UNLOCK (connection
->shm_mutex
);
177 xcb_discard_reply (connection
->xcb_connection
, shm_info
->sync
.sequence
);
178 shm_info
->sync
.sequence
= XCB_NONE
;
180 *shm_info_out
= shm_info
;
181 return CAIRO_STATUS_SUCCESS
;
186 cairo_list_foreach_entry_safe (pool
, next
, cairo_xcb_shm_mem_pool_t
,
187 &connection
->shm_pools
, link
)
189 if (pool
->mem
.free_bytes
> size
) {
190 mem
= _cairo_mempool_alloc (&pool
->mem
, size
);
192 /* keep the active pools towards the front */
193 cairo_list_move (&pool
->link
, &connection
->shm_pools
);
194 goto allocate_shm_info
;
197 /* scan for old, unused pools */
198 if (pool
->mem
.free_bytes
== pool
->mem
.max_bytes
) {
199 _cairo_xcb_connection_shm_detach (connection
,
201 _cairo_xcb_shm_mem_pool_destroy (pool
);
203 shm_allocated
+= pool
->mem
.max_bytes
;
207 if (unlikely (shm_allocated
>= CAIRO_MAX_SHM_MEMORY
)) {
208 CAIRO_MUTEX_UNLOCK (connection
->shm_mutex
);
209 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
212 pool
= malloc (sizeof (cairo_xcb_shm_mem_pool_t
));
213 if (unlikely (pool
== NULL
)) {
214 CAIRO_MUTEX_UNLOCK (connection
->shm_mutex
);
215 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
218 bytes
= 1 << maxbits
;
219 while (bytes
<= size
)
220 bytes
<<= 1, maxbits
++;
224 pool
->shmid
= shmget (IPC_PRIVATE
, bytes
, IPC_CREAT
| 0600);
225 if (pool
->shmid
!= -1)
228 /* If the allocation failed because we asked for too much memory, we try
229 * again with a smaller request, as long as our allocation still fits. */
231 if (errno
!= EINVAL
|| bytes
< size
)
234 if (pool
->shmid
== -1) {
236 if (! (err
== EINVAL
|| err
== ENOMEM
))
237 connection
->flags
&= ~CAIRO_XCB_HAS_SHM
;
239 CAIRO_MUTEX_UNLOCK (connection
->shm_mutex
);
240 return CAIRO_INT_STATUS_UNSUPPORTED
;
243 pool
->shm
= shmat (pool
->shmid
, NULL
, 0);
244 if (unlikely (pool
->shm
== (char *) -1)) {
245 shmctl (pool
->shmid
, IPC_RMID
, NULL
);
247 CAIRO_MUTEX_UNLOCK (connection
->shm_mutex
);
248 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
251 status
= _cairo_mempool_init (&pool
->mem
, pool
->shm
, bytes
,
252 minbits
, maxbits
- minbits
+ 1);
253 if (unlikely (status
)) {
256 CAIRO_MUTEX_UNLOCK (connection
->shm_mutex
);
260 pool
->shmseg
= _cairo_xcb_connection_shm_attach (connection
, pool
->shmid
, FALSE
);
261 shmctl (pool
->shmid
, IPC_RMID
, NULL
);
263 cairo_list_add (&pool
->link
, &connection
->shm_pools
);
264 mem
= _cairo_mempool_alloc (&pool
->mem
, size
);
267 shm_info
= _cairo_freepool_alloc (&connection
->shm_info_freelist
);
268 if (unlikely (shm_info
== NULL
)) {
269 _cairo_mempool_free (&pool
->mem
, mem
);
270 CAIRO_MUTEX_UNLOCK (connection
->shm_mutex
);
271 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
274 shm_info
->connection
= connection
;
275 shm_info
->pool
= pool
;
276 shm_info
->shm
= pool
->shmseg
;
277 shm_info
->size
= size
;
278 shm_info
->offset
= (char *) mem
- (char *) pool
->shm
;
280 shm_info
->sync
.sequence
= XCB_NONE
;
282 /* scan for old, unused pools */
283 cairo_list_foreach_entry_safe (pool
, next
, cairo_xcb_shm_mem_pool_t
,
284 &connection
->shm_pools
, link
)
286 if (pool
->mem
.free_bytes
== pool
->mem
.max_bytes
) {
287 _cairo_xcb_connection_shm_detach (connection
,
289 _cairo_xcb_shm_mem_pool_destroy (pool
);
292 CAIRO_MUTEX_UNLOCK (connection
->shm_mutex
);
294 *shm_info_out
= shm_info
;
295 return CAIRO_STATUS_SUCCESS
;
299 _cairo_xcb_shm_info_destroy (cairo_xcb_shm_info_t
*shm_info
)
301 cairo_xcb_connection_t
*connection
= shm_info
->connection
;
303 /* We can only return shm_info->mem to the allocator when we can be sure
304 * that the X server no longer reads from it. Since the X server processes
305 * requests in order, we send a GetInputFocus here.
306 * _cairo_xcb_shm_process_pending () will later check if the reply for that
307 * request was received and then actually mark this memory area as free. */
309 CAIRO_MUTEX_LOCK (connection
->shm_mutex
);
310 assert (shm_info
->sync
.sequence
== XCB_NONE
);
311 shm_info
->sync
= xcb_get_input_focus (connection
->xcb_connection
);
313 cairo_list_init (&shm_info
->pending
);
314 cairo_list_add_tail (&shm_info
->pending
, &connection
->shm_pending
);
315 CAIRO_MUTEX_UNLOCK (connection
->shm_mutex
);
319 _cairo_xcb_connection_shm_mem_pools_flush (cairo_xcb_connection_t
*connection
)
321 CAIRO_MUTEX_LOCK (connection
->shm_mutex
);
322 _cairo_xcb_shm_process_pending (connection
, PENDING_WAIT
);
323 CAIRO_MUTEX_UNLOCK (connection
->shm_mutex
);
327 _cairo_xcb_connection_shm_mem_pools_fini (cairo_xcb_connection_t
*connection
)
329 assert (cairo_list_is_empty (&connection
->shm_pending
));
330 while (! cairo_list_is_empty (&connection
->shm_pools
)) {
331 _cairo_xcb_shm_mem_pool_destroy (cairo_list_first_entry (&connection
->shm_pools
,
332 cairo_xcb_shm_mem_pool_t
,
337 #endif /* CAIRO_HAS_XCB_SHM_FUNCTIONS */