Add xcb_send_request_with_fds() and *_with_fds64()
Doing xcb_send_fd(), xcb_send_request() is racy. If two threads do this at the same time, they could mix up their file descriptors. This commit makes it possibly to fix this race by providing a single function which does everything that is needed. Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
parent
cc04cfb41b
commit
b15aa6bd4e
|
@ -214,15 +214,18 @@ static void send_fds(xcb_connection_t *c, int *fds, unsigned int num_fds)
|
||||||
close_fds(fds, num_fds);
|
close_fds(fds, num_fds);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t xcb_send_request64(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *req)
|
uint64_t xcb_send_request_with_fds64(xcb_connection_t *c, int flags, struct iovec *vector,
|
||||||
|
const xcb_protocol_request_t *req, unsigned int num_fds, int *fds)
|
||||||
{
|
{
|
||||||
uint64_t request;
|
uint64_t request;
|
||||||
uint32_t prefix[2];
|
uint32_t prefix[2];
|
||||||
int veclen = req->count;
|
int veclen = req->count;
|
||||||
enum workarounds workaround = WORKAROUND_NONE;
|
enum workarounds workaround = WORKAROUND_NONE;
|
||||||
|
|
||||||
if(c->has_error)
|
if(c->has_error) {
|
||||||
|
close_fds(fds, num_fds);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
assert(c != 0);
|
assert(c != 0);
|
||||||
assert(vector != 0);
|
assert(vector != 0);
|
||||||
|
@ -241,6 +244,7 @@ uint64_t xcb_send_request64(xcb_connection_t *c, int flags, struct iovec *vector
|
||||||
const xcb_query_extension_reply_t *extension = xcb_get_extension_data(c, req->ext);
|
const xcb_query_extension_reply_t *extension = xcb_get_extension_data(c, req->ext);
|
||||||
if(!(extension && extension->present))
|
if(!(extension && extension->present))
|
||||||
{
|
{
|
||||||
|
close_fds(fds, num_fds);
|
||||||
_xcb_conn_shutdown(c, XCB_CONN_CLOSED_EXT_NOTSUPPORTED);
|
_xcb_conn_shutdown(c, XCB_CONN_CLOSED_EXT_NOTSUPPORTED);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -271,6 +275,7 @@ uint64_t xcb_send_request64(xcb_connection_t *c, int flags, struct iovec *vector
|
||||||
}
|
}
|
||||||
else if(longlen > xcb_get_maximum_request_length(c))
|
else if(longlen > xcb_get_maximum_request_length(c))
|
||||||
{
|
{
|
||||||
|
close_fds(fds, num_fds);
|
||||||
_xcb_conn_shutdown(c, XCB_CONN_CLOSED_REQ_LEN_EXCEED);
|
_xcb_conn_shutdown(c, XCB_CONN_CLOSED_REQ_LEN_EXCEED);
|
||||||
return 0; /* server can't take this; maybe need BIGREQUESTS? */
|
return 0; /* server can't take this; maybe need BIGREQUESTS? */
|
||||||
}
|
}
|
||||||
|
@ -317,12 +322,25 @@ uint64_t xcb_send_request64(xcb_connection_t *c, int flags, struct iovec *vector
|
||||||
prepare_socket_request(c);
|
prepare_socket_request(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
send_fds(c, fds, num_fds);
|
||||||
send_request(c, req->isvoid, workaround, flags, vector, veclen);
|
send_request(c, req->isvoid, workaround, flags, vector, veclen);
|
||||||
request = c->has_error ? 0 : c->out.request;
|
request = c->has_error ? 0 : c->out.request;
|
||||||
pthread_mutex_unlock(&c->iolock);
|
pthread_mutex_unlock(&c->iolock);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* request number are actually uint64_t internally but keep API compat with unsigned int */
|
||||||
|
unsigned int xcb_send_request_with_fds(xcb_connection_t *c, int flags, struct iovec *vector,
|
||||||
|
const xcb_protocol_request_t *req, unsigned int num_fds, int *fds)
|
||||||
|
{
|
||||||
|
return xcb_send_request_with_fds64(c, flags, vector, req, num_fds, fds);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t xcb_send_request64(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *req)
|
||||||
|
{
|
||||||
|
return xcb_send_request_with_fds64(c, flags, vector, req, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* request number are actually uint64_t internally but keep API compat with unsigned int */
|
/* request number are actually uint64_t internally but keep API compat with unsigned int */
|
||||||
unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *req)
|
unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *req)
|
||||||
{
|
{
|
||||||
|
|
77
src/xcbext.h
77
src/xcbext.h
|
@ -68,13 +68,13 @@ enum xcb_send_request_flags_t {
|
||||||
*
|
*
|
||||||
* This function sends a new request to the X server. The data of the request is
|
* This function sends a new request to the X server. The data of the request is
|
||||||
* given as an array of @c iovecs in the @p vector argument. The length of that
|
* given as an array of @c iovecs in the @p vector argument. The length of that
|
||||||
* array and the neccessary management information are given in the @p request
|
* array and the necessary management information are given in the @p request
|
||||||
* argument.
|
* argument.
|
||||||
*
|
*
|
||||||
* When this function returns, the request might or might not be sent already.
|
* When this function returns, the request might or might not be sent already.
|
||||||
* Use xcb_flush() to make sure that it really was sent.
|
* Use xcb_flush() to make sure that it really was sent.
|
||||||
*
|
*
|
||||||
* Please note that this function is not the prefered way for sending requests.
|
* Please note that this function is not the preferred way for sending requests.
|
||||||
* It's better to use the generated wrapper functions.
|
* It's better to use the generated wrapper functions.
|
||||||
*
|
*
|
||||||
* Please note that xcb might use index -1 and -2 of the @p vector array internally,
|
* Please note that xcb might use index -1 and -2 of the @p vector array internally,
|
||||||
|
@ -82,6 +82,37 @@ 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);
|
unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a request to the server.
|
||||||
|
* @param c: The connection to the X server.
|
||||||
|
* @param flags: A combination of flags from the xcb_send_request_flags_t enumeration.
|
||||||
|
* @param vector: Data to send; must have two iovecs before start for internal use.
|
||||||
|
* @param request: Information about the request to be sent.
|
||||||
|
* @param num_fds: Number of additional file descriptors to send to the server
|
||||||
|
* @param fds: Additional file descriptors that should be send to the server.
|
||||||
|
* @return The request's sequence number on success, 0 otherwise.
|
||||||
|
*
|
||||||
|
* This function sends a new request to the X server. The data of the request is
|
||||||
|
* given as an array of @c iovecs in the @p vector argument. The length of that
|
||||||
|
* array and the necessary management information are given in the @p request
|
||||||
|
* argument.
|
||||||
|
*
|
||||||
|
* If @p num_fds is non-zero, @p fds points to an array of file descriptors that
|
||||||
|
* will be sent to the X server along with this request. After this function
|
||||||
|
* returns, all file descriptors sent are owned by xcb and will be closed
|
||||||
|
* eventually.
|
||||||
|
*
|
||||||
|
* When this function returns, the request might or might not be sent already.
|
||||||
|
* Use xcb_flush() to make sure that it really was sent.
|
||||||
|
*
|
||||||
|
* Please note that this function is not the preferred way for sending requests.
|
||||||
|
*
|
||||||
|
* Please note that xcb might use index -1 and -2 of the @p vector array internally,
|
||||||
|
* so they must be valid!
|
||||||
|
*/
|
||||||
|
unsigned int xcb_send_request_with_fds(xcb_connection_t *c, int flags, struct iovec *vector,
|
||||||
|
const xcb_protocol_request_t *request, unsigned int num_fds, int *fds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send a request to the server, with 64-bit sequence number returned.
|
* @brief Send a request to the server, with 64-bit sequence number returned.
|
||||||
* @param c: The connection to the X server.
|
* @param c: The connection to the X server.
|
||||||
|
@ -92,13 +123,13 @@ unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vect
|
||||||
*
|
*
|
||||||
* This function sends a new request to the X server. The data of the request is
|
* This function sends a new request to the X server. The data of the request is
|
||||||
* given as an array of @c iovecs in the @p vector argument. The length of that
|
* given as an array of @c iovecs in the @p vector argument. The length of that
|
||||||
* array and the neccessary management information are given in the @p request
|
* array and the necessary management information are given in the @p request
|
||||||
* argument.
|
* argument.
|
||||||
*
|
*
|
||||||
* When this function returns, the request might or might not be sent already.
|
* When this function returns, the request might or might not be sent already.
|
||||||
* Use xcb_flush() to make sure that it really was sent.
|
* Use xcb_flush() to make sure that it really was sent.
|
||||||
*
|
*
|
||||||
* Please note that this function is not the prefered way for sending requests.
|
* Please note that this function is not the preferred way for sending requests.
|
||||||
* It's better to use the generated wrapper functions.
|
* It's better to use the generated wrapper functions.
|
||||||
*
|
*
|
||||||
* Please note that xcb might use index -1 and -2 of the @p vector array internally,
|
* Please note that xcb might use index -1 and -2 of the @p vector array internally,
|
||||||
|
@ -106,6 +137,38 @@ unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vect
|
||||||
*/
|
*/
|
||||||
uint64_t xcb_send_request64(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *request);
|
uint64_t xcb_send_request64(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a request to the server, with 64-bit sequence number returned.
|
||||||
|
* @param c: The connection to the X server.
|
||||||
|
* @param flags: A combination of flags from the xcb_send_request_flags_t enumeration.
|
||||||
|
* @param vector: Data to send; must have two iovecs before start for internal use.
|
||||||
|
* @param request: Information about the request to be sent.
|
||||||
|
* @param num_fds: Number of additional file descriptors to send to the server
|
||||||
|
* @param fds: Additional file descriptors that should be send to the server.
|
||||||
|
* @return The request's sequence number on success, 0 otherwise.
|
||||||
|
*
|
||||||
|
* This function sends a new request to the X server. The data of the request is
|
||||||
|
* given as an array of @c iovecs in the @p vector argument. The length of that
|
||||||
|
* array and the necessary management information are given in the @p request
|
||||||
|
* argument.
|
||||||
|
*
|
||||||
|
* If @p num_fds is non-zero, @p fds points to an array of file descriptors that
|
||||||
|
* will be sent to the X server along with this request. After this function
|
||||||
|
* returns, all file descriptors sent are owned by xcb and will be closed
|
||||||
|
* eventually.
|
||||||
|
*
|
||||||
|
* When this function returns, the request might or might not be sent already.
|
||||||
|
* Use xcb_flush() to make sure that it really was sent.
|
||||||
|
*
|
||||||
|
* Please note that this function is not the preferred way for sending requests.
|
||||||
|
* It's better to use the generated wrapper functions.
|
||||||
|
*
|
||||||
|
* Please note that xcb might use index -1 and -2 of the @p vector array internally,
|
||||||
|
* so they must be valid!
|
||||||
|
*/
|
||||||
|
uint64_t xcb_send_request_with_fds64(xcb_connection_t *c, int flags, struct iovec *vector,
|
||||||
|
const xcb_protocol_request_t *request, unsigned int num_fds, int *fds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send a file descriptor to the server in the next call to xcb_send_request.
|
* @brief Send a file descriptor to the server in the next call to xcb_send_request.
|
||||||
* @param c: The connection to the X server.
|
* @param c: The connection to the X server.
|
||||||
|
@ -114,9 +177,9 @@ uint64_t xcb_send_request64(xcb_connection_t *c, int flags, struct iovec *vector
|
||||||
* After this function returns, the file descriptor given is owned by xcb and
|
* After this function returns, the file descriptor given is owned by xcb and
|
||||||
* will be closed eventually.
|
* will be closed eventually.
|
||||||
*
|
*
|
||||||
* FIXME: How the heck is this supposed to work in a thread-safe way? There is a
|
* @deprecated This function cannot be used in a thread-safe way. Two threads
|
||||||
* race between two threads doing xcb_send_fd(); xcb_send_request(); at the same
|
* that run xcb_send_fd(); xcb_send_request(); could mix up their file
|
||||||
* time.
|
* descriptors. Instead, xcb_send_request_with_fds() should be used.
|
||||||
*/
|
*/
|
||||||
void xcb_send_fd(xcb_connection_t *c, int fd);
|
void xcb_send_fd(xcb_connection_t *c, int fd);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue