Use the Arla xg files rather than C headers as sources for the rxgen script.
Signed-off-by: David Howells <dhowells@redhat.com>
CFLAGS := $(shell python3-config --cflags)
+RXGEN := ./rxgen/rxgen.pl $(wildcard ./rxgen/*.pm)
-pykafs.so: afs_xg.c afs_py.c afs_py.h
+GENERATED := afs_xg.c afs_xg.h afs_py.c afs_py.h
+
+pykafs.so: $(GENERATED)
python3 compile_pykafs.py build
-AFS_API := afs.h afs_vl.h afs_fs.h afs_cm.h
+AFS_API := rpc-api/afsuuid.h rpc-api/vldb.xg
-afs_xg.c afs_py.c afs_py.h: $(AFS_API) ./rxgen/rxgen.pl
+$(GENERATED): $(AFS_API) $(RXGEN)
./rxgen/rxgen.pl $(AFS_API)
clean:
find \( -name "*~" -o -name "*.o" -o -name "*.so" \) -delete
rm -rf build/
- rm -f afs_xg.c afs_py.c afs_py.h
+ rm -f $(GENERATED)
*/
int rxrpc_send_request(struct rx_connection *z_conn,
struct rx_call *call,
- const net_xdr_t *request,
- size_t request_size,
- size_t reply_buf_size)
+ struct iovec *request,
+ int request_ioc)
{
struct msghdr msg;
- struct iovec iov[2];
size_t ctrllen;
unsigned char control[128];
- call->got_eor = 0;
- call->error_code = 0;
- call->abort_code = 0;
- call->reply_buf_size = reply_buf_size;
- call->reply_size = 0;
-
/* request an operation */
ctrllen = 0;
RXRPC_ADD_CALLID(control, ctrllen, (unsigned long)call);
- iov[0].iov_base = (void *)request;
- iov[0].iov_len = request_size;
-
msg.msg_name = &z_conn->peer;
msg.msg_namelen = sizeof(z_conn->peer);
- msg.msg_iov = iov;
- msg.msg_iovlen = 1;
+ msg.msg_iov = request;
+ msg.msg_iovlen = request_ioc;
msg.msg_control = control;
msg.msg_controllen = ctrllen;
msg.msg_flags = 0;
//dump_cmsg(&msg);
+ if (0) {
+ const uint8_t *p;
+ unsigned i, j;
+
+ printf("NAME %02u [", msg.msg_namelen);
+ p = (const void *)msg.msg_name;
+ for (i = 0; i < msg.msg_namelen; i++)
+ printf("%02x", *p++);
+ printf("]\n");
+
+ for (j = 0; j < msg.msg_iovlen; j++) {
+ printf("IOV[%02u] %04zu [", i, msg.msg_iov[j].iov_len);
+ p = (const void *)msg.msg_iov[j].iov_base;
+ for (i = 0; i < msg.msg_iov[j].iov_len; i++)
+ printf("%02x", *p++);
+ printf("]\n");
+ }
+
+ printf("CTRL %02zu [", msg.msg_controllen);
+ p = (const void *)msg.msg_control;
+ for (i = 0; i < msg.msg_controllen; i++)
+ printf("%02x", *p++);
+ printf("]\n");
+
+ printf("FLAGS %x\n", msg.msg_flags);
+ }
+
return sendmsg(z_conn->fd, &msg, 0) == -1 ? -1 : 0;
}
struct cmsghdr *cmsg;
struct msghdr msg;
struct iovec iov[2];
- size_t space;
- unsigned char control[128], overrun[sizeof(long)];
+ unsigned char control[128];
int ret;
/* wait for a reply */
- while (!call->got_eor) {
- space = call->reply_buf_size - call->reply_size;
- iov[0].iov_base = call->reply + call->reply_size;
- iov[0].iov_len = space;
- iov[1].iov_base = &overrun;
- iov[1].iov_len = sizeof(overrun);
-
- if (iov[0].iov_len > 0) {
- msg.msg_iov = iov;
- msg.msg_iovlen = 2;
+ while (!call->got_eor &&
+ CIRC_CNT(call->head, call->tail, call->size) < call->need_size
+ ) {
+ struct iovec *piov = iov;
+ unsigned size = call->size;
+ unsigned mask = size - 1;
+ unsigned head = call->head & mask;
+ unsigned tail = call->tail & mask;
+ unsigned space = CIRC_SPACE(head, tail, size);
+
+ if (head >= tail) {
+ piov->iov_base = (void *)call->reply + head;
+ piov->iov_len = size - head;
+ piov++;
+ space -= size - (head & mask);
+ if (space > 0) {
+ piov->iov_base = (void *)call->reply;
+ piov->iov_len = space;
+ piov++;
+ }
} else {
- msg.msg_iov = iov + 1;
- msg.msg_iovlen = 1;
+ piov->iov_base = (void *)call->reply + head;
+ piov->iov_len = space;
+ piov++;
}
+ msg.msg_iov = iov;
+ msg.msg_iovlen = piov - iov;
+
memcpy(&srx, &z_conn->peer, sizeof(struct sockaddr_rxrpc));
msg.msg_name = &srx;
msg.msg_namelen = sizeof(srx);
sizeof(call->abort_code));
z_conn->last_abort_code = call->abort_code;
errno = ECONNABORTED;
- return call->abort_code;;
+ return call->abort_code;
case RXRPC_NET_ERROR:
case RXRPC_LOCAL_ERROR:
}
}
- if (ret > space) {
- errno = EMSGSIZE;
- return -1;
- }
-
- call->reply_size += ret;
+ call->head += ret;
}
return 0;
--- /dev/null
+/*
+ * See Documentation/circular-buffers.txt for more information.
+ */
+
+#ifndef _LINUX_CIRC_BUF_H
+#define _LINUX_CIRC_BUF_H 1
+
+/* Return count in buffer. */
+#define CIRC_CNT(head,tail,size) (((head) - (tail)) & ((size)-1))
+
+/* Return space available, 0..size-1. We always leave one free char
+ as a completely full buffer has head == tail, which is the same as
+ empty. */
+#define CIRC_SPACE(head,tail,size) CIRC_CNT((tail),((head)+1),(size))
+
+/* Return count up to the end of the buffer. Carefully avoid
+ accessing head and tail more than once, so they can change
+ underneath us without returning inconsistent results. */
+#define CIRC_CNT_TO_END(head,tail,size) \
+ ({int end = (size) - (tail); \
+ int n = ((head) + end) & ((size)-1); \
+ n < end ? n : end;})
+
+/* Return space available up to the end of the buffer. */
+#define CIRC_SPACE_TO_END(head,tail,size) \
+ ({int end = (size) - 1 - (head); \
+ int n = (end + (tail)) & ((size)-1); \
+ n <= end ? n : end+1;})
+
+#endif /* _LINUX_CIRC_BUF_H */
from distutils.core import setup, Extension
setup(name="kafs", version="0.1",
ext_modules=[Extension("kafs",
- sources = [ "kafs.c",
+ sources = [ "afs_xg.c",
+ "kafs.c",
"afs_py.c",
"py_rxgen.c",
- "afs_xg.c",
"af_rxrpc.c"
],
)])
#include "py_rxgen.h"
#include "rxgen.h"
+PyObject *py_rxgen_get_struct(const void *p, PyObject **cache,
+ PyObject *(*data_to_type)(const void *elem))
+{
+ PyObject *obj;
+
+ if (*cache) {
+ Py_INCREF(*cache);
+ return *cache;
+ }
+
+ obj = data_to_type(p);
+ if (!obj)
+ return NULL;
+
+ Py_INCREF(obj);
+ *cache = obj;
+ return obj;
+}
+
+int py_rxgen_set_struct(PyObject **cache, PyTypeObject *type, PyObject *val)
+{
+ if (!PyObject_TypeCheck(val, type)) {
+ PyErr_Format(PyExc_TypeError, "Unexpected type");
+ return -1;
+ }
+ Py_XDECREF(*cache);
+ Py_INCREF(val);
+ *cache = val;
+ return 0;
+}
+
+int py_rxgen_premarshal_struct(void *array, size_t size, size_t offs,
+ PyObject *cache,
+ int (*premarshal)(PyObject *object))
+{
+ if (!cache)
+ return 0;
+
+ if (premarshal(cache) < 0)
+ return -1;
+ memcpy(array, (void *)cache + offs, size);
+ return 0;
+}
+
PyObject *py_rxgen_get_string(const void *_array, size_t n)
{
const char *array = _array;
return 0;
}
-PyObject *py_rxgen_get_uint8(const void *_array, size_t n)
+PyObject *py_rxgen_get_uint8(const void *_array, size_t n, PyObject **cache)
{
PyObject *list;
const uint8_t *array = _array;
int i;
- list = PyTuple_New(n);
+ if (*cache) {
+ Py_INCREF(*cache);
+ return *cache;
+ }
+
+ list = PyList_New(n);
if (!list)
return NULL;
if (!num)
goto error;
- if (PyTuple_SetItem(list, i, num) != 0) {
+ if (PyList_SetItem(list, i, num) != 0) {
Py_DECREF(num);
goto error;
}
}
+
+ Py_INCREF(list);
+ *cache = list;
return list;
error:
return NULL;
}
-PyObject *py_rxgen_get_uint16(const void *_array, size_t n)
+PyObject *py_rxgen_get_uint16(const void *_array, size_t n, PyObject **cache)
{
PyObject *list;
const uint16_t *array = _array;
int i;
- list = PyTuple_New(n);
+ if (*cache) {
+ Py_INCREF(*cache);
+ return *cache;
+ }
+
+ list = PyList_New(n);
if (!list)
return NULL;
if (!num)
goto error;
- if (PyTuple_SetItem(list, i, num) != 0) {
+ if (PyList_SetItem(list, i, num) != 0) {
Py_DECREF(num);
goto error;
}
}
+
+ Py_INCREF(list);
+ *cache = list;
return list;
error:
return NULL;
}
-PyObject *py_rxgen_get_uint32(const void *_array, size_t n)
+PyObject *py_rxgen_get_uint32(const void *_array, size_t n, PyObject **cache)
{
PyObject *list;
const uint32_t *array = _array;
int i;
- list = PyTuple_New(n);
+ if (*cache) {
+ Py_INCREF(*cache);
+ return *cache;
+ }
+
+ list = PyList_New(n);
if (!list)
return NULL;
if (!num)
goto error;
- if (PyTuple_SetItem(list, i, num) != 0) {
+ if (PyList_SetItem(list, i, num) != 0) {
Py_DECREF(num);
goto error;
}
}
+
+ Py_INCREF(list);
+ *cache = list;
return list;
error:
return NULL;
}
-int py_rxgen_set_uint32(void *_array, size_t n, PyObject *val)
+int py_rxgen_set_array(size_t n, PyObject **cache, PyObject *list)
{
- uint32_t *array = _array;
- int i;
+ if (!PySequence_Check(list) ||
+ PySequence_Size(list) > n) {
+ PyErr_Format(PyExc_ValueError,
+ "Expected a sequence of up to %zu size", n);
+ return -1;
+ }
+ Py_XDECREF(*cache);
+ Py_INCREF(list);
+ *cache = list;
+ return 0;
+}
+
+int py_rxgen_premarshal_uint8(void *_array, size_t n, PyObject *cache)
+{
+ PyObject *list;
+ uint8_t *array = _array;
+ Py_ssize_t i, c;
- if (!PyTuple_Check(val)) {
- PyErr_Format(PyExc_TypeError,
- "Expected a tuple");
+ if (!cache)
+ return 0;
+
+ list = PySequence_Fast(cache, "Expecting list or tuple of integers");
+ if (!list)
return -1;
+ c = PySequence_Fast_GET_SIZE(list);
+ if (c > n) {
+ PyErr_Format(PyExc_ValueError,
+ "Expected a sequence of up to %zu size", n);
+ goto error;
+ }
+
+ PyErr_Clear();
+ for (i = 0; i < c; i++) {
+ PyObject *p = PySequence_Fast_GET_ITEM(list, i);
+ unsigned long val = PyLong_AsUnsignedLong(p);
+
+ if (PyErr_Occurred())
+ goto error;
+ array[i] = val;
}
- if (PyTuple_GET_SIZE(val) != n) {
+ for (; i < n; i++)
+ array[i] = 0;
+
+ Py_DECREF(list);
+ return 0;
+
+error:
+ Py_DECREF(list);
+ return -1;
+}
+
+int py_rxgen_premarshal_uint16(void *_array, size_t n, PyObject *cache)
+{
+ PyObject *list;
+ uint16_t *array = _array;
+ Py_ssize_t i, c;
+
+ if (!cache)
+ return 0;
+
+ list = PySequence_Fast(cache, "Expecting list or tuple of integers");
+ if (!list)
+ return -1;
+ c = PySequence_Fast_GET_SIZE(list);
+ if (c > n) {
PyErr_Format(PyExc_ValueError,
- "Expected a tuple of %zu size", n);
+ "Expected a sequence of up to %zu size", n);
+ goto error;
+ }
+
+ PyErr_Clear();
+ for (i = 0; i < c; i++) {
+ PyObject *p = PySequence_Fast_GET_ITEM(list, i);
+ unsigned long val = PyLong_AsUnsignedLong(p);
+
+ if (PyErr_Occurred())
+ goto error;
+ array[i] = val;
+ }
+ for (; i < n; i++)
+ array[i] = 0;
+
+ Py_DECREF(list);
+ return 0;
+
+error:
+ Py_DECREF(list);
+ return -1;
+}
+
+int py_rxgen_premarshal_uint32(void *_array, size_t n, PyObject *cache)
+{
+ PyObject *list;
+ uint32_t *array = _array;
+ Py_ssize_t i, c;
+
+ if (!cache)
+ return 0;
+
+ list = PySequence_Fast(cache, "Expecting list or tuple of integers");
+ if (!list)
return -1;
+ c = PySequence_Fast_GET_SIZE(list);
+ if (c > n) {
+ PyErr_Format(PyExc_ValueError,
+ "Expected a sequence of up to %zu size", n);
+ goto error;
}
PyErr_Clear();
- for (i = 0; i < n; i++) {
- PyObject *p = PyTuple_GET_ITEM(val, i);
+ for (i = 0; i < c; i++) {
+ PyObject *p = PySequence_Fast_GET_ITEM(list, i);
unsigned long val = PyLong_AsUnsignedLong(p);
if (PyErr_Occurred())
- return -1;
+ goto error;
array[i] = val;
}
+ for (; i < n; i++)
+ array[i] = 0;
+
+ Py_DECREF(list);
+ return 0;
+
+error:
+ Py_DECREF(list);
+ return -1;
+}
+
+PyObject *py_rxgen_get_structs(const void *data, size_t num, size_t size,
+ PyObject **cache,
+ PyObject *(*data_to_type)(const void *elem))
+{
+ PyObject *list, *obj;
+ int i;
+
+ if (*cache) {
+ Py_INCREF(*cache);
+ return *cache;
+ }
+
+ list = PyList_New(num);
+ if (!list)
+ return NULL;
+
+ for (i = 0; i < num; i++) {
+ obj = data_to_type(data + num * size);
+ if (!obj) {
+ Py_DECREF(list);
+ return NULL;
+ }
+ PyList_SetItem(list, i, obj);
+ }
+
+ Py_INCREF(list);
+ *cache = list;
+ return list;
+}
+
+int py_rxgen_premarshal_structs(void *array,
+ size_t n, size_t size, size_t offs,
+ PyObject *cache,
+ int (*premarshal)(PyObject *object))
+{
+ PyObject *list;
+ Py_ssize_t i, c;
+
+ list = PySequence_Fast(cache, "Expecting list or tuple of structs");
+ if (!list)
+ return -1;
+ c = PySequence_Fast_GET_SIZE(list);
+ if (c > n) {
+ PyErr_Format(PyExc_ValueError,
+ "Expected a sequence of up to %zu size", n);
+ goto error;
+ }
+ for (i = 0; i < c; i++) {
+ PyObject *p = PySequence_Fast_GET_ITEM(list, i);
+ if (premarshal(p) < 0)
+ goto error;
+ memcpy(array + i * size, (void *)p + offs, size);
+ }
+
+ if (i < n)
+ memset(array + i * size, 0, (n - i) * size);
+
+ Py_DECREF(list);
return 0;
+
+error:
+ Py_DECREF(list);
+ return -1;
}
/*
extern PyObject *kafs_py_rx_new_connection(PyObject *, PyObject *);
-extern PyObject *py_rxgen_get_string(const void *_p, size_t n);
-extern PyObject *py_rxgen_get_uint8(const void *_p, size_t n);
-extern PyObject *py_rxgen_get_uint16(const void *_p, size_t n);
-extern PyObject *py_rxgen_get_uint32(const void *_p, size_t n);
+/*
+ * Single embedded struct handling
+ */
+extern PyObject *py_rxgen_get_struct(const void *p, PyObject **cache,
+ PyObject *(*data_to_type)(const void *elem));
+extern int py_rxgen_set_struct(PyObject **cache, PyTypeObject *type, PyObject *val);
+extern int py_rxgen_premarshal_struct(void *p, size_t size, size_t offs,
+ PyObject *cache,
+ int (*premarshal)(PyObject *object));
+/*
+ * Embedded string (char array) handling
+ */
+extern PyObject *py_rxgen_get_string(const void *_p, size_t n);
extern int py_rxgen_set_string(void *_p, size_t n, PyObject *val);
-extern int py_rxgen_set_uint8(void *_p, size_t n, PyObject *val);
-extern int py_rxgen_set_uint16(void *_p, size_t n, PyObject *val);
-extern int py_rxgen_set_uint32(void *_p, size_t n, PyObject *val);
+
+/*
+ * Embedded general array handling
+ */
+extern int py_rxgen_set_array(size_t n, PyObject **cache, PyObject *val);
+
+/*
+ * Embedded integer array handling
+ */
+extern PyObject *py_rxgen_get_uint8(const void *_array , size_t n, PyObject **cache);
+extern PyObject *py_rxgen_get_uint16(const void *_array, size_t n, PyObject **cache);
+extern PyObject *py_rxgen_get_uint32(const void *_array, size_t n, PyObject **cache);
+
+extern int py_rxgen_premarshal_uint8(void *_array, size_t n, PyObject *cache);
+extern int py_rxgen_premarshal_uint16(void *_array, size_t n, PyObject *cache);
+extern int py_rxgen_premarshal_uint32(void *_array, size_t n, PyObject *cache);
+
+/*
+ * Embedded struct array handling
+ */
+extern PyObject *py_rxgen_get_structs(const void *data, size_t num, size_t size,
+ PyObject **cache,
+ PyObject *(*data_to_type)(const void *elem));
+extern int py_rxgen_premarshal_structs(void *array, size_t n, size_t size, size_t offs,
+ PyObject *cache,
+ int (*premarshal)(PyObject *object));
#endif /* _PY_RXGEN_H */
%#ifndef _AFSUUID_COMMON_
%#define _AFSUUID_COMMON_
-#ifndef AFSUUID_GENERATE
-#define AFSUUID_GENERATE __attribute__((__nogenerate__))
-#endif
-
struct afsUUID {
uint32_t time_low;
uint16_t time_mid;
uint8_t clock_seq_hi_and_reserved;
uint8_t clock_seq_low;
uint8_t node[6];
-} AFSUUID_GENERATE;
+};
%#endif /* _AFSUUID_COMMON_ */
#include "common.h"
+const VL_PORT = 7003; /* volume location service port */
+const VL_SERVICE = 52; /* RxRPC service ID for the Volume Location service */
+
/*
* Structures and defines for vldb data
*/
#define _RXGEN_H
#include "af_rxrpc.h"
+#include "circ_buf.h"
typedef uint32_t net_xdr_t;
int got_eor;
int error_code;
uint32_t abort_code;
- unsigned reply_buf_size;
- unsigned reply_size;
- net_xdr_t *reply;
+ int phase;
+ unsigned need_size;
+ unsigned need_bulk_count;
+ unsigned item_per_buf;
+ unsigned bulk_index;
+
+ /* Circular buffer holding received data (power-of-two size) */
+ unsigned head;
+ unsigned tail;
+ unsigned size;
+ net_xdr_t reply[];
};
+static inline size_t rxgen_call_buffer_space_to_end(struct rx_call *call)
+{
+ return CIRC_SPACE_TO_END(call->head, call->tail, call->size);
+}
+
extern struct rx_connection *rx_new_connection(const struct sockaddr *sa,
socklen_t salen,
uint16_t service,
extern int rxrpc_send_request(struct rx_connection *z_conn,
struct rx_call *call,
- const net_xdr_t *request,
- size_t request_size,
- size_t reply_buf_size);
+ struct iovec *request,
+ int request_ioc);
extern int rxrpc_wait_for_sync_reply(struct rx_connection *z_conn,
struct rx_call *call);
# 2 of the Licence, or (at your option) any later version.
#
+###############################################################################
+#
+# Emit structure encoders and decoders predeclarations
+#
+###############################################################################
+sub emit_struct_encdec_decls ($) {
+ my ($struct) = @_;
+
+ print RXOUT "/* ", $struct->{type}, " XDR size ", $struct->{xdr_size}, " */\n"
+}
+
###############################################################################
#
# Emit structure encoders and decoders
#
###############################################################################
-sub emit_struct_encdec ($@) {
- my ($struct, @members) = @_;
+sub emit_struct_encdec ($) {
+ my ($struct) = @_;
# Dump the banner comment block
+ print RXHDR "\n";
+ print RXHDR @{$struct->{banner}};
print RXOUT "\n";
- print RXOUT @{shift @members};
+ print RXOUT @{$struct->{banner}};
+
+ # Write out a C structure definition for this type
+ print RXHDR "struct ", $struct->{type}, " {\n";
+ foreach my $m (@{$struct->{members}}) {
+ if ($m->{class} eq "basic") {
+ print RXHDR "\t", $m->{type}, "\t", $m->{name};
+ } elsif ($m->{class} eq "struct") {
+ print RXHDR "\tstruct ", $m->{type}, "\t", $m->{name};
+ } elsif ($m->{class} eq "array") {
+ if ($m->{elem}->{class} eq "basic") {
+ print RXHDR "\t", $m->{elem}->{type}, "\t", $m->{name}, "[", $m->{dim}, "]";
+ } else {
+ print RXHDR "\tstruct ", $m->{elem}->{type}, "\t", $m->{name}, "[", $m->{dim}, "]";
+ }
+ } else {
+ die $m->{where}, ": Unsupported type class '", $m->{class}, "'\n";
+ }
+ print RXHDR ";\n";
+ }
+ print RXHDR "};\n";
# Write an encoding function
- print RXOUT "static net_xdr_t *rxgen_encode_", $struct, "(net_xdr_t *xdr, const struct $struct *p)\n";
+ print RXOUT "static __attribute__((unused))\n";
+ print RXOUT "net_xdr_t *rxgen_encode_", $struct->{type}, "(net_xdr_t *xdr, const struct ", $struct->{type}, " *p)\n";
print RXOUT "{\n";
- foreach my $m (@members) {
- my ($type, $name, $array_size, $max_size) = @{$m};
- if ($array_size != -1) {
+ foreach my $m (@{$struct->{members}}) {
+ if ($m->{class} eq "array") {
print RXOUT "\tint i;\n\n";
last;
}
}
- foreach my $m (@members) {
- my ($type, $name, $array_size, $max_size) = @{$m};
- if ($array_size != -1) {
- print RXOUT "\tfor (i = 0; i < ", $array_size, "; i++)\n";
- print RXOUT "\t\t*xdr++ = htonl(p->", $name, "[i]);\n";
+ foreach my $m (@{$struct->{members}}) {
+ if ($m->{class} eq "basic") {
+ if ($m->{type} !~ /64/) {
+ print RXOUT "\t*xdr++ = htonl(p->", $m->{name}, ");\n";
+ } else {
+ die $m->{where}, ": No encoding for type '", $m->{type}, "'";
+ }
+ } elsif ($m->{class} eq "struct") {
+ print RXOUT "\txdr = rxgen_encode_", $m->{type}, "(xdr, &p->", $m->{name}, ");\n";
+ } elsif ($m->{class} eq "array") {
+ print RXOUT "\tfor (i = 0; i < ", $m->{dim}, "; i++)\n";
+ if ($m->{elem}->{class} eq "basic" && $m->{elem}->{type} !~ /64/) {
+ print RXOUT "\t\t*xdr++ = htonl(p->", $m->{name}, "[i]);\n";
+ } elsif ($m->{elem}->{class} eq "struct") {
+ print RXOUT "\t\txdr = rxgen_encode_", $m->{elem}->{type},
+ "(xdr, &p->", $m->{name}, "[i]);\n";
+ } else {
+ die $m->{where}, ": No encoding for array type '", $m->{elem}->{type}, "'";
+ }
} else {
- print RXOUT "\t*xdr++ = htonl(p->", $name, ");\n";
+ die $m->{where}, "No encoding for type class '$class'";
}
}
print RXOUT "\n";
# Write a decoding function
- print RXOUT "static const net_xdr_t *rxgen_decode_", $struct, "(struct $struct *p, const net_xdr_t *xdr)\n";
+ print RXOUT "static __attribute__((unused))\n";
+ print RXOUT "unsigned rxgen_decode_", $struct->{type}, "(struct ", $struct->{type}, " *p, const net_xdr_t *xdr, unsigned tail, unsigned mask)\n";
print RXOUT "{\n";
- foreach my $m (@members) {
- my ($type, $name, $array_size, $max_size) = @{$m};
- if ($array_size != -1) {
+ foreach my $m (@{$struct->{members}}) {
+ if ($m->{class} eq "array") {
print RXOUT "\tint i;\n\n";
last;
}
}
- foreach my $m (@members) {
- my ($type, $name, $array_size, $max_size) = @{$m};
- if ($array_size != -1) {
- print RXOUT "\tfor (i = 0; i < ", $array_size, "; i++)\n";
- print RXOUT "\t\tp->", $name, "[i] = ntohl(*xdr++);\n";
+ foreach my $m (@{$struct->{members}}) {
+ if ($m->{class} eq "basic") {
+ if ($m->{type} !~ /64/) {
+ print RXOUT "\tp->", $m->{name}, " = ntohl(xdr[tail++ & mask]);\n";
+ } else {
+ die $m->{where}, "No decoding for type '$type'";
+ }
+ } elsif ($m->{class} eq "struct") {
+ print RXOUT "\ttail = rxgen_decode_", $m->{type}, "(&p->", $m->{name}, ", xdr, tail, mask);\n";
+ } elsif ($m->{class} eq "array") {
+ print RXOUT "\tfor (i = 0; i < ", $m->{dim}, "; i++)\n";
+ if ($m->{elem}->{class} eq "basic" && $m->{elem}->{type} !~ /64/) {
+ print RXOUT "\t\tp->", $m->{name}, "[i] = ntohl(xdr[tail++ & mask]);\n";
+ } elsif ($m->{elem}->{class} eq "struct") {
+ print RXOUT "\t\ttail = rxgen_decode_", $m->{elem}->{type}, "(&p->", $m->{name}, "[i], xdr, tail, mask);\n";
+ } else {
+ die $m->{where}, "No decoding for array type '$type'";
+ }
} else {
- print RXOUT "\tp->", $name, " = ntohl(*xdr++);\n";
+ die $m->{where}, "No decoding for type class '$class'";
}
}
- print RXOUT "\treturn xdr;\n";
+ print RXOUT "\treturn tail;\n";
print RXOUT "}\n";
- print RXOUT "\n";
- print RXOUT "/* XDR size ", $struct_sizes{$struct}, " */\n"
}
1;
# 2 of the Licence, or (at your option) any later version.
#
+###############################################################################
+#
+# Calculate the C function prototypes
+#
+###############################################################################
+sub calc_func_prototype($)
+{
+ my ($func) = @_;
+
+ # Function prototype lists (we add commas and the closing bracket later)
+ my @protos = ( "int " . $func->{name} . "(\n" );
+ my @send_protos = ( "int rxgen_send_request_" . $func->{name} . "(\n" );
+ my @recv_protos = ( "int rxgen_decode_reply_" . $func->{name} . "(\n" );
+ push @protos, "\tstruct rx_connection *z_conn";
+ push @send_protos, "\tstruct rx_connection *z_conn";
+ push @send_protos, "\tstruct rx_call *call";
+ push @recv_protos, "\tstruct rx_connection *z_conn";
+ push @recv_protos, "\tstruct rx_call *call";
+
+ # Arguments to pass when sending a call or processing a reply
+ my @send_args = ();
+ my @recv_args = ();
+
+ foreach my $p (@{$func->{params}}) {
+ my @lines = ();
+ my @args = ();
+
+ $proto = "\t /*" . $p->{dir} . "*/ ";
+ if ($p->{class} eq "array") {
+ die $p->{where}, ": Array arg not supported";
+ } elsif ($p->{class} eq "bulk" &&
+ !($p->{elem}->{class} eq "string" ||
+ $p->{elem}->{class} eq "opaque")
+ ) {
+ if ($p->{dir} eq "OUT") {
+ if ($p->{elem}->{class} eq "struct") {
+ $proto .= "int (*alloc__" . $p->{name} . ")(void *token, int index, ";
+ $proto .= "struct " . $p->{type} . " **p_object)";
+ push @args, "alloc__" . $p->{name};
+ } else {
+ $proto .= "int (*store__" . $p->{name} . ")(void *token, int index, ";
+ $proto .= $p->{type} . " *value)";
+ push @args, "store__" . $p->{name};
+ }
+ push @lines, $proto;
+ $proto = "\t\t void *token__" . $p->{name};
+ push @args, "token__" . $p->{name};
+ } else {
+ if ($p->{elem}->{class} eq "struct") {
+ $proto .= "int (*get__" . $p->{name} . ")(void *token, int index, ";
+ $proto .= "const struct " . $p->{type} . " **object)";
+ } else {
+ $proto .= "int (*get__" . $p->{name} . ")(void *token, int index, ";
+ $proto .= $p->{type} . " *object)";
+ }
+ push @lines, $proto;
+ $proto = "\t\tvoid *token__" . $p->{name};
+ push @lines, $proto;
+ $proto = "\t\tsize_t nr__" . $p->{name};
+ push @args, "get__" . $p->{name}, "token__" . $p->{name};
+ push @args, "nr__" . $p->{name};
+ }
+ } else {
+ if ($p->{class} eq "bulk" && $p->{elem}->{class} ne "string") {
+ $proto .= "size_t nr_" . $p->{name} . ", ";
+ push @args, "nr__" . $p->{name};
+ }
+ $proto .= "const " if ($p->{dir} eq "IN" && $p->{class} ne "basic");
+ $proto .= "struct " if ($p->{class} eq "struct");
+ $proto .= $p->{type} . " " . $p->{ptr} . $p->{name};
+ push @args, $p->{name};
+ }
+
+ push @lines, $proto;
+ push @protos, @lines;
+ push @send_protos, @lines unless ($p->{dir} eq "OUT");
+ push @recv_protos, @lines unless ($p->{dir} eq "IN");
+ push @send_args, @args unless ($p->{dir} eq "OUT");
+ push @recv_args, @args unless ($p->{dir} eq "IN");
+ }
+
+ # Terminate each line with a comma, excepting the last, which we terminate
+ # with a closing bracket.
+ for (my $i = 1; $i < $#protos; $i++) {
+ $protos[$i] .= ",\n";
+ }
+ $protos[$#protos] .= ")";
+
+ for (my $i = 1; $i < $#send_protos; $i++) {
+ $send_protos[$i] .= ",\n";
+ }
+ $send_protos[$#send_protos] .= ")";
+
+ for (my $i = 1; $i < $#recv_protos; $i++) {
+ $recv_protos[$i] .= ",\n";
+ }
+ $recv_protos[$#recv_protos] .= ")";
+
+ $func->{protos} = \@protos;
+ $func->{send_protos} = \@send_protos;
+ $func->{recv_protos} = \@recv_protos;
+ $func->{send_args} = \@send_args;
+ $func->{recv_args} = \@recv_args;
+}
+
###############################################################################
#
# Emit a function to encode a request
#
###############################################################################
-sub emit_func_enc_request($$$$$@)
+sub emit_func_send_request($)
{
- my ($func, $op, $request_size, $req_has_charptr, $reply_size, @request) = @_;
+ my ($func) = @_;
- # Function definition and arguments
- print RXOUT "int rxgen_send_request_", $func, "(\n";
- print RXOUT "\tstruct rx_connection *z_conn,\n";
- print RXOUT "\tstruct rx_call *call";
- foreach my $p (@request) {
- my ($type, $name, $array_size, $max_size, $dir) = @{$p};
- print RXOUT ",\n\t";
- print RXOUT "const " if ($type =~ "[*]");
- print RXOUT "$type $name";
- die "Array arg not supported '$name'" if ($array_size != -1);
- }
- print RXOUT ")\n";
+ # Count up how many chunks we're going to need to send (iovec components)
+ # and how much XDR buffer size we're going to need.
+ my $xdr_bufsize = 0;
+ my $need_tmp = 0;
+ my @iovs = ();
+ my $iov = [ "buf + 0" ];
+ my $iov_size = 4;
+ foreach my $p (@{$func->{request}}) {
+ $iov = [ "buf + " . $xdr_bufsize / 4 ] if (!$iov);
- # Function body, beginning with local variables
+ $p->{enc_ioc} = $#iovs + 1;
+
+ if ($p->{class} eq "bulk") {
+ $iov_size += 4; # Element count
+ $xdr_bufsize += $iov_size;
+ push @{$iov}, "$iov_size";
+ $iov_size = 0;
+ push @iovs, $iov;
+ $iov = 0;
+
+ push @iovs, [ ($p->{elem}->{class} eq "string" ||
+ $p->{elem}->{class} eq "opaque") ? "(void *)" . $p->{name} : "NULL",
+ "nr__" . $p->{name} . " * " . $p->{xdr_size} ];
+ if ($p->{elem}->{xdr_size} & 3 != 0) {
+ # Allocate space to use as padding
+ $need_tmp = 1;
+ $xdr_bufsize += 4;
+ $iov = [ "buf + " . $xdr_bufsize / 4 ];
+ $iov_size = 0;
+ }
+ } else {
+ $iov_size += $p->{xdr_size};
+ }
+ }
+
+ if ($iov) {
+ $xdr_bufsize += $iov_size;
+ push @{$iov}, "$iov_size";
+ push @iovs, $iov;
+ }
+
+ die if ($#iovs < 0);
+
+ # Function definition and arguments
+ foreach $proto (@{$func->{send_protos}}) {
+ print RXOUT $proto;
+ }
+ print RXOUT "\n";
print RXOUT "{\n";
- if ($req_has_charptr) {
- print RXOUT "\tnet_xdr_t request[", $request_size / 4, " + 1], *xdr;\n";
- print RXOUT "\tuint32_t tmp;\n";
- } else {
- print RXOUT "\tnet_xdr_t request[", $request_size / 4, "], *xdr;\n";
+
+ my @bulk_params = ();
+ foreach my $p (@{$func->{request}}) {
+ if ($p->{class} eq "bulk" &&
+ $p->{elem}->{class} ne "string" &&
+ $p->{elem}->{class} ne "opaque"
+ ) {
+ push @bulk_params, $p;
+ }
+ }
+
+ # Local variables
+ foreach my $p (@{$func->{request}}) {
+ if ($p->{class} eq "bulk" && $p->{elem}->{class} eq "string") {
+ print RXOUT "\tsize_t nr__", $p->{name}, " = strlen(", $p->{name}, ");\n";
+ }
+ }
+ print RXOUT "\tnet_xdr_t buf[", $xdr_bufsize / 4, "];\n";
+ print RXOUT "\tstruct iovec iov[", $#iovs + 1, "] = {\n";
+ for my $iov (@iovs) {
+ print RXOUT "\t\t{ ", join(", ", @{$iov}), " },\n";
+ }
+ print RXOUT "\t};\n";
+
+ if ($func->{req_has_charptr} || @bulk_params) {
+ print RXOUT "\tsize_t tmp;\n";
+ }
+ print RXOUT "\tint ret;\n";
+
+ # If we have bulk data that isn't string/opaque, we need a buffer to encode into
+ if (@bulk_params) {
+ print RXOUT "\tsize_t bulk_size = 0;\n";
+ print RXOUT "\tvoid *bulk_buffer = NULL;\n";
+ print RXOUT "\tnet_xdr_t *xdr;\n";
+ print RXOUT "\n";
+ foreach my $p (@bulk_params) {
+ print RXOUT "\tbulk_size += nr__", $p->{name}, " * ", $p->{elem}->{xdr_size}, ";\n";
+ }
+
+ print RXOUT "\tif (bulk_size > 0) {\n";
+ print RXOUT "\t\tbulk_buffer = malloc(bulk_size);\n";
+ print RXOUT "\t\tif (!bulk_buffer)\n";
+ print RXOUT "\t\t\treturn -1;\n";
+
+ print RXOUT "\n";
+ print RXOUT "\t\tbulk_size = 0;\n";
+ foreach my $p (@bulk_params) {
+ print RXOUT "\t\tiov[", $p->{enc_ioc} + 1, "].iov_base = bulk_buffer + bulk_size;\n";
+ print RXOUT "\t\tbulk_size += nr__", $p->{name}, " * ", $p->{elem}->{xdr_size}, ";\n";
+ }
+
+ print RXOUT "\t}\n";
}
# Marshal the data
+ my $ix = 4;
+
print RXOUT "\n";
- print RXOUT "\txdr = request;\n";
- print RXOUT "\t*xdr++ = htonl($op);\n";
- foreach my $p (@request) {
- my ($type, $name, $array_size, $max_size, $dir) = @{$p};
- if ($type eq "uint8_t" ||
- $type eq "uint16_t" ||
- $type eq "uint32_t") {
- print RXOUT "\t*xdr++ = htonl($name);\n";
- } elsif ($type eq "char*") {
- print RXOUT "\ttmp = strlen($name);\n";
- print RXOUT "\t*xdr++ = htonl(tmp);\n";
- print RXOUT "\txdr[tmp / 4] = 0;\n";
- print RXOUT "\tmemcpy(xdr, $name, tmp);\n";
- print RXOUT "\txdr += (tmp + 3) / 4;\n";
- } elsif ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) {
- print RXOUT "\txdr = rxgen_encode_$1(xdr, $name);\n";
+ #print RXOUT "\txdr = request;\n";
+ print RXOUT "\tbuf[0] = htonl(", $func->{opcode}, ");\n";
+ foreach my $p (@{$func->{request}}) {
+ if ($p->{class} eq "basic" && $p->{type} !~ /64/) {
+ print RXOUT "\tbuf[", $ix/4, "] = htonl(", $p->{name}, ");\n";
+ $ix += 4;
+ } elsif ($p->{class} eq "basic" && $p->{type} =~ /64/) {
+ print RXOUT "\tbuf[", $ix/4, "] = htonl((unsigned long)", $p->{name}, ");\n";
+ $ix += 4;
+ print RXOUT "\tbuf[", $ix/4, "] = htonl((unsigned long)(", $p->{name}, " >> 32));\n";
+ $ix += 4;
+ } elsif ($p->{class} eq "struct") {
+ print RXOUT "\trxgen_encode_", $p->{type}, "(buf + ", $ix/4, ", ", $p->{name}, ");\n";
+ $ix += $p->{xdr_size};
+ } elsif ($p->{class} eq "bulk" && ($p->{elem}->{class} eq "string" ||
+ $p->{elem}->{class} eq "opaque")) {
+ if (exists $p->{dim}) {
+ print RXOUT "\tif (nr__", $p->{name}, " > ", $p->{dim}, ") {\n";
+ print RXOUT "\t\terrno = EINVAL;\n";
+ print RXOUT "\t\treturn -1;\n";
+ print RXOUT "\t};\n";
+ }
+ print RXOUT "\tbuf[", $ix/4, "] = htonl(nr__", $p->{name}, ");\n";
+ $ix += 4;
+ print RXOUT "\tbuf[", $ix/4, "] = 0; /* end-of-object padding */\n";
+ $ix += 4;
+ print RXOUT "\ttmp = (4 - (nr__", $p->{name}, " & 3)) & 3;\n";
+ print RXOUT "\tiov[", $p->{enc_ioc} + 2, "].iov_len += tmp;\n";
+ print RXOUT "\tiov[", $p->{enc_ioc} + 2, "].iov_base -= tmp;\n";
+ } elsif ($p->{class} eq "bulk") {
+ print RXOUT "\txdr = iov[", $p->{enc_ioc} + 1, "].iov_base;\n";
+ print RXOUT "\tfor (tmp = 0; tmp < nr__", $p->{name}, "; tmp++) {\n";
+ if ($p->{elem}->{class} eq "basic" && $p->{elem}->{type} !~ /64/) {
+ print RXOUT "\t\t", $p->{elem}->{type}, " x;\n";
+ print RXOUT "\t\tget__", $p->{name}, "(token__", $p->{name}, ", tmp, &x);\n";
+ print RXOUT "\t\t*xdr++ = htonl(x);\n";
+ } elsif ($p->{elem}->{class} eq "struct") {
+ print RXOUT "\t\txdr = rxgen_encode_", $p->{elem}->{type}, "(xdr, &p->", $p->{name}, "[i]);\n";
+ } else {
+ die $p->{where}, "No decoding for array type '$type'";
+ }
+ print RXOUT "\t}";
+ } else {
+ die $p->{where}, ": Unsupported param encoding";
}
}
# Send the message
print RXOUT "\n";
- print RXOUT "\treturn rxrpc_send_request(z_conn, call, request, (xdr - request) * 4, $reply_size);\n";
+ print RXOUT "\tret = rxrpc_send_request(z_conn, call, iov, ", $#iovs + 1, ");\n";
+ print RXOUT "\tfree(bulk_buffer);\n" if (@bulk_params);
+ print RXOUT "\treturn ret;\n";
print RXOUT "}\n";
}
###############################################################################
#
-# Emit a function to decode a reply
+# Emit a function to decode a reply in a way that can be used from asynchronous
+# code.
#
###############################################################################
-sub emit_func_dec_reply($$$@)
+sub emit_func_decode_reply($)
{
- my ($func, $op, $reply_size, @reply) = @_;
+ my ($func) = @_;
- print RXOUT "\n";
+ # We fetch the data in a number of phases. Each phase receives a chunk of
+ # data of a certain size. A phase's size might be dependent on a variable
+ # in the previous phase. Variable-sized bulk arrays are split across
+ # multiple phases, with the length being at the end of the first phase and
+ # the data in the second.
+ my @phases = ();
+ my $phase = 0;
+ my $buf_size = 16;
+ my $have_bulk = 0;
- # Function definition and arguments
- print RXOUT "void rxgen_decode_reply_", $func, "(\n";
- print RXOUT "\tstruct rx_connection *z_conn,\n";
- print RXOUT "\tstruct rx_call *call";
- foreach my $p (@reply) {
- my ($type, $name, $array_size, $max_size, $dir) = @{$p};
- print RXOUT ",\n\t";
- print RXOUT "$type $name";
- die "Array arg not supported '$name'" if ($array_size != -1);
+ foreach my $p (@{$func->{reply}}) {
+ unless ($phase) {
+ $phase = { type => "flat", size => 0, params => [] };
+ push @phases, $phase;
+ }
+
+ if ($p->{class} eq "basic" ||
+ $p->{class} eq "struct"
+ ) {
+ $p->{reply_offset} = $phase->{size};
+ $phase->{size} += $p->{xdr_size};
+ push @{$phase->{params}}, $p;
+ } elsif ($p->{class} eq "bulk") {
+ die if ($p->{elem}->{class} eq "string" ||
+ $p->{elem}->{class} eq "opaque");
+ $have_bulk = 1;
+
+ # Bulk objects begin with an element count
+ $p->{reply_offset} = $phase->{size};
+ $phase->{elem_count} = $phase->{size};
+ $phase->{size} += 4;
+
+ my %pseudoparam = (
+ class => "basic",
+ type => "bulk_size",
+ name => $p->{name},
+ elem => $p->{elem},
+ where => $p->{where},
+ xdr_size => $p->{xdr_size},
+ );
+ push @{$phase->{params}}, \%pseudoparam;
+
+ # Create a new phase
+ $phase = {
+ type => "bulk",
+ name => $p->{name},
+ params => [ $p ],
+ xdr_size => $p->{xdr_size},
+ };
+ push @phases, $phase;
+
+ # We don't want to be asking recvmsg() for one object at a time if
+ # they're really small.
+ my $n_buf = ($p->{xdr_size} < 1020) ? int(1020 / $p->{xdr_size}) : 1;
+ $n_buf *= $p->{xdr_size};
+ $buf_size = $n_buf if ($buf_size < $n_buf);
+ $phase->{size} = $p->{xdr_size};
+ $phase = 0;
+ } else {
+ die $p->{where}, "Reply array not supported";
+ }
}
- print RXOUT ")\n";
- # Function body, beginning with local variables
+ # Determine the size of the reply buffer. It has to be big enough to hold
+ # all of a flat phase or at least one element of a bulk variable array.
+ #
+ # We need to round up to the nearest power-of-2 so that the circular buffer
+ # algorithm can operate with bitwise-AND masking and we need to leave a
+ # blank slot so that the head and tail pointers don't collide when the
+ # buffer is full.
+ foreach my $phase (@phases) {
+ $buf_size = $phase->{size} if ($buf_size < $phase->{size});
+ }
+ $buf_size++;
+
+ my $i;
+ for ($i = 1; $i < $buf_size; $i *= 2) {
+ ;
+ }
+ $buf_size = $i;
+ $func->{call_buf_size} = $buf_size;
+
+ # Function definition and arguments
+ print RXOUT "\n";
+ foreach $proto (@{$func->{recv_protos}}) {
+ print RXOUT $proto;
+ }
+ print RXOUT "\n";
print RXOUT "{\n";
- print RXOUT "\tconst net_xdr_t *xdr;\n";
-
- # Unmarshal the data
- print RXOUT "\n";
- print RXOUT "\txdr = call->reply;\n";
- foreach my $p (@reply) {
- my ($type, $name, $array_size, $max_size, $dir) = @{$p};
- if ($type eq "int8_t*" ||
- $type eq "int16_t*" ||
- $type eq "int32_t*" ||
- $type eq "uint8_t*" ||
- $type eq "uint16_t*" ||
- $type eq "uint32_t*") {
- print RXOUT "\t*$name = ntohl(*xdr++);\n";
- } elsif ($type eq "int64_t*" ||
- $type eq "uint64_t*") {
- print RXOUT "\t*$name = (uint64_t)ntohl(*xdr++) << 32\n";
- print RXOUT "\t\t | (uint64_t)ntohl(*xdr++);\n";
- } elsif ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) {
- print RXOUT "\txdr = rxgen_decode_$1($name, xdr);\n";
+
+ # Local variables
+ print RXOUT "\tconst net_xdr_t *xdr = call->reply;\n";
+ print RXOUT "\tunsigned head = call->head / 4;\n";
+ print RXOUT "\tunsigned tail = call->tail / 4;\n";
+ print RXOUT "\tunsigned size = call->size / 4;\n";
+ print RXOUT "\tunsigned mask = size - 1;\n";
+
+ if ($have_bulk) {
+ print RXOUT "\tunion {\n";
+ foreach my $p (@{$func->{reply}}) {
+ if ($p->{class} eq "bulk") {
+ if ($p->{elem}->{class} eq "basic") {
+ print RXOUT "\t\t", $p->{type}, " ", $p->{name}, ";\n";
+ } else {
+ print RXOUT "\t\tstruct ", $p->{type}, " *", $p->{name}, ";\n";
+ }
+ }
+ }
+ print RXOUT "\t} bulk;\n";
+ }
+
+ # Deal with each phase
+ print RXOUT "\n";
+ print RXOUT "\tswitch (call->phase) {\n";
+
+ print RXOUT "\tcase 0:\n";
+
+ my $phase_goto_label = 0;
+ my $close_phase = 0;
+ my $phix;
+ for ($phix = 1; $phix <= $#phases + 1; $phix++) {
+ $phase = $phases[$phix - 1];
+ if ($phase_goto_label == $phix) {
+ print RXOUT "\tphase_", $phix, ":\n";
+ $phase_goto_label = 0;
+ }
+ print RXOUT "\t\tcall->need_size = ", $phase->{size}, ";\n"
+ unless ($phase->{type} eq "bulk");
+ print RXOUT "\t\tcall->phase = ", $phix, ";\n";
+ print RXOUT "\tcase ", $phix, ":\n";
+
+ print RXOUT "\t\tdo {\n";
+ $close_phase = 1;
+ print RXOUT "\t\t\tif (CIRC_CNT(head, tail, size) < ", $phase->{size}, " / 4)";
+ if ($phase->{type} eq "bulk") {
+ print RXOUT " {\n";
+ print RXOUT "\t\t\t\tcall->need_size = MIN(call->need_bulk_count, call->item_per_buf);\n";
+ print RXOUT "\t\t\t\tcall->need_size *= ", $phase->{xdr_size}, ";\n";
+ } else {
+ print RXOUT "\n";
}
+ print RXOUT "\t\t\t\tgoto need_more_data;\n";
+ print RXOUT "\t\t\t}" if ($phase->{type} eq "bulk");
+
+ # Unmarshal the data
+ print RXOUT "\n";
+ foreach my $p (@{$phase->{params}}) {
+ if ($p->{type} eq "bulk_size") {
+ print RXOUT "\t\t\tcall->need_bulk_count = ntohl(xdr[tail++ & mask]);\n";
+ print RXOUT "\t\t} while (0);\n" if ($close_phase);
+ $close_phase = 0;
+
+ if ($p->{elem}->{class} eq "basic") {
+ print RXOUT "\t\tif (store__", $p->{name}, "(token__", $p->{name}, ", call->need_bulk_count, NULL) < 0)\n";
+ } else {
+ print RXOUT "\t\tif (alloc__", $p->{name}, "(token__", $p->{name}, ", call->need_bulk_count, NULL) < 0)\n";
+ }
+ print RXOUT "\t\t\treturn -1;\n";
+ print RXOUT "\t\tif (call->need_bulk_count == 0)\n";
+ print RXOUT "\t\t\tgoto phase_", $phix + 2, ";\n";
+ $phase_goto_label = $phix + 2;
+ print RXOUT "\t\tcall->item_per_buf = size / (", $p->{xdr_size}, " / 4);\n";
+ print RXOUT "\t\tcall->bulk_index = 0;\n";
+ next;
+ }
+
+ if ($p->{class} eq "bulk" && $p->{elem}->{class} eq "basic") {
+ if ($p->{elem}->{xdr_size} == 4) {
+ print RXOUT "\t\t\tbulk.", $p->{name}, " = ntohl(xdr[tail++ & mask]);\n";
+ } elsif ($p->{elem}->{xdr_size} == 8) {
+ print RXOUT "\t\t\tbulk.", $p->{name}, " = (uint64_t)ntohl(xdr[tail++ & mask]) << 32\n";
+ print RXOUT "\t\t\t\t | (uint64_t)ntohl(xdr[tail++ & mask]);\n";
+ } else {
+ die;
+ }
+ print RXOUT "\t\t\tif (store__", $p->{name}, "(token__", $p->{name}, ", call->bulk_index++, &bulk.", $p->{name}, ") < 0)\n";
+ print RXOUT "\t\t\t\treturn -1;\n";
+
+ } elsif ($p->{class} eq "bulk" && $p->{elem}->{class} eq "struct") {
+ print RXOUT "\t\t\tif (alloc__", $p->{name}, "(token__", $p->{name}, ", call->bulk_index++, &bulk.", $p->{name}, ") < 0)\n";
+ print RXOUT "\t\t\t\treturn -1;\n";
+ print RXOUT "\t\t\ttail = rxgen_decode_", $p->{type}, "(bulk.", $p->{name}, ", xdr, tail, mask);\n";
+ } elsif ($p->{class} eq "basic" && $p->{xdr_size} == 4) {
+ print RXOUT "\t\t\t*", $p->{name}, " = ntohl(xdr[tail++ & mask]);\n";
+ } elsif ($p->{class} eq "basic" && $p->{xdr_size} == 8) {
+ print RXOUT "\t\t\t*", $p->{name}, " = (uint64_t)ntohl(xdr[tail++ & mask]) << 32\n";
+ print RXOUT "\t\t\t\t | (uint64_t)ntohl(xdr[tail++ & mask]);\n";
+ } elsif ($p->{class} eq "struct") {
+ print RXOUT "\t\t\ttail = rxgen_decode_", $p->{type}, "(", $p->{name}, ", xdr, tail, mask);\n";
+ } else {
+ die $p->{where}, ": Unsupported type in decode";
+ }
+
+ if ($p->{class} eq "bulk") {
+ print RXOUT "\t\t\tcall->need_bulk_count--;\n";
+ print RXOUT "\t\t} while (call->need_bulk_count > 0);\n";
+ $close_phase = 0;
+ }
+ }
+
+ print RXOUT "\t\t} while (0);\n" if ($close_phase);
}
+ if ($phase_goto_label == $phix) {
+ print RXOUT "\tphase_", $phix, ":\n";
+ $phase_goto_label = 0;
+ }
+ print RXOUT "\t\tcall->phase = ", $phix, ";\n";
+ print RXOUT "\tcase ", $phix, ":\n";
+ print RXOUT "\t\tif (!call->got_eor) {\n";
+ print RXOUT "\t\t\ttail = head;\n";
+ print RXOUT "\t\t\tcall->need_size = size - 1;\n";
+ print RXOUT "\t\t\tgoto need_more_data_2;\n";
+ print RXOUT "\t\t}\n";
+ print RXOUT "\t\tbreak;\n";
+ print RXOUT "\t}\n";
+
+ print RXOUT "\n";
+ print RXOUT "\tcall->tail = tail * 4;\n";
+ print RXOUT "\treturn 0;\n";
+
+ print RXOUT "\n";
+ print RXOUT "need_more_data:\n";
+ print RXOUT "\tif (call->got_eor) {\n";
+ print RXOUT "\t\terrno = EMSGSIZE;\n";
+ print RXOUT "\t\treturn -1;\n";
+ print RXOUT "\t}\n";
+ print RXOUT "need_more_data_2:\n";
+ print RXOUT "\tcall->tail = tail;\n";
+ print RXOUT "\treturn 1;\n";
+
print RXOUT "}\n";
}
###############################################################################
#
-# Emit a function to make a simple synchronous call
+# Emit a dummy function to decode a replyless reply in a way that can be used
+# from asynchronous code.
+#
+###############################################################################
+sub emit_func_dummy_decode_reply($)
+{
+ my ($func) = @_;
+
+ # Function definition and arguments
+ print RXOUT "\n";
+ foreach $proto (@{$func->{recv_protos}}) {
+ print RXOUT $proto;
+ }
+ print RXOUT "\n";
+ print RXOUT "{\n";
+ print RXOUT "\tcall->tail = call->head;\n";
+ print RXOUT "\tcall->need_size = call->size - 1;\n";
+ print RXOUT "\treturn call->got_eor ? 0 : 1;\n";
+
+ print RXOUT "}\n";
+}
+
+###############################################################################
+#
+# Emit a function to allocate a call struct with appropriately sized bufferage.
#
###############################################################################
-sub emit_func_simple_sync_call($$$$$@)
+sub emit_func_alloc_call($)
{
- my ($func, $request_size, $reply_size, $_request, $_reply, @params) = @_;
- my @request = @{$_request};
- my @reply = @{$_reply};
+ my ($func) = @_;
+
+ my $buf_size = 16;
+
+ $buf_size = $func->{call_buf_size} if (exists $func->{call_buf_size});
+ # Emit a function to allocate an rxrpc_call struct for this call
print RXOUT "\n";
+ print RXOUT "struct rx_call *rxgen_alloc_call_", $func->{name}, "(void)\n";
+ print RXOUT "{\n";
+ print RXOUT "\tstruct rx_call *call = malloc(sizeof(*call) + ", $buf_size, ");\n";
+ print RXOUT "\tif (call) {\n";
+ print RXOUT "\t\tmemset(call, 0, sizeof(*call));\n";
+ print RXOUT "\t\tcall->size = ", $buf_size, ";\n";
+ print RXOUT "\t}\n";
+ print RXOUT "\treturn call;\n";
+ print RXOUT "}\n";
+}
+
+###############################################################################
+#
+# Emit a function to make a simple synchronous call
+#
+###############################################################################
+sub emit_func_simple_sync_call($)
+{
+ my ($func) = @_;
+
+ # Function declaration
+ print RXHDR "\n";
+ print RXHDR "extern ";
+ foreach $proto (@{$func->{protos}}) {
+ print RXHDR $proto;
+ }
+ print RXHDR ";\n";
# Function definition and arguments
- print RXOUT "int ", $func, "(\n";
- print RXOUT "\tstruct rx_connection *z_conn";
- foreach my $p (@params) {
- my ($type, $name, $array_size, $max_size, $dir) = @{$p};
- print RXOUT ",\n\t";
- print RXOUT "const " if ($type =~ "[*]" && $dir eq "IN");
- print RXOUT "$type $name";
- die "Array arg not supported '$name'" if ($array_size != -1);
+ print RXOUT "\n";
+ foreach $proto (@{$func->{protos}}) {
+ print RXOUT $proto;
}
- print RXOUT ")\n";
+ print RXOUT "\n";
# Function body, beginning with local variables
print RXOUT "{\n";
print RXOUT "\n";
# Allocate a call record and reply buffer
- print RXOUT "\tcall = malloc(sizeof(*call) + $reply_size);\n";
+ print RXOUT "\tcall = rxgen_alloc_call_", $func->{name}, "();\n";
print RXOUT "\tif (!call)\n";
print RXOUT "\t\treturn -1;\n";
- print RXOUT "\tcall->reply = (void *)call + sizeof(*call);\n";
print RXOUT "\n";
# Send the request
- print RXOUT "\tret = rxgen_send_request_", $func, "(";
+ print RXOUT "\tret = rxgen_send_request_", $func->{name}, "(";
print RXOUT "z_conn, call";
- foreach my $p (@request) {
- my ($type, $name, $array_size, $max_size, $dir) = @{$p};
- print RXOUT ", $name";
+ foreach (@{$func->{send_args}}) {
+ print RXOUT ", ", $_;
}
print RXOUT ");\n";
print RXOUT "\tif (ret != 0) {\n";
print RXOUT "\t\treturn ret;\n";
print RXOUT "\t}\n";
- # Wait for the reply
- print RXOUT "\tret = rxrpc_wait_for_sync_reply(z_conn, call);\n";
- print RXOUT "\tif (ret != 0) {\n";
- print RXOUT "\t\tfree(call);\n";
- print RXOUT "\t\treturn ret;\n";
- print RXOUT "\t}\n";
- print RXOUT "\n";
-
- # Unmarshal the reply
- if (@reply) {
- print RXOUT "\trxgen_decode_reply_", $func, "(";
- print RXOUT "z_conn, call";
- foreach my $p (@reply) {
- my ($type, $name, $array_size, $max_size, $dir) = @{$p};
- print RXOUT ", $name";
- }
- print RXOUT ");\n";
+ # Set up the reply buffer and try to parse the reply as it's received
+ print RXOUT "\tfor (;;) {\n";
+
+ print RXOUT "\t\tret = rxgen_decode_reply_", $func->{name}, "(z_conn, call";
+ foreach my $a (@{$func->{recv_args}}) {
+ print RXOUT ", ", $a;
}
+ print RXOUT ");\n";
+ print RXOUT "\t\tif (ret != 1)\n";
+ print RXOUT "\t\t\tbreak;\n";
+
+ # Receive reply data
+ print RXOUT "\t\tret = rxrpc_wait_for_sync_reply(z_conn, call);\n";
+ print RXOUT "\t\tif (ret != 0)\n";
+ print RXOUT "\t\t\tbreak;\n";
+ print RXOUT "\t}\n";
print RXOUT "\n";
- print RXOUT "\treturn 0;\n";
+ print RXOUT "\tfree(call);\n";
+ print RXOUT "\treturn ret;\n";
print RXOUT "}\n";
}
print PYOUT " */\n";
print PYOUT "static PyMethodDef module_methods[] = {\n";
- foreach my $s (@structs) {
- my $struct = @{$s}[0];
- print PYOUT "\t{\"new_$struct\", (PyCFunction)kafs_new_py_$struct, METH_NOARGS,\n";
- print PYOUT "\t \"Create a new $struct record.\"\n";
+ foreach my $struct (@structs) {
+ print PYOUT "\t{\"new_", $struct->{type}, "\", (PyCFunction)kafs_new_py_", $struct->{type}, ", METH_NOARGS,\n";
+ print PYOUT "\t \"Create a new ", $struct->{type}, " record.\"\n";
print PYOUT "\t},\n";
}
- foreach $func (sort keys %funcs) {
- my @params = @{$funcs{$func}};
- print PYOUT "\t{\"$func\", (PyCFunction)kafs_$func, METH_VARARGS, \"\" },\n";
+ foreach my $funcname (sort keys %func_names) {
+ my $func = $func_names{$funcname};
+ print PYOUT "\t{\"", $func->{name}, "\", (PyCFunction)kafs_", $func->{name}, ", METH_VARARGS, \"\" },\n";
}
print PYOUT "\t{\"rx_new_connection\", (PyCFunction)kafs_py_rx_new_connection, METH_VARARGS,\n";
print PYOUT "\tif (";
print PYOUT "PyType_Ready(&py_rx_connectionType) < 0";
my $first = 0;
- foreach my $s (@structs) {
- my @members = @{$s};
- my $struct = $members[0];
+ foreach my $struct (@structs) {
print PYOUT " ||\n\t " unless ($first);
- print PYOUT "PyType_Ready(&py_", $struct, "Type) < 0";
+ print PYOUT "PyType_Ready(&py_", $struct->{type}, "Type) < 0";
$first = 0;
}
print PYOUT ")\n";
if (@structs) {
print PYOUT "\n";
- foreach my $s (@structs) {
- my @members = @{$s};
- my $struct = $members[0];
- print PYOUT "\tPy_INCREF(&py_", $struct, "Type);\n";
- print PYOUT "\tPyModule_AddObject(m, \"$struct\", (PyObject *)&py_", $struct, "Type);\n";
+ foreach my $struct (@structs) {
+ print PYOUT "\tPy_INCREF(&py_", $struct->{type}, "Type);\n";
+ print PYOUT "\tPyModule_AddObject(m, \"", $struct->{type}, "\", (PyObject *)&py_", $struct->{type}, "Type);\n";
}
print PYOUT "\n";
# 2 of the Licence, or (at your option) any later version.
#
+my %bulk_get_helpers = ();
+my %bulk_set_helpers = ();
+
+###############################################################################
+#
+# Emit functions to help deal with bulk lists
+#
+###############################################################################
+sub emit_py_func_bulk_helper($)
+{
+ my ($func) = @_;
+
+ foreach my $p (@{$func->{params}}) {
+ next if ($p->{class} ne "bulk");
+ next if ($p->{elem}->{class} eq "string" || $p->{elem}->{class} eq "opaque");
+
+ # Data transmission
+ if ($p->{dir} eq "IN" && !exists $bulk_get_helpers{$p->{type}}) {
+ $bulk_get_helpers{$p->{type}} = 1;
+
+ print PYOUT "\n";
+ print PYOUT "static int py_get__", $p->{type}, "(";
+ if ($p->{elem}->{class} eq "basic") {
+ print PYOUT "void *token, int index, ", $p->{type}, " *object)\n";
+ } elsif ($p->{elem}->{class} eq "struct") {
+ print PYOUT "void *token, int index, ", $p->{type}, " **object)\n";
+ } else {
+ die $p->{where}, ": Unsupported type for bulk helper";
+ }
+
+ print PYOUT "{\n";
+ print PYOUT "\tPyObject *list = token;\n";
+ print PYOUT "\tPyObject *item;\n";
+ print PYOUT "\n";
+ print PYOUT "\titem = PyList_GetItem(list, index);\n";
+ print PYOUT "\tif (!item)\n";
+ print PYOUT "\t\treturn -1;\n";
+
+ print PYOUT "\n";
+ if ($p->{elem}->{class} eq "basic") {
+ print PYOUT "\tif (!PyLong_Check(item)) {\n";
+ print PYOUT "\t\tPyErr_SetString(PyExc_TypeError, \"Expected list of ", $p->{type}, "\");\n";
+ print PYOUT "\t\treturn -1;\n";
+ print PYOUT "\t}\n";
+ } else {
+ print PYOUT "\tif (py_premarshal_", $p->{type}, "(item))\n";
+ print PYOUT "\t\treturn -1;\n";
+ }
+
+ if ($p->{elem}->{class} eq "basic") {
+ if ($p->{elem}->{type} eq "int64_t") {
+ print PYOUT "\t*object = PyLong_AsLongLong(item);\n";
+ } elsif ($p->{elem}->{type} eq "uint64_t") {
+ print PYOUT "\t*object = PyLong_AsUnsignedLongLong(item);\n";
+ } elsif ($p->{elem}->{type} =~ /^int/) {
+ print PYOUT "\t*object = PyLong_AsLong(item);\n";
+ } elsif ($p->{elem}->{type} =~ /^uint|^char/) {
+ print PYOUT "\t*object = PyLong_AsUnsignedLong(item);\n";
+ }
+ } else {
+ print PYOUT "\t*object = &((struct py_", $p->{type}, " *)item)->x;\n";
+ }
+ print PYOUT "\treturn 0;\n";
+ print PYOUT "}\n";
+ }
+
+ # Data reception
+ if ($p->{dir} eq "OUT" && !exists $bulk_set_helpers{$p->{type}}) {
+ $bulk_set_helpers{$p->{type}} = 1;
+
+ print PYOUT "\n";
+ if ($p->{elem}->{class} eq "basic") {
+ print PYOUT "static int py_store__", $p->{type}, "(";
+ print PYOUT "void *token, int index, ", $p->{type}, " *object)\n";
+ } elsif ($p->{elem}->{class} eq "struct") {
+ print PYOUT "static int py_alloc__", $p->{type}, "(";
+ print PYOUT "void *token, int index, struct ", $p->{type}, " **object)\n";
+ } else {
+ die $p->{where}, ": Unsupported type for bulk helper";
+ }
+
+ print PYOUT "{\n";
+ print PYOUT "\tPyObject *list = token;\n";
+ print PYOUT "\tPyObject *item;\n";
+
+ # Bulk array size indication if !object
+ print PYOUT "\n";
+ print PYOUT "\tif (!object)\n";
+ print PYOUT "\t\treturn 0;\n";
+
+ print PYOUT "\n";
+ if ($p->{elem}->{class} eq "basic") {
+ if ($p->{elem}->{type} eq "int64_t") {
+ print PYOUT "\titem = PyLong_FromLongLong(*object);\n";
+ } elsif ($p->{elem}->{type} eq "uint64_t") {
+ print PYOUT "\titem = PyLong_FromUnsignedLongLong(*object);\n";
+ } elsif ($p->{elem}->{type} =~ /^int/) {
+ print PYOUT "\titem = PyLong_FromLong(*object);\n";
+ } elsif ($p->{elem}->{type} =~ /^uint|^char/) {
+ print PYOUT "\titem = PyLong_FromUnsignedLong(*object);\n";
+ }
+ } else {
+ print PYOUT "\titem = kafs_new_py_", $p->{type}, "(NULL, NULL);\n";
+ }
+ print PYOUT "\tif (!item)\n";
+ print PYOUT "\t\treturn -1;\n";
+
+ print PYOUT "\n";
+ print PYOUT "\tif (PyList_Insert(list, index, item) < 0) {\n";
+ print PYOUT "\t\tPy_DECREF(item);\n";
+ print PYOUT "\t\treturn -1;\n";
+ print PYOUT "\t}\n";
+
+ if ($p->{elem}->{class} eq "struct") {
+ print PYOUT "\n";
+ print PYOUT "\t*object = &((struct py_", $p->{type}, " *)item)->x;\n";
+ }
+
+ print PYOUT "\treturn 0;\n";
+ print PYOUT "}\n";
+ }
+ }
+}
+
###############################################################################
#
# Emit a python wrapper function to make a simple synchronous call
#
###############################################################################
-sub emit_py_func_simple_sync_call($$$@)
+sub emit_py_func_simple_sync_call($)
{
- my ($func, $_request, $_reply, @params) = @_;
- my @request = @{$_request};
- my @reply = @{$_reply};
+ my ($func) = @_;
+ print PYOUT "\n";
print PYOUT "PyObject *\n";
- print PYOUT "kafs_", $func, "(PyObject *_self, PyObject *args)\n";
+ print PYOUT "kafs_", $func->{name}, "(PyObject *_self, PyObject *args)\n";
print PYOUT "{\n";
- # Declare parameter variables
+ # Local variable declarations representing parameters to send
my $need_tmp = 0;
print PYOUT "\tstruct py_rx_connection *z_conn;\n";
- foreach my $p (@params) {
- my ($type, $name, $array_size, $max_size, $dir) = @{$p};
- if ($type eq "char*") {
- die "String output args not supported" unless ($dir eq "IN");
- print PYOUT "\tconst char *param_$name;\n";
- } elsif ($type eq "int8_t" || $type eq "int8_t*" ||
- $type eq "int16_t" || $type eq "int16_t*" ||
- $type eq "int32_t" || $type eq "int32_t*" ||
- $type eq "int64_t" || $type eq "int64_t*" ||
- $type eq "uint8_t" || $type eq "uint8_t*" ||
- $type eq "uint16_t" || $type eq "uint16_t*" ||
- $type eq "uint32_t" || $type eq "uint32_t*" ||
- $type eq "uint64_t" || $type eq "uint64_t*"
- ) {
- $type =~ s/[*]$//;
- $need_tmp = 1 unless ($dir eq "IN");
- print PYOUT "\t$type param_$name;\n";
- } elsif ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) {
- die "INOUT struct args not supported" if ($dir eq "INOUT");
- print PYOUT "\tstruct py_$1 *param_$name;\n";
+ foreach my $p (@{$func->{params}}) {
+ if ($p->{class} eq "bulk" && $p->{elem}->{class} eq "string") {
+ die $p->{where}, ": String output args not supported" unless ($p->{dir} eq "IN");
+ print PYOUT "\tconst char *param_", $p->{name}, ";\n";
+ } elsif ($p->{class} eq "basic") {
+ $need_tmp = 1 unless ($p->{dir} eq "IN");
+ print PYOUT "\t", $p->{type}, " param_", $p->{name}, ";\n";
+ } elsif ($p->{class} eq "struct") {
+ die $p->{where}, ": INOUT struct args not supported" if ($p->{dir} eq "INOUT");
+ print PYOUT "\tstruct py_", $p->{type}, " *param_", $p->{name}, ";\n";
+ } elsif ($p->{class} eq "bulk") {
+ die $p->{where}, ": INOUT bulk args not supported" if ($p->{dir} eq "INOUT");
+ print PYOUT "\tPyObject *param_", $p->{name}, ";\n"
+ unless ($p->{dir} eq "OUT");
} else {
- die "Unsupported type \"$type\"";
+ die $p->{where}, ": Unsupported type \"", $p->{type}, "\"";
}
}
# Replies are passed back into lists provided by the caller. INOUT variable
# input values must already occupy the lists.
- foreach my $p (@reply) {
- my ($type, $name, $array_size, $max_size, $dir) = @{$p};
- print PYOUT "\tPyObject *reply_$name;\n";
+ foreach my $p (@{$func->{reply}}) {
+ print PYOUT "\tPyObject *reply_", $p->{name}, ";\n";
}
- print PYOUT "\tPyObject *tmp;\n" if ($need_tmp);
+ print PYOUT "\tPyObject *tmp = NULL;\n" if ($need_tmp);
print PYOUT "\tPyObject *res = NULL;\n";
print PYOUT "\tint ret;\n";
print PYOUT "\n";
print PYOUT "\tif (!PyArg_ParseTuple(args, \"O!";
- foreach my $p (@params) {
- my ($type, $name, $array_size, $max_size, $dir) = @{$p};
- if ($dir ne "IN") {
- print PYOUT "O!";
- } elsif ($type eq "char*") {
+ foreach my $p (@{$func->{params}}) {
+ if ($p->{dir} ne "IN") { print PYOUT "O!";
+ } elsif ($p->{type} eq "int8_t") { print PYOUT "B";
+ } elsif ($p->{type} eq "int16_t") { print PYOUT "h";
+ } elsif ($p->{type} eq "int32_t") { print PYOUT "i";
+ } elsif ($p->{type} eq "int64_t") { print PYOUT "L";
+ } elsif ($p->{type} eq "uint8_t") { print PYOUT "b";
+ } elsif ($p->{type} eq "uint16_t") { print PYOUT "H";
+ } elsif ($p->{type} eq "uint32_t") { print PYOUT "I";
+ } elsif ($p->{type} eq "uint64_t") { print PYOUT "K";
+ } elsif ($p->{class} eq "struct") { print PYOUT "O!";
+ } elsif ($p->{class} eq "bulk" && $p->{elem}->{class} eq "string") {
print PYOUT "s";
- } elsif ($type eq "int8_t") {
- print PYOUT "B";
- } elsif ($type eq "int16_t") {
- print PYOUT "h";
- } elsif ($type eq "int32_t") {
- print PYOUT "i";
- } elsif ($type eq "int64_t") {
- print PYOUT "L";
- } elsif ($type eq "uint8_t") {
- print PYOUT "b";
- } elsif ($type eq "uint16_t") {
- print PYOUT "H";
- } elsif ($type eq "uint32_t") {
- print PYOUT "I";
- } elsif ($type eq "uint64_t") {
- print PYOUT "K";
- } elsif ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) {
- print PYOUT "O!";
+ } else {
+ die $p->{where}, ": No py parse for param";
}
}
print PYOUT "\",\n";
print PYOUT "\t\t\t &py_rx_connectionType, &z_conn";
- foreach my $p (@params) {
- my ($type, $name, $array_size, $max_size, $dir) = @{$p};
+ foreach my $p (@{$func->{params}}) {
print PYOUT ",\n";
- print PYOUT "\t\t\t /*$dir*/ ";
- if ($dir ne "IN") {
- print PYOUT "&PyList_Type, &reply_$name";
- } elsif ($type eq "char*" ||
- $type eq "int8_t" || $type eq "int8_t" ||
- $type eq "int16_t" || $type eq "int16_t" ||
- $type eq "int32_t" || $type eq "int32_t" ||
- $type eq "int64_t" || $type eq "int64_t" ||
- $type eq "uint8_t" || $type eq "uint8_t" ||
- $type eq "uint16_t" || $type eq "uint16_t" ||
- $type eq "uint32_t" || $type eq "uint32_t" ||
- $type eq "uint64_t" || $type eq "uint64_t") {
- print PYOUT "¶m_$name";
- } elsif ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) {
- print PYOUT "&py_", $1, "Type, ¶m_$name";
+ print PYOUT "\t\t\t /*", $p->{dir}, "*/ ";
+ if ($p->{dir} ne "IN") {
+ print PYOUT "&PyList_Type, &reply_", $p->{name};
+ } elsif ($p->{class} eq "bulk" && ($p->{elem}->{class} eq "string" ||
+ $p->{elem}->{class} eq "opaque") ||
+ $p->{class} eq "basic") {
+ print PYOUT "¶m_", $p->{name};
+ } elsif ($p->{class} eq "struct") {
+ print PYOUT "&py_", $p->{type}, "Type, ¶m_", $p->{name};
+ } elsif ($p->{class} eq "bulk") {
+ print PYOUT "&PyList_Type, ¶m_", $p->{name};
} else {
- die "Unsupported type \"$type\"";
+ die $p->{where}, ": Unsupported type \"", $p->{type}, "\"";
}
}
print PYOUT "))\n";
print PYOUT "\t\treturn NULL;\n";
# Allocate reply buffer objects
- if (@reply) {
+ if (@{$func->{reply}}) {
print PYOUT "\n";
- foreach my $p (@reply) {
- my ($type, $name, $array_size, $max_size, $dir) = @{$p};
- if ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) {
- print PYOUT "\tparam_$name = (struct py_$1 *)kafs_new_py_$1(NULL, NULL);\n";
- print PYOUT "\tif (!param_$name)\n";
- print PYOUT "\t\tgoto error_alloc_$name;\n";
+ foreach my $p (@{$func->{reply}}) {
+ if ($p->{class} eq "struct") {
+ print PYOUT "\tparam_", $p->{name}, " = (struct py_", $p->{type}, " *)kafs_new_py_", $p->{type}, "(NULL, NULL);\n";
+ print PYOUT "\tif (!param_", $p->{name}, ")\n";
+ print PYOUT "\t\tgoto error_alloc_", $p->{name}, ";\n";
}
}
}
# Make the call
print PYOUT "\n";
- print PYOUT "\tret = $func(\n";
+ print PYOUT "\tret = ", $func->{name}, "(\n";
print PYOUT "\t\tz_conn->x";
- foreach my $p (@params) {
+ foreach my $p (@{$func->{params}}) {
print PYOUT ",\n";
- my ($type, $name, $array_size, $max_size, $dir) = @{$p};
- if ($type eq "char*" ||
- $type eq "int8_t" || $type eq "int8_t*" ||
- $type eq "int16_t" || $type eq "int16_t*" ||
- $type eq "int32_t" || $type eq "int32_t*" ||
- $type eq "int64_t" || $type eq "int64_t*" ||
- $type eq "uint8_t" || $type eq "uint8_t*" ||
- $type eq "uint16_t" || $type eq "uint16_t*" ||
- $type eq "uint32_t" || $type eq "uint32_t*" ||
- $type eq "uint64_t" || $type eq "uint64_t*") {
- if ($dir eq "IN") {
- print PYOUT "\t\tparam_$name";
+ if ($p->{class} eq "bulk" && $p->{elem}->{class} eq "string" ||
+ $p->{class} eq "basic") {
+ if ($p->{dir} eq "IN") {
+ print PYOUT "\t\tparam_", $p->{name};
} else {
- print PYOUT "\t\t¶m_$name";
+ print PYOUT "\t\t¶m_", $p->{name};
+ }
+ } elsif ($p->{class} eq "struct") {
+ print PYOUT "\t\t¶m_", $p->{name}, "->x";
+ } elsif ($p->{class} eq "bulk") {
+ if ($p->{dir} eq "IN") {
+ print PYOUT "\t\tpy_get__", $p->{type}, ", param_", $p->{name};
+ print PYOUT ", PyList_Size(param_", $p->{name}, ")";
+ } elsif ($p->{elem}->{class} eq "basic") {
+ print PYOUT "\t\tpy_store__", $p->{type}, ", reply_", $p->{name};
+ } elsif ($p->{elem}->{class} eq "struct") {
+ print PYOUT "\t\tpy_alloc__", $p->{type}, ", reply_", $p->{name};
+ } else {
+ die;
}
- } elsif ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) {
- print PYOUT "\t\t¶m_$name->x";
} else {
- die "Unsupported type \"$type\"";
+ die $p->{where}, ": Unsupported type \"", $p->{type}, "\"";
}
}
print PYOUT ");\n";
print PYOUT "\t}\n";
# Pass back any replies
- if (@reply) {
+ if (@{$func->{reply}}) {
print PYOUT "\n";
- foreach my $p (@reply) {
- my ($type, $name, $array_size, $max_size, $dir) = @{$p};
-
+ foreach my $p (@{$func->{reply}}) {
my $set_null = 0;
my $var = "tmp";
- if ($type eq "int8_t" || $type eq "int8_t*" ||
- $type eq "int16_t" || $type eq "int16_t*" ||
- $type eq "int32_t" || $type eq "int32_t*") {
- print PYOUT "\ttmp = PyLong_FromLong(param_$name);\n";
- } elsif ($type eq "int64_t" || $type eq "int64_t*") {
- print PYOUT "\ttmp = PyLong_FromLongLong(param_$name);\n";
- } elsif ($type eq "uint8_t" || $type eq "uint8_t*" ||
- $type eq "uint16_t" || $type eq "uint16_t*" ||
- $type eq "uint32_t" || $type eq "uint32_t*") {
-
- print PYOUT "\ttmp = PyLong_FromUnsignedLong(param_$name);\n";
-
- } elsif ($type eq "uint64_t" || $type eq "uint64_t*") {
- print PYOUT "\ttmp = PyLong_FromUnsignedLongLong(param_$name);\n";
+ if ($p->{class} eq "basic") {
+ if ($p->{type} eq "int64_t") {
+ print PYOUT "\ttmp = PyLong_FromLongLong(param_", $p->{name}, ");\n";
+ } elsif ($p->{type} eq "uint64_t") {
+ print PYOUT "\ttmp = PyLong_FromUnsignedLongLong(param_", $p->{name}, ");\n";
+ } elsif ($p->{type} !~ /^u/) {
+ print PYOUT "\ttmp = PyLong_FromLong(param_", $p->{name}, ");\n";
+ } else {
+ print PYOUT "\ttmp = PyLong_FromUnsignedLong(param_", $p->{name}, ");\n";
+ }
- } elsif ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) {
- $var = "(PyObject *)param_$name";
+ } elsif ($p->{class} eq "struct") {
+ $var = "(PyObject *)param_" . $p->{name};
$set_null = 1;
+ } elsif ($p->{class} eq "bulk") {
+ # All done in the helper func
} else {
- die "Unsupported type \"$type\"";
+ die $p->{where}, ": Unsupported class \"", $p->{class}, "\"";
}
if ($var eq "tmp") {
print PYOUT "\t\tgoto error;\n";
}
- print PYOUT "\tif (PyList_Insert(reply_$name, 0, $var) == -1)\n";
+ print PYOUT "\tif (PyList_Insert(reply_", $p->{name}, ", 0, ", $var, ") == -1)\n";
print PYOUT "\t\tgoto error", $need_tmp ? "_tmp" : "", ";\n";
- print PYOUT "\tparam_$name = NULL;\n" if ($set_null);
+ print PYOUT "\tparam_", $p->{name}, " = NULL;\n" if ($set_null);
}
}
print PYOUT "\tPy_DECREF(tmp);\n";
}
print PYOUT "error:\n";
- if (@reply) {
- foreach my $p (reverse @reply) {
- my ($type, $name, $array_size, $max_size, $dir) = @{$p};
- if ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) {
- print PYOUT "\tPy_XDECREF(param_$name);\n";
- print PYOUT "error_alloc_$name:\n";
+ if (@{$func->{reply}}) {
+ foreach my $p (reverse @{$func->{reply}}) {
+ if ($p->{class} eq "struct") {
+ print PYOUT "\tPy_XDECREF(param_", $p->{name}, ");\n";
+ print PYOUT "error_alloc_", $p->{name}, ":\n";
}
}
}
# 2 of the Licence, or (at your option) any later version.
#
+###############################################################################
+#
+# Emit python type wrapper declarations
+#
+###############################################################################
+sub emit_py_type_wrapper_decls($) {
+ my ($s) = @_;
+
+ print PYOUT "static PyTypeObject py_", $s->{type}, "Type;\n";
+}
+
###############################################################################
#
# Emit python type wrappers for C structs.
#
###############################################################################
-sub emit_py_type_wrapper($@) {
- my ($struct, @members) = @_;
+sub emit_py_type_wrapper($) {
+ my ($struct) = @_;
# Dump the banner comment block
- my @comments = @{shift @members};
-
print PYHDR "\n";
- print PYHDR @comments;
+ print PYHDR @{$struct->{banner}};
print PYOUT "\n";
- print PYOUT @comments;
+ print PYOUT @{$struct->{banner}};
+
+ # Divide the struct members into single ints, single structs, char arrays
+ # (strings) and other arrays
+ my @single_ints = ();
+ my @single_structs = ();
+ my @char_arrays = ();
+ my @arrays = ();
+ foreach my $m (@{$struct->{members}}) {
+ if ($m->{class} eq "array" && $m->{elem}->{type} eq "char") {
+ push @char_arrays, $m;
+ } elsif ($m->{class} eq "basic") {
+ push @single_ints, $m;
+ } elsif ($m->{class} eq "struct") {
+ push @single_structs, $m;
+ } elsif ($m->{class} eq "array") {
+ push @arrays, $m;
+ } else {
+ die;
+ }
+ }
# Write a python wrapper struct
- print PYHDR "struct py_$struct {\n";
+ #
+ # We have a copy of the raw struct and we also have caches for python
+ # objects for non-integer, non-array bits of the struct. We populate the
+ # caches when these bits are called for and then fold their contents back
+ # into the raw struct when we're about to marshal it.
+ #
+ print PYHDR "\n";
+ print PYHDR "struct py_", $struct->{type}, " {\n";
print PYHDR "\tPyObject_HEAD\n";
- print PYHDR "\tstruct $struct x;\n";
+ print PYHDR "\tstruct ", $struct->{type}, " x;\n";
+ if ($#single_structs + $#arrays > -2) {
+ print PYHDR "\tstruct {\n";
+ foreach my $m (@single_structs, @arrays) {
+ print PYHDR "\t\tPyObject *", $m->{name}, ";\n";
+ }
+ print PYHDR "\t} c;\n";
+ }
print PYHDR "};\n";
- print PYHDR "\n";
- # We want allocation and deallocation functions
- print PYOUT "static PyObject *\n";
- print PYOUT "py_", $struct, "_new(PyTypeObject *type, PyObject *args, PyObject *kwds)\n";
- print PYOUT "{\n";
- print PYOUT "\treturn (PyObject *)(struct py_$struct *)type->tp_alloc(type, 0);\n";
- print PYOUT "}\n";
+ # We have to have a deallocation function
print PYOUT "\n";
print PYOUT "static void\n";
- print PYOUT "py_", $struct, "_dealloc(struct py_$struct *self)\n";
+ print PYOUT "py_", $struct->{type}, "_dealloc(struct py_", $struct->{type}, " *self)\n";
print PYOUT "{\n";
+ foreach my $m (@single_structs, @arrays) {
+ print PYOUT "\tPy_XDECREF(self->c.", $m->{name}, ");\n";
+ }
print PYOUT "\tPy_TYPE(self)->tp_free((PyObject *)self);\n";
print PYOUT "}\n";
- print PYOUT "\n";
- # Divide into single members and array members
- my @singles = ();
- my @arrays = ();
- foreach my $m (@members) {
- my ($type, $name, $array_size, $max_size) = @{$m};
- if ($array_size == -1) {
- push @singles, $m;
- } else {
- push @arrays, $m;
- }
- }
-
- # Any non-array elements are made directly accessible to the Python interpreter
- print PYOUT "static PyMemberDef py_", $struct, "_members[] = {\n";
- if (@singles) {
- foreach my $m (@singles) {
- my ($type, $name, $array_size, $max_size) = @{$m};
- print PYOUT "\t{ \"$name\", ";
- if ($type eq "char") {
- print PYOUT "T_CHAR";
- } elsif ($type eq "int8_t") {
- print PYOUT "T_BYTE";
- } elsif ($type eq "int16_t") {
- print PYOUT "T_SHORT";
- } elsif ($type eq "int32_t") {
- print PYOUT "T_INT";
- } elsif ($type eq "int64_t") {
- print PYOUT "T_LONGLONG";
- } elsif ($type eq "uint8_t") {
- print PYOUT "T_UBYTE";
- } elsif ($type eq "uint16_t") {
- print PYOUT "T_USHORT";
- } elsif ($type eq "uint32_t") {
- print PYOUT "T_UINT";
- } elsif ($type eq "uint64_t") {
- print PYOUT "T_ULONGLONG";
- } elsif ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) {
- die "Don't py-wrap structs yet";
+ # Any integer non-array elements are made directly accessible to the Python
+ # interpreter
+ if ($#single_ints + $#char_arrays > -2) {
+ print PYOUT "\n";
+ print PYOUT "static PyMemberDef py_", $struct->{type}, "_members[] = {\n";
+ foreach my $m (@single_ints) {
+ print PYOUT "\t{ \"", $m->{name}, "\", ";
+ if ($m->{type} eq "char") { print PYOUT "T_CHAR";
+ } elsif ($m->{type} eq "int8_t") { print PYOUT "T_BYTE";
+ } elsif ($m->{type} eq "int16_t") { print PYOUT "T_SHORT";
+ } elsif ($m->{type} eq "int32_t") { print PYOUT "T_INT";
+ } elsif ($m->{type} eq "int64_t") { print PYOUT "T_LONGLONG";
+ } elsif ($m->{type} eq "uint8_t") { print PYOUT "T_UBYTE";
+ } elsif ($m->{type} eq "uint16_t") { print PYOUT "T_USHORT";
+ } elsif ($m->{type} eq "uint32_t") { print PYOUT "T_UINT";
+ } elsif ($m->{type} eq "uint64_t") { print PYOUT "T_ULONGLONG";
} else {
- die "Unsupported type \"$type\"";
+ die $m->{where}, ": Unsupported type \"", $m->{type}, "\"";
}
- print PYOUT ", offsetof(struct py_$struct, x.$name), 0, \"\"},\n";
+ print PYOUT ", offsetof(struct py_", $struct->{type}, ", x.", $m->{name}, "), 0, \"\"},\n";
}
+ print PYOUT "\t{}\n";
+ print PYOUT "};\n";
}
- print PYOUT "\t{}\n";
- print PYOUT "};\n";
- print PYOUT "\n";
+
+ # Non-single integer elements need to be turned into their respective
+ # Python types and returned.
# Array elements have to be accessed through ->tp_[sg]etattro() as
- # tuples (int[]/uint[]) or strings (char[])
- if (@arrays) {
+ # tuples (int[]/uint[]/struct[]) or strings (char[])
+ if ($#single_structs + $#arrays + $#char_arrays > -3) {
# The attribute get function
+ print PYOUT "\n";
print PYOUT "static PyObject *\n";
- print PYOUT "py_", $struct, "_getattro(PyObject *_self, PyObject *name)\n";
+ print PYOUT "py_", $struct->{type}, "_getattro(PyObject *_self, PyObject *name)\n";
print PYOUT "{\n";
- print PYOUT "\tstruct py_$struct *self = (struct py_$struct *)_self;\n";
+ print PYOUT "\tstruct py_", $struct->{type}, " *self = (struct py_", $struct->{type}, " *)_self;\n";
print PYOUT "\n";
print PYOUT "\tif (PyUnicode_Check(name)) {\n";
- foreach my $m (@arrays) {
- my ($type, $name, $array_size, $max_size) = @{$m};
-
- print PYOUT "\t\tif (PyUnicode_CompareWithASCIIString(name, \"$name\") == 0)\n";
- if ($type eq "char") {
- print PYOUT "\t\t\treturn py_rxgen_get_string(&self->x.$name, $array_size);\n";
- } elsif ($type eq "uint8_t") {
- print PYOUT "\t\t\treturn py_rxgen_get_uint8(&self->x.$name, $array_size);\n";
- } elsif ($type eq "uint16_t") {
- print PYOUT "\t\t\treturn py_rxgen_get_uint16(&self->x.$name, $array_size);\n";
- } elsif ($type eq "uint32_t") {
- print PYOUT "\t\t\treturn py_rxgen_get_uint32(&self->x.$name, $array_size);\n";
- } elsif ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) {
- die "Don't py-wrap struct arrays yet";
+ foreach my $m (@char_arrays, @single_structs, @arrays) {
+ print PYOUT "\t\tif (PyUnicode_CompareWithASCIIString(name, \"", $m->{name}, "\") == 0)\n";
+ if ($m->{class} eq "struct") {
+ print PYOUT "\t\t\treturn py_rxgen_get_struct(&self->x.", $m->{name}, ",\n";
+ print PYOUT "\t\t\t\t\t\t &self->c.", $m->{name}, ",\n";
+ print PYOUT "\t\t\t\t\t\t py_data_to_", $m->{type}, ");\n";
+ } elsif ($m->{class} ne "array") {
+ die $m->{where}, ": Unsupported type class \"", $m->{class}, "\"";
+ } elsif ($m->{elem}->{class} eq "struct") {
+ print PYOUT "\t\t\treturn py_rxgen_get_structs(&self->x.", $m->{name}, ", ", $m->{dim}, ",\n";
+ print PYOUT "\t\t\t\t\t\t sizeof(struct ", $m->{elem}->{type}, "),\n";
+ print PYOUT "\t\t\t\t\t\t &self->c.", $m->{name}, ",\n";
+ print PYOUT "\t\t\t\t\t\t py_data_to_", $m->{elem}->{type}, ");\n";
+ } elsif ($m->{elem}->{class} ne "basic") {
+ die $m->{where}, ": Unsupported array type class \"", $m->{elem}->{class}, "\"";
+ } elsif ($m->{elem}->{type} eq "char") {
+ print PYOUT "\t\t\treturn py_rxgen_get_string(&self->x.", $m->{name}, ", ", $m->{dim}, ");\n";
+ } elsif ($m->{elem}->{type} eq "uint8_t") {
+ print PYOUT "\t\t\treturn py_rxgen_get_uint8(&self->x.", $m->{name}, ", ", $m->{dim}, ",\n";
+ print PYOUT "\t\t\t\t\t\t &self->c.", $m->{name}, ");\n";
+ } elsif ($m->{elem}->{type} eq "uint16_t") {
+ print PYOUT "\t\t\treturn py_rxgen_get_uint16(&self->x.", $m->{name}, ", ", $m->{dim}, ",\n";
+ print PYOUT "\t\t\t\t\t\t &self->c.", $m->{name}, ");\n";
+ } elsif ($m->{elem}->{type} eq "uint32_t") {
+ print PYOUT "\t\t\treturn py_rxgen_get_uint32(&self->x.", $m->{name}, ", ", $m->{dim}, ",\n";
+ print PYOUT "\t\t\t\t\t\t &self->c.", $m->{name}, ");\n";
} else {
- die "Unsupported array type \"$type\"";
+ die $m->{where}, ": Unsupported array type \"", $m->{elem}->{type}, "\"";
}
}
# The attribute set function
print PYOUT "static int\n";
- print PYOUT "py_", $struct, "_setattro(PyObject *_self, PyObject *name, PyObject *val)\n";
+ print PYOUT "py_", $struct->{type}, "_setattro(PyObject *_self, PyObject *name, PyObject *val)\n";
print PYOUT "{\n";
- print PYOUT "\tstruct py_$struct *self = (struct py_$struct *)_self;\n";
+ print PYOUT "\tstruct py_", $struct->{type}, " *self = (struct py_", $struct->{type}, " *)_self;\n";
print PYOUT "\n";
print PYOUT "\tif (PyUnicode_Check(name)) {\n";
- foreach my $m (@arrays) {
- my ($type, $name, $array_size, $max_size) = @{$m};
-
- print PYOUT "\t\tif (PyUnicode_CompareWithASCIIString(name, \"$name\") == 0)\n";
- if ($type eq "char") {
- print PYOUT "\t\t\treturn py_rxgen_set_string(&self->x.$name, $array_size, val);\n";
- } elsif ($type eq "uint8_t") {
- print PYOUT "\t\t\treturn py_rxgen_set_uint8(&self->x.$name, $array_size, val);\n";
- } elsif ($type eq "uint16_t") {
- print PYOUT "\t\t\treturn py_rxgen_set_uint16(&self->x.$name, $array_size, val);\n";
- } elsif ($type eq "uint32_t") {
- print PYOUT "\t\t\treturn py_rxgen_set_uint32(&self->x.$name, $array_size, val);\n";
- } elsif ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) {
- die "Don't py-wrap struct arrays yet";
+ foreach my $m (@char_arrays, @single_structs, @arrays) {
+ print PYOUT "\t\tif (PyUnicode_CompareWithASCIIString(name, \"", $m->{name}, "\") == 0)\n";
+ if ($m->{class} eq "struct") {
+ print PYOUT "\t\t\treturn py_rxgen_set_struct(&self->c.", $m->{name}, ",\n";
+ print PYOUT "\t\t\t\t\t\t &py_", $struct->{type}, "Type, val);\n";
+ } elsif ($m->{class} ne "array") {
+ die $m->{where}, ": Unsupported type class \"", $m->{class}, "\"";
+ } elsif ($m->{elem}->{type} eq "char") {
+ print PYOUT "\t\t\treturn py_rxgen_set_string(&self->x.", $m->{name}, ", ", $m->{dim}, ", val);\n";
+ } elsif ($m->{elem}->{class} eq "basic" ||
+ $m->{elem}->{class} eq "struct") {
+ print PYOUT "\t\t\treturn py_rxgen_set_array(", $m->{dim}, ", &self->c.", $m->{name}, ", val);\n";
} else {
- die "Unsupported array type \"$type\"";
+ die $m->{where}, ": Unsupported array type \"", $m->{elem}->{type}, "\"";
}
}
}
# Emit the Python type definition
- print PYOUT "static PyTypeObject py_", $struct, "Type = {\n";
-
+ print PYOUT "static PyTypeObject py_", $struct->{type}, "Type = {\n";
print PYOUT "\tPyVarObject_HEAD_INIT(NULL, 0)\n";
- print PYOUT "\t\"kafs.$struct\",\t\t/*tp_name*/\n";
- print PYOUT "\tsizeof(struct py_$struct),\t/*tp_basicsize*/\n";
+ print PYOUT "\t\"kafs.", $struct->{type}, "\",\t\t/*tp_name*/\n";
+ print PYOUT "\tsizeof(struct py_", $struct->{type}, "),\t/*tp_basicsize*/\n";
print PYOUT "\t0,\t\t\t\t/*tp_itemsize*/\n";
- print PYOUT "\t(destructor)py_", $struct, "_dealloc, /*tp_dealloc*/\n";
+ print PYOUT "\t(destructor)py_", $struct->{type}, "_dealloc, /*tp_dealloc*/\n";
print PYOUT "\t0,\t\t\t\t/*tp_print*/\n";
print PYOUT "\t0,\t\t\t\t/*tp_getattr*/\n";
print PYOUT "\t0,\t\t\t\t/*tp_setattr*/\n";
print PYOUT "\t0,\t\t\t\t/*tp_hash */\n";
print PYOUT "\t0,\t\t\t\t/*tp_call*/\n";
print PYOUT "\t0,\t\t\t\t/*tp_str*/\n";
- if (@arrays) {
- print PYOUT "\tpy_", $struct, "_getattro,\n";
- print PYOUT "\tpy_", $struct, "_setattro,\n";
+ if ($#single_structs + $#arrays + $#char_arrays > -3) {
+ print PYOUT "\tpy_", $struct->{type}, "_getattro,\n";
+ print PYOUT "\tpy_", $struct->{type}, "_setattro,\n";
} else {
print PYOUT "\t0,\t\t\t\t/*tp_getattro*/\n";
print PYOUT "\t0,\t\t\t\t/*tp_setattro*/\n";
print PYOUT "\t0,\t\t\t\t/* tp_iter */\n";
print PYOUT "\t0,\t\t\t\t/* tp_iternext */\n";
print PYOUT "\t0,\t\t\t\t/* tp_methods */\n";
- if (@singles) {
- print PYOUT "\tpy_", $struct, "_members,\n";
+ if (@single_ints) {
+ print PYOUT "\tpy_", $struct->{type}, "_members,\n";
} else {
print PYOUT "\t0,\t\t\t/* tp_members */\n";
}
print PYOUT "\t0,\t\t\t\t/* tp_dictoffset */\n";
print PYOUT "\t0,\t\t\t\t/* tp_init */\n";
print PYOUT "\t0,\t\t\t\t/* tp_alloc */\n";
- print PYOUT "\tpy_", $struct, "_new,\t/* tp_new */\n";
+ print PYOUT "\t0,\t\t\t\t/* tp_new */\n";
print PYOUT "};\n";
# Emit a function to allocate such a type
- print PYHDR "extern PyObject *kafs_new_py_$struct(PyObject *, PyObject *);\n";
+ print PYHDR "extern PyObject *kafs_new_py_", $struct->{type}, "(PyObject *, PyObject *);\n";
print PYOUT "\n";
print PYOUT "PyObject *\n";
- print PYOUT "kafs_new_py_$struct(PyObject *_self, PyObject *args)\n";
+ print PYOUT "kafs_new_py_", $struct->{type}, "(PyObject *_self, PyObject *args)\n";
print PYOUT "{\n";
- print PYOUT "\tPyObject *obj;\n";
- print PYOUT "\tobj = _PyObject_New(&py_", $struct, "Type);\n";
- print PYOUT "\treturn obj ?: PyExc_MemoryError;\n";
+ print PYOUT "\tPyObject *obj = _PyObject_New(&py_", $struct->{type}, "Type);\n";
+ print PYOUT "\tstruct py_", $struct->{type}, " *self = (struct py_", $struct->{type}, " *)obj;\n";
+ print PYOUT "\tif (!obj)\n";
+ print PYOUT "\t\treturn PyExc_MemoryError;\n";
+ print PYOUT "\tmemset(&self->x, 0, sizeof(self->x));\n";
+ if ($#single_structs + $#arrays > -2) {
+ print PYOUT "\tmemset(&self->c, 0, sizeof(self->c));\n";
+ }
+ print PYOUT "\treturn obj;\n";
print PYOUT "}\n";
+
+ # Emit a function to create an object of this type from raw data
+ print PYHDR "extern PyObject *py_data_to_", $struct->{type}, "(const void *);\n";
+
+ print PYOUT "\n";
+ print PYOUT "PyObject *py_data_to_", $struct->{type}, "(const void *data) {\n";
+ print PYOUT "\tPyObject *obj = _PyObject_New(&py_", $struct->{type}, "Type);\n";
+ print PYOUT "\tstruct py_", $struct->{type}, " *self = (struct py_", $struct->{type}, " *)obj;\n";
+ print PYOUT "\tif (!obj)\n";
+ print PYOUT "\t\treturn PyExc_MemoryError;\n";
+ print PYOUT "\tmemcpy(&self->x, data, sizeof(self->x));\n";
+ if ($#single_structs + $#arrays > -2) {
+ print PYOUT "\tmemset(&self->c, 0, sizeof(self->c));\n";
+ }
+ print PYOUT "\treturn obj;\n";
+ print PYOUT "}\n";
+
+ # Emit a function to premarshal such a type. This folds the contents of
+ # the cached Python objects into their raw fields.
+ #
+ if ($#single_structs + $#arrays > -2) {
+ print PYHDR "extern int py_premarshal_", $struct->{type}, "(PyObject *);\n";
+
+ print PYOUT "\n";
+ print PYOUT "int py_premarshal_", $struct->{type}, "(PyObject *_self)\n";
+ print PYOUT "{\n";
+ print PYOUT "\tstruct py_", $struct->{type}, " *self = (struct py_", $struct->{type}, " *)_self;\n";
+
+ # Check that the type we've been given is the right one
+ print PYOUT "\n";
+ print PYOUT "\tif (!PyObject_TypeCheck(self, &py_", $struct->{type}, "Type)) {\n";
+ print PYOUT "\t\tPyErr_Format(PyExc_TypeError, \"Expected object of type ", $struct->{type}, "\");\n";
+ print PYOUT "\t\treturn -1;\n";
+ print PYOUT "\t}\n";
+
+ print PYOUT "\n";
+ my $first = 1;
+ foreach my $m (@single_structs, @arrays) {
+ if ($first) {
+ print PYOUT "\tif (";
+ $first = 0;
+ } else {
+ print PYOUT " ||\n";
+ print PYOUT "\t ";
+ }
+
+ if ($m->{class} eq "struct") {
+ print PYOUT "py_rxgen_premarshal_struct(&self->x.", $m->{name}, ",\n";
+ print PYOUT "\t\t\t\t sizeof(struct ", $m->{type}, "),\n";
+ print PYOUT "\t\t\t\t offsetof(struct py_", $m->{type}, ", x),\n";
+ print PYOUT "\t\t\t\t self->c.", $m->{name}, ",\n";
+ print PYOUT "\t\t\t\t py_premarshal_", $m->{type}, ") < 0";
+ } elsif ($m->{class} ne "array") {
+ die $m->{where}, ": Unsupported type class \"", $m->{class}, "\"";
+ } elsif ($m->{elem}->{class} eq "struct") {
+ print PYOUT "py_rxgen_premarshal_structs(&self->x.", $m->{name}, ",\n";
+ print PYOUT "\t\t\t\t\t", $m->{dim}, ", sizeof(struct ", $m->{elem}->{type}, "),\n";
+ print PYOUT "\t\t\t\t\toffsetof(struct py_", $m->{elem}->{type}, ", x),\n";
+ print PYOUT "\t\t\t\t\tself->c.", $m->{name}, ",\n";
+ print PYOUT "\t\t\t\t\tpy_premarshal_", $m->{elem}->{type}, ") < 0";
+ } elsif ($m->{elem}->{class} ne "basic") {
+ die $m->{where}, ": Unsupported array type class \"", $m->{elem}->{class}, "\"";
+ } elsif ($m->{elem}->{type} eq "uint8_t") {
+ print PYOUT "py_rxgen_premarshal_uint8(&self->x.", $m->{name}, ", ", $m->{dim}, ", self->c.", $m->{name}, ") < 0";
+ } elsif ($m->{elem}->{type} eq "uint16_t") {
+ print PYOUT "py_rxgen_premarshal_uint16(&self->x.", $m->{name}, ", ", $m->{dim}, ", self->c.", $m->{name}, ") < 0";
+ } elsif ($m->{elem}->{type} eq "uint32_t") {
+ print PYOUT "py_rxgen_premarshal_uint32(&self->x.", $m->{name}, ", ", $m->{dim}, ", self->c.", $m->{name}, ") < 0";
+ } else {
+ die $m->{where}, ": Unsupported array type \"", $m->{elem}->{type}, "\"";
+ }
+ }
+
+ print PYOUT ")\n";
+ print PYOUT "\t\treturn -1;\n";
+ print PYOUT "\treturn 0;\n";
+ print PYOUT "}\n";
+ }
}
1;
use emit_py_sync_funcs;
use emit_py_module;
-die "Need list of sources\n" if ($#ARGV < 0);
+die "Need list of xg files to process\n" if ($#ARGV < 0);
our @structs = (); # Structure definitions
our %struct_sizes = (); # Structure sizes
-our %funcs = (); # Function declarations
-our %constants = (); # #defined constants
+our @funcs = (); # Functions in declaration order
+our %func_names = (); # Function name uniquifier
+our %constants = (); # Constants
+our @abort_codes = (); # Abort codes
#
# Divide the lines from the files up into typed collections
#
my @comment = ();
+my $pkg = "";
my $banner = 0;
my $struct = 0;
-my $size = 0;
my $func = 0;
-my @members;
+my $cpp_exclude = 0;
+my $error_codes = 0;
my @files = @ARGV;
+my $file = "";
+my $where = "";
-die "No API files specified" unless (@files);
+###############################################################################
+#
+# Handle defined types.
+#
+# Each type is specified by a hash of the following elements:
+#
+# class Complexity class (basic, string, struct, array, bulk)
+# type Basic/struct type (char, {u,}int{8,16,32,64}_t, opaque, struct name)
+# elem Ref to element type def (if array/bulk)
+# multi 1 if array or bulk type, 0 otherwise
+# dim Number of elements in array or max elements in bulk array (if array/bulk)
+# members Members of struct
+# xdr_size Size of XDR encoded object
+# where Where defined in file
+# banner Banner comment
+#
+# Members/parameters take a copy of their parent type's hash and add:
+#
+# name Member or parameter name
+# ptr "*" if a pointer
+# dir Direction (IN, OUT or INOUT)
+#
+###############################################################################
+# Defined types
+our %types = (
+ "char" => { class => "basic", type => "char", xdr_size => 4, multi => 0, },
+ "int8_t" => { class => "basic", type => "int8_t", xdr_size => 4, multi => 0, },
+ "int16_t" => { class => "basic", type => "int16_t", xdr_size => 4, multi => 0, },
+ "int32_t" => { class => "basic", type => "int32_t", xdr_size => 4, multi => 0, },
+ "int64_t" => { class => "basic", type => "int64_t", xdr_size => 8, multi => 0, },
+ "uint8_t" => { class => "basic", type => "uint8_t", xdr_size => 4, multi => 0, },
+ "uint16_t" => { class => "basic", type => "uint16_t", xdr_size => 4, multi => 0, },
+ "uint32_t" => { class => "basic", type => "uint32_t", xdr_size => 4, multi => 0, },
+ "uint64_t" => { class => "basic", type => "uint64_t", xdr_size => 8, multi => 0, },
+ "string" => { class => "string", type => "char", xdr_size => 1, multi => 0, },
+ "opaque" => { class => "opaque", type => "void", xdr_size => 1, multi => 0, },
+ );
+
+sub look_up_type($)
+{
+ my ($type) = @_;
+
+ die $where, ": Undefined type '$type'\n" unless exists $types{$type};
+ return $types{$type};
+}
-sub parse_header($) {
- my ($file) = @_;
- open my $APIHDR, "<$file" || die $file;
+sub define_type($$)
+{
+ my ($new_type, $as) = @_;
+ die $where, ": Redefining type '$new_type'\n" if exists $types{$new_type};
+ $as->{where} = $where;
+ $types{$new_type} = $as;
+}
+
+sub define_typedef($$$)
+{
+ my ($new_type, $as, $flags) = @_;
+
+ my $type = look_up_type($as);
+
+ my %combined = %{$type};
+
+ if ($flags->{class} eq "bulk" ||
+ $flags->{class} eq "array") {
+ die $where, ": Typedef'ing array/bulk as array/bulk not supported\n"
+ if ($type->{multi});
+ $combined{multi} = 1;
+ $combined{class} = $flags->{class};
+ $combined{elem} = $type;
+ $combined{dim} = $flags->{dim} if (exists $flags->{dim});
+ $combined{xdr_size} *= $combined{dim} if ($flags->{class} eq "array");
+ }
+
+ define_type($new_type, \%combined);
+}
+
+###############################################################################
+#
+# Parse an xg interface definition
+#
+###############################################################################
+sub parse_xg($) {
+ my ($filename) = @_;
+ $file = $filename;
+ open my $APIHDR, "<$filename" || die $filename;
while (my $line = <$APIHDR>) {
+ $where = $file . ':' . $. ;
+
+ # Detect #if 0/#endif pairs to exclude parts
+ if ($line =~ m@^#\s*if\s+0@) {
+ die $where, ": Embedded #if 0 clause\n" if $cpp_exclude;
+ $cpp_exclude = 1;
+ next;
+ }
+
+ if ($line =~ m@^#\s*endif@) {
+ die $where, ": Unbalanced #endif\n" unless $cpp_exclude;
+ $cpp_exclude = 0;
+ next;
+ }
+
+ next if $cpp_exclude;
+
# Gather comments for later attachment to subsequent structs and funcs
- if ($line =~ m@^/[*]@) {
- die if $banner;
+ if ($line =~ m@^/[*]\s*$@) {
+ die $where, ": Embedded comment\n" if $banner;
$banner = 1;
@comment = ( $line );
next;
}
if ($banner) {
- die if ($line !~ /^ [*]/);
+ die $where, ": Commentless terminator\n" if ($line !~ /^ [*]/);
push @comment, $line;
$banner = 0 if ($line =~ m!^ [*]/!);
next;
}
- # Extract #defines
- if ($line =~ /^#define\s+([A-Za-z0-9_]+)\s+(.*)/) {
- $constants{$1} = $2 if ($2);
+ chomp($line);
+
+ @comment = () if ($line eq "");
+
+ # Complain about #defines
+ die $where, ": Use const not #define" if ($line =~ /^#define/);
+
+ # Extract package prefix
+ if ($line =~ /^package\s+([A-Za-z_][A-Za-z0-9_]*)/) {
+ $pkg = $1;
+ next;
+ }
+
+ # Extract error codes
+ if ($line eq "/* Error codes */") {
+ $error_codes = 1;
+ next;
+ }
+
+ $error_codes = 0 if ($line eq "");
+
+ #######################################################################
+ # Extract constants
+ #
+ if ($line =~ /^const\s+([A-Za-z0-9_]+)\s*=\s*(.*);/) {
+ my $c = $1;
+ my $v = $2;
+ die $where, ": Duplicate constant $c" if (exists $constants{$c});
+ $v =~ s/^\s+//;
+ $v =~ s/\s+$//;
+ $constants{$c} = $v;
+ push @abort_codes, $c if $error_codes;
@comment = ();
next;
}
+ #######################################################################
+ # Extract typedefs
+ #
+ if ($line =~ /^typedef\s+([a-zA-Z_][a-zA-Z0-9_]*)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*;/) {
+ define_typedef($2, $1, { });
+ next;
+ }
+
+ if ($line =~ /^typedef\s+([a-zA-Z_][a-zA-Z0-9_]*)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*<\s*>\s*;/) {
+ define_typedef($2, $1, { class => "bulk" });
+ next;
+ }
+
+ if ($line =~ /^typedef\s+([a-zA-Z_][a-zA-Z0-9_]*)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*<\s*([a-zA-Z0-9_]+)\s*>\s*;/) {
+ define_typedef($2, $1, { class => "bulk", dim => $3 });
+ next;
+ }
+
+ #######################################################################
# Extract structures
- if ($line =~ /^struct ([a-zA-Z_][a-zA-Z0-9_]*) {/) {
- $struct = "$1";
- $size = 0;
- @members = ( [ @comment ] );
+ #
+ if ($line =~ /^struct\s+([a-zA-Z_][a-zA-Z0-9_]*) {/) {
+ my %type = (
+ class => "struct",
+ type => $1,
+ members => [],
+ banner => \@comment,
+ xdr_size => 0,
+ );
+ define_type($1, \%type);
+ push @structs, \%type;
+ $struct = \%type;
+ @comment = ();
next;
}
if ($line =~ /};/ && $struct) {
- push @structs, [ $struct, @members ];
- $struct_sizes{$struct} = $size;
- @members = ();
$struct = 0;
next;
}
# Strip trailing comments
$line =~ s@\s*/[*][^*]*[*]/$@@;
- if ($line =~ /(uint[0-9]+_t|char)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*;/) {
- push @members, [ $1, $2, -1, -1 ];
- $size += 4;
+ if ($line =~ /([a-zA-Z_][a-zA-Z0-9_]*)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*;/) {
+ my %member = %{look_up_type($1)};
+ die $where, ": Don't support bulk constructs in structs\n"
+ if ($member{class} eq "bulk");
+ $member{name} = $2;
+ $member{where} = $where;
+ push $struct->{members}, \%member;
+ $struct->{xdr_size} += $member{xdr_size};
#print "nonarray $2\n";
- } elsif ($line =~ /(uint[0-9]+_t|char)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\[\s*([^]]+)\s*\]\s*;/) {
- my $type = $1;
- my $name = $2;
- my $array_size = $3;
- if ($array_size =~ /^[0-9]+$/) {
- } elsif (exists $constants{$array_size}) {
- $array_size = $constants{$array_size};
+ } elsif ($line =~ /([a-zA-Z_][a-zA-Z0-9_]*)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\[\s*([^]]+)\s*\]\s*;/) {
+ my $element = look_up_type($1);
+ die $where, ": Don't support arrays of bulk constructs or arrays\n"
+ if ($element->{multi});
+
+ my %member = ();
+ $member{class} = "array";
+ $member{elem} = $element;
+ $member{name} = $2;
+ $member{dim} = $3;
+ $member{where} = $where;
+
+ if ($member{dim} =~ /^[0-9]+$/) {
+ $constants{$member{dim}} = $member{dim};
+ } elsif (exists $constants{$member{dim}}) {
} else {
- die "In struct $struct: No constant for [$array_size]"
+ die $where, ": No constant for [", $member{dim}, "]\n"
}
- push @members, [ $type, $name, $array_size, -1 ];
- $size += $array_size * 4;
+ $member{xdr_size} = $constants{$member{dim}} * $element->{xdr_size};
+ push $struct->{members}, \%member;
+ $struct->{xdr_size} += $member{xdr_size};
#print "array $2\n";
} else {
- die "Unrecognised struct member";
+ die $where, ": Unrecognised struct member '$line'";
}
}
+ #######################################################################
# Extract functions
- if ($line =~ /^extern\s+int\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(\s*\n/) {
+ #
+ if (!$func && $line =~ /^([a-zA-Z_][a-zA-Z0-9_]*)\s*\(\s*(.*)$/) {
#print "func $1\n";
- $func = "$1";
- @members = ( [ @comment ] );
- next;
+ my %function = (
+ name => $pkg . $1,
+ banner => \@comment,
+ params => [],
+ where => $where,
+ );
+ die $where, ": Duplicate function name '$1'\n"
+ if (exists($func_names{$1}));
+ $func_names{$1} = \%function;
+ push @funcs, \%function;
+ $func = \%function;
+ @comment = ();
+ $line = $2;
}
# Extract function parameters
if ($func) {
my $dir = "";
- my $const = "";
- my $type = "";
- my $name = "";
my $term = 0;
- my $max = -1;
-
- chomp $line;
-
- $dir = $1 if ($line =~ s@/[*](IN|OUT|INOUT)[*]/\s+@@);
-
- if ($line =~ s@/[*]\s+Max ([0-9]+)\s+[*]/@@) {
- $max = $1;
- } elsif ($line =~ s@/[*]\s+Max ([a-zA-Z0-9_]+)\s+[*]/@@) {
- die "No constant for $1" unless exists $constants{$1};
- $max = $constants{$1};
+ my $bulk_dim = 0;
+
+ $dir = $1 if ($line =~ s@^\s*(IN|OUT|INOUT)\s+@@);
+
+ if ($line =~ s@<\s*>@@) {
+ $bulk_dim = -1;
+ } elsif ($line =~ s@<\s*([0-9]+)\s*>@@) {
+ $bulk_dim = $1;
+ $constants{$bulk_dim} = $bulk_dim;
+ } elsif ($line =~ s@<\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*>@@) {
+ die $where, ": No constant for $1\n" unless exists $constants{$1};
+ $bulk_dim = $1;
}
# Strip trailing comments
$line =~ s@\s*/[*][^*]*[*]/$@@;
$line =~ s/\s+$//;
- if ($line =~ s/[)];$//) {
+ if ($line =~ s/[)]\s*=\s*([a-zA-Z0-9_]*)\s*;$//) {
$term = 1;
+ $func->{opcode} = $1;
} elsif ($line =~ s/,$//) {
$term = 0;
} else {
- die "Unexpected line termination '$line'";
+ die $where, ": Unexpected line termination '$line'";
}
$line =~ s/\s+$//;
- $const = $1 if ($line =~ s@^const\s+@@);
-
#print "\"", $line, "\"\n";
- if ($line =~ /(struct\s+[a-zA-Z_][a-zA-Z0-9_]*|uint[0-9]+_t|char)\s+([*]*)([a-zA-Z_][a-zA-Z0-9_]*)\s*/) {
- $type = $1 . $2;
- $name = $3;
+ if ($line =~ /([a-zA-Z_][a-zA-Z0-9_]*)\s+([*]*)([a-zA-Z_][a-zA-Z0-9_]*)\s*/) {
+ die $where, ": No parameter direction specified\n" unless $dir;
+
+ my $type = look_up_type($1);
+ my %param = %{$type};
+ $param{ptr} = $2;
+ $param{name} = $3;
+ $param{dir} = $dir;
+ $param{where} = $where;
+
+ die $where, ": 'string' only supported with IN\n"
+ if ($param{type} eq "string" && $dir ne "IN");
+ die $where, ": Array parameters not supported\n"
+ if ($param{class} eq "array");
+ if ($bulk_dim) {
+ die $where, ": Bulk-of-bulk parameters not supported\n"
+ if ($param{class} eq "bulk");
+ $param{class} = "bulk";
+ $param{elem} = $type;
+ $param{dim} = $bulk_dim;
+ }
+
+ $param{ptr} = "*" if ($type->{class} eq "string");
+
+ #print "- ", $1, " ", $param{name}, " ISA ", $param{class}, ".", $param{type}, " ", $param{dir}, "\n";
+ push $func->{params}, \%param;
- #print "- ", $name, " ISA ", $type, " ", $dir, "\n";
- push @members, [ $type, $name, -1, $max, $dir ] unless ($1 eq "struct rx_connection");
+ } elsif ($line eq "") {
+ # Parameterless function
} else {
- die "Unhandled RPC call parameter";
+ die $where, ": Unhandled RPC call parameter '$line'";
}
if ($term) {
- $funcs{$func} = [ @members ];
- @members = ();
$func = 0;
next;
}
}
foreach my $file (@files) {
- parse_header($file);
+ parse_xg($file);
}
print "Extracted ", scalar keys %constants, " constants\n";
-print "Extracted ", scalar @structs, " types\n";
-print "Extracted ", scalar keys %funcs, " functions\n";
+print "Extracted ", scalar @structs, " structs\n";
+print "Extracted ", scalar keys %types, " types\n";
+print "Extracted ", scalar @funcs, " functions\n";
+print "Extracted ", scalar @abort_codes, " abort codes\n";
###############################################################################
#
# Create the output files and emit the file prologues.
#
###############################################################################
+open RXHDR, ">afs_xg.h" || die "afs_xg.h";
+print RXHDR "/* AUTOGENERATED */\n";
+#print RXHDR "#define _XOPEN_SOURCE\n";
+print RXHDR "#include <stdint.h>\n";
+print RXHDR "#include \"rxgen.h\"\n";
+
open RXOUT, ">afs_xg.c" || die "afs_xg.c";
print RXOUT "/* AUTOGENERATED */\n";
-print RXOUT "#define _XOPEN_SOURCE\n";
-print RXOUT "#include <stdint.h>\n";
+print RXOUT "#include \"afs_xg.h\"\n";
print RXOUT "#include <stdio.h>\n";
print RXOUT "#include <stdlib.h>\n";
print RXOUT "#include <string.h>\n";
print RXOUT "#include <unistd.h>\n";
print RXOUT "#include <errno.h>\n";
print RXOUT "#include <sys/socket.h>\n";
+print RXOUT "#include <sys/param.h>\n";
print RXOUT "#include <arpa/inet.h>\n";
-print RXOUT "#include \"rxgen.h\"\n";
+print RXOUT "\n";
open PYHDR, ">afs_py.h" || die "afs_py.h";
print PYHDR "/* AUTOGENERATED */\n";
print PYHDR "#include <Python.h>\n";
-print PYHDR "#include <stdint.h>\n";
-
-foreach $_ (@files) {
- print RXOUT "#include \"$_\"\n";
- print PYHDR "#include \"$_\"\n";
-}
+print PYHDR "#include \"afs_xg.h\"\n";
open PYOUT, ">afs_py.c" || die "afs_py.c";
print PYOUT "/* AUTOGENERATED */\n";
print PYOUT "#include \"afs_py.h\"\n";
print PYOUT "#include <arpa/inet.h>\n";
print PYOUT "#include \"py_rxgen.h\"\n";
+print PYOUT "\n";
+
+# Declare constants
+print RXHDR "\n";
+foreach my $c (sort keys %constants) {
+ print RXHDR "#define $c ", $constants{$c}, "\n" unless ($c =~ /^[0-9]/)
+}
# Declare types
foreach my $s (@structs) {
- my @members = @{$s};
- my $struct = shift @members;
- emit_struct_encdec($struct, @members);
- emit_py_type_wrapper($struct, @members);
+ emit_struct_encdec_decls($s);
+ emit_py_type_wrapper_decls($s);
+}
+
+foreach my $s (@structs) {
+ emit_struct_encdec($s);
+ emit_py_type_wrapper($s);
}
###############################################################################
# to input and output usage and work out how big the RPC messages will be.
#
###############################################################################
-foreach $func (sort keys %funcs) {
- my @params = @{$funcs{$func}};
-
+foreach $func (@funcs) {
# Dump the banner comment block
- my @banner = @{shift @params};
print RXOUT "\n";
- print RXOUT @banner;
- print PYOUT "\n";
- print PYOUT @banner;
-
- # Find the Operation ID from the banner comment
- my $op = "";
- foreach $_ (@banner) {
- if ($_ =~ /Operation: ([A-Z][_A-Z0-9]+)/) {
- $op = $1;
- last;
- }
+ if (@{$func->{banner}}) {
+ print RXOUT @{$func->{banner}};
+ print PYOUT "\n";
+ print PYOUT @{$func->{banner}};
+ } else {
+ print RXOUT "/*\n";
+ print RXOUT " * RPC Call ", $func->{name}, "\n";
+ print RXOUT " */\n";
}
- die "Operation ID unspecified for $func" unless $op;
+ # Find the Operation ID
+ die "Operation ID unspecified for ", $func->{name}, "\n"
+ unless exists $func->{opcode};
# Filter the parameters into request and reply
my @request = ();
my $request_size = 4;
my $reply_size = 0;
my $req_has_charptr = 0;
+ my $req_size_is_indefinite = 0;
+ my $rep_size_is_indefinite = 0;
- foreach my $p (@params) {
- my ($type, $name, $array_size, $max_size, $dir) = @{$p};
-
+ foreach my $p (@{$func->{params}}) {
#print RXOUT $dir, " ", $type, " ", $name, "\n";
- my $size = 0;
- my $has_charptr = 0;
- if ($array_size == -1) {
- if ($type eq "char*") {
- $size = (4 + $max_size + 3) & ~3;
- $has_charptr = 1;
- } elsif ($type eq "uint8_t" || $type eq "uint8_t*" ||
- $type eq "uint16_t" || $type eq "uint16_t*" ||
- $type eq "uint32_t" || $type eq "uint32_t*" ||
- $type eq "uint64_t" || $type eq "uint64_t*") {
- $size = 4;
- } elsif ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) {
- die "No encoding for $type" unless exists $struct_sizes{$1};
- $size = $struct_sizes{$1};
+ my $buffer_size = 0;
+ my $indefinite = 0;
+ if ($p->{class} eq "basic") {
+ $buffer_size = $p->{xdr_size};
+
+ } elsif ($p->{class} eq "struct") {
+ die unless (exists $p->{xdr_size});
+ $buffer_size = $p->{xdr_size};
+
+ } elsif ($p->{class} eq "bulk") {
+ die $p->{where}, ": No element type" unless (exists $p->{elem});
+ die $p->{where}, ": Element has no XDR size" unless (exists $p->{elem}->{xdr_size});
+ if (exists $p->{dim} && $p->{elem}->{xdr_size} > 0) {
+ $buffer_size = $p->{elem}->{xdr_size};
+ $buffer_size *= $constants{$p->{dim}};
+ $buffer_size = (4 + $buffer_size + 3) & ~3;
+ $req_has_charptr = 1 if ($p->{elem}->{class} eq "string");
} else {
- die "Unsupported type \"$type\"";
+ $buffer_size = 4;
+ $indefinite = 1;
}
} else {
- if ($type eq "uint8_t" || $type eq "uint8_t*" ||
- $type eq "uint16_t" || $type eq "uint16_t*" ||
- $type eq "uint32_t" || $type eq "uint32_t*" ||
- $type eq "uint64_t" || $type eq "uint64_t*") {
- $size = 4;
- } else {
- die "Unsupported type \"$type\"";
- }
- $size *= $array_size;
+ die $p->where, ": Unsupported param class \"", $p->{class}, "\"";
}
- if ($dir eq "IN") {
+ if ($p->{dir} eq "IN") {
push @request, $p;
- $request_size += $size;
- $req_has_charptr |= $has_charptr;
- } elsif ($dir eq "OUT") {
+ $request_size += $buffer_size;
+ $req_size_is_indefinite |= $indefinite;
+ } elsif ($p->{dir} eq "OUT") {
push @reply, $p;
- $reply_size += $size;
- } elsif ($dir eq "INOUT") {
+ $reply_size += $buffer_size;
+ $rep_size_is_indefinite |= $indefinite;
+ } elsif ($p->{dir} eq "INOUT") {
push @reply, $p;
push @request, $p;
- $request_size += $size;
- $reply_size += $size;
- $req_has_charptr |= $has_charptr;
+ $request_size += $buffer_size;
+ $reply_size += $buffer_size;
+ $req_size_is_indefinite |= $indefinite;
+ $rep_size_is_indefinite |= $indefinite;
}
}
+ $func->{request} = \@request;
+ $func->{request_size} = $request_size unless ($req_size_is_indefinite);
+ $func->{req_has_charptr} = $req_has_charptr;
+ $func->{reply} = \@reply;
+ $func->{reply_size} = $reply_size unless ($rep_size_is_indefinite);
+
#print RXOUT "/* req max size: $request_size */\n";
#print RXOUT "/* rep max size: $reply_size */\n";
- emit_func_enc_request($func, $op, $request_size, $req_has_charptr, $reply_size, @request);
- emit_func_dec_reply($func, $op, $reply_size, @reply)
- if (@reply);
- emit_func_simple_sync_call($func, $request_size, $reply_size, \@request, \@reply, @params);
- emit_py_func_simple_sync_call($func, \@request, \@reply, @params);
+ calc_func_prototype($func);
+ emit_func_send_request($func);
+ if (@reply) {
+ emit_func_decode_reply($func);
+ } else {
+ emit_func_dummy_decode_reply($func);
+ }
+ emit_func_alloc_call($func);
+ emit_func_simple_sync_call($func);
+ emit_py_func_bulk_helper($func);
+ emit_py_func_simple_sync_call($func);
}
emit_py_module();
for vlserver in vladdrs:
print("Trying", vlserver);
- z_conn = kafs.rx_new_connection(vlserver, kafs.AFS_VL_PORT, kafs.VL_SERVICE);
+ z_conn = kafs.rx_new_connection(vlserver, kafs.VL_PORT, kafs.VL_SERVICE);
try:
ret = kafs.VL_Probe(z_conn);