Just a nitpick: On 6 November 2013 01:41, Keith Packard <kei...@keithp.com> wrote: > Requests signal which replies will have fds, and the replies report > how many fds they expect in byte 1. > > Signed-off-by: Keith Packard <kei...@keithp.com> > --- > src/c_client.py | 65 ++++++++++++++++++++++++++++++++++++++++++++---- > src/xcb_in.c | 76 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- > src/xcbext.h | 4 ++- > src/xcbint.h | 8 +++--- > 4 files changed, 141 insertions(+), 12 deletions(-) > > diff --git a/src/c_client.py b/src/c_client.py > index ed92185..4c5da0a 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
This could be more pythonic: return any([field.isfd for field in self.fields]) > + > +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 ac4d284..f9a10e7 100644 > --- a/src/xcb_in.c > +++ b/src/xcb_in.c > @@ -91,11 +91,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 -1; > + memcpy(fds, ifds, nfd * sizeof (int)); > + c->in.in_fd.ifd += nfd; > + return nfd * sizeof (int); > +} > +#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; > @@ -165,13 +180,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); > @@ -199,6 +219,17 @@ static int read_packet(xcb_connection_t *c) > } > } > > +#if HAVE_SENDMSG > + if (nfd) > + { > + if (read_fds(c, (int *) &((char *) buf)[length], nfd) <= 0) > + { > + free(buf); > + return 0; > + } > + } > +#endif > + > if(pend && (pend->flags & XCB_REQUEST_DISCARD_REPLY)) > { > free(buf); > @@ -432,6 +463,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; > @@ -666,9 +702,43 @@ 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 msghdr msg = { > + .msg_name = NULL, > + .msg_namelen = 0, > + .msg_iov = &iov, > + .msg_iovlen = 1, > + .msg_control = &c->in.in_fd, > + .msg_controllen = sizeof (struct cmsghdr) + sizeof (int) * > XCB_MAX_PASS_FD, > + }; > + assert(c->in.in_fd.ifd == c->in.in_fd.nfd); > + c->in.in_fd.ifd = 0; > + c->in.in_fd.nfd = 0; > + n = recvmsg(c->fd, &msg, 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 (c->in.in_fd.cmsghdr.cmsg_level == SOL_SOCKET && > + c->in.in_fd.cmsghdr.cmsg_type == SCM_RIGHTS && > + !((msg.msg_flags & MSG_TRUNC) || > + (msg.msg_flags & MSG_CTRUNC))) > + { > + c->in.in_fd.nfd = (msg.msg_controllen - sizeof (struct > cmsghdr)) / sizeof (int); > + } > + } > +#endif > c->in.queue_len += n; > + } > while(read_packet(c)) > /* empty */; > #ifndef _WIN32 > 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 356350b..75d159f 100644 > --- a/src/xcbint.h > +++ b/src/xcbint.h > @@ -84,11 +84,12 @@ typedef void (*xcb_return_socket_func_t)(void *closure); > #if HAVE_SENDMSG > #define XCB_MAX_PASS_FD 16 > > -typedef struct _xcb_out_fd { > +typedef struct _xcb_fd { > struct cmsghdr cmsghdr; > int fd[XCB_MAX_PASS_FD]; > int nfd; > -} _xcb_out_fd; > + int ifd; > +} _xcb_fd; > #endif > > typedef struct _xcb_out { > @@ -112,7 +113,7 @@ typedef struct _xcb_out { > uint32_t value; > } maximum_request_length; > #if HAVE_SENDMSG > - _xcb_out_fd out_fd; > + _xcb_fd out_fd; > #endif > } _xcb_out; > > @@ -146,6 +147,7 @@ typedef struct _xcb_in { > > struct pending_reply *pending_replies; > struct pending_reply **pending_replies_tail; > + _xcb_fd in_fd; > } _xcb_in; > > int _xcb_in_init(_xcb_in *in); > -- > 1.8.4.2 > > _______________________________________________ > xorg-devel@lists.x.org: X.Org development > Archives: http://lists.x.org/archives/xorg-devel > Info: http://lists.x.org/mailman/listinfo/xorg-devel _______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel