[Xcb] [PATCH 1/4] Disable cancellation around every (potential) cancellation point...
Rémi Denis-Courmont
remi at remlab.net
Thu Jan 7 09:25:12 PST 2010
...and functions in external libraries (just in case).
This should make XCB safe w.r.t. to synchronous cancellation.
However, with no cancellation points, this is not terribly useful.
---
src/xcb_auth.c | 26 +++++++++++++++++++++-----
src/xcb_conn.c | 37 ++++++++++++++++++++++++++++---------
src/xcb_in.c | 14 ++++++++++++--
src/xcb_out.c | 18 ++++++++++++++++++
src/xcb_util.c | 24 ++++++++++++++++++++++++
5 files changed, 103 insertions(+), 16 deletions(-)
diff --git a/src/xcb_auth.c b/src/xcb_auth.c
index 104f2f0..f98dee1 100644
--- a/src/xcb_auth.c
+++ b/src/xcb_auth.c
@@ -92,12 +92,14 @@ static int authname_match(enum auth_protos kind, char *name, size_t namelen)
static Xauth *get_authptr(struct sockaddr *sockname, unsigned int socknamelen,
int display)
{
+ Xauth *xauth;
char *addr = 0;
int addrlen = 0;
unsigned short family;
char hostnamebuf[256]; /* big enough for max hostname */
char dispbuf[40]; /* big enough to hold more than 2^64 base 10 */
int dispbuflen;
+ int canc;
family = FamilyLocal; /* 256 */
switch(sockname->sa_family)
@@ -134,17 +136,22 @@ static Xauth *get_authptr(struct sockaddr *sockname, unsigned int socknamelen,
/* snprintf may have truncate our text */
dispbuflen = MIN(dispbuflen, sizeof(dispbuf) - 1);
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &canc);
if (family == FamilyLocal) {
- if (gethostname(hostnamebuf, sizeof(hostnamebuf)) == -1)
+ if (gethostname(hostnamebuf, sizeof(hostnamebuf)) == -1) {
+ pthread_setcancelstate(canc, NULL);
return 0; /* do not know own hostname */
+ }
addr = hostnamebuf;
addrlen = strlen(addr);
}
- return XauGetBestAuthByAddr (family,
- (unsigned short) addrlen, addr,
- (unsigned short) dispbuflen, dispbuf,
- N_AUTH_PROTOS, authnames, authnameslen);
+ xauth = XauGetBestAuthByAddr (family,
+ (unsigned short) addrlen, addr,
+ (unsigned short) dispbuflen, dispbuf,
+ N_AUTH_PROTOS, authnames, authnameslen);
+ pthread_setcancelstate(canc, NULL);
+ return xauth;
}
#ifdef HASXDMAUTH
@@ -167,6 +174,8 @@ static void do_append(char *buf, int *idxp, void *val, size_t valsize) {
static int compute_auth(xcb_auth_info_t *info, Xauth *authptr, struct sockaddr *sockname)
{
+ int canc;
+
if (authname_match(AUTH_MC1, authptr->name, authptr->name_length)) {
info->datalen = memdup(&info->data, authptr->data, authptr->data_length);
if(!info->datalen)
@@ -234,7 +243,9 @@ static int compute_auth(xcb_auth_info_t *info, Xauth *authptr, struct sockaddr *
while (j < 192 / 8)
info->data[j++] = 0;
info->datalen = j;
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &canc);
XdmcpWrap ((unsigned char *) info->data, (unsigned char *) authptr->data + 8, (unsigned char *) info->data, info->datalen);
+ pthread_setcancelstate(canc, NULL);
return 1;
}
#undef APPEND
@@ -253,6 +264,7 @@ int _xcb_get_auth_info(int fd, xcb_auth_info_t *info, int display)
int gotsockname = 0;
Xauth *authptr = 0;
int ret = 1;
+ int canc;
/* Some systems like hpux or Hurd do not expose peer names
* for UNIX Domain Sockets, but this is irrelevant,
@@ -288,12 +300,16 @@ int _xcb_get_auth_info(int fd, xcb_auth_info_t *info, int display)
goto no_auth; /* cannot build auth record */
}
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &canc);
XauDisposeAuth(authptr);
+ pthread_setcancelstate(canc, NULL);
return ret;
no_auth:
info->name = 0;
info->namelen = 0;
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &canc);
XauDisposeAuth(authptr);
+ pthread_setcancelstate(canc, NULL);
return 0;
}
diff --git a/src/xcb_conn.c b/src/xcb_conn.c
index ed2153d..23b2eb1 100644
--- a/src/xcb_conn.c
+++ b/src/xcb_conn.c
@@ -52,15 +52,18 @@ static const int error_connection = 1;
static int set_fd_flags(const int fd)
{
- int flags = fcntl(fd, F_GETFL, 0);
- if(flags == -1)
- return 0;
- flags |= O_NONBLOCK;
- if(fcntl(fd, F_SETFL, flags) == -1)
- return 0;
- if(fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
- return 0;
- return 1;
+ int flags;
+ int cancel;
+ int ret = 0;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
+ flags = fcntl(fd, F_GETFL, 0);
+ if(flags != -1 &&
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK) != -1 &&
+ fcntl(fd, F_SETFD, FD_CLOEXEC) != -1)
+ ret = 1;
+ pthread_setcancelstate(cancel, NULL);
+ return ret;
}
static int write_setup(xcb_connection_t *c, xcb_auth_info_t *auth_info)
@@ -136,14 +139,20 @@ static int read_setup(xcb_connection_t *c)
case 0: /* failed */
{
xcb_setup_failed_t *setup = (xcb_setup_failed_t *) c->setup;
+ int cancel;
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
write(STDERR_FILENO, xcb_setup_failed_reason(setup), xcb_setup_failed_reason_length(setup));
+ pthread_setcancelstate(cancel, NULL);
return 0;
}
case 2: /* authenticate */
{
xcb_setup_authenticate_t *setup = (xcb_setup_authenticate_t *) c->setup;
+ int cancel;
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
write(STDERR_FILENO, xcb_setup_authenticate_reason(setup), xcb_setup_authenticate_reason_length(setup));
+ pthread_setcancelstate(cancel, NULL);
return 0;
}
}
@@ -155,8 +164,11 @@ static int read_setup(xcb_connection_t *c)
static int write_vec(xcb_connection_t *c, struct iovec **vector, int *count)
{
int n;
+ int cancel;
assert(!c->out.queue_len);
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
n = writev(c->fd, *vector, *count);
+ pthread_setcancelstate(cancel, NULL);
if(n < 0 && errno == EAGAIN)
return 1;
if(n <= 0)
@@ -238,11 +250,15 @@ xcb_connection_t *xcb_connect_to_fd(int fd, xcb_auth_info_t *auth_info)
void xcb_disconnect(xcb_connection_t *c)
{
+ int cancel;
+
if(c->has_error)
return;
free(c->setup);
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
close(c->fd);
+ pthread_setcancelstate(cancel, NULL);
pthread_mutex_destroy(&c->iolock);
_xcb_in_destroy(&c->in);
@@ -264,6 +280,7 @@ void _xcb_conn_shutdown(xcb_connection_t *c)
int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vector, int *count)
{
int ret;
+ int cancel;
#if USE_POLL
struct pollfd fd;
#else
@@ -303,6 +320,7 @@ int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vec
#endif
pthread_mutex_unlock(&c->iolock);
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
do {
#if USE_POLL
ret = poll(&fd, 1, -1);
@@ -310,6 +328,7 @@ int _xcb_conn_wait(xcb_connection_t *c, pthread_cond_t *cond, struct iovec **vec
ret = select(c->fd + 1, &rfds, &wfds, 0, 0);
#endif
} while (ret == -1 && errno == EINTR);
+ pthread_setcancelstate(cancel, NULL);
if (ret < 0)
{
_xcb_conn_shutdown(c);
diff --git a/src/xcb_in.c b/src/xcb_in.c
index 26ab358..afb7cad 100644
--- a/src/xcb_in.c
+++ b/src/xcb_in.c
@@ -267,7 +267,11 @@ static int read_block(const int fd, void *buf, const ssize_t len)
int done = 0;
while(done < len)
{
- int ret = read(fd, ((char *) buf) + done, len - done);
+ int ret;
+ int cancel;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
+ ret = read(fd, ((char *) buf) + done, len - done);
if(ret > 0)
done += ret;
if(ret < 0 && errno == EAGAIN)
@@ -289,6 +293,7 @@ static int read_block(const int fd, void *buf, const ssize_t len)
} while (ret == -1 && errno == EINTR);
#endif
}
+ pthread_setcancelstate(cancel, NULL);
if(ret <= 0)
return ret;
}
@@ -555,7 +560,12 @@ void _xcb_in_replies_done(xcb_connection_t *c)
int _xcb_in_read(xcb_connection_t *c)
{
- int n = read(c->fd, c->in.queue + c->in.queue_len, sizeof(c->in.queue) - c->in.queue_len);
+ int n;
+ int cancel;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
+ n = read(c->fd, c->in.queue + c->in.queue_len, sizeof(c->in.queue) - c->in.queue_len);
+ pthread_setcancelstate(cancel, NULL);
if(n > 0)
c->in.queue_len += n;
while(read_packet(c))
diff --git a/src/xcb_out.c b/src/xcb_out.c
index b3050fe..c5137a7 100644
--- a/src/xcb_out.c
+++ b/src/xcb_out.c
@@ -58,7 +58,13 @@ static int write_block(xcb_connection_t *c, struct iovec *vector, int count)
static void get_socket_back(xcb_connection_t *c)
{
while(c->out.return_socket && c->out.socket_moving)
+ {
+ int cancel;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
pthread_cond_wait(&c->out.socket_cond, &c->iolock);
+ pthread_setcancelstate(cancel, NULL);
+ }
if(!c->out.return_socket)
return;
@@ -209,7 +215,13 @@ unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vect
pthread_mutex_lock(&c->iolock);
/* wait for other writing threads to get out of my way. */
while(c->out.writing)
+ {
+ int cancel;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
pthread_cond_wait(&c->out.cond, &c->iolock);
+ pthread_setcancelstate(cancel, NULL);
+ }
get_socket_back(c);
request = ++c->out.request;
@@ -356,7 +368,13 @@ int _xcb_out_flush_to(xcb_connection_t *c, uint64_t request)
return _xcb_out_send(c, &vec_ptr, &count);
}
while(c->out.writing)
+ {
+ int cancel;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
pthread_cond_wait(&c->out.cond, &c->iolock);
+ pthread_setcancelstate(cancel, NULL);
+ }
assert(XCB_SEQUENCE_COMPARE(c->out.request_written, >=, request));
return 1;
}
diff --git a/src/xcb_util.c b/src/xcb_util.c
index c3cbfa6..325681a 100644
--- a/src/xcb_util.c
+++ b/src/xcb_util.c
@@ -184,6 +184,7 @@ static int _xcb_open_decnet(const char *host, const char *protocol, const unsign
struct sockaddr_dn addr;
struct accessdata_dn accessdata;
struct nodeent *nodeaddr = getnodebyname(host);
+ int cancel;
if(!nodeaddr)
return -1;
@@ -209,10 +210,13 @@ static int _xcb_open_decnet(const char *host, const char *protocol, const unsign
return -1;
setsockopt(fd, DNPROTO_NSP, SO_CONACCESS, &accessdata, sizeof(accessdata));
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
if(connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
close(fd);
+ pthread_setcancelstate(cancel, NULL);
return -1;
}
+ pthread_setcancelstate(cancel, NULL);
return fd;
}
#endif
@@ -224,6 +228,7 @@ static int _xcb_open_tcp(char *host, char *protocol, const unsigned short port)
char service[6]; /* "65535" with the trailing '\0' */
struct addrinfo *results, *addr;
char *bracket;
+ int cancel;
if (protocol && strcmp("tcp",protocol))
return -1;
@@ -250,9 +255,15 @@ static int _xcb_open_tcp(char *host, char *protocol, const unsigned short port)
#endif
snprintf(service, sizeof(service), "%hu", port);
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
if(getaddrinfo(host, service, &hints, &results))
+ {
+ pthread_setcancelstate(cancel, NULL);
/* FIXME: use gai_strerror, and fill in error connection */
return -1;
+ }
+ pthread_setcancelstate(cancel, NULL);
for(addr = results; addr; addr = addr->ai_next)
{
@@ -262,9 +273,14 @@ static int _xcb_open_tcp(char *host, char *protocol, const unsigned short port)
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on));
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
if (connect(fd, addr->ai_addr, addr->ai_addrlen) >= 0)
+ {
+ pthread_setcancelstate(cancel, NULL);
break;
+ }
close(fd);
+ pthread_setcancelstate(cancel, NULL);
fd = -1;
}
}
@@ -275,6 +291,7 @@ static int _xcb_open_tcp(char *host, char *protocol, const unsigned short port)
static int _xcb_open_unix(char *protocol, const char *file)
{
int fd;
+ int cancel;
struct sockaddr_un addr;
if (protocol && strcmp("unix",protocol))
@@ -288,10 +305,13 @@ static int _xcb_open_unix(char *protocol, const char *file)
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if(fd == -1)
return -1;
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
if(connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
close(fd);
+ pthread_setcancelstate(cancel, NULL);
return -1;
}
+ pthread_setcancelstate(cancel, NULL);
return fd;
}
@@ -299,6 +319,7 @@ static int _xcb_open_unix(char *protocol, const char *file)
static int _xcb_open_abstract(char *protocol, const char *file, size_t filelen)
{
int fd;
+ int cancel;
struct sockaddr_un addr = {0};
socklen_t namelen;
@@ -314,10 +335,13 @@ static int _xcb_open_abstract(char *protocol, const char *file, size_t filelen)
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == -1)
return -1;
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel);
if (connect(fd, (struct sockaddr *) &addr, namelen) == -1) {
close(fd);
+ pthread_setcancelstate(cancel, NULL);
return -1;
}
+ pthread_setcancelstate(cancel, NULL);
return fd;
}
#endif
--
1.6.6
More information about the Xcb
mailing list