Просмотр исходного кода

Make read_user() non-blocking, and add select() call.

tags/v0.9.3
Michael Brown 17 лет назад
Родитель
Сommit
07f84566d5
3 измененных файлов: 151 добавлений и 50 удалений
  1. 59
    35
      src/core/posix_io.c
  2. 54
    0
      src/include/gpxe/posix_io.h
  3. 38
    15
      src/interface/pxe/pxe_tftp.c

+ 59
- 35
src/core/posix_io.c Просмотреть файл

@@ -60,12 +60,6 @@ struct posix_file {
60 60
 /** List of open files */
61 61
 static LIST_HEAD ( posix_files );
62 62
 
63
-/** Minimum file descriptor that will ever be allocated */
64
-#define POSIX_FD_MIN ( 1 )
65
-
66
-/** Maximum file descriptor that will ever be allocated */
67
-#define POSIX_FD_MAX ( 255 )
68
-
69 63
 /**
70 64
  * Free open file
71 65
  *
@@ -251,6 +245,38 @@ int open ( const char *uri_string ) {
251 245
 	return rc;
252 246
 }
253 247
 
248
+/**
249
+ * Check file descriptors for readiness
250
+ *
251
+ * @v readfds		File descriptors to check
252
+ * @v wait		Wait until data is ready
253
+ * @ret nready		Number of ready file descriptors
254
+ */
255
+int select ( fd_set *readfds, int wait ) {
256
+	struct posix_file *file;
257
+	int fd;
258
+
259
+	do {
260
+		for ( fd = POSIX_FD_MIN ; fd <= POSIX_FD_MAX ; fd++ ) {
261
+			if ( ! FD_ISSET ( fd, readfds ) )
262
+				continue;
263
+			file = posix_fd_to_file ( fd );
264
+			if ( ! file )
265
+				return -EBADF;
266
+			if ( ( list_empty ( &file->data ) ) &&
267
+			     ( file->rc != -EINPROGRESS ) )
268
+				continue;
269
+			/* Data is available or status has changed */
270
+			FD_ZERO ( readfds );
271
+			FD_SET ( fd, readfds );
272
+			return 1;
273
+		}
274
+		step();
275
+	} while ( wait );
276
+
277
+	return 0;
278
+}
279
+
254 280
 /**
255 281
  * Read data from file
256 282
  *
@@ -258,47 +284,45 @@ int open ( const char *uri_string ) {
258 284
  * @v offset		Starting offset within data buffer
259 285
  * @v len		Maximum length to read
260 286
  * @ret len		Actual length read, or negative error number
287
+ *
288
+ * This call is non-blocking; if no data is available to read then
289
+ * -EWOULDBLOCK will be returned.
261 290
  */
262 291
 ssize_t read_user ( int fd, userptr_t buffer, off_t offset, size_t max_len ) {
263 292
 	struct posix_file *file;
264 293
 	struct io_buffer *iobuf;
265
-	size_t frag_len;
266
-	ssize_t len = 0;
294
+	size_t len;
267 295
 
268 296
 	/* Identify file */
269 297
 	file = posix_fd_to_file ( fd );
270 298
 	if ( ! file )
271 299
 		return -EBADF;
272 300
 
273
-	while ( 1 ) {
274
-		/* Try to fetch more data if none available */
275
-		if ( list_empty ( &file->data ) )
276
-			step();
277
-		/* Dequeue at most one received I/O buffer into user buffer */
278
-		list_for_each_entry ( iobuf, &file->data, list ) {
279
-			frag_len = iob_len ( iobuf );
280
-			if ( frag_len > max_len )
281
-				frag_len = max_len;
282
-			copy_to_user ( buffer, offset, iobuf->data,
283
-				       frag_len );
284
-			iob_pull ( iobuf, frag_len );
285
-			if ( ! iob_len ( iobuf ) ) {
286
-				list_del ( &iobuf-> list );
287
-				free_iob ( iobuf );
288
-			}
289
-			file->pos += frag_len;
290
-			len += frag_len;
291
-			offset += frag_len;
292
-			max_len -= frag_len;
293
-			break;
301
+	/* Try to fetch more data if none available */
302
+	if ( list_empty ( &file->data ) )
303
+		step();
304
+
305
+	/* Dequeue at most one received I/O buffer into user buffer */
306
+	list_for_each_entry ( iobuf, &file->data, list ) {
307
+		len = iob_len ( iobuf );
308
+		if ( len > max_len )
309
+			len = max_len;
310
+		copy_to_user ( buffer, offset, iobuf->data, len );
311
+		iob_pull ( iobuf, len );
312
+		if ( ! iob_len ( iobuf ) ) {
313
+			list_del ( &iobuf->list );
314
+			free_iob ( iobuf );
294 315
 		}
295
-		/* If buffer is full, return */
296
-		if ( ! max_len )
297
-			return len;
298
-		/* If file has completed, return */
299
-		if ( file->rc != -EINPROGRESS )
300
-			return ( file->rc ? file->rc : len );
316
+		file->pos += len;
317
+		return len;
301 318
 	}
319
+
320
+	/* If file has completed, return (after returning all data) */
321
+	if ( file->rc != -EINPROGRESS )
322
+		return file->rc;
323
+
324
+	/* No data ready and file still in progress; return -WOULDBLOCK */
325
+	return -EWOULDBLOCK;
302 326
 }
303 327
 
304 328
 /**

+ 54
- 0
src/include/gpxe/posix_io.h Просмотреть файл

@@ -10,12 +10,66 @@
10 10
 #include <stdint.h>
11 11
 #include <gpxe/uaccess.h>
12 12
 
13
+/** Minimum file descriptor that will ever be allocated */
14
+#define POSIX_FD_MIN ( 1 )
15
+
16
+/** Maximum file descriptor that will ever be allocated */
17
+#define POSIX_FD_MAX ( 31 )
18
+
19
+/** File descriptor set as used for select() */
20
+typedef uint32_t fd_set;
21
+
13 22
 extern int open ( const char *uri_string );
14 23
 extern ssize_t read_user ( int fd, userptr_t buffer,
15 24
 			   off_t offset, size_t len );
25
+extern int select ( fd_set *readfds, int wait );
16 26
 extern ssize_t fsize ( int fd );
17 27
 extern int close ( int fd );
18 28
 
29
+/**
30
+ * Zero a file descriptor set
31
+ *
32
+ * @v set		File descriptor set
33
+ */
34
+static inline __attribute__ (( always_inline )) void
35
+FD_ZERO ( fd_set *set ) {
36
+	*set = 0;
37
+}
38
+
39
+/**
40
+ * Set a bit within a file descriptor set
41
+ *
42
+ * @v fd		File descriptor
43
+ * @v set		File descriptor set
44
+ */
45
+static inline __attribute__ (( always_inline )) void
46
+FD_SET ( int fd, fd_set *set ) {
47
+	*set |= ( 1 << fd );
48
+}
49
+
50
+/**
51
+ * Clear a bit within a file descriptor set
52
+ *
53
+ * @v fd		File descriptor
54
+ * @v set		File descriptor set
55
+ */
56
+static inline __attribute__ (( always_inline )) void
57
+FD_CLR ( int fd, fd_set *set ) {
58
+	*set &= ~( 1 << fd );
59
+}
60
+
61
+/**
62
+ * Test a bit within a file descriptor set
63
+ *
64
+ * @v fd		File descriptor
65
+ * @v set		File descriptor set
66
+ * @ret is_set		Corresponding bit is set
67
+ */
68
+static inline __attribute__ (( always_inline )) int
69
+FD_ISSET ( int fd, fd_set *set ) {
70
+	return ( *set & ( 1 << fd ) );
71
+}
72
+
19 73
 /**
20 74
  * Read data from file
21 75
  *

+ 38
- 15
src/interface/pxe/pxe_tftp.c Просмотреть файл

@@ -78,6 +78,37 @@ static void pxe_tftp_build_uri ( char *uri_string,
78 78
 		   ( ( filename[0] == '/' ) ? "" : "/" ), filename );
79 79
 }
80 80
 
81
+/**
82
+ * Read as much as possible from file
83
+ *
84
+ * @v fd				File descriptor
85
+ * @v buffer				Data buffer
86
+ * @v max_len				Maximum length to read
87
+ * @ret len				Actual length read, or negative error
88
+ */
89
+static ssize_t pxe_tftp_read_all ( int fd, userptr_t buffer,
90
+				   size_t max_len ) {
91
+	fd_set fdset;
92
+	off_t offset = 0;
93
+	int ready;
94
+	ssize_t len;
95
+
96
+	do {
97
+		FD_ZERO ( &fdset );
98
+		FD_SET ( fd, &fdset );
99
+		ready = select ( &fdset, 1 );
100
+		if ( ready < 0 )
101
+			return ready;
102
+		len = read_user ( fd, buffer, offset, max_len );
103
+		if ( len < 0 )
104
+			return len;
105
+		offset += len;
106
+	        max_len -= len;
107
+	} while ( max_len && len );
108
+
109
+	return offset;
110
+}
111
+
81 112
 /**
82 113
  * TFTP OPEN
83 114
  *
@@ -251,11 +282,12 @@ PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ) {
251 282
 
252 283
 	buffer = real_to_user ( tftp_read->Buffer.segment,
253 284
 				tftp_read->Buffer.offset );
254
-	len = read_user ( pxe_single_fd, buffer, 0, pxe_single_blksize );
285
+	len = pxe_tftp_read_all ( pxe_single_fd, buffer, pxe_single_blksize );
255 286
 	if ( len < 0 ) {
256 287
 		tftp_read->Status = PXENV_STATUS ( len );
257 288
 		return PXENV_EXIT_FAILURE;
258 289
 	}
290
+
259 291
 	tftp_read->BufferSize = len;
260 292
 	tftp_read->PacketNumber = ++pxe_single_blkidx;
261 293
 
@@ -359,10 +391,8 @@ PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
359 391
 	char uri_string[PXE_URI_LEN];
360 392
 	int fd;
361 393
 	userptr_t buffer;
362
-	size_t max_len;
363
-	ssize_t frag_len;
364
-	size_t len = 0;
365
-	int rc = -ENOBUFS;
394
+	ssize_t len;
395
+	int rc = 0;
366 396
 
367 397
 	DBG ( "PXENV_TFTP_READ_FILE" );
368 398
 
@@ -384,16 +414,9 @@ PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
384 414
 
385 415
 	/* Read file */
386 416
 	buffer = phys_to_user ( tftp_read_file->Buffer );
387
-	max_len = tftp_read_file->BufferSize;
388
-	while ( max_len ) {
389
-		frag_len = read_user ( fd, buffer, len, max_len );
390
-		if ( frag_len <= 0 ) {
391
-			rc = frag_len;
392
-			break;
393
-		}
394
-		len += frag_len;
395
-		max_len -= frag_len;
396
-	}
417
+	len = pxe_tftp_read_all ( fd, buffer, tftp_read_file->BufferSize );
418
+	if ( len < 0 )
419
+		rc = len;
397 420
 
398 421
 	close ( fd );
399 422
 	tftp_read_file->BufferSize = len;

Загрузка…
Отмена
Сохранить