[Xcb] [PATCH 3/3] fix pthread_cond_wait and get_socket_back dependency
Christian König
deathsimple at vodafone.de
Thu May 16 02:35:07 PDT 2013
Am 16.05.2013 02:02, schrieb Jamey Sharp:
> Thanks for splitting the original patch into these independent parts--it
> helped a lot for review!
>
> After reviewing the code this patch touches, I think there are two
> possibilities.
>
> - Either this patch does not completely address race conditions around
> socket ownership;
>
> - Or there are existing, interlocking, invariants that make this safe,
> and they just need to be better documented.
>
> Consider, for example: What happens if xcb_take_socket is called from
> two threads at once?
Not much, changing socket ownership is protected by the iolock. So when
two threads call into xcb_take_socket the thread who can acquire the
iolock wins and gets the socket. The other thread gets the iolock after
the first returns from xcb_take_socket and so calls return_socket to get
the socket back to xcb before giving it out again.
But that's exactly the argument why the current implementation doesn't
work correctly, any caller of xcb_take_socket must make sure that the
socket isn't stolen by another thread. The conventional way to do so is
to use a locking primitive, which is acquired by the caller of
xcb_take_socket and inside return_socket.
So calling return_socket with the iolock held (and yes using
socket_moving has the same effect of holding the iolock) is just a
classic case of acquiring locking primitives in different order.
Christian.
> I'm not excited to merge this patch as-is, because it makes the
> invariants more obscure than they already were. I would rather see a
> patch that makes the code obviously correct. As it stands, I can't
> convince myself that the original code is wrong, and I can't convince
> myself that the replacement code is right.
>
> Thanks,
> Jamey
>
> On Wed, May 15, 2013 at 11:21:37AM +0200, Christian König wrote:
>> From: Christian König <christian.koenig at amd.com>
>>
>> Both functions may drop the iolock, so it is possible that somebody else has
>> acquired the socket or started writing data.
>>
>> Signed-off-by: Christian König <christian.koenig at amd.com>
>> ---
>> src/xcb_out.c | 16 +++++++++++-----
>> 1 file changed, 11 insertions(+), 5 deletions(-)
>>
>> diff --git a/src/xcb_out.c b/src/xcb_out.c
>> index 429fa99..b9901ca 100644
>> --- a/src/xcb_out.c
>> +++ b/src/xcb_out.c
>> @@ -239,10 +239,12 @@ unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vect
>>
>> /* get a sequence number and arrange for delivery. */
>> pthread_mutex_lock(&c->iolock);
>> + get_socket_back(c);
>> /* 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);
>> - get_socket_back(c);
>> + get_socket_back(c);
>> + }
>>
>> /* send GetInputFocus (sync_req) when 64k-2 requests have been sent without
>> * a reply. */
>> @@ -357,10 +359,12 @@ int _xcb_out_send(xcb_connection_t *c, struct iovec *vector, int count)
>>
>> void _xcb_out_send_sync(xcb_connection_t *c)
>> {
>> + get_socket_back(c);
>> /* 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);
>> - get_socket_back(c);
>> + get_socket_back(c);
>> + }
>> send_sync(c);
>> }
>>
>> @@ -377,8 +381,10 @@ int _xcb_out_flush_to(xcb_connection_t *c, uint64_t request)
>> c->out.queue_len = 0;
>> return _xcb_out_send(c, &vec, 1);
>> }
>> - while(c->out.writing)
>> + while(c->out.writing) {
>> pthread_cond_wait(&c->out.cond, &c->iolock);
>> + get_socket_back(c);
>> + }
>> assert(XCB_SEQUENCE_COMPARE(c->out.request_written, >=, request));
>> return 1;
>> }
>> --
>> 1.7.9.5
>>
>> _______________________________________________
>> Xcb mailing list
>> Xcb at lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/xcb
More information about the Xcb
mailing list