Browse Source

[interface] Expand object interface to allow for polymorphic interfaces

We have several types of object interface at present (data-xfer, job
control, name resolution), and there is some duplication of
functionality between them.  For example, job_done(), job_kill() and
xfer_close() are almost isomorphic to each other.

This updated version of the object interface mechanism allows for each
interface to export an arbitrary list of supported operations.
Advantages include:

  Operations methods now receive a pointer to the object, rather than
  a pointer to the interface.  This allows an object to, for example,
  implement a single close() method that can handle close() operations
  from any of its exposed interfaces.

  The close() operation is implemented as a generic operation (rather
  than having specific variants for data-xfer, job control, etc.).
  This will allow functions such as monojob_wait() to be used to wait
  for e.g.  a name resolution to complete.

  The amount of boilerplate code required in objects is reduced, not
  least because it is no longer necessary to include per-interface
  methods that simply use container_of() to derive a pointer to the
  object and then tail-call to a common per-object method.

  The cost of adding new operations is reduced; adding a new data-xfer
  operation such as stat() no longer incurs the penalty of adding a
  .stat member to the operations table of all existing data-xfer
  interfaces.

The data-xfer, job control and name resolution interfaces have not yet
been updated to use the new interface mechanism, but the code will
still compile and run.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 16 years ago
parent
commit
e71b83b22b
5 changed files with 413 additions and 44 deletions
  1. 222
    14
      src/core/interface.c
  2. 182
    21
      src/include/ipxe/interface.h
  3. 3
    3
      src/include/ipxe/job.h
  4. 3
    3
      src/include/ipxe/resolv.h
  5. 3
    3
      src/include/ipxe/xfer.h

+ 222
- 14
src/core/interface.c View File

@@ -18,19 +18,42 @@
18 18
 
19 19
 FILE_LICENCE ( GPL2_OR_LATER );
20 20
 
21
+#include <string.h>
21 22
 #include <ipxe/interface.h>
22 23
 
23 24
 /** @file
24 25
  *
25
- * Object communication interfaces
26
+ * Object interfaces
27
+ *
28
+ */
29
+
30
+/*****************************************************************************
31
+ *
32
+ * The null interface
33
+ *
34
+ */
35
+
36
+/** Null interface operations */
37
+static struct interface_operation null_intf_op[] = {};
38
+
39
+/** Null interface descriptor */
40
+struct interface_descriptor null_intf_desc =
41
+	INTF_DESC_PURE ( null_intf_op );
42
+
43
+/** The null interface */
44
+struct interface null_intf = INTF_INIT ( null_intf_desc );
45
+
46
+/*****************************************************************************
47
+ *
48
+ * Object interface plumbing
26 49
  *
27 50
  */
28 51
 
29 52
 /**
30
- * Plug an interface into a new destination interface
53
+ * Plug an object interface into a new destination object interface
31 54
  *
32
- * @v intf		Interface
33
- * @v dest		New destination interface
55
+ * @v intf		Object interface
56
+ * @v dest		New destination object interface
34 57
  *
35 58
  * The reference to the existing destination interface is dropped, a
36 59
  * reference to the new destination interface is obtained, and the
@@ -39,24 +62,209 @@ FILE_LICENCE ( GPL2_OR_LATER );
39 62
  * Note that there is no "unplug" call; instead you must plug the
40 63
  * interface into a null interface.
41 64
  */
42
-void plug ( struct interface *intf, struct interface *dest ) {
43
-	DBGC ( intf, "INTF %p moving from INTF %p to INTF %p\n",
44
-	       intf, intf->dest, dest );
65
+void intf_plug ( struct interface *intf, struct interface *dest ) {
66
+	DBGC ( INTF_COL ( intf ),
67
+	       "INTF " INTF_INTF_FMT " replug to " INTF_FMT "\n",
68
+	       INTF_INTF_DBG ( intf, intf->dest ), INTF_DBG ( dest ) );
69
+	intf_get ( dest );
45 70
 	intf_put ( intf->dest );
46
-	intf->dest = intf_get ( dest );
71
+	intf->dest = dest;
47 72
 }
48 73
 
49 74
 /**
50
- * Plug two interfaces together
75
+ * Plug two object interfaces together
51 76
  *
52
- * @v a			Interface A
53
- * @v b			Interface B
77
+ * @v a			Object interface A
78
+ * @v b			Object interface B
54 79
  *
55 80
  * Plugs interface A into interface B, and interface B into interface
56 81
  * A.  (The basic plug() function is unidirectional; this function is
57 82
  * merely a shorthand for two calls to plug(), hence the name.)
58 83
  */
59
-void plug_plug ( struct interface *a, struct interface *b ) {
60
-	plug ( a, b );
61
-	plug ( b, a );
84
+void intf_plug_plug ( struct interface *a, struct interface *b ) {
85
+	intf_plug ( a, b );
86
+	intf_plug ( b, a );
87
+}
88
+
89
+/**
90
+ * Unplug an object interface
91
+ *
92
+ * @v intf		Object interface
93
+ */
94
+void intf_unplug ( struct interface *intf ) {
95
+	intf_plug ( intf, &null_intf );
96
+}
97
+
98
+/**
99
+ * Ignore all further operations on an object interface
100
+ *
101
+ * @v intf		Object interface
102
+ */
103
+void intf_nullify ( struct interface *intf ) {
104
+	intf->desc = &null_intf_desc;
105
+}
106
+
107
+/**
108
+ * Increment reference count on an object interface
109
+ *
110
+ * @v intf		Object interface
111
+ * @ret intf		Object interface
112
+ */
113
+struct interface * intf_get ( struct interface *intf ) {
114
+	ref_get ( intf->refcnt );
115
+	return intf;
116
+}
117
+
118
+/**
119
+ * Decrement reference count on an object interface
120
+ *
121
+ * @v intf		Object interface
122
+ */
123
+void intf_put ( struct interface *intf ) {
124
+	ref_put ( intf->refcnt );
125
+}
126
+
127
+/**
128
+ * Get pointer to object containing object interface
129
+ *
130
+ * @v intf		Object interface
131
+ * @ret object		Containing object
132
+ */
133
+void * intf_object ( struct interface *intf ) {
134
+	return ( ( ( void * ) intf ) - intf->desc->offset );
135
+}
136
+
137
+/**
138
+ * Get pass-through interface
139
+ *
140
+ * @v intf		Object interface
141
+ * @ret passthru	Pass-through interface, or NULL
142
+ */
143
+static struct interface * intf_get_passthru ( struct interface *intf ) {
144
+	struct interface_descriptor *desc = intf->desc;
145
+
146
+	if ( desc->passthru_offset ) {
147
+		return ( ( ( void * ) intf ) + desc->passthru_offset );
148
+	} else {
149
+		return NULL;
150
+	}
151
+}
152
+
153
+/**
154
+ * Get object interface destination and operation method
155
+ *
156
+ * @v intf		Object interface
157
+ * @v type		Operation type
158
+ * @ret dest		Destination interface
159
+ * @ret func		Implementing method, or NULL
160
+ */
161
+void * intf_get_dest_op_untyped ( struct interface *intf, void *type,
162
+				  struct interface **dest ) {
163
+	struct interface_descriptor *desc;
164
+	struct interface_operation *op;
165
+	unsigned int i;
166
+
167
+	while ( 1 ) {
168
+		/* Search for an implementing method provided by the
169
+		 * current destination interface.
170
+		 */
171
+		*dest = intf_get ( intf->dest );
172
+		desc = (*dest)->desc;
173
+		for ( i = desc->num_op, op = desc->op ; i ; i--, op++ ) {
174
+			if ( op->type == type )
175
+				return op->func;
176
+		}
177
+
178
+		/* Pass through to the underlying interface, if applicable */
179
+		if ( ! ( intf = intf_get_passthru ( *dest ) ) )
180
+			return NULL;
181
+		intf_put ( *dest );
182
+	}
183
+}
184
+
185
+/*****************************************************************************
186
+ *
187
+ * Generic interface operations
188
+ *
189
+ */
190
+
191
+/**
192
+ * Close an object interface
193
+ *
194
+ * @v intf		Object interface
195
+ * @v rc		Reason for close
196
+ *
197
+ * Note that this function merely informs the destination object that
198
+ * the interface is about to be closed; it doesn't actually disconnect
199
+ * the interface.  In most cases, you probably want to use
200
+ * intf_shutdown() or intf_restart() instead.
201
+ */
202
+void intf_close ( struct interface *intf, int rc ) {
203
+	struct interface *dest;
204
+	intf_close_TYPE ( void * ) *op =
205
+		intf_get_dest_op ( intf, intf_close, &dest );
206
+	void *object = intf_object ( dest );
207
+
208
+	DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " close (%s)\n",
209
+	       INTF_INTF_DBG ( intf, dest ), strerror ( rc ) );
210
+
211
+	if ( op ) {
212
+		op ( object, rc );
213
+	} else {
214
+		/* Default is to ignore intf_close() */
215
+	}
216
+
217
+	intf_put ( dest );
218
+}
219
+
220
+/**
221
+ * Shut down an object interface
222
+ *
223
+ * @v intf		Object interface
224
+ * @v rc		Reason for close
225
+ *
226
+ * Blocks further operations from being received via the interface,
227
+ * executes a close operation on the destination interface, and
228
+ * unplugs the interface.
229
+ */
230
+void intf_shutdown ( struct interface *intf, int rc ) {
231
+
232
+	DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " shutting down (%s)\n",
233
+	       INTF_DBG ( intf ), strerror ( rc ) );
234
+
235
+	/* Block further operations */
236
+	intf_nullify ( intf );
237
+
238
+	/* Notify destination of close */
239
+	intf_close ( intf, rc );
240
+
241
+	/* Unplug interface */
242
+	intf_unplug ( intf );
243
+}
244
+
245
+/**
246
+ * Shut down and restart an object interface
247
+ *
248
+ * @v intf		Object interface
249
+ * @v rc		Reason for close
250
+ *
251
+ * Shuts down the interface, then unblocks operations that were
252
+ * blocked during shutdown.
253
+ */
254
+void intf_restart ( struct interface *intf, int rc ) {
255
+	struct interface_descriptor *desc = intf->desc;
256
+
257
+	/* Shut down the interface */
258
+	intf_shutdown ( intf, rc );
259
+
260
+	DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " restarting\n",
261
+	       INTF_DBG ( intf ) );
262
+
263
+	/* Restore the interface descriptor.  Must be done after
264
+	 * shutdown (rather than inhibiting intf_shutdown() from
265
+	 * nullifying the descriptor) in order to avoid a potential
266
+	 * infinite loop as the intf_close() operations on each side
267
+	 * of the link call each other recursively.
268
+	 */
269
+	intf->desc = desc;
62 270
 }

+ 182
- 21
src/include/ipxe/interface.h View File

@@ -3,23 +3,116 @@
3 3
 
4 4
 /** @file
5 5
  *
6
- * Object communication interfaces
6
+ * Object interfaces
7 7
  *
8 8
  */
9 9
 
10 10
 FILE_LICENCE ( GPL2_OR_LATER );
11 11
 
12
+#include <stddef.h>
12 13
 #include <ipxe/refcnt.h>
13 14
 
14
-/** An object communication interface */
15
+/** An object interface operation */
16
+struct interface_operation {
17
+	/** Operation type */
18
+	void *type;
19
+	/** Implementing method */
20
+	void *func;
21
+};
22
+
23
+/**
24
+ * Define an object interface operation
25
+ *
26
+ * @v op_type		Operation type
27
+ * @v object_type	Implementing method's expected object type
28
+ * @v op_func		Implementing method
29
+ * @ret op		Object interface operation
30
+ */
31
+#define INTF_OP( op_type, object_type, op_func ) {			      \
32
+		.type = op_type,					      \
33
+		.func = ( ( ( ( typeof ( op_func ) * ) NULL ) ==	      \
34
+			    ( ( op_type ## _TYPE ( object_type ) * ) NULL ) ) \
35
+			  ? op_func : op_func ),			      \
36
+	}
37
+
38
+/** An object interface descriptor */
39
+struct interface_descriptor {
40
+	/** Offset of interface within containing object */
41
+	size_t offset;
42
+	/** Number of interface operations */
43
+	unsigned int num_op;
44
+	/** Object interface operations */
45
+	struct interface_operation *op;
46
+	/** Offset to pass-through interface, if present */
47
+	ssize_t passthru_offset;
48
+};
49
+
50
+#define intf_offset( object_type, intf )				      \
51
+	( ( ( ( typeof ( ( ( object_type * ) NULL )->intf ) * ) NULL )	      \
52
+	    == ( ( struct interface * ) NULL ) )			      \
53
+	  ? offsetof ( object_type, intf )				      \
54
+	  : offsetof ( object_type, intf ) )
55
+
56
+/**
57
+ * Define an object interface descriptor
58
+ *
59
+ * @v object_type	Containing object data type
60
+ * @v intf		Interface name (i.e. field within object data type)
61
+ * @v operations	Object interface operations array
62
+ * @ret desc		Object interface descriptor
63
+ */
64
+#define INTF_DESC( object_type, intf, operations ) {			      \
65
+		.offset = intf_offset ( object_type, intf ),		      \
66
+		.op = operations,					      \
67
+		.num_op = ( sizeof ( operations ) /			      \
68
+			    sizeof ( operations[0] ) ),			      \
69
+		.passthru_offset = 0,					      \
70
+	}
71
+
72
+/**
73
+ * Define an object interface descriptor with pass-through interface
74
+ *
75
+ * @v object_type	Containing object data type
76
+ * @v intf		Interface name (i.e. field within object data type)
77
+ * @v operations	Object interface operations array
78
+ * @v passthru		Pass-through interface name
79
+ * @ret desc		Object interface descriptor
80
+ */
81
+#define INTF_DESC_PASSTHRU( object_type, intf, operations, passthru ) {	      \
82
+		.offset = offsetof ( object_type, intf ),		      \
83
+		.op = operations,					      \
84
+		.num_op = ( sizeof ( operations ) /			      \
85
+			    sizeof ( operations[0] ) ),			      \
86
+		.passthru_offset = ( intf_offset ( object_type, passthru ) -  \
87
+				     intf_offset ( object_type, intf ) ),     \
88
+	}
89
+
90
+/**
91
+ * Define an object interface descriptor for a pure-interface object
92
+ *
93
+ * @v operations	Object interface operations array
94
+ * @ret desc		Object interface descriptor
95
+ *
96
+ * A pure-interface object is an object that consists solely of a
97
+ * single interface.
98
+ */
99
+#define INTF_DESC_PURE( operations ) {					      \
100
+		.offset = 0,						      \
101
+		.op = operations,					      \
102
+		.num_op = ( sizeof ( operations ) /			      \
103
+			    sizeof ( operations[0] ) ),			      \
104
+		.passthru_offset = 0,					      \
105
+	}
106
+
107
+/** An object interface */
15 108
 struct interface {
16
-	/** Destination interface
109
+	/** Destination object interface
17 110
 	 *
18
-	 * When messages are sent via this interface, they will be
19
-	 * delivered to the destination interface.
111
+	 * When the containing object invokes an operation on this
112
+	 * interface, it will be executed by the destination object.
20 113
 	 *
21 114
 	 * This pointer may never be NULL.  When the interface is
22
-	 * unplugged, it should point to a null interface.
115
+	 * unplugged, it should point to the null interface.
23 116
 	 */
24 117
 	struct interface *dest;
25 118
 	/** Reference counter
@@ -28,31 +121,99 @@ struct interface {
28 121
 	 * object, this field may be NULL.
29 122
 	 */
30 123
 	struct refcnt *refcnt;
124
+	/** Interface descriptor */
125
+	struct interface_descriptor *desc;
31 126
 };
32 127
 
128
+extern void intf_plug ( struct interface *intf, struct interface *dest );
129
+extern void intf_plug_plug ( struct interface *a, struct interface *b );
130
+extern void intf_unplug ( struct interface *intf );
131
+extern void intf_nullify ( struct interface *intf );
132
+extern struct interface * intf_get ( struct interface *intf );
133
+extern void intf_put ( struct interface *intf );
134
+extern void * __attribute__ (( pure )) intf_object ( struct interface *intf );
135
+extern void * intf_get_dest_op_untyped ( struct interface *intf, void *type,
136
+					 struct interface **dest );
137
+
138
+extern void intf_close ( struct interface *intf, int rc );
139
+#define intf_close_TYPE( object_type ) \
140
+	typeof ( void ( object_type, int rc ) )
141
+
142
+extern void intf_shutdown ( struct interface *intf, int rc );
143
+extern void intf_restart ( struct interface *intf, int rc );
144
+
145
+extern struct interface_descriptor null_intf_desc;
146
+extern struct interface null_intf;
147
+
33 148
 /**
34
- * Increment reference count on an interface
149
+ * Initialise an object interface
35 150
  *
36
- * @v intf		Interface
37
- * @ret intf		Interface
151
+ * @v intf		Object interface
152
+ * @v desc		Object interface descriptor
153
+ * @v refcnt		Containing object reference counter, or NULL
38 154
  */
39
-static inline __attribute__ (( always_inline )) struct interface *
40
-intf_get ( struct interface *intf ) {
41
-	ref_get ( intf->refcnt );
42
-	return intf;
155
+static inline void intf_init ( struct interface *intf,
156
+			       struct interface_descriptor *desc,
157
+			       struct refcnt *refcnt ) {
158
+	intf->dest = &null_intf;
159
+	intf->refcnt = refcnt;
160
+	intf->desc = desc;
43 161
 }
44 162
 
45 163
 /**
46
- * Decrement reference count on an interface
164
+ * Initialise a static object interface
47 165
  *
48
- * @v intf		Interface
166
+ * @v descriptor	Object interface descriptor
49 167
  */
50
-static inline __attribute__ (( always_inline )) void
51
-intf_put ( struct interface *intf ) {
52
-	ref_put ( intf->refcnt );
53
-}
168
+#define INTF_INIT( descriptor ) {		\
169
+		.dest = &null_intf,		\
170
+		.refcnt = NULL,			\
171
+		.desc = &(descriptor),		\
172
+	}
173
+
174
+/**
175
+ * Get object interface destination and operation method
176
+ *
177
+ * @v intf		Object interface
178
+ * @v type		Operation type
179
+ * @ret dest		Destination interface
180
+ * @ret func		Implementing method, or NULL
181
+ */
182
+#define intf_get_dest_op( intf, type, dest )				\
183
+	( ( type ## _TYPE ( void * ) * )				\
184
+	  intf_get_dest_op_untyped ( intf, type, dest ) )
185
+
186
+/**
187
+ * Find debugging colourisation for an object interface
188
+ *
189
+ * @v intf		Object interface
190
+ * @ret col		Debugging colourisation
191
+ *
192
+ * Use as the first argument to DBGC() or equivalent macro.
193
+ */
194
+#define INTF_COL( intf ) intf_object ( intf )
195
+
196
+/** printf() format string for INTF_DBG() */
197
+#define INTF_FMT "%p+%zx"
54 198
 
55
-extern void plug ( struct interface *intf, struct interface *dest );
56
-extern void plug_plug ( struct interface *a, struct interface *b );
199
+/**
200
+ * printf() arguments for representing an object interface
201
+ *
202
+ * @v intf		Object interface
203
+ * @ret args		printf() argument list corresponding to INTF_FMT
204
+ */
205
+#define INTF_DBG( intf ) intf_object ( intf ), (intf)->desc->offset
206
+
207
+/** printf() format string for INTF_INTF_DBG() */
208
+#define INTF_INTF_FMT INTF_FMT "->" INTF_FMT
209
+
210
+/**
211
+ * printf() arguments for representing an object interface pair
212
+ *
213
+ * @v intf		Object interface
214
+ * @v dest		Destination object interface
215
+ * @ret args		printf() argument list corresponding to INTF_INTF_FMT
216
+ */
217
+#define INTF_INTF_DBG( intf, dest ) INTF_DBG ( intf ), INTF_DBG ( dest )
57 218
 
58 219
 #endif /* _IPXE_INTERFACE_H */

+ 3
- 3
src/include/ipxe/job.h View File

@@ -131,7 +131,7 @@ job_put ( struct job_interface *job ) {
131 131
  */
132 132
 static inline void job_plug ( struct job_interface *job,
133 133
 			       struct job_interface *dest ) {
134
-	plug ( &job->intf, &dest->intf );
134
+	intf_plug ( &job->intf, &dest->intf );
135 135
 }
136 136
 
137 137
 /**
@@ -142,7 +142,7 @@ static inline void job_plug ( struct job_interface *job,
142 142
  */
143 143
 static inline void job_plug_plug ( struct job_interface *a,
144 144
 				    struct job_interface *b ) {
145
-	plug_plug ( &a->intf, &b->intf );
145
+	intf_plug_plug ( &a->intf, &b->intf );
146 146
 }
147 147
 
148 148
 /**
@@ -151,7 +151,7 @@ static inline void job_plug_plug ( struct job_interface *a,
151 151
  * @v job		Job control interface
152 152
  */
153 153
 static inline void job_unplug ( struct job_interface *job ) {
154
-	plug ( &job->intf, &null_job.intf );
154
+	intf_plug ( &job->intf, &null_job.intf );
155 155
 }
156 156
 
157 157
 /**

+ 3
- 3
src/include/ipxe/resolv.h View File

@@ -94,7 +94,7 @@ resolv_put ( struct resolv_interface *resolv ) {
94 94
  */
95 95
 static inline __attribute__ (( always_inline )) void
96 96
 resolv_plug ( struct resolv_interface *resolv, struct resolv_interface *dest ) {
97
-	plug ( &resolv->intf, &dest->intf );
97
+	intf_plug ( &resolv->intf, &dest->intf );
98 98
 }
99 99
 
100 100
 /**
@@ -105,7 +105,7 @@ resolv_plug ( struct resolv_interface *resolv, struct resolv_interface *dest ) {
105 105
  */
106 106
 static inline __attribute__ (( always_inline )) void
107 107
 resolv_plug_plug ( struct resolv_interface *a, struct resolv_interface *b ) {
108
-	plug_plug ( &a->intf, &b->intf );
108
+	intf_plug_plug ( &a->intf, &b->intf );
109 109
 }
110 110
 
111 111
 /**
@@ -115,7 +115,7 @@ resolv_plug_plug ( struct resolv_interface *a, struct resolv_interface *b ) {
115 115
  */
116 116
 static inline __attribute__ (( always_inline )) void
117 117
 resolv_unplug ( struct resolv_interface *resolv ) {
118
-	plug ( &resolv->intf, &null_resolv.intf );
118
+	intf_plug ( &resolv->intf, &null_resolv.intf );
119 119
 }
120 120
 
121 121
 /**

+ 3
- 3
src/include/ipxe/xfer.h View File

@@ -238,7 +238,7 @@ xfer_put ( struct xfer_interface *xfer ) {
238 238
  */
239 239
 static inline __attribute__ (( always_inline )) void
240 240
 xfer_plug ( struct xfer_interface *xfer, struct xfer_interface *dest ) {
241
-	plug ( &xfer->intf, &dest->intf );
241
+	intf_plug ( &xfer->intf, &dest->intf );
242 242
 }
243 243
 
244 244
 /**
@@ -249,7 +249,7 @@ xfer_plug ( struct xfer_interface *xfer, struct xfer_interface *dest ) {
249 249
  */
250 250
 static inline __attribute__ (( always_inline )) void
251 251
 xfer_plug_plug ( struct xfer_interface *a, struct xfer_interface *b ) {
252
-	plug_plug ( &a->intf, &b->intf );
252
+	intf_plug_plug ( &a->intf, &b->intf );
253 253
 }
254 254
 
255 255
 /**
@@ -259,7 +259,7 @@ xfer_plug_plug ( struct xfer_interface *a, struct xfer_interface *b ) {
259 259
  */
260 260
 static inline __attribute__ (( always_inline )) void
261 261
 xfer_unplug ( struct xfer_interface *xfer ) {
262
-	plug ( &xfer->intf, &null_xfer.intf );
262
+	intf_plug ( &xfer->intf, &null_xfer.intf );
263 263
 }
264 264
 
265 265
 /**

Loading…
Cancel
Save