[PATCH xserver] dix: Allow secondary threads to use the work queue

Peter Hutterer peter.hutterer at who-t.net
Fri Feb 24 02:21:47 UTC 2017


On Fri, Feb 24, 2017 at 07:31:32AM +1000, Peter Hutterer wrote:
> On Thu, Feb 23, 2017 at 04:25:35PM -0500, Adam Jackson wrote:
> > The work queue code is reentrant with itself on a single thread, but not
> > when the queue is modified from thread A while being run on thread B.
> > We will only ever run it from the main thread, but the input thread
> > wants to be able to queue work for event emission. Mutex the list so it
> > can do so safely.
> > 
> > This does mean queued work should be cheap to execute since if the lock
> > is contended the input thread will block. That was always true though.
> > If this contention turns out to be a problem, we can fix how we walk the
> > work queue to hold the lock less.
> > 
> > Signed-off-by: Adam Jackson <ajax at redhat.com>
> > ---
> >  dix/dixutils.c | 22 ++++++++++++++++++++++
> >  dix/main.c     |  2 ++
> >  include/dix.h  |  3 +--
> >  3 files changed, 25 insertions(+), 2 deletions(-)
> > 
> > diff --git a/dix/dixutils.c b/dix/dixutils.c
> > index 540023c..a282b15 100644
> > --- a/dix/dixutils.c
> > +++ b/dix/dixutils.c
> > @@ -506,12 +506,29 @@ InitBlockAndWakeupHandlers(void)
> >  
> >  WorkQueuePtr workQueue;
> >  static WorkQueuePtr *workQueueLast = &workQueue;
> > +static pthread_mutex_t wq_mutex;
> 
> I'm not a fan of changing the naming scheme here...

looking at this again because I realised that timers are used as well and it
turns out they already have input_lock(), see 8174daa6bd3f. Can we just use
input_lock()/input_unlock() here rather than a new mutex?

Cheers,
   Peter

> > +
> > +Bool
> > +InitWorkQueue(void)
> > +{
> > +    if (serverGeneration == 1) {
> > +        pthread_mutexattr_t attr;
> > +
> > +        pthread_mutexattr_init(&attr);
> > +        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
> > +        if (pthread_mutex_init(&wq_mutex, &attr))
> > +            FatalError("Could not initialize work queue lock");
> > +    }
> > +
> > +    return TRUE;
> > +}
> >  
> >  void
> >  ProcessWorkQueue(void)
> >  {
> >      WorkQueuePtr q, *p;
> >  
> > +    pthread_mutex_lock(&wq_mutex);
> >      p = &workQueue;
> >      /*
> >       * Scan the work queue once, calling each function.  Those
> > @@ -530,6 +547,7 @@ ProcessWorkQueue(void)
> >          }
> >      }
> >      workQueueLast = p;
> > +    pthread_mutex_unlock(&wq_mutex);
> >  }
> >  
> >  void
> > @@ -537,6 +555,7 @@ ProcessWorkQueueZombies(void)
> >  {
> >      WorkQueuePtr q, *p;
> >  
> > +    pthread_mutex_lock(&wq_mutex);
> >      p = &workQueue;
> >      while ((q = *p)) {
> >          if (q->client && q->client->clientGone) {
> > @@ -550,6 +569,7 @@ ProcessWorkQueueZombies(void)
> >          }
> >      }
> >      workQueueLast = p;
> > +    pthread_mutex_unlock(&wq_mutex);
> >  }
> >  
> >  Bool
> > @@ -565,8 +585,10 @@ QueueWorkProc(Bool (*function) (ClientPtr pClient, void *closure),
> >      q->client = client;
> >      q->closure = closure;
> >      q->next = NULL;
> > +    pthread_mutex_lock(&wq_mutex);
> >      *workQueueLast = q;
> >      workQueueLast = &q->next;
> > +    pthread_mutex_unlock(&wq_mutex);
> >      return TRUE;
> >  }
> >  
> > diff --git a/dix/main.c b/dix/main.c
> > index 4947062..0278bf5 100644
> > --- a/dix/main.c
> > +++ b/dix/main.c
> > @@ -154,6 +154,8 @@ dix_main(int argc, char *argv[], char *envp[])
> >          DPMSPowerLevel = 0;
> >  #endif
> >          InitBlockAndWakeupHandlers();
> > +        InitWorkQueue();
> > +
> >          /* Perform any operating system dependent initializations you'd like */
> >          OsInit();
> >          if (serverGeneration == 1) {
> > diff --git a/include/dix.h b/include/dix.h
> > index 240018b..3e3a672 100644
> > --- a/include/dix.h
> > +++ b/include/dix.h
> > @@ -240,10 +240,9 @@ extern _X_EXPORT void RemoveBlockAndWakeupHandlers(ServerBlockHandlerProcPtr blo
> >  
> >  extern _X_EXPORT void InitBlockAndWakeupHandlers(void);
> >  
> > +extern _X_EXPORT Bool InitWorkQueue(void);
> >  extern _X_EXPORT void ProcessWorkQueue(void);
> > -
> >  extern _X_EXPORT void ProcessWorkQueueZombies(void);
> > -
> >  extern _X_EXPORT Bool QueueWorkProc(Bool (*function)(ClientPtr clientUnused,
> >                                                       void *closure),
> >                                      ClientPtr client,
> > -- 
> > 2.9.3
> > 
> > _______________________________________________
> > xorg-devel at lists.x.org: X.Org development
> > Archives: http://lists.x.org/archives/xorg-devel
> > Info: https://lists.x.org/mailman/listinfo/xorg-devel
> > 
> _______________________________________________
> xorg-devel at lists.x.org: X.Org development
> Archives: http://lists.x.org/archives/xorg-devel


More information about the xorg-devel mailing list