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

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 2fab24e3 was ec19b21, checked in by Thierry Delisle <tdelisle@…>, 4 years ago

Fixed compile for older versions of io_uring

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