~ubuntu-branches/ubuntu/trusty/geis/trusty

« back to all changes in this revision

Viewing changes to libgeis/backend/grail/geis_grail_xsync.c

  • Committer: Package Import Robot
  • Author(s): Chase Douglas
  • Date: 2012-07-30 08:51:42 UTC
  • Revision ID: package-import@ubuntu.com-20120730085142-jrc33ygjvt0ob1wl
Tags: upstream-2.2.11
ImportĀ upstreamĀ versionĀ 2.2.11

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * @file geis_grail_xsync.c
 
3
 * @brief Handles XSync lib usage for the GEIS grail backend
 
4
 */
 
5
/*
 
6
 * Copyright 2012 Canonical Ltd.
 
7
 *
 
8
 * This file is part of GEIS.
 
9
 *
 
10
 * GEIS is free software: you can redistribute it and/or modify it
 
11
 * under the terms of the GNU Lesser General Public License as published by the
 
12
 * Free Software Foundation, either version 3 of the License, or (at your
 
13
 * option) any later version.
 
14
 *
 
15
 * GEIS is distributed in the hope that it will be useful, but WITHOUT
 
16
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
17
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 
18
 * details.
 
19
 *
 
20
 * You should have received a copy of the GNU Lesser General Public License
 
21
 * along with GEIS.  If not, see <http://www.gnu.org/licenses/>.
 
22
 */
 
23
 
 
24
#include "geis_grail_xsync.h"
 
25
 
 
26
#include "geis_bag.h"
 
27
#include "geis_logging.h"
 
28
#include "geis/geis.h"
 
29
#include <X11/extensions/sync.h>
 
30
#include <string.h>
 
31
 
 
32
struct GeisGrailAlarm {
 
33
  XSyncAlarm xsync_alarm;
 
34
  uint64_t timeout;
 
35
};
 
36
 
 
37
struct GeisGrailXSync
 
38
{
 
39
  Display *display;
 
40
  XSyncCounter   server_time_counter;
 
41
  int xsync_event_base;
 
42
  GeisBag alarms; /* List of GeisGrailAlarm, describing existing alarms */
 
43
};
 
44
 
 
45
GeisGrailXSync
 
46
geis_grail_xsync_new(Display *display)
 
47
{
 
48
  GeisGrailXSync self = malloc(sizeof(struct GeisGrailXSync));
 
49
  if (!self)
 
50
  {
 
51
    geis_error("failed to allocate new GeisGrailXSync");
 
52
    goto return_failure;
 
53
  }
 
54
 
 
55
  self->display = display;
 
56
  self->xsync_event_base = -1;
 
57
 
 
58
  self->alarms = geis_bag_new(sizeof(struct GeisGrailAlarm), 4, 4.0f);
 
59
  if (!self->alarms)
 
60
  {
 
61
    geis_error("failed to create GeisGrailXSync.alarms bag");
 
62
    goto return_failure;
 
63
  }
 
64
 
 
65
  /* check for the presence of the XSync extension */
 
66
  int error_base;
 
67
  if (XSyncQueryExtension(self->display, &self->xsync_event_base, &error_base) != True)
 
68
  {
 
69
    geis_warning("XSync extension is not available");
 
70
    goto return_failure;
 
71
  }
 
72
 
 
73
  /* initialize the XSync extension */
 
74
  int major;
 
75
  int minor;
 
76
  if (XSyncInitialize(self->display, &major, &minor) != True)
 
77
  {
 
78
    geis_warning("failed to initialize XSync extension");
 
79
    goto return_failure;
 
80
  }
 
81
 
 
82
  /* find the server-time counter */
 
83
  int num_system_counters;
 
84
  XSyncSystemCounter *counters;
 
85
  counters = XSyncListSystemCounters(self->display, &num_system_counters);
 
86
  GeisBoolean found_counter = GEIS_FALSE;
 
87
  for (int i = 0; i < num_system_counters; ++i)
 
88
  {
 
89
    if (0 == strcmp(counters[i].name, "SERVERTIME"))
 
90
    {
 
91
      self->server_time_counter = counters[i].counter;
 
92
      found_counter = GEIS_TRUE;
 
93
      break;
 
94
    }
 
95
  }
 
96
  XSyncFreeSystemCounterList(counters);
 
97
  if (!found_counter)
 
98
    geis_warning("couldn't find SERVERTIME XSyncCounter");
 
99
 
 
100
  return self;
 
101
 
 
102
return_failure:
 
103
  if (self->alarms)
 
104
    geis_bag_delete(self->alarms);
 
105
 
 
106
  if (self)
 
107
    free(self);
 
108
 
 
109
  return NULL;
 
110
}
 
111
 
 
112
void
 
113
geis_grail_xsync_delete(GeisGrailXSync self)
 
114
{
 
115
  free(self);
 
116
}
 
117
 
 
118
/**
 
119
 * Creates and returns an XSyncAlarm configured with the given timeout or
 
120
 * None on failure
 
121
 */
 
122
static XSyncAlarm
 
123
_geis_grail_xsync_create_alarm(GeisGrailXSync self, uint64_t timeout)
 
124
{
 
125
  XSyncAlarmAttributes alarm_attributes;
 
126
  alarm_attributes.trigger.counter = self->server_time_counter;
 
127
  alarm_attributes.trigger.value_type = XSyncAbsolute;
 
128
  XSyncIntsToValue(&alarm_attributes.trigger.wait_value, timeout & 0xffffffff,
 
129
                   timeout & 0xffffffff00000000);
 
130
  alarm_attributes.trigger.test_type = XSyncPositiveComparison;
 
131
  alarm_attributes.events = True;
 
132
 
 
133
  return XSyncCreateAlarm(self->display,
 
134
                          XSyncCACounter | XSyncCAValueType | XSyncCAValue
 
135
                          | XSyncCATestType | XSyncCAEvents,
 
136
                          &alarm_attributes);
 
137
}
 
138
 
 
139
/**
 
140
 * Returns GEIS_TRUE if an XSyncAlarm exists for the given timeout or
 
141
 * GEIS_FALSE otherwise
 
142
 */
 
143
static GeisBoolean
 
144
_geis_grail_xsync_alarm_exists_for_timeout(GeisGrailXSync self, uint64_t timeout)
 
145
{
 
146
  for (GeisSize i = 0, alarms_count = geis_bag_count(self->alarms);
 
147
       i < alarms_count; ++i)
 
148
  {
 
149
    struct GeisGrailAlarm *alarm = geis_bag_at(self->alarms, i);
 
150
    if (alarm->timeout == timeout)
 
151
      return GEIS_TRUE;
 
152
  }
 
153
  return GEIS_FALSE;
 
154
}
 
155
 
 
156
void
 
157
geis_grail_xsync_set_timeout(GeisGrailXSync self, uint64_t timeout)
 
158
{
 
159
  if (_geis_grail_xsync_alarm_exists_for_timeout(self, timeout))
 
160
    return;
 
161
 
 
162
  struct GeisGrailAlarm alarm;
 
163
 
 
164
  alarm.xsync_alarm = _geis_grail_xsync_create_alarm(self, timeout);
 
165
  if (alarm.xsync_alarm == None)
 
166
  {
 
167
    geis_error("failed to create an XSync alarm.");
 
168
    return;
 
169
  }
 
170
  /* make sure xserver creates the alarm now, otherwise it could in theory
 
171
     happen only after the desired timeout period */
 
172
  XFlush(self->display); 
 
173
 
 
174
  alarm.timeout = timeout;
 
175
 
 
176
  geis_bag_append(self->alarms, &alarm);
 
177
}
 
178
 
 
179
/**
 
180
 * If the given XSyncAlarm exists, it's destroyed, removed from the
 
181
 * list of alarms and the function returns GEIS_TRUE.
 
182
 *
 
183
 * If the given XSyncAlarm doesn't exist, the function returns GEIS_FALSE.
 
184
 */
 
185
static GeisBoolean
 
186
_geis_grail_xsync_destroy_alarm(GeisGrailXSync self, XSyncAlarm xsync_alarm)
 
187
{
 
188
  for (GeisSize i = 0, alarms_count = geis_bag_count(self->alarms);
 
189
       i < alarms_count; ++i)
 
190
  {
 
191
    struct GeisGrailAlarm *alarm = geis_bag_at(self->alarms, i);
 
192
    if (alarm->xsync_alarm == xsync_alarm)
 
193
    {
 
194
      if (XSyncDestroyAlarm(self->display, xsync_alarm) == False)
 
195
        geis_error("failed to destroy XSync alarm");
 
196
 
 
197
      geis_bag_remove(self->alarms, i);
 
198
      return GEIS_TRUE;
 
199
    }
 
200
  }
 
201
  return GEIS_FALSE;
 
202
}
 
203
 
 
204
GeisBoolean
 
205
geis_grail_xsync_is_timeout(GeisGrailXSync self, const XEvent *event)
 
206
{
 
207
  if (event->type != (self->xsync_event_base + XSyncAlarmNotify))
 
208
    return GEIS_FALSE;
 
209
 
 
210
  const XSyncAlarmNotifyEvent *alarm_notify =
 
211
      (const XSyncAlarmNotifyEvent *) event;
 
212
 
 
213
  /* If the destruction isn't successful it means that this alarm has already
 
214
     been destroyed due to a previous XSyncAlarmNotifyEvent. Therefore its
 
215
     corresponding timeout has already happened and we shouldn't confirm it
 
216
     again. */
 
217
  return _geis_grail_xsync_destroy_alarm(self, alarm_notify->alarm);
 
218
}
 
219
 
 
220
uint64_t
 
221
geis_grail_xsync_get_server_time(const XEvent *event)
 
222
{
 
223
  const XSyncAlarmNotifyEvent *alarm_notify =
 
224
      (const XSyncAlarmNotifyEvent *) event;
 
225
 
 
226
  XSyncValue time = alarm_notify->counter_value;
 
227
 
 
228
  return (uint64_t)XSyncValueHigh32(time) << 32 | XSyncValueLow32(time);
 
229
}