diff options
author | marha <marha@users.sourceforge.net> | 2015-06-15 20:27:26 +0200 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2015-06-15 20:27:26 +0200 |
commit | e8d5e7c4bb11f7fcb0a4ba5c13f43e7929849a2f (patch) | |
tree | a88d66b3d34f8e008f08e2bd77889c6c6718ab11 /libxcb/src | |
parent | 0b3be550b20ad9f991f77bf979b2c306a7d4ef11 (diff) | |
download | vcxsrv-release/external.tar.gz vcxsrv-release/external.tar.bz2 vcxsrv-release/external.zip |
fontconfig libX11 libxcb xcb-proto mesa pixman xserver xkeyboard-config git update 15 June 2015release/external
xserver commit fa12f2c150b2f50de9dac4a2b09265f13af353af
libxcb commit f85661c3bca97faa72431df92a3867be39a74e23
libxcb/xcb-proto commit fef8a4cdc2cacd9541a656026371a3d338dadb8e
xkeyboard-config commit 61fb58a95a071cc1c212f6d3808908c086219fe0
libX11 commit f0286b2770ece10aef5e2e8c004260217f12fd25
pixman commit eebc1b78200aff075dbcae9c8d00edad1f830d91
fontconfig commit f6d61c9beed856a925bd60c025b55284b2d88161
mesa commit 932d1613d1e15ec22555e5ec09105c49eb850e36
Diffstat (limited to 'libxcb/src')
-rw-r--r-- | libxcb/src/c_client.py | 103 | ||||
-rw-r--r-- | libxcb/src/xcb_in.c | 1 | ||||
-rw-r--r-- | libxcb/src/xcb_out.c | 85 | ||||
-rw-r--r-- | libxcb/src/xcbext.h | 77 |
4 files changed, 198 insertions, 68 deletions
diff --git a/libxcb/src/c_client.py b/libxcb/src/c_client.py index e55fc3c6b..70f842933 100644 --- a/libxcb/src/c_client.py +++ b/libxcb/src/c_client.py @@ -629,8 +629,7 @@ def _c_helper_resolve_field_names (prefix): all_fields = {} tmp_prefix = [] # look for fields in the remaining containers - for idx, p in enumerate(prefix): - name, sep, obj = p + for idx, (name, sep, obj) in enumerate(prefix): if ''==sep: # sep can be preset in prefix, if not, make a sensible guess sep = '.' if (obj.is_switch or obj.is_case_or_bitcase) else '->' @@ -1033,7 +1032,7 @@ def _c_serialize_helper_fields_fixed_size(context, self, field, if not self.is_case_or_bitcase: code_lines.append('%s /* %s.%s */' % (space, self.c_type, field.c_field_name)) else: - scoped_name = [p[2].c_type if idx==0 else p[0] for idx, p in enumerate(prefix)] + scoped_name = [obj.c_type if idx==0 else name for idx, (name, _, obj) in enumerate(prefix)] typename = ".".join(scoped_name) code_lines.append('%s /* %s.%s */' % (space, typename, field.c_field_name)) @@ -1327,7 +1326,7 @@ def _c_serialize(context, self): for p in params: typespec, pointerspec, field_name = p spacing = ' '*(maxtypelen-len(typespec)-len(pointerspec)) - param_str.append("%s%s%s %s%s /**< */" % (indent, typespec, spacing, pointerspec, field_name)) + param_str.append("%s%s%s %s%s" % (indent, typespec, spacing, pointerspec, field_name)) # insert function name param_str[0] = "%s (%s" % (func_name, param_str[0].strip()) param_str = ["%s," % x for x in param_str] @@ -1520,9 +1519,9 @@ def _c_iterator(self, name): _h(' * @brief %s', self.c_iterator_type) _h(' **/') _h('typedef struct %s {', self.c_iterator_type) - _h(' %s *data; /**< */', self.c_type) - _h(' int%s rem; /**< */', ' ' * (len(self.c_type) - 2)) - _h(' int%s index; /**< */', ' ' * (len(self.c_type) - 2)) + _h(' %s *data;', self.c_type) + _h(' int%s rem;', ' ' * (len(self.c_type) - 2)) + _h(' int%s index;', ' ' * (len(self.c_type) - 2)) # add additional params of the type "self" as fields to the iterator struct # so that they can be passed to the sizeof-function by the iterator's next-function params = _c_get_additional_type_params(self) @@ -1546,8 +1545,8 @@ def _c_iterator(self, name): _h(' */') _c('') _hc('void') - _h('%s (%s *i /**< */);', self.c_next_name, self.c_iterator_type) - _c('%s (%s *i /**< */)', self.c_next_name, self.c_iterator_type) + _h('%s (%s *i);', self.c_next_name, self.c_iterator_type) + _c('%s (%s *i)', self.c_next_name, self.c_iterator_type) _c('{') if not self.fixed_size(): @@ -1592,8 +1591,8 @@ def _c_iterator(self, name): _h(' */') _c('') _hc('xcb_generic_iterator_t') - _h('%s (%s i /**< */);', self.c_end_name, self.c_iterator_type) - _c('%s (%s i /**< */)', self.c_end_name, self.c_iterator_type) + _h('%s (%s i);', self.c_end_name, self.c_iterator_type) + _c('%s (%s i)', self.c_end_name, self.c_iterator_type) _c('{') _c(' xcb_generic_iterator_t ret;') @@ -1749,8 +1748,8 @@ def _c_accessors_field(self, field): if field.type.is_simple: _hc('') _hc('%s', field.c_field_type) - _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type) - _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type) + _h('%s (const %s *R);', field.c_accessor_name, c_type) + _c('%s (const %s *R)', field.c_accessor_name, c_type) _c('{') if field.prev_varsized_field is None: _c(' return (%s *) (R + 1);', field.c_field_type) @@ -1767,8 +1766,8 @@ def _c_accessors_field(self, field): return_type = '%s *' % field.c_field_type _hc(return_type) - _h('%s (const %s *R /**< */);', field.c_accessor_name, c_type) - _c('%s (const %s *R /**< */)', field.c_accessor_name, c_type) + _h('%s (const %s *R);', field.c_accessor_name, c_type) + _c('%s (const %s *R)', field.c_accessor_name, c_type) _c('{') if field.prev_varsized_field is None: _c(' return (%s) (R + 1);', return_type) @@ -1867,7 +1866,7 @@ def _c_accessors_list(self, field): if len(additional_params) == 0: return '' else: - return (',\n' + indent).join([''] + ['%s %s /**< */' % p for p in additional_params]) + return (',\n' + indent).join([''] + ['%s %s' % p for p in additional_params]) _h_setlevel(1) _c_setlevel(1) @@ -1876,8 +1875,8 @@ def _c_accessors_list(self, field): _hc('') _hc('%s *', field.c_field_type) - _h('%s (%s /**< */);', field.c_accessor_name, params[idx][0]) - _c('%s (%s /**< */)', field.c_accessor_name, params[idx][0]) + _h('%s (%s);', field.c_accessor_name, params[idx][0]) + _c('%s (%s)', field.c_accessor_name, params[idx][0]) _c('{') if switch_obj is not None: @@ -1902,12 +1901,12 @@ def _c_accessors_list(self, field): spacing = ' '*(len(field.c_length_name)+2) add_param_str = additional_params_to_str(spacing) if switch_obj is not None: - _hc('%s (const %s *R /**< */,', field.c_length_name, R_obj.c_type) - _h('%sconst %s *S /**< */%s);', spacing, S_obj.c_type, add_param_str) - _c('%sconst %s *S /**< */%s)', spacing, S_obj.c_type, add_param_str) + _hc('%s (const %s *R,', field.c_length_name, R_obj.c_type) + _h('%sconst %s *S%s);', spacing, S_obj.c_type, add_param_str) + _c('%sconst %s *S%s)', spacing, S_obj.c_type, add_param_str) else: - _h('%s (const %s *R /**< */%s);', field.c_length_name, c_type, add_param_str) - _c('%s (const %s *R /**< */%s)', field.c_length_name, c_type, add_param_str) + _h('%s (const %s *R%s);', field.c_length_name, c_type, add_param_str) + _c('%s (const %s *R%s)', field.c_length_name, c_type, add_param_str) _c('{') length = _c_accessor_get_expr(field.type.expr, fields) _c(' return %s;', length) @@ -1919,12 +1918,12 @@ def _c_accessors_list(self, field): spacing = ' '*(len(field.c_end_name)+2) add_param_str = additional_params_to_str(spacing) if switch_obj is not None: - _hc('%s (const %s *R /**< */,', field.c_end_name, R_obj.c_type) - _h('%sconst %s *S /**< */%s);', spacing, S_obj.c_type, add_param_str) - _c('%sconst %s *S /**< */%s)', spacing, S_obj.c_type, add_param_str) + _hc('%s (const %s *R,', field.c_end_name, R_obj.c_type) + _h('%sconst %s *S%s);', spacing, S_obj.c_type, add_param_str) + _c('%sconst %s *S%s)', spacing, S_obj.c_type, add_param_str) else: - _h('%s (const %s *R /**< */%s);', field.c_end_name, c_type, add_param_str) - _c('%s (const %s *R /**< */%s)', field.c_end_name, c_type, add_param_str) + _h('%s (const %s *R%s);', field.c_end_name, c_type, add_param_str) + _c('%s (const %s *R%s)', field.c_end_name, c_type, add_param_str) _c('{') _c(' xcb_generic_iterator_t i;') @@ -1952,12 +1951,12 @@ def _c_accessors_list(self, field): spacing = ' '*(len(field.c_iterator_name)+2) add_param_str = additional_params_to_str(spacing) if switch_obj is not None: - _hc('%s (const %s *R /**< */,', field.c_iterator_name, R_obj.c_type) - _h('%sconst %s *S /**< */%s);', spacing, S_obj.c_type, add_param_str) - _c('%sconst %s *S /**< */%s)', spacing, S_obj.c_type, add_param_str) + _hc('%s (const %s *R,', field.c_iterator_name, R_obj.c_type) + _h('%sconst %s *S%s);', spacing, S_obj.c_type, add_param_str) + _c('%sconst %s *S%s)', spacing, S_obj.c_type, add_param_str) else: - _h('%s (const %s *R /**< */%s);', field.c_iterator_name, c_type, add_param_str) - _c('%s (const %s *R /**< */%s)', field.c_iterator_name, c_type, add_param_str) + _h('%s (const %s *R%s);', field.c_iterator_name, c_type, add_param_str) + _c('%s (const %s *R%s)', field.c_iterator_name, c_type, add_param_str) _c('{') _c(' %s i;', field.c_iterator_type) @@ -2063,10 +2062,10 @@ def _c_complex(self, force_packed = False): # necessary for unserialize to work (self.is_switch and field.type.is_switch)): spacing = ' ' * (maxtypelen - len(field.c_field_type)) - _h('%s %s%s %s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript) + _h('%s %s%s %s%s;', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript) else: spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1)) - _h('%s %s%s *%s%s; /**< */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript) + _h('%s %s%s *%s%s;', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript) if not self.is_switch: for field in struct_fields: @@ -2243,9 +2242,9 @@ def _c_request_helper(self, name, void, regular, aux=False, reply_fds=False): spacing = ' ' * (maxtypelen - len('xcb_connection_t')) comma = ',' if len(param_fields) else ');' - _h('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma) + _h('%s (xcb_connection_t%s *c%s', func_name, spacing, comma) comma = ',' if len(param_fields) else ')' - _c('%s (xcb_connection_t%s *c /**< */%s', func_name, spacing, comma) + _c('%s (xcb_connection_t%s *c%s', func_name, spacing, comma) func_spacing = ' ' * (len(func_name) + 2) count = len(param_fields) @@ -2258,10 +2257,10 @@ def _c_request_helper(self, name, void, regular, aux=False, reply_fds=False): c_pointer = '*' spacing = ' ' * (maxtypelen - len(c_field_const_type)) comma = ',' if count else ');' - _h('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type, + _h('%s%s%s %s%s%s', func_spacing, c_field_const_type, spacing, c_pointer, field.c_field_name, comma) comma = ',' if count else ')' - _c('%s%s%s %s%s /**< */%s', func_spacing, c_field_const_type, + _c('%s%s%s %s%s%s', func_spacing, c_field_const_type, spacing, c_pointer, field.c_field_name, comma) count = 2 @@ -2291,13 +2290,16 @@ def _c_request_helper(self, name, void, regular, aux=False, reply_fds=False): _c(' void *xcb_aux = 0;') - for idx, f in enumerate(serial_fields): + for idx, _ in enumerate(serial_fields): if aux: _c(' void *xcb_aux%d = 0;' % (idx)) if list_with_var_size_elems: _c(' unsigned int i;') _c(' unsigned int xcb_tmp_len;') _c(' char *xcb_tmp;') + num_fds = len([field for field in param_fields if field.isfd]) + if num_fds > 0: + _c(' int fds[%d];' % (num_fds)) _c('') # fixed size fields @@ -2398,11 +2400,16 @@ def _c_request_helper(self, name, void, regular, aux=False, reply_fds=False): # no padding necessary - _serialize() keeps track of padding automatically _c('') + fd_index = 0 for field in param_fields: if field.isfd: - _c(' xcb_send_fd(c, %s);', field.c_field_name) + _c(' fds[%d] = %s;', fd_index, field.c_field_name) + fd_index = fd_index + 1 - _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags) + if num_fds == 0: + _c(' xcb_ret.sequence = xcb_send_request(c, %s, xcb_parts + 2, &xcb_req);', func_flags) + else: + _c(' xcb_ret.sequence = xcb_send_request_with_fds(c, %s, xcb_parts + 2, &xcb_req, %d, fds);', func_flags, num_fds) # free dyn. all. data, if any for f in free_calls: @@ -2457,10 +2464,10 @@ def _c_reply(self, name): _h(' */') _c('') _hc('%s *', self.c_reply_type) - _hc('%s (xcb_connection_t%s *c /**< */,', self.c_reply_name, spacing1) + _hc('%s (xcb_connection_t%s *c,', self.c_reply_name, spacing1) _hc('%s%s cookie /**< */,', spacing3, self.c_cookie_type) - _h('%sxcb_generic_error_t%s **e /**< */);', spacing3, spacing2) - _c('%sxcb_generic_error_t%s **e /**< */)', spacing3, spacing2) + _h('%sxcb_generic_error_t%s **e);', spacing3, spacing2) + _c('%sxcb_generic_error_t%s **e)', spacing3, spacing2) _c('{') if len(unserialize_fields)>0: @@ -2515,8 +2522,8 @@ def _c_reply_fds(self, name): _c('') _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) + _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) @@ -2543,7 +2550,7 @@ def _c_cookie(self, name): _h(' * @brief %s', self.c_cookie_type) _h(' **/') _h('typedef struct %s {', self.c_cookie_type) - _h(' unsigned int sequence; /**< */') + _h(' unsigned int sequence;') _h('} %s;', self.c_cookie_type) def _man_request(self, name, void, aux): diff --git a/libxcb/src/xcb_in.c b/libxcb/src/xcb_in.c index 623a0a803..322bed816 100644 --- a/libxcb/src/xcb_in.c +++ b/libxcb/src/xcb_in.c @@ -761,6 +761,7 @@ xcb_generic_event_t *xcb_wait_for_special_event(xcb_connection_t *c, if(!_xcb_conn_wait(c, &se->special_event_cond, 0, 0)) break; + _xcb_in_wake_up_next_reader(c); pthread_mutex_unlock(&c->iolock); return event; } diff --git a/libxcb/src/xcb_out.c b/libxcb/src/xcb_out.c index 8cc5be868..3601a5fa4 100644 --- a/libxcb/src/xcb_out.c +++ b/libxcb/src/xcb_out.c @@ -177,15 +177,59 @@ uint32_t xcb_get_maximum_request_length(xcb_connection_t *c) return c->out.maximum_request_length.value; } -uint64_t xcb_send_request64(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *req) +static void close_fds(int *fds, unsigned int num_fds) +{ + for (unsigned int index = 0; index < num_fds; index++) + close(fds[index]); +} + +static void send_fds(xcb_connection_t *c, int *fds, unsigned int num_fds) +{ +#if HAVE_SENDMSG + /* Calling _xcb_out_flush_to() can drop the iolock and wait on a condition + * variable if another thread is currently writing (c->out.writing > 0). + * This call waits for writers to be done and thus _xcb_out_flush_to() will + * do the work itself (in which case we are a writer and + * prepare_socket_request() will wait for us to be done if another threads + * tries to send fds, too). Thanks to this, we can atomically write out FDs. + */ + prepare_socket_request(c); + + while (num_fds > 0) { + while (c->out.out_fd.nfd == XCB_MAX_PASS_FD && !c->has_error) { + /* XXX: if c->out.writing > 0, this releases the iolock and + * potentially allows other threads to interfere with their own fds. + */ + _xcb_out_flush_to(c, c->out.request); + + if (c->out.out_fd.nfd == XCB_MAX_PASS_FD) { + /* We need some request to send FDs with */ + _xcb_out_send_sync(c); + } + } + if (c->has_error) + break; + + c->out.out_fd.fd[c->out.out_fd.nfd++] = fds[0]; + fds++; + num_fds--; + } +#endif + close_fds(fds, num_fds); +} + +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; uint32_t prefix[2]; int veclen = req->count; enum workarounds workaround = WORKAROUND_NONE; - if(c->has_error) + if(c->has_error) { + close_fds(fds, num_fds); return 0; + } assert(c != 0); assert(vector != 0); @@ -204,6 +248,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); if(!(extension && extension->present)) { + close_fds(fds, num_fds); _xcb_conn_shutdown(c, XCB_CONN_CLOSED_EXT_NOTSUPPORTED); return 0; } @@ -234,6 +279,7 @@ uint64_t xcb_send_request64(xcb_connection_t *c, int flags, struct iovec *vector } else if(longlen > xcb_get_maximum_request_length(c)) { + close_fds(fds, num_fds); _xcb_conn_shutdown(c, XCB_CONN_CLOSED_REQ_LEN_EXCEED); return 0; /* server can't take this; maybe need BIGREQUESTS? */ } @@ -264,6 +310,11 @@ uint64_t xcb_send_request64(xcb_connection_t *c, int flags, struct iovec *vector /* get a sequence number and arrange for delivery. */ pthread_mutex_lock(&c->iolock); + /* send FDs before establishing a good request number, because this might + * call send_sync(), too + */ + send_fds(c, fds, num_fds); + prepare_socket_request(c); /* send GetInputFocus (sync_req) when 64k-2 requests have been sent without @@ -272,7 +323,7 @@ uint64_t xcb_send_request64(xcb_connection_t *c, int flags, struct iovec *vector * applications see sequence 0 as that is used to indicate * an error in sending the request */ - + while ((req->isvoid && c->out.request == c->in.request_expected + (1 << 16) - 2) || (unsigned int) (c->out.request + 1) == 0) { @@ -287,6 +338,18 @@ uint64_t xcb_send_request64(xcb_connection_t *c, int flags, struct iovec *vector } /* 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 */ unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *req) { return xcb_send_request64(c, flags, vector, req); @@ -295,19 +358,15 @@ unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vect void xcb_send_fd(xcb_connection_t *c, int fd) { -#if HAVE_SENDMSG - if (c->has_error) + int fds[1] = { fd }; + + if (c->has_error) { + close(fd); 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_lock(&c->iolock); + send_fds(c, &fds[0], 1); 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) diff --git a/libxcb/src/xcbext.h b/libxcb/src/xcbext.h index b2575f7e3..44d789eee 100644 --- a/libxcb/src/xcbext.h +++ b/libxcb/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 * 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. * * 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 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. * * Please note that xcb might use index -1 and -2 of the @p vector array internally, @@ -83,6 +83,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); /** + * @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. * @param c: The connection to the X server. * @param flags: A combination of flags from the xcb_send_request_flags_t enumeration. @@ -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 * 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. * * 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 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. * * Please note that xcb might use index -1 and -2 of the @p vector array internally, @@ -107,6 +138,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); /** + * @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. * @param c: The connection to the X server. * @param fd: The file descriptor to send. @@ -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 * will be closed eventually. * - * FIXME: How the heck is this supposed to work in a thread-safe way? There is a - * race between two threads doing xcb_send_fd(); xcb_send_request(); at the same - * time. + * @deprecated This function cannot be used in a thread-safe way. Two threads + * that run xcb_send_fd(); xcb_send_request(); could mix up their file + * descriptors. Instead, xcb_send_request_with_fds() should be used. */ void xcb_send_fd(xcb_connection_t *c, int fd); |