L4Re/departure

Annotated tests/dstest_pipe_client.cc

618:7123a7307a82
8 months ago Paul Boddie Introduced some debugging output control.
paul@65 1
/*
paul@65 2
 * Test pipe operations.
paul@65 3
 *
paul@479 4
 * Copyright (C) 2020, 2021, 2022, 2023 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@455 34
#include <systypes/format.h>
paul@455 35
paul@455 36
#define FMToffsetd "%" pFMToffset "d"
paul@65 37
paul@65 38
paul@66 39
paul@402 40
/* Common size and iteration details. */
paul@402 41
paul@402 42
const offset_t TO_TRANSFER = 600;
paul@402 43
const int NUMBER_OF_ITERATIONS = 3;
paul@402 44
paul@402 45
paul@402 46
paul@117 47
/* Use the writer to fill the pipe with data. */
paul@117 48
paul@124 49
static void write_pipe(file_t *writer, int number)
paul@117 50
{
paul@402 51
  char buffer[TO_TRANSFER];
paul@124 52
  long err;
paul@124 53
paul@124 54
  /* Make writers blocking to permit synchronisation. */
paul@124 55
paul@124 56
  if ((err = client_set_blocking(writer, NOTIFY_SPACE_AVAILABLE)))
paul@124 57
  {
paul@124 58
    printf("Could not set pipe #%d as blocking: %s\n", number, l4sys_errtostr(err));
paul@124 59
    return;
paul@124 60
  }
paul@117 61
paul@402 62
  for (int loop = 0; loop < NUMBER_OF_ITERATIONS; loop++)
paul@117 63
  {
paul@117 64
    for (int region = 0; region < 26; region++)
paul@117 65
    {
paul@402 66
      memset(buffer, (int) 'a' + region, TO_TRANSFER);
paul@117 67
paul@402 68
      offset_t nwritten = client_write(writer, buffer, TO_TRANSFER);
paul@117 69
paul@455 70
      printf("Written " FMToffsetd "/" FMToffsetd " in #%d of %d/%d to pipe #%d...\n", nwritten, TO_TRANSFER, region, loop, 2, number);
paul@117 71
    }
paul@123 72
paul@123 73
    sleep(1);
paul@117 74
  }
paul@117 75
paul@117 76
  /* Flush to make the final output available. */
paul@117 77
paul@132 78
  client_close(writer);
paul@117 79
}
paul@117 80
paul@117 81
/* Use the reader to obtain data from the pipe. */
paul@117 82
paul@123 83
static void read_pipes(file_t *reader1, file_t *reader2)
paul@117 84
{
paul@402 85
  offset_t totals[] = {0, 0};
paul@126 86
  unsigned int active = 2;
paul@124 87
  long err;
paul@123 88
  file_t *reader;
paul@124 89
paul@180 90
  /* Use a local notifier to wait for pipe events. */
paul@180 91
paul@575 92
  notifier_t *notifier = client_notifier_local();
paul@180 93
paul@124 94
  /* Register the readers for notification. */
paul@124 95
paul@180 96
  if ((err = client_subscribe(reader1, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, notifier)) ||
paul@180 97
      (err = client_subscribe(reader2, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, notifier)))
paul@123 98
  {
paul@124 99
    printf("Could not subscribe to notifications: %s\n", l4sys_errtostr(err));
paul@123 100
    return;
paul@123 101
  }
paul@123 102
paul@123 103
  while (1)
paul@117 104
  {
paul@402 105
    char buffer[TO_TRANSFER];
paul@124 106
    offset_t nread;
paul@124 107
paul@123 108
    /* Wait for notification of content. */
paul@123 109
paul@180 110
    err = client_wait_files(&reader, notifier);
paul@123 111
paul@123 112
    if (err)
paul@123 113
    {
paul@123 114
      printf("Error waiting for notifications: %s\n", l4sys_errtostr(err));
paul@180 115
      client_notifier_close(notifier);
paul@123 116
      return;
paul@123 117
    }
paul@123 118
paul@123 119
    if ((reader != reader1) && (reader != reader2))
paul@123 120
    {
paul@123 121
      printf("Spurious notification received for %p versus %p, %p.\n", reader, reader1, reader2);
paul@123 122
      continue;
paul@123 123
    }
paul@123 124
paul@123 125
    int p = reader == reader1 ? 0 : 1;
paul@123 126
paul@479 127
    printf("Pipe #%d notified with conditions:%s%s\n", p + 1, file_notifications(reader) & NOTIFY_PEER_CLOSED ? " closed" : "",
paul@479 128
                                                              file_notifications(reader) & NOTIFY_CONTENT_AVAILABLE ? " content" : "");
paul@126 129
paul@402 130
    nread = client_read(reader, buffer, TO_TRANSFER);
paul@123 131
paul@124 132
    while (nread)
paul@123 133
    {
paul@123 134
      totals[p] += nread;
paul@123 135
paul@455 136
      printf("Read " FMToffsetd "/" FMToffsetd ", total " FMToffsetd ", first %c, last %c, from pipe #%d...\n", nread, TO_TRANSFER, totals[p], *buffer, *(buffer + nread - 1), p + 1);
paul@402 137
      nread = client_read(reader, buffer, TO_TRANSFER);
paul@123 138
    }
paul@128 139
paul@128 140
    /* Without any more content, a peer closed event should terminate reading
paul@128 141
       from the pipe. */
paul@128 142
paul@479 143
    if (file_notifications(reader) & NOTIFY_PEER_CLOSED)
paul@128 144
    {
paul@128 145
      active--;
paul@128 146
      if (!active)
paul@128 147
        break;
paul@128 148
    }
paul@117 149
  }
paul@117 150
paul@132 151
  client_close(reader1);
paul@132 152
  client_close(reader2);
paul@180 153
  client_notifier_close(notifier);
paul@132 154
paul@402 155
  for (int p = 0; p < 2; p++)
paul@402 156
  {
paul@556 157
    printf("Data received for pipe #%d: " FMToffsetd "\n", p + 1, totals[p]);
paul@556 158
    printf("Data shown for pipe #%d: %s\n", p + 1, totals[p] == TO_TRANSFER * 26 * NUMBER_OF_ITERATIONS ? "True" : "False");
paul@402 159
  }
paul@117 160
}
paul@117 161
paul@65 162
int main(void)
paul@65 163
{
paul@178 164
  /* Obtain pipe endpoint references. Blocking will be set up manually. */
paul@65 165
paul@424 166
  printf("Obtaining pipes...\n");
paul@424 167
paul@132 168
  file_t *reader1, *reader2, *writer1, *writer2;
paul@178 169
  long err = client_pipe(&reader1, &writer1, O_NONBLOCK) ||
paul@178 170
             client_pipe(&reader2, &writer2, O_NONBLOCK);
paul@65 171
paul@65 172
  if (err)
paul@65 173
  {
paul@123 174
    printf("Could not obtain pipes: %s\n", l4sys_errtostr(err));
paul@65 175
    return 1;
paul@65 176
  }
paul@65 177
paul@424 178
  printf("Starting activities...\n");
paul@424 179
paul@117 180
  /* Schedule reader and writer threads. */
paul@117 181
paul@123 182
  std::thread *activities[3];
paul@65 183
paul@132 184
  activities[0] = new std::thread(read_pipes, reader1, reader2);
paul@132 185
  activities[1] = new std::thread(write_pipe, writer1, 1);
paul@132 186
  activities[2] = new std::thread(write_pipe, writer2, 2);
paul@117 187
paul@123 188
  for (int i = 0; i < 3; i++)
paul@117 189
    activities[i]->join();
paul@407 190
paul@407 191
  printf("End of test.\n");
paul@407 192
  return 0;
paul@65 193
}
paul@65 194
paul@65 195
// vim: tabstop=2 expandtab shiftwidth=2