[PATCH] client: Add acquire-fd API to avoid requiring a polling main thread
Uli Schlachter
psychon at znc.in
Wed Apr 10 11:29:51 PDT 2013
On 10.04.2013 17:16, Kristian Høgsberg wrote:
[...]
> +WL_EXPORT int
> +wl_display_acquire_fd(struct wl_display *display)
> +{
> + char c = 0;
> + int old_state;
> +
> + pthread_mutex_lock(&display->mutex);
> +
> + if (display->reader_state == LOCKED_READER &&
> + !pthread_equal(display->reader, pthread_self())) {
> + errno = EBUSY;
> + pthread_mutex_unlock(&display->mutex);
> + return -1;
> + }
> +
> + old_state = display->reader_state;
> + display->reader_state = LOCKED_READER;
> + display->reader = pthread_self();
> +
> + if (old_state == VOLUNTEER_READER) {
> + write(display->reader_pipe[1], &c, 1);
> + pthread_cond_wait(&display->pipe_cond, &display->mutex);
> + }
> +
> + pthread_mutex_unlock(&display->mutex);
> +
> + return display->fd;
> +}
[...]
> + if (display->reader_state == NO_READER) {
> + /* A thread gets here when it's the first reader to
> + * try to read and there's no LOCKED_READER. We set
> + * VOLUNTEER_READER and poll on the fd and the
> + * reader_pipe, so that a locked reader can preempt if
> + * it needs to. */
> + display->reader = pthread_self();
> + display->reader_state = VOLUNTEER_READER;
> +
> + pthread_mutex_unlock(&display->mutex);
> +
> + pfd[0].fd = display->fd;
> + pfd[0].events = POLLIN;
> + pfd[1].fd = display->reader_pipe[0];
> + pfd[1].events = POLLIN;
> + ret = poll(pfd, 2, -1);
> + if (pfd[1].revents & POLLIN)
> + read(display->reader_pipe[0], &c, 1);
> +
> + pthread_mutex_lock(&display->mutex);
> +
> + pthread_cond_signal(&display->pipe_cond);
> +
> + if (ret == -1) {
> + display_fatal_error(display, errno);
> + return -1;
> + }
[...]
This still has the "pending byte in the pipe"-problem from earlier, doesn't it?
I mean this one:
Uli Schlachter wrote:
> Ok, I think I found another problem:
>
> - Thread 1 is a volunteer reader, sitting in poll()
> - The server sends some data and poll() returns because display->fd is readable
> - Thread 2 calls wl_display_acquire_fd() and reaches the cond_wait(pipe_cond)
> - Thread 1 reaches the above cond_wait(reader_cond)
> - Thread 2 normally reads from the connection and wakes up all readers.
>
> At this point, everything is OK. No thread has any problems. However, there is
> still a single byte sitting in the pipe that was not read. So what happens next?
>
> - Thread X wants to read from the display and becomes a volunteer reader. Since
> the pipe is readable, it immediately continues, reads the byte and ends up in
> the above cond_wait(reader_cond). At this point we have a thread waiting on
> reader_cond, but no reader which will wake it up (=exactly the situation that
> inspired this patch, just a lot more unlikely).
Cheers,
Uli
P.S.: Urgh, I really don't like pthread's spurious wakeups. Thanks for
remembering them, Jiergir.
--
Q: Because it reverses the logical flow of conversation.
A: Why is putting a reply at the top of the message frowned upon?
More information about the wayland-devel
mailing list