diff options
Diffstat (limited to 'src/include/gpxe')
| -rw-r--r-- | src/include/gpxe/aoe.h | 7 | ||||
| -rw-r--r-- | src/include/gpxe/async.h | 184 | ||||
| -rw-r--r-- | src/include/gpxe/dhcp.h | 4 | ||||
| -rw-r--r-- | src/include/gpxe/ftp.h | 2 | ||||
| -rw-r--r-- | src/include/gpxe/hello.h | 2 | ||||
| -rw-r--r-- | src/include/gpxe/http.h | 21 | ||||
| -rw-r--r-- | src/include/gpxe/iscsi.h | 7 | ||||
| -rw-r--r-- | src/include/gpxe/tftp.h | 2 |
8 files changed, 168 insertions, 61 deletions
diff --git a/src/include/gpxe/aoe.h b/src/include/gpxe/aoe.h index 8b3e0ca48..3c54b6bb1 100644 --- a/src/include/gpxe/aoe.h +++ b/src/include/gpxe/aoe.h @@ -107,7 +107,7 @@ struct aoe_session { /** Byte offset within command's data buffer */ unsigned int command_offset; /** Asynchronous operation for this command */ - struct async_operation aop; + struct async async; /** Retransmission timer */ struct retry_timer timer; @@ -121,8 +121,9 @@ struct aoe_session { extern void aoe_open ( struct aoe_session *aoe ); extern void aoe_close ( struct aoe_session *aoe ); -extern struct async_operation * aoe_issue ( struct aoe_session *aoe, - struct ata_command *command ); +extern int aoe_issue ( struct aoe_session *aoe, + struct ata_command *command, + struct async *parent ); /** An AoE device */ struct aoe_device { diff --git a/src/include/gpxe/async.h b/src/include/gpxe/async.h index 8a6819786..d3b075b92 100644 --- a/src/include/gpxe/async.h +++ b/src/include/gpxe/async.h @@ -7,56 +7,164 @@ * */ -#include <errno.h> -#include <assert.h> +#include <gpxe/list.h> -/** An asynchronous operation */ -struct async_operation { - /** Operation status - * - * This is an error code as defined in errno.h, plus an offset - * of EINPROGRESS. This means that a status value of 0 - * corresponds to a return status code of -EINPROGRESS, - * i.e. that the default state of an asynchronous operation is - * "not yet completed". - */ - int status; -}; +struct async; -/** - * Set asynchronous operation status +/** An asynchronous operation ID * - * @v aop Asynchronous operation - * @v rc Return status code + * Only positive identifiers are valid; negative values are used to + * indicate errors. */ -static inline __attribute__ (( always_inline )) void -async_set_status ( struct async_operation *aop, int rc ) { - aop->status = ( rc + EINPROGRESS ); -} +typedef long aid_t; + +/** Signals that can be delivered to asynchronous operations */ +enum signal { + /** A child asynchronous operation has completed + * + * The parent should call async_wait() to reap the completed + * child. async_wait() will return the exit status and + * operation identifier of the child. + * + * The handler for this signal can be set to @c NULL; if it + * is, then the children will accumulate as zombies until + * async_wait() is called. + * + * The handler for this signal can also be set to @c SIG_IGN; + * if it is, then the children will automatically be reaped. + * Note that if you use @c SIG_IGN then you will not be able + * to retrieve the return status of the children; the call to + * async_wait() will simply return -ECHILD. + */ + SIGCHLD = 0, + /** Cancel asynchronous operation + * + * This signal should trigger the asynchronous operation to + * cancel itself (including killing all its own children, if + * any), and then call async_done(). The asynchronous + * operation is allowed to not complete immediately. + * + * The handler for this signal can be set to @c NULL; if it + * is, then attempts to cancel the asynchronous operation will + * fail and the operation will complete normally. Anything + * waiting for the operation to cancel will block. + */ + SIGKILL, + /** Update progress of asynchronous operation + * + * This signal should cause the asynchronous operation to + * immediately update the @c completed and @c total fields. + * + * The handler for this signal can be set to @c NULL; if it + * is, then the asynchronous operation is expected to keep its + * @c completed and @c total fields up to date at all times. + */ + SIGUPDATE, + SIGMAX +}; /** - * Get asynchronous operation status + * A signal handler * - * @v aop Asynchronous operation - * @ret rc Return status code + * @v async Asynchronous operation + * @v signal Signal received */ -static inline __attribute__ (( always_inline )) int -async_status ( struct async_operation *aop ) { - return ( aop->status - EINPROGRESS ); -} +typedef void ( * signal_handler_t ) ( struct async *async, + enum signal signal ); + +/** Asynchronous operation operations */ +struct async_operations { + /** Reap asynchronous operation + * + * @v async Asynchronous operation + * + * Release all resources associated with the asynchronous + * operation. This will be called only after the asynchronous + * operation itself calls async_done(), so the only remaining + * resources will probably be the memory used by the struct + * async itself. + * + * This method can be set to @c NULL; if it is, then no + * resources will be freed. This may be suitable for + * asynchronous operations that consume no dynamically + * allocated memory. + */ + void ( * reap ) ( struct async *async ); + /** Handle signals */ + signal_handler_t signal[SIGMAX]; +}; + +/** An asynchronous operation */ +struct async { + /** Other asynchronous operations with the same parent */ + struct list_head siblings; + /** Child asynchronous operations */ + struct list_head children; + /** Parent asynchronous operation + * + * This field is optional; if left to NULL then the owner must + * never call async_done(). + */ + struct async *parent; + /** Asynchronous operation ID */ + aid_t aid; + /** Final return status code */ + int rc; + + /** Amount of operation completed so far + * + * The units for this quantity are arbitrary. @c completed + * divded by @total should give something which approximately + * represents the progress through the operation. For a + * download operation, using byte counts would make sense. + * + * This progress indicator should also incorporate the status + * of any child asynchronous operations. + */ + unsigned long completed; + /** Total operation size + * + * See @c completed. A zero value means "total size unknown" + * and is explcitly permitted; users should take this into + * account before calculating @c completed/total. + */ + unsigned long total; + + struct async_operations *aop; +}; + +extern struct async_operations default_async_operations; +extern struct async_operations orphan_async_operations; + +extern aid_t async_init ( struct async *async, struct async_operations *aop, + struct async *parent ); +extern void async_ignore_signal ( struct async *async, enum signal signal ); +extern void async_signal ( struct async *async, enum signal signal ); +extern void async_signal_children ( struct async *async, enum signal signal ); +extern void async_done ( struct async *async, int rc ); +extern aid_t async_wait ( struct async *async, int *rc, int block ); + +/** Default signal handler */ +#define SIG_DFL NULL + +/** Ignore signal */ +#define SIG_IGN async_ignore_signal /** - * Flag asynchronous operation as complete + * Initialise orphan asynchronous operation * - * @v aop Asynchronous operation - * @v rc Return status code + * @v async Asynchronous operation + * @ret aid Asynchronous operation ID + * + * An orphan asynchronous operation can act as a context for child + * operations. However, you must not call async_done() on such an + * operation, since this would attempt to send a signal to its + * (non-existent) parent. Instead, simply free the structure (after + * calling async_wait() to ensure that any child operations have + * completed). */ -static inline __attribute__ (( always_inline )) void -async_done ( struct async_operation *aop, int rc ) { - assert ( rc != -EINPROGRESS ); - async_set_status ( aop, rc ); +static inline aid_t async_init_orphan ( struct async *async ) { + return async_init ( async, &orphan_async_operations, NULL ); } -extern int async_wait ( struct async_operation *aop ); - #endif /* _GPXE_ASYNC_H */ diff --git a/src/include/gpxe/dhcp.h b/src/include/gpxe/dhcp.h index 60991e7e8..a3311d1a1 100644 --- a/src/include/gpxe/dhcp.h +++ b/src/include/gpxe/dhcp.h @@ -466,7 +466,7 @@ struct dhcp_session { */ int state; /** Asynchronous operation for this DHCP session */ - struct async_operation aop; + struct async async; /** Retransmission timer */ struct retry_timer timer; }; @@ -504,6 +504,6 @@ extern int create_dhcp_packet ( struct net_device *netdev, uint8_t msgtype, struct dhcp_packet *dhcppkt ); extern int copy_dhcp_packet_options ( struct dhcp_packet *dhcppkt, struct dhcp_option_block *options ); -extern struct async_operation * start_dhcp ( struct dhcp_session *dhcp ); +extern int start_dhcp ( struct dhcp_session *dhcp, struct async *parent ); #endif /* _GPXE_DHCP_H */ diff --git a/src/include/gpxe/ftp.h b/src/include/gpxe/ftp.h index 2c51036ae..06799d248 100644 --- a/src/include/gpxe/ftp.h +++ b/src/include/gpxe/ftp.h @@ -64,7 +64,7 @@ struct ftp_request { struct tcp_application tcp_data; /** Asynchronous operation for this FTP operation */ - struct async_operation aop; + struct async async; }; struct async_operation * ftp_get ( struct ftp_request *ftp ); diff --git a/src/include/gpxe/hello.h b/src/include/gpxe/hello.h index 18d0b3781..31e035cd7 100644 --- a/src/include/gpxe/hello.h +++ b/src/include/gpxe/hello.h @@ -44,7 +44,7 @@ struct hello_request { struct tcp_application tcp; /** Asynchronous operation */ - struct async_operation aop; + struct async async; }; extern struct async_operation * say_hello ( struct hello_request *hello ); diff --git a/src/include/gpxe/http.h b/src/include/gpxe/http.h index ca0afb942..49922e502 100644 --- a/src/include/gpxe/http.h +++ b/src/include/gpxe/http.h @@ -11,6 +11,7 @@ #include <gpxe/tcp.h> #include <gpxe/async.h> #include <gpxe/linebuf.h> +#include <gpxe/uri.h> /** HTTP default port */ #define HTTP_PORT 80 @@ -28,33 +29,29 @@ enum http_rx_state { * */ struct http_request { - /** Server address */ - struct sockaddr_tcpip server; - /** Server host name */ - const char *hostname; - /** Filename */ - const char *filename; + /** URI being fetched */ + struct uri *uri; /** Data buffer to fill */ struct buffer *buffer; + /** Asynchronous operation */ + struct async async; /** HTTP response code */ unsigned int response; /** HTTP Content-Length */ size_t content_length; + /** TCP application for this request */ + struct tcp_application tcp; /** Number of bytes already sent */ size_t tx_offset; /** RX state */ enum http_rx_state rx_state; /** Line buffer for received header lines */ struct line_buffer linebuf; - - /** TCP application for this request */ - struct tcp_application tcp; - /** Asynchronous operation */ - struct async_operation aop; }; -extern struct async_operation * http_get ( struct http_request *http ); +extern int http_get ( struct uri *uri, struct buffer *buffer, + struct async *parent ); #endif /* _GPXE_HTTP_H */ diff --git a/src/include/gpxe/iscsi.h b/src/include/gpxe/iscsi.h index bcb27376f..745606496 100644 --- a/src/include/gpxe/iscsi.h +++ b/src/include/gpxe/iscsi.h @@ -591,7 +591,7 @@ struct iscsi_session { */ struct scsi_command *command; /** Asynchronous operation for the current iSCSI operation */ - struct async_operation aop; + struct async async; /** Instant return code * * Set to a non-zero value if all requests should return @@ -637,8 +637,9 @@ struct iscsi_session { /** Maximum number of retries at connecting */ #define ISCSI_MAX_RETRIES 2 -extern struct async_operation * iscsi_issue ( struct iscsi_session *iscsi, - struct scsi_command *command ); +extern int iscsi_issue ( struct iscsi_session *iscsi, + struct scsi_command *command, + struct async *parent ); extern void iscsi_shutdown ( struct iscsi_session *iscsi ); /** An iSCSI device */ diff --git a/src/include/gpxe/tftp.h b/src/include/gpxe/tftp.h index 2359dcc45..551a6fc9d 100644 --- a/src/include/gpxe/tftp.h +++ b/src/include/gpxe/tftp.h @@ -135,7 +135,7 @@ struct tftp_session { int state; /** Asynchronous operation for this session */ - struct async_operation aop; + struct async async; /** Retransmission timer */ struct retry_timer timer; }; |
