Merge branch 'master' into debian

This commit is contained in:
Jamey Sharp 2007-11-05 15:58:40 -08:00
commit e9f909add8
16 changed files with 1133 additions and 203 deletions

View File

@ -48,4 +48,8 @@ xcb-xfixes.pc.in \
xcb-xprint.pc.in \ xcb-xprint.pc.in \
xcb-xtest.pc.in \ xcb-xtest.pc.in \
xcb-xv.pc.in \ xcb-xv.pc.in \
xcb-xvmc.pc.in xcb-xvmc.pc.in \
tools/README \
tools/api_conv.pl \
tools/constants \
autogen.sh

57
NEWS
View File

@ -1,3 +1,60 @@
Release 1.1 (2007-11-04)
========================
This release requires xcb-proto 1.1, due to the addition of the
extension-multiword attribute to the XML schema.
This release contains several important bug fixes, summarized below. It
also contains a patch much like Novell's libxcb-sloppy-lock.diff.
Rationale from the commit message follows. The patch and this rationale
were authored by Jamey Sharp <jamey@minilop.net>, with agreement from
Josh Triplett <josh@freedesktop.org>.
I strongly opposed proposals like this one for a long time.
Originally I had a very good reason: libX11, when compiled to use
XCB, would crash soon after a locking correctness violation, so it
was better to have an informative assert failure than a mystifying
crash soon after.
It took some time for me to realize that I'd changed the libX11
implementation (for unrelated reasons) so that it could survive most
invalid locking situations, as long as it wasn't actually being used
from multiple threads concurrently.
The other thing that has changed is that most of the code with
incorrect locking has now been fixed. The value of the assert is
accordingly lower.
However, remaining broken callers do need to be fixed. That's why
libXCB will still noisily print a stacktrace (if possible) on each
assertion failure, even when assert isn't actually invoked to
abort() the program; and that's why aborting is still default. This
environment variable is provided only for use as a temporary
workaround for broken applications.
Enhancements:
* Print a backtrace, if possible, on locking assertion failures.
* Skip abort() on locking assertions if LIBXCB_ALLOW_SLOPPY_LOCK is set.
* xcb_poll_for_event: Return already-read events before reading again.
* Output a configuration summary at the end of ./configure.
Bug fixes:
* Don't hold the xlib-xcb lock while sleeping: that allows deadlock.
* Allow unix:<screen> style display names again.
* Bug #9119: test xcb_popcount
* Fix unit tests for FreeBSD
* NetBSD doesn't have AI_ADDRCONFIG: use it only if it's available.
* Require libXau >= 0.99.2; earlier versions have a broken .pc file
* Use substitition variables in xcb-xinerama.pc.in
* Update autogen.sh to one that does objdir != srcdir
* Add tools/* and autogen.sh to EXTRA_DIST.
* Doxygen can now be fully disabled if desired.
Documentation improvements:
* Many fixes and updates to the tutorial.
* Iterators, requests, and replies get partial Doxygen documentation.
Release 1.0 (2006-11-23) Release 1.0 (2006-11-23)
======================== ========================

9
README
View File

@ -1,11 +1,12 @@
About libxcb About libxcb
============ ============
libxcb provides an interface to the X Window System protocol, which replaces libxcb provides an interface to the X Window System protocol, which
the current Xlib interface. It has several advantages over Xlib, including: replaces the current Xlib interface. It has several advantages over
- size: small library and lower memory footprint Xlib, including:
- size: small, simple library, and lower memory footprint
- latency hiding: batch several requests and wait for the replies later - latency hiding: batch several requests and wait for the replies later
- direct protocol access: one-to-one mapping between interface and protocol - direct protocol access: interface and protocol correspond exactly
- proven thread support: transparently access XCB from multiple threads - proven thread support: transparently access XCB from multiple threads
- easy extension implementation: interfaces auto-generated from XML-XCB - easy extension implementation: interfaces auto-generated from XML-XCB

View File

@ -44,12 +44,16 @@ AC_DEFUN([AM_CHECK_DOXYGEN],
AC_HELP_STRING( AC_HELP_STRING(
[--disable-build-docs], [--disable-build-docs],
[Disable the build of the documentation]), [Disable the build of the documentation]),
[if test "${disable_build_docs}" = "yes" ; then [if test x"$enableval" != x"yes" ; then
enable_build_docs="no" enable_build_docs="no"
else else
enable_build_docs="yes" enable_build_docs="yes"
fi], fi],
[enable_build_docs="yes"]) [enable_build_docs="yes"])
if test "$enable_build_docs" = "no" ; then
BUILD_DOCS=no
else
dnl dnl
dnl Get the prefix where doxygen is installed. dnl Get the prefix where doxygen is installed.
dnl dnl
@ -93,6 +97,7 @@ AC_DEFUN([AM_CHECK_DOXYGEN],
AC_MSG_WARN( AC_MSG_WARN(
[Warning: no doxygen detected. Documentation will not be built]) [Warning: no doxygen detected. Documentation will not be built])
fi]) fi])
fi
AC_MSG_CHECKING([whether documentation is built]) AC_MSG_CHECKING([whether documentation is built])
AC_MSG_RESULT([${BUILD_DOCS}]) AC_MSG_RESULT([${BUILD_DOCS}])
dnl dnl

View File

@ -1,3 +1,12 @@
#! /bin/sh #! /bin/sh
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
ORIGDIR=`pwd`
cd $srcdir
autoreconf -v --install || exit 1 autoreconf -v --install || exit 1
./configure "$@" cd $ORIGDIR || exit $?
$srcdir/configure --enable-maintainer-mode "$@"

View File

@ -3,13 +3,13 @@
AC_PREREQ(2.57) AC_PREREQ(2.57)
AC_INIT([libxcb], AC_INIT([libxcb],
1.0, 1.1,
[xcb@lists.freedesktop.org]) [xcb@lists.freedesktop.org])
AC_CONFIG_SRCDIR([xcb.pc.in]) AC_CONFIG_SRCDIR([xcb.pc.in])
AM_INIT_AUTOMAKE([foreign dist-bzip2]) AM_INIT_AUTOMAKE([foreign dist-bzip2])
PKG_CHECK_MODULES(CHECK, [check >= 0.9.4], [HAVE_CHECK=true], [HAVE_CHECK=false]) PKG_CHECK_MODULES(CHECK, [check >= 0.9.4], [HAVE_CHECK=yes], [HAVE_CHECK=no])
AM_CONDITIONAL(HAVE_CHECK, test x$HAVE_CHECK = xtrue) AM_CONDITIONAL(HAVE_CHECK, test x$HAVE_CHECK = xyes)
AC_CONFIG_HEADERS([src/config.h]) AC_CONFIG_HEADERS([src/config.h])
@ -22,7 +22,7 @@ if test "$XSLTPROC" = "no"; then
fi fi
HTML_CHECK_RESULT=false HTML_CHECK_RESULT=false
if test x"$HAVE_CHECK" = xtrue; then if test x"$HAVE_CHECK" = xyes; then
if test x"$XSLTPROC" != xno; then if test x"$XSLTPROC" != xno; then
HTML_CHECK_RESULT=true HTML_CHECK_RESULT=true
fi fi
@ -30,15 +30,17 @@ fi
AC_SUBST(HTML_CHECK_RESULT) AC_SUBST(HTML_CHECK_RESULT)
# Checks for pkg-config packages # Checks for pkg-config packages
PKG_CHECK_MODULES(XCBPROTO, xcb-proto >= 1.0) PKG_CHECK_MODULES(XCBPROTO, xcb-proto >= 1.1)
NEEDED="xau pthread-stubs" NEEDED="pthread-stubs xau >= 0.99.2"
PKG_CHECK_MODULES(NEEDED, $NEEDED) PKG_CHECK_MODULES(NEEDED, $NEEDED)
have_xdmcp="no"
PKG_CHECK_MODULES(XDMCP, xdmcp, PKG_CHECK_MODULES(XDMCP, xdmcp,
AC_CHECK_LIB(Xdmcp, XdmcpWrap, AC_CHECK_LIB(Xdmcp, XdmcpWrap,
[ [
AC_DEFINE(HASXDMAUTH,1,[Has Wraphelp.c needed for XDM AUTH protocols]) AC_DEFINE(HASXDMAUTH,1,[Has Wraphelp.c needed for XDM AUTH protocols])
NEEDED="$NEEDED xdmcp" NEEDED="$NEEDED xdmcp"
have_xdmcp="yes"
], ],
[ [
XDMCP_CFLAGS= XDMCP_CFLAGS=
@ -46,6 +48,8 @@ PKG_CHECK_MODULES(XDMCP, xdmcp,
], [$XDMCP_LIBS]), ], [$XDMCP_LIBS]),
[AC_MSG_RESULT(no)]) [AC_MSG_RESULT(no)])
AC_CHECK_HEADER([execinfo.h], [AC_DEFINE(HAVE_BACKTRACE,1,[Has backtrace*() needed for retrieving stack traces])])
AC_SUBST(NEEDED) AC_SUBST(NEEDED)
# Find the xcb-proto protocol descriptions # Find the xcb-proto protocol descriptions
@ -87,3 +91,21 @@ AC_CONFIG_FILES([xcb.pc xcb-xlib.pc xcb-composite.pc xcb-damage.pc xcb-dpms.pc x
AC_CONFIG_FILES([doc/xcb.doxygen]) AC_CONFIG_FILES([doc/xcb.doxygen])
AC_OUTPUT AC_OUTPUT
dnl Configuration output
echo ""
echo " Package: ${PACKAGE_NAME} ${PACKAGE_VERSION}"
echo ""
echo " Configuration"
echo " XDM support.........: ${have_xdmcp}"
echo " Build unit tests....: ${HAVE_CHECK}"
echo ""
echo " Used CFLAGS:"
echo " CPPFLAGS............: ${CPPFLAGS}"
echo " CFLAGS..............: ${CFLAGS}"
echo " Warning CFLAGS......: ${CWARNFLAGS}"
echo ""
echo " Installation:"
echo " Prefix..............: ${prefix}"
echo ""

File diff suppressed because it is too large Load Diff

View File

@ -101,23 +101,23 @@ span.code
font-family: monospace; font-family: monospace;
font-size: 12px; font-size: 12px;
} }
pre.code type pre.code .type
{ {
color: #44bb44; color: #44bb44;
} }
pre.code function pre.code .function
{ {
color: #449fb7; color: #449fb7;
} }
pre.code include pre.code .include
{ {
color: #7d93ae; color: #7d93ae;
} }
pre.code string pre.code .string
{ {
color: #ef6e4b; color: #ef6e4b;
} }
pre.code keyword pre.code .keyword
{ {
color: #00bbbb; color: #00bbbb;
} }

View File

@ -97,31 +97,19 @@ authorization from the authors.
<xsl:param name="name" /> <xsl:param name="name" />
<func:result> <func:result>
<xsl:text>xcb</xsl:text> <xsl:text>xcb</xsl:text>
<xsl:choose> <xsl:if test="/xcb/@extension-name">
<xsl:when test="/xcb/@extension-name = 'RandR'"> <xsl:text>_</xsl:text>
<xsl:text>_randr</xsl:text> <xsl:choose>
</xsl:when> <xsl:when test="/xcb/@extension-multiword = 'true' or /xcb/@extension-multiword = '1'">
<xsl:when test="/xcb/@extension-name = 'ScreenSaver'"> <xsl:call-template name="camelcase-to-underscore">
<xsl:text>_screensaver</xsl:text> <xsl:with-param name="camelcase" select="/xcb/@extension-name" />
</xsl:when> </xsl:call-template>
<xsl:when test="/xcb/@extension-name = 'XF86Dri'"> </xsl:when>
<xsl:text>_xf86dri</xsl:text> <xsl:otherwise>
</xsl:when> <xsl:value-of select="translate(/xcb/@extension-name, $ucase, $lcase)"/>
<xsl:when test="/xcb/@extension-name = 'XFixes'"> </xsl:otherwise>
<xsl:text>_xfixes</xsl:text> </xsl:choose>
</xsl:when> </xsl:if>
<xsl:when test="/xcb/@extension-name = 'XvMC'">
<xsl:text>_xvmc</xsl:text>
</xsl:when>
<xsl:when test="/xcb/@extension-name">
<xsl:text>_</xsl:text>
<xsl:call-template name="camelcase-to-underscore">
<xsl:with-param name="camelcase" select="/xcb/@extension-name" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="$name"> <xsl:if test="$name">
<xsl:text>_</xsl:text> <xsl:text>_</xsl:text>
<xsl:call-template name="camelcase-to-underscore"> <xsl:call-template name="camelcase-to-underscore">
@ -342,6 +330,24 @@ authorization from the authors.
<xsl:with-param name="request" select="$req" /> <xsl:with-param name="request" select="$req" />
</xsl:call-template> </xsl:call-template>
</xsl:attribute> </xsl:attribute>
<doc>/**</doc>
<doc> * Delivers a request to the X server</doc>
<doc> * @param c The connection</doc>
<doc> * @return A cookie</doc>
<doc> *</doc>
<doc> * Delivers a request to the X server.</doc>
<doc> * </doc>
<xsl:if test="$checked='true' and not($req/reply)">
<doc> * This form can be used only if the request will not cause</doc>
<doc> * a reply to be generated. Any returned error will be</doc>
<doc> * saved for handling by xcb_request_check().</doc>
</xsl:if>
<xsl:if test="$checked='false' and $req/reply">
<doc> * This form can be used only if the request will cause</doc>
<doc> * a reply to be generated. Any returned error will be</doc>
<doc> * placed in the event queue.</doc>
</xsl:if>
<doc> */</doc>
<field type="xcb_connection_t *" name="c" /> <field type="xcb_connection_t *" name="c" />
<xsl:apply-templates select="$req/*[not(self::reply)]" mode="param" /> <xsl:apply-templates select="$req/*[not(self::reply)]" mode="param" />
<do-request ref="{xcb:xcb-prefix($req/@name)}_request_t" opcode="{translate(xcb:xcb-prefix($req/@name), $lcase, $ucase)}" <do-request ref="{xcb:xcb-prefix($req/@name)}_request_t" opcode="{translate(xcb:xcb-prefix($req/@name), $lcase, $ucase)}"
@ -390,6 +396,18 @@ authorization from the authors.
</struct> </struct>
<iterator-functions ref="{xcb:xcb-prefix(@name)}" kind="_reply" /> <iterator-functions ref="{xcb:xcb-prefix(@name)}" kind="_reply" />
<function type="{xcb:xcb-prefix(@name)}_reply_t *" name="{xcb:xcb-prefix(@name)}_reply"> <function type="{xcb:xcb-prefix(@name)}_reply_t *" name="{xcb:xcb-prefix(@name)}_reply">
<doc>/**</doc>
<doc> * Return the reply</doc>
<doc> * @param c The connection</doc>
<doc> * @param cookie The cookie</doc>
<doc> * @param e The xcb_generic_error_t supplied</doc>
<doc> *</doc>
<doc> * Returns the reply of the request asked by</doc>
<doc> * </doc>
<doc> * The parameter @p e supplied to this function must be NULL if</doc>
<doc> * <xsl:value-of select="xcb:xcb-prefix(@name)" />_unchecked(). is used.</doc>
<doc> * Otherwise, it stores the error if any.</doc>
<doc> */</doc>
<field type="xcb_connection_t *" name="c" /> <field type="xcb_connection_t *" name="c" />
<field name="cookie"> <field name="cookie">
<xsl:attribute name="type"> <xsl:attribute name="type">
@ -924,6 +942,14 @@ authorization from the authors.
</xsl:for-each> </xsl:for-each>
<xsl:if test="not($kind)"> <xsl:if test="not($kind)">
<function type="void" name="{$ref}_next"> <function type="void" name="{$ref}_next">
<doc>/**</doc>
<doc> * Get the next element of the iterator</doc>
<doc> * @param i Pointer to a <xsl:value-of select="$ref" />_iterator_t</doc>
<doc> *</doc>
<doc> * Get the next element in the iterator. The member rem is</doc>
<doc> * decreased by one. The member data points to the next</doc>
<doc> * element. The member index is increased by sizeof(<xsl:value-of select="$ref" />_t)</doc>
<doc> */</doc>
<field type="{$ref}_iterator_t *" name="i" /> <field type="{$ref}_iterator_t *" name="i" />
<xsl:choose> <xsl:choose>
<xsl:when test="$struct/list[not(@fixed)]"> <xsl:when test="$struct/list[not(@fixed)]">
@ -942,6 +968,15 @@ authorization from the authors.
</xsl:choose> </xsl:choose>
</function> </function>
<function type="xcb_generic_iterator_t" name="{$ref}_end"> <function type="xcb_generic_iterator_t" name="{$ref}_end">
<doc>/**</doc>
<doc> * Return the iterator pointing to the last element</doc>
<doc> * @param i An <xsl:value-of select="$ref" />_iterator_t</doc>
<doc> * @return The iterator pointing to the last element</doc>
<doc> *</doc>
<doc> * Set the current element in the iterator to the last element.</doc>
<doc> * The member rem is set to 0. The member data points to the</doc>
<doc> * last element.</doc>
<doc> */</doc>
<field type="{$ref}_iterator_t" name="i" /> <field type="{$ref}_iterator_t" name="i" />
<l>xcb_generic_iterator_t ret;</l> <l>xcb_generic_iterator_t ret;</l>
<xsl:choose> <xsl:choose>
@ -1178,6 +1213,10 @@ authorization from the authors.
</xsl:call-template> </xsl:call-template>
</xsl:variable> </xsl:variable>
<!-- Doxygen for functions in header. --> <!-- Doxygen for functions in header. -->
<xsl:if test="$h">
<xsl:apply-templates select="doc" mode="function-doc">
</xsl:apply-templates>
</xsl:if>
/***************************************************************************** /*****************************************************************************
** **
** <xsl:value-of select="@type" /> ** <xsl:value-of select="@type" />
@ -1242,6 +1281,11 @@ authorization from the authors.
</xsl:if> </xsl:if>
</xsl:template> </xsl:template>
<xsl:template match="doc" mode="function-doc">
<xsl:value-of select="." /><xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="l" mode="function-body"> <xsl:template match="l" mode="function-body">
<xsl:param name="indent" /> <xsl:param name="indent" />
<xsl:value-of select="concat($indent, .)" /><xsl:text> <xsl:value-of select="concat($indent, .)" /><xsl:text>

View File

@ -62,6 +62,9 @@ static int set_fd_flags(const int fd)
static int _xcb_xlib_init(_xcb_xlib *xlib) static int _xcb_xlib_init(_xcb_xlib *xlib)
{ {
xlib->lock = 0; xlib->lock = 0;
#ifndef NDEBUG
xlib->sloppy_lock = (getenv("LIBXCB_ALLOW_SLOPPY_LOCK") != 0);
#endif
pthread_cond_init(&xlib->cond, 0); pthread_cond_init(&xlib->cond, 0);
return 1; return 1;
} }
@ -285,15 +288,33 @@ void _xcb_unlock_io(xcb_connection_t *c)
pthread_mutex_unlock(&c->iolock); pthread_mutex_unlock(&c->iolock);
} }
void _xcb_wait_io(xcb_connection_t *c, pthread_cond_t *cond)
{
int xlib_locked = c->xlib.lock;
if(xlib_locked)
{
c->xlib.lock = 0;
pthread_cond_broadcast(&c->xlib.cond);
}
pthread_cond_wait(cond, &c->iolock);
if(xlib_locked)
{
while(c->xlib.lock)
pthread_cond_wait(&c->xlib.cond, &c->iolock);
c->xlib.lock = 1;
c->xlib.thread = pthread_self();
}
}
int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vector, int *count) int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vector, int *count)
{ {
int ret; int ret, xlib_locked;
fd_set rfds, wfds; fd_set rfds, wfds;
/* If the thing I should be doing is already being done, wait for it. */ /* If the thing I should be doing is already being done, wait for it. */
if(count ? c->out.writing : c->in.reading) if(count ? c->out.writing : c->in.reading)
{ {
pthread_cond_wait(cond, &c->iolock); _xcb_wait_io(c, cond);
return 1; return 1;
} }
@ -308,6 +329,12 @@ int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vec
++c->out.writing; ++c->out.writing;
} }
xlib_locked = c->xlib.lock;
if(xlib_locked)
{
c->xlib.lock = 0;
pthread_cond_broadcast(&c->xlib.cond);
}
_xcb_unlock_io(c); _xcb_unlock_io(c);
do { do {
ret = select(c->fd + 1, &rfds, &wfds, 0, 0); ret = select(c->fd + 1, &rfds, &wfds, 0, 0);
@ -318,6 +345,11 @@ int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vec
ret = 0; ret = 0;
} }
_xcb_lock_io(c); _xcb_lock_io(c);
if(xlib_locked)
{
c->xlib.lock = 1;
c->xlib.thread = pthread_self();
}
if(ret) if(ret)
{ {

View File

@ -403,7 +403,8 @@ xcb_generic_event_t *xcb_poll_for_event(xcb_connection_t *c)
{ {
_xcb_lock_io(c); _xcb_lock_io(c);
/* FIXME: follow X meets Z architecture changes. */ /* FIXME: follow X meets Z architecture changes. */
if(_xcb_in_read(c)) /* _xcb_in_read shuts down the connection on error */ ret = get_event(c);
if(!ret && _xcb_in_read(c)) /* _xcb_in_read shuts down the connection on error */
ret = get_event(c); ret = get_event(c);
_xcb_unlock_io(c); _xcb_unlock_io(c);
} }

View File

@ -190,7 +190,7 @@ unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vect
_xcb_lock_io(c); _xcb_lock_io(c);
/* wait for other writing threads to get out of my way. */ /* wait for other writing threads to get out of my way. */
while(c->out.writing) while(c->out.writing)
pthread_cond_wait(&c->out.cond, &c->iolock); _xcb_wait_io(c, &c->out.cond);
request = ++c->out.request; request = ++c->out.request;
/* send GetInputFocus (sync) when 64k-2 requests have been sent without /* send GetInputFocus (sync) when 64k-2 requests have been sent without
@ -297,7 +297,7 @@ int _xcb_out_flush_to(xcb_connection_t *c, unsigned int request)
return _xcb_out_send(c, &vec_ptr, &count); return _xcb_out_send(c, &vec_ptr, &count);
} }
while(c->out.writing) while(c->out.writing)
pthread_cond_wait(&c->out.cond, &c->iolock); _xcb_wait_io(c, &c->out.cond);
assert(XCB_SEQUENCE_COMPARE(c->out.request_written, >=, request)); assert(XCB_SEQUENCE_COMPARE(c->out.request_written, >=, request));
return 1; return 1;
} }

View File

@ -55,14 +55,30 @@ int xcb_popcount(uint32_t mask)
return ((y + (y >> 3)) & 030707070707) % 077; return ((y + (y >> 3)) & 030707070707) % 077;
} }
int xcb_parse_display(const char *name, char **host, int *displayp, int *screenp) static int _xcb_parse_display(const char *name, char **host, char **protocol,
int *displayp, int *screenp)
{ {
int len, display, screen; int len, display, screen;
char *colon, *dot, *end; char *slash, *colon, *dot, *end;
if(!name || !*name) if(!name || !*name)
name = getenv("DISPLAY"); name = getenv("DISPLAY");
if(!name) if(!name)
return 0; return 0;
slash = strrchr(name, '/');
if (slash) {
len = slash - name;
if (protocol) {
*protocol = malloc(len + 1);
if(!*protocol)
return 0;
memcpy(*protocol, name, len);
(*protocol)[len] = '\0';
}
name = slash + 1;
} else
if (protocol)
*protocol = NULL;
colon = strrchr(name, ':'); colon = strrchr(name, ':');
if(!colon) if(!colon)
return 0; return 0;
@ -96,51 +112,58 @@ int xcb_parse_display(const char *name, char **host, int *displayp, int *screenp
return 1; return 1;
} }
static int _xcb_open_tcp(char *host, const unsigned short port); int xcb_parse_display(const char *name, char **host, int *displayp,
static int _xcb_open_unix(const char *file); int *screenp)
{
return _xcb_parse_display(name, host, NULL, displayp, screenp);
}
static int _xcb_open_tcp(char *host, char *protocol, const unsigned short port);
static int _xcb_open_unix(char *protocol, const char *file);
#ifdef DNETCONN #ifdef DNETCONN
static int _xcb_open_decnet(const char *host, const unsigned short port); static int _xcb_open_decnet(const char *host, char *protocol, const unsigned short port);
#endif #endif
static int _xcb_open(char *host, const int display) static int _xcb_open(char *host, char *protocol, const int display)
{ {
int fd; int fd;
static const char base[] = "/tmp/.X11-unix/X";
char file[sizeof(base) + 20];
if(*host) if(*host)
{ {
#ifdef DNETCONN #ifdef DNETCONN
/* DECnet displays have two colons, so xcb_parse_display will have left /* DECnet displays have two colons, so _xcb_parse_display will have
one at the end. However, an IPv6 address can end with *two* colons, left one at the end. However, an IPv6 address can end with *two*
so only treat this as a DECnet display if host ends with exactly one colons, so only treat this as a DECnet display if host ends with
colon. */ exactly one colon. */
char *colon = strchr(host, ':'); char *colon = strchr(host, ':');
if(colon && *(colon+1) == '\0') if(colon && *(colon+1) == '\0')
{ {
*colon = '\0'; *colon = '\0';
fd = _xcb_open_decnet(host, display); return _xcb_open_decnet(host, protocol, display);
} }
else else
#endif #endif
{ if (protocol
/* display specifies TCP */ || strcmp("unix",host)) { /* follow the old unix: rule */
unsigned short port = X_TCP_PORT + display;
fd = _xcb_open_tcp(host, port); /* display specifies TCP */
} unsigned short port = X_TCP_PORT + display;
} return _xcb_open_tcp(host, protocol, port);
else }
{
/* display specifies Unix socket */
static const char base[] = "/tmp/.X11-unix/X";
char file[sizeof(base) + 20];
snprintf(file, sizeof(file), "%s%d", base, display);
fd = _xcb_open_unix(file);
} }
/* display specifies Unix socket */
snprintf(file, sizeof(file), "%s%d", base, display);
return _xcb_open_unix(protocol, file);
return fd; return fd;
} }
#ifdef DNETCONN #ifdef DNETCONN
static int _xcb_open_decnet(const char *host, const unsigned short port) static int _xcb_open_decnet(const char *host, const char *protocol, const unsigned short port)
{ {
int fd; int fd;
struct sockaddr_dn addr; struct sockaddr_dn addr;
@ -149,6 +172,8 @@ static int _xcb_open_decnet(const char *host, const unsigned short port)
if(!nodeaddr) if(!nodeaddr)
return -1; return -1;
if (protocol && strcmp("dnet",protocol))
return -1;
addr.sdn_family = AF_DECnet; addr.sdn_family = AF_DECnet;
addr.sdn_add.a_len = nodeaddr->n_length; addr.sdn_add.a_len = nodeaddr->n_length;
@ -173,7 +198,7 @@ static int _xcb_open_decnet(const char *host, const unsigned short port)
} }
#endif #endif
static int _xcb_open_tcp(char *host, const unsigned short port) static int _xcb_open_tcp(char *host, char *protocol, const unsigned short port)
{ {
int fd = -1; int fd = -1;
struct addrinfo hints = { 0 struct addrinfo hints = { 0
@ -187,7 +212,10 @@ static int _xcb_open_tcp(char *host, const unsigned short port)
char service[6]; /* "65535" with the trailing '\0' */ char service[6]; /* "65535" with the trailing '\0' */
struct addrinfo *results, *addr; struct addrinfo *results, *addr;
char *bracket; char *bracket;
if (protocol && strcmp("tcp",protocol))
return -1;
/* Allow IPv6 addresses enclosed in brackets. */ /* Allow IPv6 addresses enclosed in brackets. */
if(host[0] == '[' && (bracket = strrchr(host, ']')) && bracket[1] == '\0') if(host[0] == '[' && (bracket = strrchr(host, ']')) && bracket[1] == '\0')
{ {
@ -213,10 +241,14 @@ static int _xcb_open_tcp(char *host, const unsigned short port)
return fd; return fd;
} }
static int _xcb_open_unix(const char *file) static int _xcb_open_unix(char *protocol, const char *file)
{ {
int fd; int fd;
struct sockaddr_un addr = { AF_UNIX }; struct sockaddr_un addr = { AF_UNIX };
if (protocol && strcmp("unix",protocol))
return -1;
strcpy(addr.sun_path, file); strcpy(addr.sun_path, file);
fd = socket(AF_UNIX, SOCK_STREAM, 0); fd = socket(AF_UNIX, SOCK_STREAM, 0);
@ -231,12 +263,13 @@ xcb_connection_t *xcb_connect(const char *displayname, int *screenp)
{ {
int fd, display = 0; int fd, display = 0;
char *host; char *host;
char *protocol;
xcb_connection_t *c; xcb_connection_t *c;
xcb_auth_info_t auth; xcb_auth_info_t auth;
if(!xcb_parse_display(displayname, &host, &display, screenp)) if(!_xcb_parse_display(displayname, &host, &protocol, &display, screenp))
return (xcb_connection_t *) &error_connection; return (xcb_connection_t *) &error_connection;
fd = _xcb_open(host, display); fd = _xcb_open(host, protocol, display);
free(host); free(host);
if(fd == -1) if(fd == -1)
return (xcb_connection_t *) &error_connection; return (xcb_connection_t *) &error_connection;
@ -256,10 +289,11 @@ xcb_connection_t *xcb_connect_to_display_with_auth_info(const char *displayname,
{ {
int fd, display = 0; int fd, display = 0;
char *host; char *host;
char *protocol;
if(!xcb_parse_display(displayname, &host, &display, screenp)) if(!_xcb_parse_display(displayname, &host, &protocol, &display, screenp))
return (xcb_connection_t *) &error_connection; return (xcb_connection_t *) &error_connection;
fd = _xcb_open(host, display); fd = _xcb_open(host, protocol, display);
free(host); free(host);
if(fd == -1) if(fd == -1)
return (xcb_connection_t *) &error_connection; return (xcb_connection_t *) &error_connection;

View File

@ -28,6 +28,38 @@
#include <assert.h> #include <assert.h>
#ifdef HAVE_BACKTRACE
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#endif
static void xcb_xlib_printbt(void)
{
#ifdef HAVE_BACKTRACE
void *array[20];
int size;
char **strings;
int i;
size = backtrace(array, 20);
strings = backtrace_symbols(array, size);
fprintf(stderr, "Locking assertion failure. Backtrace:\n");
for (i = 0; i < size; ++i)
fprintf(stderr, "#%i %s\n", i, strings[i]);
free(strings);
#endif
}
#ifndef NDEBUG
#define xcb_assert(c,x) do { if (!(x)) { xcb_xlib_printbt(); if (!(c)->xlib.sloppy_lock) assert(x); } } while(0)
#else
#define xcb_assert(c,x)
#endif
unsigned int xcb_get_request_sent(xcb_connection_t *c) unsigned int xcb_get_request_sent(xcb_connection_t *c)
{ {
if(c->has_error) if(c->has_error)
@ -38,7 +70,7 @@ unsigned int xcb_get_request_sent(xcb_connection_t *c)
void xcb_xlib_lock(xcb_connection_t *c) void xcb_xlib_lock(xcb_connection_t *c)
{ {
_xcb_lock_io(c); _xcb_lock_io(c);
assert(!c->xlib.lock); xcb_assert(c, !c->xlib.lock);
c->xlib.lock = 1; c->xlib.lock = 1;
c->xlib.thread = pthread_self(); c->xlib.thread = pthread_self();
_xcb_unlock_io(c); _xcb_unlock_io(c);
@ -47,8 +79,8 @@ void xcb_xlib_lock(xcb_connection_t *c)
void xcb_xlib_unlock(xcb_connection_t *c) void xcb_xlib_unlock(xcb_connection_t *c)
{ {
_xcb_lock_io(c); _xcb_lock_io(c);
assert(c->xlib.lock); xcb_assert(c, c->xlib.lock);
assert(pthread_equal(c->xlib.thread, pthread_self())); xcb_assert(c, pthread_equal(c->xlib.thread, pthread_self()));
c->xlib.lock = 0; c->xlib.lock = 0;
pthread_cond_broadcast(&c->xlib.cond); pthread_cond_broadcast(&c->xlib.cond);
_xcb_unlock_io(c); _xcb_unlock_io(c);

View File

@ -130,6 +130,7 @@ int _xcb_in_read_block(xcb_connection_t *c, void *buf, int nread);
typedef struct _xcb_xlib { typedef struct _xcb_xlib {
int lock; int lock;
int sloppy_lock;
pthread_t thread; pthread_t thread;
pthread_cond_t cond; pthread_cond_t cond;
} _xcb_xlib; } _xcb_xlib;
@ -182,6 +183,7 @@ struct xcb_connection_t {
}; };
void _xcb_conn_shutdown(xcb_connection_t *c); void _xcb_conn_shutdown(xcb_connection_t *c);
void _xcb_wait_io(xcb_connection_t *c, pthread_cond_t *cond);
int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vector, int *count); int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vector, int *count);

View File

@ -3,6 +3,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "check_suites.h" #include "check_suites.h"
#include "xcb.h" #include "xcb.h"
#include "xcbext.h"
/* xcb_parse_display tests {{{ */ /* xcb_parse_display tests {{{ */
@ -180,6 +181,28 @@ END_TEST
/* }}} */ /* }}} */
static void popcount_eq(uint32_t bits, int count)
{
fail_unless(xcb_popcount(bits) == count, "unexpected popcount(%08x) != %d", bits, count);
}
START_TEST(popcount)
{
uint32_t mask;
int count;
for (mask = 0xffffffff, count = 32; count >= 0; mask >>= 1, --count) {
popcount_eq(mask, count);
}
for (mask = 0x80000000; mask; mask >>= 1) {
popcount_eq(mask, 1);
}
for (mask = 0x80000000; mask > 1; mask >>= 1) {
popcount_eq(mask | 1, 2);
}
}
END_TEST
Suite *public_suite(void) Suite *public_suite(void)
{ {
Suite *s = suite_create("Public API"); Suite *s = suite_create("Public API");
@ -190,5 +213,6 @@ Suite *public_suite(void)
suite_add_test(s, parse_display_ipv6, "xcb_parse_display ipv6"); suite_add_test(s, parse_display_ipv6, "xcb_parse_display ipv6");
suite_add_test(s, parse_display_decnet, "xcb_parse_display decnet"); suite_add_test(s, parse_display_decnet, "xcb_parse_display decnet");
suite_add_test(s, parse_display_negative, "xcb_parse_display negative"); suite_add_test(s, parse_display_negative, "xcb_parse_display negative");
suite_add_test(s, popcount, "xcb_popcount");
return s; return s;
} }