L4Re/OLD/libfsserver

Changeset

93:6058a18d9e55
2019-07-11 Paul Boddie raw files shortlog changelog graph Added a queue abstraction for concurrency control.
include/fsserver/queue.h (file) lib/src/Makefile (file) lib/src/queue.cc (file)
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/include/fsserver/queue.h	Thu Jul 11 17:15:05 2019 +0200
     1.3 @@ -0,0 +1,79 @@
     1.4 +/*
     1.5 + * A queue mechanism for concurrent access to a resource.
     1.6 + *
     1.7 + * Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk>
     1.8 + *
     1.9 + * This program is free software; you can redistribute it and/or
    1.10 + * modify it under the terms of the GNU General Public License as
    1.11 + * published by the Free Software Foundation; either version 2 of
    1.12 + * the License, or (at your option) any later version.
    1.13 + *
    1.14 + * This program is distributed in the hope that it will be useful,
    1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.17 + * GNU General Public License for more details.
    1.18 + *
    1.19 + * You should have received a copy of the GNU General Public License
    1.20 + * along with this program; if not, write to the Free Software
    1.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    1.22 + * Boston, MA  02110-1301, USA
    1.23 + */
    1.24 +
    1.25 +#pragma once
    1.26 +
    1.27 +#include <l4/sys/types.h>
    1.28 +
    1.29 +#include <pthread.h>
    1.30 +
    1.31 +#include <queue>
    1.32 +
    1.33 +
    1.34 +
    1.35 +/* Queue operations. */
    1.36 +
    1.37 +enum { Queue_op_start, Queue_op_yield, Queue_op_end };
    1.38 +
    1.39 +
    1.40 +
    1.41 +/* A queue abstraction. */
    1.42 +
    1.43 +class Queue
    1.44 +{
    1.45 +  /* A queue of threads and the current running thread. */
    1.46 +
    1.47 +  std::queue<l4_cap_idx_t> _queue;
    1.48 +  l4_cap_idx_t _running = L4_INVALID_CAP;
    1.49 +
    1.50 +  /* The endpoint for interacting with the queue and its own thread. */
    1.51 +
    1.52 +  l4_cap_idx_t _thread_ep;
    1.53 +  pthread_t _thread;
    1.54 +
    1.55 +public:
    1.56 +  explicit Queue()
    1.57 +  {
    1.58 +  }
    1.59 +
    1.60 +  /* Initiation and dispatch methods. */
    1.61 +
    1.62 +  virtual long start();
    1.63 +
    1.64 +  virtual void mainloop();
    1.65 +
    1.66 +  /* Queue interaction methods. */
    1.67 +
    1.68 +  virtual long start(l4_cap_idx_t ep);
    1.69 +
    1.70 +  virtual long yield();
    1.71 +
    1.72 +  virtual long end();
    1.73 +
    1.74 +protected:
    1.75 +  /* Maintenance and scheduling methods. */
    1.76 +
    1.77 +  virtual void remove();
    1.78 +
    1.79 +  virtual void next();
    1.80 +
    1.81 +  l4_cap_idx_t pop();
    1.82 +};
     2.1 --- a/lib/src/Makefile	Mon Jul 08 21:25:44 2019 +0200
     2.2 +++ b/lib/src/Makefile	Thu Jul 11 17:15:05 2019 +0200
     2.3 @@ -3,7 +3,7 @@
     2.4  
     2.5  TARGET		= libfsserver.a libfsserver.so
     2.6  PC_FILENAME 	= libfsserver
     2.7 -SRC_CC		= accessor.cc file_resource.cc flexpage.cc pager.cc paging.cc pages.cc resource.cc server.cc
     2.8 +SRC_CC		= accessor.cc file_resource.cc flexpage.cc pager.cc paging.cc pages.cc queue.cc resource.cc server.cc
     2.9  REQUIRES_LIBS	= libipc libfsclient
    2.10  
    2.11  PRIVATE_INCDIR	= $(PKGDIR)/include/fsserver
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/lib/src/queue.cc	Thu Jul 11 17:15:05 2019 +0200
     3.3 @@ -0,0 +1,188 @@
     3.4 +/*
     3.5 + * A queue mechanism for concurrent access to a resource.
     3.6 + *
     3.7 + * Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk>
     3.8 + *
     3.9 + * This program is free software; you can redistribute it and/or
    3.10 + * modify it under the terms of the GNU General Public License as
    3.11 + * published by the Free Software Foundation; either version 2 of
    3.12 + * the License, or (at your option) any later version.
    3.13 + *
    3.14 + * This program is distributed in the hope that it will be useful,
    3.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.17 + * GNU General Public License for more details.
    3.18 + *
    3.19 + * You should have received a copy of the GNU General Public License
    3.20 + * along with this program; if not, write to the Free Software
    3.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    3.22 + * Boston, MA  02110-1301, USA
    3.23 + */
    3.24 +
    3.25 +#include <l4/re/c/util/cap_alloc.h>
    3.26 +
    3.27 +#include <stdlib.h>
    3.28 +#include <stdio.h>
    3.29 +
    3.30 +#include <pthread-l4.h>
    3.31 +
    3.32 +#include <ipc/server.h>
    3.33 +#include <ipc/util_ipc.h>
    3.34 +#include "queue.h"
    3.35 +
    3.36 +
    3.37 +
    3.38 +/* Thread main function for a queue. */
    3.39 +
    3.40 +static void *queue_thread(void *data)
    3.41 +{
    3.42 +  Queue *obj = reinterpret_cast<Queue *>(data);
    3.43 +
    3.44 +  obj->mainloop();
    3.45 +  return 0;
    3.46 +}
    3.47 +
    3.48 +
    3.49 +
    3.50 +/* Set up thread. */
    3.51 +
    3.52 +long Queue::start()
    3.53 +{
    3.54 +  pthread_create(&_thread, NULL, queue_thread, this);
    3.55 +
    3.56 +  long err = ipc_server_new_gate_for_thread(&_thread_ep, pthread_l4_cap(_thread), l4_umword_t(this));
    3.57 +  if (err)
    3.58 +    return err;
    3.59 +
    3.60 +  return L4_EOK;
    3.61 +}
    3.62 +
    3.63 +/* Listen for messages. */
    3.64 +
    3.65 +void Queue::mainloop()
    3.66 +{
    3.67 +  ipc_expect_capabilities(1);
    3.68 +
    3.69 +  while (1)
    3.70 +  {
    3.71 +    l4_msgtag_t tag = ipc_server_wait((l4_umword_t) this);
    3.72 +    long op = l4_msgtag_label(tag);
    3.73 +
    3.74 +    if (l4_ipc_error(tag, l4_utcb()))
    3.75 +      continue;
    3.76 +
    3.77 +    /* Register the client and either continue or wait to continue. */
    3.78 +
    3.79 +    if (op == Queue_op_start)
    3.80 +    {
    3.81 +      l4_cap_idx_t client = L4_INVALID_CAP;
    3.82 +
    3.83 +      if (ipc_import_capability(tag, 0, &client))
    3.84 +        continue;
    3.85 +
    3.86 +      _queue.push(client);
    3.87 +
    3.88 +      ipc_expect_capability(0);
    3.89 +
    3.90 +      /* Only schedule another client if another is not running and is
    3.91 +         available. */
    3.92 +
    3.93 +      if (_queue.size() > 1)
    3.94 +        if (l4_is_invalid_cap(_running))
    3.95 +          next();
    3.96 +    }
    3.97 +
    3.98 +    /* Remove the client and schedule another client. */
    3.99 +
   3.100 +    else if (op == Queue_op_end)
   3.101 +    {
   3.102 +      remove();
   3.103 +      next();
   3.104 +    }
   3.105 +
   3.106 +    /* Yield from the client, scheduling another. */
   3.107 +
   3.108 +    else if (op == Queue_op_yield)
   3.109 +    {
   3.110 +      next();
   3.111 +    }
   3.112 +  }
   3.113 +}
   3.114 +
   3.115 +/* Remove the running task from the queue, releasing its capability. */
   3.116 +
   3.117 +void Queue::remove()
   3.118 +{
   3.119 +  if (l4_is_invalid_cap(_running))
   3.120 +    return;
   3.121 +
   3.122 +  l4re_util_cap_free_um(_running);
   3.123 +
   3.124 +  _running = L4_INVALID_CAP;
   3.125 +}
   3.126 +
   3.127 +/* Schedule another client from the queue. */
   3.128 +
   3.129 +void Queue::next()
   3.130 +{
   3.131 +  if (_queue.empty())
   3.132 +    return;
   3.133 +
   3.134 +  if (l4_is_valid_cap(_running))
   3.135 +    _queue.push(_running);
   3.136 +
   3.137 +  _running = pop();
   3.138 +
   3.139 +  l4_ipc_send(_running, l4_utcb(), l4_msgtag(0, 0, 0, 0), L4_IPC_NEVER);
   3.140 +}
   3.141 +
   3.142 +/* Pop the front of the queue. */
   3.143 +
   3.144 +l4_cap_idx_t Queue::pop()
   3.145 +{
   3.146 +  l4_cap_idx_t front = _queue.front();
   3.147 +  _queue.pop();
   3.148 +  return front;
   3.149 +}
   3.150 +
   3.151 +
   3.152 +
   3.153 +/* Finish with the queue. */
   3.154 +
   3.155 +long Queue::end()
   3.156 +{
   3.157 +  l4_msgtag_t tag;
   3.158 +
   3.159 +  tag = l4_msgtag(Queue_op_end, 0, 0, 0);
   3.160 +  tag = l4_ipc_send(_thread_ep, l4_utcb(), tag, L4_IPC_NEVER);
   3.161 +
   3.162 +  return l4_error(tag);
   3.163 +}
   3.164 +
   3.165 +/* Register with the queue. */
   3.166 +
   3.167 +long Queue::start(l4_cap_idx_t ep)
   3.168 +{
   3.169 +  l4_msgtag_t tag;
   3.170 +
   3.171 +  if (l4_is_invalid_cap(ep))
   3.172 +    return -L4_EINVAL;
   3.173 +
   3.174 +  tag = l4_msgtag(Queue_op_start, 0, 1, 0);
   3.175 +  ipc_export_capability(tag, 0, ep);
   3.176 +  tag = l4_ipc_call(_thread_ep, l4_utcb(), tag, L4_IPC_NEVER);
   3.177 +
   3.178 +  return l4_error(tag);
   3.179 +}
   3.180 +
   3.181 +/* Yield control to another member of the queue. */
   3.182 +
   3.183 +long Queue::yield()
   3.184 +{
   3.185 +  l4_msgtag_t tag;
   3.186 +
   3.187 +  tag = l4_msgtag(Queue_op_yield, 0, 0, 0);
   3.188 +  tag = l4_ipc_call(_thread_ep, l4_utcb(), tag, L4_IPC_NEVER);
   3.189 +
   3.190 +  return l4_error(tag);
   3.191 +}