L4Re/departure

tests/dstest_test_client.cc

339:8349c51951e2
2022-05-22 Paul Boddie Changed the mmap interface to employ explicit visible region limits. mmap-region-flags
     1 /*     2  * Test dataspace operations.     3  *     4  * Copyright (C) 2020, 2021, 2022 Paul Boddie <paul@boddie.org.uk>     5  *     6  * This program is free software; you can redistribute it and/or     7  * modify it under the terms of the GNU General Public License as     8  * published by the Free Software Foundation; either version 2 of     9  * the License, or (at your option) any later version.    10  *    11  * This program is distributed in the hope that it will be useful,    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    14  * GNU General Public License for more details.    15  *    16  * You should have received a copy of the GNU General Public License    17  * along with this program; if not, write to the Free Software    18  * Foundation, Inc., 51 Franklin Street, Fifth Floor,    19  * Boston, MA  02110-1301, USA    20  */    21     22 #include <l4/re/env.h>    23 #include <l4/sys/err.h>    24     25 #include <systypes/fcntl.h>    26     27 #include <stdio.h>    28 #include <string.h>    29 #include <stdlib.h>    30 #include <time.h>    31     32 #include <system_error>    33 #include <thread>    34     35 #include <ipc/thread.h>    36     37 #include <fsclient/file.h>    38 #include <mem/memory_utils.h>    39     40     41     42 /* Test parameters affected by capability limits. */    43     44 const unsigned long NUMBER_OF_FILES = 10;    45 const unsigned int START_LIMIT = 10;    46 const unsigned int ACTIVITY_ITERATIONS = 20;    47     48 /* Test parameters unaffected by any capability limits. */    49     50 const unsigned int MAP_PAGES = 20;    51 const unsigned int REGION_ITERATIONS = 20;    52     53     54     55 /* An activity opening and reading from a file. */    56     57 static long activity(file_t *context, unsigned long fileid, unsigned int start_page)    58 {    59   unsigned long step = page(1);    60   unsigned long sample = page(1);    61     62   /* Allocate a buffer for sampling from the file. */    63     64   char buf[sample + 1];    65     66   /* Invoke the open method to receive the file reference. */    67     68   file_t file;    69     70   long err = file_context_open(&file, O_RDONLY, context);    71     72   if (err)    73   {    74     printf("Could not obtain file for %ld @ page %d: %s\n", fileid, start_page, l4sys_errtostr(err));    75     return err;    76   }    77     78   /* A region of the file is mapped. */    79     80   err = file_mmap(&file, page(start_page), page(MAP_PAGES), 0, 0, file_region_flags(file.flags));    81     82   if (err)    83   {    84     printf("Could not map file region for %ld @ page %d: %s\n", fileid, start_page, l4sys_errtostr(err));    85     file_close(&file);    86     return err;    87   }    88     89   /* Read the region a number of times. */    90     91   for (unsigned int read_counter = 0; read_counter < REGION_ITERATIONS; read_counter++)    92   {    93     for (unsigned long offset = 0; offset < file_populated_span(&file); offset += step)    94     {    95       unsigned long remaining = file_populated_span(&file) - offset;    96       unsigned long sample_remaining = remaining < sample ? remaining : sample;    97     98       strncpy(buf, (file.memory + offset), sample_remaining);    99       buf[sample_remaining] = '\0';   100    101       /* Test the data obtained. */   102    103       unsigned long filepos = file.start_pos + offset;   104       unsigned long _fileid = 0, _filepos = 0;   105       char *sep = strchr(buf, ':');   106    107       if (sep != NULL)   108       {   109         *sep = '\0'; sep++;   110         _fileid = atol(buf); _filepos = atol(sep);   111       }   112    113       if ((fileid != _fileid) || (filepos != _filepos))   114         printf("! %ld:%ld is not %ld:%ld\n", _fileid, _filepos, fileid, filepos);   115     }   116   }   117    118   file_close(&file);   119    120   return L4_EOK;   121 }   122    123    124    125 static long activity_iterate(file_t *context, unsigned long fileid, unsigned int start_page)   126 {   127   long err;   128    129   /* Open the file, read pages, close the file, over and over. */   130    131   for (unsigned int iteration = 0; iteration < ACTIVITY_ITERATIONS; iteration++)   132   {   133     err = activity(context, fileid, start_page);   134     if (err)   135       break;   136   }   137    138   return err;   139 }   140    141    142    143 static long context_for_file(unsigned long fileid, file_t *file, l4_cap_idx_t server)   144 {   145   long err = file_context(file, server);   146    147   if (err)   148   {   149     printf("Could not obtain context: %s\n", l4sys_errtostr(err));   150     file_close(file);   151     return err;   152   }   153    154   /* Write the filename. */   155    156   sprintf(file->memory, "%ld", fileid);   157    158   return L4_EOK;   159 }   160    161    162    163 int main(void)   164 {   165   long err;   166    167   /* Introduce concurrency control. */   168    169   err = ipc_thread_init();   170    171   if (err)   172   {   173     printf("Initialisation error: %s\n", l4sys_errtostr(err));   174     return 1;   175   }   176    177   /* Retain activity and context details. */   178    179   std::thread *activities[NUMBER_OF_FILES * START_LIMIT];   180   file_t contexts[NUMBER_OF_FILES];   181    182   /* Obtain access to the filesystem. */   183    184   l4_cap_idx_t server = l4re_env_get_cap("server");   185    186   /* Obtain opener contexts for the files. */   187    188   unsigned long fileid;   189    190   for (fileid = 0; fileid < NUMBER_OF_FILES; fileid++)   191   {   192     err = context_for_file(fileid, &contexts[fileid], server);   193    194     if (err)   195     {   196       printf("Context allocation failed.\n");   197       return 1;   198     }   199   }   200    201   /* Start threads accessing all the files. */   202    203   printf("Starting threads...\n");   204    205   time_t t = time(NULL);   206   int current = 0;   207   unsigned long errors = 0;   208    209   for (fileid = 0; fileid < NUMBER_OF_FILES; fileid++)   210   {   211     for (unsigned int start_page = 0; start_page < START_LIMIT; start_page++)   212     {   213       try   214       {   215         activities[current++] = new std::thread(activity_iterate, &contexts[fileid], fileid, start_page);   216       }   217       catch (const std::system_error &exc)   218       {   219         errors++;   220       }   221     }   222   }   223    224   /* Wait for the threads. */   225    226   int limit = current;   227    228   printf("Waiting for %d threads...\n", limit);   229    230   for (current = 0; current < limit; current++)   231     activities[current]->join();   232    233   /* Discard the contexts. */   234    235   for (fileid = 0; fileid < NUMBER_OF_FILES; fileid++)   236     file_close(&contexts[fileid]);   237    238   t = time(NULL) - t;   239   printf("Activities completed in %ld seconds (with %ld threads not started).\n", t, errors);   240    241   return 0;   242 }   243    244 // vim: tabstop=2 expandtab shiftwidth=2