L4Re/departure

Annotated tests/dstest_pipe_client.cc

360:92c5f6aa8c36
2022-06-12 Paul Boddie Reintroduced PagerObject code generation required to initiate servers. mmap-region-flags
paul@65 1
/*
paul@65 2
 * Test pipe operations.
paul@65 3
 *
paul@65 4
 * Copyright (C) 2020, 2021 Paul Boddie <paul@boddie.org.uk>
paul@65 5
 *
paul@65 6
 * This program is free software; you can redistribute it and/or
paul@65 7
 * modify it under the terms of the GNU General Public License as
paul@65 8
 * published by the Free Software Foundation; either version 2 of
paul@65 9
 * the License, or (at your option) any later version.
paul@65 10
 *
paul@65 11
 * This program is distributed in the hope that it will be useful,
paul@65 12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@65 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@65 14
 * GNU General Public License for more details.
paul@65 15
 *
paul@65 16
 * You should have received a copy of the GNU General Public License
paul@65 17
 * along with this program; if not, write to the Free Software
paul@65 18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@65 19
 * Boston, MA  02110-1301, USA
paul@65 20
 */
paul@65 21
paul@65 22
#include <l4/re/env.h>
paul@65 23
#include <l4/sys/err.h>
paul@65 24
paul@117 25
#include <thread>
paul@117 26
paul@65 27
#include <stdio.h>
paul@65 28
#include <string.h>
paul@65 29
#include <stdlib.h>
paul@123 30
#include <unistd.h> /* sleep */
paul@65 31
paul@108 32
#include <fsclient/client.h>
paul@178 33
#include <systypes/fcntl.h>
paul@65 34
paul@65 35
paul@66 36
paul@117 37
/* Use the writer to fill the pipe with data. */
paul@117 38
paul@124 39
static void write_pipe(file_t *writer, int number)
paul@117 40
{
paul@117 41
  offset_t size = 600;
paul@117 42
  char buffer[size];
paul@124 43
  long err;
paul@124 44
paul@124 45
  /* Make writers blocking to permit synchronisation. */
paul@124 46
paul@124 47
  if ((err = client_set_blocking(writer, NOTIFY_SPACE_AVAILABLE)))
paul@124 48
  {
paul@124 49
    printf("Could not set pipe #%d as blocking: %s\n", number, l4sys_errtostr(err));
paul@124 50
    return;
paul@124 51
  }
paul@117 52
paul@117 53
  for (int loop = 0; loop < 3; loop++)
paul@117 54
  {
paul@117 55
    for (int region = 0; region < 26; region++)
paul@117 56
    {
paul@117 57
      memset(buffer, (int) 'a' + region, size);
paul@117 58
paul@117 59
      offset_t nwritten = client_write(writer, buffer, size);
paul@117 60
paul@124 61
      printf("Written %ld/%ld in #%d of %d/%d to pipe #%d...\n", nwritten, size, region, loop, 2, number);
paul@117 62
    }
paul@123 63
paul@123 64
    sleep(1);
paul@117 65
  }
paul@117 66
paul@117 67
  /* Flush to make the final output available. */
paul@117 68
paul@132 69
  client_close(writer);
paul@117 70
}
paul@117 71
paul@117 72
/* Use the reader to obtain data from the pipe. */
paul@117 73
paul@123 74
static void read_pipes(file_t *reader1, file_t *reader2)
paul@117 75
{
paul@123 76
  offset_t size = 600, totals[] = {0, 0};
paul@126 77
  unsigned int active = 2;
paul@124 78
  long err;
paul@123 79
  file_t *reader;
paul@124 80
paul@180 81
  /* Use a local notifier to wait for pipe events. */
paul@180 82
paul@180 83
  file_notifier_t *notifier = client_notifier_local();
paul@180 84
paul@124 85
  /* Register the readers for notification. */
paul@124 86
paul@180 87
  if ((err = client_subscribe(reader1, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, notifier)) ||
paul@180 88
      (err = client_subscribe(reader2, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, notifier)))
paul@123 89
  {
paul@124 90
    printf("Could not subscribe to notifications: %s\n", l4sys_errtostr(err));
paul@123 91
    return;
paul@123 92
  }
paul@123 93
paul@123 94
  while (1)
paul@117 95
  {
paul@124 96
    char buffer[size];
paul@124 97
    offset_t nread;
paul@124 98
paul@123 99
    /* Wait for notification of content. */
paul@123 100
paul@180 101
    err = client_wait_files(&reader, notifier);
paul@123 102
paul@123 103
    if (err)
paul@123 104
    {
paul@123 105
      printf("Error waiting for notifications: %s\n", l4sys_errtostr(err));
paul@180 106
      client_notifier_close(notifier);
paul@123 107
      return;
paul@123 108
    }
paul@123 109
paul@123 110
    if ((reader != reader1) && (reader != reader2))
paul@123 111
    {
paul@123 112
      printf("Spurious notification received for %p versus %p, %p.\n", reader, reader1, reader2);
paul@123 113
      continue;
paul@123 114
    }
paul@123 115
paul@123 116
    int p = reader == reader1 ? 0 : 1;
paul@123 117
paul@164 118
    printf("Pipe #%d notified with conditions:%s%s\n", p + 1, reader->notifications & NOTIFY_PEER_CLOSED ? " closed" : "",
paul@164 119
                                                              reader->notifications & NOTIFY_CONTENT_AVAILABLE ? " content" : "");
paul@126 120
paul@126 121
    nread = client_read(reader, buffer, size);
paul@123 122
paul@124 123
    while (nread)
paul@123 124
    {
paul@123 125
      totals[p] += nread;
paul@123 126
paul@124 127
      printf("Read %ld/%ld, total %ld, first %c, last %c, from pipe #%d...\n", nread, size, totals[p], *buffer, *(buffer + nread - 1), p + 1);
paul@123 128
#if 0
paul@123 129
      for (offset_t i = 0; i < nread; i += 60)
paul@123 130
      {
paul@123 131
        fwrite(buffer + i, sizeof(char), nread - i > 60 ? 60 : nread - i, stdout);
paul@123 132
        fputs("\n", stdout);
paul@123 133
      }
paul@123 134
#endif
paul@123 135
      nread = client_read(reader, buffer, size);
paul@123 136
    }
paul@128 137
paul@128 138
    /* Without any more content, a peer closed event should terminate reading
paul@128 139
       from the pipe. */
paul@128 140
paul@128 141
    if (reader->notifications & NOTIFY_PEER_CLOSED)
paul@128 142
    {
paul@128 143
      active--;
paul@128 144
      if (!active)
paul@128 145
        break;
paul@128 146
    }
paul@117 147
  }
paul@117 148
paul@132 149
  client_close(reader1);
paul@132 150
  client_close(reader2);
paul@180 151
  client_notifier_close(notifier);
paul@132 152
paul@117 153
  printf("Data shown.\n");
paul@117 154
}
paul@117 155
paul@65 156
int main(void)
paul@65 157
{
paul@178 158
  /* Obtain pipe endpoint references. Blocking will be set up manually. */
paul@65 159
paul@132 160
  file_t *reader1, *reader2, *writer1, *writer2;
paul@178 161
  long err = client_pipe(&reader1, &writer1, O_NONBLOCK) ||
paul@178 162
             client_pipe(&reader2, &writer2, O_NONBLOCK);
paul@65 163
paul@65 164
  if (err)
paul@65 165
  {
paul@123 166
    printf("Could not obtain pipes: %s\n", l4sys_errtostr(err));
paul@65 167
    return 1;
paul@65 168
  }
paul@65 169
paul@117 170
  /* Schedule reader and writer threads. */
paul@117 171
paul@123 172
  std::thread *activities[3];
paul@65 173
paul@132 174
  activities[0] = new std::thread(read_pipes, reader1, reader2);
paul@132 175
  activities[1] = new std::thread(write_pipe, writer1, 1);
paul@132 176
  activities[2] = new std::thread(write_pipe, writer2, 2);
paul@117 177
paul@123 178
  for (int i = 0; i < 3; i++)
paul@117 179
    activities[i]->join();
paul@65 180
}
paul@65 181
paul@65 182
// vim: tabstop=2 expandtab shiftwidth=2