1 /*******************************************************************************
2 
3     Test for AsyncIO.
4 
5     Copyright:
6         Copyright (c) 2018 dunnhumby Germany GmbH.
7         All rights reserved.
8 
9     License:
10         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
11         Alternatively, this file may be distributed under the terms of the Tango
12         3-Clause BSD License (see LICENSE_BSD.txt for details).
13 
14 *******************************************************************************/
15 
16 module integrationtest.asyncio.main;
17 
18 import ocean.meta.types.Qualifiers;
19 
20 import core.sys.posix.sys.stat;
21 import core.sys.posix.pthread;
22 import ocean.core.Test;
23 import ocean.sys.ErrnoException;
24 import ocean.util.app.DaemonApp;
25 import ocean.task.Scheduler;
26 import ocean.task.Task;
27 import ocean.util.aio.AsyncIO;
28 import ocean.io.device.File;
29 import ocean.util.test.DirectorySandbox;
30 
31 extern(C) int pthread_getattr_np(pthread_t thread, pthread_attr_t* attr);
32 
33 class AsyncIOUsingApp: DaemonApp
34 {
35     AsyncIO async_io;
36 
37     this ( )
38     {
39 
40         istring name = "Application";
41         istring desc = "Testing async IO";
42 
43         DaemonApp.OptionalSettings settings;
44         settings.use_task_ext = true;
45 
46         super(name, desc, VersionInfo.init, settings);
47     }
48 
49 
50     /// Per-thread context to be used by the delegate
51     class AioContext: AsyncIO.Context
52     {
53         void* thread_sp;
54     }
55 
56     /// Delegate to call once per thread to create and
57     /// initialize the thread context. Normally used
58     /// to initialize libraries needed for the callback
59     /// delegates
60     AsyncIO.Context makeContext()
61     {
62         auto ctx = new AioContext;
63 
64         pthread_attr_t attr;
65         void* stack_addr;
66         size_t stack_size;
67 
68         pthread_getattr_np(pthread_self(), &attr);
69         pthread_attr_getstack(&attr, &stack_addr, &stack_size);
70         pthread_attr_destroy(&attr);
71 
72         ctx.thread_sp = stack_addr;
73 
74         return ctx;
75     }
76 
77     /// counter value to set from the working thread
78     int counter;
79 
80     /// last thread's sp value
81     void* thread_sp;
82 
83     /// Callback called from another thread to set the counter
84     private void setCounter (AsyncIO.Context ctx)
85     {
86         auto myctx = cast(AioContext)ctx;
87 
88         this.thread_sp = myctx.thread_sp;
89         this.counter++;
90     }
91 
92     // Called after arguments and config file parsing.
93     override protected int run ( Arguments args, ConfigParser config )
94     {
95         this.async_io = new AsyncIO(theScheduler.epoll, 10, &makeContext);
96 
97         // open a new file
98         auto f = new File("var/output.txt", File.ReadWriteAppending);
99 
100         char[] buf = "Hello darkness, my old friend.".dup;
101         this.async_io.blocking.write(buf, f.fileHandle());
102 
103         buf[] = '\0';
104         this.async_io.blocking.pread(buf, f.fileHandle(), 0);
105 
106         test!("==")(buf[], "Hello darkness, my old friend.");
107         test!("==")(f.length, buf.length);
108 
109         this.async_io.blocking.callDelegate(&setCounter);
110         test!("==")(this.counter, 1);
111         test!("!is")(this.thread_sp, null);
112 
113         theScheduler.shutdown();
114         return 0; // return code to OS
115     }
116 }
117 
118 version (unittest) {} else
119 void main(istring[] args)
120 {
121 
122     initScheduler(SchedulerConfiguration.init);
123     theScheduler.exception_handler = (Task t, Exception e) {
124         throw e;
125     };
126 
127     auto sandbox = DirectorySandbox.create(["etc", "log", "var"]);
128 
129     File.set("etc/config.ini", "[LOG.Root]\n" ~
130                "console = false\n\n");
131 
132     auto app = new AsyncIOUsingApp;
133     auto ret = app.main(args);
134 }