No subject
Tue Dec 14 18:14:06 PST 2010
would've been if we, instead of breaking the initialization code, had only one
setup routine, within which we pthread_create'd and pthread_cond_wait'ed based
on a conditional variable that signaled the existence of at least one input
device attached to the system.
Some people might claim that checking the conditional variable could decrease
the performance of this fast-path, but I'm yet to see numbers validating this
concern. As a (probably unnecessary) reminding, the glibc implementation of
thread synchronization primitives in Linux is based on futexes, which have the
nice characteristic of degenerating to userland calls, thus avoiding the high
cost of context-switches in all but the contended cases.
> +
> +/**
> + * Pre-initialize the facility used for threaded generation of input events
> + *
> + */
> +void
> +InputThreadPreInit(void)
> +{
> + int fds[2], hotplugPipe[2];
> +
> + if (pipe(fds) < 0)
> + FatalError("input-thread: could not create pipe");
> +
> + if (pipe(hotplugPipe) < 0)
> + FatalError("input-thread: could not create pipe");
> +
> + inputThreadInfo = malloc(sizeof(InputThreadInfo));
> + if (!inputThreadInfo)
> + FatalError("input-thread: could not allocate memory");
> +
> + inputThreadInfo->thread = 0;
> + inputThreadInfo->devs = NULL;
> + FD_ZERO(&inputThreadInfo->fds);
> +
> + /* By making read head non-blocking, we ensure that while the main thread
> + * is busy servicing client requests, the dedicated input thread can work
> + * in parallel.
> + */
> + inputThreadInfo->readPipe = fds[0];
> + fcntl(inputThreadInfo->readPipe, F_SETFL, O_NONBLOCK | O_CLOEXEC);
> + AddGeneralSocket(inputThreadInfo->readPipe);
> + RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
> + InputThreadWakeup, NULL);
> +
> + inputThreadInfo->writePipe = fds[1];
> +
> + hotplugPipeRead = hotplugPipe[0];
> + fcntl(hotplugPipeRead, F_SETFL, O_NONBLOCK | O_CLOEXEC);
> + hotplugPipeWrite = hotplugPipe[1];
> +}
> +
> +/**
> + * Start the threaded generation of input events. This routine complements what
> + * was previously done by InputThreadPreInit(), being only responsible for
> + * creating the dedicated input thread.
> + *
> + */
> +void
> +InputThreadInit(void)
> +{
> + pthread_attr_t attr;
> +
> + pthread_attr_init(&attr);
> +
> + /* For OSes that differentiate between processes and threads, the following
> + * lines have sense. Linux uses the 1:1 thread model. The scheduler handles
> + * every thread as a normal process. Therefore this probably has no meaning
> + * if we are under Linux.
> + */
> + if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) != 0)
> + ErrorF("input-thread: error setting thread scope\n");
> +
> + if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN) != 0)
> + ErrorF("input-thread: error setting thread stack size\n");
> +
> + DebugF("input-thread: creating thread\n");
> + pthread_create(&inputThreadInfo->thread, &attr,
> + &InputThreadDoWork, NULL);
> +
> + pthread_attr_destroy (&attr);
> +}
> +
Thanks for spending your energy in this.
More information about the xorg-devel
mailing list