├── LICENSE ├── README.md ├── docs ├── asyncio.md ├── flowcontrol.md ├── functor.md ├── kernel.md ├── scheduler.md └── tabutils.md ├── examples └── example_when_time.lua ├── rockspec ├── schedlua-0.1-1.rockspec ├── schedlua-0.1-2.rockspec └── schedlua-0.1-3.rockspec ├── schedlua ├── alarm.lua ├── kernel.lua ├── linux │ ├── epollio.lua │ ├── linux_errno.lua │ ├── linux_ffi.lua │ ├── linux_net.lua │ ├── lookupsite.lua │ ├── nativesocket.lua │ └── timeticker.lua ├── net.lua ├── predicate.lua ├── queue.lua ├── scheduler.lua ├── stopwatch.lua ├── tabutils.lua ├── task.lua └── windows │ ├── arch.lua │ ├── asyncio.lua │ ├── basetsd.lua │ ├── core_errorhandling_l1_1_1.lua │ ├── core_io_l1_1_1.lua │ ├── guiddef.lua │ ├── iocompletionset.lua │ ├── ioops.lua │ ├── iotracker.lua │ ├── ntstatus.lua │ ├── timeticker.lua │ ├── winbase.lua │ └── wtypes.lua └── testy ├── application.lua ├── collections.lua ├── functor.lua ├── linux_timespec.lua ├── lookupsite.lua ├── siteextractor.lua ├── sites.lua ├── test_alarm_delay.lua ├── test_alarm_periodic.lua ├── test_alarm_sleep.lua ├── test_async_socket.lua ├── test_http_barrier.lua ├── test_http_probe.lua ├── test_kernel.lua ├── test_kernel_signal.lua ├── test_kernel_signal2.lua ├── test_linux_net.lua ├── test_predicate_wait.lua ├── test_predicate_when.lua ├── test_predicate_whenever.lua ├── test_queue.lua ├── test_scheduler.lua └── test_stopwatch.lua /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 William Adams 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | schedlua is a set of routines that make it relatively easy to create cooperative 2 | multi-tasking applications in LuaJIT. 3 | 4 | Design criteria 5 | - Simplicity through minimal coding 6 | - Complexity by composition rather than complex structures 7 | - Compactness through reuse 8 | - minimal number of concepts 9 | - implied operations where possible 10 | 11 | The lua programming language is great for multi-tasking because it already contains 12 | the notion of co-routines. This mechanism provides the means to readily 13 | compartmentalize operations into easily coded sections. The challenge of this 14 | method of multi-tasking is that it is cooperative, and you end up with a 15 | management challenge as the number of independently operating tasks increases. 16 | 17 | schedlua provides a couple of key features which make multi-task programming 18 | with lua a lot more manageable. The first is easy scheduling of tasks. In a 19 | cooperative multi-tasking environment, scheduling is nothing more than deciding 20 | which task should run next after the currently running task decides to yield. 21 | schedlua provides a relatively simple scheduling mechanism which deals with this 22 | selection process. 23 | 24 | The second feature schedlua provides is a series of well named functions which 25 | further enable typical multi-tasking tasks. At the core there are routines that 26 | handle signaling (events). A task can emit events, as well as wait on events. 27 | Built atop the signaling is a relatively new but useful paradign named predicate 28 | flow control. This is basically the async equivalent of if/then blocks. There 29 | are alarms, which provide mechanism for sleeping and delaying executing, and 30 | last, there is async io operations, particularly as they relate to network 31 | programming. 32 | 33 | 34 | 35 | Here is a typical application: 36 | 37 | ```lua 38 | local Kernel = require("schedlua.kernel") 39 | 40 | 41 | local function task1() 42 | print("first task, first line") 43 | yield(); 44 | print("first task, second line") 45 | halt(); 46 | end 47 | 48 | local function task2() 49 | print("second task, only line") 50 | end 51 | 52 | local function main() 53 | local t1 = spawn(task1) 54 | local t2 = spawn(task2) 55 | end 56 | 57 | run(main) 58 | ``` 59 | 60 | All applications must begin by including the schedlua.kernel module. 61 | All applications begin execution by explicitly calling the 'run()' function. 62 | The run() function takes an optional function to be executed, so it is 63 | convenient the create a single function, which in turn has all the code 64 | that you want to execute. 65 | 66 | Within this example, there are two calls to the spawn() function. Each 67 | call to this function will create a separate cooperative task, which will 68 | in turn be added to the scheduler for execution. A call to 'spawn' does 69 | not cause the task to execute immediately, but merely to be scheduled for execution. 70 | 71 | The runtime will constantly step through the list of tasks ready to be run, 72 | executing them in turn until each of them reaches a point where they will 73 | yield, and allow for another task to run. 74 | 75 | Example Using Time and Predicates 76 | ================================= 77 | 78 | ```lua 79 | --[[ 80 | An example of how to use time, predicates 81 | and multiple tasks. 82 | --]] 83 | 84 | local Kernel = require("schedlua.kernel") 85 | local StopWatch = require("schedlua.stopwatch") 86 | 87 | local sw = StopWatch(); 88 | 89 | 90 | -- A simple conditional which will return true 91 | -- once we pass 12 seconds according to the clock 92 | local function timeExpires() 93 | return sw:seconds() > 12 94 | end 95 | 96 | -- The response to be executed once we reach 97 | -- a time of 12 seconds 98 | local function revertToForm() 99 | print("Time: ", sw:seconds()) 100 | print("The carriage has reverted to a pumpkin") 101 | halt(); 102 | end 103 | 104 | 105 | -- The response which will be executed whenever 106 | -- we pass another second 107 | local function printTime() 108 | print("Time: ", sw:seconds()) 109 | end 110 | 111 | 112 | -- Stitching it all together 113 | local function main() 114 | periodic(1000, printTime) 115 | when(timeExpires, revertToForm) 116 | end 117 | 118 | run(main) 119 | ``` 120 | 121 | In this example, the timer function 'periodic' is being used, as well as the 122 | predicate function 'when'. The periodic function is simply executing the 123 | 'printTime' function once every second (1000 milliseconds). By calling 124 | 'periodic', a cooperative task is scheduled, and the program continues on 125 | to the next statement, which is the 'when' call. The 'when()' function takes 126 | two parameters. The first is a function which always returns a non-false 127 | value, or false. When the function returns a non-false value, it will 128 | then execute the second parameter, which should be a function. In this case 129 | the 'revertToForm()' function. 130 | 131 | So, overall, the example will print the current running time, once a second, and 132 | after 12 seconds, it will print a message, and halt() the program. 133 | 134 | 135 | References 136 | ========== 137 | * Blog Entries 138 | * https://williamaadams.wordpress.com/?s=schedlua 139 | -------------------------------------------------------------------------------- /docs/asyncio.md: -------------------------------------------------------------------------------- 1 | asyncio 2 | ======= 3 | 4 | Performing asynchronous IO operations is one of the areas of fundamental 5 | difference between Linux and Windows. Both platforms allow for the performance 6 | of async IO operations, but they do them slightly differently. 7 | 8 | On Linux, there are many mechanisms available, from kernel supported asio routines 9 | to higher level library routines. The mechanism employed by schedlua is epoll. 10 | 11 | With epoll, you essentially query a file descriptor to see if it is ready 12 | for a specified operation to occur without blocking. For example, if you want 13 | to read from a network socket, you would perform the following operations: 14 | 15 | ```lua 16 | function AsyncSocket.read(self, buff, bufflen) 17 | 18 | local success, err = asyncio:waitForIOEvent(self.fdesc, self.ReadEvent); 19 | 20 | --print(string.format("AsyncSocket.read(), after wait: 0x%x %s", success, tostring(err))) 21 | 22 | if not success then 23 | print("AsyncSocket.read(), FAILED WAITING: ", string.format("0x%x",err)) 24 | return false, err; 25 | end 26 | 27 | 28 | local bytesRead = 0; 29 | 30 | if band(success, epoll.EPOLLIN) > 0 then 31 | bytesRead, err = self.fdesc:read(buff, bufflen); 32 | --print("async_read(), bytes read: ", bytesRead, err) 33 | end 34 | 35 | return bytesRead, err; 36 | end 37 | ``` 38 | 39 | The first operation is to wait for readiness to read. Then, assuming it's ready, perform 40 | the read operation on the file descriptor, returning the number of bytes actually read. 41 | 42 | Windows takes an almost opposite approach. Rather than waiting until the file descriptor is ready to be read, you perform the read operation, and wait to be told when 43 | the operation was completed. 44 | 45 | ```lua 46 | fd:read(buff, bufflen) 47 | waitForCompletion(fd) 48 | ``` 49 | 50 | It's challenging to make these two different paradigms appear the same as an abstraction, 51 | so the approach taken in schedlua is to provide objects that are surfaced from the 52 | platform specific, and generalize there. So, there is a nativesocket, nativefiledescriptor, and the like. Any generalizations will be peformed atop these 53 | native objects. 54 | -------------------------------------------------------------------------------- /docs/flowcontrol.md: -------------------------------------------------------------------------------- 1 | Flow Control 2 | ============ 3 | 4 | The 'if-then-else' construct is the most usual mechanism for flow control in 5 | a typical serial application. Schedlua introduces a few more constructs which 6 | make it easier to reason about programming in a multi-tasking environment. 7 | 8 | At the core of any flow control construct is a boolean test. 9 | ```lua 10 | if conditionisTrue then 11 | performsomeaction() 12 | end 13 | ``` 14 | 15 | In a single tasking environment, this is easy to understand, as when the 16 | condition is true, the action is performed, otherwise it is not. 17 | 18 | The first flow control construct schedlua introduces is that of the 19 | suspending a task until a particular condition is met. So, whereas the 20 | simple 'if' statement is a one time test, 'waitForTruth' will suspend 21 | the task indefinitely, until the condition is met. 22 | 23 | ```lua 24 | local counter = 0; 25 | local function counterIsFive() 26 | counter = counter + 1; 27 | if counter >= 5 then return true end 28 | 29 | return false 30 | end 31 | 32 | -- executing some code serially 33 | waitForTruth(counterIsFive) 34 | 35 | -- continue to execute 36 | print(counter) 37 | ``` 38 | 39 | In this case, the task that is currently executing will be suspended when it makes 40 | the call to 'waitForTruth'. It will remain in this suspended state as long as the 41 | 'somecondition' function returns 'false'. Once it returns true, the task will 42 | continue from the point at which it was suspended. 43 | 44 | Suspending the current task in place is useful, and most similar to a simple while loop. 45 | What if you want to disassociate the conditional check from the current task, and 46 | essentially just have some bit of code execute cooperatively when the condition 47 | proves to be true? 48 | 49 | `when(conditionisTrue, action)` 50 | 51 | The implementation of this construct is the following: 52 | ```lua 53 | local function when(pred, func) 54 | local function closure(lpred, lfunc) 55 | waitForPredicate(lpred) 56 | lfunc() 57 | end 58 | 59 | return spawn(closure, pred, func) 60 | end 61 | ``` 62 | 63 | This is a matter of convenience. A task is spawned which will be suspended until 64 | the condition is true. Once the condition is true, the specified action will 65 | be performed. 66 | 67 | This is similar to the signaling construct, but the 'signal' is given by a function 68 | returning a true value, rather than some other mechanism. The truth is, the signaling 69 | mechanism with schedlua is actually at the core of the implementation of the 70 | waitForPredicate() function. 71 | 72 | 73 | Another supported construct is when you want to perform the action repeatedly, 74 | rather than doing a one shot, as is the case with the 'when' construct. The 'whenever' 75 | construct will serve this purpose. 76 | 77 | `whenever(condition, action)` 78 | 79 | In this case, once the condition returns 'true', the action is performed, and the 80 | condition continues to be check, and the action continues to be performed for each 81 | 'true' value. This will go on forever. 82 | 83 | In other environments, signaling and callbacks are supported. At their core, these 84 | constructs are very similar. The ways in which they differ are perhaps subtle, but 85 | very useful. First is the naming itself. In English, it's fairly easy to understand 86 | the words 'when', and 'whenever', and even 'waitForTruth'. That makes forming a program 87 | with these constructs fairly easy to remember. The more subtle aspect though is the 88 | usage of implied spawned tasks. This essentially decouples that condition and execution 89 | from the calling site. You do not end up with long chains of callback branches, where 90 | you need to keep track of failure states. You essentially just write simple code 91 | which is strung together with fairly simple statements. 92 | 93 | Here is a program which spawns a task which is a counter, and then 94 | uses the 'when' construct to halt the program once we have determined 95 | counting has finished. 96 | 97 | ```lua 98 | local Kernel = require("schedlua.kernel") 99 | 100 | local idx = 0; 101 | local maxidx = 20; 102 | 103 | 104 | local function counter(name, nCount) 105 | for num=1, nCount do 106 | idx = num 107 | yield(); 108 | end 109 | end 110 | 111 | local function countingFinished() 112 | return idx >= maxidx; 113 | end 114 | 115 | local function main() 116 | local t1 = spawn(counter, "counter", maxidx) 117 | 118 | when(countingFinished, halt) 119 | end 120 | 121 | run(main) 122 | ``` 123 | 124 | 125 | Here is another program, which uses the 'whenever' construct to repeatedly perform 126 | actions based on some conditions. It also uses the signaling mechanism to 127 | halt the program, just to show how these two can be mixed. 128 | 129 | ```lua 130 | local Kernel = require("schedlua.kernel") 131 | 132 | local idx = 0; 133 | local maxidx = 20; 134 | 135 | 136 | local function counter(name, nCount) 137 | for num=1, nCount do 138 | idx = num 139 | local eventName = name..tostring(idx); 140 | print(eventName, idx) 141 | signalOne(eventName); 142 | 143 | yield(); 144 | end 145 | 146 | signalAll(name..'-finished') 147 | end 148 | 149 | local function every5() 150 | local lastidx = 0; 151 | 152 | while idx <= maxidx do 153 | waitForPredicate(function() return (idx % 5) == 0 end) 154 | if idx > lastidx then 155 | print("!! matched 5 !!") 156 | lastidx = idx; 157 | --yield(); 158 | end 159 | end 160 | end 161 | 162 | local function test_whenever(modulus) 163 | local lastidx = 0; 164 | 165 | local function modulustest() 166 | --print("modulustest: ", idx, lastidx, maxidx) 167 | if idx > maxidx then 168 | return false; 169 | end 170 | 171 | if idx > lastidx then 172 | lastidx = idx; 173 | return (idx % modulus) == 0 174 | end 175 | end 176 | 177 | local t1 = whenever(modulustest, function() print("== EVERY: ", modulus) end) 178 | 179 | return t1; 180 | end 181 | 182 | local function main() 183 | local t1 = spawn(counter, "counter", maxidx) 184 | 185 | test_whenever(2); 186 | test_whenever(5); 187 | 188 | 189 | -- setup to call halt when counting is finished 190 | onSignal("counter-finished", halt) 191 | end 192 | 193 | run(main) 194 | ``` 195 | 196 | So, that is how you can begin to construct multi-tasking programs using the 197 | 'when' and 'whenever' constructs. They are essentially a combination of 198 | a signal and a spawn, and in the case of whenever, a repeating loop. 199 | -------------------------------------------------------------------------------- /docs/functor.md: -------------------------------------------------------------------------------- 1 | functor 2 | ======= 3 | 4 | A functor is a function that can stand in for another function. 5 | It is somewhat of an object because it retains a certain amount 6 | of state. In this case, it retains the target object, if there is 7 | any. 8 | 9 | This is fairly useful when you need to call a function on an object 10 | at a later time. 11 | 12 | Normally, if the object is constructed thus: 13 | 14 | ```lua 15 | function obj.func1(self, params) 16 | end 17 | ``` 18 | 19 | You would call the function thus: 20 | `objinstance:func1(params)` 21 | 22 | which is really 23 | `obj.func1(objinstance, params)` 24 | 25 | The object instance is passed into the function as the 'self' parameter 26 | before the other parameters. 27 | 28 | This is easy enough, but when you want to store a reference to the function 29 | to be called in a table? It's easy enough to store 'obj.func1', but what 30 | about the instance value? We must retain the 'objinstance' somewhere. 31 | 32 | This is where the Functor comes in. It will store both the object instance 33 | (target, if there is one) and the function reference for later execution. 34 | 35 | You can use it like this: 36 | 37 | ```lua 38 | funcs = { 39 | routine1 = Functor(obj.func1, someobj); 40 | routine2 = Functor(obj.func1, someobj2); 41 | routine3 = Functor(obj.func2, someobj); 42 | } 43 | ``` 44 | 45 | Then use it as: 46 | ```lua 47 | funcs.routine1(params); 48 | funcs.routine3(params); 49 | ``` 50 | -------------------------------------------------------------------------------- /docs/kernel.md: -------------------------------------------------------------------------------- 1 | kernel 2 | ====== 3 | Schedlua is a multi-tasking environment. It supports the easy creation of applications 4 | that utilize multiple cooperating tasks, and managing the complex interactions of those 5 | tasks. 6 | 7 | Any program that uses schedlua must begin by including the 'schedlua.kernel' module. 8 | 9 | local Kernel = require("schedlua.kernel") 10 | 11 | There is only a single Kernel module for any given lua state, so even though you can 12 | include the module multiple times, you will only have a single instance. 13 | 14 | Once you include this module, it will add several functions to the global namespace. 15 | they are the following. 16 | 17 | Runtime management 18 | ================== 19 | run 20 | halt 21 | 22 | Task management 23 | =============== 24 | coop 25 | suspend 26 | yield 27 | 28 | Signaling 29 | ========= 30 | onSignal 31 | signalTasks 32 | signalOne 33 | signalAll 34 | signalAllImmediate 35 | waitForSignal 36 | 37 | Predicates 38 | ========== 39 | signalOnPredicate 40 | waitForTruth 41 | when 42 | whenever 43 | 44 | Alarms 45 | ====== 46 | delay 47 | periodic 48 | sleep 49 | 50 | IO Events 51 | ========= 52 | waitForIOEvent 53 | watchForIOEvents 54 | 55 | -------------------------------------------------------------------------------- /docs/scheduler.md: -------------------------------------------------------------------------------- 1 | scheduler 2 | ========= 3 | 4 | The scheduler is the primary mechanism used to organize and coordinate 5 | which task is to be run at any given time. The application is essentially 6 | a single thread of execution, but tasks will relinquish control at 7 | convenient times in order to allow other tasks to perform until they 8 | relinquish control. 9 | 10 | The scheduler maintains a ReadyToRun list, which is essentially a queue 11 | of the tasks which have been scheduled to run, through calling the 12 | 'scheduleTask()' function. 13 | 14 | Through repeated calls to the 'step()' function, each task is retrieved 15 | from the ReadyToRun list, and resumed. Once the task performs a 'yield()' 16 | it goes back on the ReadyToRun list, and the next task from the list 17 | is executed. 18 | 19 | The scheduler as currently implemented uses a simple queue as the 20 | ReadyToRun list. This provides for an easy to understand 21 | first in first out (FIFO) management mechanism. That is, all tasks 22 | are considered equal, and they are executed in the order in which 23 | they were added to the schedule. 24 | 25 | There is a convenience method for putting a task at the front of the list. 26 | Calling scheduleTask(self, task, params, priority), with a priority of '0' 27 | will cause the tasks to be placed at the beginning of the list, to be 28 | executed next. 29 | 30 | This rudimentary prioritization should be used sparinging. If a high 31 | priority task is placed at the front of the list repeatedly, it could 32 | cause starvation of the other tasks, and they will never get a chance 33 | to be run. 34 | 35 | -------------------------------------------------------------------------------- /docs/tabutils.md: -------------------------------------------------------------------------------- 1 | 2 | We have need to maintain a table in a sorted order. We want to be able 3 | to insert into and remove values from that table easily. The couple of 4 | routines here offer a relatively easy binary search mechanism to maintain 5 | table order. 6 | 7 | It's good for a few hundred, or couple thousand entries, so you don't have 8 | to resort to a more interesting data structure such as b-tree for small things. 9 | 10 | Usage: 11 | bininsert( tbl, value [, comp] ) 12 | 13 | Inserts a given value through BinaryInsert into the table sorted by [, comp]. 14 | 15 | If 'comp' is given, it is a function that is used to compare two values 16 | in the table. It must be a function that receives two table elements, 17 | and returns true when the first is less than the second, depending on the sort order 18 | 19 | example: 20 | local function comp(a, b) 21 | return a > b 22 | end 23 | 24 | will give a sorted table, with the biggest value on position 1. 25 | 26 | [, comp] behaves as in table.sort(table, value [, comp]) 27 | 28 | returns the index where 'value' was inserted 29 | -------------------------------------------------------------------------------- /examples/example_when_time.lua: -------------------------------------------------------------------------------- 1 | --test_stopwatch.lua 2 | 3 | --[[ 4 | An example of how to use time, predicates 5 | and multiple tasks. 6 | --]] 7 | 8 | local Kernel = require("schedlua.kernel") 9 | local StopWatch = require("schedlua.stopwatch") 10 | 11 | local sw = StopWatch(); 12 | 13 | 14 | -- A simple conditional which will return true 15 | -- once we pass 12 seconds according to the clock 16 | local function timeExpires() 17 | return sw:seconds() > 12 18 | end 19 | 20 | -- The response to be executed once we reach 21 | -- a time of 12 seconds 22 | local function revertToForm() 23 | print("Time: ", sw:seconds()) 24 | print("The carriage has reverted to a pumpkin") 25 | halt(); 26 | end 27 | 28 | 29 | -- The response which will be executed whenever 30 | -- we pass another second 31 | local function printTime() 32 | print("Time: ", sw:seconds()) 33 | end 34 | 35 | 36 | -- Stitching it all together 37 | local function main() 38 | periodic(1000, printTime) 39 | when(timeExpires, revertToForm) 40 | end 41 | 42 | run(main) 43 | -------------------------------------------------------------------------------- /rockspec/schedlua-0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "schedlua" 2 | version = "0.1-1" 3 | 4 | source = { 5 | url = "https://github.com/wiladams/schedlua", 6 | tag = "v0.1-1" 7 | } 8 | 9 | description = { 10 | summary = "Scheduled cooperative task kernel written in LuaJIT", 11 | detailed = [[ 12 | LuaJIT based kernel which provides easy cooperative multi-tasking 13 | environment. The kernel supports signaling, alarms (sleep, delay, periodic) 14 | as well as seamless async io without forcing the use of callbacks. 15 | 16 | This is for Linux ONLY! And requires LuaJIT 17 | ]], 18 | homepage = "http://github.com/wiladams/schedlua", 19 | license = "MIT/X11" 20 | } 21 | 22 | supported_platforms = {"linux"} 23 | 24 | dependencies = { 25 | "lua ~> 5.1" 26 | } 27 | 28 | build = { 29 | type = "builtin", 30 | 31 | modules = { 32 | -- general programming goodness 33 | ["schedlua.AsyncSocket"] = "schedlua/AsyncSocket.lua", 34 | ["schedlua.alarm"] = "schedlua/alarm.lua", 35 | ["schedlua.asyncio"] = "schedlua/asyncio.lua", 36 | ["schedlua.clock"] = "schedlua/clock.lua", 37 | ["schedlua.epoll"] = "schedlua/epoll.lua", 38 | ["schedlua.functor"] = "schedlua/functor.lua", 39 | ["schedlua.linux"] = "schedlua/linux.lua", 40 | ["schedlua.linux_errno"] = "schedlua/linux_errno.lua", 41 | ["schedlua.linux_net"] = "schedlua/linux_net.lua", 42 | ["schedlua.predicate"] = "schedlua/predicate.lua", 43 | ["schedlua.queue"] = "schedlua/queue.lua", 44 | ["schedlua.scheduler"] = "schedlua/scheduler.lua", 45 | ["schedlua.tabutils"] = "schedlua/tabutils.lua", 46 | ["schedlua.task"] = "schedlua/task.lua", 47 | 48 | }, 49 | } 50 | -------------------------------------------------------------------------------- /rockspec/schedlua-0.1-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "schedlua" 2 | version = "0.1-2" 3 | 4 | source = { 5 | url = "https://github.com/wiladams/schedlua", 6 | tag = "v0.1-2" 7 | } 8 | 9 | description = { 10 | summary = "Scheduled cooperative task kernel written in LuaJIT", 11 | detailed = [[ 12 | LuaJIT based kernel which provides easy cooperative multi-tasking 13 | environment. The kernel supports signaling, alarms (sleep, delay, periodic) 14 | as well as seamless async io without forcing the use of callbacks. 15 | 16 | This is for Linux ONLY! And requires LuaJIT 17 | ]], 18 | homepage = "http://github.com/wiladams/schedlua", 19 | license = "MIT/X11" 20 | } 21 | 22 | supported_platforms = {"linux"} 23 | 24 | dependencies = { 25 | "lua ~> 5.1" 26 | } 27 | 28 | build = { 29 | type = "builtin", 30 | 31 | modules = { 32 | -- general programming goodness 33 | ["schedlua.AsyncSocket"] = "schedlua/AsyncSocket.lua", 34 | ["schedlua.alarm"] = "schedlua/alarm.lua", 35 | ["schedlua.asyncio"] = "schedlua/asyncio.lua", 36 | ["schedlua.clock"] = "schedlua/clock.lua", 37 | ["schedlua.epoll"] = "schedlua/epoll.lua", 38 | ["schedlua.functor"] = "schedlua/functor.lua", 39 | ["schedlua.linux"] = "schedlua/linux.lua", 40 | ["schedlua.linux_errno"] = "schedlua/linux_errno.lua", 41 | ["schedlua.linux_net"] = "schedlua/linux_net.lua", 42 | ["schedlua.predicate"] = "schedlua/predicate.lua", 43 | ["schedlua.queue"] = "schedlua/queue.lua", 44 | ["schedlua.scheduler"] = "schedlua/scheduler.lua", 45 | ["schedlua.tabutils"] = "schedlua/tabutils.lua", 46 | ["schedlua.task"] = "schedlua/task.lua", 47 | 48 | }, 49 | } 50 | -------------------------------------------------------------------------------- /rockspec/schedlua-0.1-3.rockspec: -------------------------------------------------------------------------------- 1 | package = "schedlua" 2 | version = "0.1-3" 3 | 4 | source = { 5 | url = "https://github.com/wiladams/schedlua/archive/v0.1-3.tar.gz", 6 | dir = "schedlua-0.1-3", 7 | } 8 | 9 | description = { 10 | summary = "Scheduled cooperative task kernel written in LuaJIT", 11 | detailed = [[ 12 | LuaJIT based kernel which provides easy cooperative multi-tasking 13 | environment. The kernel supports signaling, alarms (sleep, delay, periodic) 14 | as well as seamless async io without forcing the use of callbacks. 15 | 16 | This is for Linux ONLY! And requires LuaJIT 17 | ]], 18 | homepage = "http://github.com/wiladams/schedlua", 19 | license = "MIT/X11" 20 | } 21 | 22 | supported_platforms = {"linux"} 23 | 24 | dependencies = { 25 | "lua ~> 5.1" 26 | } 27 | 28 | build = { 29 | type = "builtin", 30 | 31 | modules = { 32 | -- general programming goodness 33 | ["schedlua.AsyncSocket"] = "schedlua/AsyncSocket.lua", 34 | ["schedlua.alarm"] = "schedlua/alarm.lua", 35 | ["schedlua.asyncio"] = "schedlua/asyncio.lua", 36 | ["schedlua.clock"] = "schedlua/clock.lua", 37 | ["schedlua.epoll"] = "schedlua/epoll.lua", 38 | ["schedlua.functor"] = "schedlua/functor.lua", 39 | ["schedlua.linux"] = "schedlua/linux.lua", 40 | ["schedlua.linux_errno"] = "schedlua/linux_errno.lua", 41 | ["schedlua.linux_net"] = "schedlua/linux_net.lua", 42 | ["schedlua.predicate"] = "schedlua/predicate.lua", 43 | ["schedlua.queue"] = "schedlua/queue.lua", 44 | ["schedlua.scheduler"] = "schedlua/scheduler.lua", 45 | ["schedlua.tabutils"] = "schedlua/tabutils.lua", 46 | ["schedlua.task"] = "schedlua/task.lua", 47 | 48 | }, 49 | } 50 | -------------------------------------------------------------------------------- /schedlua/alarm.lua: -------------------------------------------------------------------------------- 1 | --alarm.lua 2 | --[[ 3 | Implied global kernel 4 | --]] 5 | 6 | if Alarm then 7 | return Alarm 8 | end 9 | 10 | 11 | local tabutils = require("schedlua.tabutils") 12 | local stopwatch = require("schedlua.stopwatch") 13 | 14 | local ContinueRunning = true; 15 | local SignalsWaitingForTime = {}; 16 | local SWatch = stopwatch(); 17 | 18 | local function runningTime() 19 | return SWatch:seconds(); 20 | end 21 | 22 | local function compareDueTime(task1, task2) 23 | if task1.DueTime < task2.DueTime then 24 | return true 25 | end 26 | 27 | return false; 28 | end 29 | 30 | 31 | function waitUntilTime(atime) 32 | -- create a signal 33 | local taskID = getCurrentTaskID(); 34 | local signalName = "sleep-"..tostring(taskID); 35 | local fiber = {DueTime = atime, SignalName = signalName}; 36 | 37 | -- put time/signal into list so watchdog will pick it up 38 | tabutils.binsert(SignalsWaitingForTime, fiber, compareDueTime) 39 | 40 | -- put the current task to wait on signal 41 | waitForSignal(signalName); 42 | end 43 | 44 | -- suspend the current task for the 45 | -- specified number of milliseconds 46 | local function sleep(millis) 47 | -- figure out the time in the future 48 | local currentTime = SWatch:seconds(); 49 | local futureTime = currentTime + (millis / 1000); 50 | 51 | return waitUntilTime(futureTime); 52 | end 53 | 54 | local function delay(millis, func) 55 | millis = millis or 1000 56 | 57 | local function closure() 58 | sleep(millis) 59 | func(); 60 | end 61 | 62 | return spawn(closure) 63 | end 64 | 65 | local function periodic(millis, func) 66 | millis = millis or 1000 67 | 68 | local function closure() 69 | while true do 70 | sleep(millis) 71 | func(); 72 | end 73 | end 74 | 75 | return spawn(closure) 76 | end 77 | 78 | -- The routine task which checks the list of waiting tasks to see 79 | -- if any of them need to be signaled to wakeup 80 | local function taskReadyToRun() 81 | local currentTime = SWatch:seconds(); 82 | 83 | -- traverse through the fibers that are waiting 84 | -- on time 85 | local nAwaiting = #SignalsWaitingForTime; 86 | 87 | for i=1,nAwaiting do 88 | local task = SignalsWaitingForTime[1]; 89 | if not task then 90 | return false; 91 | end 92 | 93 | if task.DueTime <= currentTime then 94 | return task 95 | else 96 | return false 97 | end 98 | end 99 | 100 | return false; 101 | end 102 | 103 | local function runTask(task) 104 | signalOne(task.SignalName); 105 | table.remove(SignalsWaitingForTime, 1); 106 | end 107 | 108 | 109 | local function globalize(tbl) 110 | tbl = tbl or _G 111 | 112 | rawset(tbl,"delay",delay); 113 | rawset(tbl,"periodic",periodic); 114 | rawset(tbl,"runningTime",runningTime); 115 | rawset(tbl,"sleep",sleep); 116 | 117 | return tbl; 118 | end 119 | 120 | globalize(); 121 | 122 | 123 | -- This is a global variable because These routines 124 | -- MUST be a singleton within a lua state 125 | Alarm = whenever(taskReadyToRun, runTask) 126 | 127 | return Alarm 128 | -------------------------------------------------------------------------------- /schedlua/kernel.lua: -------------------------------------------------------------------------------- 1 | -- kernel.lua 2 | -- The kernel is the central figure in schedlua. There is a single 3 | -- instance of the kernel within a single lua state, so the kernel 4 | -- is a global variable. 5 | -- If it has already been created, we simply return that single instance. 6 | 7 | --print("== KERNEL INCLUDED ==") 8 | 9 | if Kernel ~= nil then 10 | return Kernel; 11 | end 12 | 13 | local Scheduler = require("schedlua.scheduler") 14 | local Task = require("schedlua.task") 15 | 16 | Kernel = { 17 | ContinueRunning = true; 18 | TaskID = 0; 19 | Scheduler = Scheduler(); 20 | TasksSuspendedForSignal = {}; 21 | } 22 | local Kernel = Kernel; 23 | 24 | 25 | local function getNewTaskID() 26 | Kernel.TaskID = Kernel.TaskID + 1; 27 | return Kernel.TaskID; 28 | end 29 | 30 | local function getCurrentTask() 31 | return Kernel.Scheduler:getCurrentTask(); 32 | end 33 | 34 | local function getCurrentTaskID() 35 | return getCurrentTask().TaskID; 36 | end 37 | 38 | 39 | local function inMainTask() 40 | return coroutine.running() == nil; 41 | end 42 | 43 | local function coop(priority, func, ...) 44 | local task = Task(func, ...) 45 | task.TaskID = getNewTaskID(); 46 | task.Priority = priority; 47 | return Kernel.Scheduler:scheduleTask(task, {...}); 48 | end 49 | 50 | local function spawn(func, ...) 51 | return coop(100, func, ...); 52 | end 53 | 54 | local function yield(...) 55 | return coroutine.yield(...); 56 | end 57 | 58 | local function suspend(...) 59 | Kernel.Scheduler:suspendCurrentTask(); 60 | return yield(...) 61 | end 62 | 63 | 64 | local function signalTasks(eventName, priority, allofthem, ...) 65 | local tasklist = Kernel.TasksSuspendedForSignal[eventName]; 66 | 67 | if not tasklist then 68 | return false, "event not registered", eventName 69 | end 70 | 71 | local nTasks = #tasklist 72 | if nTasks < 1 then 73 | return false, "no tasks waiting for event" 74 | end 75 | 76 | if allofthem then 77 | local allparams = {...} 78 | for i=1,nTasks do 79 | Kernel.Scheduler:scheduleTask(tasklist[1],allparams, priority); 80 | table.remove(tasklist, 1); 81 | end 82 | else 83 | Kernel.Scheduler:scheduleTask(tasklist[1],{...}, priority); 84 | table.remove(tasklist, 1); 85 | end 86 | 87 | return true; 88 | end 89 | 90 | local function signalOne(eventName, ...) 91 | return signalTasks(eventName, 100, false, ...) 92 | end 93 | 94 | local function signalAll(eventName, ...) 95 | return signalTasks(eventName, 100, true, ...) 96 | end 97 | 98 | local function signalAllImmediate(eventName, ...) 99 | return signalTasks(eventName, 0, true, ...) 100 | end 101 | 102 | local function waitForSignal(eventName,...) 103 | local currentFiber = Kernel.Scheduler:getCurrentTask(); 104 | 105 | if currentFiber == nil then 106 | return false, "not currently in a running task" 107 | end 108 | 109 | if not Kernel.TasksSuspendedForSignal[eventName] then 110 | Kernel.TasksSuspendedForSignal[eventName] = {} 111 | end 112 | 113 | table.insert(Kernel.TasksSuspendedForSignal[eventName], currentFiber); 114 | 115 | return suspend(...) 116 | end 117 | 118 | local function onSignal(eventName, func) 119 | local function closure() 120 | waitForSignal(eventName) 121 | func(); 122 | end 123 | 124 | return spawn(closure) 125 | end 126 | 127 | 128 | 129 | local function run(func, ...) 130 | 131 | if func ~= nil then 132 | spawn(func, ...) 133 | end 134 | 135 | while (Kernel.ContinueRunning) do 136 | Kernel.Scheduler:step(); 137 | end 138 | end 139 | 140 | local function halt(self) 141 | Kernel.ContinueRunning = false; 142 | end 143 | 144 | local function globalize(tbl) 145 | tbl = tbl or _G; 146 | 147 | rawset(tbl, "Kernel", Kernel); 148 | 149 | -- task management 150 | rawset(tbl, "halt", halt); 151 | rawset(tbl,"run", run); 152 | rawset(tbl,"coop", coop); 153 | rawset(tbl,"spawn", spawn); 154 | rawset(tbl,"suspend", suspend); 155 | rawset(tbl,"yield", yield); 156 | 157 | -- signaling 158 | rawset(tbl,"onSignal", onSignal); 159 | rawset(tbl,"signalAll", signalAll); 160 | rawset(tbl,"signalAllImmediate", signalAllImmediate); 161 | rawset(tbl,"signalOne", signalOne); 162 | rawset(tbl,"waitForSignal", waitForSignal); 163 | 164 | -- extras 165 | rawset(tbl,"getCurrentTaskID", getCurrentTaskID); 166 | 167 | return tbl; 168 | end 169 | 170 | -- We globalize before including the extras because they will 171 | -- assume the global state is already set, and spawning and signaling 172 | -- are already available. 173 | 174 | local global = globalize(); 175 | 176 | -- Extra non-core routines 177 | local Predicate = require("schedlua.predicate") 178 | local Alarm = require("schedlua.alarm") 179 | 180 | return globalize; 181 | 182 | -------------------------------------------------------------------------------- /schedlua/linux/epollio.lua: -------------------------------------------------------------------------------- 1 | --epoll_set.lua 2 | 3 | local ffi = require("ffi") 4 | local bit = require("bit") 5 | local lshift, rshift, bor, band = bit.lshift, bit.rshift, bit.bor, bit.band; 6 | 7 | local exports = {} 8 | 9 | --[[ 10 | Things related to epoll 11 | --]] 12 | 13 | exports.EPOLLIN = 0x0001; 14 | exports.EPOLLPRI = 0x0002; 15 | exports.EPOLLOUT = 0x0004; 16 | exports.EPOLLRDNORM = 0x0040; -- SAME AS EPOLLIN 17 | exports.EPOLLRDBAND = 0x0080; 18 | exports.EPOLLWRNORM = 0x0100; -- SAME AS EPOLLOUT 19 | exports.EPOLLWRBAND = 0x0200; 20 | exports.EPOLLMSG = 0x0400; -- NOT USED 21 | exports.EPOLLERR = 0x0008; 22 | exports.EPOLLHUP = 0x0010; 23 | exports.EPOLLRDHUP = 0x2000; 24 | exports.EPOLLWAKEUP = lshift(1,29); 25 | exports.EPOLLONESHOT = lshift(1,30); 26 | exports.EPOLLET = lshift(1,31); 27 | 28 | 29 | 30 | 31 | -- Valid opcodes ( "op" parameter ) to issue to epoll_ctl(). 32 | exports.EPOLL_CTL_ADD =1 -- Add a file descriptor to the interface. 33 | exports.EPOLL_CTL_DEL =2 -- Remove a file descriptor from the interface. 34 | exports.EPOLL_CTL_MOD =3 -- Change file descriptor epoll_event structure. 35 | 36 | ffi.cdef[[ 37 | /* Flags to be passed to epoll_create1. */ 38 | enum 39 | { 40 | EPOLL_CLOEXEC = 02000000 41 | }; 42 | ]] 43 | 44 | ffi.cdef[[ 45 | typedef union epoll_data { 46 | void *ptr; 47 | int fd; 48 | uint32_t u32; 49 | uint64_t u64; 50 | } epoll_data_t; 51 | ]] 52 | 53 | --[=[ 54 | ffi.cdef[[ 55 | struct epoll_event { 56 | uint32_t events; 57 | epoll_data_t data; 58 | }; 59 | ]]..(ffi.arch == "x64" and [[__attribute__((__packed__));]] or [[;]])) 60 | --]=] 61 | 62 | ffi.cdef([[ 63 | struct epoll_event { 64 | int32_t events; 65 | epoll_data_t data; 66 | }]]..(ffi.arch == "x64" and [[__attribute__((__packed__));]] or [[;]])) 67 | 68 | 69 | 70 | ffi.cdef[[ 71 | int epoll_create (int __size) ; 72 | int epoll_create1 (int __flags) ; 73 | int epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event) ; 74 | int epoll_wait (int __epfd, struct epoll_event *__events, int __maxevents, int __timeout); 75 | 76 | //int epoll_pwait (int __epfd, struct epoll_event *__events, 77 | // int __maxevents, int __timeout, 78 | // const __sigset_t *__ss); 79 | ]] 80 | 81 | ffi.cdef[[ 82 | typedef struct _epollset { 83 | int epfd; // epoll file descriptor 84 | } epollset; 85 | ]] 86 | 87 | local epollset = ffi.typeof("epollset") 88 | local epollset_mt = { 89 | __new = function(ct, epfd) 90 | if not epfd then 91 | epfd = ffi.C.epoll_create1(0); 92 | end 93 | 94 | if epfd < 0 then 95 | return nil; 96 | end 97 | 98 | return ffi.new(ct, epfd) 99 | end, 100 | 101 | __gc = function(self) 102 | -- ffi.C.close(self.epfd); 103 | end; 104 | 105 | __index = { 106 | add = function(self, fd, event) 107 | local ret = ffi.C.epoll_ctl(self.epfd, exports.EPOLL_CTL_ADD, fd, event) 108 | 109 | if ret > -1 then 110 | return ret; 111 | end 112 | 113 | return false, ffi.errno(); 114 | end, 115 | 116 | delete = function(self, fd, event) 117 | local ret = ffi.C.epoll_ctl(self.epfd, exports.EPOLL_CTL_DEL, fd, event) 118 | 119 | if ret > -1 then 120 | return ret; 121 | end 122 | 123 | return false, ffi.errno(); 124 | end, 125 | 126 | modify = function(self, fd, event) 127 | --print("epollset.modify: ", self, fd, event) 128 | local ret = ffi.C.epoll_ctl(self.epfd, exports.EPOLL_CTL_MOD, fd, event) 129 | if ret > -1 then 130 | return ret; 131 | end 132 | 133 | return false, ffi.errno(); 134 | end, 135 | 136 | -- struct epoll_event *__events 137 | wait = function(self, events, maxevents, timeout) 138 | events = events or ffi.new("struct epoll_event[1]") 139 | maxevents = maxevents or 1 140 | timeout = timeout or -1 141 | 142 | -- gets either number of ready events 143 | -- or -1 indicating an error 144 | local ret = ffi.C.epoll_wait (self.epfd, events, maxevents, timeout); 145 | if ret == -1 then 146 | return false, ffi.errno(); 147 | end 148 | 149 | return ret, events; 150 | end, 151 | }; 152 | } 153 | ffi.metatype(epollset, epollset_mt); 154 | 155 | exports.epollset = epollset; 156 | 157 | -- export to global namespace 158 | setmetatable(exports, { 159 | __call = function(self, params) 160 | params = params or {} 161 | 162 | if params.exportglobal then 163 | for k,v in pairs(exports) do 164 | _G[k] = v; 165 | end 166 | end 167 | 168 | return self; 169 | end; 170 | }) 171 | 172 | return exports; 173 | 174 | -------------------------------------------------------------------------------- /schedlua/linux/linux_errno.lua: -------------------------------------------------------------------------------- 1 | -- errno-base.h 2 | -- Database of error codes for Linux 3 | local exports = {} 4 | 5 | setmetatable(exports, { 6 | __call = function(self, params) 7 | params = params or {} 8 | if params.exportglobal then 9 | for k,v in pairs(exports.errnos) do 10 | _G[k] = v; 11 | end 12 | end 13 | return self; 14 | end 15 | }) 16 | 17 | 18 | exports.errnos = { 19 | EPERM = 1; -- Operation not permitted 20 | ENOENT = 2; -- No such file or directory 21 | ESRCH = 3; -- No such process 22 | EINTR = 4; -- Interrupted system call 23 | EIO = 5; -- I/O error 24 | ENXIO = 6; -- No such device or address 25 | E2BIG = 7; -- Argument list too long 26 | ENOEXEC = 8; -- Exec format error 27 | EBADF = 9; -- Bad file number 28 | ECHILD = 10; -- No child processes 29 | EAGAIN = 11; -- Try again 30 | ENOMEM = 12; -- Out of memory 31 | EACCES = 13; -- Permission denied 32 | EFAULT = 14; -- Bad address 33 | ENOTBLK = 15; -- Block device required 34 | EBUSY = 16; -- Device or resource busy 35 | EEXIST = 17; -- File exists 36 | EXDEV = 18; -- Cross-device link 37 | ENODEV = 19; -- No such device 38 | ENOTDIR = 20; -- Not a directory 39 | EISDIR = 21; -- Is a directory 40 | EINVAL = 22; -- Invalid argument 41 | ENFILE = 23; -- File table overflow 42 | EMFILE = 24; -- Too many open files 43 | ENOTTY = 25; -- Not a typewriter 44 | ETXTBSY = 26; -- Text file busy 45 | EFBIG = 27; -- File too large 46 | ENOSPC = 28; -- No space left on device 47 | ESPIPE = 29; -- Illegal seek 48 | EROFS = 30; -- Read-only file system 49 | EMLINK = 31; -- Too many links 50 | EPIPE = 32; -- Broken pipe 51 | EDOM = 33; -- Math argument out of domain of func 52 | ERANGE = 34; -- Math result not representable 53 | 54 | EDEADLK = 35; -- Resource deadlock would occur 55 | ENAMETOOLONG = 36; -- File name too long 56 | ENOLCK = 37; -- No record locks available 57 | ENOSYS = 38; -- Function not implemented 58 | ENOTEMPTY = 39; -- Directory not empty 59 | ELOOP = 40; -- Too many symbolic links encountered 60 | EWOULDBLOCK = EAGAIN; -- Operation would block 61 | ENOMSG = 42; -- No message of desired type 62 | EIDRM = 43; -- Identifier removed 63 | ECHRNG = 44; -- Channel number out of range 64 | EL2NSYNC = 45; -- Level 2 not synchronized 65 | EL3HLT = 46; -- Level 3 halted 66 | EL3RST = 47; -- Level 3 reset 67 | ELNRNG = 48; -- Link number out of range 68 | EUNATCH = 49; -- Protocol driver not attached 69 | ENOCSI = 50; -- No CSI structure available 70 | EL2HLT = 51; -- Level 2 halted 71 | EBADE = 52; -- Invalid exchange 72 | EBADR = 53; -- Invalid request descriptor 73 | EXFULL = 54; -- Exchange full 74 | ENOANO = 55; -- No anode 75 | EBADRQC = 56; -- Invalid request code 76 | EBADSLT = 57; -- Invalid slot 77 | 78 | EDEADLOCK = EDEADLK; 79 | 80 | EBFONT = 59; -- Bad font file format 81 | ENOSTR = 60; -- Device not a stream 82 | ENODATA = 61; -- No data available 83 | ETIME = 62; -- Timer expired 84 | ENOSR = 63; -- Out of streams resources 85 | ENONET = 64; -- Machine is not on the network 86 | ENOPKG = 65; -- Package not installed 87 | EREMOTE = 66; -- Object is remote 88 | ENOLINK = 67; -- Link has been severed 89 | EADV = 68; -- Advertise error 90 | ESRMNT = 69; -- Srmount error 91 | ECOMM = 70; -- Communication error on send 92 | EPROTO = 71; -- Protocol error 93 | EMULTIHOP = 72; -- Multihop attempted 94 | EDOTDOT = 73; -- RFS specific error 95 | EBADMSG = 74; -- Not a data message 96 | EOVERFLOW = 75; -- Value too large for defined data type 97 | ENOTUNIQ = 76; -- Name not unique on network 98 | EBADFD = 77; -- File descriptor in bad state 99 | EREMCHG = 78; -- Remote address changed 100 | ELIBACC = 79; -- Can not access a needed shared library 101 | ELIBBAD = 80; -- Accessing a corrupted shared library 102 | ELIBSCN = 81; -- .lib section in a.out corrupted 103 | ELIBMAX = 82; -- Attempting to link in too many shared libraries 104 | ELIBEXEC = 83; -- Cannot exec a shared library directly 105 | EILSEQ = 84; -- Illegal byte sequence 106 | ERESTART = 85; -- Interrupted system call should be restarted 107 | ESTRPIPE = 86; -- Streams pipe error 108 | EUSERS = 87; -- Too many users 109 | ENOTSOCK = 88; -- Socket operation on non-socket 110 | EDESTADDRREQ = 89; -- Destination address required 111 | EMSGSIZE = 90; -- Message too long 112 | EPROTOTYPE = 91; -- Protocol wrong type for socket 113 | ENOPROTOOPT = 92; -- Protocol not available 114 | EPROTONOSUPPORT = 93; -- Protocol not supported 115 | ESOCKTNOSUPPORT = 94; -- Socket type not supported 116 | EOPNOTSUPP = 95; -- Operation not supported on transport endpoint 117 | EPFNOSUPPORT = 96; -- Protocol family not supported 118 | EAFNOSUPPORT = 97; -- Address family not supported by protocol 119 | EADDRINUSE = 98; -- Address already in use 120 | EADDRNOTAVAIL = 99; -- Cannot assign requested address 121 | ENETDOWN = 100; -- Network is down 122 | ENETUNREACH = 101; -- Network is unreachable 123 | ENETRESET = 102; -- Network dropped connection because of reset 124 | ECONNABORTED = 103; -- Software caused connection abort 125 | ECONNRESET = 104; -- Connection reset by peer 126 | ENOBUFS = 105; -- No buffer space available 127 | EISCONN = 106; -- Transport endpoint is already connected 128 | ENOTCONN = 107; -- Transport endpoint is not connected 129 | ESHUTDOWN = 108; -- Cannot send after transport endpoint shutdown 130 | ETOOMANYREFS = 109; -- Too many references: cannot splice 131 | ETIMEDOUT = 110; -- Connection timed out 132 | ECONNREFUSED = 111; -- Connection refused 133 | EHOSTDOWN = 112; -- Host is down 134 | EHOSTUNREACH = 113; -- No route to host 135 | EALREADY = 114; -- Operation already in progress 136 | EINPROGRESS = 115; -- Operation now in progress 137 | ESTALE = 116; -- Stale file handle 138 | EUCLEAN = 117; -- Structure needs cleaning 139 | ENOTNAM = 118; -- Not a XENIX named type file 140 | ENAVAIL = 119; -- No XENIX semaphores available 141 | EISNAM = 120; -- Is a named type file 142 | EREMOTEIO = 121; -- Remote I/O error 143 | EDQUOT = 122; -- Quota exceeded 144 | 145 | ENOMEDIUM = 123; -- No medium found 146 | EMEDIUMTYPE = 124; -- Wrong medium type 147 | ECANCELED = 125; -- Operation Canceled 148 | ENOKEY = 126; -- Required key not available 149 | EKEYEXPIRED = 127; -- Key has expired 150 | EKEYREVOKED = 128; -- Key has been revoked 151 | EKEYREJECTED = 129; -- Key was rejected by service 152 | 153 | -- for robust mutexes 154 | EOWNERDEAD = 130; -- Owner died 155 | ENOTRECOVERABLE = 131; -- State not recoverable 156 | 157 | ERFKILL = 132; -- Operation not possible due to RF-kill 158 | 159 | EHWPOISON = 133; -- Memory page has hardware error 160 | } 161 | 162 | function exports.lookuperrno(errorNumber) 163 | for name, value in pairs(exports.errnos) do 164 | if value == errorNumber then 165 | return name; 166 | end 167 | 168 | end 169 | 170 | return "UNKNOWN ERROR: "..tostring(errorNumber); 171 | end 172 | 173 | return exports; 174 | -------------------------------------------------------------------------------- /schedlua/linux/linux_ffi.lua: -------------------------------------------------------------------------------- 1 | --linux_ffi.lua 2 | 3 | local ffi = require("ffi") 4 | 5 | local exports = {} 6 | local C = {} 7 | 8 | 9 | 10 | -- all types passed to syscalls are int or long, 11 | -- define them here for convenience 12 | local int = ffi.typeof("int") 13 | local uint = ffi.typeof("unsigned int") 14 | local long = ffi.typeof("long") 15 | local ulong = ffi.typeof("unsigned long") 16 | 17 | local voidp = ffi.typeof("void *") 18 | 19 | local function void(x) 20 | return ffi.cast(voidp, x) 21 | end 22 | 23 | local errno = ffi.errno 24 | 25 | 26 | 27 | ffi.cdef[[ 28 | long syscall(int number, ...); 29 | ]] 30 | 31 | local syscall_long = ffi.C.syscall -- returns long 32 | local function syscall(...) return tonumber(syscall_long(...)) end -- int is default as most common 33 | --local function syscall_uint(...) return uint(syscall_long(...)) end 34 | --local function syscall_void(...) return void(syscall_long(...)) end 35 | --local function syscall_off(...) return u64(syscall_long(...)) end -- off_t 36 | 37 | local NR = { 38 | io_setup = 206; 39 | io_destroy = 207; 40 | io_getevents = 208; 41 | io_submit = 209; 42 | io_cancel = 210; 43 | } 44 | 45 | -- endian dependent 46 | if ffi.abi("le") then 47 | ffi.cdef [[ 48 | struct iocb { 49 | uint64_t aio_data; 50 | uint32_t aio_key, aio_reserved1; 51 | uint16_t aio_lio_opcode; 52 | int16_t aio_reqprio; 53 | uint32_t aio_fildes; 54 | uint64_t aio_buf; 55 | uint64_t aio_nbytes; 56 | int64_t aio_offset; 57 | uint64_t aio_reserved2; 58 | uint32_t aio_flags; 59 | uint32_t aio_resfd; 60 | }; 61 | ]] 62 | else 63 | ffi.cdef [[ 64 | struct iocb { 65 | // internal to the kernel 66 | uint64_t aio_data; 67 | uint32_t aio_reserved1, aio_key; 68 | 69 | // common fields 70 | uint16_t aio_lio_opcode; 71 | int16_t aio_reqprio; 72 | uint32_t aio_fildes; 73 | uint64_t aio_buf; 74 | uint64_t aio_nbytes; 75 | int64_t aio_offset; 76 | uint64_t aio_reserved2; 77 | uint32_t aio_flags; 78 | uint32_t aio_resfd; 79 | }; 80 | ]] 81 | end 82 | 83 | ffi.cdef[[ 84 | struct io_event { 85 | uint64_t data; 86 | uint64_t obj; 87 | int64_t res; 88 | int64_t res2; 89 | }; 90 | ]] 91 | 92 | ffi.cdef[[ 93 | typedef unsigned long aio_context_t; 94 | 95 | enum { 96 | IOCB_CMD_PREAD = 0, 97 | IOCB_CMD_PWRITE = 1, 98 | IOCB_CMD_FSYNC = 2, 99 | IOCB_CMD_FDSYNC = 3, 100 | /* These two are experimental. 101 | * IOCB_CMD_PREADX = 4, 102 | * IOCB_CMD_POLL = 5, 103 | */ 104 | IOCB_CMD_NOOP = 6, 105 | IOCB_CMD_PREADV = 7, 106 | IOCB_CMD_PWRITEV = 8, 107 | }; 108 | ]] 109 | 110 | -- native Linux aio not generally supported by libc, only posix API 111 | -- aio routines lifted from ljsyscall 112 | 113 | function C.io_setup(nr_events, ctx) 114 | return syscall(NR.io_setup, uint(nr_events), void(ctx)) 115 | end 116 | 117 | function C.io_destroy(ctx) 118 | return syscall(NR.io_destroy, ulong(ctx)) 119 | end 120 | 121 | function C.io_cancel(ctx, iocb, result) 122 | return syscall(NR.io_cancel, ulong(ctx), void(iocb), void(result)) 123 | end 124 | 125 | function C.io_getevents(ctx, min, nr, events, timeout) 126 | return syscall(NR.io_getevents, ulong(ctx), long(min), long(nr), void(events), void(timeout)) 127 | end 128 | 129 | function C.io_submit(ctx, iocb, nr) 130 | return syscall(NR.io_submit, ulong(ctx), long(nr), void(iocb)) 131 | end 132 | 133 | --[[ 134 | function S.io_setup(nr_events) 135 | local ctx = ffi.new("aio_context[1]"); 136 | local ret, err = C.io_setup(nr_events, ctx) 137 | if ret == -1 then return nil, t.error(err or errno()) end 138 | return ctx[0] 139 | end 140 | 141 | function S.io_destroy(ctx) return retbool(C.io_destroy(ctx)) end 142 | 143 | function S.io_cancel(ctx, iocb, result) 144 | result = result or t.io_event() 145 | local ret, err = C.io_cancel(ctx, iocb, result) 146 | if ret == -1 then return nil, t.error(err or errno()) end 147 | return result 148 | end 149 | 150 | function S.io_getevents(ctx, min, events, timeout) 151 | if timeout then timeout = mktype(t.timespec, timeout) end 152 | local ret, err = C.io_getevents(ctx, min or events.count, events.count, events.ev, timeout) 153 | return retiter(ret, err, events.ev) 154 | end 155 | 156 | -- iocb must persist until retrieved (as we get pointer), so cannot be passed as table must take t.iocb_array 157 | function S.io_submit(ctx, iocb) 158 | return retnum(C.io_submit(ctx, iocb.ptrs, iocb.nr)) 159 | end 160 | --]] 161 | 162 | exports.O_RDONLY = 00; 163 | exports.O_WRONLY = 01; 164 | exports.O_RDWR = 02; 165 | exports.O_CREAT = 0100; 166 | 167 | 168 | -- File system 169 | ffi.cdef[[ 170 | typedef uint32_t mode_t; 171 | typedef uint32_t uid_t; 172 | typedef uint32_t gid_t; 173 | typedef int32_t pid_t; 174 | typedef uint64_t dev_t; 175 | 176 | 177 | int open(const char *pathname, int flags, mode_t mode); 178 | int close(int fd); 179 | int chdir(const char *path); 180 | int fchdir(int fd); 181 | int mkdir(const char *pathname, mode_t mode); 182 | int rmdir(const char *pathname); 183 | int unlink(const char *pathname); 184 | int rename(const char *oldpath, const char *newpath); 185 | int chmod(const char *path, mode_t mode); 186 | int fchmod(int fd, mode_t mode); 187 | int chown(const char *path, uid_t owner, gid_t group); 188 | int fchown(int fd, uid_t owner, gid_t group); 189 | int lchown(const char *path, uid_t owner, gid_t group); 190 | int link(const char *oldpath, const char *newpath); 191 | int linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags); 192 | int symlink(const char *oldpath, const char *newpath); 193 | int chroot(const char *path); 194 | mode_t umask(mode_t mask); 195 | void sync(void); 196 | int mknod(const char *pathname, mode_t mode, dev_t dev); 197 | int mkfifo(const char *path, mode_t mode); 198 | ]] 199 | 200 | -- file IO 201 | --[=[ 202 | ffi.cdef[[ 203 | ssize_t read(int fd, void *buf, size_t count); 204 | ssize_t readv(int fd, const struct iovec *iov, int iovcnt); 205 | ssize_t write(int fd, const void *buf, size_t count); 206 | ssize_t writev(int fd, const struct iovec *iov, int iovcnt); 207 | ssize_t pread(int fd, void *buf, size_t count, off_t offset); 208 | ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset); 209 | ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset); 210 | ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset); 211 | int access(const char *pathname, int mode); 212 | off_t lseek(int fd, off_t offset, int whence); 213 | ssize_t readlink(const char *path, char *buf, size_t bufsiz); 214 | int fsync(int fd); 215 | int fdatasync(int fd); 216 | int fcntl(int fd, int cmd, void *arg); /* arg is long or pointer */ 217 | int stat(const char *path, struct stat *sb); 218 | int lstat(const char *path, struct stat *sb); 219 | int fstat(int fd, struct stat *sb); 220 | int truncate(const char *path, off_t length); 221 | int ftruncate(int fd, off_t length); 222 | ]] 223 | --]=] 224 | 225 | 226 | ffi.cdef[[ 227 | int shm_open(const char *pathname, int flags, mode_t mode); 228 | int shm_unlink(const char *name); 229 | int flock(int fd, int operation); 230 | ]] 231 | 232 | ffi.cdef[[ 233 | int socket(int domain, int type, int protocol); 234 | int socketpair(int domain, int type, int protocol, int sv[2]); 235 | ssize_t recv(int sockfd, void *buf, size_t len, int flags); 236 | ssize_t send(int sockfd, const void *buf, size_t len, int flags); 237 | ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); 238 | ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); 239 | ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); 240 | ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); 241 | int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); 242 | int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); 243 | int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 244 | int listen(int sockfd, int backlog); 245 | int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 246 | int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 247 | int accept4(int sockfd, void *addr, socklen_t *addrlen, int flags); 248 | int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 249 | int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 250 | int shutdown(int sockfd, int how); 251 | int sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags); 252 | int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags, struct timespec *timeout); 253 | ]] 254 | 255 | 256 | ffi.cdef[[ 257 | int pipe2(int pipefd[2], int flags); 258 | int dup(int oldfd); 259 | int dup2(int oldfd, int newfd); 260 | int dup3(int oldfd, int newfd, int flags); 261 | 262 | int pipe(int pipefd[2]); 263 | 264 | int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 265 | int poll(struct pollfd *fds, nfds_t nfds, int timeout); 266 | int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask); 267 | 268 | int nanosleep(const struct timespec *req, struct timespec *rem); 269 | int getrusage(int who, struct rusage *usage); 270 | int getpriority(int which, int who); 271 | int setpriority(int which, int who, int prio); 272 | ]] 273 | 274 | 275 | ffi.cdef[[ 276 | uid_t getuid(void); 277 | uid_t geteuid(void); 278 | pid_t getpid(void); 279 | pid_t getppid(void); 280 | gid_t getgid(void); 281 | gid_t getegid(void); 282 | int setuid(uid_t uid); 283 | int setgid(gid_t gid); 284 | int seteuid(uid_t euid); 285 | int setegid(gid_t egid); 286 | pid_t getsid(pid_t pid); 287 | pid_t setsid(void); 288 | int setpgid(pid_t pid, pid_t pgid); 289 | pid_t getpgid(pid_t pid); 290 | pid_t getpgrp(void); 291 | ]] 292 | 293 | ffi.cdef[[ 294 | pid_t fork(void); 295 | int execve(const char *filename, const char *argv[], const char *envp[]); 296 | void exit(int status); 297 | void _exit(int status); 298 | int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); 299 | int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); 300 | int sigpending(sigset_t *set); 301 | int sigsuspend(const sigset_t *mask); 302 | int kill(pid_t pid, int sig); 303 | 304 | int getgroups(int size, gid_t list[]); 305 | int setgroups(size_t size, const gid_t *list); 306 | 307 | int gettimeofday(struct timeval *tv, void *tz); 308 | int settimeofday(const struct timeval *tv, const void *tz); 309 | int getitimer(int which, struct itimerval *curr_value); 310 | int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value); 311 | 312 | int acct(const char *filename); 313 | 314 | void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); 315 | int munmap(void *addr, size_t length); 316 | int msync(void *addr, size_t length, int flags); 317 | int madvise(void *addr, size_t length, int advice); 318 | int mlock(const void *addr, size_t len); 319 | int munlock(const void *addr, size_t len); 320 | int mlockall(int flags); 321 | int munlockall(void); 322 | 323 | int openat(int dirfd, const char *pathname, int flags, mode_t mode); 324 | int mkdirat(int dirfd, const char *pathname, mode_t mode); 325 | int unlinkat(int dirfd, const char *pathname, int flags); 326 | int renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); 327 | int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags); 328 | int symlinkat(const char *oldpath, int newdirfd, const char *newpath); 329 | int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev); 330 | int mkfifoat(int dirfd, const char *pathname, mode_t mode); 331 | int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags); 332 | int readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz); 333 | int faccessat(int dirfd, const char *pathname, int mode, int flags); 334 | int fstatat(int dirfd, const char *pathname, struct stat *buf, int flags); 335 | 336 | int futimens(int fd, const struct timespec times[2]); 337 | int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags); 338 | 339 | int lchmod(const char *path, mode_t mode); 340 | int fchroot(int fd); 341 | int utimes(const char *filename, const struct timeval times[2]); 342 | int futimes(int, const struct timeval times[2]); 343 | int lutimes(const char *filename, const struct timeval times[2]); 344 | pid_t wait4(pid_t wpid, int *status, int options, struct rusage *rusage); 345 | int posix_openpt(int oflag); 346 | 347 | 348 | int getpagesize(void); 349 | 350 | int timer_create(clockid_t clockid, struct sigevent *sevp, timer_t *timerid); 351 | int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value, struct itimerspec * old_value); 352 | int timer_gettime(timer_t timerid, struct itimerspec *curr_value); 353 | int timer_delete(timer_t timerid); 354 | int timer_getoverrun(timer_t timerid); 355 | 356 | int adjtime(const struct timeval *delta, struct timeval *olddelta); 357 | 358 | int aio_cancel(int, struct aiocb *); 359 | int aio_error(const struct aiocb *); 360 | int aio_fsync(int, struct aiocb *); 361 | int aio_read(struct aiocb *); 362 | int aio_return(struct aiocb *); 363 | int aio_write(struct aiocb *); 364 | int lio_listio(int, struct aiocb *const *, int, struct sigevent *); 365 | int aio_suspend(const struct aiocb *const *, int, const struct timespec *); 366 | int aio_waitcomplete(struct aiocb **, struct timespec *); 367 | ]] 368 | 369 | return exports 370 | -------------------------------------------------------------------------------- /schedlua/linux/linux_net.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | local bit = require("bit") 3 | local band, bor, lshift, rshift = bit.band, bit.bor, bit.lshift, bit.rshift 4 | 5 | local exports = require("schedlua.net") 6 | 7 | 8 | ffi.cdef[[ 9 | int close(int fd); 10 | int fcntl (int __fd, int __cmd, ...); 11 | int ioctl (int __fd, unsigned long int __request, ...); 12 | 13 | ssize_t read(int fd, void *buf, size_t count); 14 | ssize_t write(int fd, const void *buf, size_t count); 15 | ]] 16 | 17 | ffi.cdef[[ 18 | int inet_aton (__const char *__cp, struct in_addr *__inp); 19 | char *inet_ntoa (struct in_addr __in); 20 | ]] 21 | 22 | ffi.cdef[[ 23 | int socket(int domain, int type, int protocol); 24 | int socketpair(int domain, int type, int protocol, int sv[2]); 25 | ssize_t recv(int sockfd, void *buf, size_t len, int flags); 26 | ssize_t send(int sockfd, const void *buf, size_t len, int flags); 27 | ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); 28 | ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); 29 | ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); 30 | ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); 31 | int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); 32 | int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); 33 | int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 34 | int listen(int sockfd, int backlog); 35 | int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 36 | int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 37 | int accept4(int sockfd, void *addr, socklen_t *addrlen, int flags); 38 | int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 39 | int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 40 | int shutdown(int sockfd, int how); 41 | int sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags); 42 | int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags, struct timespec *timeout); 43 | ]] 44 | 45 | ffi.cdef[[ 46 | struct addrinfo { 47 | int ai_flags; // AI_PASSIVE, AI_CANONNAME, ... 48 | int ai_family; // AF_xxx 49 | int ai_socktype; // SOCK_xxx 50 | int ai_protocol; // 0 (auto) or IPPROTO_TCP, IPPROTO_UDP 51 | 52 | socklen_t ai_addrlen; // length of ai_addr 53 | struct sockaddr *ai_addr; // binary address 54 | char *ai_canonname; // canonical name for nodename 55 | struct addrinfo *ai_next; // next structure in linked list 56 | }; 57 | 58 | int getaddrinfo(const char *nodename, const char *servname, 59 | const struct addrinfo *hints, struct addrinfo **res); 60 | 61 | void freeaddrinfo(struct addrinfo *ai); 62 | ]] 63 | 64 | 65 | exports.FIONBIO = 0x5421; 66 | 67 | 68 | -- Socket level values. 69 | -- To select the IP level. 70 | exports.SOL_IP = 0; 71 | 72 | -- from /usr/include/asm-generic/socket.h 73 | -- For setsockopt(2) 74 | exports.SOL_SOCKET = 1; 75 | 76 | exports.SO_DEBUG =1 77 | exports.SO_REUSEADDR =2 78 | exports.SO_TYPE =3 79 | exports.SO_ERROR =4 80 | exports.SO_DONTROUTE =5 81 | exports.SO_BROADCAST =6 82 | exports.SO_SNDBUF =7 83 | exports.SO_RCVBUF =8 84 | exports.SO_SNDBUFFORCE =32 85 | exports.SO_RCVBUFFORCE =33 86 | exports.SO_KEEPALIVE =9 87 | exports.SO_OOBINLINE =10 88 | exports.SO_NO_CHECK =11 89 | exports.SO_PRIORITY =12 90 | exports.SO_LINGER =13 91 | exports.SO_BSDCOMPAT =14 92 | exports.SO_REUSEPORT =15 93 | exports.SO_PASSCRED =16 94 | exports.SO_PEERCRED =17 95 | exports.SO_RCVLOWAT =18 96 | exports.SO_SNDLOWAT =19 97 | exports.SO_RCVTIMEO =20 98 | exports.SO_SNDTIMEO =21 99 | 100 | exports.SOL_IPV6 = 41; 101 | exports.SOL_ICMPV6 = 58; 102 | 103 | exports.SOL_RAW = 255; 104 | exports.SOL_DECNET = 261; 105 | exports.SOL_X25 = 262; 106 | exports.SOL_PACKET = 263; 107 | exports.SOL_ATM = 264; -- ATM layer (cell level). 108 | exports.SOL_AAL = 265; -- ATM Adaption Layer (packet level). 109 | exports.SOL_IRDA = 266; 110 | 111 | -- Maximum queue length specifiable by listen. 112 | exports.SOMAXCONN = 128; 113 | 114 | 115 | -- for SOL_IP Options 116 | exports.IP_DEFAULT_MULTICAST_TTL = 1; 117 | exports.IP_DEFAULT_MULTICAST_LOOP = 1; 118 | exports.IP_MAX_MEMBERSHIPS = 20; 119 | 120 | -- constants should be used for the second parameter of `shutdown'. 121 | exports.SHUT_RD = 0; -- No more receptions. 122 | exports.SHUT_WR = 1; -- No more transmissions. 123 | exports.SHUT_RDWR=2; -- No more receptions or transmissions. 124 | 125 | 126 | local sockaddr_in = ffi.typeof("struct sockaddr_in"); 127 | local sockaddr_in_mt = { 128 | __new = function(ct, address, port, family) 129 | family = family or exports.AF_INET; 130 | 131 | local sa = ffi.new(ct) 132 | sa.sin_family = family; 133 | sa.sin_port = exports.htons(port) 134 | if type(address) == "number" then 135 | addr.sin_addr.s_addr = address; 136 | elseif type(address) == "string" then 137 | local inp = ffi.new("struct in_addr") 138 | local ret = ffi.C.inet_aton (address, inp); 139 | sa.sin_addr.s_addr = inp.s_addr; 140 | end 141 | 142 | return sa; 143 | end; 144 | 145 | __index = { 146 | setPort = function(self, port) 147 | self.sin_port = exports.htons(port); 148 | return self; 149 | end, 150 | }, 151 | 152 | } 153 | ffi.metatype(sockaddr_in, sockaddr_in_mt); 154 | exports.sockaddr_in = sockaddr_in; 155 | 156 | 157 | 158 | -- the filedesc type gives an easy place to hang things 159 | -- related to a file descriptor. Primarily it keeps the 160 | -- basic file descriptor. 161 | -- It also performs the async read/write operations 162 | 163 | ffi.cdef[[ 164 | typedef struct filedesc_t { 165 | int fd; 166 | } filedesc; 167 | 168 | typedef struct async_ioevent_t { 169 | struct filedesc_t fdesc; 170 | int eventKind; 171 | } async_ioevent; 172 | ]] 173 | 174 | 175 | local filedesc = ffi.typeof("struct filedesc_t") 176 | local filedesc_mt = { 177 | __new = function(ct, fd) 178 | local obj = ffi.new(ct, fd); 179 | 180 | return obj; 181 | end; 182 | 183 | __gc = function(self) 184 | if self.fd > -1 then 185 | self:close(); 186 | end 187 | end; 188 | 189 | __index = { 190 | close = function(self) 191 | ffi.C.close(self.fd); 192 | self.fd = -1; -- make it invalid 193 | end, 194 | 195 | read = function(self, buff, bufflen) 196 | local bytes = tonumber(ffi.C.read(self.fd, buff, bufflen)); 197 | 198 | if bytes > 0 then 199 | return bytes; 200 | end 201 | 202 | if bytes == 0 then 203 | return 0; 204 | end 205 | 206 | return false, ffi.errno(); 207 | end, 208 | 209 | write = function(self, buff, bufflen) 210 | local bytes = tonumber(ffi.C.write(self.fd, buff, bufflen)); 211 | 212 | if bytes > 0 then 213 | return bytes; 214 | end 215 | 216 | if bytes == 0 then 217 | return 0; 218 | end 219 | 220 | return false, ffi.errno(); 221 | end, 222 | 223 | setNonBlocking = function(self) 224 | local feature_on = ffi.new("int[1]",1) 225 | local ret = ffi.C.ioctl(self.fd, exports.FIONBIO, feature_on) 226 | return ret == 0; 227 | end, 228 | 229 | }; 230 | } 231 | ffi.metatype(filedesc, filedesc_mt); 232 | exports.filedesc = filedesc; 233 | 234 | 235 | return exports 236 | -------------------------------------------------------------------------------- /schedlua/linux/lookupsite.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | local net = require("schedlua.net") 3 | 4 | local function lookupsite(nodename, servname) 5 | --local servname = nil; -- "http" 6 | local res = ffi.new("struct addrinfo * [1]") 7 | local hints = ffi.new("struct addrinfo") 8 | 9 | --hints.ai_flags = net.AI_CANONNAME; 10 | hints.ai_family = net.AF_INET; 11 | hints.ai_socktype = net.SOCK_STREAM; 12 | 13 | local ret = ffi.C.getaddrinfo(nodename, servname, hints, res); 14 | --print("getaddrinfo: ", ret) 15 | if ret ~= 0 then 16 | return false, ret; 17 | end 18 | 19 | 20 | local sa = ffi.new("struct sockaddr") 21 | local addrlen = res[0].ai_addrlen; 22 | 23 | ffi.copy(sa, res[0].ai_addr, res[0].ai_addrlen) 24 | 25 | ffi.C.freeaddrinfo(res[0]); 26 | 27 | return sa, addrlen 28 | end 29 | 30 | return lookupsite 31 | -------------------------------------------------------------------------------- /schedlua/linux/nativesocket.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | local bit = require("bit") 3 | local band, bor, lshift, rshift = bit.band, bit.bor, bit.lshift, bit.rshift 4 | 5 | local net = require("schedlua.linux.linux_net") 6 | local epoll = require("schedlua.linux.epollio"); 7 | local errnos = require("schedlua.linux.linux_errno").errnos 8 | local lookupsite = require("schedlua.linux.lookupsite") 9 | 10 | 11 | --[[ 12 | Async IO Specific 13 | ]] 14 | local EventQuanta = 10; 15 | local MaxEvents = 100; -- number of events we'll ask per quanta 16 | local Events = ffi.new("struct epoll_event[?]", MaxEvents); 17 | local PollSet = epoll.epollset(); 18 | 19 | 20 | local IO_READ = 1; 21 | local IO_WRITE = 2; 22 | local IO_CONNECT = 3; 23 | 24 | 25 | local function sigNameFromFileDescriptor(fd) 26 | return "waitforio-"..fd 27 | end 28 | 29 | ---[[ 30 | local function sigNameFromEvent(event, title) 31 | title = title or ""; 32 | local fdesc = ffi.cast("filedesc *", event.data.ptr); 33 | --print("sigNameFromEvent, fdesc: ", fdesc) 34 | local fd = fdesc.fd; 35 | --print(" fd: ", fd); 36 | 37 | return sigNameFromFileDescriptor(fdesc.fd); 38 | end 39 | --]] 40 | 41 | local function setEventQuanta(quanta) 42 | EventQuanta = quanta; 43 | end 44 | 45 | 46 | local function watchForIOEvents(fd, event) 47 | return PollSet:add(fd, event); 48 | end 49 | 50 | -- This function allows us to wait for a specific IO event 51 | -- 52 | local function waitForIOEvent(fdesc, event, title) 53 | --print("waitForIOEvent: ", fdesc.fd, event, title) 54 | local success, err = PollSet:modify(fdesc.fd, event); 55 | 56 | local sigName = sigNameFromEvent(event, title); 57 | print("waitForIOEvent, modify, sigName: ", success, err, sigName) 58 | success, err = waitForSignal(sigName); 59 | print("waitForIOEvent, wait: ", success, err) 60 | 61 | return success, err; 62 | end 63 | 64 | 65 | 66 | local function ioAvailable() 67 | local success, events = PollSet:wait(Events, MaxEvents); 68 | 69 | print("ioAvailable, after wait: ", success, events, Events) 70 | 71 | if not success then return false end 72 | 73 | return success, events; 74 | end 75 | 76 | local function signalIOTasks(available, events) 77 | print("signalIOTasks: ", available, events) 78 | 79 | for idx=0,available-1 do 80 | --local event = ffi.cast("struct epoll_event *", ffi.cast("char *", Events)+ffi.sizeof("struct epoll_event")*idx); 81 | --print("signalIOTasks, ptr.data.ptr: ", ptr, ptr.data.ptr); 82 | local sigName = sigNameFromFileDescriptor(Events[idx].data.fd); 83 | print(string.format("signalIOTasks(), signaling: '%s'", sigName)) 84 | signalAll(sigName, Events[idx].events); 85 | end 86 | end 87 | 88 | 89 | 90 | --[[ 91 | Create something that represents a socket in the underlying 92 | operating system. 93 | --]] 94 | local NativeSocket = {} 95 | setmetatable(NativeSocket, { 96 | __call = function(self, ...) 97 | return self:create(...); 98 | end, 99 | }); 100 | 101 | local NativeSocket_mt = { 102 | __index = NativeSocket; 103 | } 104 | 105 | 106 | function NativeSocket:init(sock, kind, family, flags) 107 | local obj = { 108 | kind = kind; 109 | family = family; 110 | flags = flags; 111 | 112 | fdesc = net.filedesc(sock); 113 | } 114 | 115 | 116 | obj.fdesc:setNonBlocking(true); 117 | 118 | obj.WatchdogEvent = ffi.new("struct epoll_event") 119 | obj.WatchdogEvent.data.ptr = obj.fdesc; 120 | obj.WatchdogEvent.events = bor(epoll.EPOLLOUT,epoll.EPOLLIN, epoll.EPOLLRDHUP, epoll.EPOLLERR, epoll.EPOLLET); 121 | 122 | watchForIOEvents(obj.fdesc.fd, obj.WatchdogEvent); 123 | 124 | obj.ConnectEvent = ffi.new("struct epoll_event") 125 | obj.ConnectEvent.data.ptr = obj.fdesc; 126 | obj.ConnectEvent.events = bor(epoll.EPOLLOUT,epoll.EPOLLRDHUP, epoll.EPOLLERR, epoll.EPOLLET); 127 | 128 | obj.ReadEvent = ffi.new("struct epoll_event") 129 | obj.ReadEvent.data.ptr = obj.fdesc; 130 | obj.ReadEvent.events = bor(epoll.EPOLLIN, epoll.EPOLLERR); 131 | 132 | obj.WriteEvent = ffi.new("struct epoll_event") 133 | obj.WriteEvent.data.ptr = obj.fdesc; 134 | obj.WriteEvent.data.fd = obj.fdesc.fd; 135 | obj.WriteEvent.events = bor(epoll.EPOLLOUT, epoll.EPOLLERR); 136 | 137 | setmetatable(obj, NativeSocket_mt) 138 | 139 | return obj; 140 | end 141 | 142 | function NativeSocket:create(kind, flags, family) 143 | kind = kind or net.SOCK_STREAM; 144 | family = family or net.AF_INET 145 | flags = flags or 0; 146 | 147 | local sock = ffi.C.socket(family, kind, flags); 148 | 149 | --print("NativeSocket:create, sock: ", sock) 150 | 151 | if sock < 0 then 152 | return nil, ffi.errno(); 153 | end 154 | 155 | return self:init(sock, kind, family, flags) 156 | end 157 | 158 | 159 | 160 | 161 | function NativeSocket.setSocketOption(self, optname, on, level) 162 | local feature_on = ffi.new("int[1]") 163 | if on then feature_on[0] = 1; end 164 | level = level or net.SOL_SOCKET 165 | 166 | local ret = ffi.C.setsockopt(self.fdesc.fd, level, optname, feature_on, ffi.sizeof("int")) 167 | 168 | return ret == 0; 169 | end 170 | 171 | function NativeSocket.setNonBlocking(self, on) 172 | return self.fdesc:setNonBlocking(on); 173 | end 174 | 175 | function NativeSocket.setUseKeepAlive(self, on) 176 | return setSocketOption(self, net.SO_KEEPALIVE, on); 177 | end 178 | 179 | function NativeSocket.setReuseAddress(self, on) 180 | return setSocketOption(self, net.SO_REUSEADDR, on); 181 | end 182 | 183 | function NativeSocket.getLastError(self) 184 | local retVal = ffi.new("int[1]") 185 | local retValLen = ffi.new("int[1]", ffi.sizeof("int")) 186 | 187 | local ret = getSocketOption(self, net.SO_ERROR, retVal, retValLen) 188 | 189 | return retVal[0]; 190 | end 191 | 192 | function NativeSocket.connect(self, servername, port) 193 | local sa, size = lookupsite(servername); 194 | if not sa then 195 | return false, size; 196 | end 197 | ffi.cast("struct sockaddr_in *", sa):setPort(port); 198 | 199 | local ret = tonumber(ffi.C.connect(self.fdesc.fd, sa, size)); 200 | 201 | local err = ffi.errno(); 202 | if ret ~= 0 then 203 | if err ~= errnos.EINPROGRESS then 204 | return false, err; 205 | end 206 | end 207 | 208 | 209 | -- now wait for the socket to be writable 210 | local success, err = waitForIOEvent(self.fdesc, self.ConnectEvent); 211 | 212 | return success, err; 213 | end 214 | 215 | function NativeSocket.read(self, buff, bufflen) 216 | 217 | local success, err = waitForIOEvent(self.fdesc, self.ReadEvent); 218 | 219 | --print(string.format("AsyncSocket.read(), after wait: 0x%x %s", success, tostring(err))) 220 | 221 | if not success then 222 | print("AsyncSocket.read(), FAILED WAITING: ", string.format("0x%x",err)) 223 | return false, err; 224 | end 225 | 226 | 227 | local bytesRead = 0; 228 | 229 | if band(success, epoll.EPOLLIN) > 0 then 230 | bytesRead, err = self.fdesc:read(buff, bufflen); 231 | --print("async_read(), bytes read: ", bytesRead, err) 232 | end 233 | 234 | return bytesRead, err; 235 | end 236 | 237 | function NativeSocket.write(self, buff, bufflen) 238 | 239 | local success, err = waitForIOEvent(self.fdesc, self.WriteEvent); 240 | print(string.format("async_write, after wait: 0x%x %s", success, tostring(err))) 241 | if not success then 242 | return false, err; 243 | end 244 | 245 | local bytes = 0; 246 | 247 | if band(success, epoll.EPOLLOUT) > 0 then 248 | bytes, err = self.fdesc:write(buff, bufflen); 249 | --print("async_write(), bytes: ", bytes, err) 250 | end 251 | 252 | return bytes, err; 253 | end 254 | 255 | function NativeSocket.close(self) 256 | self.fdesc:close(); 257 | end 258 | 259 | 260 | -- Start off the iotask watchdog 261 | whenever(ioAvailable, signalIOTasks) 262 | 263 | return NativeSocket 264 | 265 | -------------------------------------------------------------------------------- /schedlua/linux/timeticker.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | 3 | 4 | -- mostly from time.h 5 | ffi.cdef[[ 6 | typedef int32_t clockid_t; 7 | typedef long time_t; 8 | 9 | struct timespec { 10 | time_t tv_sec; 11 | long tv_nsec; 12 | }; 13 | ]] 14 | 15 | local timespec = ffi.typeof("struct timespec") 16 | 17 | ffi.cdef[[ 18 | int clock_getres(clockid_t clk_id, struct timespec *res); 19 | int clock_gettime(clockid_t clk_id, struct timespec *tp); 20 | int clock_settime(clockid_t clk_id, const struct timespec *tp); 21 | int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request, struct timespec *remain); 22 | 23 | static const int CLOCK_REALTIME = 0; 24 | static const int CLOCK_MONOTONIC = 1; 25 | static const int CLOCK_PROCESS_CPUTIME_ID = 2; 26 | static const int CLOCK_THREAD_CPUTIME_ID = 3; 27 | static const int CLOCK_MONOTONIC_RAW = 4; 28 | static const int CLOCK_REALTIME_COARSE = 5; 29 | static const int CLOCK_MONOTONIC_COARSE = 6; 30 | static const int CLOCK_BOOTTIME = 7; 31 | static const int CLOCK_REALTIME_ALARM = 8; 32 | static const int CLOCK_BOOTTIME_ALARM = 9; 33 | static const int CLOCK_SGI_CYCLE = 10; // Hardware specific 34 | static const int CLOCK_TAI = 11; 35 | 36 | ]] 37 | 38 | 39 | local function GetCurrentTickTime() 40 | local tspec = timespec(); 41 | local res = ffi.C.clock_gettime(ffi.C.CLOCK_REALTIME, tspec) 42 | 43 | if res ~= 0 then 44 | return false, ffi.errno(); 45 | end 46 | 47 | local secs = tonumber(tspec.tv_sec) + (tonumber(tspec.tv_nsec) / 1000000000); -- one billion'th of a second 48 | 49 | return secs; 50 | end 51 | 52 | 53 | 54 | 55 | 56 | return { 57 | seconds = GetCurrentTickTime, 58 | } 59 | 60 | -------------------------------------------------------------------------------- /schedlua/net.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | 3 | ffi.cdef[[ 4 | typedef long ssize_t; 5 | 6 | typedef uint32_t in_addr_t; 7 | typedef uint16_t in_port_t; 8 | 9 | typedef unsigned short int sa_family_t; 10 | typedef unsigned int socklen_t; 11 | 12 | ]] 13 | 14 | 15 | local exports = { 16 | 17 | 18 | INADDR_ANY = 0x00000000; 19 | INADDR_LOOPBACK = 0x7f000001; 20 | INADDR_BROADCAST = 0xffffffff; 21 | INADDR_NONE = 0xffffffff; 22 | 23 | INET_ADDRSTRLEN = 16; 24 | INET6_ADDRSTRLEN = 46; 25 | 26 | -- Socket Types 27 | SOCK_STREAM = 1; -- stream socket 28 | SOCK_DGRAM = 2; -- datagram socket 29 | SOCK_RAW = 3; -- raw-protocol interface 30 | SOCK_RDM = 4; -- reliably-delivered message 31 | SOCK_SEQPACKET = 5; -- sequenced packet stream 32 | 33 | 34 | -- Address families 35 | AF_UNSPEC = 0; -- unspecified */ 36 | AF_LOCAL = 1; 37 | AF_UNIX = 1; -- local to host (pipes, portals) */ 38 | AF_INET = 2; -- internetwork: UDP, TCP, etc. */ 39 | AF_IMPLINK = 3; -- arpanet imp addresses */ 40 | AF_PUP = 4; -- pup protocols: e.g. BSP */ 41 | AF_CHAOS = 5; -- mit CHAOS protocols */ 42 | AF_IPX = 6; -- IPX and SPX */ 43 | AF_NS = 6; -- XEROX NS protocols */ 44 | AF_ISO = 7; -- ISO protocols */ 45 | AF_OSI = 7; -- OSI is ISO */ 46 | AF_ECMA = 8; -- european computer manufacturers */ 47 | AF_DATAKIT = 9; -- datakit protocols */ 48 | AF_CCITT = 10; -- CCITT protocols, X.25 etc */ 49 | AF_SNA = 11; -- IBM SNA */ 50 | AF_DECnet = 12; -- DECnet */ 51 | AF_DLI = 13; -- Direct data link interface */ 52 | AF_LAT = 14; -- LAT */ 53 | AF_HYLINK = 15; -- NSC Hyperchannel */ 54 | AF_APPLETALK = 16; -- AppleTalk */ 55 | AF_NETBIOS = 17; -- NetBios-style addresses */ 56 | AF_VOICEVIEW = 18; -- VoiceView */ 57 | AF_FIREFOX = 19; -- FireFox */ 58 | AF_UNKNOWN1 = 20; -- Somebody is using this! */ 59 | AF_BAN = 21; -- Banyan */ 60 | AF_INET6 = 23; -- Internetwork Version 6 61 | AF_SIP = 24; 62 | AF_IRDA = 26; -- IrDA 63 | AF_NETDES = 28; -- Network Designers OSI & gateway 64 | AF_INET6 = 28; 65 | 66 | 67 | AF_TCNPROCESS = 29; 68 | AF_TCNMESSAGE = 30; 69 | AF_ICLFXBM = 31; 70 | 71 | AF_BTH = 32; -- Bluetooth RFCOMM/L2CAP protocols 72 | AF_LINK = 33; 73 | AF_ARP = 35; 74 | AF_BLUETOOTH = 36; 75 | AF_MAX = 37; 76 | 77 | -- 78 | -- Protocols 79 | -- 80 | 81 | IPPROTO_IP = 0; -- dummy for IP 82 | IPPROTO_ICMP = 1; -- control message protocol 83 | IPPROTO_IGMP = 2; -- group management protocol 84 | IPPROTO_GGP = 3; -- gateway^2 (deprecated) 85 | IPPROTO_TCP = 6; -- tcp 86 | IPPROTO_PUP = 12; -- pup 87 | IPPROTO_UDP = 17; -- user datagram protocol 88 | IPPROTO_IDP = 22; -- xns idp 89 | IPPROTO_RDP = 27; 90 | IPPROTO_IPV6 = 41; -- IPv6 header 91 | IPPROTO_ROUTING = 43; -- IPv6 Routing header 92 | IPPROTO_FRAGMENT = 44; -- IPv6 fragmentation header 93 | IPPROTO_ESP = 50; -- encapsulating security payload 94 | IPPROTO_AH = 51; -- authentication header 95 | IPPROTO_ICMPV6 = 58; -- ICMPv6 96 | IPPROTO_NONE = 59; -- IPv6 no next header 97 | IPPROTO_DSTOPTS = 60; -- IPv6 Destination options 98 | IPPROTO_ND = 77; -- UNOFFICIAL net disk proto 99 | IPPROTO_ICLFXBM = 78; 100 | IPPROTO_PIM = 103; 101 | IPPROTO_PGM = 113; 102 | --IPPROTO_RM = IPPROTO_PGM; 103 | IPPROTO_L2TP = 115; 104 | IPPROTO_SCTP = 132; 105 | 106 | 107 | IPPROTO_RAW = 255; -- raw IP packet 108 | IPPROTO_MAX = 256; 109 | 110 | -- Possible values for `ai_flags' field in `addrinfo' structure. 111 | AI_PASSIVE = 0x0001; 112 | AI_CANONNAME = 0x0002; 113 | AI_NUMERICHOST = 0x0004; 114 | AI_V4MAPPED = 0x0008; 115 | AI_ALL = 0x0010; 116 | AI_ADDRCONFIG = 0x0020; 117 | AI_IDN = 0x0040; 118 | AI_CANONIDN = 0x0080; 119 | AI_IDN_ALLOW_UNASSIGNED = 0x0100; 120 | AI_IDN_USE_STD3_ASCII_RULES = 0x0200; 121 | AI_NUMERICSERV = 0x0400; 122 | } 123 | 124 | 125 | if ffi.abi("be") then -- nothing to do 126 | function exports.htonl(b) return b end 127 | function exports.htons(b) return b end 128 | else 129 | function exports.htonl(b) return bit.bswap(b) end 130 | function exports.htons(b) return bit.rshift(bit.bswap(b), 16) end 131 | end 132 | exports.ntohl = exports.htonl -- reverse is the same 133 | exports.ntohs = exports.htons -- reverse is the same 134 | 135 | ffi.cdef[[ 136 | struct in_addr { 137 | in_addr_t s_addr; 138 | }; 139 | 140 | struct in6_addr { 141 | unsigned char s6_addr[16]; 142 | }; 143 | ]] 144 | 145 | ffi.cdef[[ 146 | /* Structure describing a generic socket address. */ 147 | struct sockaddr { 148 | sa_family_t sa_family; 149 | char sa_data[14]; 150 | }; 151 | ]] 152 | 153 | ffi.cdef[[ 154 | struct sockaddr_in { 155 | sa_family_t sin_family; 156 | in_port_t sin_port; 157 | struct in_addr sin_addr; 158 | unsigned char sin_zero[sizeof (struct sockaddr) - 159 | (sizeof (unsigned short int)) - 160 | sizeof (in_port_t) - 161 | sizeof (struct in_addr)]; 162 | }; 163 | ]] 164 | 165 | 166 | 167 | ffi.cdef[[ 168 | struct sockaddr_in6 { 169 | uint8_t sin6_len; 170 | sa_family_t sin6_family; 171 | in_port_t sin6_port; 172 | uint32_t sin6_flowinfo; 173 | struct in6_addr sin6_addr; 174 | uint32_t sin6_scope_id; 175 | }; 176 | 177 | struct sockaddr_un 178 | { 179 | sa_family_t sun_family; 180 | char sun_path[108]; 181 | }; 182 | 183 | struct sockaddr_storage { 184 | // uint8_t ss_len; 185 | sa_family_t ss_family; 186 | char __ss_pad1[6]; 187 | int64_t __ss_align; 188 | char __ss_pad2[128 - 2 - 8 - 6]; 189 | }; 190 | ]] 191 | 192 | ffi.cdef[[ 193 | /* Structure used to manipulate the SO_LINGER option. */ 194 | struct linger 195 | { 196 | int l_onoff; /* Nonzero to linger on close. */ 197 | int l_linger; /* Time to linger. */ 198 | }; 199 | 200 | struct ethhdr { 201 | unsigned char h_dest[6]; 202 | unsigned char h_source[6]; 203 | unsigned short h_proto; /* __be16 */ 204 | } __attribute__((packed)); 205 | 206 | struct udphdr { 207 | uint16_t source; 208 | uint16_t dest; 209 | uint16_t len; 210 | uint16_t check; 211 | }; 212 | ]] 213 | 214 | 215 | return exports -------------------------------------------------------------------------------- /schedlua/predicate.lua: -------------------------------------------------------------------------------- 1 | --predicate.lua 2 | 3 | --[[ 4 | This, implementation of cooperative flow control mechanisms. 5 | The routines essentially wrap basic signaling with convenient words 6 | and spawning operations. 7 | 8 | The fundamental building block is the 'predicate', which is nothing more 9 | than a function which returns a boolean value. 10 | 11 | The typical usage will be to block a task with 'waitForPredicate', which will 12 | suspend the current task until the specified predicate returns a value of 'true'. 13 | It will then be resumed from that point. 14 | 15 | waitForPredicate 16 | signalOnPredicate 17 | when 18 | whenever 19 | --]] 20 | 21 | local spawn = spawn; 22 | local signalAll = signalAll; 23 | local signalOne = signalOne; 24 | local getCurrentTaskID = getCurrentTaskID; 25 | 26 | 27 | local function waitForPredicate(pred) 28 | local signalName = "predicate-"..tostring(getCurrentTaskID()); 29 | signalOnPredicate(pred, signalName); 30 | return waitForSignal(signalName); 31 | end 32 | 33 | local function signalOnPredicate(pred, signalName) 34 | local function closure(lpred) 35 | local res = nil; 36 | repeat 37 | res = lpred(); 38 | if res then 39 | return signalAllImmediate(signalName, res) 40 | end; 41 | 42 | yield(); 43 | until res == nil 44 | end 45 | 46 | return spawn(closure, pred) 47 | end 48 | 49 | 50 | 51 | local function when(pred, func) 52 | local function closure(lpred, lfunc) 53 | lfunc(waitForPredicate(lpred)) 54 | end 55 | 56 | return spawn(closure, pred, func) 57 | end 58 | 59 | local function whenever(pred, func) 60 | local function closure(lpred, lfunc) 61 | local signalName = "whenever-"..tostring(getCurrentTaskID()); 62 | local res = true; 63 | repeat 64 | signalOnPredicate(lpred, signalName); 65 | res = waitForSignal(signalName); 66 | lfunc(res) 67 | until false 68 | end 69 | 70 | return spawn(closure, pred, func) 71 | end 72 | 73 | local function globalize(tbl) 74 | tbl = tbl or _G; 75 | 76 | rawset(tbl,"signalOnPredicate", signalOnPredicate); 77 | rawset(tbl,"waitForPredicate", waitForPredicate); 78 | rawset(tbl,"waitForTruth", waitForPredicate); 79 | rawset(tbl,"when", when); 80 | rawset(tbl,"whenever", whenever); 81 | 82 | return tbl; 83 | end 84 | 85 | return globalize() 86 | 87 | -------------------------------------------------------------------------------- /schedlua/queue.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Queue 3 | 4 | The Queue is a simple data structure that represents a 5 | first in first out behavior. 6 | --]] 7 | local tabutils = require("schedlua.tabutils") 8 | 9 | local Queue = {} 10 | setmetatable(Queue, { 11 | __call = function(self, ...) 12 | return self:create(...); 13 | end, 14 | }); 15 | 16 | local Queue_mt = { 17 | __index = Queue; 18 | } 19 | 20 | function Queue.init(self, first, last, name) 21 | first = first or 1; 22 | last = last or 0; 23 | 24 | local obj = { 25 | first=first, 26 | last=last, 27 | name=name}; 28 | 29 | setmetatable(obj, Queue_mt); 30 | 31 | return obj 32 | end 33 | 34 | function Queue.create(self, first, last, name) 35 | first = first or 1 36 | last = last or 0 37 | 38 | return self:init(first, last, name); 39 | end 40 | 41 | --[[ 42 | function Queue.new(name) 43 | return Queue:init(1, 0, name); 44 | end 45 | --]] 46 | 47 | function Queue:pushFront(value) 48 | -- PushLeft 49 | local first = self.first - 1; 50 | self.first = first; 51 | self[first] = value; 52 | end 53 | 54 | function Queue:pinsert(value, fcomp) 55 | tabutils.binsert(self, value, fcomp) 56 | self.last = self.last + 1; 57 | end 58 | 59 | function Queue:enqueue(value) 60 | --self.MyList:PushRight(value) 61 | local last = self.last + 1 62 | self.last = last 63 | self[last] = value 64 | 65 | return value 66 | end 67 | 68 | function Queue:dequeue(value) 69 | -- return self.MyList:PopLeft() 70 | local first = self.first 71 | 72 | if first > self.last then 73 | return nil, "list is empty" 74 | end 75 | 76 | local value = self[first] 77 | self[first] = nil -- to allow garbage collection 78 | self.first = first + 1 79 | 80 | return value 81 | end 82 | 83 | function Queue:length() 84 | return self.last - self.first+1 85 | end 86 | 87 | -- Returns an iterator over all the current 88 | -- values in the queue 89 | function Queue:Entries(func, param) 90 | local starting = self.first-1; 91 | local len = self:length(); 92 | 93 | local closure = function() 94 | starting = starting + 1; 95 | return self[starting]; 96 | end 97 | 98 | return closure; 99 | end 100 | 101 | 102 | return Queue; 103 | -------------------------------------------------------------------------------- /schedlua/scheduler.lua: -------------------------------------------------------------------------------- 1 | 2 | local ffi = require("ffi"); 3 | 4 | local Queue = require("schedlua.queue") 5 | local Task = require("schedlua.task"); 6 | local tabutils = require("schedlua.tabutils") 7 | 8 | 9 | 10 | local Scheduler = {} 11 | setmetatable(Scheduler, { 12 | __call = function(self, ...) 13 | return self:new(...) 14 | end, 15 | }) 16 | local Scheduler_mt = { 17 | __index = Scheduler, 18 | } 19 | 20 | function Scheduler.init(self, ...) 21 | local obj = { 22 | TasksReadyToRun = Queue(); 23 | } 24 | setmetatable(obj, Scheduler_mt) 25 | 26 | return obj; 27 | end 28 | 29 | function Scheduler.new(self, ...) 30 | return self:init(...) 31 | end 32 | 33 | --[[ 34 | Instance Methods 35 | --]] 36 | --[[ 37 | tasksPending 38 | 39 | A simple method to let anyone know how many tasks are currently 40 | on the ready to run list. 41 | 42 | This might be useful when you're running some predicate logic based 43 | on how many tasks there are. 44 | --]] 45 | function Scheduler.tasksPending(self) 46 | return self.TasksReadyToRun:length(); 47 | end 48 | 49 | 50 | --[[ 51 | Task Handling 52 | --]] 53 | 54 | -- put a task on the ready list 55 | -- the 'task' should be something that can be executed, 56 | -- whether it's a function, functor, or something that has a '__call' 57 | -- metamethod implemented. 58 | -- The 'params' is a table of parameters which will be passed to the task 59 | -- when it's ready to run. 60 | function Scheduler.scheduleTask(self, task, params, priority) 61 | --print("Scheduler.scheduleTask: ", task, params) 62 | params = params or {} 63 | 64 | if not task then 65 | return false, "no task specified" 66 | end 67 | 68 | task:setParams(params); 69 | 70 | 71 | if priority == 0 then 72 | self.TasksReadyToRun:pushFront(task); 73 | else 74 | self.TasksReadyToRun:enqueue(task); 75 | end 76 | 77 | task.state = "readytorun" 78 | 79 | return task; 80 | end 81 | 82 | function Scheduler.removeTask(self, task) 83 | --print("REMOVING DEAD TASK: ", task); 84 | return true; 85 | end 86 | 87 | function Scheduler.getCurrentTask(self) 88 | return self.CurrentFiber; 89 | end 90 | 91 | function Scheduler.suspendCurrentTask(self, ...) 92 | self.CurrentFiber.state = "suspended" 93 | end 94 | 95 | function Scheduler.step(self) 96 | -- Now check the regular fibers 97 | local task = self.TasksReadyToRun:dequeue() 98 | 99 | -- If no fiber in ready queue, then just return 100 | if task == nil then 101 | --print("Scheduler.step: NO TASK") 102 | return true 103 | end 104 | 105 | if task:getStatus() == "dead" then 106 | self:removeTask(task) 107 | 108 | return true; 109 | end 110 | 111 | -- If the task we pulled off the active list is 112 | -- not dead, then perhaps it is suspended. If that's true 113 | -- then it needs to drop out of the active list. 114 | -- We assume that some other part of the system is responsible for 115 | -- keeping track of the task, and rescheduling it when appropriate. 116 | if task.state == "suspended" then 117 | --print("suspended task wants to run") 118 | return true; 119 | end 120 | 121 | -- If we have gotten this far, then the task truly is ready to 122 | -- run, and it should be set as the currentFiber, and its coroutine 123 | -- is resumed. 124 | self.CurrentFiber = task; 125 | local results = {task:resume()}; 126 | 127 | -- once we get results back from the resume, one 128 | -- of two things could have happened. 129 | -- 1) The routine exited normally 130 | -- 2) The routine yielded 131 | -- 132 | -- In both cases, we parse out the results of the resume 133 | -- into a success indicator and the rest of the values returned 134 | -- from the routine 135 | --local pcallsuccess = results[1]; 136 | --table.remove(results,1); 137 | 138 | local success = results[1]; 139 | table.remove(results,1); 140 | 141 | --print("PCALL, RESUME: ", pcallsuccess, success) 142 | 143 | -- no task is currently executing 144 | self.CurrentFiber = nil; 145 | 146 | 147 | if not success then 148 | print("RESUME ERROR") 149 | print(unpack(results)); 150 | end 151 | 152 | -- Again, check to see if the task is dead after 153 | -- the most recent resume. If it's dead, then don't 154 | -- bother putting it back into the readytorun queue 155 | -- just remove the task from the list of tasks 156 | if task:getStatus() == "dead" then 157 | self:removeTask(task) 158 | 159 | return true; 160 | end 161 | 162 | -- The only way the task will get back onto the readylist 163 | -- is if it's state is 'readytorun', otherwise, it will 164 | -- stay out of the readytorun list. 165 | if task.state == "readytorun" then 166 | self:scheduleTask(task, results); 167 | end 168 | end 169 | 170 | return Scheduler 171 | -------------------------------------------------------------------------------- /schedlua/stopwatch.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | 3 | local timeticker = nil; 4 | 5 | if ffi.os == "Windows" then 6 | timeticker = require("schedlua.windows.timeticker") 7 | else 8 | timeticker = require("schedlua.linux.timeticker") 9 | end 10 | 11 | 12 | local StopWatch = {} 13 | setmetatable(StopWatch, { 14 | __call = function(self, ...) 15 | return self:create(...); 16 | end; 17 | 18 | }) 19 | 20 | local StopWatch_mt = { 21 | __index = StopWatch; 22 | } 23 | 24 | function StopWatch.init(self, ...) 25 | 26 | local obj = { 27 | starttime = 0; 28 | } 29 | setmetatable(obj, StopWatch_mt); 30 | obj:reset(); 31 | 32 | return obj; 33 | end 34 | 35 | 36 | function StopWatch.create(self, ...) 37 | return self:init(); 38 | end 39 | 40 | function StopWatch.seconds(self) 41 | local currentTime = timeticker.seconds(); 42 | return currentTime - self.starttime; 43 | end 44 | 45 | function StopWatch.reset(self) 46 | self.starttime = timeticker.seconds(); 47 | end 48 | 49 | 50 | return StopWatch 51 | -------------------------------------------------------------------------------- /schedlua/tabutils.lua: -------------------------------------------------------------------------------- 1 | -- tabutils.lua 2 | local floor = math.floor; 3 | local insert = table.insert; 4 | 5 | local function fcomp_default( a,b ) 6 | return a < b 7 | end 8 | 9 | local function getIndex(t, value, fcomp) 10 | local fcomp = fcomp or fcomp_default 11 | 12 | local iStart = 1; 13 | local iEnd = #t; 14 | local iMid = 1; 15 | local iState = 0; 16 | 17 | while iStart <= iEnd do 18 | -- calculate middle 19 | iMid = floor( (iStart+iEnd)/2 ); 20 | 21 | -- compare 22 | if fcomp( value,t[iMid] ) then 23 | iEnd = iMid - 1; 24 | iState = 0; 25 | else 26 | iStart = iMid + 1; 27 | iState = 1; 28 | end 29 | end 30 | 31 | return (iMid+iState); 32 | end 33 | 34 | local function binsert(tbl, value, fcomp) 35 | local idx = getIndex(tbl, value, fcomp); 36 | insert( tbl, idx, value); 37 | 38 | return idx; 39 | end 40 | 41 | 42 | return { 43 | getIndex = getIndex, 44 | binsert = binsert, 45 | } 46 | -------------------------------------------------------------------------------- /schedlua/task.lua: -------------------------------------------------------------------------------- 1 | 2 | --[[ 3 | Task, contains stuff related to encapsulated code 4 | --]] 5 | local Task = {} 6 | 7 | setmetatable(Task, { 8 | __call = function(self, ...) 9 | return self:create(...); 10 | end, 11 | }); 12 | 13 | local Task_mt = { 14 | __index = Task, 15 | } 16 | 17 | function Task.init(self, aroutine, ...) 18 | 19 | local obj = { 20 | routine = coroutine.create(aroutine), 21 | } 22 | setmetatable(obj, Task_mt); 23 | 24 | obj:setParams({...}); 25 | 26 | return obj 27 | end 28 | 29 | function Task.create(self, aroutine, ...) 30 | -- The 'aroutine' should be something that is callable 31 | -- either a function, or a table with a meta '__call' 32 | -- implementation. Checking with type == 'function' 33 | -- is not good enough as it will miss the meta __call cases 34 | 35 | return self:init(aroutine, ...) 36 | end 37 | 38 | 39 | function Task.getStatus(self) 40 | return coroutine.status(self.routine); 41 | end 42 | 43 | -- A function that can be used as a predicate 44 | function Task.isFinished(self) 45 | return task:getStatus() == "dead" 46 | end 47 | 48 | 49 | function Task.setParams(self, params) 50 | self.params = params 51 | 52 | return self; 53 | end 54 | 55 | function Task.resume(self) 56 | --print("Task, RESUMING: ", unpack(self.params)); 57 | return coroutine.resume(self.routine, unpack(self.params)); 58 | end 59 | 60 | 61 | return Task; 62 | -------------------------------------------------------------------------------- /schedlua/windows/arch.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | 3 | local arch = {} 4 | 5 | function arch.stringToPointer(str) 6 | local num = tonumber(str); 7 | if not num then 8 | return nil, "invalid number"; 9 | end 10 | 11 | return ffi.cast("void *", ffi.cast("intptr_t", num)); 12 | end 13 | 14 | 15 | -- This helper routine will take a pointer 16 | -- to cdata, and return a string that contains 17 | -- the memory address 18 | -- tonumber(ffi.cast('intptr_t', ffi.cast('void *', ptr))) 19 | function arch.pointerToString(instance) 20 | if ffi.abi("64bit") then 21 | return string.format("0x%016x", tonumber(ffi.cast("int64_t", ffi.cast("void *", instance)))) 22 | elseif ffi.abi("32bit") then 23 | return string.format("0x%08x", tonumber(ffi.cast("int32_t", ffi.cast("void *", instance)))) 24 | end 25 | 26 | return nil; 27 | end 28 | 29 | function arch.fieldAddress(astruct, fieldname) 30 | local structtype = ffi.typeof(astruct); 31 | local offset = ffi.offsetof(structtype, fieldname); 32 | local structptr = ffi.cast("uint8_t *", astruct); 33 | 34 | return structptr + offset; 35 | end 36 | 37 | return arch; 38 | -------------------------------------------------------------------------------- /schedlua/windows/asyncio.lua: -------------------------------------------------------------------------------- 1 | -- waitForIO.lua 2 | 3 | local ffi = require("ffi") 4 | local iocompletionset = require("IOCompletionPort"); 5 | local arch = require("arch") 6 | 7 | 8 | local EventQuanta = 10; 9 | local ContinueRunning = true; 10 | local PollSet = iopoll(); 11 | local MaxEvents = 100; -- number of events we'll ask per quanta 12 | 13 | local READ = 1; 14 | local WRITE = 2; 15 | local CONNECT = 3; 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | function waitForIO.init(self, scheduler) 24 | -- print("waitForIO.init, MessageQuanta: ", self.MessageQuanta) 25 | 26 | local obj = { 27 | IOEventQueue = IOCompletionPort:create(); 28 | FibersAwaitingEvent = {}; 29 | EventFibers = {}; 30 | 31 | MessageQuanta = self.MessageQuanta; -- milliseconds 32 | OperationId = 0; 33 | } 34 | setmetatable(obj, waitForIO_mt) 35 | 36 | return obj; 37 | end 38 | 39 | function waitForIO.create(self, scheduler) 40 | scheduler = scheduler or self.Scheduler 41 | 42 | if not scheduler then 43 | return nil, "no scheduler specified" 44 | end 45 | 46 | return self:init(scheduler) 47 | end 48 | 49 | function waitForIO.setMessageQuanta(self, quanta) 50 | self.MessageQuanta = quanta; 51 | end 52 | 53 | function waitForIO.setScheduler(self, scheduler) 54 | self.Scheduler = scheduler; 55 | end 56 | 57 | function waitForIO.tasksArePending(self) 58 | local fibersawaitio = false; 59 | 60 | for fiber in pairs(self.FibersAwaitingEvent) do 61 | fibersawaitio = true; 62 | break; 63 | end 64 | 65 | return fibersawaitio 66 | end 67 | 68 | 69 | local function getNextOperationId() 70 | OperationId = OperationId + 1; 71 | return OperationId; 72 | end 73 | 74 | local function watchForIOEvents(handle, param) 75 | --print("waitForIO.observeIOEvent, adding: ", handle, param) 76 | 77 | return PollSet:add(handle, param); 78 | end 79 | 80 | --[[ 81 | function waitForIO.yield(self, socket, overlapped) 82 | --print("== waitForIO.yield: BEGIN: ", arch.pointerToString(overlapped)); 83 | 84 | local currentFiber = self.Scheduler:getCurrentFiber() 85 | 86 | if not currentFiber then 87 | print("waitForIO.yield: NO CURRENT FIBER"); 88 | return nil, "not currently running within a task" 89 | end 90 | 91 | -- Track the task based on the overlapped structure 92 | self.EventFibers[arch.pointerToString(overlapped)] = currentFiber; 93 | self.FibersAwaitingEvent[currentFiber] = true; 94 | 95 | return self.Scheduler:suspend() 96 | end 97 | --]] 98 | 99 | 100 | local function processIOEvent(key, numbytes, overlapped) 101 | --print("waitForIO.processIOEvent: ", key, numbytes, arch.pointerToString(overlapped)) 102 | 103 | local ovl = ffi.cast("IOOverlapped *", overlapped); 104 | 105 | ovl.bytestransferred = numbytes; 106 | 107 | -- Find the task that is waiting for this IO event 108 | local fiber = self.EventFibers[arch.pointerToString(overlapped)] 109 | 110 | --print("waitForIO: fiber wiating: ", fiber) 111 | 112 | if not fiber then 113 | print("waitForIO: No fiber waiting for IO Completion") 114 | return false, "waitForIO.processIOEvent,NO FIBER WAITING FOR IO EVENT: " 115 | end 116 | 117 | -- remove the task from the list of tasks that are 118 | -- waiting for an IO event 119 | self.FibersAwaitingEvent[fiber] = nil; 120 | 121 | -- remove the fiber from the index based on the 122 | -- overlapped structure 123 | self.EventFibers[arch.pointerToString(overlapped)] = nil; 124 | --print("waitForIO.processIOEvent, before rescheduler:", key, numbytes, overlapped) 125 | local task = self.Scheduler:scheduleTask(fiber, {key, numbytes, overlapped}); 126 | --print("after reschedule: ", task.state) 127 | 128 | return true; 129 | end 130 | 131 | 132 | local function watchdog() 133 | while true do 134 | -- Check to see if there are any IO Events to deal with 135 | --local key, numbytes, overlapped = self.IOEventQueue:dequeue(self.MessageQuanta); 136 | local param1, param2, param3, param4, param5 = self.IOEventQueue:dequeue(self.MessageQuanta); 137 | 138 | --print("waitForIO.step: ", param1, param2) 139 | 140 | local key, bytes, ovl 141 | 142 | -- First check to see if we've got a timeout 143 | -- if so, then just return immediately 144 | if not param1 then 145 | if param2 == WAIT_TIMEOUT then 146 | return true; 147 | end 148 | 149 | -- other errors that can occur at this point 150 | -- could either be iocp errors, or they could 151 | -- be socket specific errors 152 | -- If the error is ERROR_NETNAME_DELETED 153 | -- a socket has closed, so do something about it? 154 | --[[ 155 | if param2 == ERROR_NETNAME_DELETED then 156 | print("Processor.stepIOEvents(), ERROR_NETNAME_DELETED: ", param3); 157 | else 158 | print("Processor.stepIOEvents(), ERROR: ", param3, param2); 159 | end 160 | --]] 161 | key = param3; 162 | bytes = param4; 163 | ovl = param5; 164 | else 165 | key = param1; 166 | bytes = param2; 167 | ovl = param3; 168 | end 169 | 170 | local status, err = processIOEvent(key, bytes, ovl); 171 | 172 | yield() 173 | end 174 | end 175 | 176 | function watchdog(self) 177 | while true do 178 | local status, err = self:step(); 179 | --print("waitForIO.start, status, err: ", status, err) 180 | 181 | yield(); 182 | end 183 | end 184 | 185 | 186 | return waitForIO 187 | -------------------------------------------------------------------------------- /schedlua/windows/basetsd.lua: -------------------------------------------------------------------------------- 1 | 2 | local ffi = require("ffi"); 3 | 4 | _WIN64 = (ffi.os == "Windows") and ffi.abi("64bit"); 5 | 6 | -- intsafe.h contains many of these base 7 | -- definitions as well. 8 | 9 | ffi.cdef[[ 10 | typedef char CHAR; 11 | typedef unsigned char UCHAR; 12 | typedef unsigned char BYTE; 13 | typedef int16_t SHORT; 14 | typedef unsigned short USHORT; 15 | typedef uint16_t WORD; 16 | typedef int INT; 17 | typedef unsigned int UINT; 18 | typedef long LONG; 19 | typedef unsigned long ULONG; 20 | typedef unsigned long DWORD; 21 | typedef int64_t LONGLONG; 22 | typedef uint64_t ULONGLONG; 23 | typedef uint64_t DWORDLONG; 24 | ]] 25 | 26 | ffi.cdef[[ 27 | typedef uint64_t *PDWORDLONG; 28 | ]] 29 | 30 | ffi.cdef[[ 31 | typedef int8_t INT8, *PINT8; 32 | typedef int16_t INT16, *PINT16; 33 | typedef int32_t INT32, *PINT32; 34 | typedef int64_t INT64, *PINT64; 35 | typedef uint8_t UINT8, *PUINT8; 36 | typedef uint16_t UINT16, *PUINT16; 37 | typedef uint32_t UINT32, *PUINT32; 38 | typedef uint64_t UINT64, *PUINT64; 39 | ]] 40 | 41 | ffi.cdef[[ 42 | // 43 | // The following types are guaranteed to be signed and 32 bits wide. 44 | // 45 | 46 | typedef int32_t LONG32, *PLONG32; 47 | 48 | // 49 | // The following types are guaranteed to be unsigned and 32 bits wide. 50 | // 51 | 52 | typedef uint32_t ULONG32, *PULONG32; 53 | typedef uint32_t DWORD32, *PDWORD32; 54 | ]] 55 | 56 | if _WIN64 then 57 | ffi.cdef[[ 58 | typedef int64_t INT_PTR, *PINT_PTR; 59 | typedef uint64_t UINT_PTR, *PUINT_PTR; 60 | typedef intptr_t LONG_PTR, *PLONG_PTR, *PLONG_PTR; 61 | typedef uint64_t ULONG_PTR, *PULONG_PTR; 62 | ]] 63 | else 64 | ffi.cdef[[ 65 | typedef int INT_PTR, *PINT_PTR; 66 | typedef unsigned int UINT_PTR, *PUINT_PTR; 67 | typedef intptr_t LONG_PTR, *PLONG_PTR; 68 | typedef unsigned long ULONG_PTR, *PULONG_PTR; 69 | ]] 70 | 71 | end 72 | 73 | ffi.cdef[[ 74 | typedef ULONG_PTR SIZE_T, *PSIZE_T; 75 | typedef LONG_PTR SSIZE_T, *PSSIZE_T; 76 | ]] 77 | 78 | 79 | ffi.cdef[[ 80 | // 81 | // Add Windows flavor DWORD_PTR types 82 | // 83 | 84 | typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; 85 | 86 | // 87 | // The following types are guaranteed to be signed and 64 bits wide. 88 | // 89 | 90 | typedef int64_t LONG64, *PLONG64; 91 | 92 | // 93 | // The following types are guaranteed to be unsigned and 64 bits wide. 94 | // 95 | 96 | typedef uint64_t ULONG64, *PULONG64; 97 | typedef uint64_t DWORD64, *PDWORD64; 98 | 99 | // 100 | // Structure to represent a group-specific affinity, such as that of a 101 | // thread. Specifies the group number and the affinity within that group. 102 | // 103 | typedef ULONG_PTR KAFFINITY; 104 | typedef KAFFINITY *PKAFFINITY; 105 | ]] 106 | -------------------------------------------------------------------------------- /schedlua/windows/core_errorhandling_l1_1_1.lua: -------------------------------------------------------------------------------- 1 | -- core_errorhandling_l1_1_1.lua 2 | -- api-ms-win-core-errorhandling-l1-1-1.dll 3 | 4 | local ffi = require("ffi"); 5 | 6 | local k32Lib = ffi.load("kernel32"); 7 | local WTypes = require ("WTypes"); 8 | local WinNT = require("WinNT"); 9 | 10 | 11 | ffi.cdef[[ 12 | static const int SEM_FAILCRITICALERRORS =0x0001; 13 | static const int SEM_NOGPFAULTERRORBOX =0x0002; 14 | static const int SEM_NOALIGNMENTFAULTEXCEPT =0x0004; 15 | static const int SEM_NOOPENFILEERRORBOX =0x8000; 16 | ]] 17 | 18 | ffi.cdef[[ 19 | typedef LONG (* PTOP_LEVEL_EXCEPTION_FILTER)(struct _EXCEPTION_POINTERS *ExceptionInfo); 20 | typedef PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER; 21 | ]] 22 | 23 | ffi.cdef[[ 24 | PVOID 25 | AddVectoredContinueHandler (ULONG First, PVECTORED_EXCEPTION_HANDLER Handler); 26 | 27 | PVOID 28 | AddVectoredExceptionHandler (ULONG First, PVECTORED_EXCEPTION_HANDLER Handler); 29 | 30 | UINT 31 | GetErrorMode(void); 32 | 33 | DWORD 34 | GetLastError(void); 35 | 36 | void 37 | RaiseException( 38 | DWORD dwExceptionCode, 39 | DWORD dwExceptionFlags, 40 | DWORD nNumberOfArguments, 41 | const ULONG_PTR *lpArguments); 42 | 43 | ULONG 44 | RemoveVectoredContinueHandler (PVOID Handle); 45 | 46 | ULONG 47 | RemoveVectoredExceptionHandler (PVOID Handle); 48 | 49 | void 50 | RestoreLastError(DWORD dwErrCode); 51 | 52 | UINT 53 | SetErrorMode(UINT uMode); 54 | 55 | void 56 | SetLastError(DWORD dwErrCode); 57 | 58 | LPTOP_LEVEL_EXCEPTION_FILTER 59 | SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); 60 | 61 | LONG 62 | UnhandledExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo); 63 | 64 | ]] 65 | 66 | 67 | return { 68 | Lib = k32Lib, 69 | 70 | AddVectoredContinueHandler = k32Lib.AddVectoredContinueHandler, 71 | AddVectoredExceptionHandler = k32Lib.AddVectoredExceptionHandler, 72 | GetErrorMode = k32Lib.GetErrorMode, 73 | GetLastError = k32Lib.GetLastError, 74 | RaiseException = k32Lib.RaiseException, 75 | RemoveVectoredContinueHandler = k32Lib.RemoveVectoredContinueHandler, 76 | RemoveVectoredExceptionHandler = k32Lib.RemoveVectoredExceptionHandler, 77 | RestoreLastError = k32Lib.RestoreLastError, 78 | SetErrorMode = k32Lib.SetErrorMode, 79 | SetLastError = k32Lib.SetLastError, 80 | SetUnhandledExceptionFilter = k32Lib.SetUnhandledExceptionFilter, 81 | UnhandledExceptionFilter = k32Lib.UnhandledExceptionFilter, 82 | } 83 | -------------------------------------------------------------------------------- /schedlua/windows/core_io_l1_1_1.lua: -------------------------------------------------------------------------------- 1 | -- core_io_l1_1_1.lua 2 | -- api-ms-win-core-io-l1-1-1.dll 3 | 4 | local ffi = require("ffi"); 5 | local Lib = ffi.load("kernel32"); 6 | 7 | local WinBase = require("schedlua.windows.winbase"); 8 | 9 | ffi.cdef[[ 10 | BOOL 11 | CancelIo(HANDLE hFile); 12 | 13 | BOOL 14 | CancelIoEx(HANDLE hFile, 15 | LPOVERLAPPED lpOverlapped); 16 | 17 | BOOL 18 | CancelSynchronousIo(HANDLE hThread); 19 | 20 | 21 | HANDLE CreateIoCompletionPort(HANDLE FileHandle, 22 | HANDLE ExistingCompletionPort, 23 | ULONG_PTR CompletionKey, 24 | DWORD NumberOfConcurrentThreads); 25 | 26 | BOOL 27 | DeviceIoControl( 28 | HANDLE hDevice, 29 | DWORD dwIoControlCode, 30 | LPVOID lpInBuffer, 31 | DWORD nInBufferSize, 32 | LPVOID lpOutBuffer, 33 | DWORD nOutBufferSize, 34 | LPDWORD lpBytesReturned, 35 | LPOVERLAPPED lpOverlapped 36 | ); 37 | 38 | BOOL 39 | GetOverlappedResult( 40 | HANDLE hFile, 41 | LPOVERLAPPED lpOverlapped, 42 | LPDWORD lpNumberOfBytesTransferred, 43 | BOOL bWait 44 | ); 45 | 46 | BOOL GetQueuedCompletionStatus( 47 | HANDLE CompletionPort, 48 | LPDWORD lpNumberOfBytesTransferred, 49 | PULONG_PTR lpCompletionKey, 50 | LPOVERLAPPED *lpOverlapped, 51 | DWORD dwMilliseconds 52 | ); 53 | 54 | BOOL 55 | GetQueuedCompletionStatusEx( 56 | HANDLE CompletionPort, 57 | LPOVERLAPPED_ENTRY lpCompletionPortEntries, 58 | ULONG ulCount, 59 | PULONG ulNumEntriesRemoved, 60 | DWORD dwMilliseconds, 61 | BOOL fAlertable 62 | ); 63 | 64 | BOOL PostQueuedCompletionStatus( 65 | HANDLE CompletionPort, 66 | DWORD dwNumberOfBytesTransferred, 67 | ULONG_PTR dwCompletionKey, 68 | LPOVERLAPPED lpOverlapped 69 | ); 70 | ]] 71 | 72 | return { 73 | Lib = Lib, 74 | 75 | CancelIo = Lib.CancelIo, 76 | CancelIoEx = Lib.CancelIoEx, 77 | CancelSynchronousIo = Lib.CancelSynchronousIo, 78 | CreateIoCompletionPort = Lib.CreateIoCompletionPort, 79 | DeviceIoControl = Lib.DeviceIoControl, 80 | GetOverlappedResult = Lib.GetOverlappedResult, 81 | -- GetOverlappedResultEx = Lib.GetOverlappedResultEx, 82 | GetQueuedCompletionStatus = Lib.GetQueuedCompletionStatus, 83 | GetQueuedCompletionStatusEx = Lib.GetQueuedCompletionStatusEx, 84 | PostQueuedCompletionStatus = Lib.PostQueuedCompletionStatus, 85 | } 86 | -------------------------------------------------------------------------------- /schedlua/windows/guiddef.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- From guiddef.h 3 | -- 4 | local ffi = require "ffi" 5 | local C = ffi.C 6 | 7 | 8 | ffi.cdef[[ 9 | typedef struct { 10 | unsigned long Data1; 11 | unsigned short Data2; 12 | unsigned short Data3; 13 | unsigned char Data4[8]; 14 | } GUID, UUID, *LPGUID; 15 | ]] 16 | 17 | ffi.cdef[[ 18 | typedef const GUID * LPCGUID; 19 | typedef const GUID * REFGUID; 20 | 21 | typedef GUID IID; 22 | typedef IID * LPIID; 23 | typedef const IID * REFIID; 24 | 25 | typedef GUID CLSID; 26 | typedef CLSID * LPCLSID; 27 | typedef const GUID * REFCLSID; 28 | ]] 29 | 30 | ffi.cdef[[ 31 | typedef GUID FMTID; 32 | typedef FMTID *LPFMTID; 33 | ]] 34 | 35 | 36 | local function bytecompare(a, b, n) 37 | local res = true 38 | for i=0,n-1 do 39 | if a[i] ~= b[i] then 40 | return false 41 | end 42 | end 43 | return res 44 | end 45 | 46 | GUID = ffi.typeof("GUID"); 47 | GUID_mt = { 48 | __tostring = function(self) 49 | local res = string.format("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 50 | self.Data1, self.Data2, self.Data3, 51 | self.Data4[0], self.Data4[1], 52 | self.Data4[2], self.Data4[3], self.Data4[4], 53 | self.Data4[5], self.Data4[6], self.Data4[7]) 54 | return res 55 | end, 56 | 57 | __eq = function(a, b) 58 | return (a.Data1 == b.Data1) and 59 | (a.Data2 == b.Data2) and 60 | (a.Data3 == b.Data3) and 61 | bytecompare(a.Data4, b.Data4, 4) 62 | end, 63 | 64 | __index = { 65 | Define = function(self, name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8 ) 66 | return GUID({ l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }), name 67 | end, 68 | 69 | DefineOle = function(self, name, l, w1, w2) 70 | return GUID({ l, w1, w2, { 0xC0,0,0,0,0,0,0,0x46 } }), name 71 | end, 72 | }, 73 | } 74 | GUID = ffi.metatype("GUID", GUID_mt) 75 | 76 | --require "CGuid" 77 | 78 | GUID_NULL = GUID() 79 | IID_NULL = GUID_NULL 80 | CLSID_NULL = GUID_NULL 81 | FMTID_NULL = GUID_NULL 82 | 83 | 84 | function DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) 85 | local aguid = GUID():Define(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) 86 | _G[name] = aguid; 87 | return aguid; 88 | end 89 | 90 | DEFINE_UUID = DEFINE_GUID 91 | 92 | function DEFINE_OLEGUID(name, l, w1, w2) 93 | return GUID():DefineOle(name, l, w1, w2) 94 | end 95 | 96 | --[[ 97 | Useful routines 98 | --]] 99 | 100 | function IsEqualIID(riid1, riid2) 101 | return riid1 == riid2 102 | end 103 | 104 | function IsEqualCLSID(rclsid1, rclsid2) 105 | return rclsid1 == rclsid2 106 | end 107 | 108 | function IsEqualFMTID(rfmtid1, rfmtid2) 109 | return rfmtid1 == rfmtid2 110 | end 111 | 112 | 113 | 114 | 115 | -- From Rpcrt4.h 116 | 117 | Rpcrt4 = ffi.load("Rpcrt4") 118 | 119 | ffi.cdef[[ 120 | int UuidCreate(UUID * Uuid); 121 | int UuidFromStringA(const char * StringUuid, UUID * Uuid); 122 | int UuidToStringA(UUID * Uuid , char ** StringUuid); 123 | ]] 124 | 125 | 126 | -- Helpful function for constructing a UUID/GUID 127 | -- from a string 128 | function UUIDFromString(stringid) 129 | local id = ffi.new("UUID") 130 | Rpcrt4.UuidFromStringA(stringid, id) 131 | 132 | return id 133 | end 134 | 135 | function GetNewGUID() 136 | local lpGUID = ffi.new("GUID[1]") 137 | local status = Rpcrt4.UuidCreate(lpGUID) 138 | if status ~= 0 then -- RPC_S_OK 139 | return nil 140 | end 141 | 142 | return lpGUID[0] 143 | end 144 | -------------------------------------------------------------------------------- /schedlua/windows/iocompletionset.lua: -------------------------------------------------------------------------------- 1 | 2 | local ffi = require("ffi"); 3 | local core_io = require("schedlua.windows.core_io_l1_1_1"); 4 | local errorhandling = require("schedlua.windows.core_errorhandling_l1_1_1"); 5 | local WTypes = require("schedlua.windows.WTypes") 6 | --local WinBase = require("WinBase"); 7 | 8 | INVALID_HANDLE_VALUE = ffi.cast("HANDLE",ffi.cast("LONG_PTR",-1)); 9 | 10 | 11 | ffi.cdef[[ 12 | typedef struct { 13 | HANDLE Handle; 14 | } IOCompletionHandle; 15 | ]] 16 | local IOCompletionHandle = ffi.typeof("IOCompletionHandle") 17 | local IOCompletionHandle_mt = { 18 | __index = {}, 19 | } 20 | ffi.metatype(IOCompletionHandle, IOCompletionHandle_mt) 21 | 22 | 23 | local iocompletionset = {} 24 | setmetatable(iocompletionset, { 25 | __call = function(self, ...) 26 | return self:create(...); 27 | end, 28 | }); 29 | 30 | local iocompletionset_mt = { 31 | __index = iocompletionset, 32 | } 33 | 34 | function iocompletionset.init(self, rawhandle) 35 | 36 | local obj = { 37 | Handle = IOCompletionHandle(rawhandle); 38 | }; 39 | setmetatable(obj, iocompletionset_mt); 40 | 41 | return obj; 42 | end 43 | 44 | function iocompletionset.create(self, ExistingCompletionPort, FileHandle, NumberOfConcurrentThreads) 45 | FileHandle = FileHandle or INVALID_HANDLE_VALUE; 46 | NumberOfConcurrentThreads = NumberOfConcurrentThreads or 0 47 | local CompletionKey = 0; 48 | 49 | local rawhandle = core_io.Createiocompletionset(FileHandle, 50 | ExistingCompletionPort, 51 | CompletionKey, 52 | NumberOfConcurrentThreads); 53 | 54 | if rawhandle == nil then 55 | return false, errorhandling.GetLastError(); 56 | end 57 | 58 | return self:init(rawhandle); 59 | end 60 | 61 | function iocompletionset.getNativeHandle(self) 62 | return self.Handle.Handle; 63 | end 64 | 65 | function iocompletionset.HasOverlappedIoCompleted(self, lpOverlapped) 66 | return ffi.cast("DWORD",lpOverlapped.Internal) ~= ffi.C.STATUS_PENDING; 67 | end 68 | 69 | --[[ 70 | Add another handle to the completion set so that we can 71 | watch for IO completion on that handle 72 | --]] 73 | function iocompletionset.add(self, otherhandle, Key) 74 | Key = Key or ffi.cast("ULONG_PTR", 0); 75 | Key = ffi.cast("ULONG_PTR", ffi.cast("void *",Key)); 76 | 77 | local rawhandle = core_io.CreateIOCompletionPort(otherhandle, self:getNativeHandle(), Key, 0); 78 | 79 | if rawhandle == nil then 80 | return false, errorhandling.GetLastError(); 81 | end 82 | 83 | return iocompletionset(rawhandle); 84 | end 85 | 86 | function iocompletionset.enqueue(self, dwCompletionKey, dwNumberOfBytesTransferred, lpOverlapped) 87 | if not dwCompletionKey then 88 | print("iocompletionset.enqueue(), NO KEY SPECIFIED") 89 | return false, "no data specified" 90 | end 91 | 92 | dwNumberOfBytesTransferred = dwNumberOfBytesTransferred or 0; 93 | 94 | local status = core_io.PostQueuedCompletionStatus(self:getNativeHandle(), 95 | dwNumberOfBytesTransferred, 96 | ffi.cast("ULONG_PTR",ffi.cast("void *", dwCompletionKey)), 97 | lpOverlapped); 98 | 99 | if status == 0 then 100 | return false, errorhandling.GetLastError(); 101 | end 102 | 103 | return self; 104 | end 105 | 106 | function iocompletionset.wait(self, timeout) 107 | timeout = timeout or ffi.C.INFINITE; 108 | 109 | 110 | local lpNumberOfBytesTransferred = ffi.new("DWORD[1]"); 111 | local lpCompletionKey = ffi.new("ULONG_PTR[1]"); -- PULONG_PTR 112 | local lpOverlapped = ffi.new("LPOVERLAPPED[1]"); 113 | 114 | local status = core_io.GetQueuedCompletionStatusEx(self:getNativeHandle(), 115 | LPOVERLAPPED_ENTRY lpCompletionPortEntries, 116 | ULONG ulCount, 117 | PULONG ulNumEntriesRemoved, 118 | timeout, 119 | BOOL fAlertable 120 | ); 121 | local status = core_io.GetQueuedCompletionStatus(self:getNativeHandle(), 122 | lpNumberOfBytesTransferred, 123 | lpCompletionKey, 124 | lpOverlapped, 125 | timeout); 126 | 127 | if status == 0 then 128 | local err = errorhandling.GetLastError(); 129 | 130 | -- If the dequeue failed, there can be two cases 131 | -- In the first case, the lpOverlapped is nil, 132 | -- in this case, nothing was dequeued, 133 | -- so just return whatever the reported error was. 134 | if lpOverlapped[0] == nil then 135 | return false, err; 136 | end 137 | 138 | -- if lpOverlapped[0] ~= nil, then 139 | -- data was transferred, but there is an error 140 | -- indicated in the underlying connection 141 | return false, err, lpCompletionKey[0], lpNumberOfBytesTransferred[0], lpOverlapped[0]; 142 | end 143 | 144 | -- For the remaining cases, where success is indicated 145 | return true, { 146 | completionKey = lpCompletionKey[0], 147 | bytesTransferred = lpNumberOfBytesTransferred[0], 148 | overlapped = lpOverlapped[0] 149 | } 150 | --return lpCompletionKey[0], lpNumberOfBytesTransferred[0], lpOverlapped[0]; 151 | end 152 | 153 | 154 | return iocompletionset; 155 | -------------------------------------------------------------------------------- /schedlua/windows/ioops.lua: -------------------------------------------------------------------------------- 1 | -- IOOps.lua 2 | 3 | local ffi = require("ffi"); 4 | 5 | ffi.cdef[[ 6 | typedef struct { 7 | OVERLAPPED OVL; 8 | 9 | // Data Buffer 10 | uint8_t * Buffer; 11 | int BufferLength; 12 | 13 | int operation; 14 | int bytestransferred; 15 | int opcounter; 16 | 17 | } IOOverlapped; 18 | ]] 19 | 20 | 21 | ffi.cdef[[ 22 | typedef struct { 23 | IOOverlapped OVL; 24 | 25 | // Our specifics 26 | HANDLE file; 27 | } FileOverlapped; 28 | ]] 29 | 30 | 31 | return { 32 | ERROR = -1; 33 | CONNECT = 1; 34 | ACCEPT = 2; 35 | READ = 3; 36 | WRITE = 4; 37 | }; 38 | -------------------------------------------------------------------------------- /schedlua/windows/iotracker.lua: -------------------------------------------------------------------------------- 1 | -- asyncio.lua 2 | 3 | local ffi = require("ffi") 4 | local bit = require("bit") 5 | local band, bor, lshift, rshift = bit.band, bit.bor, bit.lshift, bit.rshift 6 | 7 | local coreio = require("schedlua.windows.core_io_l1_1_1") 8 | 9 | 10 | 11 | local EventQuanta = 10; 12 | local ContinueRunning = true; 13 | local EPollSet = epoll.epollset(); 14 | local MaxEvents = 100; -- number of events we'll ask per quanta 15 | 16 | local READ = 1; 17 | local WRITE = 2; 18 | local CONNECT = 3; 19 | 20 | 21 | local Events = ffi.new("struct epoll_event[?]", self.MaxEvents); 22 | 23 | 24 | local function sigNameFromEvent(event, title) 25 | title = title or ""; 26 | local fdesc = ffi.cast("filedesc *", event.data.ptr); 27 | --print("sigNameFromEvent, fdesc: ", fdesc) 28 | local fd = fdesc.fd; 29 | --print(" fd: ", fd); 30 | 31 | local str = "waitforio-"..fd; 32 | 33 | return str; 34 | end 35 | 36 | 37 | local function setEventQuanta(quanta) 38 | self.EventQuanta = quanta; 39 | end 40 | 41 | local function getNextOperationId() 42 | OperationId = OperationId + 1; 43 | return OperationId; 44 | end 45 | 46 | local function watchForIOEvents(fdesc, event) 47 | return self.EPollSet:add(fdesc.fd, event); 48 | end 49 | 50 | local function waitForIOEvent(fdesc, event, title) 51 | local success, err = EPollSet:modify(fdesc.fd, event); 52 | local sigName = sigNameFromEvent(event, title); 53 | 54 | --print("\nAsyncIO.waitForIOEvent(), waiting for: ", sigName) 55 | 56 | success, err = waitForSignal(sigName); 57 | 58 | return success, err; 59 | end 60 | 61 | 62 | -- The watchdog() routine is the regular task that will 63 | -- always be calling epoll_wait when it gets a chance 64 | -- and signaling the appropriate tasks when they have events 65 | local function watchdog() 66 | while ContinueRunning do 67 | local available, err = EPollSet:wait(Events, MaxEvents, EventQuanta); 68 | --print("+=+=+= AsyncIO.watchdog: ", available, err) 69 | 70 | 71 | if available then 72 | if available > 0 then 73 | --print("+=+=+= AsyncIO.watchdog: ", available) 74 | for idx=0,available-1 do 75 | local ptr = ffi.cast("struct epoll_event *", ffi.cast("char *", self.Events)+ffi.sizeof("struct epoll_event")*idx); 76 | --print("watchdog, ptr.data.ptr: ", ptr, ptr.data.ptr); 77 | local sigName = sigNameFromEvent(ptr); 78 | --print(string.format("AsyncIO.watchdog(), signaling: '%s' Events: 0x%x", sigName, self.Events[idx].events)) 79 | signalAll(sigName, Events[idx].events); 80 | end 81 | else 82 | --print("NO EVENTS AVAILABLE") 83 | end 84 | else 85 | print("AsyncIO.watchdog, error from EPollSet:wait(): ", available, err) 86 | end 87 | 88 | yield(); 89 | end 90 | end 91 | 92 | 93 | local function globalize(tbl) 94 | tbl = tbl or _G 95 | 96 | tbl["waitForIOEvent"] = waitForIOEvent; 97 | tbl["watchForIOEvents"] = watchForIOEvents; 98 | 99 | return tbl; 100 | end 101 | 102 | globalize() 103 | 104 | AsyncIO = spawn(watchdog) 105 | 106 | return AsyncIO 107 | -------------------------------------------------------------------------------- /schedlua/windows/ntstatus.lua: -------------------------------------------------------------------------------- 1 | -- ntstatus.lua 2 | 3 | local ffi = require("ffi") 4 | 5 | ffi.cdef[[ 6 | typedef uint32_t NTSTATUS; 7 | typedef NTSTATUS *PNTSTATUS; 8 | ]] 9 | 10 | ffi.cdef[[ 11 | static const int STATUS_PENDING = (0x00000103); // winnt 12 | static const int STATUS_ACCESS_DENIED = ((NTSTATUS)0xC0000022); 13 | 14 | 15 | 16 | static const int DBG_CONTINUE = ((NTSTATUS)0x00010002); // winnt 17 | static const int DBG_EXCEPTION_NOT_HANDLED = ((NTSTATUS)0x80010001); // winnt 18 | 19 | ]] 20 | -------------------------------------------------------------------------------- /schedlua/windows/timeticker.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | 3 | require("schedlua.windows.wtypes") 4 | 5 | 6 | 7 | ffi.cdef[[ 8 | BOOL QueryPerformanceFrequency(int64_t *lpFrequency); 9 | BOOL QueryPerformanceCounter(int64_t *lpPerformanceCount); 10 | ]] 11 | 12 | local function GetPerformanceFrequency(anum) 13 | anum = anum or ffi.new("int64_t[1]"); 14 | local success = ffi.C.QueryPerformanceFrequency(anum) 15 | if success == 0 then 16 | return false, errorhandling.GetLastError(); 17 | end 18 | 19 | return tonumber(anum[0]) 20 | end 21 | 22 | local function GetPerformanceCounter(anum) 23 | anum = anum or ffi.new("int64_t[1]") 24 | local success = ffi.C.QueryPerformanceCounter(anum) 25 | if success == 0 then 26 | return false, errorhandling.GetLastError(); 27 | end 28 | 29 | return tonumber(anum[0]) 30 | end 31 | 32 | local function GetCurrentTickTime() 33 | local frequency = 1/GetPerformanceFrequency(); 34 | local currentCount = GetPerformanceCounter(); 35 | local seconds = currentCount * frequency; 36 | 37 | return seconds; 38 | end 39 | 40 | local k32Lib = ffi.load("kernel32"); 41 | 42 | return { 43 | Lib = k32Lib, 44 | 45 | getPerformanceCounter = GetPerformanceCounter, 46 | getPerformanceFrequency = GetPerformanceFrequency, 47 | getCurrentTickTime = GetCurrentTickTime, 48 | seconds = GetCurrentTickTime, 49 | 50 | QueryPerformanceCounter = k32Lib.QueryPerformanceCounter; 51 | QueryPerformanceFrequency = k32Lib.QueryPerformanceFrequency; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /schedlua/windows/winbase.lua: -------------------------------------------------------------------------------- 1 | -- WinBase.lua 2 | -- From WinBase.h 3 | local ffi = require "ffi" 4 | 5 | require ("schedlua.windows.wtypes"); 6 | require ("schedlua.windows.ntstatus"); 7 | 8 | 9 | 10 | 11 | INVALID_HANDLE_VALUE = ffi.cast("HANDLE",ffi.cast("LONG_PTR",-1)); 12 | INVALID_FILE_SIZE = (0xFFFFFFFF); 13 | INVALID_SET_FILE_POINTER = (-1); 14 | INVALID_FILE_ATTRIBUTES = (-1); 15 | 16 | WAIT_OBJECT_0 = 0; 17 | WAIT_ABANDONED = 0x00000080; 18 | WAIT_TIMEOUT = 0x102; 19 | WAIT_FAILED = 0xFFFFFFFF; 20 | 21 | FILE_SHARE_READ = 0X01; 22 | FILE_SHARE_WRITE = 0X02; 23 | FILE_FLAG_OVERLAPPED = 0X40000000; 24 | 25 | FILE_READ_DATA = 0x0001 -- file & pipe 26 | FILE_WRITE_DATA = 0x0002 -- file & pipe 27 | FILE_APPEND_DATA = 0x0004 -- file 28 | FILE_READ_EA = 0x0008 -- file & directory 29 | FILE_WRITE_EA = 0x0010 -- file & directory 30 | FILE_EXECUTE = 0x0020 -- file 31 | FILE_READ_ATTRIBUTES = 0x0080 -- all 32 | FILE_WRITE_ATTRIBUTES = 0x0100 -- all 33 | 34 | --[[ 35 | --FILE_ALL_ACCESS =STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF, 36 | 37 | 38 | FILE_GENERIC_READ = 39 | STANDARD_RIGHTS_READ | 40 | FILE_READ_DATA | 41 | FILE_READ_ATTRIBUTES | 42 | FILE_READ_EA | 43 | SYNCHRONIZE, 44 | 45 | 46 | FILE_GENERIC_WRITE = 47 | STANDARD_RIGHTS_WRITE | 48 | FILE_WRITE_DATA | 49 | FILE_WRITE_ATTRIBUTES | 50 | FILE_WRITE_EA | 51 | FILE_APPEND_DATA | 52 | SYNCHRONIZE, 53 | 54 | FILE_GENERIC_EXECUTE = 55 | STANDARD_RIGHTS_EXECUTE | 56 | FILE_READ_ATTRIBUTES | 57 | FILE_EXECUTE | 58 | SYNCHRONIZE, 59 | --]] 60 | 61 | 62 | CREATE_NEW = 1; 63 | CREATE_ALWAYS = 2; 64 | OPEN_EXISTING = 3; 65 | OPEN_ALWAYS = 4; 66 | TRUNCATE_EXISTING = 5; 67 | 68 | 69 | 70 | 71 | 72 | PURGE_TXABORT = 0x01; 73 | PURGE_RXABORT = 0x02; 74 | PURGE_TXCLEAR = 0x04; 75 | PURGE_RXCLEAR = 0x08; 76 | 77 | 78 | 79 | 80 | ERROR_IO_PENDING = 0x03E5; -- 997 81 | 82 | ffi.cdef[[ 83 | static const int INFINITE = 0xFFFFFFFF; 84 | ]] 85 | 86 | 87 | -- Access Rights 88 | DELETE = 0x00010000 89 | READ_CONTROL = 0x00020000 90 | WRITE_DAC = 0x00040000 91 | WRITE_OWNER = 0x00080000 92 | SYNCHRONIZE = 0x00100000 93 | 94 | 95 | --THREAD_ALL_ACCESS 96 | THREAD_DIRECT_IMPERSONATION = 0x0200 97 | THREAD_GET_CONTEXT = 0x0008 98 | THREAD_IMPERSONATE = 0x0100 99 | THREAD_QUERY_INFORMATION = 0x0040 100 | THREAD_QUERY_LIMITED_INFORMATION = 0x0800 101 | THREAD_SET_CONTEXT = 0x0010 102 | THREAD_SET_INFORMATION = 0x0020 103 | THREAD_SET_LIMITED_INFORMATION = 0x0400 104 | THREAD_SET_THREAD_TOKEN = 0x0080 105 | THREAD_SUSPEND_RESUME = 0x0002 106 | THREAD_TERMINATE = 0x0001 107 | 108 | -- Process dwCreationFlag values 109 | 110 | DEBUG_PROCESS = 0x00000001 111 | DEBUG_ONLY_THIS_PROCESS = 0x00000002 112 | CREATE_SUSPENDED = 0x00000004 113 | DETACHED_PROCESS = 0x00000008 114 | 115 | CREATE_NEW_CONSOLE = 0x00000010 116 | NORMAL_PRIORITY_CLASS = 0x00000020 117 | IDLE_PRIORITY_CLASS = 0x00000040 118 | HIGH_PRIORITY_CLASS = 0x00000080 119 | 120 | REALTIME_PRIORITY_CLASS = 0x00000100 121 | CREATE_NEW_PROCESS_GROUP = 0x00000200 122 | CREATE_UNICODE_ENVIRONMENT = 0x00000400 123 | CREATE_SEPARATE_WOW_VDM = 0x00000800 124 | 125 | CREATE_SHARED_WOW_VDM = 0x00001000 126 | CREATE_FORCEDOS = 0x00002000 127 | BELOW_NORMAL_PRIORITY_CLASS = 0x00004000 128 | ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000 129 | 130 | INHERIT_PARENT_AFFINITY = 0x00010000 131 | CREATE_PROTECTED_PROCESS = 0x00040000 132 | EXTENDED_STARTUPINFO_PRESENT = 0x00080000 133 | 134 | PROCESS_MODE_BACKGROUND_BEGIN = 0x00100000 135 | PROCESS_MODE_BACKGROUND_END = 0x00200000 136 | 137 | CREATE_BREAKAWAY_FROM_JOB = 0x01000000 138 | CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000 139 | CREATE_DEFAULT_ERROR_MODE = 0x04000000 140 | CREATE_NO_WINDOW = 0x08000000 141 | 142 | PROFILE_USER = 0x10000000 143 | PROFILE_KERNEL = 0x20000000 144 | PROFILE_SERVER = 0x40000000 145 | CREATE_IGNORE_SYSTEM_DEFAULT = 0x80000000 146 | 147 | 148 | STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000 -- Threads only 149 | 150 | ffi.cdef[[ 151 | static const int STILL_ACTIVE = STATUS_PENDING; 152 | ]] 153 | 154 | --[[ 155 | #define WAIT_IO_COMPLETION STATUS_USER_APC 156 | #define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION 157 | #define EXCEPTION_DATATYPE_MISALIGNMENT STATUS_DATATYPE_MISALIGNMENT 158 | #define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT 159 | #define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP 160 | #define EXCEPTION_ARRAY_BOUNDS_EXCEEDED STATUS_ARRAY_BOUNDS_EXCEEDED 161 | #define EXCEPTION_FLT_DENORMAL_OPERAND STATUS_FLOAT_DENORMAL_OPERAND 162 | #define EXCEPTION_FLT_DIVIDE_BY_ZERO STATUS_FLOAT_DIVIDE_BY_ZERO 163 | #define EXCEPTION_FLT_INEXACT_RESULT STATUS_FLOAT_INEXACT_RESULT 164 | #define EXCEPTION_FLT_INVALID_OPERATION STATUS_FLOAT_INVALID_OPERATION 165 | #define EXCEPTION_FLT_OVERFLOW STATUS_FLOAT_OVERFLOW 166 | #define EXCEPTION_FLT_STACK_CHECK STATUS_FLOAT_STACK_CHECK 167 | #define EXCEPTION_FLT_UNDERFLOW STATUS_FLOAT_UNDERFLOW 168 | #define EXCEPTION_INT_DIVIDE_BY_ZERO STATUS_INTEGER_DIVIDE_BY_ZERO 169 | #define EXCEPTION_INT_OVERFLOW STATUS_INTEGER_OVERFLOW 170 | #define EXCEPTION_PRIV_INSTRUCTION STATUS_PRIVILEGED_INSTRUCTION 171 | #define EXCEPTION_IN_PAGE_ERROR STATUS_IN_PAGE_ERROR 172 | #define EXCEPTION_ILLEGAL_INSTRUCTION STATUS_ILLEGAL_INSTRUCTION 173 | #define EXCEPTION_NONCONTINUABLE_EXCEPTION STATUS_NONCONTINUABLE_EXCEPTION 174 | #define EXCEPTION_STACK_OVERFLOW STATUS_STACK_OVERFLOW 175 | #define EXCEPTION_INVALID_DISPOSITION STATUS_INVALID_DISPOSITION 176 | #define EXCEPTION_GUARD_PAGE STATUS_GUARD_PAGE_VIOLATION 177 | #define EXCEPTION_INVALID_HANDLE STATUS_INVALID_HANDLE 178 | #define EXCEPTION_POSSIBLE_DEADLOCK STATUS_POSSIBLE_DEADLOCK 179 | #define CONTROL_C_EXIT STATUS_CONTROL_C_EXIT 180 | --]] 181 | 182 | -- 183 | -- Priority flags 184 | -- 185 | --[[ 186 | THREAD_PRIORITY_LOWEST THREAD_BASE_PRIORITY_MIN 187 | THREAD_PRIORITY_BELOW_NORMAL (THREAD_PRIORITY_LOWEST+1) 188 | THREAD_PRIORITY_NORMAL 0 189 | THREAD_PRIORITY_HIGHEST THREAD_BASE_PRIORITY_MAX 190 | THREAD_PRIORITY_ABOVE_NORMAL (THREAD_PRIORITY_HIGHEST-1) 191 | THREAD_PRIORITY_ERROR_RETURN (MAXLONG) 192 | 193 | THREAD_PRIORITY_TIME_CRITICAL THREAD_BASE_PRIORITY_LOWRT 194 | THREAD_PRIORITY_IDLE THREAD_BASE_PRIORITY_IDLE 195 | 196 | THREAD_MODE_BACKGROUND_BEGIN 0x00010000 197 | THREAD_MODE_BACKGROUND_END 0x00020000 198 | --]] 199 | 200 | ffi.cdef[[ 201 | typedef DWORD (* PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter); 202 | typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; 203 | ]] 204 | 205 | ffi.cdef[[ 206 | typedef struct _OVERLAPPED { 207 | ULONG_PTR Internal; 208 | ULONG_PTR InternalHigh; 209 | union { 210 | struct { 211 | DWORD Offset; 212 | DWORD OffsetHigh; 213 | }; 214 | 215 | PVOID Pointer; 216 | }; 217 | 218 | HANDLE hEvent; 219 | } OVERLAPPED, *LPOVERLAPPED; 220 | 221 | typedef struct _OVERLAPPED_ENTRY { 222 | ULONG_PTR lpCompletionKey; 223 | LPOVERLAPPED lpOverlapped; 224 | ULONG_PTR Internal; 225 | DWORD dwNumberOfBytesTransferred; 226 | } OVERLAPPED_ENTRY, *LPOVERLAPPED_ENTRY; 227 | 228 | 229 | typedef struct _PROCESS_INFORMATION { 230 | HANDLE hProcess; 231 | HANDLE hThread; 232 | DWORD dwProcessId; 233 | DWORD dwThreadId; 234 | } PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION; 235 | 236 | typedef struct _BY_HANDLE_FILE_INFORMATION { 237 | DWORD dwFileAttributes; 238 | FILETIME ftCreationTime; 239 | FILETIME ftLastAccessTime; 240 | FILETIME ftLastWriteTime; 241 | DWORD dwVolumeSerialNumber; 242 | DWORD nFileSizeHigh; 243 | DWORD nFileSizeLow; 244 | DWORD nNumberOfLinks; 245 | DWORD nFileIndexHigh; 246 | DWORD nFileIndexLow; 247 | } BY_HANDLE_FILE_INFORMATION, *PBY_HANDLE_FILE_INFORMATION, *LPBY_HANDLE_FILE_INFORMATION; 248 | ]] 249 | 250 | 251 | ffi.cdef[[ 252 | // 253 | // Dual Mode API below this line. Dual Mode Structures also included. 254 | // 255 | 256 | static const int STARTF_USESHOWWINDOW =0x00000001; 257 | static const int STARTF_USESIZE =0x00000002; 258 | static const int STARTF_USEPOSITION =0x00000004; 259 | static const int STARTF_USECOUNTCHARS =0x00000008; 260 | static const int STARTF_USEFILLATTRIBUTE =0x00000010; 261 | static const int STARTF_RUNFULLSCREEN =0x00000020; // ignored for non-x86 platforms 262 | static const int STARTF_FORCEONFEEDBACK =0x00000040; 263 | static const int STARTF_FORCEOFFFEEDBACK =0x00000080; 264 | static const int STARTF_USESTDHANDLES =0x00000100; 265 | 266 | 267 | static const int STARTF_USEHOTKEY =0x00000200; 268 | static const int STARTF_TITLEISLINKNAME =0x00000800; 269 | static const int STARTF_TITLEISAPPID =0x00001000; 270 | static const int STARTF_PREVENTPINNING =0x00002000; 271 | 272 | typedef struct _STARTUPINFOA { 273 | DWORD cb; 274 | LPSTR lpReserved; 275 | LPSTR lpDesktop; 276 | LPSTR lpTitle; 277 | DWORD dwX; 278 | DWORD dwY; 279 | DWORD dwXSize; 280 | DWORD dwYSize; 281 | DWORD dwXCountChars; 282 | DWORD dwYCountChars; 283 | DWORD dwFillAttribute; 284 | DWORD dwFlags; 285 | WORD wShowWindow; 286 | WORD cbReserved2; 287 | LPBYTE lpReserved2; 288 | HANDLE hStdInput; 289 | HANDLE hStdOutput; 290 | HANDLE hStdError; 291 | } STARTUPINFOA, *LPSTARTUPINFOA; 292 | 293 | typedef struct _STARTUPINFOW { 294 | DWORD cb; 295 | LPWSTR lpReserved; 296 | LPWSTR lpDesktop; 297 | LPWSTR lpTitle; 298 | DWORD dwX; 299 | DWORD dwY; 300 | DWORD dwXSize; 301 | DWORD dwYSize; 302 | DWORD dwXCountChars; 303 | DWORD dwYCountChars; 304 | DWORD dwFillAttribute; 305 | DWORD dwFlags; 306 | WORD wShowWindow; 307 | WORD cbReserved2; 308 | LPBYTE lpReserved2; 309 | HANDLE hStdInput; 310 | HANDLE hStdOutput; 311 | HANDLE hStdError; 312 | } STARTUPINFOW, *LPSTARTUPINFOW; 313 | ]] 314 | 315 | if UNICODE then 316 | ffi.cdef[[ 317 | typedef STARTUPINFOW STARTUPINFO; 318 | typedef LPSTARTUPINFOW LPSTARTUPINFO; 319 | ]] 320 | else 321 | ffi.cdef[[ 322 | typedef STARTUPINFOA STARTUPINFO; 323 | typedef LPSTARTUPINFOA LPSTARTUPINFO; 324 | ]] 325 | end -- UNICODE 326 | 327 | ffi.cdef[[ 328 | typedef struct _PROC_THREAD_ATTRIBUTE_LIST *PPROC_THREAD_ATTRIBUTE_LIST, *LPPROC_THREAD_ATTRIBUTE_LIST; 329 | 330 | typedef struct _STARTUPINFOEXA { 331 | STARTUPINFOA StartupInfo; 332 | LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList; 333 | } STARTUPINFOEXA, *LPSTARTUPINFOEXA; 334 | typedef struct _STARTUPINFOEXW { 335 | STARTUPINFOW StartupInfo; 336 | LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList; 337 | } STARTUPINFOEXW, *LPSTARTUPINFOEXW; 338 | ]] 339 | 340 | if UNICODE then 341 | ffi.cdef[[ 342 | typedef STARTUPINFOEXW STARTUPINFOEX; 343 | typedef LPSTARTUPINFOEXW LPSTARTUPINFOEX; 344 | ]] 345 | else 346 | ffi.cdef[[ 347 | typedef STARTUPINFOEXA STARTUPINFOEX; 348 | typedef LPSTARTUPINFOEXA LPSTARTUPINFOEX; 349 | ]] 350 | end -- UNICODE 351 | 352 | ffi.cdef[[ 353 | // 354 | // Logon Support APIs 355 | // 356 | 357 | static const int LOGON32_LOGON_INTERACTIVE = 2; 358 | static const int LOGON32_LOGON_NETWORK = 3; 359 | static const int LOGON32_LOGON_BATCH = 4; 360 | static const int LOGON32_LOGON_SERVICE = 5; 361 | static const int LOGON32_LOGON_UNLOCK = 7; 362 | static const int LOGON32_LOGON_NETWORK_CLEARTEXT =8; 363 | static const int LOGON32_LOGON_NEW_CREDENTIALS =9; 364 | 365 | static const int LOGON32_PROVIDER_DEFAULT =0; 366 | static const int LOGON32_PROVIDER_WINNT35 =1; 367 | static const int LOGON32_PROVIDER_WINNT40 =2; 368 | static const int LOGON32_PROVIDER_WINNT50 =3; 369 | static const int LOGON32_PROVIDER_VIRTUAL =4; 370 | ]] 371 | 372 | ffi.cdef[[ 373 | // 374 | // LogonFlags 375 | // 376 | static const int LOGON_WITH_PROFILE = 0x00000001; 377 | static const int LOGON_NETCREDENTIALS_ONLY = 0x00000002; 378 | static const int LOGON_ZERO_PASSWORD_BUFFER = 0x80000000; 379 | 380 | BOOL 381 | CreateProcessWithLogonW( 382 | LPCWSTR lpUsername, 383 | LPCWSTR lpDomain, 384 | LPCWSTR lpPassword, 385 | DWORD dwLogonFlags, 386 | LPCWSTR lpApplicationName, 387 | LPWSTR lpCommandLine, 388 | DWORD dwCreationFlags, 389 | LPVOID lpEnvironment, 390 | LPCWSTR lpCurrentDirectory, 391 | LPSTARTUPINFOW lpStartupInfo, 392 | LPPROCESS_INFORMATION lpProcessInformation 393 | ); 394 | 395 | 396 | BOOL 397 | CreateProcessWithTokenW( 398 | HANDLE hToken, 399 | DWORD dwLogonFlags, 400 | LPCWSTR lpApplicationName, 401 | LPWSTR lpCommandLine, 402 | DWORD dwCreationFlags, 403 | LPVOID lpEnvironment, 404 | LPCWSTR lpCurrentDirectory, 405 | LPSTARTUPINFOW lpStartupInfo, 406 | LPPROCESS_INFORMATION lpProcessInformation 407 | ); 408 | ]] 409 | 410 | -- File System Specific 411 | ffi.cdef[[ 412 | typedef enum _GET_FILEEX_INFO_LEVELS { 413 | GetFileExInfoStandard, 414 | GetFileExMaxInfoLevel 415 | } GET_FILEEX_INFO_LEVELS; 416 | 417 | typedef enum _FILE_INFO_BY_HANDLE_CLASS { 418 | FileBasicInfo, 419 | FileStandardInfo, 420 | FileNameInfo, 421 | FileRenameInfo, 422 | FileDispositionInfo, 423 | FileAllocationInfo, 424 | FileEndOfFileInfo, 425 | FileStreamInfo, 426 | FileCompressionInfo, 427 | FileAttributeTagInfo, 428 | FileIdBothDirectoryInfo, 429 | FileIdBothDirectoryRestartInfo, 430 | FileIoPriorityHintInfo, 431 | FileRemoteProtocolInfo, 432 | MaximumFileInfoByHandleClass 433 | } FILE_INFO_BY_HANDLE_CLASS, *PFILE_INFO_BY_HANDLE_CLASS; 434 | 435 | typedef WCHAR *PWCHAR, *LPWCH, *PWCH; 436 | typedef const WCHAR *LPCWCH, *PCWCH; 437 | 438 | typedef 439 | void (* LPOVERLAPPED_COMPLETION_ROUTINE)( 440 | DWORD dwErrorCode, 441 | DWORD dwNumberOfBytesTransfered, 442 | LPOVERLAPPED lpOverlapped 443 | ); 444 | ]] 445 | 446 | ffi.cdef[[ 447 | typedef struct _REASON_CONTEXT { 448 | ULONG Version; 449 | DWORD Flags; 450 | union { 451 | struct { 452 | HMODULE LocalizedReasonModule; 453 | ULONG LocalizedReasonId; 454 | ULONG ReasonStringCount; 455 | LPWSTR *ReasonStrings; 456 | 457 | } Detailed; 458 | 459 | LPWSTR SimpleReasonString; 460 | } Reason; 461 | } REASON_CONTEXT, *PREASON_CONTEXT; 462 | ]] 463 | 464 | ffi.cdef[[ 465 | /* Local Memory Flags */ 466 | static const int LMEM_FIXED = 0x0000; 467 | static const int LMEM_MOVEABLE = 0x0002; 468 | static const int LMEM_NOCOMPACT = 0x0010; 469 | static const int LMEM_NODISCARD = 0x0020; 470 | static const int LMEM_ZEROINIT = 0x0040; 471 | static const int LMEM_MODIFY = 0x0080; 472 | static const int LMEM_DISCARDABLE = 0x0F00; 473 | static const int LMEM_VALID_FLAGS = 0x0F72; 474 | static const int LMEM_INVALID_HANDLE= 0x8000; 475 | 476 | static const int LHND =(LMEM_MOVEABLE | LMEM_ZEROINIT); 477 | static const int LPTR =(LMEM_FIXED | LMEM_ZEROINIT); 478 | 479 | static const int NONZEROLHND =(LMEM_MOVEABLE); 480 | static const int NONZEROLPTR =(LMEM_FIXED); 481 | 482 | HLOCAL 483 | LocalAlloc( 484 | UINT uFlags, 485 | SIZE_T uBytes); 486 | 487 | HLOCAL 488 | LocalReAlloc( 489 | HLOCAL hMem, 490 | SIZE_T uBytes, 491 | UINT uFlags); 492 | 493 | LPVOID 494 | LocalLock( 495 | HLOCAL hMem); 496 | 497 | UINT 498 | LocalFlags(HLOCAL hMem); 499 | 500 | HLOCAL 501 | LocalFree(HLOCAL hMem); 502 | 503 | HLOCAL 504 | LocalHandle(LPCVOID pMem); 505 | 506 | BOOL 507 | LocalUnlock(HLOCAL hMem); 508 | 509 | SIZE_T 510 | LocalShrink( 511 | HLOCAL hMem, 512 | UINT cbNewSize); 513 | 514 | SIZE_T 515 | LocalCompact(UINT uMinFree); 516 | 517 | SIZE_T 518 | LocalSize(HLOCAL hMem); 519 | 520 | ]] 521 | 522 | local k32Lib = ffi.load("kernel32") 523 | local advapiLib = ffi.load("AdvApi32"); 524 | 525 | return { 526 | Lib = advapiLib, 527 | k32Lib = k32Lib, 528 | 529 | CreateProcessWithLogonW = advapiLib.CreateProcessWithLogonW, 530 | CreateProcessWithTokenW = advapiLib.CreateProcessWithTokenW, 531 | 532 | LocalAlloc = k32Lib.LocalAlloc, 533 | LocalFree = k32Lib.LocalFree, 534 | } -------------------------------------------------------------------------------- /schedlua/windows/wtypes.lua: -------------------------------------------------------------------------------- 1 | local ffi = require"ffi" 2 | local bit = require"bit" 3 | 4 | local bnot = bit.bnot 5 | local band = bit.band 6 | local bor = bit.bor 7 | local lshift = bit.lshift 8 | local rshift = bit.rshift 9 | 10 | local basetsd = require("schedlua.windows.basetsd"); 11 | local arch = require("schedlua.windows.arch"); 12 | 13 | ffi.cdef[[ 14 | typedef uint32_t * PDWORD; 15 | typedef long * PLONG; 16 | typedef long *LPLONG; 17 | 18 | ]] 19 | 20 | 21 | ffi.cdef[[ 22 | 23 | // Basic Data types 24 | typedef unsigned char *PBYTE; 25 | 26 | typedef BYTE BOOLEAN; 27 | 28 | typedef wchar_t WCHAR; 29 | 30 | 31 | typedef long BOOL; 32 | typedef long * PBOOL; 33 | 34 | 35 | typedef int * LPINT; 36 | typedef int * PINT; 37 | 38 | 39 | 40 | 41 | typedef float FLOAT; 42 | typedef double DOUBLE; 43 | 44 | typedef uint8_t BCHAR; 45 | typedef uint32_t UINT32; 46 | 47 | 48 | // Some pointer types 49 | typedef char * PCHAR; 50 | typedef const char * PCCHAR; 51 | typedef unsigned char * PUCHAR; 52 | typedef char * PSTR; 53 | 54 | 55 | typedef uint16_t * PWCHAR; 56 | 57 | typedef unsigned char * PBOOLEAN; 58 | typedef const unsigned char *PCUCHAR; 59 | typedef unsigned int * PUINT; 60 | typedef uint32_t * PUINT32; 61 | typedef unsigned long *PULONG; 62 | typedef unsigned short *PUSHORT; 63 | typedef LONGLONG *PLONGLONG; 64 | typedef ULONGLONG *PULONGLONG; 65 | 66 | 67 | typedef void VOID; 68 | typedef void * PVOID; 69 | ]] 70 | 71 | 72 | 73 | ffi.cdef[[ 74 | typedef DWORD * LPCOLORREF; 75 | 76 | typedef BOOL * LPBOOL; 77 | typedef BYTE * LPBYTE; 78 | typedef char * LPSTR; 79 | typedef short * LPWSTR; 80 | typedef short * PWSTR; 81 | typedef const WCHAR * LPCWSTR; 82 | typedef const WCHAR * PCWSTR; 83 | typedef PWSTR * PZPWSTR; 84 | typedef LPSTR LPTSTR; 85 | 86 | typedef DWORD * LPDWORD; 87 | typedef void * LPVOID; 88 | typedef WORD * LPWORD; 89 | 90 | typedef const char * LPCSTR; 91 | typedef const char * PCSTR; 92 | typedef LPCSTR LPCTSTR; 93 | typedef const void * LPCVOID; 94 | 95 | 96 | typedef LONG_PTR LRESULT; 97 | 98 | typedef LONG_PTR LPARAM; 99 | typedef UINT_PTR WPARAM; 100 | 101 | 102 | typedef unsigned char TBYTE; 103 | typedef char TCHAR; 104 | 105 | typedef USHORT COLOR16; 106 | typedef DWORD COLORREF; 107 | 108 | // Special types 109 | typedef WORD ATOM; 110 | typedef DWORD LCID; 111 | typedef USHORT LANGID; 112 | ]] 113 | 114 | ffi.cdef[[ 115 | typedef struct tagDEC { 116 | USHORT wReserved; 117 | union { 118 | struct { 119 | BYTE scale; 120 | BYTE sign; 121 | }; 122 | USHORT signscale; 123 | }; 124 | ULONG Hi32; 125 | union { 126 | struct { 127 | ULONG Lo32; 128 | ULONG Mid32; 129 | } ; 130 | ULONGLONG Lo64; 131 | } ; 132 | } DECIMAL; 133 | typedef DECIMAL *LPDECIMAL; 134 | ]] 135 | --[[ 136 | #define DECIMAL_NEG ((BYTE)0x80) 137 | #define DECIMAL_SETZERO(dec) \ 138 | {(dec).Lo64 = 0; (dec).Hi32 = 0; (dec).signscale = 0;} 139 | --]] 140 | 141 | ffi.cdef[[ 142 | // Ole Automation 143 | typedef WCHAR OLECHAR; 144 | typedef OLECHAR *LPOLESTR; 145 | typedef const OLECHAR *LPCOLESTR; 146 | 147 | //typedef char OLECHAR; 148 | //typedef LPSTR LPOLESTR; 149 | //typedef LPCSTR LPCOLESTR; 150 | 151 | typedef OLECHAR *BSTR; 152 | typedef BSTR *LPBSTR; 153 | 154 | typedef struct tagBSTRBLOB 155 | { 156 | ULONG cbSize; 157 | BYTE *pData; 158 | } BSTRBLOB; 159 | 160 | typedef struct tagBSTRBLOB *LPBSTRBLOB; 161 | 162 | ]] 163 | 164 | ffi.cdef[[ 165 | /* 0 == FALSE, -1 == TRUE */ 166 | typedef short VARIANT_BOOL; 167 | typedef VARIANT_BOOL _VARIANT_BOOL; 168 | 169 | ]] 170 | 171 | 172 | ffi.cdef[[ 173 | typedef DWORD ACCESS_MASK; 174 | typedef ACCESS_MASK* PACCESS_MASK; 175 | 176 | 177 | typedef LONG FXPT16DOT16, *LPFXPT16DOT16; 178 | typedef LONG FXPT2DOT30, *LPFXPT2DOT30; 179 | ]] 180 | 181 | ffi.cdef[[ 182 | typedef struct tagBLOB 183 | { 184 | ULONG cbSize; 185 | BYTE *pBlobData; 186 | } BLOB; 187 | 188 | typedef struct tagBLOB *LPBLOB; 189 | ]] 190 | 191 | local BLOB = ffi.typeof("BLOB") 192 | local BLOB_mt = { 193 | __tostring = function(self) 194 | return string.format("BLOB(%d, %s)", self.cbSize, arch.pointerToString(self.pBlobData)) 195 | end, 196 | } 197 | ffi.metatype(BLOB, BLOB_mt); 198 | 199 | 200 | ffi.cdef[[ 201 | typedef struct tagCLIPDATA 202 | { 203 | ULONG cbSize; 204 | long ulClipFmt; 205 | BYTE *pClipData; 206 | } CLIPDATA; 207 | 208 | typedef unsigned short VARTYPE; 209 | ]] 210 | 211 | if STRICT then 212 | ffi.cdef[[ 213 | typedef void *HANDLE; 214 | ]] 215 | 216 | function DECLARE_HANDLE(name) 217 | ffi.cdef(string.format("struct %s__{int unused;}; typedef struct %s__ *%s", name, name, name)); 218 | end 219 | else 220 | ffi.cdef[[ 221 | typedef PVOID HANDLE; 222 | ]] 223 | 224 | function DECLARE_HANDLE(name) 225 | ffi.cdef(string.format("typedef HANDLE %s",name)); 226 | end 227 | end 228 | 229 | ffi.cdef[[ 230 | typedef HANDLE *PHANDLE; 231 | ]] 232 | 233 | ffi.cdef[[ 234 | // Various Handles 235 | typedef HANDLE * LPHANDLE; 236 | typedef void * HBITMAP; 237 | typedef void * HBRUSH; 238 | typedef void * HICON; 239 | typedef HICON HCURSOR; 240 | typedef HANDLE HDC; 241 | typedef void * HDESK; 242 | typedef HANDLE HDROP; 243 | typedef HANDLE HDWP; 244 | typedef HANDLE HENHMETAFILE; 245 | typedef INT HFILE; 246 | typedef HANDLE HFONT; 247 | typedef void * HGDIOBJ; 248 | typedef HANDLE HGLOBAL; 249 | typedef HANDLE HGLRC; 250 | typedef HANDLE HHOOK; 251 | typedef void * HINSTANCE; 252 | typedef void * HKEY; 253 | typedef HKEY * PHKEY; 254 | typedef void * HKL; 255 | typedef HANDLE HLOCAL; 256 | typedef void * HMEMF; 257 | typedef HANDLE HMENU; 258 | typedef HANDLE HMETAFILE; 259 | typedef void HMF; 260 | typedef HINSTANCE HMODULE; 261 | typedef HANDLE HMONITOR; 262 | typedef HANDLE HPALETTE; 263 | typedef void * HPEN; 264 | typedef LONG HRESULT; 265 | typedef HANDLE HRGN; 266 | typedef void * HRSRC; 267 | typedef void * HSTR; 268 | typedef HANDLE HSZ; 269 | typedef void * HTASK; 270 | typedef void * HWINSTA; 271 | typedef HANDLE HWND; 272 | ]] 273 | 274 | require "schedlua.windows.guiddef" 275 | 276 | 277 | 278 | ffi.cdef[[ 279 | // Update Sequence Number 280 | 281 | typedef LONGLONG USN; 282 | 283 | 284 | typedef union _LARGE_INTEGER { 285 | struct { 286 | DWORD LowPart; 287 | LONG HighPart; 288 | }; 289 | struct { 290 | DWORD LowPart; 291 | LONG HighPart; 292 | } u; 293 | LONGLONG QuadPart; 294 | } LARGE_INTEGER, *PLARGE_INTEGER; 295 | 296 | typedef struct _ULARGE_INTEGER 297 | { 298 | ULONGLONG QuadPart; 299 | } ULARGE_INTEGER; 300 | 301 | typedef ULARGE_INTEGER *PULARGE_INTEGER; 302 | 303 | ]] 304 | 305 | 306 | ffi.cdef[[ 307 | typedef struct _FILETIME 308 | { 309 | DWORD dwLowDateTime; 310 | DWORD dwHighDateTime; 311 | } FILETIME; 312 | 313 | typedef struct _FILETIME *PFILETIME; 314 | 315 | typedef struct _FILETIME *LPFILETIME; 316 | ]] 317 | 318 | ffi.cdef[[ 319 | typedef struct _SYSTEMTIME 320 | { 321 | WORD wYear; 322 | WORD wMonth; 323 | WORD wDayOfWeek; 324 | WORD wDay; 325 | WORD wHour; 326 | WORD wMinute; 327 | WORD wSecond; 328 | WORD wMilliseconds; 329 | } SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME; 330 | 331 | 332 | typedef struct _SECURITY_ATTRIBUTES { 333 | DWORD nLength; 334 | LPVOID lpSecurityDescriptor; 335 | BOOL bInheritHandle; 336 | } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; 337 | 338 | 339 | typedef USHORT SECURITY_DESCRIPTOR_CONTROL; 340 | 341 | typedef USHORT *PSECURITY_DESCRIPTOR_CONTROL; 342 | 343 | typedef LONG SECURITY_STATUS; 344 | 345 | typedef PVOID PSID; 346 | 347 | typedef LONG SCODE; 348 | 349 | typedef SCODE *PSCODE; 350 | 351 | 352 | typedef 353 | enum tagMEMCTX 354 | { MEMCTX_TASK = 1, 355 | MEMCTX_SHARED = 2, 356 | MEMCTX_MACSYSTEM = 3, 357 | MEMCTX_UNKNOWN = -1, 358 | MEMCTX_SAME = -2 359 | } MEMCTX; 360 | 361 | 362 | 363 | 364 | typedef 365 | enum tagMSHLFLAGS 366 | { MSHLFLAGS_NORMAL = 0, 367 | MSHLFLAGS_TABLESTRONG = 1, 368 | MSHLFLAGS_TABLEWEAK = 2, 369 | MSHLFLAGS_NOPING = 4, 370 | MSHLFLAGS_RESERVED1 = 8, 371 | MSHLFLAGS_RESERVED2 = 16, 372 | MSHLFLAGS_RESERVED3 = 32, 373 | MSHLFLAGS_RESERVED4 = 64 374 | } MSHLFLAGS; 375 | 376 | typedef 377 | enum tagMSHCTX 378 | { MSHCTX_LOCAL = 0, 379 | MSHCTX_NOSHAREDMEM = 1, 380 | MSHCTX_DIFFERENTMACHINE = 2, 381 | MSHCTX_INPROC = 3, 382 | MSHCTX_CROSSCTX = 4 383 | } MSHCTX; 384 | 385 | typedef 386 | enum tagDVASPECT 387 | { DVASPECT_CONTENT = 1, 388 | DVASPECT_THUMBNAIL = 2, 389 | DVASPECT_ICON = 4, 390 | DVASPECT_DOCPRINT = 8 391 | } DVASPECT; 392 | 393 | typedef 394 | enum tagSTGC 395 | { STGC_DEFAULT = 0, 396 | STGC_OVERWRITE = 1, 397 | STGC_ONLYIFCURRENT = 2, 398 | STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 4, 399 | STGC_CONSOLIDATE = 8 400 | } STGC; 401 | 402 | typedef 403 | enum tagSTGMOVE 404 | { STGMOVE_MOVE = 0, 405 | STGMOVE_COPY = 1, 406 | STGMOVE_SHALLOWCOPY = 2 407 | } STGMOVE; 408 | 409 | typedef 410 | enum tagSTATFLAG 411 | { STATFLAG_DEFAULT = 0, 412 | STATFLAG_NONAME = 1, 413 | STATFLAG_NOOPEN = 2 414 | } STATFLAG; 415 | 416 | typedef void *HCONTEXT; 417 | 418 | typedef struct _BYTE_BLOB 419 | { 420 | unsigned long clSize; 421 | uint8_t abData[ 1 ]; 422 | } BYTE_BLOB; 423 | 424 | typedef struct _WORD_BLOB 425 | { 426 | unsigned long clSize; 427 | unsigned short asData[ 1 ]; 428 | } WORD_BLOB; 429 | 430 | typedef struct _DWORD_BLOB 431 | { 432 | unsigned long clSize; 433 | unsigned long alData[ 1 ]; 434 | } DWORD_BLOB; 435 | 436 | typedef struct _FLAGGED_BYTE_BLOB 437 | { 438 | unsigned long fFlags; 439 | unsigned long clSize; 440 | uint8_t abData[ 1 ]; 441 | } FLAGGED_BYTE_BLOB; 442 | 443 | typedef struct _FLAGGED_WORD_BLOB 444 | { 445 | unsigned long fFlags; 446 | unsigned long clSize; 447 | unsigned short asData[ 1 ]; 448 | } FLAGGED_WORD_BLOB; 449 | 450 | typedef struct _BYTE_SIZEDARR 451 | { 452 | unsigned long clSize; 453 | uint8_t *pData; 454 | } BYTE_SIZEDARR; 455 | 456 | typedef struct _SHORT_SIZEDARR 457 | { 458 | unsigned long clSize; 459 | unsigned short *pData; 460 | } WORD_SIZEDARR; 461 | 462 | typedef struct _LONG_SIZEDARR 463 | { 464 | unsigned long clSize; 465 | unsigned long *pData; 466 | } DWORD_SIZEDARR; 467 | 468 | 469 | ]] 470 | 471 | --typedef enum tagCLSCTX { 472 | CLSCTX_INPROC_SERVER = 0x1 473 | CLSCTX_INPROC_HANDLER = 0x2 474 | CLSCTX_LOCAL_SERVER = 0x4 475 | CLSCTX_INPROC_SERVER16 = 0x8 476 | CLSCTX_REMOTE_SERVER = 0x10 477 | CLSCTX_INPROC_HANDLER16 = 0x20 478 | CLSCTX_RESERVED1 = 0x40 479 | CLSCTX_RESERVED2 = 0x80 480 | CLSCTX_RESERVED3 = 0x100 481 | CLSCTX_RESERVED4 = 0x200 482 | CLSCTX_NO_CODE_DOWNLOAD = 0x400 483 | CLSCTX_RESERVED5 = 0x800 484 | CLSCTX_NO_CUSTOM_MARSHAL = 0x1000 485 | CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000 486 | CLSCTX_NO_FAILURE_LOG = 0x4000 487 | CLSCTX_DISABLE_AAA = 0x8000 488 | CLSCTX_ENABLE_AAA = 0x10000 489 | CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000 490 | CLSCTX_ACTIVATE_32_BIT_SERVER = 0x40000 491 | CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000 492 | CLSCTX_ENABLE_CLOAKING = 0x100000 493 | CLSCTX_PS_DLL = 0x80000000 494 | --} CLSCTX; 495 | 496 | CLSCTX_VALID_MASK = bor( 497 | CLSCTX_INPROC_SERVER , 498 | CLSCTX_INPROC_HANDLER , 499 | CLSCTX_LOCAL_SERVER , 500 | CLSCTX_INPROC_SERVER16 , 501 | CLSCTX_REMOTE_SERVER , 502 | CLSCTX_NO_CODE_DOWNLOAD , 503 | CLSCTX_NO_CUSTOM_MARSHAL , 504 | CLSCTX_ENABLE_CODE_DOWNLOAD , 505 | CLSCTX_NO_FAILURE_LOG , 506 | CLSCTX_DISABLE_AAA , 507 | CLSCTX_ENABLE_AAA , 508 | CLSCTX_FROM_DEFAULT_CONTEXT , 509 | CLSCTX_ACTIVATE_32_BIT_SERVER , 510 | CLSCTX_ACTIVATE_64_BIT_SERVER , 511 | CLSCTX_ENABLE_CLOAKING , 512 | CLSCTX_PS_DLL) 513 | 514 | WDT_INPROC_CALL =( 0x48746457 ) 515 | 516 | WDT_REMOTE_CALL =( 0x52746457 ) 517 | 518 | WDT_INPROC64_CALL = ( 0x50746457 ) 519 | 520 | ffi.cdef[[ 521 | typedef struct _tagpropertykey 522 | { 523 | GUID fmtid; 524 | DWORD pid; 525 | } PROPERTYKEY; 526 | 527 | typedef const PROPERTYKEY * REFPROPERTYKEY; 528 | 529 | enum VARENUM 530 | { VT_EMPTY = 0, 531 | VT_NULL = 1, 532 | VT_I2 = 2, 533 | VT_I4 = 3, 534 | VT_R4 = 4, 535 | VT_R8 = 5, 536 | VT_CY = 6, 537 | VT_DATE = 7, 538 | VT_BSTR = 8, 539 | VT_DISPATCH = 9, 540 | VT_ERROR = 10, 541 | VT_BOOL = 11, 542 | VT_VARIANT = 12, 543 | VT_UNKNOWN = 13, 544 | VT_DECIMAL = 14, 545 | VT_I1 = 16, 546 | VT_UI1 = 17, 547 | VT_UI2 = 18, 548 | VT_UI4 = 19, 549 | VT_I8 = 20, 550 | VT_UI8 = 21, 551 | VT_INT = 22, 552 | VT_UINT = 23, 553 | VT_VOID = 24, 554 | VT_HRESULT = 25, 555 | VT_PTR = 26, 556 | VT_SAFEARRAY = 27, 557 | VT_CARRAY = 28, 558 | VT_USERDEFINED = 29, 559 | VT_LPSTR = 30, 560 | VT_LPWSTR = 31, 561 | VT_RECORD = 36, 562 | VT_INT_PTR = 37, 563 | VT_UINT_PTR = 38, 564 | VT_FILETIME = 64, 565 | VT_BLOB = 65, 566 | VT_STREAM = 66, 567 | VT_STORAGE = 67, 568 | VT_STREAMED_OBJECT = 68, 569 | VT_STORED_OBJECT = 69, 570 | VT_BLOB_OBJECT = 70, 571 | VT_CF = 71, 572 | VT_CLSID = 72, 573 | VT_VERSIONED_STREAM = 73, 574 | VT_BSTR_BLOB = 0xfff, 575 | VT_VECTOR = 0x1000, 576 | VT_ARRAY = 0x2000, 577 | VT_BYREF = 0x4000, 578 | VT_RESERVED = 0x8000, 579 | VT_ILLEGAL = 0xffff, 580 | VT_ILLEGALMASKED = 0xfff, 581 | VT_TYPEMASK = 0xfff 582 | } ; 583 | 584 | typedef ULONG PROPID; 585 | 586 | ]] 587 | 588 | ffi.cdef[[ 589 | typedef double DATE; 590 | 591 | // Currency 592 | typedef union tagCY { 593 | struct { 594 | unsigned long Lo; 595 | long Hi; 596 | }; 597 | LONGLONG int64; 598 | } CY; 599 | ]] 600 | 601 | ffi.cdef[[ 602 | enum { 603 | MAXSHORT = 32767, 604 | MINSHORT = -32768, 605 | 606 | MAXINT = 2147483647, 607 | MININT = -2147483648, 608 | 609 | // MAXLONGLONG = 9223372036854775807, 610 | // MINLONGLONG = -9223372036854775807, 611 | // ULONGLONG_MAX 0xffffffffffffffffui64, 612 | }; 613 | 614 | ]] 615 | 616 | 617 | ffi.cdef[[ 618 | 619 | typedef struct tagSIZE { 620 | LONG cx; 621 | LONG cy; 622 | } SIZE, *PSIZE, *LPSIZE; 623 | 624 | typedef struct tagPOINT { 625 | int32_t x; 626 | int32_t y; 627 | } POINT, *PPOINT, *LPPOINT; 628 | 629 | typedef struct tagPOINTS 630 | { 631 | SHORT x; 632 | SHORT y; 633 | } POINTS, *PPOINTS, *LPPOINTS; 634 | 635 | typedef struct _POINTL { 636 | LONG x; 637 | LONG y; 638 | } POINTL, *PPOINTL; 639 | ]] 640 | 641 | ffi.cdef[[ 642 | typedef struct tagRECT { 643 | int32_t left; 644 | int32_t top; 645 | int32_t right; 646 | int32_t bottom; 647 | } RECT, *PRECT, *LPRECT; 648 | 649 | typedef const RECT * LPCRECT; 650 | ]] 651 | 652 | 653 | RECT = ffi.typeof("RECT") 654 | RECT_mt = { 655 | __tostring = function(self) 656 | local str = string.format("%d %d %d %d", self.left, self.top, self.right, self.bottom) 657 | return str 658 | end, 659 | 660 | __index = { 661 | } 662 | } 663 | ffi.metatype(RECT, RECT_mt) 664 | 665 | local exports = { 666 | -- Constants 667 | VARIANT_TRUE = ffi.cast("VARIANT_BOOL", -1); 668 | VARIANT_FALSE = ffi.cast("VARIANT_BOOL", 0); 669 | 670 | -- Types 671 | BLOB = BLOB, 672 | POINT = ffi.typeof("POINT"); 673 | RECT = RECT, 674 | SIZE = ffi.typeof("SIZE"); 675 | 676 | -- Functions 677 | DECLARE_HANDLE = DECLARE_HANDLE, 678 | } 679 | 680 | return exports 681 | -------------------------------------------------------------------------------- /testy/application.lua: -------------------------------------------------------------------------------- 1 | -- Application.lua 2 | local Kernel = require("kernel"){exportglobal = true}; 3 | 4 | local Predicate = require("predicate")(Kernel, true) 5 | local Alarm = require("alarm")(Kernel, true) 6 | local asyncio = require("asyncio"){Kernel = Kernel, exportglobal = true} 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /testy/collections.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Collections.lua 3 | 4 | This file contains a few collection classes that are 5 | useful for many things. The most basic object is the 6 | simple list. 7 | 8 | From the list is implemented a queue 9 | --]] 10 | local setmetatable = setmetatable; 11 | 12 | 13 | --[[ 14 | A bag behaves similar to a dictionary. 15 | You can add values to it using simple array indexing 16 | You can also retrieve values based on array indexing 17 | The one addition is the '#' length operator works 18 | --]] 19 | local Bag = {} 20 | setmetatable(Bag, { 21 | __call = function(self, ...) 22 | return self:_new(...); 23 | end, 24 | }) 25 | 26 | local Bag_mt = { 27 | __index = function(self, key) 28 | --print("__index: ", key) 29 | return self.tbl[key] 30 | end, 31 | 32 | __newindex = function(self, key, value) 33 | --print("__newindex: ", key, value) 34 | if value == nil then 35 | self.__Count = self.__Count - 1; 36 | else 37 | self.__Count = self.__Count + 1; 38 | end 39 | 40 | --rawset(self, key, value) 41 | self.tbl[key] = value; 42 | end, 43 | 44 | __len = function(self) 45 | -- print("__len: ", self.__Count) 46 | return self.__Count; 47 | end, 48 | 49 | __pairs = function(self) 50 | return pairs(self.tbl) 51 | end, 52 | } 53 | 54 | function Bag._new(self, obj) 55 | local obj = { 56 | tbl = {}, 57 | __Count = 0, 58 | } 59 | 60 | setmetatable(obj, Bag_mt); 61 | 62 | return obj; 63 | end 64 | 65 | 66 | -- The basic list type 67 | -- This will be used to implement queues and other things 68 | local List = {} 69 | local List_mt = { 70 | __index = List; 71 | } 72 | 73 | function List.new(params) 74 | local obj = params or {first=0, last=-1} 75 | 76 | setmetatable(obj, List_mt) 77 | 78 | return obj 79 | end 80 | 81 | 82 | function List:PushLeft (value) 83 | local first = self.first - 1 84 | self.first = first 85 | self[first] = value 86 | end 87 | 88 | function List:PushRight(value) 89 | local last = self.last + 1 90 | self.last = last 91 | self[last] = value 92 | end 93 | 94 | function List:PopLeft() 95 | local first = self.first 96 | 97 | if first > self.last then 98 | return nil, "list is empty" 99 | end 100 | local value = self[first] 101 | self[first] = nil -- to allow garbage collection 102 | self.first = first + 1 103 | 104 | return value 105 | end 106 | 107 | function List:PopRight() 108 | local last = self.last 109 | if self.first > last then 110 | return nil, "list is empty" 111 | end 112 | local value = self[last] 113 | self[last] = nil -- to allow garbage collection 114 | self.last = last - 1 115 | 116 | return value 117 | end 118 | 119 | --[[ 120 | Stack 121 | --]] 122 | local Stack = {} 123 | setmetatable(Stack,{ 124 | __call = function(self, ...) 125 | return self:new(...); 126 | end, 127 | }); 128 | 129 | local Stack_mt = { 130 | __len = function(self) 131 | return self.Impl.last - self.Impl.first+1 132 | end, 133 | 134 | __index = Stack; 135 | } 136 | 137 | function Stack.new(self, ...) 138 | local obj = { 139 | Impl = List.new(); 140 | } 141 | 142 | setmetatable(obj, Stack_mt); 143 | 144 | return obj; 145 | end 146 | 147 | function Stack.len(self) 148 | return self.Impl.last - self.Impl.first+1 149 | end 150 | 151 | function Stack.push(self, item) 152 | return self.Impl:PushRight(item); 153 | end 154 | 155 | function Stack.pop(self) 156 | return self.Impl:PopRight(); 157 | end 158 | 159 | 160 | 161 | 162 | return { 163 | Bag = Bag; 164 | List = List; 165 | Stack = Stack; 166 | } 167 | 168 | -------------------------------------------------------------------------------- /testy/functor.lua: -------------------------------------------------------------------------------- 1 | -- functor.lua 2 | --[[ 3 | A function is a way to attach a function to a target without having 4 | to construct a table explicitly. 5 | 6 | Example: 7 | 8 | local function printNameField(tbl) 9 | print(tbl.Name); 10 | end 11 | 12 | local func = Functor(printNameField, someTable) 13 | 14 | func() 15 | 16 | This construct is useful when you have an instance of a table, which has 17 | associated functions, and you want to pass a particular function call within 18 | that instance to another function that expects a single value. 19 | 20 | --]] 21 | local function Functor(func, target) 22 | return function(...) 23 | if target then 24 | return func(target,...) 25 | end 26 | 27 | return func(...) 28 | end 29 | end 30 | 31 | return Functor -------------------------------------------------------------------------------- /testy/linux_timespec.lua: -------------------------------------------------------------------------------- 1 | --linux.lua 2 | --[[ 3 | ffi routines for Linux. 4 | To get full *nix support, we should use ljsyscall as that 5 | has already worked out all the cross platform details. 6 | For now, we just want to get a minimum ste of routines 7 | that will work with x86_64 Linux 8 | 9 | As soon as this file becomes a few hundred lines, it's time 10 | to abandon it and switch to ljsyscall 11 | --]] 12 | local ffi = require("ffi") 13 | 14 | local exports = {} 15 | local C = {} -- C interop, or syscall 16 | 17 | 18 | local timespec = ffi.typeof("struct timespec") 19 | local timespec_mt = { 20 | __add = function(lhs, rhs) 21 | local newspec = timespec(); 22 | newspec:setFromSeconds(lhs:seconds()+rhs:seconds()) 23 | 24 | return newspec; 25 | end; 26 | 27 | __sub = function(lhs, rhs) 28 | local newspec = timespec(); 29 | newspec:setFromSeconds(lhs:seconds()-rhs:seconds()) 30 | 31 | return newspec; 32 | end; 33 | 34 | __tostring = function(self) 35 | return string.format("%d.%d", tonumber(self.tv_sec), tonumber(self.tv_nsec)); 36 | end; 37 | 38 | __index = { 39 | gettime = function(self, clockid) 40 | clockid = clockid or ffi.C.CLOCK_REALTIME; 41 | local res = ffi.C.clock_gettime(clockid, self) 42 | return res; 43 | end; 44 | 45 | getresolution = function(self, clockid) 46 | clockid = clockid or ffi.C.CLOCK_REALTIME; 47 | local res = ffi.C.clock_getres(clockid, self); 48 | return res; 49 | end; 50 | 51 | setFromSeconds = function(self, seconds) 52 | -- the seconds without fraction can become tv_sec 53 | local secs, frac = math.modf(seconds) 54 | local nsecs = frac * 1000000000; 55 | self.tv_sec = secs; 56 | self.tv_nsec = nsecs; 57 | 58 | return true; 59 | end; 60 | 61 | seconds = function(self) 62 | return tonumber(self.tv_sec) + (tonumber(self.tv_nsec) / 1000000000); -- one billion'th of a second 63 | end; 64 | 65 | }; 66 | } 67 | ffi.metatype(timespec, timespec_mt) 68 | exports.timespec = timespec; 69 | 70 | function exports.sleep(seconds, clockid, flags) 71 | clockid = clockid or ffi.C.CLOCK_REALTIME; 72 | flags = flags or 0 73 | local request = timespec(); 74 | local remain = timespec(); 75 | 76 | request:setFromSeconds(seconds); 77 | local res = ffi.C.clock_nanosleep(clockid, flags, request, remain); 78 | 79 | return remain:seconds(); 80 | end 81 | 82 | 83 | 84 | exports.C = C; 85 | 86 | setmetatable(exports, { 87 | __call = function(self) 88 | for k,v in pairs(exports) do 89 | _G[k] = v; 90 | end 91 | end; 92 | }) 93 | 94 | return exports 95 | -------------------------------------------------------------------------------- /testy/lookupsite.lua: -------------------------------------------------------------------------------- 1 | --lookupsite.lua 2 | package.path = package.path..";../?.lua" 3 | 4 | local ffi = require("ffi") 5 | local net = require("linux_net") 6 | local sites = require("sites") 7 | 8 | --[[ 9 | struct addrinfo { 10 | int ai_flags; // AI_PASSIVE, AI_CANONNAME, ... 11 | int ai_family; // AF_xxx 12 | int ai_socktype; // SOCK_xxx 13 | int ai_protocol; // 0 (auto) or IPPROTO_TCP, IPPROTO_UDP 14 | 15 | socklen_t ai_addrlen; // length of ai_addr 16 | struct sockaddr *ai_addr; // binary address 17 | char *ai_canonname; // canonical name for nodename 18 | struct addrinfo *ai_next; // next structure in linked list 19 | }; 20 | --]] 21 | 22 | local function lookupsite(nodename) 23 | print("==== lookupsite: ", nodename) 24 | 25 | local servname = "http" 26 | local res = ffi.new("struct addrinfo * [1]") 27 | local hints = ffi.new("struct addrinfo") 28 | 29 | hints.ai_flags = net.AI_CANONNAME; 30 | hints.ai_family = net.AF_UNSPEC; 31 | hints.ai_socktype = net.SOCK_STREAM; 32 | 33 | local ret = ffi.C.getaddrinfo(nodename, servname, hints, res); 34 | print("getaddrinfo: ", ret) 35 | if ret ~= 0 then 36 | return false, ret; 37 | end 38 | 39 | local ptr = res[0]; 40 | 41 | local sa = ffi.new("struct sockaddr_in") 42 | 43 | print(string.format("-- family: %d socktype: %d proto: %d", 44 | ptr.ai_family, ptr.ai_socktype, ptr.ai_protocol)); 45 | if ptr.ai_canonname ~= nil then 46 | print(" canonname: ", ffi.string(ptr.ai_canonname)) 47 | end 48 | 49 | --print(" ai.addr: ", ptr.ai_addr, ptr.ai_addrlen); 50 | 51 | ffi.copy(sa, ptr.ai_addr, ffi.sizeof(sa)) 52 | 53 | ffi.C.freeaddrinfo(res[0]); 54 | 55 | return sa, ffi.sizeof(sa) 56 | end 57 | 58 | 59 | for idx=1,5 do 60 | print(lookupsite(sites[idx])) 61 | end 62 | 63 | 64 | --print(lookupsite(nil)) -------------------------------------------------------------------------------- /testy/siteextractor.lua: -------------------------------------------------------------------------------- 1 | -- download a .csv file from 2 | -- https://moz.com/top500 3 | -- Then run it through this program. 4 | -- running the extractfromcsv will generate individual 5 | -- lines, each containing the url of a domain 6 | -- this will go to stdout 7 | -- redirect to a file, edit as necessary, typically making a table 8 | 9 | local function split(s, sep) 10 | local sep = sep or "/" 11 | local fields = {} 12 | local pattern = string.format("([^%s]+)", sep) 13 | 14 | s:gsub(pattern, function(c) fields[#fields+1] = c end) 15 | 16 | return fields 17 | end 18 | 19 | local function extractfromcsv(filename) 20 | local filename = "top500.domains.01.14.csv" 21 | for line in io.lines(filename) do 22 | local record = split(line, ',') 23 | local url = record[2]:gsub('/',''); 24 | 25 | print(string.format("%s,",url)) 26 | end 27 | end 28 | 29 | local function importfromtable(moduleName) 30 | print("==== importfromtable: ", moduleName) 31 | 32 | local sites = require(moduleName) 33 | 34 | for _, site in ipairs(sites) do 35 | print(site) 36 | end 37 | end 38 | 39 | 40 | extractfromcsv("top500.domains.01.14.csv") 41 | --importfromtable("sites") 42 | -------------------------------------------------------------------------------- /testy/sites.lua: -------------------------------------------------------------------------------- 1 | local exports = { 2 | "facebook.com", 3 | "twitter.com", 4 | "google.com", 5 | "youtube.com", 6 | "wordpress.org", 7 | "adobe.com", 8 | "blogspot.com", 9 | "wikipedia.org", 10 | "linkedin.com", 11 | "wordpress.com", 12 | "yahoo.com", 13 | "amazon.com", 14 | "flickr.com", 15 | "pinterest.com", 16 | "tumblr.com", 17 | "w3.org", 18 | "apple.com", 19 | "myspace.com", 20 | "vimeo.com", 21 | "microsoft.com", 22 | "youtu.be", 23 | "qq.com", 24 | "digg.com", 25 | "baidu.com", 26 | "stumbleupon.com", 27 | "addthis.com", 28 | "statcounter.com", 29 | "feedburner.com", 30 | "miibeian.gov.cn", 31 | "delicious.com", 32 | "nytimes.com", 33 | "reddit.com", 34 | "weebly.com", 35 | "bbc.co.uk", 36 | "blogger.com", 37 | "msn.com", 38 | "macromedia.com", 39 | "goo.gl", 40 | "instagram.com", 41 | "gov.uk", 42 | "icio.us", 43 | "yandex.ru", 44 | "cnn.com", 45 | "webs.com", 46 | "google.de", 47 | "t.co", 48 | "livejournal.com", 49 | "imdb.com", 50 | "mail.ru", 51 | "jimdo.com", 52 | "sourceforge.net", 53 | "go.com", 54 | "tinyurl.com", 55 | "vk.com", 56 | "google.co.jp", 57 | "fc2.com", 58 | "free.fr", 59 | "joomla.org", 60 | "creativecommons.org", 61 | "typepad.com", 62 | "networkadvertising.org", 63 | "technorati.com", 64 | "sina.com.cn", 65 | "hugedomains.com", 66 | "about.com", 67 | "theguardian.com", 68 | "yahoo.co.jp", 69 | "nih.gov", 70 | "huffingtonpost.com", 71 | "google.co.uk", 72 | "mozilla.org", 73 | "51.la", 74 | "aol.com", 75 | "ebay.com", 76 | "ameblo.jp", 77 | "wsj.com", 78 | "europa.eu", 79 | "taobao.com", 80 | "bing.com", 81 | "rambler.ru", 82 | "guardian.co.uk", 83 | "tripod.com", 84 | "godaddy.com", 85 | "issuu.com", 86 | "gnu.org", 87 | "geocities.com", 88 | "slideshare.net", 89 | "wix.com", 90 | "mapquest.com", 91 | "washingtonpost.com", 92 | "homestead.com", 93 | "reuters.com", 94 | "163.com", 95 | "photobucket.com", 96 | "forbes.com", 97 | "clickbank.net", 98 | "weibo.com", 99 | "etsy.com", 100 | "amazon.co.uk", 101 | "dailymotion.com", 102 | "soundcloud.com", 103 | "usatoday.com", 104 | "yelp.com", 105 | "cnet.com", 106 | "posterous.com", 107 | "telegraph.co.uk", 108 | "archive.org", 109 | "google.fr", 110 | "constantcontact.com", 111 | "phoca.cz", 112 | "phpbb.com", 113 | "latimes.com", 114 | "e-recht24.de", 115 | "rakuten.co.jp", 116 | "amazon.de", 117 | "opera.com", 118 | "miitbeian.gov.cn", 119 | "php.net", 120 | "scribd.com", 121 | "bbb.org", 122 | "parallels.com", 123 | "ning.com", 124 | "dailymail.co.uk", 125 | "cdc.gov", 126 | "sohu.com", 127 | "wikimedia.org", 128 | "deviantart.com", 129 | "mit.edu", 130 | "sakura.ne.jp", 131 | "altervista.org", 132 | "addtoany.com", 133 | "time.com", 134 | "google.it", 135 | "stanford.edu", 136 | "live.com", 137 | "alibaba.com", 138 | "squidoo.com", 139 | "harvard.edu", 140 | "gravatar.com", 141 | "histats.com", 142 | "nasa.gov", 143 | "npr.org", 144 | "ca.gov", 145 | "eventbrite.com", 146 | "wired.com", 147 | "amazon.co.jp", 148 | "nbcnews.com", 149 | "blog.com", 150 | "amazonaws.com", 151 | "bloomberg.com", 152 | "narod.ru", 153 | "blinklist.com", 154 | "imageshack.us", 155 | "kickstarter.com", 156 | "hatena.ne.jp", 157 | "nifty.com", 158 | "angelfire.com", 159 | "google.es", 160 | "ocn.ne.jp", 161 | "over-blog.com", 162 | "dedecms.com", 163 | "google.ca", 164 | "a8.net", 165 | "weather.com", 166 | "pbs.org", 167 | "ibm.com", 168 | "cpanel.net", 169 | "prweb.com", 170 | "bandcamp.com", 171 | "barnesandnoble.com", 172 | "mozilla.com", 173 | "noaa.gov", 174 | "goo.ne.jp", 175 | "comsenz.com", 176 | "xrea.com", 177 | "cbsnews.com", 178 | "foxnews.com", 179 | "discuz.net", 180 | "eepurl.com", 181 | "businessweek.com", 182 | "berkeley.edu", 183 | "newsvine.com", 184 | "bluehost.com", 185 | "geocities.jp", 186 | "loc.gov", 187 | "yolasite.com", 188 | "apache.org", 189 | "mashable.com", 190 | "usda.gov", 191 | "nationalgeographic.com", 192 | "whitehouse.gov", 193 | "tripadvisor.com", 194 | "ted.com", 195 | "sfgate.com", 196 | "biglobe.ne.jp", 197 | "epa.gov", 198 | "vkontakte.ru", 199 | "oracle.com", 200 | "seesaa.net", 201 | "examiner.com", 202 | "cornell.edu", 203 | "hp.com", 204 | "nps.gov", 205 | "disqus.com", 206 | "alexa.com", 207 | "mysql.com", 208 | "house.gov", 209 | "sphinn.com", 210 | "boston.com", 211 | "techcrunch.com", 212 | "un.org", 213 | "squarespace.com", 214 | "icq.com", 215 | "freewebs.com", 216 | "ezinearticles.com", 217 | "ucoz.ru", 218 | "independent.co.uk", 219 | "mediafire.com", 220 | "xinhuanet.com", 221 | "google.nl", 222 | "reverbnation.com", 223 | "imgur.com", 224 | "irs.gov", 225 | "webnode.com", 226 | "wunderground.com", 227 | "bizjournals.com", 228 | "who.int", 229 | "soup.io", 230 | "cloudflare.com", 231 | "people.com.cn", 232 | "ustream.tv", 233 | "senate.gov", 234 | "cbslocal.com", 235 | "ycombinator.com", 236 | "opensource.org", 237 | "spiegel.de", 238 | "oaic.gov.au", 239 | "nature.com", 240 | "businessinsider.com", 241 | "drupal.org", 242 | "last.fm", 243 | "privacy.gov.au", 244 | "skype.com", 245 | "wikia.com", 246 | "about.me", 247 | "webmd.com", 248 | "youku.com", 249 | "gmpg.org", 250 | "fda.gov", 251 | "redcross.org", 252 | "github.com", 253 | "cbc.ca", 254 | "umich.edu", 255 | "jugem.jp", 256 | "shinystat.com", 257 | "google.com.br", 258 | "ifeng.com", 259 | "mac.com", 260 | "wiley.com", 261 | "discovery.com", 262 | "topsy.com", 263 | "paypal.com", 264 | "google.cn", 265 | "surveymonkey.com", 266 | "moonfruit.com", 267 | "dropbox.com", 268 | "exblog.jp", 269 | "google.pl", 270 | "prnewswire.com", 271 | "ft.com", 272 | "uol.com.br", 273 | "behance.net", 274 | "goodreads.com", 275 | "netvibes.com", 276 | "auda.org.au", 277 | "marketwatch.com", 278 | "ed.gov", 279 | "networksolutions.com", 280 | "state.gov", 281 | "sitemeter.com", 282 | "liveinternet.ru", 283 | "ftc.gov", 284 | "census.gov", 285 | "quantcast.com", 286 | "economist.com", 287 | "nydailynews.com", 288 | "zdnet.com", 289 | "cafepress.com", 290 | "ow.ly", 291 | "meetup.com", 292 | "netscape.com", 293 | "chicagotribune.com", 294 | "theatlantic.com", 295 | "google.com.au", 296 | "1688.com", 297 | "skyrock.com", 298 | "list-manage.com", 299 | "pagesperso-orange.fr", 300 | "cdbaby.com", 301 | "friendfeed.com", 302 | "ehow.com", 303 | "patch.com", 304 | "upenn.edu", 305 | "engadget.com", 306 | "diigo.com", 307 | "com.com", 308 | "slashdot.org", 309 | "washington.edu", 310 | "columbia.edu", 311 | "nhs.uk", 312 | "abc.net.au", 313 | "elegantthemes.com", 314 | "utexas.edu", 315 | "yale.edu", 316 | "marriott.com", 317 | "bigcartel.com", 318 | "ucla.edu", 319 | "usgs.gov", 320 | "jigsy.com", 321 | "hexun.com", 322 | "hubpages.com", 323 | "slate.com", 324 | "purevolume.com", 325 | "umn.edu", 326 | "bloglines.com", 327 | "so-net.ne.jp", 328 | "wikispaces.com", 329 | "cargocollective.com", 330 | "howstuffworks.com", 331 | "plala.or.jp", 332 | "infoseek.co.jp", 333 | "jiathis.com", 334 | "usnews.com", 335 | "xing.com", 336 | "flavors.me", 337 | "desdev.cn", 338 | "hc360.com", 339 | "usa.gov", 340 | "edublogs.org", 341 | "lycos.com", 342 | "wisc.edu", 343 | "thetimes.co.uk", 344 | "state.tx.us", 345 | "example.com", 346 | "shareasale.com", 347 | "biblegateway.com", 348 | "is.gd", 349 | "yellowbook.com", 350 | "samsung.com", 351 | "businesswire.com", 352 | "g.co", 353 | "dion.ne.jp", 354 | "dagondesign.com", 355 | "theglobeandmail.com", 356 | "booking.com", 357 | "storify.com", 358 | "salon.com", 359 | "ucoz.com", 360 | "gizmodo.com", 361 | "psu.edu", 362 | "smh.com.au", 363 | "reference.com", 364 | "sun.com", 365 | "unicef.org", 366 | "devhub.com", 367 | "artisteer.com", 368 | "unesco.org", 369 | "istockphoto.com", 370 | "answers.com", 371 | "trellian.com", 372 | "cocolog-nifty.com", 373 | "i2i.jp", 374 | "t-online.de", 375 | "intel.com", 376 | "1und1.de", 377 | "ebay.co.uk", 378 | "sciencedaily.com", 379 | "paginegialle.it", 380 | "ask.com", 381 | "springer.com", 382 | "canalblog.com", 383 | "timesonline.co.uk", 384 | "de.vu", 385 | "deliciousdays.com", 386 | "smugmug.com", 387 | "wufoo.com", 388 | "globo.com", 389 | "cmu.edu", 390 | "domainmarket.com", 391 | "odnoklassniki.ru", 392 | "twitpic.com", 393 | "ovh.net", 394 | "home.pl", 395 | "naver.com", 396 | "google.ru", 397 | "si.edu", 398 | "newyorker.com", 399 | "blogs.com", 400 | "sciencedirect.com", 401 | "hibu.com", 402 | "hud.gov", 403 | "hhs.gov", 404 | "dmoz.org", 405 | "dot.gov", 406 | "cyberchimps.com", 407 | "google.com.hk", 408 | "jalbum.net", 409 | "craigslist.org", 410 | "zimbio.com", 411 | "chronoengine.com", 412 | "cnbc.com", 413 | "uiuc.edu", 414 | "vistaprint.com", 415 | "symantec.com", 416 | "prlog.org", 417 | "360.cn", 418 | "indiatimes.com", 419 | "mtv.com", 420 | "webeden.co.uk", 421 | "java.com", 422 | "cisco.com", 423 | "japanpost.jp", 424 | "4shared.com", 425 | "github.io", 426 | "mayoclinic.com", 427 | "studiopress.com", 428 | "admin.ch", 429 | "virginia.edu", 430 | "printfriendly.com", 431 | "mlb.com", 432 | "omniture.com", 433 | "simplemachines.org", 434 | "dell.com", 435 | "accuweather.com", 436 | "princeton.edu", 437 | "fotki.com", 438 | "comcast.net", 439 | "chron.com", 440 | "nyu.edu", 441 | "wp.com", 442 | "merriam-webster.com", 443 | "nba.com", 444 | "shop-pro.jp", 445 | "lulu.com", 446 | "furl.net", 447 | "indiegogo.com", 448 | "buzzfeed.com", 449 | "tuttocitta.it", 450 | "ox.ac.uk", 451 | "mapy.cz", 452 | "army.mil", 453 | "csmonitor.com", 454 | "bravesites.com", 455 | "tamu.edu", 456 | "rediff.com", 457 | "toplist.cz", 458 | "yellowpages.com", 459 | "va.gov", 460 | "tiny.cc", 461 | "netlog.com", 462 | "elpais.com", 463 | "oakley.com", 464 | "multiply.com", 465 | "tmall.com", 466 | "hostgator.com", 467 | "nymag.com", 468 | "fema.gov", 469 | "blogtalkradio.com", 470 | "china.com.cn", 471 | "unblog.fr", 472 | "fastcompany.com", 473 | "earthlink.net", 474 | "vinaora.com", 475 | "msu.edu", 476 | "aboutads.info", 477 | "ucsd.edu", 478 | "sogou.com", 479 | "seattletimes.com", 480 | "dyndns.org", 481 | "123-reg.co.uk", 482 | "sbwire.com", 483 | "tinypic.com", 484 | "acquirethisname.com", 485 | "shutterfly.com", 486 | "walmart.com", 487 | "pen.io", 488 | "arizona.edu", 489 | "woothemes.com", 490 | "scientificamerican.com", 491 | "themeforest.net", 492 | "spotify.com", 493 | "cam.ac.uk", 494 | "unc.edu", 495 | "arstechnica.com", 496 | "hao123.com", 497 | "illinois.edu", 498 | "bloglovin.com", 499 | "nsw.gov.au", 500 | "ihg.com", 501 | "pcworld.com", 502 | } 503 | 504 | return exports 505 | -------------------------------------------------------------------------------- /testy/test_alarm_delay.lua: -------------------------------------------------------------------------------- 1 | --test_stopwatch.lua 2 | package.path = "../?.lua;"..package.path 3 | 4 | local Kernel = require("schedlua.kernel") 5 | local StopWatch = require("schedlua.stopwatch") 6 | 7 | local sw = StopWatch(); 8 | 9 | local function twoSeconds() 10 | print("TWO SECONDS: ", sw:seconds()); 11 | halt(); 12 | end 13 | 14 | local function main() 15 | print("delay(2000, twoSeconds)"); 16 | delay(2000, twoSeconds); 17 | print("still going") 18 | end 19 | 20 | run(main) 21 | -------------------------------------------------------------------------------- /testy/test_alarm_periodic.lua: -------------------------------------------------------------------------------- 1 | --test_stopwatch.lua 2 | package.path = package.path..";../?.lua" 3 | 4 | local Kernel = require("schedlua.kernel")(); 5 | local StopWatch = require("schedlua.stopwatch") 6 | 7 | local sw = StopWatch(); 8 | 9 | 10 | local function haltAfterTime(msecs) 11 | local function closure() 12 | print("READY TO HALT: ", msecs, sw:seconds()); 13 | halt(); 14 | end 15 | 16 | delay(msecs, closure); -- halt after specified seconds 17 | end 18 | 19 | local function everyPeriod() 20 | print("PERIODIC: ", sw:seconds()); 21 | end 22 | 23 | local function main() 24 | periodic(250, everyPeriod) 25 | haltAfterTime(5000); 26 | end 27 | 28 | run(main) 29 | -------------------------------------------------------------------------------- /testy/test_alarm_sleep.lua: -------------------------------------------------------------------------------- 1 | --test_stopwatch.lua 2 | package.path = package.path..";../?.lua" 3 | 4 | local Kernel = require("schedlua.kernel") 5 | local StopWatch = require("schedlua.stopwatch") 6 | 7 | local sw = StopWatch(); 8 | 9 | 10 | 11 | local function main() 12 | local starttime = sw:reset(); 13 | print("sleep(3525)"); 14 | 15 | sleep(3525); 16 | 17 | local duration = sw:seconds(); 18 | 19 | print("Duration: ", duration); 20 | 21 | halt(); 22 | end 23 | 24 | run(main) 25 | -------------------------------------------------------------------------------- /testy/test_async_socket.lua: -------------------------------------------------------------------------------- 1 | --test_async_socket.lua 2 | package.path = package.path..";../?.lua" 3 | 4 | --[[ 5 | Simple networking test case. 6 | Implement a client that will do a basic HTTP GET to any 7 | given url. It will read results back until the socket 8 | is closed. 9 | 10 | This does not do any http parsing. 11 | --]] 12 | local ffi = require("ffi") 13 | 14 | 15 | local Kernel = require("kernel"); 16 | local AsyncSocket = require("AsyncSocket") 17 | 18 | local servername = arg[1] or "www.bing.com" 19 | 20 | local function httpRequest(s) 21 | local request = string.format("GET / HTTP/1.1\r\nUser-Agent: schedlua (linux-gnu)\r\nAccept: */*\r\nHost: %s\r\nConnection: close\r\n\r\n", servername); 22 | 23 | io.write(request) 24 | print("===================") 25 | 26 | return s:write(request, #request); 27 | end 28 | 29 | local function httpResponse(s) 30 | local BUFSIZ = 512; 31 | local buffer = ffi.new("char[512+1]"); 32 | local bytesRead = 0 33 | local err = nil; 34 | 35 | repeat 36 | bytesRead = 0; 37 | 38 | bytesRead, err = s:read(buffer, BUFSIZ); 39 | 40 | if bytesRead then 41 | local str = ffi.string(buffer, bytesRead); 42 | io.write(str); 43 | else 44 | print("read, error: ", err) 45 | break; 46 | end 47 | 48 | until bytesRead < 1 49 | end 50 | 51 | 52 | local function probeHttp(s) 53 | httpRequest(s); 54 | httpResponse(s); 55 | 56 | Kernel:halt(); 57 | end 58 | 59 | local function main() 60 | local s = AsyncSocket(); 61 | if not s:connect(servername, 80) then 62 | print("connection error") 63 | return false; 64 | end 65 | 66 | Kernel:spawn(probeHttp, s) 67 | end 68 | 69 | Kernel:run(main) 70 | -------------------------------------------------------------------------------- /testy/test_http_barrier.lua: -------------------------------------------------------------------------------- 1 | --test_linux_net.lua 2 | package.path = package.path..";../?.lua" 3 | 4 | local ffi = require("ffi") 5 | 6 | local Kernel = require("schedlua.kernel"){exportglobal = true} 7 | local predicate = require("schedlua.predicate")(Kernel, true) 8 | local AsyncSocket = require("schedlua.AsyncSocket") 9 | 10 | local sites = require("sites"); 11 | 12 | -- list of tasks 13 | local taskList = {} 14 | 15 | 16 | local function httpRequest(s, sitename) 17 | local request = string.format("GET / HTTP/1.1\r\nUser-Agent: schedlua (linux-gnu)\r\nAccept: */*\r\nHost: %s\r\nConnection: close\r\n\r\n", sitename); 18 | return s:write(request, #request); 19 | end 20 | 21 | local function httpResponse(s) 22 | local BUFSIZ = 512; 23 | local buffer = ffi.new("char[512+1]"); 24 | local bytesRead = 0 25 | local err = nil; 26 | local cumulative = 0 27 | 28 | repeat 29 | bytesRead, err = s:read(buffer, BUFSIZ); 30 | 31 | if bytesRead then 32 | cumulative = cumulative + bytesRead; 33 | else 34 | print("read, error: ", err) 35 | break; 36 | end 37 | until bytesRead < 1 38 | 39 | return cumulative; 40 | end 41 | 42 | 43 | local function siteGET(sitename) 44 | print("siteGET, BEGIN: ", sitename); 45 | 46 | local s = AsyncSocket(); 47 | 48 | local success, err = s:connect(sitename, 80); 49 | 50 | if success then 51 | httpRequest(s, sitename); 52 | httpResponse(s); 53 | else 54 | print("connect, error: ", err, sitename); 55 | end 56 | 57 | s:close(); 58 | 59 | print("siteGET, FINISHED: ", sitename) 60 | end 61 | 62 | 63 | local function allProbesFinished() 64 | for idx, t in ipairs(taskList) do 65 | if t:getStatus() ~= "dead" then 66 | return false; 67 | end 68 | end 69 | 70 | return true; 71 | end 72 | 73 | local function main() 74 | for count=1,20 do 75 | table.insert(taskList, Kernel:spawn(siteGET, sites[math.random(#sites)])) 76 | Kernel:yield(); 77 | end 78 | 79 | when(allProbesFinished, halt); 80 | 81 | --[[ 82 | while true 83 | if allProbesFinished() then 84 | halt(); 85 | break; 86 | end 87 | yield(); 88 | end 89 | --]] 90 | end 91 | 92 | run(main) 93 | -------------------------------------------------------------------------------- /testy/test_http_probe.lua: -------------------------------------------------------------------------------- 1 | --test_linux_net.lua 2 | package.path = "../?.lua;"..package.path 3 | 4 | --[[ 5 | Simple networking test case. 6 | Implement a client to the daytime service (port 13) 7 | Make a basic TCP connection, read data, finish 8 | --]] 9 | local ffi = require("ffi") 10 | local bit = require("bit") 11 | local band, bor, lshift, rshift = bit.band, bit.bor, bit.lshift, bit.rshift 12 | 13 | 14 | local Kernel = require("schedlua.kernel"); 15 | local AsyncSocket = require("schedlua.linux.nativesocket"); 16 | 17 | 18 | 19 | local sites = require("sites"); 20 | 21 | 22 | local function httpRequest(s, sitename) 23 | local request = string.format("GET / HTTP/1.1\r\nUser-Agent: schedlua (linux-gnu)\r\nAccept: */*\r\nHost: %s\r\nConnection: close\r\n\r\n", sitename); 24 | 25 | 26 | local success, err = s:write(request, #request); 27 | print("==== httpRequest(), WRITE: ", success, err); 28 | io.write(request) 29 | print("---------------------"); 30 | 31 | return success, err; 32 | end 33 | 34 | 35 | local function httpResponse(s) 36 | local bytesRead = 0 37 | local err = nil; 38 | local BUFSIZ = 512; 39 | local buffer = ffi.new("char[512+1]"); 40 | 41 | 42 | -- Now that the socket is ready, we can wait for it to 43 | -- be readable, and do a read 44 | print("==== httpResponse ====") 45 | repeat 46 | bytesRead = 0; 47 | 48 | bytesRead, err = s:read(buffer, BUFSIZ); 49 | 50 | if bytesRead then 51 | local str = ffi.string(buffer, bytesRead); 52 | io.write(str); 53 | else 54 | print("==== httpResponse.READ, ERROR: ", err) 55 | break; 56 | end 57 | 58 | until bytesRead < 1 59 | 60 | print("-----------------") 61 | end 62 | 63 | 64 | local function probeSite(sitename) 65 | 66 | local s = AsyncSocket(); 67 | print("==== probeSite : ", sitename, s.fdesc.fd); 68 | 69 | local success, err = s:connect(sitename, 80); 70 | 71 | if not success then 72 | print("NO CONNECTION TO: ", sitename, err); 73 | return false, err 74 | end 75 | -- issue a request so we have something to read 76 | httpRequest(s, sitename); 77 | httpResponse(s); 78 | 79 | s:close(); 80 | end 81 | 82 | local function stopProgram() 83 | halt(); 84 | end 85 | 86 | local function main() 87 | local maxProbes = 80; 88 | 89 | delay(1000*10, stopProgram) 90 | 91 | for idx=1,maxProbes do 92 | --probeSite(sites[idx]) 93 | spawn(probeSite, sites[idx]) 94 | yield(); 95 | end 96 | end 97 | 98 | 99 | local function probeStress() 100 | alarm:delay(stopProgram, 1000*20) 101 | 102 | for i=1,10 do 103 | spawn(probeSite, sites[i]) 104 | --probeSite(sites[i]) 105 | end 106 | end 107 | 108 | run(main) 109 | --run(probeStress) 110 | -------------------------------------------------------------------------------- /testy/test_kernel.lua: -------------------------------------------------------------------------------- 1 | --test_scheduler.lua 2 | package.path = package.path..";../?.lua" 3 | 4 | local Kernel = require("schedlua.kernel") 5 | 6 | 7 | 8 | 9 | local function numbers(ending) 10 | local idx = 0; 11 | local function fred() 12 | idx = idx + 1; 13 | if idx > ending then 14 | return nil; 15 | end 16 | return idx; 17 | end 18 | 19 | return fred; 20 | end 21 | 22 | local function task1() 23 | print("first task, first line") 24 | yield(); 25 | print("first task, second line") 26 | end 27 | 28 | local function task2() 29 | print("second task, only line") 30 | end 31 | 32 | local function counter(name, nCount) 33 | for num in numbers(nCount) do 34 | print(name, num); 35 | yield(); 36 | end 37 | halt(); 38 | end 39 | 40 | local function main() 41 | local t0 = spawn(counter, "counter1", 5) 42 | local t1 = spawn(task1) 43 | local t2 = spawn(task2) 44 | local t3 = spawn(counter, "counter2", 7) 45 | end 46 | 47 | run(main) 48 | 49 | 50 | print("After kernel run...") 51 | -------------------------------------------------------------------------------- /testy/test_kernel_signal.lua: -------------------------------------------------------------------------------- 1 | --test_kernel_signal.lua 2 | --[[ 3 | A rudimentary test of the kernel signaling routines. 4 | This test runs a counter which generates a stream of well named 5 | events. A couple of routines will respond to the appropriate events 6 | using signalOne(). 7 | 8 | The halt() routine will respond to the 'counter-finished' event 9 | which is signaled with signalAll() 10 | --]] 11 | package.path = package.path..";../?.lua" 12 | 13 | local Kernel = require("schedlua.kernel") 14 | 15 | 16 | 17 | --[[ 18 | counter 19 | 20 | This routine serves the purpose of generating signals 21 | based on the iteration of a series of numbers. 22 | 23 | The name of the signal is derived from the concatenation of 24 | the name parameter passed into the function, and the current 25 | numerical value of the iteration. 26 | 27 | During each iteration, a single task is signaled (with signalOne) 28 | and the counter yields, allowing that task to actually execute. 29 | 30 | At the end of the enumeration, all tasks that are waiting on the 'finished' 31 | event are signaled (with signalAll()). 32 | --]] 33 | local function counter(name, nCount) 34 | for num=1, nCount do 35 | local eventName = name..tostring(num); 36 | print(eventName) 37 | 38 | signalOne(eventName); 39 | yield(); 40 | end 41 | 42 | signalAll(name..'-finished') 43 | end 44 | 45 | -- A task which will wait for the count of 15 46 | -- and print a message 47 | function wait15() 48 | waitForSignal("counter15") 49 | print("reached 15!!") 50 | end 51 | 52 | -- A task which will wait for the count of 20 53 | -- and print a message. 54 | function wait20() 55 | waitForSignal("counter20") 56 | print("reached 20!!") 57 | end 58 | 59 | 60 | local function main() 61 | -- Spawn the task which will generate a steady stream of signals 62 | local t1 = spawn(counter, "counter", 25) 63 | 64 | -- spawn a couple of tasks which will respond to reaching 65 | -- specific counting events 66 | local t2 = spawn(wait20) 67 | local t3 = spawn(wait15) 68 | 69 | -- setup to call halt when counting is finished 70 | onSignal("counter-finished", halt) 71 | end 72 | 73 | run(main) 74 | -------------------------------------------------------------------------------- /testy/test_kernel_signal2.lua: -------------------------------------------------------------------------------- 1 | package.path = package.path.."';../?.lua" 2 | 3 | local kernel = require("schedlua.kernel") 4 | local alarm = require("schedlua.alarm")(kernel,true); 5 | 6 | local function waiter(num) 7 | num = num or 0 8 | 9 | local function closure() 10 | print(string.format("WAITED: %d", num)) 11 | end 12 | 13 | return closure; 14 | end 15 | 16 | local function main() 17 | for i=1,4 do 18 | onSignal(waiting, waiter(i)) 19 | end 20 | 21 | -- sleep a bit giving waiter a chance to register 22 | -- for their signals 23 | sleep(500); 24 | 25 | print("4 waiters spawned"); 26 | print("signalOne, result: ", signalOne("waiting")); 27 | print("After signalOne"); 28 | sleep(2000) 29 | 30 | signalAll("waiting") 31 | sleep(2000); 32 | 33 | print("SLEEP AFTER signalAll") 34 | 35 | halt(); 36 | end 37 | 38 | run(main) 39 | 40 | -------------------------------------------------------------------------------- /testy/test_linux_net.lua: -------------------------------------------------------------------------------- 1 | package.path = package.path.."';../?.lua" 2 | --test_linux_net.lua 3 | --[[ 4 | Simple networking test case. 5 | Implement a client to the daytime service (port 13) 6 | Make a basic TCP connection, read data, finish 7 | --]] 8 | local ffi = require("ffi") 9 | local bit = require("bit") 10 | local band, bor, lshift, rshift = bit.band, bit.bor, bit.lshift, bit.rshift 11 | 12 | local net = require("schedlua.linux_net"){exportglobal=true} 13 | 14 | 15 | local server_address = "127.0.0.1" 16 | local server_port = 13; 17 | 18 | 19 | local function main() 20 | local s = net.bsdsocket(SOCK_STREAM); 21 | 22 | local sa, err = net.sockaddr_in(server_address, server_port); 23 | local success, err = net.connect(s, sa) 24 | if not success then 25 | print("connect, error", err); 26 | return false, err; 27 | end 28 | 29 | 30 | local BUFSIZ = 512; 31 | local buffer = ffi.new("char[512+1]"); 32 | local bytesRead 33 | 34 | repeat 35 | bytesRead, err = s:read(buffer, BUFSIZ); 36 | if not bytesRead then 37 | print("read, error: ", err) 38 | return false, err; 39 | end 40 | 41 | local str = ffi.string(buffer, bytesRead); 42 | io.write(str); 43 | until bytesRead < 1 44 | end 45 | 46 | main() 47 | -------------------------------------------------------------------------------- /testy/test_predicate_wait.lua: -------------------------------------------------------------------------------- 1 | --test_scheduler.lua 2 | package.path = package.path..";../?.lua" 3 | 4 | --[[ 5 | In this we are testing the simple predicate waiting mechanism 6 | The spawn method is used to create a couple of tasks which will 7 | in turn use 'waitForTruth' to suspend themselves until 8 | the predicate returns a 'true' value. Then they print their message. 9 | --]] 10 | 11 | local Kernel = require("schedlua.kernel") 12 | 13 | 14 | local idx = 0; 15 | local maxidx = 25; 16 | 17 | 18 | local function counter(name, nCount) 19 | for num=1, nCount do 20 | idx = num 21 | local eventName = name..tostring(idx); 22 | print(eventName, idx) 23 | signalOne(eventName); 24 | 25 | yield(); 26 | end 27 | 28 | signalAll(name..'-finished') 29 | end 30 | 31 | 32 | local function predCount(num) 33 | waitForTruth(function() return idx == num end) 34 | print(string.format("PASSED: %d!!", num)) 35 | end 36 | 37 | 38 | local function main() 39 | local t1 = spawn(counter, "counter", maxidx) 40 | 41 | local t2 = spawn(predCount, 12) 42 | local t4 = spawn(predCount, 20) 43 | 44 | 45 | -- setup to call halt when counting is finished 46 | onSignal("counter-finished", halt) 47 | end 48 | 49 | run(main) 50 | -------------------------------------------------------------------------------- /testy/test_predicate_when.lua: -------------------------------------------------------------------------------- 1 | --test_scheduler.lua 2 | package.path = package.path..";../?.lua" 3 | 4 | local Kernel = require("schedlua.kernel") 5 | 6 | local idx = 0; 7 | local maxidx = 20; 8 | 9 | 10 | local function counter(name, nCount) 11 | for num=1, nCount do 12 | idx = num 13 | local eventName = name..tostring(idx); 14 | print(eventName, idx) 15 | 16 | yield(); 17 | end 18 | end 19 | 20 | 21 | 22 | local function countingFinished() 23 | return idx >= maxidx; 24 | end 25 | 26 | local function main() 27 | local t1 = spawn(counter, "counter", maxidx) 28 | 29 | when(countingFinished, halt) 30 | end 31 | 32 | run(main) 33 | -------------------------------------------------------------------------------- /testy/test_predicate_whenever.lua: -------------------------------------------------------------------------------- 1 | --test_scheduler.lua 2 | package.path = package.path..";../?.lua" 3 | 4 | local Kernel = require("schedlua.kernel") 5 | 6 | local idx = 0; 7 | local maxidx = 20; 8 | 9 | 10 | local function counter(name, nCount) 11 | for num=1, nCount do 12 | idx = num 13 | local eventName = name..tostring(idx); 14 | print(eventName, idx) 15 | signalOne(eventName); 16 | 17 | yield(); 18 | end 19 | 20 | signalAll(name..'-finished') 21 | end 22 | 23 | 24 | 25 | local function every5() 26 | local lastidx = 0; 27 | 28 | while idx <= maxidx do 29 | waitForPredicate(function() return (idx % 5) == 0 end) 30 | if idx > lastidx then 31 | print("!! matched 5 !!") 32 | lastidx = idx; 33 | --yield(); 34 | end 35 | end 36 | end 37 | 38 | local function test_whenever(modulus) 39 | local lastidx = 0; 40 | 41 | local function modulustest() 42 | --print("modulustest: ", idx, lastidx, maxidx) 43 | if idx > maxidx then 44 | return false; 45 | end 46 | 47 | if idx > lastidx then 48 | lastidx = idx; 49 | return (idx % modulus) == 0 50 | end 51 | end 52 | 53 | local t1 = whenever(modulustest, function() print("== EVERY: ", modulus) end) 54 | 55 | return t1; 56 | end 57 | 58 | local function main() 59 | local t1 = spawn(counter, "counter", maxidx) 60 | 61 | test_whenever(2); 62 | test_whenever(5); 63 | 64 | 65 | -- setup to call halt when counting is finished 66 | onSignal("counter-finished", halt) 67 | end 68 | 69 | run(main) 70 | -------------------------------------------------------------------------------- /testy/test_queue.lua: -------------------------------------------------------------------------------- 1 | package.path = "../?.lua;"..package.path 2 | 3 | local queue = require("schedlua.queue") 4 | local tutils = require("schedlua.tabutils") 5 | 6 | local q1 = queue(); 7 | 8 | --print("Q Length (0): ", q1:length()) 9 | 10 | 11 | local t1 = {Priority = 20, name = "1"} 12 | local t2 = {Priority = 50, name = "2"} 13 | local t3 = {Priority = 30, name = "3"} 14 | local t4 = {Priority = 10, name = "4"} 15 | local t5 = {Priority = 10, name = "5"} 16 | local t6 = {Priority = 10, name = "6"} 17 | 18 | local function priority_comp( a,b ) 19 | return a.Priority < b.Priority 20 | end 21 | 22 | q1:pinsert(t1, priority_comp); 23 | q1:pinsert(t2, priority_comp); 24 | q1:pinsert(t3, priority_comp); 25 | q1:pinsert(t4, priority_comp); 26 | q1:pinsert(t5, priority_comp); 27 | q1:pinsert(t6, priority_comp); 28 | 29 | 30 | print("Q Length : ", q1.first, q1.last, q1:length()) 31 | 32 | 33 | for entry in q1:Entries() do 34 | print("Entry: ", entry.Priority, entry.name) 35 | end -------------------------------------------------------------------------------- /testy/test_scheduler.lua: -------------------------------------------------------------------------------- 1 | --test_scheduler.lua 2 | package.path = package.path..";../?.lua" 3 | 4 | Scheduler = require("schedlua.scheduler")() 5 | Task = require("schedlua.task") 6 | local taskID = 0; 7 | 8 | local function getNewTaskID() 9 | taskID = taskID + 1; 10 | return taskID; 11 | end 12 | 13 | local function spawn(scheduler, func, ...) 14 | local task = Task(func, ...) 15 | task.TaskID = getNewTaskID(); 16 | Scheduler:scheduleTask(task, {...}); 17 | 18 | return task; 19 | end 20 | 21 | 22 | local function task1() 23 | print("first task, first line") 24 | Scheduler:yield(); 25 | print("first task, second line") 26 | end 27 | 28 | local function task2() 29 | print("second task, only line") 30 | end 31 | 32 | local function main() 33 | local t1 = spawn(Scheduler, task1) 34 | local t2 = spawn(Scheduler, task2) 35 | 36 | while (true) do 37 | --print("STATUS: ", t1:getStatus(), t2:getStatus()) 38 | if t1:getStatus() == "dead" and t2:getStatus() == "dead" then 39 | break; 40 | end 41 | Scheduler:step() 42 | end 43 | end 44 | 45 | main() 46 | 47 | 48 | -------------------------------------------------------------------------------- /testy/test_stopwatch.lua: -------------------------------------------------------------------------------- 1 | -- test_timeticker.lua 2 | package.path = package.path..";../?.lua" 3 | 4 | local stopwatch = require("schedlua.stopwatch") 5 | local sw = stopwatch(); 6 | 7 | print("Current Tick: ", sw:seconds()) 8 | 9 | 10 | for i = 1,500 do 11 | print("i: ", i) 12 | end 13 | 14 | print("Ellapsed: ", sw:seconds()) 15 | --------------------------------------------------------------------------------