summaryrefslogtreecommitdiffstats
path: root/src/include/gpxe
diff options
context:
space:
mode:
Diffstat (limited to 'src/include/gpxe')
-rw-r--r--src/include/gpxe/aoe.h7
-rw-r--r--src/include/gpxe/async.h184
-rw-r--r--src/include/gpxe/dhcp.h4
-rw-r--r--src/include/gpxe/ftp.h2
-rw-r--r--src/include/gpxe/hello.h2
-rw-r--r--src/include/gpxe/http.h21
-rw-r--r--src/include/gpxe/iscsi.h7
-rw-r--r--src/include/gpxe/tftp.h2
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;
};