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