]> Git Repo - binutils.git/blob - gdb/testsuite/lib/read1.c
Automatic date update in version.in
[binutils.git] / gdb / testsuite / lib / read1.c
1 /* This is part of GDB, the GNU debugger.
2
3    Copyright 2011-2022 Free Software Foundation, Inc.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #define _GNU_SOURCE 1
20 #include <dlfcn.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <stdio.h>
27
28 /* Default READMORE method.  */
29 #define READMORE_METHOD_DEFAULT 2
30
31 /* Default READMORE sleep time in miliseconds.  */
32 #define READMORE_SLEEP_DEFAULT 10
33
34 /* Helper function.  Intialize *METHOD according to environment variable
35    READMORE_METHOD, and *SLEEP according to environment variable
36    READMORE_SLEEP.  */
37
38 static void
39 init_readmore (int *method, unsigned int *sleep, FILE **log)
40 {
41   char *env = getenv ("READMORE_METHOD");
42   if (env == NULL)
43     *method = READMORE_METHOD_DEFAULT;
44   else if (strcmp (env, "1") == 0)
45     *method = 1;
46   else if (strcmp (env, "2") == 0)
47     *method = 2;
48   else
49     /* Default.  */
50     *method = READMORE_METHOD_DEFAULT;
51
52   env = getenv ("READMORE_SLEEP");
53   if (env == NULL)
54     *sleep = READMORE_SLEEP_DEFAULT;
55   else
56     *sleep = atoi (env);
57
58   env = getenv ("READMORE_LOG");
59   if (env == NULL)
60     *log = NULL;
61   else
62     *log = fopen (env, "w");
63 }
64
65 /* Wrap 'read', and modify it's behaviour using READ1 or READMORE style.  */
66
67 ssize_t
68 read (int fd, void *buf, size_t count)
69 {
70   static ssize_t (*read2) (int fd, void *buf, size_t count) = NULL;
71   static FILE *log;
72   int readmore;
73 #ifdef READMORE
74   readmore = 1;
75 #else
76   readmore = 0;
77 #endif
78   static int readmore_method;
79   static unsigned int readmore_sleep;
80   if (read2 == NULL)
81     {
82       /* Use setenv (v, "", 1) rather than unsetenv (v) to work around
83          https://core.tcl-lang.org/tcl/tktview?name=67fd4f973a "incorrect
84          results of 'info exists' when unset env var in one interp and check
85          for existence from another interp".  */
86       setenv ("LD_PRELOAD", "", 1);
87       read2 = dlsym (RTLD_NEXT, "read");
88       if (readmore)
89         init_readmore (&readmore_method, &readmore_sleep, &log);
90     }
91
92   /* Only modify 'read' behaviour when reading from the terminal.  */
93   if (isatty (fd) == 0)
94     goto fallback;
95
96   if (!readmore)
97     {
98       /* READ1.  Force read to return only one byte at a time.  */
99       return read2 (fd, buf, 1);
100     }
101
102   if (readmore_method == 1)
103     {
104       /* READMORE, method 1.  Wait a little before doing a read.  */
105       usleep (readmore_sleep * 1000);
106       return read2 (fd, buf, count);
107     }
108
109   if (readmore_method == 2)
110     {
111       /* READMORE, method 2.  After doing a read, either return or wait
112          a little and do another read, and so on.  */
113       ssize_t res, total;
114       int iteration;
115       int max_iterations = -1;
116
117       total = 0;
118       for (iteration = 1; ; iteration++)
119         {
120           res = read2 (fd, (char *)buf + total, count - total);
121           if (log != NULL)
122             fprintf (log,
123                      "READ (%d): fd: %d, COUNT: %zd, RES: %zd, ERRNO: %s\n",
124                      iteration, fd, count - total, res,
125                      res == -1 ? strerror (errno) : "none");
126           if (res == -1)
127             {
128               if (iteration == 1)
129                 {
130                   /* Error on first read, report.  */
131                   total = -1;
132                   break;
133                 }
134
135               if (total > 0
136                   && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EIO))
137                 {
138                   /* Ignore error, but don't try anymore reading.  */
139                   errno = 0;
140                   break;
141                 }
142
143               /* Other error, report back.  */
144               total = -1;
145               break;
146             }
147
148           total += res;
149           if (total == count)
150             /* Buf full, no need to do any more reading.  */
151             break;
152
153           /* Handle end-of-file.  */
154           if (res == 0)
155             break;
156
157           if (iteration == max_iterations)
158             break;
159
160           usleep (readmore_sleep * 1000);
161         }
162
163       if (log)
164         fprintf (log, "READ returning: RES: %zd, ERRNO: %s\n",
165                  total, total == -1 ? strerror (errno) : "none");
166       return total;
167     }
168
169  fallback:
170   /* Fallback, regular read.  */
171   return read2 (fd, buf, count);
172 }
This page took 0.031581 seconds and 4 git commands to generate.