Browse Source

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

tags/v0.9.3
Michael Brown 17 years ago
parent
commit
07f84566d5
3 changed files with 151 additions and 50 deletions
  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 View File

60
 /** List of open files */
60
 /** List of open files */
61
 static LIST_HEAD ( posix_files );
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
  * Free open file
64
  * Free open file
71
  *
65
  *
251
 	return rc;
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
  * Read data from file
281
  * Read data from file
256
  *
282
  *
258
  * @v offset		Starting offset within data buffer
284
  * @v offset		Starting offset within data buffer
259
  * @v len		Maximum length to read
285
  * @v len		Maximum length to read
260
  * @ret len		Actual length read, or negative error number
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
 ssize_t read_user ( int fd, userptr_t buffer, off_t offset, size_t max_len ) {
291
 ssize_t read_user ( int fd, userptr_t buffer, off_t offset, size_t max_len ) {
263
 	struct posix_file *file;
292
 	struct posix_file *file;
264
 	struct io_buffer *iobuf;
293
 	struct io_buffer *iobuf;
265
-	size_t frag_len;
266
-	ssize_t len = 0;
294
+	size_t len;
267
 
295
 
268
 	/* Identify file */
296
 	/* Identify file */
269
 	file = posix_fd_to_file ( fd );
297
 	file = posix_fd_to_file ( fd );
270
 	if ( ! file )
298
 	if ( ! file )
271
 		return -EBADF;
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 View File

10
 #include <stdint.h>
10
 #include <stdint.h>
11
 #include <gpxe/uaccess.h>
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
 extern int open ( const char *uri_string );
22
 extern int open ( const char *uri_string );
14
 extern ssize_t read_user ( int fd, userptr_t buffer,
23
 extern ssize_t read_user ( int fd, userptr_t buffer,
15
 			   off_t offset, size_t len );
24
 			   off_t offset, size_t len );
25
+extern int select ( fd_set *readfds, int wait );
16
 extern ssize_t fsize ( int fd );
26
 extern ssize_t fsize ( int fd );
17
 extern int close ( int fd );
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
  * Read data from file
74
  * Read data from file
21
  *
75
  *

+ 38
- 15
src/interface/pxe/pxe_tftp.c View File

78
 		   ( ( filename[0] == '/' ) ? "" : "/" ), filename );
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
  * TFTP OPEN
113
  * TFTP OPEN
83
  *
114
  *
251
 
282
 
252
 	buffer = real_to_user ( tftp_read->Buffer.segment,
283
 	buffer = real_to_user ( tftp_read->Buffer.segment,
253
 				tftp_read->Buffer.offset );
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
 	if ( len < 0 ) {
286
 	if ( len < 0 ) {
256
 		tftp_read->Status = PXENV_STATUS ( len );
287
 		tftp_read->Status = PXENV_STATUS ( len );
257
 		return PXENV_EXIT_FAILURE;
288
 		return PXENV_EXIT_FAILURE;
258
 	}
289
 	}
290
+
259
 	tftp_read->BufferSize = len;
291
 	tftp_read->BufferSize = len;
260
 	tftp_read->PacketNumber = ++pxe_single_blkidx;
292
 	tftp_read->PacketNumber = ++pxe_single_blkidx;
261
 
293
 
359
 	char uri_string[PXE_URI_LEN];
391
 	char uri_string[PXE_URI_LEN];
360
 	int fd;
392
 	int fd;
361
 	userptr_t buffer;
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
 	DBG ( "PXENV_TFTP_READ_FILE" );
397
 	DBG ( "PXENV_TFTP_READ_FILE" );
368
 
398
 
384
 
414
 
385
 	/* Read file */
415
 	/* Read file */
386
 	buffer = phys_to_user ( tftp_read_file->Buffer );
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
 	close ( fd );
421
 	close ( fd );
399
 	tftp_read_file->BufferSize = len;
422
 	tftp_read_file->BufferSize = len;

Loading…
Cancel
Save