1602e473dSmrg/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp.
2602e473dSmrg *
3602e473dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
4602e473dSmrg * copy of this software and associated documentation files (the "Software"),
5602e473dSmrg * to deal in the Software without restriction, including without limitation
6602e473dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7602e473dSmrg * and/or sell copies of the Software, and to permit persons to whom the
8602e473dSmrg * Software is furnished to do so, subject to the following conditions:
9602e473dSmrg *
10602e473dSmrg * The above copyright notice and this permission notice shall be included in
11602e473dSmrg * all copies or substantial portions of the Software.
12602e473dSmrg *
13602e473dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14602e473dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15602e473dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16602e473dSmrg * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
17602e473dSmrg * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18602e473dSmrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19602e473dSmrg *
20602e473dSmrg * Except as contained in this notice, the names of the authors or their
21602e473dSmrg * institutions shall not be used in advertising or otherwise to promote the
22602e473dSmrg * sale, use or other dealings in this Software without prior written
23602e473dSmrg * authorization from the authors.
24602e473dSmrg */
25602e473dSmrg
26602e473dSmrg/* A cache for QueryExtension results. */
27602e473dSmrg
2821298544Smrg#ifdef HAVE_CONFIG_H
2921298544Smrg#include "config.h"
3021298544Smrg#endif
3121298544Smrg
32602e473dSmrg#include <stdlib.h>
33602e473dSmrg#include <string.h>
34602e473dSmrg
35602e473dSmrg#include "xcb.h"
36602e473dSmrg#include "xcbext.h"
37602e473dSmrg#include "xcbint.h"
38602e473dSmrg
39602e473dSmrgtypedef struct lazyreply {
40602e473dSmrg    enum lazy_reply_tag tag;
41602e473dSmrg    union {
42602e473dSmrg        xcb_query_extension_cookie_t cookie;
43602e473dSmrg        xcb_query_extension_reply_t *reply;
44602e473dSmrg    } value;
45602e473dSmrg} lazyreply;
46602e473dSmrg
47602e473dSmrgstatic lazyreply *get_index(xcb_connection_t *c, int idx)
48602e473dSmrg{
49602e473dSmrg    if(idx > c->ext.extensions_size)
50602e473dSmrg    {
51602e473dSmrg        int new_size = idx << 1;
52602e473dSmrg        lazyreply *new_extensions = realloc(c->ext.extensions, sizeof(lazyreply) * new_size);
53602e473dSmrg        if(!new_extensions)
54602e473dSmrg            return 0;
55602e473dSmrg        memset(new_extensions + c->ext.extensions_size, 0, sizeof(lazyreply) * (new_size - c->ext.extensions_size));
56602e473dSmrg        c->ext.extensions = new_extensions;
57602e473dSmrg        c->ext.extensions_size = new_size;
58602e473dSmrg    }
59602e473dSmrg    return c->ext.extensions + idx - 1;
60602e473dSmrg}
61602e473dSmrg
62602e473dSmrgstatic lazyreply *get_lazyreply(xcb_connection_t *c, xcb_extension_t *ext)
63602e473dSmrg{
64602e473dSmrg    static pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER;
65602e473dSmrg    static int next_global_id;
66602e473dSmrg
67602e473dSmrg    lazyreply *data;
68602e473dSmrg
69602e473dSmrg    pthread_mutex_lock(&global_lock);
70602e473dSmrg    if(!ext->global_id)
71602e473dSmrg        ext->global_id = ++next_global_id;
72602e473dSmrg    pthread_mutex_unlock(&global_lock);
73602e473dSmrg
74602e473dSmrg    data = get_index(c, ext->global_id);
75602e473dSmrg    if(data && data->tag == LAZY_NONE)
76602e473dSmrg    {
77602e473dSmrg        /* cache miss: query the server */
78602e473dSmrg        data->tag = LAZY_COOKIE;
79602e473dSmrg        data->value.cookie = xcb_query_extension(c, strlen(ext->name), ext->name);
80602e473dSmrg    }
81602e473dSmrg    return data;
82602e473dSmrg}
83602e473dSmrg
84602e473dSmrg/* Public interface */
85602e473dSmrg
86602e473dSmrg/* Do not free the returned xcb_query_extension_reply_t - on return, it's aliased
87602e473dSmrg * from the cache. */
88602e473dSmrgconst xcb_query_extension_reply_t *xcb_get_extension_data(xcb_connection_t *c, xcb_extension_t *ext)
89602e473dSmrg{
90602e473dSmrg    lazyreply *data;
91602e473dSmrg    if(c->has_error)
92602e473dSmrg        return 0;
93602e473dSmrg
94602e473dSmrg    pthread_mutex_lock(&c->ext.lock);
95602e473dSmrg    data = get_lazyreply(c, ext);
96602e473dSmrg    if(data && data->tag == LAZY_COOKIE)
97602e473dSmrg    {
98602e473dSmrg        data->tag = LAZY_FORCED;
99602e473dSmrg        data->value.reply = xcb_query_extension_reply(c, data->value.cookie, 0);
100602e473dSmrg    }
101602e473dSmrg    pthread_mutex_unlock(&c->ext.lock);
102602e473dSmrg
103602e473dSmrg    return data ? data->value.reply : 0;
104602e473dSmrg}
105602e473dSmrg
106602e473dSmrgvoid xcb_prefetch_extension_data(xcb_connection_t *c, xcb_extension_t *ext)
107602e473dSmrg{
108602e473dSmrg    if(c->has_error)
109602e473dSmrg        return;
110602e473dSmrg    pthread_mutex_lock(&c->ext.lock);
111602e473dSmrg    get_lazyreply(c, ext);
112602e473dSmrg    pthread_mutex_unlock(&c->ext.lock);
113602e473dSmrg}
114602e473dSmrg
115602e473dSmrg/* Private interface */
116602e473dSmrg
117602e473dSmrgint _xcb_ext_init(xcb_connection_t *c)
118602e473dSmrg{
119602e473dSmrg    if(pthread_mutex_init(&c->ext.lock, 0))
120602e473dSmrg        return 0;
121602e473dSmrg    return 1;
122602e473dSmrg}
123602e473dSmrg
124602e473dSmrgvoid _xcb_ext_destroy(xcb_connection_t *c)
125602e473dSmrg{
126602e473dSmrg    pthread_mutex_destroy(&c->ext.lock);
127602e473dSmrg    while(c->ext.extensions_size-- > 0)
128602e473dSmrg        if(c->ext.extensions[c->ext.extensions_size].tag == LAZY_FORCED)
129602e473dSmrg            free(c->ext.extensions[c->ext.extensions_size].value.reply);
130602e473dSmrg    free(c->ext.extensions);
131602e473dSmrg}
132