source: libcfa/src/concurrency/io/call.cfa.in @ c402739

arm-ehjacob/cs343-translationnew-ast-unique-expr
Last change on this file since c402739 was c402739, checked in by Thierry Delisle <tdelisle@…>, 15 months ago

I/O operations now use futures.
io calls implementation are now generated at configure time.

  • Property mode set to 100644
File size: 14.9 KB
Line 
1#!python3
2#
3# Cforall Version 1.0.0 Copyright (C) 2020 University of Waterloo
4#
5# The contents of this file are covered under the licence agreement in the
6# file "LICENCE" distributed with Cforall.
7#
8# call.cfa.in -- Python script to generate io/call.cfa
9#
10# Author           : Thierry Delisle
11# Created On       : Fri Sep 11 12:41:16 2020
12# Last Modified By :
13# Last Modified On :
14# Update Count     :
15#
16
17Header = """//
18// Cforall Version 1.0.0 Copyright (C) 2020 University of Waterloo
19//
20// The contents of this file are covered under the licence agreement in the
21// file "LICENCE" distributed with Cforall.
22//
23// call.cfa -- Api for cforall
24//
25// Author           : Generated from call.cfa.in
26// Created On       : {}
27//
28
29"""
30
31Prelude = """#define __cforall_thread__
32
33#include "bits/defs.hfa"
34#include "kernel.hfa"
35
36//=============================================================================================
37// I/O uring backend
38//=============================================================================================
39
40#if defined(CFA_HAVE_LINUX_IO_URING_H)
41        #include <assert.h>
42        #include <stdint.h>
43        #include <errno.h>
44        #include <linux/io_uring.h>
45
46        #include "kernel/fwd.hfa"
47        #include "io/types.hfa"
48
49        #if defined(CFA_HAVE_IOSQE_FIXED_FILE) && defined(CFA_HAVE_IOSQE_IO_DRAIN) && defined(CFA_HAVE_IOSQE_ASYNC)
50                #define REGULAR_FLAGS (IOSQE_FIXED_FILE | IOSQE_IO_DRAIN | IOSQE_ASYNC)
51        #elif defined(CFA_HAVE_IOSQE_FIXED_FILE) && defined(CFA_HAVE_IOSQE_ASYNC)
52                #define REGULAR_FLAGS (IOSQE_FIXED_FILE | IOSQE_ASYNC)
53        #elif defined(CFA_HAVE_IOSQE_FIXED_FILE) && defined(CFA_HAVE_IOSQE_IO_DRAIN)
54                #define REGULAR_FLAGS (IOSQE_FIXED_FILE | IOSQE_IO_DRAIN)
55        #elif defined(CFA_HAVE_IOSQE_IO_DRAIN) && defined(CFA_HAVE_IOSQE_ASYNC)
56                #define REGULAR_FLAGS (IOSQE_IO_DRAIN | IOSQE_ASYNC)
57        #elif defined(CFA_HAVE_IOSQE_FIXED_FILE)
58                #define REGULAR_FLAGS (IOSQE_FIXED_FILE)
59        #elif defined(CFA_HAVE_IOSQE_IO_DRAIN)
60                #define REGULAR_FLAGS (IOSQE_IO_DRAIN)
61        #elif defined(CFA_HAVE_IOSQE_ASYNC)
62                #define REGULAR_FLAGS (IOSQE_ASYNC)
63        #else
64                #define REGULAR_FLAGS (0)
65        #endif
66
67        #if defined(CFA_HAVE_IOSQE_IO_LINK) && defined(CFA_HAVE_IOSQE_IO_HARDLINK)
68                #define LINK_FLAGS (IOSQE_IO_LINK | IOSQE_IO_HARDLINK)
69        #elif defined(CFA_HAVE_IOSQE_IO_LINK)
70                #define LINK_FLAGS (IOSQE_IO_LINK)
71        #elif defined(CFA_HAVE_IOSQE_IO_HARDLINK)
72                #define LINK_FLAGS (IOSQE_IO_HARDLINK)
73        #else
74                #define LINK_FLAGS (0)
75        #endif
76
77        #if defined(CFA_HAVE_SPLICE_F_FD_IN_FIXED)
78                #define SPLICE_FLAGS (SPLICE_F_FD_IN_FIXED)
79        #else
80                #define SPLICE_FLAGS (0)
81        #endif
82
83        extern [* struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data );
84        extern void __submit( struct io_context * ctx, __u32 idx ) __attribute__((nonnull (1)));
85
86        static inline io_context * __get_io_context( void ) {
87                cluster * cltr = active_cluster();
88
89                /* paranoid */ verifyf( cltr, "No active cluster for io operation\\n");
90                assertf( cltr->io.cnt > 0, "Cluster %p has no default io contexts and no context was specified\\n", cltr );
91
92                /* paranoid */ verifyf( cltr->io.ctxs, "default io contexts for cluster %p are missing\\n", cltr);
93                return &cltr->io.ctxs[ __tls_rand() % cltr->io.cnt ];
94        }
95#endif
96
97//=============================================================================================
98// I/O Forwards
99//=============================================================================================
100#include <time.hfa>
101
102// Some forward declarations
103#include <errno.h>
104#include <unistd.h>
105
106extern "C" {
107        #include <sys/types.h>
108        #include <sys/socket.h>
109        #include <sys/syscall.h>
110
111#if defined(HAVE_PREADV2)
112        struct iovec;
113        extern ssize_t preadv2 (int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags);
114#endif
115#if defined(HAVE_PWRITEV2)
116        struct iovec;
117        extern ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags);
118#endif
119
120        extern int fsync(int fd);
121
122        #if __OFF_T_MATCHES_OFF64_T
123                typedef __off64_t off_t;
124        #else
125                typedef __off_t off_t;
126        #endif
127        typedef __off64_t off64_t;
128        extern int sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags);
129
130        struct msghdr;
131        struct sockaddr;
132        extern ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
133        extern ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
134        extern ssize_t send(int sockfd, const void *buf, size_t len, int flags);
135        extern ssize_t recv(int sockfd, void *buf, size_t len, int flags);
136        extern int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
137        extern int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
138
139        extern int fallocate(int fd, int mode, off_t offset, off_t len);
140        extern int posix_fadvise(int fd, off_t offset, off_t len, int advice);
141        extern int madvise(void *addr, size_t length, int advice);
142
143        extern int openat(int dirfd, const char *pathname, int flags, mode_t mode);
144        extern int close(int fd);
145
146        extern ssize_t read (int fd, void *buf, size_t count);
147
148        struct epoll_event;
149        extern int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
150
151        extern ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags);
152        extern ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags);
153}
154
155//=============================================================================================
156// I/O Interface
157//=============================================================================================
158"""
159
160print(Header.format("A Date"))
161print(Prelude)
162
163import re
164import sys
165class Call:
166        def __init__(self, op, signature, body, define=None):
167                sig = re.search("(.*) (.*)\((.*)\)", signature)
168                if not sig:
169                        print("OP '{}' has invalid signature {}".format(op, signature), file=sys.stderr)
170                        sys.exit(1)
171
172                self.op     = op
173                self.ret    = sig.group(1)
174                self.name   = sig.group(2)
175                self.params = sig.group(3)
176                self.define = define
177                self.body = ""
178
179                accepted_keys = [ 'ioprio', 'fd', 'off', 'addr2','addr', 'splice_off_in','len',
180                        'rw_flags', 'fsync_flags', 'poll_events', 'poll32_events',
181                        'sync_range_flags', 'msg_flags', 'timeout_flags', 'accept_flags',
182                        'cancel_flags', 'open_flags', 'statx_flags', 'fadvise_advice',
183                        'splice_flags', 'buf_index' ,'buf_group' 'personality',
184                        'splice_fd_in' ]
185
186                for k, v in body.items():
187                        if not k in accepted_keys:
188                                print("OP '{}' has invalid body kew {}".format(op, k), file=sys.stderr)
189                                sys.exit(1)
190
191                        self.body += "\n                sqe->{key} = {value};".format(key=k, value=v)
192
193
194        def args(self):
195                param_a = self.params.split(',')
196                args_a = [p.replace('*', ' ').split()[-1] for p in param_a]
197                for a in args_a:
198                        if '*' in a:
199                                print("OP '{}' has invalid * in argument {}".format(self.op, a), file=sys.stderr)
200                                sys.exit(1)
201
202                return ', '.join(args_a)
203
204AsyncTemplate = """inline void async_{name}(io_future_t & future, {params}, int submit_flags, io_cancellation * cancellation, io_context * context) {{
205        #if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_{op})
206                ssize_t res = {name}({args});
207                if (res >= 0) {{
208                        fulfil(future, res);
209                }}
210                else {{
211                        fulfil(future, -errno);
212                }}
213        #else
214                // we don't support LINK yet
215                if( 0 != (submit_flags & LINK_FLAGS) ) {{
216                        errno = ENOTSUP; return -1;
217                }}
218
219                if( !context ) {{
220                        context = __get_io_context();
221                }}
222                if(cancellation) {{
223                        cancellation->target = (__u64)(uintptr_t)&future;
224                }}
225
226                __u8 sflags = REGULAR_FLAGS & submit_flags;
227                struct __io_data & ring = *context->thrd.ring;
228
229                __u32 idx;
230                struct io_uring_sqe * sqe;
231                [sqe, idx] = __submit_alloc( ring, (__u64)(uintptr_t)&future );
232
233                sqe->__pad2[0] = sqe->__pad2[1] = sqe->__pad2[2] = 0;
234                sqe->opcode = IORING_OP_{op};
235                sqe->flags = sflags;{body}
236
237                verify( sqe->user_data == (__u64)(uintptr_t)&future );
238                __submit( context, idx );
239        #endif
240}}"""
241
242SyncTemplate = """{ret} cfa_{name}({params}, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {{
243        if( timeout >= 0 ) {{
244                errno = ENOTSUP;
245                return -1;
246        }}
247        io_future_t future;
248
249        async_{name}( future, {args}, submit_flags, cancellation, context );
250
251        wait( future );
252        if( future.result < 0 ) {{
253                errno = -future.result;
254                return -1;
255        }}
256        return future.result;
257}}"""
258
259calls = [
260        # CFA_HAVE_IORING_OP_READV
261        Call('READV', 'ssize_t preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags)', {
262                'fd'  : 'fd',
263                'off' : 'offset',
264                'addr': '(__u64)iov',
265                'len' : 'iovcnt',
266        }, define = 'CFA_HAVE_PREADV2'),
267        # CFA_HAVE_IORING_OP_WRITEV
268        Call('WRITEV', 'ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags)', {
269                'fd'  : 'fd',
270                'off' : 'offset',
271                'addr': '(__u64)iov',
272                'len' : 'iovcnt'
273        }, define = 'CFA_HAVE_PWRITEV2'),
274        # CFA_HAVE_IORING_OP_FSYNC
275        Call('FSYNC', 'int fsync(int fd)', {
276                'fd': 'fd'
277        }),
278        # CFA_HAVE_IORING_OP_EPOLL_CTL
279        Call('EPOLL_CTL', 'int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)', {
280                'fd': 'epfd',
281                'addr': 'fd',
282                'len': 'op',
283                'off': '(__u64)event'
284        }),
285        # CFA_HAVE_IORING_OP_SYNC_FILE_RANGE
286        Call('SYNC_FILE_RANGE', 'int sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags)', {
287                'fd': 'fd',
288                'off': 'offset',
289                'len': 'nbytes',
290                'sync_range_flags': 'flags'
291        }),
292        # CFA_HAVE_IORING_OP_SENDMSG
293        Call('SENDMSG', 'ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)', {
294                'fd': 'sockfd',
295                'addr': '(__u64)(struct msghdr *)msg',
296                'len': '1',
297                'msg_flags': 'flags'
298        }),
299        # CFA_HAVE_IORING_OP_RECVMSG
300        Call('RECVMSG', 'ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)', {
301                'fd': 'sockfd',
302                'addr': '(__u64)(struct msghdr *)msg',
303                'len': '1',
304                'msg_flags': 'flags'
305        }),
306        # CFA_HAVE_IORING_OP_SEND
307        Call('SEND', 'ssize_t send(int sockfd, const void *buf, size_t len, int flags)', {
308                'fd': 'sockfd',
309                'addr': 'buf',
310                'len': 'len',
311                'msg_flags': 'flags'
312        }),
313        # CFA_HAVE_IORING_OP_RECV
314        Call('RECV', 'ssize_t recv(int sockfd, void *buf, size_t len, int flags)', {
315                'fd': 'sockfd',
316                'addr': 'buf',
317                'len': 'len',
318                'msg_flags': 'flags'
319        }),
320        # CFA_HAVE_IORING_OP_ACCEPT
321        Call('ACCEPT4', 'int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)', {
322                'fd': 'sockfd',
323                'addr': 'addr',
324                'addr2': 'addrlen',
325                'accept_flags': 'flags'
326        }),
327        # CFA_HAVE_IORING_OP_CONNECT
328        Call('CONNECT', 'int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)', {
329                'fd': 'sockfd',
330                'addr': 'addr',
331                'off': 'addrlen'
332        }),
333        # CFA_HAVE_IORING_OP_FALLOCATE
334        Call('FALLOCATE', 'int fallocate(int fd, int mode, off_t offset, off_t len)', {
335                'fd': 'fd',
336                'addr': '(__u64)len',
337                'len': 'mode',
338                'off': 'offset'
339        }),
340        # CFA_HAVE_IORING_OP_FADVISE
341        Call('FADVISE', 'int posix_fadvise(int fd, off_t offset, off_t len, int advice)', {
342                'fd': 'fd',
343                'off': 'off',
344                'len': 'len',
345                'fadvise_advice': 'advice'
346        }),
347        # CFA_HAVE_IORING_OP_MADVISE
348        Call('MADVISE', 'int madvise(void *addr, size_t length, int advice)', {
349                'addr': 'addr',
350                'len': 'length',
351                'fadvise_advice': 'advice'
352        }),
353        # CFA_HAVE_IORING_OP_OPENAT
354        Call('OPENAT', 'int openat(int dirfd, const char *pathname, int flags, mode_t mode)', {
355                'fd': 'dirfd',
356                'off': 'offset',
357                'addr': '(__u64)pathname',
358                'len': 'mode',
359                'open_flags': 'flags;'
360        }),
361        # CFA_HAVE_IORING_OP_OPENAT2
362        Call('OPENAT2', 'int openat2(int dirfd, const char *pathname, struct open_how * how, size_t size)', {
363                'fd': 'dirfd',
364                'addr': 'pathname',
365                'len': 'sizeof(*how)',
366                'off': '(__u64)how',
367        }, define = 'CFA_HAVE_OPENAT2'),
368        # CFA_HAVE_IORING_OP_CLOSE
369        Call('CLOSE', 'int close(int fd)', {
370                'fd': 'fd'
371        }),
372        # CFA_HAVE_IORING_OP_STATX
373        Call('STATX', 'int statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf)', {
374                'fd': 'dirfd',
375                'off': '(__u64)statxbuf',
376                'addr': 'pathname',
377                'len': 'mask',
378                'statx_flags': 'flags'
379        }, define = 'CFA_HAVE_STATX'),
380        # CFA_HAVE_IORING_OP_READ
381        Call('READ', 'ssize_t read(int fd, void * buf, size_t count)', {
382                'fd': 'fd',
383                'addr': 'buf',
384                'len': 'count'
385        }),
386        # CFA_HAVE_IORING_OP_WRITE
387        Call('WRITE', 'ssize_t write(int fd, void * buf, size_t count)', {
388                'fd': 'fd',
389                'addr': 'buf',
390                'len': 'count'
391        }),
392        # CFA_HAVE_IORING_OP_SPLICE
393        Call('SPLICE', 'ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags)', {
394                'splice_fd_in': 'fd_in',
395                'splice_off_in': 'off_in ? *off_in : -1',
396                'fd': 'fd_out',
397                'off': 'off_out ? *off_out : -1',
398                'len': 'len',
399                'splice_flags': 'flags'
400        }),
401        # CFA_HAVE_IORING_OP_TEE
402        Call('TEE', 'ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags)', {
403                'splice_fd_in': 'fd_in',
404                'fd': 'fd_out',
405                'len': 'len',
406                'splice_flags': 'flags'
407        })
408]
409
410print("//----------")
411print("// synchronous calls")
412for c in calls:
413        if c.define:
414                print("""#if defined({define})
415        {ret} cfa_{name}({params}, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
416#endif""".format(define=c.define,ret=c.ret, name=c.name, params=c.params))
417        else:
418                print("{ret} cfa_{name}({params}, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);"
419                .format(ret=c.ret, name=c.name, params=c.params))
420
421print("\n//----------")
422print("// asynchronous calls")
423for c in calls:
424        if c.define:
425                print("""#if defined({define})
426        void async_{name}(io_future_t & future, {params}, int submit_flags, io_cancellation * cancellation, io_context * context);
427#endif""".format(define=c.define,name=c.name, params=c.params))
428        else:
429                print("void async_{name}(io_future_t & future, {params}, int submit_flags, io_cancellation * cancellation, io_context * context);"
430                .format(name=c.name, params=c.params))
431print("\n")
432
433for c in calls:
434        print("//-----------------------------------------------------------------------------")
435        print("// {}".format(c.name))
436        Async = AsyncTemplate.format(
437                name   = c.name,
438                ret    = c.ret,
439                params = c.params,
440                args   = c.args(),
441                op     = c.op,
442                body   = c.body
443
444        )
445        Sync = SyncTemplate.format(
446                name   = c.name,
447                ret    = c.ret,
448                params = c.params,
449                args   = c.args()
450        )
451
452        if c.define:
453                print("""#if defined({})
454        //----------
455        // asynchronous call
456        {}
457
458        //----------
459        // synchronous call
460        {}
461#endif
462""".format(c.define, "\n\t".join( Async.splitlines() ), "\n\t".join( Sync.splitlines() )))
463        else :
464                print("""//----------
465// asynchronous call
466{}
467
468//----------
469// synchronous call
470{}
471""".format(Async, Sync))
472
473print("""
474//-----------------------------------------------------------------------------
475// Check if a function is has asynchronous
476bool has_user_level_blocking( fptr_t func ) {
477        #if defined(CFA_HAVE_LINUX_IO_URING_H)""")
478
479for c in calls:
480        if c.define:
481                print("""               #if defined({define})
482                        if( /*func == (fptr_t)preadv2 || */
483                                func == (fptr_t)cfa_{name} ||
484                                func == (fptr_t)async_{name} ) {{
485                                #if defined(CFA_HAVE_IORING_OP_{op})
486                                        return true;
487                                #else
488                                        return false;
489                                #endif
490                        }}
491                #endif""".format(define=c.define, name=c.name, op=c.op))
492        else:
493                print("""               if( /*func == (fptr_t)preadv2 || */
494                        func == (fptr_t)cfa_{name} ||
495                        func == (fptr_t)async_{name} ) {{
496                        #if defined(CFA_HAVE_IORING_OP_{op})
497                                return true;
498                        #else
499                                return false;
500                        #endif
501                }}""".format(name=c.name, op=c.op))
502
503print("""       #endif
504
505        return false;
506}""")
Note: See TracBrowser for help on using the repository browser.