[Xcb-commit] libxcb: 9 commits - configure.ac Makefile.am src xcb-dri3.pc.in xcb-present.pc.in
Keith Packard
keithp at kemper.freedesktop.org
Thu Nov 7 23:03:04 CET 2013
Makefile.am | 6 +
configure.ac | 23 +++-
src/.gitignore | 2
src/Makefile.am | 18 +++
src/c_client.py | 69 +++++++++++-
src/xcb.h | 58 ++++++----
src/xcb_conn.c | 31 +++++
src/xcb_in.c | 296 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
src/xcb_out.c | 18 +++
src/xcbext.h | 6 -
src/xcbint.h | 22 ++++
xcb-dri3.pc.in | 11 ++
xcb-present.pc.in | 11 ++
13 files changed, 531 insertions(+), 40 deletions(-)
New commits:
commit cca607409068ad0948e7283fb8d0465cabc51686
Author: Keith Packard <keithp at keithp.com>
Date: Thu Jul 11 16:01:02 2013 -0700
Add Present extension
Signed-off-by: Keith Packard <keithp at keithp.com>
Reviewed-By: Uli Schlachter <psychon at znc.in>
diff --git a/Makefile.am b/Makefile.am
index c9fcf08..1cb3d9a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -24,6 +24,9 @@ endif
if BUILD_GLX
pkgconfig_DATA += xcb-glx.pc
endif
+if BUILD_PRESENT
+pkgconfig_DATA += xcb-present.pc
+endif
if BUILD_RANDR
pkgconfig_DATA += xcb-randr.pc
endif
diff --git a/configure.ac b/configure.ac
index 42288de..86efc3a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -186,6 +186,7 @@ XCB_EXTENSION(DPMS, "yes")
XCB_EXTENSION(DRI2, "yes")
XCB_EXTENSION(DRI3, "$have_sendmsg")
XCB_EXTENSION(GLX, "yes")
+XCB_EXTENSION(Present, "yes")
XCB_EXTENSION(RandR, "yes")
XCB_EXTENSION(Record, "yes")
XCB_EXTENSION(Render, "yes")
@@ -231,6 +232,7 @@ xcb-dpms.pc
xcb-dri2.pc
xcb-dri3.pc
xcb-glx.pc
+xcb-present.pc
xcb-randr.pc
xcb-record.pc
xcb-render.pc
diff --git a/src/.gitignore b/src/.gitignore
index 71a7341..a2a9010 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -5,6 +5,7 @@ dpms.*
dri2.*
dri3.*
glx.*
+present.*
randr.*
record.*
render.*
diff --git a/src/Makefile.am b/src/Makefile.am
index 9d6d246..346ee03 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -64,6 +64,14 @@ libxcb_dri3_la_LIBADD = $(XCB_LIBS)
nodist_libxcb_dri3_la_SOURCES = dri3.c dri3.h
endif
+EXTSOURCES += present.c
+if BUILD_PRESENT
+lib_LTLIBRARIES += libxcb-present.la
+libxcb_present_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@
+libxcb_present_la_LIBADD = $(XCB_LIBS)
+nodist_libxcb_present_la_SOURCES = present.c present.h
+endif
+
EXTSOURCES += glx.c
if BUILD_GLX
lib_LTLIBRARIES += libxcb-glx.la
diff --git a/xcb-present.pc.in b/xcb-present.pc.in
new file mode 100644
index 0000000..848ac02
--- /dev/null
+++ b/xcb-present.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: XCB Present
+Description: XCB Present Extension
+Version: @PACKAGE_VERSION@
+Requires: xcb
+Libs: -L${libdir} -lxcb-present
+Cflags: -I${includedir}
commit 7a9373078e69b2cb2753570f91e5c31062ba25f8
Author: Keith Packard <keithp at keithp.com>
Date: Tue Apr 9 21:35:52 2013 -0700
Add DRI3 library
Signed-off-by: Keith Packard <keithp at keithp.com>
Reviewed-By: Uli Schlachter <psychon at znc.in>
diff --git a/Makefile.am b/Makefile.am
index 961595b..c9fcf08 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -18,6 +18,9 @@ endif
if BUILD_DRI2
pkgconfig_DATA += xcb-dri2.pc
endif
+if BUILD_DRI3
+pkgconfig_DATA += xcb-dri3.pc
+endif
if BUILD_GLX
pkgconfig_DATA += xcb-glx.pc
endif
diff --git a/configure.ac b/configure.ac
index 82b3676..42288de 100644
--- a/configure.ac
+++ b/configure.ac
@@ -184,6 +184,7 @@ XCB_EXTENSION(Composite, "yes")
XCB_EXTENSION(Damage, "yes")
XCB_EXTENSION(DPMS, "yes")
XCB_EXTENSION(DRI2, "yes")
+XCB_EXTENSION(DRI3, "$have_sendmsg")
XCB_EXTENSION(GLX, "yes")
XCB_EXTENSION(RandR, "yes")
XCB_EXTENSION(Record, "yes")
@@ -228,6 +229,7 @@ xcb-composite.pc
xcb-damage.pc
xcb-dpms.pc
xcb-dri2.pc
+xcb-dri3.pc
xcb-glx.pc
xcb-randr.pc
xcb-record.pc
@@ -273,6 +275,7 @@ echo " Composite...........: ${BUILD_COMPOSITE}"
echo " Damage..............: ${BUILD_DAMAGE}"
echo " Dpms................: ${BUILD_DPMS}"
echo " Dri2................: ${BUILD_DRI2}"
+echo " Dri3................: ${BUILD_DRI3}"
echo " Glx.................: ${BUILD_GLX}"
echo " Randr...............: ${BUILD_RANDR}"
echo " Record..............: ${BUILD_RECORD}"
diff --git a/src/.gitignore b/src/.gitignore
index a402afe..71a7341 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -3,6 +3,7 @@ composite.*
damage.*
dpms.*
dri2.*
+dri3.*
glx.*
randr.*
record.*
diff --git a/src/Makefile.am b/src/Makefile.am
index f48e14e..9d6d246 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -56,6 +56,14 @@ libxcb_dri2_la_LIBADD = $(XCB_LIBS)
nodist_libxcb_dri2_la_SOURCES = dri2.c dri2.h
endif
+EXTSOURCES += dri3.c
+if BUILD_DRI3
+lib_LTLIBRARIES += libxcb-dri3.la
+libxcb_dri3_la_LDFLAGS = -version-info 0:0:0 -no-undefined @lt_enable_auto_import@
+libxcb_dri3_la_LIBADD = $(XCB_LIBS)
+nodist_libxcb_dri3_la_SOURCES = dri3.c dri3.h
+endif
+
EXTSOURCES += glx.c
if BUILD_GLX
lib_LTLIBRARIES += libxcb-glx.la
diff --git a/xcb-dri3.pc.in b/xcb-dri3.pc.in
new file mode 100644
index 0000000..0eb7390
--- /dev/null
+++ b/xcb-dri3.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: XCB DRI3
+Description: XCB DRI3 Extension
+Version: @PACKAGE_VERSION@
+Requires: xcb
+Libs: -L${libdir} -lxcb-dri3
+Cflags: -I${includedir}
commit 93d733e85ded5e92292d36fc7025f0c8ff7b1167
Author: Keith Packard <keithp at keithp.com>
Date: Thu Nov 7 05:20:06 2013 -0800
Require xcb proto version 1.9
Signed-off-by: Keith Packard <keithp at keithp.com>
diff --git a/configure.ac b/configure.ac
index 54cda2f..82b3676 100644
--- a/configure.ac
+++ b/configure.ac
@@ -41,7 +41,7 @@ fi
AC_SUBST(HTML_CHECK_RESULT)
# Checks for pkg-config packages
-PKG_CHECK_MODULES(XCBPROTO, xcb-proto >= 1.7)
+PKG_CHECK_MODULES(XCBPROTO, xcb-proto >= 1.9)
NEEDED="pthread-stubs xau >= 0.99.2"
PKG_CHECK_MODULES(NEEDED, $NEEDED)
commit 79019541e7c56ddfc3828b7bf96e6e5d3cf81c56
Author: Keith Packard <keithp at keithp.com>
Date: Fri Apr 12 20:15:41 2013 -0700
Add event queue splitting
This allows apps to peel off certain XGE events into separate queues
for custom handling. Designed to support the Present extension
Signed-off-by: Keith Packard <keithp at keithp.com>
Reviewed-By: Uli Schlachter <psychon at znc.in>
diff --git a/src/xcb.h b/src/xcb.h
index 1fd1f6c..63864dc 100644
--- a/src/xcb.h
+++ b/src/xcb.h
@@ -290,6 +290,39 @@ xcb_generic_event_t *xcb_poll_for_event(xcb_connection_t *c);
*/
xcb_generic_event_t *xcb_poll_for_queued_event(xcb_connection_t *c);
+typedef struct xcb_special_event xcb_special_event_t;
+
+/**
+ * @brief Returns the next event from a special queue
+ */
+xcb_generic_event_t *xcb_poll_for_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se);
+
+/**
+ * @brief Returns the next event from a special queue, blocking until one arrives
+ */
+xcb_generic_event_t *xcb_wait_for_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se);
+/**
+ * @typedef typedef struct xcb_extension_t xcb_extension_t
+ */
+typedef struct xcb_extension_t xcb_extension_t; /**< Opaque structure used as key for xcb_get_extension_data_t. */
+
+
+/**
+ * @brief Listen for a special event
+ */
+xcb_special_event_t *xcb_register_for_special_xge(xcb_connection_t *c,
+ xcb_extension_t *ext,
+ uint32_t eid,
+ uint32_t *stamp);
+
+/**
+ * @brief Stop listening for a special event
+ */
+void xcb_unregister_for_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se);
+
/**
* @brief Return the error for a request, or NULL if none can ever arrive.
* @param c: The connection to the X server.
@@ -328,11 +361,6 @@ void xcb_discard_reply(xcb_connection_t *c, unsigned int sequence);
/* xcb_ext.c */
/**
- * @typedef typedef struct xcb_extension_t xcb_extension_t
- */
-typedef struct xcb_extension_t xcb_extension_t; /**< Opaque structure used as key for xcb_get_extension_data_t. */
-
-/**
* @brief Caches reply information from QueryExtension requests.
* @param c: The connection.
* @param ext: The extension data.
diff --git a/src/xcb_in.c b/src/xcb_in.c
index b161e93..839f615 100644
--- a/src/xcb_in.c
+++ b/src/xcb_in.c
@@ -60,6 +60,23 @@ struct event_list {
struct event_list *next;
};
+struct xcb_special_event {
+
+ struct xcb_special_event *next;
+
+ /* Match XGE events for the specific extension and event ID (the
+ * first 32 bit word after evtype)
+ */
+ uint8_t extension;
+ uint32_t eid;
+ uint32_t *stamp;
+
+ struct event_list *events;
+ struct event_list **events_tail;
+
+ pthread_cond_t special_event_cond;
+};
+
struct reply_list {
void *reply;
struct reply_list *next;
@@ -104,6 +121,46 @@ static int read_fds(xcb_connection_t *c, int *fds, int nfd)
}
#endif
+typedef struct xcb_ge_special_event_t {
+ uint8_t response_type; /**< */
+ uint8_t extension; /**< */
+ uint16_t sequence; /**< */
+ uint32_t length; /**< */
+ uint16_t evtype; /**< */
+ uint8_t pad0[2]; /**< */
+ uint32_t eid; /**< */
+ uint8_t pad1[16]; /**< */
+} xcb_ge_special_event_t;
+
+static int event_special(xcb_connection_t *c,
+ struct event_list *event)
+{
+ struct xcb_special_event *special_event;
+ struct xcb_ge_special_event_t *ges = (void *) event->event;
+
+ /* Special events are always XGE events */
+ if ((ges->response_type & 0x7f) != XCB_XGE_EVENT)
+ return 0;
+
+ for (special_event = c->in.special_events;
+ special_event;
+ special_event = special_event->next)
+ {
+ if (ges->extension == special_event->extension &&
+ ges->eid == special_event->eid)
+ {
+ *special_event->events_tail = event;
+ special_event->events_tail = &event->next;
+ if (special_event->stamp)
+ ++(*special_event->stamp);
+ pthread_cond_signal(&special_event->special_event_cond);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
static int read_packet(xcb_connection_t *c)
{
xcb_generic_reply_t genrep;
@@ -268,9 +325,12 @@ static int read_packet(xcb_connection_t *c)
}
event->event = buf;
event->next = 0;
- *c->in.events_tail = event;
- c->in.events_tail = &event->next;
- pthread_cond_signal(&c->in.event_cond);
+
+ if (!event_special(c, event)) {
+ *c->in.events_tail = event;
+ c->in.events_tail = &event->next;
+ pthread_cond_signal(&c->in.event_cond);
+ }
return 1; /* I have something for you... */
}
@@ -661,17 +721,21 @@ xcb_generic_event_t *xcb_wait_for_special_event(xcb_connection_t *c,
xcb_special_event_t *
xcb_register_for_special_xge(xcb_connection_t *c,
- uint8_t extension,
+ xcb_extension_t *ext,
uint32_t eid,
uint32_t *stamp)
{
xcb_special_event_t *se;
+ const xcb_query_extension_reply_t *ext_reply;
if(c->has_error)
return NULL;
+ ext_reply = xcb_get_extension_data(c, ext);
+ if (!ext_reply)
+ return NULL;
pthread_mutex_lock(&c->iolock);
for (se = c->in.special_events; se; se = se->next) {
- if (se->extension == extension &&
+ if (se->extension == ext_reply->major_opcode &&
se->eid == eid) {
pthread_mutex_unlock(&c->iolock);
return NULL;
@@ -683,7 +747,7 @@ xcb_register_for_special_xge(xcb_connection_t *c,
return NULL;
}
- se->extension = extension;
+ se->extension = ext_reply->major_opcode;
se->eid = eid;
se->events = NULL;
@@ -694,7 +758,6 @@ xcb_register_for_special_xge(xcb_connection_t *c,
se->next = c->in.special_events;
c->in.special_events = se;
-
pthread_mutex_unlock(&c->iolock);
return se;
}
@@ -706,6 +769,9 @@ xcb_unregister_for_special_event(xcb_connection_t *c,
xcb_special_event_t *s, **prev;
struct event_list *events, *next;
+ if (!se)
+ return;
+
if (c->has_error)
return;
diff --git a/src/xcbint.h b/src/xcbint.h
index 4a01f6f..e122f2f 100644
--- a/src/xcbint.h
+++ b/src/xcbint.h
@@ -154,6 +154,7 @@ typedef struct _xcb_in {
#if HAVE_SENDMSG
_xcb_fd in_fd;
#endif
+ struct xcb_special_event *special_events;
} _xcb_in;
int _xcb_in_init(_xcb_in *in);
commit 7983bf0fbdc2725403f9db6154d0f5bc944040e5
Author: Keith Packard <keithp at keithp.com>
Date: Fri Jan 18 01:29:40 2013 -0800
Add support for receiving fds in replies
Requests signal which replies will have fds, and the replies report
how many fds they expect in byte 1.
Signed-off-by: Keith Packard <keithp at keithp.com>
Reviewed-By: Uli Schlachter <psychon at znc.in>
diff --git a/src/c_client.py b/src/c_client.py
index cc26f72..7280004 100644
--- a/src/c_client.py
+++ b/src/c_client.py
@@ -303,6 +303,7 @@ def _c_type_setup(self, name, postfix):
self.c_reply_name = _n(name + ('reply',))
self.c_reply_type = _t(name + ('reply',))
self.c_cookie_type = _t(name + ('cookie',))
+ self.c_reply_fds_name = _n(name + ('reply_fds',))
self.need_aux = False
self.need_serialize = False
@@ -1835,7 +1836,7 @@ def c_union(self, name):
_c_complex(self)
_c_iterator(self, name)
-def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
+def _c_request_helper(self, name, cookie_type, void, regular, aux=False, reply_fds=False):
'''
Declares a request function.
'''
@@ -1864,6 +1865,12 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
# What flag is passed to xcb_request
func_flags = '0' if (void and regular) or (not void and not regular) else 'XCB_REQUEST_CHECKED'
+ if reply_fds:
+ if func_flags == '0':
+ func_flags = 'XCB_REQUEST_REPLY_FDS'
+ else:
+ func_flags = func_flags + '|XCB_REQUEST_REPLY_FDS'
+
# Global extension id variable or NULL for xproto
func_ext_global = '&' + _ns.c_ext_global_name if _ns.is_ext else '0'
@@ -2256,6 +2263,51 @@ def _c_reply(self, name):
_c('}')
+def _c_reply_has_fds(self):
+ for field in self.fields:
+ if field.isfd:
+ return True
+ return False
+
+def _c_reply_fds(self, name):
+ '''
+ Declares the function that returns fds related to the reply.
+ '''
+ spacing1 = ' ' * (len(self.c_reply_type) - len('xcb_connection_t'))
+ spacing3 = ' ' * (len(self.c_reply_fds_name) + 2)
+ _h('')
+ _h('/**')
+ _h(' * Return the reply fds')
+ _h(' * @param c The connection')
+ _h(' * @param reply The reply')
+ _h(' *')
+ _h(' * Returns the array of reply fds of the request asked by')
+ _h(' * ')
+ _h(' * The returned value must be freed by the caller using free().')
+ _h(' */')
+ _c('')
+ _hc('')
+ _hc('/*****************************************************************************')
+ _hc(' **')
+ _hc(' ** int * %s', self.c_reply_fds_name)
+ _hc(' ** ')
+ _hc(' ** @param xcb_connection_t%s *c', spacing1)
+ _hc(' ** @param %s *reply', self.c_reply_type)
+ _hc(' ** @returns int *')
+ _hc(' **')
+ _hc(' *****************************************************************************/')
+ _hc(' ')
+ _hc('int *')
+ _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_fds_name, spacing1)
+ _h('%s%s *reply /**< */);', spacing3, self.c_reply_type)
+ _c('%s%s *reply /**< */)', spacing3, self.c_reply_type)
+ _c('{')
+
+ _c(' return xcb_get_reply_fds(c, reply, sizeof(%s) + 4 * reply->length);', self.c_reply_type)
+
+ _c('}')
+
+
def _c_opcode(name, opcode):
'''
Declares the opcode define for requests, events, and errors.
@@ -2816,14 +2868,17 @@ def c_request(self, name):
# Reply structure definition
_c_complex(self.reply)
# Request prototypes
- _c_request_helper(self, name, self.c_cookie_type, False, True)
- _c_request_helper(self, name, self.c_cookie_type, False, False)
+ has_fds = _c_reply_has_fds(self.reply)
+ _c_request_helper(self, name, self.c_cookie_type, False, True, False, has_fds)
+ _c_request_helper(self, name, self.c_cookie_type, False, False, False, has_fds)
if self.need_aux:
- _c_request_helper(self, name, self.c_cookie_type, False, True, True)
- _c_request_helper(self, name, self.c_cookie_type, False, False, True)
+ _c_request_helper(self, name, self.c_cookie_type, False, True, True, has_fds)
+ _c_request_helper(self, name, self.c_cookie_type, False, False, True, has_fds)
# Reply accessors
_c_accessors(self.reply, name + ('reply',), name)
_c_reply(self, name)
+ if has_fds:
+ _c_reply_fds(self, name)
else:
# Request prototypes
_c_request_helper(self, name, 'xcb_void_cookie_t', True, False)
diff --git a/src/xcb_in.c b/src/xcb_in.c
index 8a7af92..b161e93 100644
--- a/src/xcb_in.c
+++ b/src/xcb_in.c
@@ -90,11 +90,26 @@ static void remove_finished_readers(reader_list **prev_reader, uint64_t complete
}
}
+#if HAVE_SENDMSG
+static int read_fds(xcb_connection_t *c, int *fds, int nfd)
+{
+ int *ifds = &c->in.in_fd.fd[c->in.in_fd.ifd];
+ int infd = c->in.in_fd.nfd - c->in.in_fd.ifd;
+
+ if (nfd > infd)
+ return 0;
+ memcpy(fds, ifds, nfd * sizeof (int));
+ c->in.in_fd.ifd += nfd;
+ return 1;
+}
+#endif
+
static int read_packet(xcb_connection_t *c)
{
xcb_generic_reply_t genrep;
uint64_t length = 32;
uint64_t eventlength = 0; /* length after first 32 bytes for GenericEvents */
+ int nfd = 0; /* Number of file descriptors attached to the reply */
uint64_t bufsize;
void *buf;
pending_reply *pend = 0;
@@ -164,13 +179,18 @@ static int read_packet(xcb_connection_t *c)
genrep.length = p[2] * p[3] * 2;
}
length += genrep.length * 4;
+
+ /* XXX a bit of a hack -- we "know" that all FD replys place
+ * the number of fds in the pad0 byte */
+ if (pend && pend->flags & XCB_REQUEST_REPLY_FDS)
+ nfd = genrep.pad0;
}
/* XGE events may have sizes > 32 */
if ((genrep.response_type & 0x7f) == XCB_XGE_EVENT)
eventlength = genrep.length * 4;
- bufsize = length + eventlength +
+ bufsize = length + eventlength + nfd * sizeof(int) +
(genrep.response_type == XCB_REPLY ? 0 : sizeof(uint32_t));
if (bufsize < INT32_MAX)
buf = malloc((size_t) bufsize);
@@ -198,6 +218,17 @@ static int read_packet(xcb_connection_t *c)
}
}
+#if HAVE_SENDMSG
+ if (nfd)
+ {
+ if (!read_fds(c, (int *) &((char *) buf)[length], nfd))
+ {
+ free(buf);
+ return 0;
+ }
+ }
+#endif
+
if(pend && (pend->flags & XCB_REQUEST_DISCARD_REPLY))
{
free(buf);
@@ -431,6 +462,11 @@ void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_
return ret;
}
+int *xcb_get_reply_fds(xcb_connection_t *c, void *reply, size_t reply_size)
+{
+ return (int *) (&((char *) reply)[reply_size]);
+}
+
static void insert_pending_discard(xcb_connection_t *c, pending_reply **prev_next, uint64_t seq)
{
pending_reply *pend;
@@ -577,6 +613,120 @@ xcb_generic_error_t *xcb_request_check(xcb_connection_t *c, xcb_void_cookie_t co
return ret;
}
+static xcb_generic_event_t *get_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se)
+{
+ xcb_generic_event_t *event = NULL;
+ struct event_list *events;
+
+ if ((events = se->events) != NULL) {
+ event = events->event;
+ if (!(se->events = events->next))
+ se->events_tail = &se->events;
+ free (events);
+ }
+ return event;
+}
+
+xcb_generic_event_t *xcb_poll_for_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se)
+{
+ xcb_generic_event_t *event;
+
+ if(c->has_error)
+ return 0;
+ pthread_mutex_lock(&c->iolock);
+ event = get_special_event(c, se);
+ pthread_mutex_unlock(&c->iolock);
+ return event;
+}
+
+xcb_generic_event_t *xcb_wait_for_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se)
+{
+ xcb_generic_event_t *event;
+
+ if(c->has_error)
+ return 0;
+ pthread_mutex_lock(&c->iolock);
+
+ /* get_special_event returns 0 on empty list. */
+ while(!(event = get_special_event(c, se)))
+ if(!_xcb_conn_wait(c, &se->special_event_cond, 0, 0))
+ break;
+
+ pthread_mutex_unlock(&c->iolock);
+ return event;
+}
+
+xcb_special_event_t *
+xcb_register_for_special_xge(xcb_connection_t *c,
+ uint8_t extension,
+ uint32_t eid,
+ uint32_t *stamp)
+{
+ xcb_special_event_t *se;
+
+ if(c->has_error)
+ return NULL;
+ pthread_mutex_lock(&c->iolock);
+ for (se = c->in.special_events; se; se = se->next) {
+ if (se->extension == extension &&
+ se->eid == eid) {
+ pthread_mutex_unlock(&c->iolock);
+ return NULL;
+ }
+ }
+ se = calloc(1, sizeof(xcb_special_event_t));
+ if (!se) {
+ pthread_mutex_unlock(&c->iolock);
+ return NULL;
+ }
+
+ se->extension = extension;
+ se->eid = eid;
+
+ se->events = NULL;
+ se->events_tail = &se->events;
+ se->stamp = stamp;
+
+ pthread_cond_init(&se->special_event_cond, 0);
+
+ se->next = c->in.special_events;
+ c->in.special_events = se;
+
+ pthread_mutex_unlock(&c->iolock);
+ return se;
+}
+
+void
+xcb_unregister_for_special_event(xcb_connection_t *c,
+ xcb_special_event_t *se)
+{
+ xcb_special_event_t *s, **prev;
+ struct event_list *events, *next;
+
+ if (c->has_error)
+ return;
+
+ pthread_mutex_lock(&c->iolock);
+
+ for (prev = &c->in.special_events; (s = *prev) != NULL; prev = &(s->next)) {
+ if (s == se) {
+ *prev = se->next;
+ for (events = se->events; events; events = next) {
+ next = events->next;
+ free (events->event);
+ free (events);
+ }
+ pthread_cond_destroy(&se->special_event_cond);
+ free (se);
+ break;
+ }
+ }
+ pthread_mutex_unlock(&c->iolock);
+}
+
/* Private interface */
int _xcb_in_init(_xcb_in *in)
@@ -665,11 +815,79 @@ void _xcb_in_replies_done(xcb_connection_t *c)
int _xcb_in_read(xcb_connection_t *c)
{
- int n = recv(c->fd, c->in.queue + c->in.queue_len, sizeof(c->in.queue) - c->in.queue_len, 0);
- if(n > 0)
+ int n;
+
+#if HAVE_SENDMSG
+ struct iovec iov = {
+ .iov_base = c->in.queue + c->in.queue_len,
+ .iov_len = sizeof(c->in.queue) - c->in.queue_len,
+ };
+ struct {
+ struct cmsghdr cmsghdr;
+ int fd[XCB_MAX_PASS_FD];
+ } fds;
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = &fds,
+ .msg_controllen = sizeof (struct cmsghdr) + sizeof(int) * (XCB_MAX_PASS_FD - c->in.in_fd.nfd),
+ };
+ n = recvmsg(c->fd, &msg, 0);
+
+ /* Check for truncation errors. Only MSG_CTRUNC is
+ * probably possible here, which would indicate that
+ * the sender tried to transmit more than XCB_MAX_PASS_FD
+ * file descriptors.
+ */
+ if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
+ _xcb_conn_shutdown(c, XCB_CONN_CLOSED_FDPASSING_FAILED);
+ return 0;
+ }
+#else
+ n = recv(c->fd, c->in.queue + c->in.queue_len, sizeof(c->in.queue) - c->in.queue_len, 0);
+#endif
+ if(n > 0) {
+#if HAVE_SENDMSG
+ if (msg.msg_controllen > sizeof (struct cmsghdr))
+ {
+ if (fds.cmsghdr.cmsg_level == SOL_SOCKET &&
+ fds.cmsghdr.cmsg_type == SCM_RIGHTS)
+ {
+ int nfd = (msg.msg_controllen - sizeof (struct cmsghdr)) / sizeof (int);
+ memmove(&c->in.in_fd.fd[c->in.in_fd.nfd],
+ fds.fd,
+ nfd);
+ c->in.in_fd.nfd += nfd;
+ }
+ }
+#endif
c->in.queue_len += n;
+ }
while(read_packet(c))
/* empty */;
+#if HAVE_SENDMSG
+ if (c->in.in_fd.nfd) {
+ c->in.in_fd.nfd -= c->in.in_fd.ifd;
+ memmove(&c->in.in_fd.fd[0],
+ &c->in.in_fd.fd[c->in.in_fd.ifd],
+ c->in.in_fd.nfd * sizeof (int));
+ c->in.in_fd.ifd = 0;
+
+ /* If we have any left-over file descriptors after emptying
+ * the input buffer, then the server sent some that we weren't
+ * expecting. Close them and mark the connection as broken;
+ */
+ if (c->in.queue_len == 0 && c->in.in_fd.nfd != 0) {
+ int i;
+ for (i = 0; i < c->in.in_fd.nfd; i++)
+ close(c->in.in_fd.fd[i]);
+ _xcb_conn_shutdown(c, XCB_CONN_CLOSED_FDPASSING_FAILED);
+ return 0;
+ }
+ }
+#endif
#ifndef _WIN32
if((n > 0) || (n < 0 && errno == EAGAIN))
#else
diff --git a/src/xcbext.h b/src/xcbext.h
index 44030c3..1eb1be7 100644
--- a/src/xcbext.h
+++ b/src/xcbext.h
@@ -54,7 +54,8 @@ typedef struct {
enum xcb_send_request_flags_t {
XCB_REQUEST_CHECKED = 1 << 0,
XCB_REQUEST_RAW = 1 << 1,
- XCB_REQUEST_DISCARD_REPLY = 1 << 2
+ XCB_REQUEST_DISCARD_REPLY = 1 << 2,
+ XCB_REQUEST_REPLY_FDS = 1 << 3
};
unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *request);
@@ -91,6 +92,7 @@ int xcb_writev(xcb_connection_t *c, struct iovec *vector, int count, uint64_t re
void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_error_t **e);
int xcb_poll_for_reply(xcb_connection_t *c, unsigned int request, void **reply, xcb_generic_error_t **error);
+int *xcb_get_reply_fds(xcb_connection_t *c, void *reply, size_t replylen);
/* xcb_util.c */
diff --git a/src/xcbint.h b/src/xcbint.h
index 391a4e1..4a01f6f 100644
--- a/src/xcbint.h
+++ b/src/xcbint.h
@@ -92,6 +92,7 @@ typedef struct _xcb_fd {
struct cmsghdr cmsghdr;
int fd[XCB_MAX_PASS_FD];
int nfd;
+ int ifd;
} _xcb_fd;
#endif
@@ -150,6 +151,9 @@ typedef struct _xcb_in {
struct pending_reply *pending_replies;
struct pending_reply **pending_replies_tail;
+#if HAVE_SENDMSG
+ _xcb_fd in_fd;
+#endif
} _xcb_in;
int _xcb_in_init(_xcb_in *in);
commit 7b53fb0f9bddae77b3ab8823743db57faee4e99b
Author: Keith Packard <keithp at keithp.com>
Date: Mon Jan 14 11:23:00 2013 -0800
Add xcb_send_fd API
This uses sendmsg to transmit file descriptors from the application to
the X server
Signed-off-by: Keith Packard <keithp at keithp.com>
Reviewed-By: Uli Schlachter <psychon at znc.in>
diff --git a/configure.ac b/configure.ac
index 4a30584..54cda2f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -81,6 +81,19 @@ AC_HEADER_STDC
AC_SEARCH_LIBS(getaddrinfo, socket)
AC_SEARCH_LIBS(connect, socket)
+have_sendmsg="no"
+case $host_os in
+linux*)
+ AC_SEARCH_LIBS(sendmsg, socket, [have_sendmsg="yes"], [have_sendmsg="no"])
+ ;;
+esac
+
+case x$have_sendmsg in
+xyes)
+ AC_DEFINE([HAVE_SENDMSG],1,[Define if your platform supports sendmsg])
+ ;;
+esac
+
have_win32="no"
lt_enable_auto_import=""
case $host_os in
@@ -250,6 +263,7 @@ echo " Package: ${PACKAGE_NAME} ${PACKAGE_VERSION}"
echo ""
echo " Configuration"
echo " XDM support.........: ${have_xdmcp}"
+echo " sendmsg fd passing..: ${have_sendmsg}"
echo " Build unit tests....: ${HAVE_CHECK}"
echo " with html results.: ${HTML_CHECK_RESULT}"
echo " XCB buffer size.....: ${xcb_queue_buffer_size}"
diff --git a/src/c_client.py b/src/c_client.py
index a6f8edd..cc26f72 100644
--- a/src/c_client.py
+++ b/src/c_client.py
@@ -2149,6 +2149,10 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
# no padding necessary - _serialize() keeps track of padding automatically
_c(' ')
+ for field in param_fields:
+ if field.isfd:
+ _c(' xcb_send_fd(c, %s);', field.c_field_name)
+
_c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags)
# free dyn. all. data, if any
diff --git a/src/xcb.h b/src/xcb.h
index c251330..1fd1f6c 100644
--- a/src/xcb.h
+++ b/src/xcb.h
@@ -87,6 +87,9 @@ extern "C" {
/** Connection closed because the server does not have a screen matching the display. */
#define XCB_CONN_CLOSED_INVALID_SCREEN 6
+/** Connection closed because some FD passing operation failed */
+#define XCB_CONN_CLOSED_FDPASSING_FAILED 7
+
#define XCB_TYPE_PAD(T,I) (-(I) & (sizeof(T) > 4 ? 3 : sizeof(T) - 1))
/* Opaque structures */
diff --git a/src/xcb_conn.c b/src/xcb_conn.c
index 7dd25d3..c06c7cb 100644
--- a/src/xcb_conn.c
+++ b/src/xcb_conn.c
@@ -214,9 +214,34 @@ static int write_vec(xcb_connection_t *c, struct iovec **vector, int *count)
if (n > IOV_MAX)
n = IOV_MAX;
- n = writev(c->fd, *vector, n);
- if(n < 0 && errno == EAGAIN)
- return 1;
+#if HAVE_SENDMSG
+ if (c->out.out_fd.nfd) {
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_iov = *vector,
+ .msg_iovlen = n,
+ .msg_control = &c->out.out_fd,
+ .msg_controllen = sizeof (struct cmsghdr) + c->out.out_fd.nfd * sizeof (int),
+ };
+ int i;
+ c->out.out_fd.cmsghdr.cmsg_len = msg.msg_controllen;
+ c->out.out_fd.cmsghdr.cmsg_level = SOL_SOCKET;
+ c->out.out_fd.cmsghdr.cmsg_type = SCM_RIGHTS;
+ n = sendmsg(c->fd, &msg, 0);
+ if(n < 0 && errno == EAGAIN)
+ return 1;
+ for (i = 0; i < c->out.out_fd.nfd; i++)
+ close(c->out.out_fd.fd[i]);
+ c->out.out_fd.nfd = 0;
+ } else
+#endif
+ {
+ n = writev(c->fd, *vector, n);
+ if(n < 0 && errno == EAGAIN)
+ return 1;
+ }
+
#endif /* _WIN32 */
if(n <= 0)
diff --git a/src/xcb_out.c b/src/xcb_out.c
index 429fa99..1a3aca5 100644
--- a/src/xcb_out.c
+++ b/src/xcb_out.c
@@ -263,6 +263,24 @@ unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vect
return request;
}
+void
+xcb_send_fd(xcb_connection_t *c, int fd)
+{
+#if HAVE_SENDMSG
+ if (c->has_error)
+ return;
+ pthread_mutex_lock(&c->iolock);
+ while (c->out.out_fd.nfd == XCB_MAX_PASS_FD) {
+ _xcb_out_flush_to(c, c->out.request);
+ if (c->has_error)
+ break;
+ }
+ if (!c->has_error)
+ c->out.out_fd.fd[c->out.out_fd.nfd++] = fd;
+ pthread_mutex_unlock(&c->iolock);
+#endif
+}
+
int xcb_take_socket(xcb_connection_t *c, void (*return_socket)(void *closure), void *closure, int flags, uint64_t *sent)
{
int ret;
diff --git a/src/xcbext.h b/src/xcbext.h
index 4e1f2f7..44030c3 100644
--- a/src/xcbext.h
+++ b/src/xcbext.h
@@ -59,6 +59,8 @@ enum xcb_send_request_flags_t {
unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *request);
+void xcb_send_fd(xcb_connection_t *c, int fd);
+
/* xcb_take_socket allows external code to ask XCB for permission to
* take over the write side of the socket and send raw data with
* xcb_writev. xcb_take_socket provides the sequence number of the last
diff --git a/src/xcbint.h b/src/xcbint.h
index 7f9ab28..391a4e1 100644
--- a/src/xcbint.h
+++ b/src/xcbint.h
@@ -34,6 +34,10 @@
#include "config.h"
#endif
+#if HAVE_SENDMSG
+#include <sys/socket.h>
+#endif
+
#ifdef GCC_HAS_VISIBILITY
#pragma GCC visibility push(hidden)
#endif
@@ -81,6 +85,16 @@ void *_xcb_map_remove(_xcb_map *q, unsigned int key);
typedef void (*xcb_return_socket_func_t)(void *closure);
+#if HAVE_SENDMSG
+#define XCB_MAX_PASS_FD 16
+
+typedef struct _xcb_fd {
+ struct cmsghdr cmsghdr;
+ int fd[XCB_MAX_PASS_FD];
+ int nfd;
+} _xcb_fd;
+#endif
+
typedef struct _xcb_out {
pthread_cond_t cond;
int writing;
@@ -101,6 +115,9 @@ typedef struct _xcb_out {
xcb_big_requests_enable_cookie_t cookie;
uint32_t value;
} maximum_request_length;
+#if HAVE_SENDMSG
+ _xcb_fd out_fd;
+#endif
} _xcb_out;
int _xcb_out_init(_xcb_out *out);
commit 98c227a2222fb5c7ca7e8101b1ed2bc096a33048
Author: Keith Packard <keithp at keithp.com>
Date: Fri Jan 18 01:28:56 2013 -0800
-pendantic is too pendantic
Many system headers have warnings when compiled with this flag.
Signed-off-by: Keith Packard <keithp at keithp.com>
Reviewed-By: Uli Schlachter <psychon at znc.in>
diff --git a/configure.ac b/configure.ac
index 6c107bc..4a30584 100644
--- a/configure.ac
+++ b/configure.ac
@@ -128,7 +128,7 @@ xcbincludedir='${includedir}/xcb'
AC_SUBST(xcbincludedir)
if test "x$GCC" = xyes ; then
- CWARNFLAGS="-Wall -pedantic -Wpointer-arith -Wold-style-definition \
+ CWARNFLAGS="-Wall -Wpointer-arith -Wold-style-definition \
-Wstrict-prototypes -Wmissing-declarations -Wnested-externs"
else
AC_CHECK_DECL([__SUNPRO_C], [SUNCC="yes"], [SUNCC="no"])
commit d04a4a03a90f2721d507287938c90f1755d9da0e
Author: Keith Packard <keithp at keithp.com>
Date: Fri Jul 12 10:32:03 2013 -0700
Make protocol C files depend on protocol XML files
When new XML files get installed, make sure the C files are regenerated
Signed-off-by: Keith Packard <keithp at keithp.com>
Reviewed-By: Uli Schlachter <psychon at znc.in>
diff --git a/src/Makefile.am b/src/Makefile.am
index 6b5a2c3..f48e14e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -233,7 +233,7 @@ EXTRA_DIST = $(STATIC_MANS)
BUILT_SOURCES = $(EXTSOURCES) $(BUILT_MANS)
CLEANFILES = $(EXTSOURCES) $(EXTHEADERS) $(BUILT_MANS)
-$(EXTSOURCES): c_client.py
+$(EXTSOURCES): c_client.py $(XCBPROTO_XCBINCLUDEDIR)/$(@:.c=.xml)
$(PYTHON) $(srcdir)/c_client.py -p $(XCBPROTO_XCBPYTHONDIR) $(XCBPROTO_XCBINCLUDEDIR)/$(@:.c=.xml)
$(man_MANS): $(EXTSOURCES)
commit f4d5b84800f960831e4fbb3ad9848bbb701020be
Author: Keith Packard <keithp at keithp.com>
Date: Wed Nov 6 19:33:53 2013 -0800
Remove xcb_ge_event_t from xcb.h
xcb proto now publishes this structure from an XML description
Signed-off-by: Keith Packard <keithp at keithp.com>
diff --git a/src/xcb.h b/src/xcb.h
index 0714130..c251330 100644
--- a/src/xcb.h
+++ b/src/xcb.h
@@ -138,23 +138,6 @@ typedef struct {
} xcb_generic_event_t;
/**
- * @brief GE event
- *
- * An event as sent by the XGE extension. The length field specifies the
- * number of 4-byte blocks trailing the struct.
- */
-typedef struct {
- uint8_t response_type; /**< Type of the response */
- uint8_t pad0; /**< Padding */
- uint16_t sequence; /**< Sequence number */
- uint32_t length;
- uint16_t event_type;
- uint16_t pad1;
- uint32_t pad[5]; /**< Padding */
- uint32_t full_sequence; /**< full sequence */
-} xcb_ge_event_t;
-
-/**
* @brief Generic error.
*
* A generic error structure.
More information about the xcb-commit
mailing list