diff options
45 files changed, 4372 insertions, 0 deletions
diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..3bb3efa --- /dev/null +++ b/.travis.yml | |||
@@ -0,0 +1,67 @@ | |||
1 | # | ||
2 | # LuaDist Travis-CI Hook | ||
3 | # | ||
4 | |||
5 | # We assume C build environments | ||
6 | language: C | ||
7 | |||
8 | # Try using multiple Lua Implementations | ||
9 | env: | ||
10 | - TOOL="gcc" # Use native compiler (GCC usually) | ||
11 | - TOOL="clang" # Use clang | ||
12 | - TOOL="i686-w64-mingw32" # 32bit MinGW | ||
13 | - TOOL="x86_64-w64-mingw32" # 64bit MinGW | ||
14 | - TOOL="arm-linux-gnueabihf" # ARM hard-float (hf), linux | ||
15 | |||
16 | # Crosscompile builds may fail | ||
17 | matrix: | ||
18 | allow_failures: | ||
19 | - env: TOOL="i686-w64-mingw32" | ||
20 | - env: TOOL="x86_64-w64-mingw32" | ||
21 | - env: TOOL="arm-linux-gnueabihf" | ||
22 | |||
23 | # Install dependencies | ||
24 | install: | ||
25 | - git clone git://github.com/LuaDist/Tools.git ~/_tools | ||
26 | - ~/_tools/travis/travis install | ||
27 | |||
28 | # Bootstap | ||
29 | before_script: | ||
30 | - ~/_tools/travis/travis bootstrap | ||
31 | |||
32 | # Build the module | ||
33 | script: | ||
34 | # - ~/_tools/travis/travis build | ||
35 | - ~/luadist _test install lua-5.1.5 -binary=false -verbose -DCMAKE_TOOLCHAIN_FILE=$TOOLFILE | ||
36 | - ~/luadist _test make . -binary=false -verbose -DCMAKE_TOOLCHAIN_FILE=$TOOLFILE | ||
37 | - cd _test/share/lua-llthreads2/test | ||
38 | - $TRAVIS_BUILD_DIR/_test/bin/lua test_table_copy.lua | ||
39 | - $TRAVIS_BUILD_DIR/_test/bin/lua test_threads.lua | ||
40 | - $TRAVIS_BUILD_DIR/_test/bin/lua test_llthreads.lua | ||
41 | - $TRAVIS_BUILD_DIR/_test/bin/lua test_join_timeout.lua | ||
42 | - $TRAVIS_BUILD_DIR/_test/bin/lua test_join_detach.lua | ||
43 | - $TRAVIS_BUILD_DIR/_test/bin/lua test_join_error.lua | ||
44 | - $TRAVIS_BUILD_DIR/_test/bin/lua test_register_ffi.lua | ||
45 | - $TRAVIS_BUILD_DIR/_test/bin/lua test_logger.lua | ||
46 | - $TRAVIS_BUILD_DIR/_test/bin/lua test_pass_cfunction.lua | ||
47 | - $TRAVIS_BUILD_DIR/_test/bin/lua test_load_llthreads2.lua | ||
48 | - $TRAVIS_BUILD_DIR/_test/bin/lua test_alive.lua | ||
49 | |||
50 | |||
51 | # Execute additional tests or commands | ||
52 | after_script: | ||
53 | - cd $TRAVIS_BUILD_DIR | ||
54 | - ~/_tools/travis/travis test | ||
55 | |||
56 | # Only watch the master branch | ||
57 | branches: | ||
58 | only: | ||
59 | - dist-llthreads2 | ||
60 | |||
61 | # Notify the LuaDist Dev group if needed | ||
62 | notifications: | ||
63 | recipients: | ||
64 | - luadist-dev@googlegroups.com | ||
65 | email: | ||
66 | on_success: change | ||
67 | on_failure: always | ||
diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..596e496 --- /dev/null +++ b/CMakeLists.txt | |||
@@ -0,0 +1,17 @@ | |||
1 | cmake_minimum_required ( VERSION 2.8 ) | ||
2 | |||
3 | project ( lua-llthreads2 C ) | ||
4 | include ( cmake/dist.cmake ) | ||
5 | include ( lua ) | ||
6 | |||
7 | set ( CMAKE_THREAD_PREFER_PTHREAD TRUE ) | ||
8 | include ( FindThreads ) | ||
9 | |||
10 | include_directories ( ${CMAKE_CURRENT_SOURCE_DIR}/llthreads2/src ) | ||
11 | |||
12 | set ( LUA_LLTHREADS_SRC llthreads2/src/l52util.c llthreads2/src/llthread.c ) | ||
13 | |||
14 | install_lua_module ( llthreads2 ${LUA_LLTHREADS_SRC} LINK ${CMAKE_THREAD_LIBS_INIT} ) | ||
15 | |||
16 | install_data ( llthreads2/COPYRIGHT.llthreads llthreads2/README.md llthreads2/LICENSE ) | ||
17 | install_test ( llthreads2/test/ ) | ||
diff --git a/cmake/FindLua.cmake b/cmake/FindLua.cmake new file mode 100644 index 0000000..6991b4a --- /dev/null +++ b/cmake/FindLua.cmake | |||
@@ -0,0 +1,127 @@ | |||
1 | # Locate Lua library | ||
2 | # This module defines | ||
3 | # LUA_EXECUTABLE, if found | ||
4 | # LUA_FOUND, if false, do not try to link to Lua | ||
5 | # LUA_LIBRARIES | ||
6 | # LUA_INCLUDE_DIR, where to find lua.h | ||
7 | # LUA_VERSION_STRING, the version of Lua found (since CMake 2.8.8) | ||
8 | # | ||
9 | # Note that the expected include convention is | ||
10 | # #include "lua.h" | ||
11 | # and not | ||
12 | # #include <lua/lua.h> | ||
13 | # This is because, the lua location is not standardized and may exist | ||
14 | # in locations other than lua/ | ||
15 | |||
16 | #============================================================================= | ||
17 | # Copyright 2007-2009 Kitware, Inc. | ||
18 | # Modified to support Lua 5.2 by LuaDist 2012 | ||
19 | # | ||
20 | # Distributed under the OSI-approved BSD License (the "License"); | ||
21 | # see accompanying file Copyright.txt for details. | ||
22 | # | ||
23 | # This software is distributed WITHOUT ANY WARRANTY; without even the | ||
24 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
25 | # See the License for more information. | ||
26 | #============================================================================= | ||
27 | # (To distribute this file outside of CMake, substitute the full | ||
28 | # License text for the above reference.) | ||
29 | # | ||
30 | # The required version of Lua can be specified using the | ||
31 | # standard syntax, e.g. FIND_PACKAGE(Lua 5.1) | ||
32 | # Otherwise the module will search for any available Lua implementation | ||
33 | |||
34 | # Always search for non-versioned lua first (recommended) | ||
35 | SET(_POSSIBLE_LUA_INCLUDE include include/lua) | ||
36 | SET(_POSSIBLE_LUA_EXECUTABLE lua) | ||
37 | SET(_POSSIBLE_LUA_LIBRARY lua) | ||
38 | |||
39 | # Determine possible naming suffixes (there is no standard for this) | ||
40 | IF(Lua_FIND_VERSION_MAJOR AND Lua_FIND_VERSION_MINOR) | ||
41 | SET(_POSSIBLE_SUFFIXES "${Lua_FIND_VERSION_MAJOR}${Lua_FIND_VERSION_MINOR}" "${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR}" "-${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR}") | ||
42 | ELSE(Lua_FIND_VERSION_MAJOR AND Lua_FIND_VERSION_MINOR) | ||
43 | SET(_POSSIBLE_SUFFIXES "52" "5.2" "-5.2" "51" "5.1" "-5.1") | ||
44 | ENDIF(Lua_FIND_VERSION_MAJOR AND Lua_FIND_VERSION_MINOR) | ||
45 | |||
46 | # Set up possible search names and locations | ||
47 | FOREACH(_SUFFIX ${_POSSIBLE_SUFFIXES}) | ||
48 | LIST(APPEND _POSSIBLE_LUA_INCLUDE "include/lua${_SUFFIX}") | ||
49 | LIST(APPEND _POSSIBLE_LUA_EXECUTABLE "lua${_SUFFIX}") | ||
50 | LIST(APPEND _POSSIBLE_LUA_LIBRARY "lua${_SUFFIX}") | ||
51 | ENDFOREACH(_SUFFIX) | ||
52 | |||
53 | # Find the lua executable | ||
54 | FIND_PROGRAM(LUA_EXECUTABLE | ||
55 | NAMES ${_POSSIBLE_LUA_EXECUTABLE} | ||
56 | ) | ||
57 | |||
58 | # Find the lua header | ||
59 | FIND_PATH(LUA_INCLUDE_DIR lua.h | ||
60 | HINTS | ||
61 | $ENV{LUA_DIR} | ||
62 | PATH_SUFFIXES ${_POSSIBLE_LUA_INCLUDE} | ||
63 | PATHS | ||
64 | ~/Library/Frameworks | ||
65 | /Library/Frameworks | ||
66 | /usr/local | ||
67 | /usr | ||
68 | /sw # Fink | ||
69 | /opt/local # DarwinPorts | ||
70 | /opt/csw # Blastwave | ||
71 | /opt | ||
72 | ) | ||
73 | |||
74 | # Find the lua library | ||
75 | FIND_LIBRARY(LUA_LIBRARY | ||
76 | NAMES ${_POSSIBLE_LUA_LIBRARY} | ||
77 | HINTS | ||
78 | $ENV{LUA_DIR} | ||
79 | PATH_SUFFIXES lib64 lib | ||
80 | PATHS | ||
81 | ~/Library/Frameworks | ||
82 | /Library/Frameworks | ||
83 | /usr/local | ||
84 | /usr | ||
85 | /sw | ||
86 | /opt/local | ||
87 | /opt/csw | ||
88 | /opt | ||
89 | ) | ||
90 | |||
91 | IF(LUA_LIBRARY) | ||
92 | # include the math library for Unix | ||
93 | IF(UNIX AND NOT APPLE) | ||
94 | FIND_LIBRARY(LUA_MATH_LIBRARY m) | ||
95 | SET( LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}" CACHE STRING "Lua Libraries") | ||
96 | # For Windows and Mac, don't need to explicitly include the math library | ||
97 | ELSE(UNIX AND NOT APPLE) | ||
98 | SET( LUA_LIBRARIES "${LUA_LIBRARY}" CACHE STRING "Lua Libraries") | ||
99 | ENDIF(UNIX AND NOT APPLE) | ||
100 | ENDIF(LUA_LIBRARY) | ||
101 | |||
102 | # Determine Lua version | ||
103 | IF(LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/lua.h") | ||
104 | FILE(STRINGS "${LUA_INCLUDE_DIR}/lua.h" lua_version_str REGEX "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua .+\"") | ||
105 | |||
106 | STRING(REGEX REPLACE "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([^\"]+)\".*" "\\1" LUA_VERSION_STRING "${lua_version_str}") | ||
107 | UNSET(lua_version_str) | ||
108 | ENDIF() | ||
109 | |||
110 | # Lua 5.2 | ||
111 | IF(NOT LUA_VERSION_STRING) | ||
112 | FILE(STRINGS "${LUA_INCLUDE_DIR}/lua.h" lua_version_str REGEX "^#define LUA_VERSION_[A-Z]+[ \t]+\"[0-9]+\"") | ||
113 | STRING(REGEX REPLACE ".*#define LUA_VERSION_MAJOR[ \t]+\"([0-9]+)\".*" "\\1" LUA_VERSION_MAJOR ${lua_version_str}) | ||
114 | STRING(REGEX REPLACE ".*#define LUA_VERSION_MINOR[ \t]+\"([0-9]+)\".*" "\\1" LUA_VERSION_MINOR ${lua_version_str}) | ||
115 | STRING(REGEX REPLACE ".*#define LUA_VERSION_RELEASE[ \t]+\"([0-9]+)\".*" "\\1" LUA_VERSION_RELEASE ${lua_version_str}) | ||
116 | SET(LUA_VERSION_STRING ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}.${LUA_VERSION_RELEASE}) | ||
117 | ENDIF() | ||
118 | |||
119 | INCLUDE(FindPackageHandleStandardArgs) | ||
120 | # handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if | ||
121 | # all listed variables are TRUE | ||
122 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua | ||
123 | REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR | ||
124 | VERSION_VAR LUA_VERSION_STRING) | ||
125 | |||
126 | MARK_AS_ADVANCED(LUA_INCLUDE_DIR LUA_LIBRARIES LUA_LIBRARY LUA_MATH_LIBRARY LUA_EXECUTABLE) | ||
127 | |||
diff --git a/cmake/dist.cmake b/cmake/dist.cmake new file mode 100644 index 0000000..310ef94 --- /dev/null +++ b/cmake/dist.cmake | |||
@@ -0,0 +1,321 @@ | |||
1 | # LuaDist CMake utility library. | ||
2 | # Provides sane project defaults and macros common to LuaDist CMake builds. | ||
3 | # | ||
4 | # Copyright (C) 2007-2012 LuaDist. | ||
5 | # by David Manura, Peter Drahoš | ||
6 | # Redistribution and use of this file is allowed according to the terms of the MIT license. | ||
7 | # For details see the COPYRIGHT file distributed with LuaDist. | ||
8 | # Please note that the package source code is licensed under its own license. | ||
9 | |||
10 | ## Extract information from dist.info | ||
11 | if ( NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/dist.info ) | ||
12 | message ( FATAL_ERROR | ||
13 | "Missing dist.info file (${CMAKE_CURRENT_SOURCE_DIR}/dist.info)." ) | ||
14 | endif () | ||
15 | file ( READ ${CMAKE_CURRENT_SOURCE_DIR}/dist.info DIST_INFO ) | ||
16 | if ( "${DIST_INFO}" STREQUAL "" ) | ||
17 | message ( FATAL_ERROR "Failed to load dist.info." ) | ||
18 | endif () | ||
19 | # Reads field `name` from dist.info string `DIST_INFO` into variable `var`. | ||
20 | macro ( _parse_dist_field name var ) | ||
21 | string ( REGEX REPLACE ".*${name}[ \t]?=[ \t]?[\"']([^\"']+)[\"'].*" "\\1" | ||
22 | ${var} "${DIST_INFO}" ) | ||
23 | if ( ${var} STREQUAL DIST_INFO ) | ||
24 | message ( FATAL_ERROR "Failed to extract \"${var}\" from dist.info" ) | ||
25 | endif () | ||
26 | endmacro () | ||
27 | # | ||
28 | _parse_dist_field ( name DIST_NAME ) | ||
29 | _parse_dist_field ( version DIST_VERSION ) | ||
30 | _parse_dist_field ( license DIST_LICENSE ) | ||
31 | _parse_dist_field ( author DIST_AUTHOR ) | ||
32 | _parse_dist_field ( maintainer DIST_MAINTAINER ) | ||
33 | _parse_dist_field ( url DIST_URL ) | ||
34 | _parse_dist_field ( desc DIST_DESC ) | ||
35 | message ( "DIST_NAME: ${DIST_NAME}") | ||
36 | message ( "DIST_VERSION: ${DIST_VERSION}") | ||
37 | message ( "DIST_LICENSE: ${DIST_LICENSE}") | ||
38 | message ( "DIST_AUTHOR: ${DIST_AUTHOR}") | ||
39 | message ( "DIST_MAINTAINER: ${DIST_MAINTAINER}") | ||
40 | message ( "DIST_URL: ${DIST_URL}") | ||
41 | message ( "DIST_DESC: ${DIST_DESC}") | ||
42 | string ( REGEX REPLACE ".*depends[ \t]?=[ \t]?[\"']([^\"']+)[\"'].*" "\\1" | ||
43 | DIST_DEPENDS ${DIST_INFO} ) | ||
44 | if ( DIST_DEPENDS STREQUAL DIST_INFO ) | ||
45 | set ( DIST_DEPENDS "" ) | ||
46 | endif () | ||
47 | message ( "DIST_DEPENDS: ${DIST_DEPENDS}") | ||
48 | ## 2DO: Parse DIST_DEPENDS and try to install Dependencies with automatically using externalproject_add | ||
49 | |||
50 | |||
51 | ## INSTALL DEFAULTS (Relative to CMAKE_INSTALL_PREFIX) | ||
52 | # Primary paths | ||
53 | set ( INSTALL_BIN bin CACHE PATH "Where to install binaries to." ) | ||
54 | set ( INSTALL_LIB lib CACHE PATH "Where to install libraries to." ) | ||
55 | set ( INSTALL_INC include CACHE PATH "Where to install headers to." ) | ||
56 | set ( INSTALL_ETC etc CACHE PATH "Where to store configuration files" ) | ||
57 | set ( INSTALL_SHARE share CACHE PATH "Directory for shared data." ) | ||
58 | |||
59 | # Secondary paths | ||
60 | option ( INSTALL_VERSION | ||
61 | "Install runtime libraries and executables with version information." OFF) | ||
62 | set ( INSTALL_DATA ${INSTALL_SHARE}/${DIST_NAME} CACHE PATH | ||
63 | "Directory the package can store documentation, tests or other data in.") | ||
64 | set ( INSTALL_DOC ${INSTALL_DATA}/doc CACHE PATH | ||
65 | "Recommended directory to install documentation into.") | ||
66 | set ( INSTALL_EXAMPLE ${INSTALL_DATA}/example CACHE PATH | ||
67 | "Recommended directory to install examples into.") | ||
68 | set ( INSTALL_TEST ${INSTALL_DATA}/test CACHE PATH | ||
69 | "Recommended directory to install tests into.") | ||
70 | set ( INSTALL_FOO ${INSTALL_DATA}/etc CACHE PATH | ||
71 | "Where to install additional files") | ||
72 | |||
73 | # Tweaks and other defaults | ||
74 | # Setting CMAKE to use loose block and search for find modules in source directory | ||
75 | set ( CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true ) | ||
76 | set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH} ) | ||
77 | option ( BUILD_SHARED_LIBS "Build shared libraries" ON ) | ||
78 | |||
79 | # In MSVC, prevent warnings that can occur when using standard libraries. | ||
80 | if ( MSVC ) | ||
81 | add_definitions ( -D_CRT_SECURE_NO_WARNINGS ) | ||
82 | endif () | ||
83 | |||
84 | # RPath and relative linking | ||
85 | option ( USE_RPATH "Use relative linking." ON) | ||
86 | if ( USE_RPATH ) | ||
87 | string ( REGEX REPLACE "[^!/]+" ".." UP_DIR ${INSTALL_BIN} ) | ||
88 | set ( CMAKE_SKIP_BUILD_RPATH FALSE CACHE STRING "" FORCE ) | ||
89 | set ( CMAKE_BUILD_WITH_INSTALL_RPATH FALSE CACHE STRING "" FORCE ) | ||
90 | set ( CMAKE_INSTALL_RPATH $ORIGIN/${UP_DIR}/${INSTALL_LIB} | ||
91 | CACHE STRING "" FORCE ) | ||
92 | set ( CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE CACHE STRING "" FORCE ) | ||
93 | set ( CMAKE_INSTALL_NAME_DIR @executable_path/${UP_DIR}/${INSTALL_LIB} | ||
94 | CACHE STRING "" FORCE ) | ||
95 | endif () | ||
96 | |||
97 | ## MACROS | ||
98 | # Parser macro | ||
99 | macro ( parse_arguments prefix arg_names option_names) | ||
100 | set ( DEFAULT_ARGS ) | ||
101 | foreach ( arg_name ${arg_names} ) | ||
102 | set ( ${prefix}_${arg_name} ) | ||
103 | endforeach () | ||
104 | foreach ( option ${option_names} ) | ||
105 | set ( ${prefix}_${option} FALSE ) | ||
106 | endforeach () | ||
107 | |||
108 | set ( current_arg_name DEFAULT_ARGS ) | ||
109 | set ( current_arg_list ) | ||
110 | foreach ( arg ${ARGN} ) | ||
111 | set ( larg_names ${arg_names} ) | ||
112 | list ( FIND larg_names "${arg}" is_arg_name ) | ||
113 | if ( is_arg_name GREATER -1 ) | ||
114 | set ( ${prefix}_${current_arg_name} ${current_arg_list} ) | ||
115 | set ( current_arg_name ${arg} ) | ||
116 | set ( current_arg_list ) | ||
117 | else () | ||
118 | set ( loption_names ${option_names} ) | ||
119 | list ( FIND loption_names "${arg}" is_option ) | ||
120 | if ( is_option GREATER -1 ) | ||
121 | set ( ${prefix}_${arg} TRUE ) | ||
122 | else () | ||
123 | set ( current_arg_list ${current_arg_list} ${arg} ) | ||
124 | endif () | ||
125 | endif () | ||
126 | endforeach () | ||
127 | set ( ${prefix}_${current_arg_name} ${current_arg_list} ) | ||
128 | endmacro () | ||
129 | |||
130 | |||
131 | # install_executable ( executable_targets ) | ||
132 | # Installs any executables generated using "add_executable". | ||
133 | # USE: install_executable ( lua ) | ||
134 | # NOTE: subdirectories are NOT supported | ||
135 | set ( CPACK_COMPONENT_RUNTIME_DISPLAY_NAME "${DIST_NAME} Runtime" ) | ||
136 | set ( CPACK_COMPONENT_RUNTIME_DESCRIPTION | ||
137 | "Executables and runtime libraries. Installed into ${INSTALL_BIN}." ) | ||
138 | macro ( install_executable ) | ||
139 | foreach ( _file ${ARGN} ) | ||
140 | if ( INSTALL_VERSION ) | ||
141 | set_target_properties ( ${_file} PROPERTIES VERSION ${DIST_VERSION} | ||
142 | SOVERSION ${DIST_VERSION} ) | ||
143 | endif () | ||
144 | install ( TARGETS ${_file} RUNTIME DESTINATION ${INSTALL_BIN} | ||
145 | COMPONENT Runtime ) | ||
146 | endforeach() | ||
147 | endmacro () | ||
148 | |||
149 | # install_library ( library_targets ) | ||
150 | # Installs any libraries generated using "add_library" into apropriate places. | ||
151 | # USE: install_library ( libexpat ) | ||
152 | # NOTE: subdirectories are NOT supported | ||
153 | set ( CPACK_COMPONENT_LIBRARY_DISPLAY_NAME "${DIST_NAME} Development Libraries" ) | ||
154 | set ( CPACK_COMPONENT_LIBRARY_DESCRIPTION | ||
155 | "Static and import libraries needed for development. Installed into ${INSTALL_LIB} or ${INSTALL_BIN}." ) | ||
156 | macro ( install_library ) | ||
157 | foreach ( _file ${ARGN} ) | ||
158 | if ( INSTALL_VERSION ) | ||
159 | set_target_properties ( ${_file} PROPERTIES VERSION ${DIST_VERSION} | ||
160 | SOVERSION ${DIST_VERSION} ) | ||
161 | endif () | ||
162 | install ( TARGETS ${_file} | ||
163 | RUNTIME DESTINATION ${INSTALL_BIN} COMPONENT Runtime | ||
164 | LIBRARY DESTINATION ${INSTALL_LIB} COMPONENT Runtime | ||
165 | ARCHIVE DESTINATION ${INSTALL_LIB} COMPONENT Library ) | ||
166 | endforeach() | ||
167 | endmacro () | ||
168 | |||
169 | # helper function for various install_* functions, for PATTERN/REGEX args. | ||
170 | macro ( _complete_install_args ) | ||
171 | if ( NOT("${_ARG_PATTERN}" STREQUAL "") ) | ||
172 | set ( _ARG_PATTERN PATTERN ${_ARG_PATTERN} ) | ||
173 | endif () | ||
174 | if ( NOT("${_ARG_REGEX}" STREQUAL "") ) | ||
175 | set ( _ARG_REGEX REGEX ${_ARG_REGEX} ) | ||
176 | endif () | ||
177 | endmacro () | ||
178 | |||
179 | # install_header ( files/directories [INTO destination] ) | ||
180 | # Install a directories or files into header destination. | ||
181 | # USE: install_header ( lua.h luaconf.h ) or install_header ( GL ) | ||
182 | # USE: install_header ( mylib.h INTO mylib ) | ||
183 | # For directories, supports optional PATTERN/REGEX arguments like install(). | ||
184 | set ( CPACK_COMPONENT_HEADER_DISPLAY_NAME "${DIST_NAME} Development Headers" ) | ||
185 | set ( CPACK_COMPONENT_HEADER_DESCRIPTION | ||
186 | "Headers needed for development. Installed into ${INSTALL_INC}." ) | ||
187 | macro ( install_header ) | ||
188 | parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} ) | ||
189 | _complete_install_args() | ||
190 | foreach ( _file ${_ARG_DEFAULT_ARGS} ) | ||
191 | if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" ) | ||
192 | install ( DIRECTORY ${_file} DESTINATION ${INSTALL_INC}/${_ARG_INTO} | ||
193 | COMPONENT Header ${_ARG_PATTERN} ${_ARG_REGEX} ) | ||
194 | else () | ||
195 | install ( FILES ${_file} DESTINATION ${INSTALL_INC}/${_ARG_INTO} | ||
196 | COMPONENT Header ) | ||
197 | endif () | ||
198 | endforeach() | ||
199 | endmacro () | ||
200 | |||
201 | # install_data ( files/directories [INTO destination] ) | ||
202 | # This installs additional data files or directories. | ||
203 | # USE: install_data ( extra data.dat ) | ||
204 | # USE: install_data ( image1.png image2.png INTO images ) | ||
205 | # For directories, supports optional PATTERN/REGEX arguments like install(). | ||
206 | set ( CPACK_COMPONENT_DATA_DISPLAY_NAME "${DIST_NAME} Data" ) | ||
207 | set ( CPACK_COMPONENT_DATA_DESCRIPTION | ||
208 | "Application data. Installed into ${INSTALL_DATA}." ) | ||
209 | macro ( install_data ) | ||
210 | parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} ) | ||
211 | _complete_install_args() | ||
212 | foreach ( _file ${_ARG_DEFAULT_ARGS} ) | ||
213 | if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" ) | ||
214 | install ( DIRECTORY ${_file} | ||
215 | DESTINATION ${INSTALL_DATA}/${_ARG_INTO} | ||
216 | COMPONENT Data ${_ARG_PATTERN} ${_ARG_REGEX} ) | ||
217 | else () | ||
218 | install ( FILES ${_file} DESTINATION ${INSTALL_DATA}/${_ARG_INTO} | ||
219 | COMPONENT Data ) | ||
220 | endif () | ||
221 | endforeach() | ||
222 | endmacro () | ||
223 | |||
224 | # INSTALL_DOC ( files/directories [INTO destination] ) | ||
225 | # This installs documentation content | ||
226 | # USE: install_doc ( doc/ doc.pdf ) | ||
227 | # USE: install_doc ( index.html INTO html ) | ||
228 | # For directories, supports optional PATTERN/REGEX arguments like install(). | ||
229 | set ( CPACK_COMPONENT_DOCUMENTATION_DISPLAY_NAME "${DIST_NAME} Documentation" ) | ||
230 | set ( CPACK_COMPONENT_DOCUMENTATION_DESCRIPTION | ||
231 | "Application documentation. Installed into ${INSTALL_DOC}." ) | ||
232 | macro ( install_doc ) | ||
233 | parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} ) | ||
234 | _complete_install_args() | ||
235 | foreach ( _file ${_ARG_DEFAULT_ARGS} ) | ||
236 | if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" ) | ||
237 | install ( DIRECTORY ${_file} DESTINATION ${INSTALL_DOC}/${_ARG_INTO} | ||
238 | COMPONENT Documentation ${_ARG_PATTERN} ${_ARG_REGEX} ) | ||
239 | else () | ||
240 | install ( FILES ${_file} DESTINATION ${INSTALL_DOC}/${_ARG_INTO} | ||
241 | COMPONENT Documentation ) | ||
242 | endif () | ||
243 | endforeach() | ||
244 | endmacro () | ||
245 | |||
246 | # install_example ( files/directories [INTO destination] ) | ||
247 | # This installs additional examples | ||
248 | # USE: install_example ( examples/ exampleA ) | ||
249 | # USE: install_example ( super_example super_data INTO super) | ||
250 | # For directories, supports optional PATTERN/REGEX argument like install(). | ||
251 | set ( CPACK_COMPONENT_EXAMPLE_DISPLAY_NAME "${DIST_NAME} Examples" ) | ||
252 | set ( CPACK_COMPONENT_EXAMPLE_DESCRIPTION | ||
253 | "Examples and their associated data. Installed into ${INSTALL_EXAMPLE}." ) | ||
254 | macro ( install_example ) | ||
255 | parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} ) | ||
256 | _complete_install_args() | ||
257 | foreach ( _file ${_ARG_DEFAULT_ARGS} ) | ||
258 | if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" ) | ||
259 | install ( DIRECTORY ${_file} DESTINATION ${INSTALL_EXAMPLE}/${_ARG_INTO} | ||
260 | COMPONENT Example ${_ARG_PATTERN} ${_ARG_REGEX} ) | ||
261 | else () | ||
262 | install ( FILES ${_file} DESTINATION ${INSTALL_EXAMPLE}/${_ARG_INTO} | ||
263 | COMPONENT Example ) | ||
264 | endif () | ||
265 | endforeach() | ||
266 | endmacro () | ||
267 | |||
268 | # install_test ( files/directories [INTO destination] ) | ||
269 | # This installs tests and test files, DOES NOT EXECUTE TESTS | ||
270 | # USE: install_test ( my_test data.sql ) | ||
271 | # USE: install_test ( feature_x_test INTO x ) | ||
272 | # For directories, supports optional PATTERN/REGEX argument like install(). | ||
273 | set ( CPACK_COMPONENT_TEST_DISPLAY_NAME "${DIST_NAME} Tests" ) | ||
274 | set ( CPACK_COMPONENT_TEST_DESCRIPTION | ||
275 | "Tests and associated data. Installed into ${INSTALL_TEST}." ) | ||
276 | macro ( install_test ) | ||
277 | parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} ) | ||
278 | _complete_install_args() | ||
279 | foreach ( _file ${_ARG_DEFAULT_ARGS} ) | ||
280 | if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" ) | ||
281 | install ( DIRECTORY ${_file} DESTINATION ${INSTALL_TEST}/${_ARG_INTO} | ||
282 | COMPONENT Test ${_ARG_PATTERN} ${_ARG_REGEX} ) | ||
283 | else () | ||
284 | install ( FILES ${_file} DESTINATION ${INSTALL_TEST}/${_ARG_INTO} | ||
285 | COMPONENT Test ) | ||
286 | endif () | ||
287 | endforeach() | ||
288 | endmacro () | ||
289 | |||
290 | # install_foo ( files/directories [INTO destination] ) | ||
291 | # This installs optional or otherwise unneeded content | ||
292 | # USE: install_foo ( etc/ example.doc ) | ||
293 | # USE: install_foo ( icon.png logo.png INTO icons) | ||
294 | # For directories, supports optional PATTERN/REGEX argument like install(). | ||
295 | set ( CPACK_COMPONENT_OTHER_DISPLAY_NAME "${DIST_NAME} Unspecified Content" ) | ||
296 | set ( CPACK_COMPONENT_OTHER_DESCRIPTION | ||
297 | "Other unspecified content. Installed into ${INSTALL_FOO}." ) | ||
298 | macro ( install_foo ) | ||
299 | parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} ) | ||
300 | _complete_install_args() | ||
301 | foreach ( _file ${_ARG_DEFAULT_ARGS} ) | ||
302 | if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" ) | ||
303 | install ( DIRECTORY ${_file} DESTINATION ${INSTALL_FOO}/${_ARG_INTO} | ||
304 | COMPONENT Other ${_ARG_PATTERN} ${_ARG_REGEX} ) | ||
305 | else () | ||
306 | install ( FILES ${_file} DESTINATION ${INSTALL_FOO}/${_ARG_INTO} | ||
307 | COMPONENT Other ) | ||
308 | endif () | ||
309 | endforeach() | ||
310 | endmacro () | ||
311 | |||
312 | ## CTest defaults | ||
313 | |||
314 | ## CPack defaults | ||
315 | set ( CPACK_GENERATOR "ZIP" ) | ||
316 | set ( CPACK_STRIP_FILES TRUE ) | ||
317 | set ( CPACK_PACKAGE_NAME "${DIST_NAME}" ) | ||
318 | set ( CPACK_PACKAGE_VERSION "${DIST_VERSION}") | ||
319 | set ( CPACK_PACKAGE_VENDOR "LuaDist" ) | ||
320 | set ( CPACK_COMPONENTS_ALL Runtime Library Header Data Documentation Example Other ) | ||
321 | include ( CPack ) | ||
diff --git a/cmake/lua.cmake b/cmake/lua.cmake new file mode 100644 index 0000000..ee2e35d --- /dev/null +++ b/cmake/lua.cmake | |||
@@ -0,0 +1,309 @@ | |||
1 | # LuaDist CMake utility library for Lua. | ||
2 | # | ||
3 | # Copyright (C) 2007-2012 LuaDist. | ||
4 | # by David Manura, Peter Drahos | ||
5 | # Redistribution and use of this file is allowed according to the terms of the MIT license. | ||
6 | # For details see the COPYRIGHT file distributed with LuaDist. | ||
7 | # Please note that the package source code is licensed under its own license. | ||
8 | |||
9 | set ( INSTALL_LMOD ${INSTALL_LIB}/lua | ||
10 | CACHE PATH "Directory to install Lua modules." ) | ||
11 | set ( INSTALL_CMOD ${INSTALL_LIB}/lua | ||
12 | CACHE PATH "Directory to install Lua binary modules." ) | ||
13 | |||
14 | option ( LUA_SKIP_WRAPPER | ||
15 | "Do not build and install Lua executable wrappers." OFF ) | ||
16 | option ( LUA_STATIC_MODULE "Build modules for static linking" OFF ) | ||
17 | |||
18 | # List of (Lua module name, file path) pairs. | ||
19 | # Used internally by add_lua_test. Built by add_lua_module. | ||
20 | set ( _lua_modules ) | ||
21 | |||
22 | # utility function: appends path `path` to path `basepath`, properly | ||
23 | # handling cases when `path` may be relative or absolute. | ||
24 | macro ( _append_path basepath path result ) | ||
25 | if ( IS_ABSOLUTE "${path}" ) | ||
26 | set ( ${result} "${path}" ) | ||
27 | else () | ||
28 | set ( ${result} "${basepath}/${path}" ) | ||
29 | endif () | ||
30 | endmacro () | ||
31 | |||
32 | # install_lua_executable ( target source ) | ||
33 | # Automatically generate a binary if srlua package is available | ||
34 | # The application or its source will be placed into /bin | ||
35 | # If the application source did not have .lua suffix then it will be added | ||
36 | # USE: lua_executable ( sputnik src/sputnik.lua ) | ||
37 | macro ( install_lua_executable _name _source ) | ||
38 | get_filename_component ( _source_name ${_source} NAME_WE ) | ||
39 | # Find srlua and glue | ||
40 | find_program( SRLUA_EXECUTABLE NAMES srlua ) | ||
41 | find_program( GLUE_EXECUTABLE NAMES glue ) | ||
42 | # Executable output | ||
43 | set ( _exe ${CMAKE_CURRENT_BINARY_DIR}/${_name}${CMAKE_EXECUTABLE_SUFFIX} ) | ||
44 | if ( NOT SKIP_LUA_WRAPPER AND SRLUA_EXECUTABLE AND GLUE_EXECUTABLE ) | ||
45 | # Generate binary gluing the lua code to srlua, this is a robuust approach for most systems | ||
46 | add_custom_command( | ||
47 | OUTPUT ${_exe} | ||
48 | COMMAND ${GLUE_EXECUTABLE} | ||
49 | ARGS ${SRLUA_EXECUTABLE} ${_source} ${_exe} | ||
50 | DEPENDS ${_source} | ||
51 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} | ||
52 | VERBATIM | ||
53 | ) | ||
54 | # Make sure we have a target associated with the binary | ||
55 | add_custom_target(${_name} ALL | ||
56 | DEPENDS ${_exe} | ||
57 | ) | ||
58 | # Install with run permissions | ||
59 | install ( PROGRAMS ${_exe} DESTINATION ${INSTALL_BIN} COMPONENT Runtime) | ||
60 | # Also install source as optional resurce | ||
61 | install ( FILES ${_source} DESTINATION ${INSTALL_FOO} COMPONENT Other ) | ||
62 | else() | ||
63 | # Install into bin as is but without the lua suffix, we assume the executable uses UNIX shebang/hash-bang magic | ||
64 | install ( PROGRAMS ${_source} DESTINATION ${INSTALL_BIN} | ||
65 | RENAME ${_source_name} | ||
66 | COMPONENT Runtime | ||
67 | ) | ||
68 | endif() | ||
69 | endmacro () | ||
70 | |||
71 | macro ( _lua_module_helper is_install _name ) | ||
72 | parse_arguments ( _MODULE "LINK;ALL_IN_ONE" "" ${ARGN} ) | ||
73 | # _target is CMake-compatible target name for module (e.g. socket_core). | ||
74 | # _module is relative path of target (e.g. socket/core), | ||
75 | # without extension (e.g. .lua/.so/.dll). | ||
76 | # _MODULE_SRC is list of module source files (e.g. .lua and .c files). | ||
77 | # _MODULE_NAMES is list of module names (e.g. socket.core). | ||
78 | if ( _MODULE_ALL_IN_ONE ) | ||
79 | string ( REGEX REPLACE "\\..*" "" _target "${_name}" ) | ||
80 | string ( REGEX REPLACE "\\..*" "" _module "${_name}" ) | ||
81 | set ( _target "${_target}_all_in_one") | ||
82 | set ( _MODULE_SRC ${_MODULE_ALL_IN_ONE} ) | ||
83 | set ( _MODULE_NAMES ${_name} ${_MODULE_DEFAULT_ARGS} ) | ||
84 | else () | ||
85 | string ( REPLACE "." "_" _target "${_name}" ) | ||
86 | string ( REPLACE "." "/" _module "${_name}" ) | ||
87 | set ( _MODULE_SRC ${_MODULE_DEFAULT_ARGS} ) | ||
88 | set ( _MODULE_NAMES ${_name} ) | ||
89 | endif () | ||
90 | if ( NOT _MODULE_SRC ) | ||
91 | message ( FATAL_ERROR "no module sources specified" ) | ||
92 | endif () | ||
93 | list ( GET _MODULE_SRC 0 _first_source ) | ||
94 | |||
95 | get_filename_component ( _ext ${_first_source} EXT ) | ||
96 | if ( _ext STREQUAL ".lua" ) # Lua source module | ||
97 | list ( LENGTH _MODULE_SRC _len ) | ||
98 | if ( _len GREATER 1 ) | ||
99 | message ( FATAL_ERROR "more than one source file specified" ) | ||
100 | endif () | ||
101 | |||
102 | set ( _module "${_module}.lua" ) | ||
103 | |||
104 | get_filename_component ( _module_dir ${_module} PATH ) | ||
105 | get_filename_component ( _module_filename ${_module} NAME ) | ||
106 | _append_path ( "${CMAKE_CURRENT_SOURCE_DIR}" "${_first_source}" _module_path ) | ||
107 | list ( APPEND _lua_modules "${_name}" "${_module_path}" ) | ||
108 | |||
109 | if ( ${is_install} ) | ||
110 | install ( FILES ${_first_source} DESTINATION ${INSTALL_LMOD}/${_module_dir} | ||
111 | RENAME ${_module_filename} | ||
112 | COMPONENT Runtime | ||
113 | ) | ||
114 | endif () | ||
115 | else () # Lua C binary module | ||
116 | enable_language ( C ) | ||
117 | find_package ( Lua REQUIRED ) | ||
118 | include_directories ( ${LUA_INCLUDE_DIR} ) | ||
119 | |||
120 | set ( _module "${_module}${CMAKE_SHARED_MODULE_SUFFIX}" ) | ||
121 | |||
122 | get_filename_component ( _module_dir ${_module} PATH ) | ||
123 | get_filename_component ( _module_filenamebase ${_module} NAME_WE ) | ||
124 | foreach ( _thisname ${_MODULE_NAMES} ) | ||
125 | list ( APPEND _lua_modules "${_thisname}" | ||
126 | "${CMAKE_CURRENT_BINARY_DIR}/\${CMAKE_CFG_INTDIR}/${_module}" ) | ||
127 | endforeach () | ||
128 | |||
129 | # Static module (not linking to lua) | ||
130 | if ( LUA_STATIC_MODULE ) | ||
131 | add_library( ${_target} STATIC ${_MODULE_SRC}) | ||
132 | target_link_libraries ( ${_target} ${_MODULE_LINK} ) | ||
133 | else () | ||
134 | # Dynamic module | ||
135 | add_library( ${_target} MODULE ${_MODULE_SRC}) | ||
136 | target_link_libraries ( ${_target} ${LUA_LIBRARY} ${_MODULE_LINK} ) | ||
137 | endif () | ||
138 | |||
139 | set_target_properties ( ${_target} PROPERTIES | ||
140 | ARCHIVE_OUTPUT_DIRECTORY "${_module_dir}" | ||
141 | LIBRARY_OUTPUT_DIRECTORY "${_module_dir}" | ||
142 | PREFIX "" | ||
143 | OUTPUT_NAME "${_module_filenamebase}" ) | ||
144 | if ( ${is_install} ) | ||
145 | install ( TARGETS ${_target} | ||
146 | LIBRARY DESTINATION ${INSTALL_CMOD}/${_module_dir} | ||
147 | COMPONENT Runtime | ||
148 | ARCHIVE DESTINATION ${INSTALL_CMOD}/${_module_dir} | ||
149 | COMPONENT Library ) | ||
150 | endif () | ||
151 | endif () | ||
152 | endmacro () | ||
153 | |||
154 | # add_lua_module | ||
155 | # Builds a Lua source module into a destination locatable by Lua | ||
156 | # require syntax. | ||
157 | # Binary modules are also supported where this function takes sources and | ||
158 | # libraries to compile separated by LINK keyword. | ||
159 | # USE: add_lua_module ( socket.http src/http.lua ) | ||
160 | # USE2: add_lua_module ( mime.core src/mime.c ) | ||
161 | # USE3: add_lua_module ( socket.core ${SRC_SOCKET} LINK ${LIB_SOCKET} ) | ||
162 | # USE4: add_lua_module ( ssl.context ssl.core ALL_IN_ONE src/context.c src/ssl.c ) | ||
163 | # This form builds an "all-in-one" module (e.g. ssl.so or ssl.dll containing | ||
164 | # both modules ssl.context and ssl.core). The CMake target name will be | ||
165 | # ssl_all_in_one. | ||
166 | # Also sets variable _module_path (relative path where module typically | ||
167 | # would be installed). | ||
168 | macro ( add_lua_module ) | ||
169 | _lua_module_helper ( 0 ${ARGN} ) | ||
170 | endmacro () | ||
171 | |||
172 | |||
173 | # install_lua_module | ||
174 | # This is the same as `add_lua_module` but also installs the module. | ||
175 | # USE: install_lua_module ( socket.http src/http.lua ) | ||
176 | # USE2: install_lua_module ( mime.core src/mime.c ) | ||
177 | # USE3: install_lua_module ( socket.core ${SRC_SOCKET} LINK ${LIB_SOCKET} ) | ||
178 | macro ( install_lua_module ) | ||
179 | _lua_module_helper ( 1 ${ARGN} ) | ||
180 | endmacro () | ||
181 | |||
182 | # Builds string representing Lua table mapping Lua modules names to file | ||
183 | # paths. Used internally. | ||
184 | macro ( _make_module_table _outvar ) | ||
185 | set ( ${_outvar} ) | ||
186 | list ( LENGTH _lua_modules _n ) | ||
187 | if ( ${_n} GREATER 0 ) # avoids cmake complaint | ||
188 | foreach ( _i RANGE 1 ${_n} 2 ) | ||
189 | list ( GET _lua_modules ${_i} _path ) | ||
190 | math ( EXPR _ii ${_i}-1 ) | ||
191 | list ( GET _lua_modules ${_ii} _name ) | ||
192 | set ( ${_outvar} "${_table} ['${_name}'] = '${_path}'\;\n") | ||
193 | endforeach () | ||
194 | endif () | ||
195 | set ( ${_outvar} | ||
196 | "local modules = { | ||
197 | ${_table}}" ) | ||
198 | endmacro () | ||
199 | |||
200 | # add_lua_test ( _testfile [ WORKING_DIRECTORY _working_dir ] ) | ||
201 | # Runs Lua script `_testfile` under CTest tester. | ||
202 | # Optional named argument `WORKING_DIRECTORY` is current working directory to | ||
203 | # run test under (defaults to ${CMAKE_CURRENT_BINARY_DIR}). | ||
204 | # Both paths, if relative, are relative to ${CMAKE_CURRENT_SOURCE_DIR}. | ||
205 | # Any modules previously defined with install_lua_module are automatically | ||
206 | # preloaded (via package.preload) prior to running the test script. | ||
207 | # Under LuaDist, set test=true in config.lua to enable testing. | ||
208 | # USE: add_lua_test ( test/test1.lua [args...] [WORKING_DIRECTORY dir]) | ||
209 | macro ( add_lua_test _testfile ) | ||
210 | if ( NOT SKIP_TESTING ) | ||
211 | parse_arguments ( _ARG "WORKING_DIRECTORY" "" ${ARGN} ) | ||
212 | include ( CTest ) | ||
213 | find_program ( LUA NAMES lua lua.bat ) | ||
214 | get_filename_component ( TESTFILEABS ${_testfile} ABSOLUTE ) | ||
215 | get_filename_component ( TESTFILENAME ${_testfile} NAME ) | ||
216 | get_filename_component ( TESTFILEBASE ${_testfile} NAME_WE ) | ||
217 | |||
218 | # Write wrapper script. | ||
219 | # Note: One simple way to allow the script to find modules is | ||
220 | # to just put them in package.preload. | ||
221 | set ( TESTWRAPPER ${CMAKE_CURRENT_BINARY_DIR}/${TESTFILENAME} ) | ||
222 | _make_module_table ( _table ) | ||
223 | set ( TESTWRAPPERSOURCE | ||
224 | "local CMAKE_CFG_INTDIR = ... or '.' | ||
225 | ${_table} | ||
226 | local function preload_modules(modules) | ||
227 | for name, path in pairs(modules) do | ||
228 | if path:match'%.lua' then | ||
229 | package.preload[name] = assert(loadfile(path)) | ||
230 | else | ||
231 | local name = name:gsub('.*%-', '') -- remove any hyphen prefix | ||
232 | local symbol = 'luaopen_' .. name:gsub('%.', '_') | ||
233 | --improve: generalize to support all-in-one loader? | ||
234 | local path = path:gsub('%$%{CMAKE_CFG_INTDIR%}', CMAKE_CFG_INTDIR) | ||
235 | package.preload[name] = assert(package.loadlib(path, symbol)) | ||
236 | end | ||
237 | end | ||
238 | end | ||
239 | preload_modules(modules) | ||
240 | arg[0] = '${TESTFILEABS}' | ||
241 | table.remove(arg, 1) | ||
242 | return assert(loadfile '${TESTFILEABS}')(unpack(arg)) | ||
243 | " ) | ||
244 | if ( _ARG_WORKING_DIRECTORY ) | ||
245 | get_filename_component ( | ||
246 | TESTCURRENTDIRABS ${_ARG_WORKING_DIRECTORY} ABSOLUTE ) | ||
247 | # note: CMake 2.6 (unlike 2.8) lacks WORKING_DIRECTORY parameter. | ||
248 | set ( _pre ${CMAKE_COMMAND} -E chdir "${TESTCURRENTDIRABS}" ) | ||
249 | endif () | ||
250 | file ( WRITE ${TESTWRAPPER} ${TESTWRAPPERSOURCE}) | ||
251 | add_test ( NAME ${TESTFILEBASE} COMMAND ${_pre} ${LUA} | ||
252 | ${TESTWRAPPER} "${CMAKE_CFG_INTDIR}" | ||
253 | ${_ARG_DEFAULT_ARGS} ) | ||
254 | endif () | ||
255 | # see also http://gdcm.svn.sourceforge.net/viewvc/gdcm/Sandbox/CMakeModules/UsePythonTest.cmake | ||
256 | # Note: ${CMAKE_CFG_INTDIR} is a command-line argument to allow proper | ||
257 | # expansion by the native build tool. | ||
258 | endmacro () | ||
259 | |||
260 | |||
261 | # Converts Lua source file `_source` to binary string embedded in C source | ||
262 | # file `_target`. Optionally compiles Lua source to byte code (not available | ||
263 | # under LuaJIT2, which doesn't have a bytecode loader). Additionally, Lua | ||
264 | # versions of bin2c [1] and luac [2] may be passed respectively as additional | ||
265 | # arguments. | ||
266 | # | ||
267 | # [1] http://lua-users.org/wiki/BinToCee | ||
268 | # [2] http://lua-users.org/wiki/LuaCompilerInLua | ||
269 | function ( add_lua_bin2c _target _source ) | ||
270 | find_program ( LUA NAMES lua lua.bat ) | ||
271 | execute_process ( COMMAND ${LUA} -e "string.dump(function()end)" | ||
272 | RESULT_VARIABLE _LUA_DUMP_RESULT ERROR_QUIET ) | ||
273 | if ( NOT ${_LUA_DUMP_RESULT} ) | ||
274 | SET ( HAVE_LUA_DUMP true ) | ||
275 | endif () | ||
276 | message ( "-- string.dump=${HAVE_LUA_DUMP}" ) | ||
277 | |||
278 | if ( ARGV2 ) | ||
279 | get_filename_component ( BIN2C ${ARGV2} ABSOLUTE ) | ||
280 | set ( BIN2C ${LUA} ${BIN2C} ) | ||
281 | else () | ||
282 | find_program ( BIN2C NAMES bin2c bin2c.bat ) | ||
283 | endif () | ||
284 | if ( HAVE_LUA_DUMP ) | ||
285 | if ( ARGV3 ) | ||
286 | get_filename_component ( LUAC ${ARGV3} ABSOLUTE ) | ||
287 | set ( LUAC ${LUA} ${LUAC} ) | ||
288 | else () | ||
289 | find_program ( LUAC NAMES luac luac.bat ) | ||
290 | endif () | ||
291 | endif ( HAVE_LUA_DUMP ) | ||
292 | message ( "-- bin2c=${BIN2C}" ) | ||
293 | message ( "-- luac=${LUAC}" ) | ||
294 | |||
295 | get_filename_component ( SOURCEABS ${_source} ABSOLUTE ) | ||
296 | if ( HAVE_LUA_DUMP ) | ||
297 | get_filename_component ( SOURCEBASE ${_source} NAME_WE ) | ||
298 | add_custom_command ( | ||
299 | OUTPUT ${_target} DEPENDS ${_source} | ||
300 | COMMAND ${LUAC} -o ${CMAKE_CURRENT_BINARY_DIR}/${SOURCEBASE}.lo | ||
301 | ${SOURCEABS} | ||
302 | COMMAND ${BIN2C} ${CMAKE_CURRENT_BINARY_DIR}/${SOURCEBASE}.lo | ||
303 | ">${_target}" ) | ||
304 | else () | ||
305 | add_custom_command ( | ||
306 | OUTPUT ${_target} DEPENDS ${SOURCEABS} | ||
307 | COMMAND ${BIN2C} ${_source} ">${_target}" ) | ||
308 | endif () | ||
309 | endfunction() | ||
diff --git a/dist.info b/dist.info new file mode 100644 index 0000000..5dfdbaa --- /dev/null +++ b/dist.info | |||
@@ -0,0 +1,12 @@ | |||
1 | name = "lua-llthreads2" | ||
2 | version = "0.1.1" | ||
3 | |||
4 | desc = "A simple Lua wrapper for pthreads & WIN32 threads." | ||
5 | author = "Alexey Melnichuk" | ||
6 | license = "MIT/X11" | ||
7 | url = "https://github.com/moteus/lua-llthreads2" | ||
8 | maintainer = "Alexey Melnichuk" | ||
9 | |||
10 | depends = { | ||
11 | "lua > 5.1" | ||
12 | } \ No newline at end of file | ||
diff --git a/llthreads2/.gitignore b/llthreads2/.gitignore new file mode 100644 index 0000000..2122aa6 --- /dev/null +++ b/llthreads2/.gitignore | |||
@@ -0,0 +1,18 @@ | |||
1 | *.d | ||
2 | *.spec | ||
3 | *.obj | ||
4 | *.dll | ||
5 | *.o | ||
6 | *.lib | ||
7 | *.exp | ||
8 | *.suo | ||
9 | *.ncb | ||
10 | *.user | ||
11 | *.pdb | ||
12 | msvc/Debug/ | ||
13 | msvc/Release/ | ||
14 | CMakeCache.txt | ||
15 | CMakeFiles | ||
16 | Makefile | ||
17 | cmake_install.cmake | ||
18 | install_manifest.txt | ||
diff --git a/llthreads2/.travis.yml b/llthreads2/.travis.yml new file mode 100644 index 0000000..5b72267 --- /dev/null +++ b/llthreads2/.travis.yml | |||
@@ -0,0 +1,42 @@ | |||
1 | language: objective-c | ||
2 | |||
3 | env: | ||
4 | global: | ||
5 | - PLATFORM=macosx | ||
6 | - LUAROCKS_VER=2.1.0 | ||
7 | matrix: | ||
8 | - LUA=lua5.1 LUA_SFX= | ||
9 | - LUA=lua5.2 LUA_SFX= | ||
10 | - LUA=luajit LUA_SFX=jit | ||
11 | |||
12 | branches: | ||
13 | only: | ||
14 | - master | ||
15 | |||
16 | before_install: | ||
17 | - bash .travis/setup_lua.sh | ||
18 | |||
19 | install: | ||
20 | - sudo luarocks install lunitx | ||
21 | - sudo luarocks make rockspecs/lua-llthreads2-compat-scm-0.rockspec | ||
22 | - sudo luarocks make rockspecs/lua-llthreads2-scm-0.rockspec | ||
23 | |||
24 | script: | ||
25 | - cd test | ||
26 | - lua$LUA_SFX test_table_copy.lua | ||
27 | - lua$LUA_SFX test_threads.lua | ||
28 | - lua$LUA_SFX test_llthreads.lua | ||
29 | # - lua$LUA_SFX test_register_llthreads.lua | ||
30 | - lua$LUA_SFX test_join_timeout.lua | ||
31 | - lua$LUA_SFX test_join_detach.lua | ||
32 | - lua$LUA_SFX test_join_error.lua | ||
33 | - lua$LUA_SFX test_register_ffi.lua | ||
34 | - lua$LUA_SFX test_logger.lua | ||
35 | - lua$LUA_SFX test_pass_cfunction.lua | ||
36 | - lua$LUA_SFX test_load_llthreads2.lua | ||
37 | - lua$LUA_SFX test_alive.lua | ||
38 | |||
39 | notifications: | ||
40 | email: | ||
41 | on_success: change | ||
42 | on_failure: always | ||
diff --git a/llthreads2/.travis/setup_lua.sh b/llthreads2/.travis/setup_lua.sh new file mode 100644 index 0000000..47ce49c --- /dev/null +++ b/llthreads2/.travis/setup_lua.sh | |||
@@ -0,0 +1,35 @@ | |||
1 | # A script for setting up environment for travis-ci testing. | ||
2 | # Sets up Lua and Luarocks. | ||
3 | # LUA must be "lua5.1", "lua5.2" or "luajit". | ||
4 | # PLATFORM must be "linux" or "macosx". | ||
5 | |||
6 | if [ "$LUA" == "luajit" ]; then | ||
7 | curl http://luajit.org/download/LuaJIT-2.0.2.tar.gz | tar xz | ||
8 | cd LuaJIT-2.0.2 | ||
9 | make && sudo make install | ||
10 | cd $TRAVIS_BUILD_DIR; | ||
11 | else | ||
12 | if [ "$LUA" == "lua5.1" ]; then | ||
13 | curl http://www.lua.org/ftp/lua-5.1.5.tar.gz | tar xz | ||
14 | cd lua-5.1.5; | ||
15 | elif [ "$LUA" == "lua5.2" ]; then | ||
16 | curl http://www.lua.org/ftp/lua-5.2.3.tar.gz | tar xz | ||
17 | cd lua-5.2.3; | ||
18 | fi | ||
19 | sudo make $PLATFORM install | ||
20 | cd $TRAVIS_BUILD_DIR; | ||
21 | fi | ||
22 | |||
23 | LUAROCKS_BASE=luarocks-$LUAROCKS_VER | ||
24 | curl http://luarocks.org/releases/$LUAROCKS_BASE.tar.gz | tar xz | ||
25 | cd $LUAROCKS_BASE; | ||
26 | |||
27 | if [ "$LUA" == "luajit" ]; then | ||
28 | ./configure --lua-suffix=jit --with-lua-include=/usr/local/include/luajit-2.0; | ||
29 | else | ||
30 | ./configure; | ||
31 | fi | ||
32 | |||
33 | make && sudo make install | ||
34 | |||
35 | cd $TRAVIS_BUILD_DIR \ No newline at end of file | ||
diff --git a/llthreads2/CMakeLists.txt b/llthreads2/CMakeLists.txt new file mode 100644 index 0000000..f96b32a --- /dev/null +++ b/llthreads2/CMakeLists.txt | |||
@@ -0,0 +1,17 @@ | |||
1 | cmake_minimum_required ( VERSION 2.8 ) | ||
2 | |||
3 | project ( lua-llthreads2 C ) | ||
4 | include ( cmake/dist.cmake ) | ||
5 | include ( lua ) | ||
6 | |||
7 | set ( CMAKE_THREAD_PREFER_PTHREAD TRUE ) | ||
8 | include ( FindThreads ) | ||
9 | |||
10 | include_directories ( ${CMAKE_CURRENT_SOURCE_DIR}/src ) | ||
11 | |||
12 | set ( LUA_LLTHREADS_SRC src/l52util.c src/llthread.c ) | ||
13 | |||
14 | install_lua_module ( llthreads2 ${LUA_LLTHREADS_SRC} LINK ${CMAKE_THREAD_LIBS_INIT} ) | ||
15 | |||
16 | install_data ( COPYRIGHT.llthreads README.md LICENSE ) | ||
17 | install_test ( test/ ) | ||
diff --git a/llthreads2/COPYRIGHT.llthreads b/llthreads2/COPYRIGHT.llthreads new file mode 100644 index 0000000..4826006 --- /dev/null +++ b/llthreads2/COPYRIGHT.llthreads | |||
@@ -0,0 +1,19 @@ | |||
1 | Copyright (c) 2011 by Robert G. Jakabosky <bobby@sharedrealm.com> | ||
2 | |||
3 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
4 | of this software and associated documentation files (the "Software"), to deal | ||
5 | in the Software without restriction, including without limitation the rights | ||
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
7 | copies of the Software, and to permit persons to whom the Software is | ||
8 | furnished to do so, subject to the following conditions: | ||
9 | |||
10 | The above copyright notice and this permission notice shall be included in | ||
11 | all copies or substantial portions of the Software. | ||
12 | |||
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
19 | THE SOFTWARE. | ||
diff --git a/llthreads2/LICENSE b/llthreads2/LICENSE new file mode 100644 index 0000000..484264b --- /dev/null +++ b/llthreads2/LICENSE | |||
@@ -0,0 +1,20 @@ | |||
1 | The MIT License (MIT) | ||
2 | |||
3 | Copyright (c) 2013 Alexey Melnichuk | ||
4 | |||
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
6 | this software and associated documentation files (the "Software"), to deal in | ||
7 | the Software without restriction, including without limitation the rights to | ||
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||
9 | the Software, and to permit persons to whom the Software is furnished to do so, | ||
10 | 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, FITNESS | ||
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
diff --git a/llthreads2/README.md b/llthreads2/README.md new file mode 100644 index 0000000..22f2025 --- /dev/null +++ b/llthreads2/README.md | |||
@@ -0,0 +1,113 @@ | |||
1 | lua-llthreads2 | ||
2 | ============== | ||
3 | [](https://travis-ci.org/moteus/lua-llthreads2) | ||
4 | [](https://buildhive.cloudbees.com/job/moteus/job/lua-llthreads2/) | ||
5 | [](https://moteus.ci.cloudbees.com/job/lua-llthreads2/) | ||
6 | |||
7 | This is full dropin replacement for [llthreads](https://github.com/Neopallium/lua-llthreads) library. | ||
8 | |||
9 | ##Incompatibility list with origin llthreads library | ||
10 | * does not support Lua 5.0 | ||
11 | * does not support ffi interface (use Lua C API for LuaJIT) | ||
12 | * returns nil instead of false on error | ||
13 | * start method returns self instead of true on success | ||
14 | |||
15 | ##Additional | ||
16 | * thread:join() method support zero timeout to check if thread alive (does not work on Windows with pthreads) | ||
17 | * thread:join() method support arbitrary timeout on Windows threads | ||
18 | * thread:alive() method return whether the thread is alive (does not work on Windows with pthreads) | ||
19 | * set_logger function allow logging errors (crash Lua VM) in current llthread's threads | ||
20 | * thread:start() has additional parameter which control in which thread child Lua VM will be destroyed | ||
21 | * allow pass cfunctions to child thread (e.g. to initialize Lua state) | ||
22 | |||
23 | ##Usage | ||
24 | |||
25 | ### Use custom logger | ||
26 | In this example I use [lua-log](https://github.com/moteus/lua-log) library. | ||
27 | ``` Lua | ||
28 | -- This is child thread. | ||
29 | local llthreads = require "llthreads" | ||
30 | -- Send logs using ZMQ | ||
31 | local LOG = require"log".new( | ||
32 | require "log.writer.net.zmq".new("tcp://127.0.0.1:5555") | ||
33 | ) | ||
34 | llthread.set_logger(function(msg) LOG.error(msg) end) | ||
35 | -- This error with traceback will be passed to logger | ||
36 | error("SOME ERROR") | ||
37 | ``` | ||
38 | |||
39 | ### Start attached thread collectd in child thread | ||
40 | ``` Lua | ||
41 | -- This is main thread. | ||
42 | local thread = require "llthreads".new[[ | ||
43 | require "utils".sleep(5) | ||
44 | ]] | ||
45 | |||
46 | -- We tell that we start attached thread but child Lua State shuld be close in child thread. | ||
47 | -- If `thread` became garbage in main thread then finallizer calls thread:join() | ||
48 | -- and main thread may hungup. | ||
49 | thread:start(false, false) | ||
50 | |||
51 | -- We can call join. | ||
52 | -- Because of Lua state destroys in child thread we can not get | ||
53 | -- returned Lua vaules so we just returns `true`. | ||
54 | thread:join() | ||
55 | ``` | ||
56 | |||
57 | ### Start detached joinable thread | ||
58 | ``` Lua | ||
59 | -- This is main thread. | ||
60 | local thread = require "llthreads".new[[ | ||
61 | require "utils".sleep(5) | ||
62 | ]] | ||
63 | |||
64 | -- We tell that we start detached joinable thread. In fact we start attached | ||
65 | -- thread but if `thread` became garbage in main thread then finallizer just | ||
66 | -- detach child thread and main thread may not hungup. | ||
67 | thread:start(true, true) | ||
68 | |||
69 | -- We can call join. | ||
70 | -- Because of Lua state destroys in child thread we can not get | ||
71 | -- returned Lua vaules so we just returns `true`. | ||
72 | thread:join() | ||
73 | ``` | ||
74 | |||
75 | ### Pass to child thread host application`s library loader | ||
76 | If you close parent Lua state then some dynamic library may be unloaded | ||
77 | and cfunction in child Lua state (thread) became invalid. | ||
78 | |||
79 | ``` Lua | ||
80 | -- `myhost.XXX` modules is built-in modules in host application | ||
81 | -- host application registers cfunction as module loader | ||
82 | local preload = {} | ||
83 | preload[ 'myhost.logger' ] = package.preload[ 'myhost.logger' ] | ||
84 | preload[ 'myhost.config' ] = package.preload[ 'myhost.config' ] | ||
85 | llthreads.new([[ | ||
86 | -- registers preload | ||
87 | local preload = ... | ||
88 | for name, fn in pairs(preload) do package.preload[name] = fn end | ||
89 | |||
90 | local log = require 'myhost.logger' | ||
91 | |||
92 | ]], preload):start(true) | ||
93 | ``` | ||
94 | |||
95 | ### Wait while thread is alive | ||
96 | ``` Lua | ||
97 | local thread = require "llthreads".new[[ | ||
98 | require "utils".sleep(5) | ||
99 | return 1 | ||
100 | ]] | ||
101 | thread:start() | ||
102 | |||
103 | -- we can not use `thread:join(0)` because we can not call it twice | ||
104 | -- so all returned vaules will be lost | ||
105 | while thread:alive() do | ||
106 | -- do some work | ||
107 | end | ||
108 | |||
109 | local ok, ret = thread:join() -- true, 1 | ||
110 | ``` | ||
111 | |||
112 | [](https://bitdeli.com/free "Bitdeli Badge") | ||
113 | |||
diff --git a/llthreads2/cmake/FindLua.cmake b/llthreads2/cmake/FindLua.cmake new file mode 100644 index 0000000..6991b4a --- /dev/null +++ b/llthreads2/cmake/FindLua.cmake | |||
@@ -0,0 +1,127 @@ | |||
1 | # Locate Lua library | ||
2 | # This module defines | ||
3 | # LUA_EXECUTABLE, if found | ||
4 | # LUA_FOUND, if false, do not try to link to Lua | ||
5 | # LUA_LIBRARIES | ||
6 | # LUA_INCLUDE_DIR, where to find lua.h | ||
7 | # LUA_VERSION_STRING, the version of Lua found (since CMake 2.8.8) | ||
8 | # | ||
9 | # Note that the expected include convention is | ||
10 | # #include "lua.h" | ||
11 | # and not | ||
12 | # #include <lua/lua.h> | ||
13 | # This is because, the lua location is not standardized and may exist | ||
14 | # in locations other than lua/ | ||
15 | |||
16 | #============================================================================= | ||
17 | # Copyright 2007-2009 Kitware, Inc. | ||
18 | # Modified to support Lua 5.2 by LuaDist 2012 | ||
19 | # | ||
20 | # Distributed under the OSI-approved BSD License (the "License"); | ||
21 | # see accompanying file Copyright.txt for details. | ||
22 | # | ||
23 | # This software is distributed WITHOUT ANY WARRANTY; without even the | ||
24 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
25 | # See the License for more information. | ||
26 | #============================================================================= | ||
27 | # (To distribute this file outside of CMake, substitute the full | ||
28 | # License text for the above reference.) | ||
29 | # | ||
30 | # The required version of Lua can be specified using the | ||
31 | # standard syntax, e.g. FIND_PACKAGE(Lua 5.1) | ||
32 | # Otherwise the module will search for any available Lua implementation | ||
33 | |||
34 | # Always search for non-versioned lua first (recommended) | ||
35 | SET(_POSSIBLE_LUA_INCLUDE include include/lua) | ||
36 | SET(_POSSIBLE_LUA_EXECUTABLE lua) | ||
37 | SET(_POSSIBLE_LUA_LIBRARY lua) | ||
38 | |||
39 | # Determine possible naming suffixes (there is no standard for this) | ||
40 | IF(Lua_FIND_VERSION_MAJOR AND Lua_FIND_VERSION_MINOR) | ||
41 | SET(_POSSIBLE_SUFFIXES "${Lua_FIND_VERSION_MAJOR}${Lua_FIND_VERSION_MINOR}" "${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR}" "-${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR}") | ||
42 | ELSE(Lua_FIND_VERSION_MAJOR AND Lua_FIND_VERSION_MINOR) | ||
43 | SET(_POSSIBLE_SUFFIXES "52" "5.2" "-5.2" "51" "5.1" "-5.1") | ||
44 | ENDIF(Lua_FIND_VERSION_MAJOR AND Lua_FIND_VERSION_MINOR) | ||
45 | |||
46 | # Set up possible search names and locations | ||
47 | FOREACH(_SUFFIX ${_POSSIBLE_SUFFIXES}) | ||
48 | LIST(APPEND _POSSIBLE_LUA_INCLUDE "include/lua${_SUFFIX}") | ||
49 | LIST(APPEND _POSSIBLE_LUA_EXECUTABLE "lua${_SUFFIX}") | ||
50 | LIST(APPEND _POSSIBLE_LUA_LIBRARY "lua${_SUFFIX}") | ||
51 | ENDFOREACH(_SUFFIX) | ||
52 | |||
53 | # Find the lua executable | ||
54 | FIND_PROGRAM(LUA_EXECUTABLE | ||
55 | NAMES ${_POSSIBLE_LUA_EXECUTABLE} | ||
56 | ) | ||
57 | |||
58 | # Find the lua header | ||
59 | FIND_PATH(LUA_INCLUDE_DIR lua.h | ||
60 | HINTS | ||
61 | $ENV{LUA_DIR} | ||
62 | PATH_SUFFIXES ${_POSSIBLE_LUA_INCLUDE} | ||
63 | PATHS | ||
64 | ~/Library/Frameworks | ||
65 | /Library/Frameworks | ||
66 | /usr/local | ||
67 | /usr | ||
68 | /sw # Fink | ||
69 | /opt/local # DarwinPorts | ||
70 | /opt/csw # Blastwave | ||
71 | /opt | ||
72 | ) | ||
73 | |||
74 | # Find the lua library | ||
75 | FIND_LIBRARY(LUA_LIBRARY | ||
76 | NAMES ${_POSSIBLE_LUA_LIBRARY} | ||
77 | HINTS | ||
78 | $ENV{LUA_DIR} | ||
79 | PATH_SUFFIXES lib64 lib | ||
80 | PATHS | ||
81 | ~/Library/Frameworks | ||
82 | /Library/Frameworks | ||
83 | /usr/local | ||
84 | /usr | ||
85 | /sw | ||
86 | /opt/local | ||
87 | /opt/csw | ||
88 | /opt | ||
89 | ) | ||
90 | |||
91 | IF(LUA_LIBRARY) | ||
92 | # include the math library for Unix | ||
93 | IF(UNIX AND NOT APPLE) | ||
94 | FIND_LIBRARY(LUA_MATH_LIBRARY m) | ||
95 | SET( LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}" CACHE STRING "Lua Libraries") | ||
96 | # For Windows and Mac, don't need to explicitly include the math library | ||
97 | ELSE(UNIX AND NOT APPLE) | ||
98 | SET( LUA_LIBRARIES "${LUA_LIBRARY}" CACHE STRING "Lua Libraries") | ||
99 | ENDIF(UNIX AND NOT APPLE) | ||
100 | ENDIF(LUA_LIBRARY) | ||
101 | |||
102 | # Determine Lua version | ||
103 | IF(LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/lua.h") | ||
104 | FILE(STRINGS "${LUA_INCLUDE_DIR}/lua.h" lua_version_str REGEX "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua .+\"") | ||
105 | |||
106 | STRING(REGEX REPLACE "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([^\"]+)\".*" "\\1" LUA_VERSION_STRING "${lua_version_str}") | ||
107 | UNSET(lua_version_str) | ||
108 | ENDIF() | ||
109 | |||
110 | # Lua 5.2 | ||
111 | IF(NOT LUA_VERSION_STRING) | ||
112 | FILE(STRINGS "${LUA_INCLUDE_DIR}/lua.h" lua_version_str REGEX "^#define LUA_VERSION_[A-Z]+[ \t]+\"[0-9]+\"") | ||
113 | STRING(REGEX REPLACE ".*#define LUA_VERSION_MAJOR[ \t]+\"([0-9]+)\".*" "\\1" LUA_VERSION_MAJOR ${lua_version_str}) | ||
114 | STRING(REGEX REPLACE ".*#define LUA_VERSION_MINOR[ \t]+\"([0-9]+)\".*" "\\1" LUA_VERSION_MINOR ${lua_version_str}) | ||
115 | STRING(REGEX REPLACE ".*#define LUA_VERSION_RELEASE[ \t]+\"([0-9]+)\".*" "\\1" LUA_VERSION_RELEASE ${lua_version_str}) | ||
116 | SET(LUA_VERSION_STRING ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}.${LUA_VERSION_RELEASE}) | ||
117 | ENDIF() | ||
118 | |||
119 | INCLUDE(FindPackageHandleStandardArgs) | ||
120 | # handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if | ||
121 | # all listed variables are TRUE | ||
122 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua | ||
123 | REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR | ||
124 | VERSION_VAR LUA_VERSION_STRING) | ||
125 | |||
126 | MARK_AS_ADVANCED(LUA_INCLUDE_DIR LUA_LIBRARIES LUA_LIBRARY LUA_MATH_LIBRARY LUA_EXECUTABLE) | ||
127 | |||
diff --git a/llthreads2/cmake/dist.cmake b/llthreads2/cmake/dist.cmake new file mode 100644 index 0000000..310ef94 --- /dev/null +++ b/llthreads2/cmake/dist.cmake | |||
@@ -0,0 +1,321 @@ | |||
1 | # LuaDist CMake utility library. | ||
2 | # Provides sane project defaults and macros common to LuaDist CMake builds. | ||
3 | # | ||
4 | # Copyright (C) 2007-2012 LuaDist. | ||
5 | # by David Manura, Peter Drahoš | ||
6 | # Redistribution and use of this file is allowed according to the terms of the MIT license. | ||
7 | # For details see the COPYRIGHT file distributed with LuaDist. | ||
8 | # Please note that the package source code is licensed under its own license. | ||
9 | |||
10 | ## Extract information from dist.info | ||
11 | if ( NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/dist.info ) | ||
12 | message ( FATAL_ERROR | ||
13 | "Missing dist.info file (${CMAKE_CURRENT_SOURCE_DIR}/dist.info)." ) | ||
14 | endif () | ||
15 | file ( READ ${CMAKE_CURRENT_SOURCE_DIR}/dist.info DIST_INFO ) | ||
16 | if ( "${DIST_INFO}" STREQUAL "" ) | ||
17 | message ( FATAL_ERROR "Failed to load dist.info." ) | ||
18 | endif () | ||
19 | # Reads field `name` from dist.info string `DIST_INFO` into variable `var`. | ||
20 | macro ( _parse_dist_field name var ) | ||
21 | string ( REGEX REPLACE ".*${name}[ \t]?=[ \t]?[\"']([^\"']+)[\"'].*" "\\1" | ||
22 | ${var} "${DIST_INFO}" ) | ||
23 | if ( ${var} STREQUAL DIST_INFO ) | ||
24 | message ( FATAL_ERROR "Failed to extract \"${var}\" from dist.info" ) | ||
25 | endif () | ||
26 | endmacro () | ||
27 | # | ||
28 | _parse_dist_field ( name DIST_NAME ) | ||
29 | _parse_dist_field ( version DIST_VERSION ) | ||
30 | _parse_dist_field ( license DIST_LICENSE ) | ||
31 | _parse_dist_field ( author DIST_AUTHOR ) | ||
32 | _parse_dist_field ( maintainer DIST_MAINTAINER ) | ||
33 | _parse_dist_field ( url DIST_URL ) | ||
34 | _parse_dist_field ( desc DIST_DESC ) | ||
35 | message ( "DIST_NAME: ${DIST_NAME}") | ||
36 | message ( "DIST_VERSION: ${DIST_VERSION}") | ||
37 | message ( "DIST_LICENSE: ${DIST_LICENSE}") | ||
38 | message ( "DIST_AUTHOR: ${DIST_AUTHOR}") | ||
39 | message ( "DIST_MAINTAINER: ${DIST_MAINTAINER}") | ||
40 | message ( "DIST_URL: ${DIST_URL}") | ||
41 | message ( "DIST_DESC: ${DIST_DESC}") | ||
42 | string ( REGEX REPLACE ".*depends[ \t]?=[ \t]?[\"']([^\"']+)[\"'].*" "\\1" | ||
43 | DIST_DEPENDS ${DIST_INFO} ) | ||
44 | if ( DIST_DEPENDS STREQUAL DIST_INFO ) | ||
45 | set ( DIST_DEPENDS "" ) | ||
46 | endif () | ||
47 | message ( "DIST_DEPENDS: ${DIST_DEPENDS}") | ||
48 | ## 2DO: Parse DIST_DEPENDS and try to install Dependencies with automatically using externalproject_add | ||
49 | |||
50 | |||
51 | ## INSTALL DEFAULTS (Relative to CMAKE_INSTALL_PREFIX) | ||
52 | # Primary paths | ||
53 | set ( INSTALL_BIN bin CACHE PATH "Where to install binaries to." ) | ||
54 | set ( INSTALL_LIB lib CACHE PATH "Where to install libraries to." ) | ||
55 | set ( INSTALL_INC include CACHE PATH "Where to install headers to." ) | ||
56 | set ( INSTALL_ETC etc CACHE PATH "Where to store configuration files" ) | ||
57 | set ( INSTALL_SHARE share CACHE PATH "Directory for shared data." ) | ||
58 | |||
59 | # Secondary paths | ||
60 | option ( INSTALL_VERSION | ||
61 | "Install runtime libraries and executables with version information." OFF) | ||
62 | set ( INSTALL_DATA ${INSTALL_SHARE}/${DIST_NAME} CACHE PATH | ||
63 | "Directory the package can store documentation, tests or other data in.") | ||
64 | set ( INSTALL_DOC ${INSTALL_DATA}/doc CACHE PATH | ||
65 | "Recommended directory to install documentation into.") | ||
66 | set ( INSTALL_EXAMPLE ${INSTALL_DATA}/example CACHE PATH | ||
67 | "Recommended directory to install examples into.") | ||
68 | set ( INSTALL_TEST ${INSTALL_DATA}/test CACHE PATH | ||
69 | "Recommended directory to install tests into.") | ||
70 | set ( INSTALL_FOO ${INSTALL_DATA}/etc CACHE PATH | ||
71 | "Where to install additional files") | ||
72 | |||
73 | # Tweaks and other defaults | ||
74 | # Setting CMAKE to use loose block and search for find modules in source directory | ||
75 | set ( CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true ) | ||
76 | set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH} ) | ||
77 | option ( BUILD_SHARED_LIBS "Build shared libraries" ON ) | ||
78 | |||
79 | # In MSVC, prevent warnings that can occur when using standard libraries. | ||
80 | if ( MSVC ) | ||
81 | add_definitions ( -D_CRT_SECURE_NO_WARNINGS ) | ||
82 | endif () | ||
83 | |||
84 | # RPath and relative linking | ||
85 | option ( USE_RPATH "Use relative linking." ON) | ||
86 | if ( USE_RPATH ) | ||
87 | string ( REGEX REPLACE "[^!/]+" ".." UP_DIR ${INSTALL_BIN} ) | ||
88 | set ( CMAKE_SKIP_BUILD_RPATH FALSE CACHE STRING "" FORCE ) | ||
89 | set ( CMAKE_BUILD_WITH_INSTALL_RPATH FALSE CACHE STRING "" FORCE ) | ||
90 | set ( CMAKE_INSTALL_RPATH $ORIGIN/${UP_DIR}/${INSTALL_LIB} | ||
91 | CACHE STRING "" FORCE ) | ||
92 | set ( CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE CACHE STRING "" FORCE ) | ||
93 | set ( CMAKE_INSTALL_NAME_DIR @executable_path/${UP_DIR}/${INSTALL_LIB} | ||
94 | CACHE STRING "" FORCE ) | ||
95 | endif () | ||
96 | |||
97 | ## MACROS | ||
98 | # Parser macro | ||
99 | macro ( parse_arguments prefix arg_names option_names) | ||
100 | set ( DEFAULT_ARGS ) | ||
101 | foreach ( arg_name ${arg_names} ) | ||
102 | set ( ${prefix}_${arg_name} ) | ||
103 | endforeach () | ||
104 | foreach ( option ${option_names} ) | ||
105 | set ( ${prefix}_${option} FALSE ) | ||
106 | endforeach () | ||
107 | |||
108 | set ( current_arg_name DEFAULT_ARGS ) | ||
109 | set ( current_arg_list ) | ||
110 | foreach ( arg ${ARGN} ) | ||
111 | set ( larg_names ${arg_names} ) | ||
112 | list ( FIND larg_names "${arg}" is_arg_name ) | ||
113 | if ( is_arg_name GREATER -1 ) | ||
114 | set ( ${prefix}_${current_arg_name} ${current_arg_list} ) | ||
115 | set ( current_arg_name ${arg} ) | ||
116 | set ( current_arg_list ) | ||
117 | else () | ||
118 | set ( loption_names ${option_names} ) | ||
119 | list ( FIND loption_names "${arg}" is_option ) | ||
120 | if ( is_option GREATER -1 ) | ||
121 | set ( ${prefix}_${arg} TRUE ) | ||
122 | else () | ||
123 | set ( current_arg_list ${current_arg_list} ${arg} ) | ||
124 | endif () | ||
125 | endif () | ||
126 | endforeach () | ||
127 | set ( ${prefix}_${current_arg_name} ${current_arg_list} ) | ||
128 | endmacro () | ||
129 | |||
130 | |||
131 | # install_executable ( executable_targets ) | ||
132 | # Installs any executables generated using "add_executable". | ||
133 | # USE: install_executable ( lua ) | ||
134 | # NOTE: subdirectories are NOT supported | ||
135 | set ( CPACK_COMPONENT_RUNTIME_DISPLAY_NAME "${DIST_NAME} Runtime" ) | ||
136 | set ( CPACK_COMPONENT_RUNTIME_DESCRIPTION | ||
137 | "Executables and runtime libraries. Installed into ${INSTALL_BIN}." ) | ||
138 | macro ( install_executable ) | ||
139 | foreach ( _file ${ARGN} ) | ||
140 | if ( INSTALL_VERSION ) | ||
141 | set_target_properties ( ${_file} PROPERTIES VERSION ${DIST_VERSION} | ||
142 | SOVERSION ${DIST_VERSION} ) | ||
143 | endif () | ||
144 | install ( TARGETS ${_file} RUNTIME DESTINATION ${INSTALL_BIN} | ||
145 | COMPONENT Runtime ) | ||
146 | endforeach() | ||
147 | endmacro () | ||
148 | |||
149 | # install_library ( library_targets ) | ||
150 | # Installs any libraries generated using "add_library" into apropriate places. | ||
151 | # USE: install_library ( libexpat ) | ||
152 | # NOTE: subdirectories are NOT supported | ||
153 | set ( CPACK_COMPONENT_LIBRARY_DISPLAY_NAME "${DIST_NAME} Development Libraries" ) | ||
154 | set ( CPACK_COMPONENT_LIBRARY_DESCRIPTION | ||
155 | "Static and import libraries needed for development. Installed into ${INSTALL_LIB} or ${INSTALL_BIN}." ) | ||
156 | macro ( install_library ) | ||
157 | foreach ( _file ${ARGN} ) | ||
158 | if ( INSTALL_VERSION ) | ||
159 | set_target_properties ( ${_file} PROPERTIES VERSION ${DIST_VERSION} | ||
160 | SOVERSION ${DIST_VERSION} ) | ||
161 | endif () | ||
162 | install ( TARGETS ${_file} | ||
163 | RUNTIME DESTINATION ${INSTALL_BIN} COMPONENT Runtime | ||
164 | LIBRARY DESTINATION ${INSTALL_LIB} COMPONENT Runtime | ||
165 | ARCHIVE DESTINATION ${INSTALL_LIB} COMPONENT Library ) | ||
166 | endforeach() | ||
167 | endmacro () | ||
168 | |||
169 | # helper function for various install_* functions, for PATTERN/REGEX args. | ||
170 | macro ( _complete_install_args ) | ||
171 | if ( NOT("${_ARG_PATTERN}" STREQUAL "") ) | ||
172 | set ( _ARG_PATTERN PATTERN ${_ARG_PATTERN} ) | ||
173 | endif () | ||
174 | if ( NOT("${_ARG_REGEX}" STREQUAL "") ) | ||
175 | set ( _ARG_REGEX REGEX ${_ARG_REGEX} ) | ||
176 | endif () | ||
177 | endmacro () | ||
178 | |||
179 | # install_header ( files/directories [INTO destination] ) | ||
180 | # Install a directories or files into header destination. | ||
181 | # USE: install_header ( lua.h luaconf.h ) or install_header ( GL ) | ||
182 | # USE: install_header ( mylib.h INTO mylib ) | ||
183 | # For directories, supports optional PATTERN/REGEX arguments like install(). | ||
184 | set ( CPACK_COMPONENT_HEADER_DISPLAY_NAME "${DIST_NAME} Development Headers" ) | ||
185 | set ( CPACK_COMPONENT_HEADER_DESCRIPTION | ||
186 | "Headers needed for development. Installed into ${INSTALL_INC}." ) | ||
187 | macro ( install_header ) | ||
188 | parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} ) | ||
189 | _complete_install_args() | ||
190 | foreach ( _file ${_ARG_DEFAULT_ARGS} ) | ||
191 | if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" ) | ||
192 | install ( DIRECTORY ${_file} DESTINATION ${INSTALL_INC}/${_ARG_INTO} | ||
193 | COMPONENT Header ${_ARG_PATTERN} ${_ARG_REGEX} ) | ||
194 | else () | ||
195 | install ( FILES ${_file} DESTINATION ${INSTALL_INC}/${_ARG_INTO} | ||
196 | COMPONENT Header ) | ||
197 | endif () | ||
198 | endforeach() | ||
199 | endmacro () | ||
200 | |||
201 | # install_data ( files/directories [INTO destination] ) | ||
202 | # This installs additional data files or directories. | ||
203 | # USE: install_data ( extra data.dat ) | ||
204 | # USE: install_data ( image1.png image2.png INTO images ) | ||
205 | # For directories, supports optional PATTERN/REGEX arguments like install(). | ||
206 | set ( CPACK_COMPONENT_DATA_DISPLAY_NAME "${DIST_NAME} Data" ) | ||
207 | set ( CPACK_COMPONENT_DATA_DESCRIPTION | ||
208 | "Application data. Installed into ${INSTALL_DATA}." ) | ||
209 | macro ( install_data ) | ||
210 | parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} ) | ||
211 | _complete_install_args() | ||
212 | foreach ( _file ${_ARG_DEFAULT_ARGS} ) | ||
213 | if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" ) | ||
214 | install ( DIRECTORY ${_file} | ||
215 | DESTINATION ${INSTALL_DATA}/${_ARG_INTO} | ||
216 | COMPONENT Data ${_ARG_PATTERN} ${_ARG_REGEX} ) | ||
217 | else () | ||
218 | install ( FILES ${_file} DESTINATION ${INSTALL_DATA}/${_ARG_INTO} | ||
219 | COMPONENT Data ) | ||
220 | endif () | ||
221 | endforeach() | ||
222 | endmacro () | ||
223 | |||
224 | # INSTALL_DOC ( files/directories [INTO destination] ) | ||
225 | # This installs documentation content | ||
226 | # USE: install_doc ( doc/ doc.pdf ) | ||
227 | # USE: install_doc ( index.html INTO html ) | ||
228 | # For directories, supports optional PATTERN/REGEX arguments like install(). | ||
229 | set ( CPACK_COMPONENT_DOCUMENTATION_DISPLAY_NAME "${DIST_NAME} Documentation" ) | ||
230 | set ( CPACK_COMPONENT_DOCUMENTATION_DESCRIPTION | ||
231 | "Application documentation. Installed into ${INSTALL_DOC}." ) | ||
232 | macro ( install_doc ) | ||
233 | parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} ) | ||
234 | _complete_install_args() | ||
235 | foreach ( _file ${_ARG_DEFAULT_ARGS} ) | ||
236 | if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" ) | ||
237 | install ( DIRECTORY ${_file} DESTINATION ${INSTALL_DOC}/${_ARG_INTO} | ||
238 | COMPONENT Documentation ${_ARG_PATTERN} ${_ARG_REGEX} ) | ||
239 | else () | ||
240 | install ( FILES ${_file} DESTINATION ${INSTALL_DOC}/${_ARG_INTO} | ||
241 | COMPONENT Documentation ) | ||
242 | endif () | ||
243 | endforeach() | ||
244 | endmacro () | ||
245 | |||
246 | # install_example ( files/directories [INTO destination] ) | ||
247 | # This installs additional examples | ||
248 | # USE: install_example ( examples/ exampleA ) | ||
249 | # USE: install_example ( super_example super_data INTO super) | ||
250 | # For directories, supports optional PATTERN/REGEX argument like install(). | ||
251 | set ( CPACK_COMPONENT_EXAMPLE_DISPLAY_NAME "${DIST_NAME} Examples" ) | ||
252 | set ( CPACK_COMPONENT_EXAMPLE_DESCRIPTION | ||
253 | "Examples and their associated data. Installed into ${INSTALL_EXAMPLE}." ) | ||
254 | macro ( install_example ) | ||
255 | parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} ) | ||
256 | _complete_install_args() | ||
257 | foreach ( _file ${_ARG_DEFAULT_ARGS} ) | ||
258 | if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" ) | ||
259 | install ( DIRECTORY ${_file} DESTINATION ${INSTALL_EXAMPLE}/${_ARG_INTO} | ||
260 | COMPONENT Example ${_ARG_PATTERN} ${_ARG_REGEX} ) | ||
261 | else () | ||
262 | install ( FILES ${_file} DESTINATION ${INSTALL_EXAMPLE}/${_ARG_INTO} | ||
263 | COMPONENT Example ) | ||
264 | endif () | ||
265 | endforeach() | ||
266 | endmacro () | ||
267 | |||
268 | # install_test ( files/directories [INTO destination] ) | ||
269 | # This installs tests and test files, DOES NOT EXECUTE TESTS | ||
270 | # USE: install_test ( my_test data.sql ) | ||
271 | # USE: install_test ( feature_x_test INTO x ) | ||
272 | # For directories, supports optional PATTERN/REGEX argument like install(). | ||
273 | set ( CPACK_COMPONENT_TEST_DISPLAY_NAME "${DIST_NAME} Tests" ) | ||
274 | set ( CPACK_COMPONENT_TEST_DESCRIPTION | ||
275 | "Tests and associated data. Installed into ${INSTALL_TEST}." ) | ||
276 | macro ( install_test ) | ||
277 | parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} ) | ||
278 | _complete_install_args() | ||
279 | foreach ( _file ${_ARG_DEFAULT_ARGS} ) | ||
280 | if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" ) | ||
281 | install ( DIRECTORY ${_file} DESTINATION ${INSTALL_TEST}/${_ARG_INTO} | ||
282 | COMPONENT Test ${_ARG_PATTERN} ${_ARG_REGEX} ) | ||
283 | else () | ||
284 | install ( FILES ${_file} DESTINATION ${INSTALL_TEST}/${_ARG_INTO} | ||
285 | COMPONENT Test ) | ||
286 | endif () | ||
287 | endforeach() | ||
288 | endmacro () | ||
289 | |||
290 | # install_foo ( files/directories [INTO destination] ) | ||
291 | # This installs optional or otherwise unneeded content | ||
292 | # USE: install_foo ( etc/ example.doc ) | ||
293 | # USE: install_foo ( icon.png logo.png INTO icons) | ||
294 | # For directories, supports optional PATTERN/REGEX argument like install(). | ||
295 | set ( CPACK_COMPONENT_OTHER_DISPLAY_NAME "${DIST_NAME} Unspecified Content" ) | ||
296 | set ( CPACK_COMPONENT_OTHER_DESCRIPTION | ||
297 | "Other unspecified content. Installed into ${INSTALL_FOO}." ) | ||
298 | macro ( install_foo ) | ||
299 | parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} ) | ||
300 | _complete_install_args() | ||
301 | foreach ( _file ${_ARG_DEFAULT_ARGS} ) | ||
302 | if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" ) | ||
303 | install ( DIRECTORY ${_file} DESTINATION ${INSTALL_FOO}/${_ARG_INTO} | ||
304 | COMPONENT Other ${_ARG_PATTERN} ${_ARG_REGEX} ) | ||
305 | else () | ||
306 | install ( FILES ${_file} DESTINATION ${INSTALL_FOO}/${_ARG_INTO} | ||
307 | COMPONENT Other ) | ||
308 | endif () | ||
309 | endforeach() | ||
310 | endmacro () | ||
311 | |||
312 | ## CTest defaults | ||
313 | |||
314 | ## CPack defaults | ||
315 | set ( CPACK_GENERATOR "ZIP" ) | ||
316 | set ( CPACK_STRIP_FILES TRUE ) | ||
317 | set ( CPACK_PACKAGE_NAME "${DIST_NAME}" ) | ||
318 | set ( CPACK_PACKAGE_VERSION "${DIST_VERSION}") | ||
319 | set ( CPACK_PACKAGE_VENDOR "LuaDist" ) | ||
320 | set ( CPACK_COMPONENTS_ALL Runtime Library Header Data Documentation Example Other ) | ||
321 | include ( CPack ) | ||
diff --git a/llthreads2/cmake/lua.cmake b/llthreads2/cmake/lua.cmake new file mode 100644 index 0000000..ee2e35d --- /dev/null +++ b/llthreads2/cmake/lua.cmake | |||
@@ -0,0 +1,309 @@ | |||
1 | # LuaDist CMake utility library for Lua. | ||
2 | # | ||
3 | # Copyright (C) 2007-2012 LuaDist. | ||
4 | # by David Manura, Peter Drahos | ||
5 | # Redistribution and use of this file is allowed according to the terms of the MIT license. | ||
6 | # For details see the COPYRIGHT file distributed with LuaDist. | ||
7 | # Please note that the package source code is licensed under its own license. | ||
8 | |||
9 | set ( INSTALL_LMOD ${INSTALL_LIB}/lua | ||
10 | CACHE PATH "Directory to install Lua modules." ) | ||
11 | set ( INSTALL_CMOD ${INSTALL_LIB}/lua | ||
12 | CACHE PATH "Directory to install Lua binary modules." ) | ||
13 | |||
14 | option ( LUA_SKIP_WRAPPER | ||
15 | "Do not build and install Lua executable wrappers." OFF ) | ||
16 | option ( LUA_STATIC_MODULE "Build modules for static linking" OFF ) | ||
17 | |||
18 | # List of (Lua module name, file path) pairs. | ||
19 | # Used internally by add_lua_test. Built by add_lua_module. | ||
20 | set ( _lua_modules ) | ||
21 | |||
22 | # utility function: appends path `path` to path `basepath`, properly | ||
23 | # handling cases when `path` may be relative or absolute. | ||
24 | macro ( _append_path basepath path result ) | ||
25 | if ( IS_ABSOLUTE "${path}" ) | ||
26 | set ( ${result} "${path}" ) | ||
27 | else () | ||
28 | set ( ${result} "${basepath}/${path}" ) | ||
29 | endif () | ||
30 | endmacro () | ||
31 | |||
32 | # install_lua_executable ( target source ) | ||
33 | # Automatically generate a binary if srlua package is available | ||
34 | # The application or its source will be placed into /bin | ||
35 | # If the application source did not have .lua suffix then it will be added | ||
36 | # USE: lua_executable ( sputnik src/sputnik.lua ) | ||
37 | macro ( install_lua_executable _name _source ) | ||
38 | get_filename_component ( _source_name ${_source} NAME_WE ) | ||
39 | # Find srlua and glue | ||
40 | find_program( SRLUA_EXECUTABLE NAMES srlua ) | ||
41 | find_program( GLUE_EXECUTABLE NAMES glue ) | ||
42 | # Executable output | ||
43 | set ( _exe ${CMAKE_CURRENT_BINARY_DIR}/${_name}${CMAKE_EXECUTABLE_SUFFIX} ) | ||
44 | if ( NOT SKIP_LUA_WRAPPER AND SRLUA_EXECUTABLE AND GLUE_EXECUTABLE ) | ||
45 | # Generate binary gluing the lua code to srlua, this is a robuust approach for most systems | ||
46 | add_custom_command( | ||
47 | OUTPUT ${_exe} | ||
48 | COMMAND ${GLUE_EXECUTABLE} | ||
49 | ARGS ${SRLUA_EXECUTABLE} ${_source} ${_exe} | ||
50 | DEPENDS ${_source} | ||
51 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} | ||
52 | VERBATIM | ||
53 | ) | ||
54 | # Make sure we have a target associated with the binary | ||
55 | add_custom_target(${_name} ALL | ||
56 | DEPENDS ${_exe} | ||
57 | ) | ||
58 | # Install with run permissions | ||
59 | install ( PROGRAMS ${_exe} DESTINATION ${INSTALL_BIN} COMPONENT Runtime) | ||
60 | # Also install source as optional resurce | ||
61 | install ( FILES ${_source} DESTINATION ${INSTALL_FOO} COMPONENT Other ) | ||
62 | else() | ||
63 | # Install into bin as is but without the lua suffix, we assume the executable uses UNIX shebang/hash-bang magic | ||
64 | install ( PROGRAMS ${_source} DESTINATION ${INSTALL_BIN} | ||
65 | RENAME ${_source_name} | ||
66 | COMPONENT Runtime | ||
67 | ) | ||
68 | endif() | ||
69 | endmacro () | ||
70 | |||
71 | macro ( _lua_module_helper is_install _name ) | ||
72 | parse_arguments ( _MODULE "LINK;ALL_IN_ONE" "" ${ARGN} ) | ||
73 | # _target is CMake-compatible target name for module (e.g. socket_core). | ||
74 | # _module is relative path of target (e.g. socket/core), | ||
75 | # without extension (e.g. .lua/.so/.dll). | ||
76 | # _MODULE_SRC is list of module source files (e.g. .lua and .c files). | ||
77 | # _MODULE_NAMES is list of module names (e.g. socket.core). | ||
78 | if ( _MODULE_ALL_IN_ONE ) | ||
79 | string ( REGEX REPLACE "\\..*" "" _target "${_name}" ) | ||
80 | string ( REGEX REPLACE "\\..*" "" _module "${_name}" ) | ||
81 | set ( _target "${_target}_all_in_one") | ||
82 | set ( _MODULE_SRC ${_MODULE_ALL_IN_ONE} ) | ||
83 | set ( _MODULE_NAMES ${_name} ${_MODULE_DEFAULT_ARGS} ) | ||
84 | else () | ||
85 | string ( REPLACE "." "_" _target "${_name}" ) | ||
86 | string ( REPLACE "." "/" _module "${_name}" ) | ||
87 | set ( _MODULE_SRC ${_MODULE_DEFAULT_ARGS} ) | ||
88 | set ( _MODULE_NAMES ${_name} ) | ||
89 | endif () | ||
90 | if ( NOT _MODULE_SRC ) | ||
91 | message ( FATAL_ERROR "no module sources specified" ) | ||
92 | endif () | ||
93 | list ( GET _MODULE_SRC 0 _first_source ) | ||
94 | |||
95 | get_filename_component ( _ext ${_first_source} EXT ) | ||
96 | if ( _ext STREQUAL ".lua" ) # Lua source module | ||
97 | list ( LENGTH _MODULE_SRC _len ) | ||
98 | if ( _len GREATER 1 ) | ||
99 | message ( FATAL_ERROR "more than one source file specified" ) | ||
100 | endif () | ||
101 | |||
102 | set ( _module "${_module}.lua" ) | ||
103 | |||
104 | get_filename_component ( _module_dir ${_module} PATH ) | ||
105 | get_filename_component ( _module_filename ${_module} NAME ) | ||
106 | _append_path ( "${CMAKE_CURRENT_SOURCE_DIR}" "${_first_source}" _module_path ) | ||
107 | list ( APPEND _lua_modules "${_name}" "${_module_path}" ) | ||
108 | |||
109 | if ( ${is_install} ) | ||
110 | install ( FILES ${_first_source} DESTINATION ${INSTALL_LMOD}/${_module_dir} | ||
111 | RENAME ${_module_filename} | ||
112 | COMPONENT Runtime | ||
113 | ) | ||
114 | endif () | ||
115 | else () # Lua C binary module | ||
116 | enable_language ( C ) | ||
117 | find_package ( Lua REQUIRED ) | ||
118 | include_directories ( ${LUA_INCLUDE_DIR} ) | ||
119 | |||
120 | set ( _module "${_module}${CMAKE_SHARED_MODULE_SUFFIX}" ) | ||
121 | |||
122 | get_filename_component ( _module_dir ${_module} PATH ) | ||
123 | get_filename_component ( _module_filenamebase ${_module} NAME_WE ) | ||
124 | foreach ( _thisname ${_MODULE_NAMES} ) | ||
125 | list ( APPEND _lua_modules "${_thisname}" | ||
126 | "${CMAKE_CURRENT_BINARY_DIR}/\${CMAKE_CFG_INTDIR}/${_module}" ) | ||
127 | endforeach () | ||
128 | |||
129 | # Static module (not linking to lua) | ||
130 | if ( LUA_STATIC_MODULE ) | ||
131 | add_library( ${_target} STATIC ${_MODULE_SRC}) | ||
132 | target_link_libraries ( ${_target} ${_MODULE_LINK} ) | ||
133 | else () | ||
134 | # Dynamic module | ||
135 | add_library( ${_target} MODULE ${_MODULE_SRC}) | ||
136 | target_link_libraries ( ${_target} ${LUA_LIBRARY} ${_MODULE_LINK} ) | ||
137 | endif () | ||
138 | |||
139 | set_target_properties ( ${_target} PROPERTIES | ||
140 | ARCHIVE_OUTPUT_DIRECTORY "${_module_dir}" | ||
141 | LIBRARY_OUTPUT_DIRECTORY "${_module_dir}" | ||
142 | PREFIX "" | ||
143 | OUTPUT_NAME "${_module_filenamebase}" ) | ||
144 | if ( ${is_install} ) | ||
145 | install ( TARGETS ${_target} | ||
146 | LIBRARY DESTINATION ${INSTALL_CMOD}/${_module_dir} | ||
147 | COMPONENT Runtime | ||
148 | ARCHIVE DESTINATION ${INSTALL_CMOD}/${_module_dir} | ||
149 | COMPONENT Library ) | ||
150 | endif () | ||
151 | endif () | ||
152 | endmacro () | ||
153 | |||
154 | # add_lua_module | ||
155 | # Builds a Lua source module into a destination locatable by Lua | ||
156 | # require syntax. | ||
157 | # Binary modules are also supported where this function takes sources and | ||
158 | # libraries to compile separated by LINK keyword. | ||
159 | # USE: add_lua_module ( socket.http src/http.lua ) | ||
160 | # USE2: add_lua_module ( mime.core src/mime.c ) | ||
161 | # USE3: add_lua_module ( socket.core ${SRC_SOCKET} LINK ${LIB_SOCKET} ) | ||
162 | # USE4: add_lua_module ( ssl.context ssl.core ALL_IN_ONE src/context.c src/ssl.c ) | ||
163 | # This form builds an "all-in-one" module (e.g. ssl.so or ssl.dll containing | ||
164 | # both modules ssl.context and ssl.core). The CMake target name will be | ||
165 | # ssl_all_in_one. | ||
166 | # Also sets variable _module_path (relative path where module typically | ||
167 | # would be installed). | ||
168 | macro ( add_lua_module ) | ||
169 | _lua_module_helper ( 0 ${ARGN} ) | ||
170 | endmacro () | ||
171 | |||
172 | |||
173 | # install_lua_module | ||
174 | # This is the same as `add_lua_module` but also installs the module. | ||
175 | # USE: install_lua_module ( socket.http src/http.lua ) | ||
176 | # USE2: install_lua_module ( mime.core src/mime.c ) | ||
177 | # USE3: install_lua_module ( socket.core ${SRC_SOCKET} LINK ${LIB_SOCKET} ) | ||
178 | macro ( install_lua_module ) | ||
179 | _lua_module_helper ( 1 ${ARGN} ) | ||
180 | endmacro () | ||
181 | |||
182 | # Builds string representing Lua table mapping Lua modules names to file | ||
183 | # paths. Used internally. | ||
184 | macro ( _make_module_table _outvar ) | ||
185 | set ( ${_outvar} ) | ||
186 | list ( LENGTH _lua_modules _n ) | ||
187 | if ( ${_n} GREATER 0 ) # avoids cmake complaint | ||
188 | foreach ( _i RANGE 1 ${_n} 2 ) | ||
189 | list ( GET _lua_modules ${_i} _path ) | ||
190 | math ( EXPR _ii ${_i}-1 ) | ||
191 | list ( GET _lua_modules ${_ii} _name ) | ||
192 | set ( ${_outvar} "${_table} ['${_name}'] = '${_path}'\;\n") | ||
193 | endforeach () | ||
194 | endif () | ||
195 | set ( ${_outvar} | ||
196 | "local modules = { | ||
197 | ${_table}}" ) | ||
198 | endmacro () | ||
199 | |||
200 | # add_lua_test ( _testfile [ WORKING_DIRECTORY _working_dir ] ) | ||
201 | # Runs Lua script `_testfile` under CTest tester. | ||
202 | # Optional named argument `WORKING_DIRECTORY` is current working directory to | ||
203 | # run test under (defaults to ${CMAKE_CURRENT_BINARY_DIR}). | ||
204 | # Both paths, if relative, are relative to ${CMAKE_CURRENT_SOURCE_DIR}. | ||
205 | # Any modules previously defined with install_lua_module are automatically | ||
206 | # preloaded (via package.preload) prior to running the test script. | ||
207 | # Under LuaDist, set test=true in config.lua to enable testing. | ||
208 | # USE: add_lua_test ( test/test1.lua [args...] [WORKING_DIRECTORY dir]) | ||
209 | macro ( add_lua_test _testfile ) | ||
210 | if ( NOT SKIP_TESTING ) | ||
211 | parse_arguments ( _ARG "WORKING_DIRECTORY" "" ${ARGN} ) | ||
212 | include ( CTest ) | ||
213 | find_program ( LUA NAMES lua lua.bat ) | ||
214 | get_filename_component ( TESTFILEABS ${_testfile} ABSOLUTE ) | ||
215 | get_filename_component ( TESTFILENAME ${_testfile} NAME ) | ||
216 | get_filename_component ( TESTFILEBASE ${_testfile} NAME_WE ) | ||
217 | |||
218 | # Write wrapper script. | ||
219 | # Note: One simple way to allow the script to find modules is | ||
220 | # to just put them in package.preload. | ||
221 | set ( TESTWRAPPER ${CMAKE_CURRENT_BINARY_DIR}/${TESTFILENAME} ) | ||
222 | _make_module_table ( _table ) | ||
223 | set ( TESTWRAPPERSOURCE | ||
224 | "local CMAKE_CFG_INTDIR = ... or '.' | ||
225 | ${_table} | ||
226 | local function preload_modules(modules) | ||
227 | for name, path in pairs(modules) do | ||
228 | if path:match'%.lua' then | ||
229 | package.preload[name] = assert(loadfile(path)) | ||
230 | else | ||
231 | local name = name:gsub('.*%-', '') -- remove any hyphen prefix | ||
232 | local symbol = 'luaopen_' .. name:gsub('%.', '_') | ||
233 | --improve: generalize to support all-in-one loader? | ||
234 | local path = path:gsub('%$%{CMAKE_CFG_INTDIR%}', CMAKE_CFG_INTDIR) | ||
235 | package.preload[name] = assert(package.loadlib(path, symbol)) | ||
236 | end | ||
237 | end | ||
238 | end | ||
239 | preload_modules(modules) | ||
240 | arg[0] = '${TESTFILEABS}' | ||
241 | table.remove(arg, 1) | ||
242 | return assert(loadfile '${TESTFILEABS}')(unpack(arg)) | ||
243 | " ) | ||
244 | if ( _ARG_WORKING_DIRECTORY ) | ||
245 | get_filename_component ( | ||
246 | TESTCURRENTDIRABS ${_ARG_WORKING_DIRECTORY} ABSOLUTE ) | ||
247 | # note: CMake 2.6 (unlike 2.8) lacks WORKING_DIRECTORY parameter. | ||
248 | set ( _pre ${CMAKE_COMMAND} -E chdir "${TESTCURRENTDIRABS}" ) | ||
249 | endif () | ||
250 | file ( WRITE ${TESTWRAPPER} ${TESTWRAPPERSOURCE}) | ||
251 | add_test ( NAME ${TESTFILEBASE} COMMAND ${_pre} ${LUA} | ||
252 | ${TESTWRAPPER} "${CMAKE_CFG_INTDIR}" | ||
253 | ${_ARG_DEFAULT_ARGS} ) | ||
254 | endif () | ||
255 | # see also http://gdcm.svn.sourceforge.net/viewvc/gdcm/Sandbox/CMakeModules/UsePythonTest.cmake | ||
256 | # Note: ${CMAKE_CFG_INTDIR} is a command-line argument to allow proper | ||
257 | # expansion by the native build tool. | ||
258 | endmacro () | ||
259 | |||
260 | |||
261 | # Converts Lua source file `_source` to binary string embedded in C source | ||
262 | # file `_target`. Optionally compiles Lua source to byte code (not available | ||
263 | # under LuaJIT2, which doesn't have a bytecode loader). Additionally, Lua | ||
264 | # versions of bin2c [1] and luac [2] may be passed respectively as additional | ||
265 | # arguments. | ||
266 | # | ||
267 | # [1] http://lua-users.org/wiki/BinToCee | ||
268 | # [2] http://lua-users.org/wiki/LuaCompilerInLua | ||
269 | function ( add_lua_bin2c _target _source ) | ||
270 | find_program ( LUA NAMES lua lua.bat ) | ||
271 | execute_process ( COMMAND ${LUA} -e "string.dump(function()end)" | ||
272 | RESULT_VARIABLE _LUA_DUMP_RESULT ERROR_QUIET ) | ||
273 | if ( NOT ${_LUA_DUMP_RESULT} ) | ||
274 | SET ( HAVE_LUA_DUMP true ) | ||
275 | endif () | ||
276 | message ( "-- string.dump=${HAVE_LUA_DUMP}" ) | ||
277 | |||
278 | if ( ARGV2 ) | ||
279 | get_filename_component ( BIN2C ${ARGV2} ABSOLUTE ) | ||
280 | set ( BIN2C ${LUA} ${BIN2C} ) | ||
281 | else () | ||
282 | find_program ( BIN2C NAMES bin2c bin2c.bat ) | ||
283 | endif () | ||
284 | if ( HAVE_LUA_DUMP ) | ||
285 | if ( ARGV3 ) | ||
286 | get_filename_component ( LUAC ${ARGV3} ABSOLUTE ) | ||
287 | set ( LUAC ${LUA} ${LUAC} ) | ||
288 | else () | ||
289 | find_program ( LUAC NAMES luac luac.bat ) | ||
290 | endif () | ||
291 | endif ( HAVE_LUA_DUMP ) | ||
292 | message ( "-- bin2c=${BIN2C}" ) | ||
293 | message ( "-- luac=${LUAC}" ) | ||
294 | |||
295 | get_filename_component ( SOURCEABS ${_source} ABSOLUTE ) | ||
296 | if ( HAVE_LUA_DUMP ) | ||
297 | get_filename_component ( SOURCEBASE ${_source} NAME_WE ) | ||
298 | add_custom_command ( | ||
299 | OUTPUT ${_target} DEPENDS ${_source} | ||
300 | COMMAND ${LUAC} -o ${CMAKE_CURRENT_BINARY_DIR}/${SOURCEBASE}.lo | ||
301 | ${SOURCEABS} | ||
302 | COMMAND ${BIN2C} ${CMAKE_CURRENT_BINARY_DIR}/${SOURCEBASE}.lo | ||
303 | ">${_target}" ) | ||
304 | else () | ||
305 | add_custom_command ( | ||
306 | OUTPUT ${_target} DEPENDS ${SOURCEABS} | ||
307 | COMMAND ${BIN2C} ${_source} ">${_target}" ) | ||
308 | endif () | ||
309 | endfunction() | ||
diff --git a/llthreads2/dist.info b/llthreads2/dist.info new file mode 100644 index 0000000..5dfdbaa --- /dev/null +++ b/llthreads2/dist.info | |||
@@ -0,0 +1,12 @@ | |||
1 | name = "lua-llthreads2" | ||
2 | version = "0.1.1" | ||
3 | |||
4 | desc = "A simple Lua wrapper for pthreads & WIN32 threads." | ||
5 | author = "Alexey Melnichuk" | ||
6 | license = "MIT/X11" | ||
7 | url = "https://github.com/moteus/lua-llthreads2" | ||
8 | maintainer = "Alexey Melnichuk" | ||
9 | |||
10 | depends = { | ||
11 | "lua > 5.1" | ||
12 | } \ No newline at end of file | ||
diff --git a/llthreads2/lakeconfig.lua b/llthreads2/lakeconfig.lua new file mode 100644 index 0000000..ffe5ad7 --- /dev/null +++ b/llthreads2/lakeconfig.lua | |||
@@ -0,0 +1,252 @@ | |||
1 | local io = require "io" | ||
2 | io.stdout:setvbuf"no" | ||
3 | io.stderr:setvbuf"no" | ||
4 | |||
5 | function vc_version() | ||
6 | local VER = lake.compiler_version() | ||
7 | MSVC_VER = ({ | ||
8 | [15] = '9'; | ||
9 | [16] = '10'; | ||
10 | })[VER.MAJOR] or '' | ||
11 | return MSVC_VER | ||
12 | end | ||
13 | |||
14 | if not L then | ||
15 | |||
16 | local function arkey(t) | ||
17 | assert(type(t) == 'table') | ||
18 | local keys = {} | ||
19 | for k in pairs(t) do | ||
20 | assert(type(k) == 'number') | ||
21 | table.insert(keys, k) | ||
22 | end | ||
23 | table.sort(keys) | ||
24 | return keys | ||
25 | end | ||
26 | |||
27 | local function ikeys(t) | ||
28 | local keys = arkey(t) | ||
29 | local i = 0 | ||
30 | return function() | ||
31 | i = i + 1 | ||
32 | local k = keys[i] | ||
33 | if k == nil then return end | ||
34 | return k, t[k] | ||
35 | end | ||
36 | end | ||
37 | |||
38 | local function expand(arr, t) | ||
39 | if t == nil then return arr end | ||
40 | |||
41 | if type(t) ~= 'table' then | ||
42 | table.insert(arr, t) | ||
43 | return arr | ||
44 | end | ||
45 | |||
46 | for _, v in ikeys(t) do | ||
47 | expand(arr, v) | ||
48 | end | ||
49 | |||
50 | return arr | ||
51 | end | ||
52 | |||
53 | function L(...) | ||
54 | return expand({}, {...}) | ||
55 | end | ||
56 | |||
57 | end | ||
58 | |||
59 | J = J or path.join | ||
60 | |||
61 | IF = IF or lake.choose or choose | ||
62 | |||
63 | DIR_SEP = package.config:sub(1,1) | ||
64 | |||
65 | function prequire(...) | ||
66 | local ok, mod = pcall(require, ...) | ||
67 | if ok then return mod end | ||
68 | end | ||
69 | |||
70 | function clone(t, o) | ||
71 | o = o or {} | ||
72 | for k, v in pairs(t) do | ||
73 | if o[k] == nil then o[k] = v end | ||
74 | end | ||
75 | return o | ||
76 | end | ||
77 | |||
78 | function each_join(dir, list) | ||
79 | for i, v in ipairs(list) do | ||
80 | list[i] = path.join(dir, v) | ||
81 | end | ||
82 | return list | ||
83 | end | ||
84 | |||
85 | function run(file, cwd) | ||
86 | print() | ||
87 | print("run " .. file) | ||
88 | if not TESTING then | ||
89 | if cwd then lake.chdir(cwd) end | ||
90 | local status, code = utils.execute( LUA_RUNNER .. ' ' .. file ) | ||
91 | if cwd then lake.chdir("<") end | ||
92 | print() | ||
93 | return status, code | ||
94 | end | ||
95 | return true, 0 | ||
96 | end | ||
97 | |||
98 | function exec(file, cwd) | ||
99 | print() | ||
100 | print("exec " .. file) | ||
101 | if not TESTING then | ||
102 | if cwd then lake.chdir(cwd) end | ||
103 | local status, code = utils.execute( file ) | ||
104 | if cwd then lake.chdir("<") end | ||
105 | print() | ||
106 | return status, code | ||
107 | end | ||
108 | return true, 0 | ||
109 | end | ||
110 | |||
111 | local TESTS = {} | ||
112 | |||
113 | function run_test(name, params) | ||
114 | local test_dir = TESTDIR or J(ROOT, 'test') | ||
115 | local cmd = J(test_dir, name) | ||
116 | if params then cmd = cmd .. ' ' .. params end | ||
117 | local ok = run(cmd, test_dir) | ||
118 | |||
119 | table.insert(TESTS, {cmd = cmd, result = ok}) | ||
120 | |||
121 | print("TEST " .. name .. (ok and ' - pass!' or ' - fail!')) | ||
122 | end | ||
123 | |||
124 | function exec_test(name, params) | ||
125 | local test_dir = TESTDIR or J(ROOT, 'test') | ||
126 | local cmd = J(test_dir, name) | ||
127 | if params then cmd = cmd .. ' ' .. params end | ||
128 | local ok = exec(cmd, test_dir) | ||
129 | |||
130 | table.insert(TESTS, {cmd = cmd, result = ok}) | ||
131 | |||
132 | print("TEST " .. name .. (ok and ' - pass!' or ' - fail!')) | ||
133 | end | ||
134 | |||
135 | function test_summary() | ||
136 | local ok = true | ||
137 | print("") | ||
138 | print("------------------------------------") | ||
139 | print("Number of tests:", #TESTS) | ||
140 | for _, t in ipairs(TESTS) do | ||
141 | ok = ok and t.result | ||
142 | print((t.result and ' Pass' or ' Fail') .. " - TEST " .. t.cmd) | ||
143 | end | ||
144 | print("------------------------------------") | ||
145 | print("") | ||
146 | return ok | ||
147 | end | ||
148 | |||
149 | --[[spawn]] if WINDOWS then | ||
150 | function spawn(file, cwd) | ||
151 | local winapi = prequire "winapi" | ||
152 | if not winapi then | ||
153 | quit('needs winapi for spawn!') | ||
154 | return false | ||
155 | end | ||
156 | |||
157 | print("spawn " .. file) | ||
158 | if not TESTING then | ||
159 | if cwd then lake.chdir(cwd) end | ||
160 | assert(winapi.shell_exec(nil, LUA_RUNNER, file, cwd)) | ||
161 | if cwd then lake.chdir("<") end | ||
162 | print() | ||
163 | end | ||
164 | return true | ||
165 | end | ||
166 | else | ||
167 | function spawn(file, cwd) | ||
168 | print("spawn " .. file) | ||
169 | if not TESTING then | ||
170 | assert(run(file .. ' &', cwd)) | ||
171 | end | ||
172 | return true | ||
173 | end | ||
174 | end | ||
175 | |||
176 | function as_bool(v,d) | ||
177 | if v == nil then return not not d end | ||
178 | local n = tonumber(v) | ||
179 | if n == 0 then return false end | ||
180 | if n then return true end | ||
181 | return false | ||
182 | end | ||
183 | |||
184 | --- set global variables | ||
185 | -- LUA_NEED | ||
186 | -- LUA_DIR | ||
187 | -- LUA_RUNNER | ||
188 | -- ROOT | ||
189 | -- LUADIR | ||
190 | -- LIBDIR | ||
191 | -- TESTDIR | ||
192 | -- DOCDIR | ||
193 | -- DYNAMIC | ||
194 | function INITLAKEFILE() | ||
195 | if LUA_VER == '5.3' then | ||
196 | LUA_NEED = 'lua53' | ||
197 | LUA_DIR = ENV.LUA_DIR_5_3 or ENV.LUA_DIR | ||
198 | LUA_RUNNER = LUA_RUNNER or 'lua53' | ||
199 | elseif LUA_VER == '5.2' then | ||
200 | LUA_NEED = 'lua52' | ||
201 | LUA_DIR = ENV.LUA_DIR_5_2 or ENV.LUA_DIR | ||
202 | LUA_RUNNER = LUA_RUNNER or 'lua52' | ||
203 | elseif LUA_VER == '5.1' then | ||
204 | LUA_NEED = 'lua51' | ||
205 | LUA_DIR = ENV.LUA_DIR | ||
206 | LUA_RUNNER = LUA_RUNNER or 'lua' | ||
207 | else | ||
208 | LUA_NEED = 'lua' | ||
209 | LUA_DIR = ENV.LUA_DIR | ||
210 | LUA_RUNNER = LUA_RUNNER or 'lua' | ||
211 | end | ||
212 | ROOT = ROOT or J( LUA_DIR, 'libs', PROJECT ) | ||
213 | LUADIR = LUADIR or J( ROOT, 'share' ) | ||
214 | LIBDIR = LIBDIR or J( ROOT, 'share' ) | ||
215 | TESTDIR = TESTDIR or J( ROOT, 'test' ) | ||
216 | DOCDIR = DOCDIR or J( ROOT, 'doc' ) | ||
217 | DYNAMIC = as_bool(DYNAMIC, false) | ||
218 | end | ||
219 | |||
220 | ----------------------- | ||
221 | -- needs -- | ||
222 | ----------------------- | ||
223 | |||
224 | lake.define_need('lua53', function() | ||
225 | return { | ||
226 | incdir = J(ENV.LUA_DIR_5_3, 'include'); | ||
227 | libdir = J(ENV.LUA_DIR_5_3, 'lib'); | ||
228 | libs = {'lua53'}; | ||
229 | } | ||
230 | end) | ||
231 | |||
232 | lake.define_need('lua52', function() | ||
233 | return { | ||
234 | incdir = J(ENV.LUA_DIR_5_2, 'include'); | ||
235 | libdir = J(ENV.LUA_DIR_5_2, 'lib'); | ||
236 | libs = {'lua52'}; | ||
237 | } | ||
238 | end) | ||
239 | |||
240 | lake.define_need('lua51', function() | ||
241 | return { | ||
242 | incdir = J(ENV.LUA_DIR, 'include'); | ||
243 | libdir = J(ENV.LUA_DIR, 'lib'); | ||
244 | libs = {'lua5.1'}; | ||
245 | } | ||
246 | end) | ||
247 | |||
248 | lake.define_need('pthread', function() | ||
249 | return { | ||
250 | libs = 'pthread'; | ||
251 | } | ||
252 | end) \ No newline at end of file | ||
diff --git a/llthreads2/lakefile b/llthreads2/lakefile new file mode 100644 index 0000000..64bd3fa --- /dev/null +++ b/llthreads2/lakefile | |||
@@ -0,0 +1,45 @@ | |||
1 | PROJECT = 'llthreads' | ||
2 | |||
3 | INITLAKEFILE() | ||
4 | |||
5 | DEFINES = L{DEFINES, | ||
6 | IF(WINDOWS, 'DLL_EXPORT', ''); | ||
7 | IF(not MSVC, 'USE_PTHREAD', ''); | ||
8 | } | ||
9 | |||
10 | core = c.shared{PROJECT, | ||
11 | base = 'src', | ||
12 | src = '*.c', | ||
13 | needs = LUA_NEED, | ||
14 | defines = DEFINES, | ||
15 | dynamic = DYNAMIC, | ||
16 | strip = true, | ||
17 | libs = IF(not MSVC, 'pthread'); | ||
18 | } | ||
19 | |||
20 | target('build', core) | ||
21 | |||
22 | install = target('install', { | ||
23 | file.group{odir=LIBDIR; src = core }; | ||
24 | file.group{odir=TESTDIR; src = J('test', '*'); recurse = true }; | ||
25 | }) | ||
26 | |||
27 | target('test', install, function() | ||
28 | -- run_test('test_register_llthreads.lua') | ||
29 | run_test('test_join_timeout.lua') | ||
30 | run_test('test_llthreads.lua') | ||
31 | run_test('test_table_copy.lua') | ||
32 | run_test('test_threads.lua') | ||
33 | run_test('test_join_timeout.lua') | ||
34 | run_test('test_join_detach.lua') | ||
35 | run_test('test_join_error.lua') | ||
36 | run_test('test_register_ffi.lua') | ||
37 | run_test('test_logger.lua') | ||
38 | run_test('test_pass_cfunction.lua') | ||
39 | run_test('test_alive.lua') | ||
40 | |||
41 | if not test_summary() then | ||
42 | quit("test fail") | ||
43 | end | ||
44 | end) | ||
45 | |||
diff --git a/llthreads2/msvc/llthreads.sln b/llthreads2/msvc/llthreads.sln new file mode 100644 index 0000000..1277174 --- /dev/null +++ b/llthreads2/msvc/llthreads.sln | |||
@@ -0,0 +1,20 @@ | |||
1 |  | ||
2 | Microsoft Visual Studio Solution File, Format Version 10.00 | ||
3 | # Visual Studio 2008 | ||
4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "llthreads", "llthreads.vcproj", "{60F3B657-C1F7-47F7-B159-3EEEA6B1220D}" | ||
5 | EndProject | ||
6 | Global | ||
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
8 | Debug|Win32 = Debug|Win32 | ||
9 | Release|Win32 = Release|Win32 | ||
10 | EndGlobalSection | ||
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
12 | {60F3B657-C1F7-47F7-B159-3EEEA6B1220D}.Debug|Win32.ActiveCfg = Debug|Win32 | ||
13 | {60F3B657-C1F7-47F7-B159-3EEEA6B1220D}.Debug|Win32.Build.0 = Debug|Win32 | ||
14 | {60F3B657-C1F7-47F7-B159-3EEEA6B1220D}.Release|Win32.ActiveCfg = Release|Win32 | ||
15 | {60F3B657-C1F7-47F7-B159-3EEEA6B1220D}.Release|Win32.Build.0 = Release|Win32 | ||
16 | EndGlobalSection | ||
17 | GlobalSection(SolutionProperties) = preSolution | ||
18 | HideSolutionNode = FALSE | ||
19 | EndGlobalSection | ||
20 | EndGlobal | ||
diff --git a/llthreads2/msvc/llthreads.vcproj b/llthreads2/msvc/llthreads.vcproj new file mode 100644 index 0000000..6f6c5bd --- /dev/null +++ b/llthreads2/msvc/llthreads.vcproj | |||
@@ -0,0 +1,208 @@ | |||
1 | <?xml version="1.0" encoding="windows-1251"?> | ||
2 | <VisualStudioProject | ||
3 | ProjectType="Visual C++" | ||
4 | Version="9,00" | ||
5 | Name="llthreads" | ||
6 | ProjectGUID="{60F3B657-C1F7-47F7-B159-3EEEA6B1220D}" | ||
7 | RootNamespace="llthreads" | ||
8 | Keyword="Win32Proj" | ||
9 | TargetFrameworkVersion="196613" | ||
10 | > | ||
11 | <Platforms> | ||
12 | <Platform | ||
13 | Name="Win32" | ||
14 | /> | ||
15 | </Platforms> | ||
16 | <ToolFiles> | ||
17 | </ToolFiles> | ||
18 | <Configurations> | ||
19 | <Configuration | ||
20 | Name="Debug|Win32" | ||
21 | OutputDirectory="$(SolutionDir)$(ConfigurationName)" | ||
22 | IntermediateDirectory="$(ConfigurationName)" | ||
23 | ConfigurationType="2" | ||
24 | CharacterSet="1" | ||
25 | > | ||
26 | <Tool | ||
27 | Name="VCPreBuildEventTool" | ||
28 | /> | ||
29 | <Tool | ||
30 | Name="VCCustomBuildTool" | ||
31 | /> | ||
32 | <Tool | ||
33 | Name="VCXMLDataGeneratorTool" | ||
34 | /> | ||
35 | <Tool | ||
36 | Name="VCWebServiceProxyGeneratorTool" | ||
37 | /> | ||
38 | <Tool | ||
39 | Name="VCMIDLTool" | ||
40 | /> | ||
41 | <Tool | ||
42 | Name="VCCLCompilerTool" | ||
43 | Optimization="0" | ||
44 | AdditionalIncludeDirectories="$(LUA_DIR_5_2)\include" | ||
45 | PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LLTHREADS_EXPORTS" | ||
46 | MinimalRebuild="true" | ||
47 | BasicRuntimeChecks="3" | ||
48 | RuntimeLibrary="3" | ||
49 | UsePrecompiledHeader="0" | ||
50 | WarningLevel="3" | ||
51 | DebugInformationFormat="4" | ||
52 | /> | ||
53 | <Tool | ||
54 | Name="VCManagedResourceCompilerTool" | ||
55 | /> | ||
56 | <Tool | ||
57 | Name="VCResourceCompilerTool" | ||
58 | /> | ||
59 | <Tool | ||
60 | Name="VCPreLinkEventTool" | ||
61 | /> | ||
62 | <Tool | ||
63 | Name="VCLinkerTool" | ||
64 | AdditionalOptions="/EXPORT:luaopen_llthreads" | ||
65 | AdditionalDependencies="lua52.lib" | ||
66 | LinkIncremental="2" | ||
67 | AdditionalLibraryDirectories="$(LUA_DIR_5_2)\lib" | ||
68 | GenerateDebugInformation="true" | ||
69 | SubSystem="2" | ||
70 | TargetMachine="1" | ||
71 | /> | ||
72 | <Tool | ||
73 | Name="VCALinkTool" | ||
74 | /> | ||
75 | <Tool | ||
76 | Name="VCManifestTool" | ||
77 | /> | ||
78 | <Tool | ||
79 | Name="VCXDCMakeTool" | ||
80 | /> | ||
81 | <Tool | ||
82 | Name="VCBscMakeTool" | ||
83 | /> | ||
84 | <Tool | ||
85 | Name="VCFxCopTool" | ||
86 | /> | ||
87 | <Tool | ||
88 | Name="VCAppVerifierTool" | ||
89 | /> | ||
90 | <Tool | ||
91 | Name="VCPostBuildEventTool" | ||
92 | /> | ||
93 | </Configuration> | ||
94 | <Configuration | ||
95 | Name="Release|Win32" | ||
96 | OutputDirectory="$(SolutionDir)$(ConfigurationName)" | ||
97 | IntermediateDirectory="$(ConfigurationName)" | ||
98 | ConfigurationType="2" | ||
99 | CharacterSet="1" | ||
100 | WholeProgramOptimization="1" | ||
101 | > | ||
102 | <Tool | ||
103 | Name="VCPreBuildEventTool" | ||
104 | /> | ||
105 | <Tool | ||
106 | Name="VCCustomBuildTool" | ||
107 | /> | ||
108 | <Tool | ||
109 | Name="VCXMLDataGeneratorTool" | ||
110 | /> | ||
111 | <Tool | ||
112 | Name="VCWebServiceProxyGeneratorTool" | ||
113 | /> | ||
114 | <Tool | ||
115 | Name="VCMIDLTool" | ||
116 | /> | ||
117 | <Tool | ||
118 | Name="VCCLCompilerTool" | ||
119 | Optimization="2" | ||
120 | EnableIntrinsicFunctions="true" | ||
121 | AdditionalIncludeDirectories="$(LUA_DIR_5_2)\include" | ||
122 | PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LLTHREADS_EXPORTS" | ||
123 | RuntimeLibrary="2" | ||
124 | EnableFunctionLevelLinking="true" | ||
125 | UsePrecompiledHeader="0" | ||
126 | WarningLevel="3" | ||
127 | DebugInformationFormat="3" | ||
128 | /> | ||
129 | <Tool | ||
130 | Name="VCManagedResourceCompilerTool" | ||
131 | /> | ||
132 | <Tool | ||
133 | Name="VCResourceCompilerTool" | ||
134 | /> | ||
135 | <Tool | ||
136 | Name="VCPreLinkEventTool" | ||
137 | /> | ||
138 | <Tool | ||
139 | Name="VCLinkerTool" | ||
140 | AdditionalDependencies="lua52.lib" | ||
141 | LinkIncremental="1" | ||
142 | AdditionalLibraryDirectories="$(LUA_DIR_5_2)\lib" | ||
143 | GenerateDebugInformation="true" | ||
144 | SubSystem="2" | ||
145 | OptimizeReferences="2" | ||
146 | EnableCOMDATFolding="2" | ||
147 | TargetMachine="1" | ||
148 | /> | ||
149 | <Tool | ||
150 | Name="VCALinkTool" | ||
151 | /> | ||
152 | <Tool | ||
153 | Name="VCManifestTool" | ||
154 | /> | ||
155 | <Tool | ||
156 | Name="VCXDCMakeTool" | ||
157 | /> | ||
158 | <Tool | ||
159 | Name="VCBscMakeTool" | ||
160 | /> | ||
161 | <Tool | ||
162 | Name="VCFxCopTool" | ||
163 | /> | ||
164 | <Tool | ||
165 | Name="VCAppVerifierTool" | ||
166 | /> | ||
167 | <Tool | ||
168 | Name="VCPostBuildEventTool" | ||
169 | /> | ||
170 | </Configuration> | ||
171 | </Configurations> | ||
172 | <References> | ||
173 | </References> | ||
174 | <Files> | ||
175 | <Filter | ||
176 | Name="Source Files" | ||
177 | Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" | ||
178 | UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" | ||
179 | > | ||
180 | </Filter> | ||
181 | <Filter | ||
182 | Name="Header Files" | ||
183 | Filter="h;hpp;hxx;hm;inl;inc;xsd" | ||
184 | UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" | ||
185 | > | ||
186 | <File | ||
187 | RelativePath="..\src\l52util.h" | ||
188 | > | ||
189 | </File> | ||
190 | </Filter> | ||
191 | <Filter | ||
192 | Name="Resource Files" | ||
193 | Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" | ||
194 | UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" | ||
195 | > | ||
196 | <File | ||
197 | RelativePath="..\src\l52util.c" | ||
198 | > | ||
199 | </File> | ||
200 | <File | ||
201 | RelativePath="..\src\llthread.c" | ||
202 | > | ||
203 | </File> | ||
204 | </Filter> | ||
205 | </Files> | ||
206 | <Globals> | ||
207 | </Globals> | ||
208 | </VisualStudioProject> | ||
diff --git a/llthreads2/rockspecs/lua-llthreads2-0.1.0-1.rockspec b/llthreads2/rockspecs/lua-llthreads2-0.1.0-1.rockspec new file mode 100644 index 0000000..9116d6a --- /dev/null +++ b/llthreads2/rockspecs/lua-llthreads2-0.1.0-1.rockspec | |||
@@ -0,0 +1,44 @@ | |||
1 | package = "lua-llthreads2" | ||
2 | version = "0.1.0-1" | ||
3 | source = { | ||
4 | url = "https://github.com/moteus/lua-llthreads2/archive/v0.1.0.zip", | ||
5 | dir = "lua-llthreads2-0.1.0", | ||
6 | } | ||
7 | description = { | ||
8 | summary = "Low-Level threads for Lua", | ||
9 | homepage = "http://github.com/moteus/lua-llthreads2", | ||
10 | license = "MIT/X11", | ||
11 | detailed = [[ | ||
12 | This is drop-in replacement for `lua-llthread` module but the module called `llthreads2`. | ||
13 | In additional module supports: thread join with zero timeout; logging thread errors with | ||
14 | custom logger; run detached joinable threads; pass cfunctions as argument to child thread. | ||
15 | ]], | ||
16 | } | ||
17 | dependencies = { | ||
18 | "lua >= 5.1, < 5.3", | ||
19 | } | ||
20 | build = { | ||
21 | type = "builtin", | ||
22 | platforms = { | ||
23 | unix = { | ||
24 | modules = { | ||
25 | llthreads2 = { | ||
26 | libraries = {"pthread"}, | ||
27 | } | ||
28 | } | ||
29 | }, | ||
30 | windows = { | ||
31 | modules = { | ||
32 | llthreads2 = { | ||
33 | libraries = {"kernel32"}, | ||
34 | } | ||
35 | } | ||
36 | } | ||
37 | }, | ||
38 | modules = { | ||
39 | llthreads2 = { | ||
40 | sources = { "src/l52util.c", "src/llthread.c" }, | ||
41 | defines = { "LLTHREAD_MODULE_NAME=llthreads2" }, | ||
42 | } | ||
43 | } | ||
44 | } \ No newline at end of file | ||
diff --git a/llthreads2/rockspecs/lua-llthreads2-0.1.1-1.rockspec b/llthreads2/rockspecs/lua-llthreads2-0.1.1-1.rockspec new file mode 100644 index 0000000..af74686 --- /dev/null +++ b/llthreads2/rockspecs/lua-llthreads2-0.1.1-1.rockspec | |||
@@ -0,0 +1,44 @@ | |||
1 | package = "lua-llthreads2" | ||
2 | version = "0.1.1-1" | ||
3 | source = { | ||
4 | url = "https://github.com/moteus/lua-llthreads2/archive/v0.1.1.zip", | ||
5 | dir = "lua-llthreads2-0.1.1", | ||
6 | } | ||
7 | description = { | ||
8 | summary = "Low-Level threads for Lua", | ||
9 | homepage = "http://github.com/moteus/lua-llthreads2", | ||
10 | license = "MIT/X11", | ||
11 | detailed = [[ | ||
12 | This is drop-in replacement for `lua-llthread` module but the module called `llthreads2`. | ||
13 | In additional module supports: thread join with zero timeout; logging thread errors with | ||
14 | custom logger; run detached joinable threads; pass cfunctions as argument to child thread. | ||
15 | ]], | ||
16 | } | ||
17 | dependencies = { | ||
18 | "lua >= 5.1, < 5.3", | ||
19 | } | ||
20 | build = { | ||
21 | type = "builtin", | ||
22 | platforms = { | ||
23 | unix = { | ||
24 | modules = { | ||
25 | llthreads2 = { | ||
26 | libraries = {"pthread"}, | ||
27 | } | ||
28 | } | ||
29 | }, | ||
30 | windows = { | ||
31 | modules = { | ||
32 | llthreads2 = { | ||
33 | libraries = {"kernel32"}, | ||
34 | } | ||
35 | } | ||
36 | } | ||
37 | }, | ||
38 | modules = { | ||
39 | llthreads2 = { | ||
40 | sources = { "src/l52util.c", "src/llthread.c" }, | ||
41 | defines = { "LLTHREAD_MODULE_NAME=llthreads2" }, | ||
42 | } | ||
43 | } | ||
44 | } \ No newline at end of file | ||
diff --git a/llthreads2/rockspecs/lua-llthreads2-compat-0.1.0-1.rockspec b/llthreads2/rockspecs/lua-llthreads2-compat-0.1.0-1.rockspec new file mode 100644 index 0000000..0c058ea --- /dev/null +++ b/llthreads2/rockspecs/lua-llthreads2-compat-0.1.0-1.rockspec | |||
@@ -0,0 +1,44 @@ | |||
1 | package = "lua-llthreads2-compat" | ||
2 | version = "0.1.0-1" | ||
3 | source = { | ||
4 | url = "https://github.com/moteus/lua-llthreads2/archive/v0.1.0.zip", | ||
5 | dir = "lua-llthreads2-0.1.0", | ||
6 | } | ||
7 | description = { | ||
8 | summary = "Low-Level threads for Lua", | ||
9 | homepage = "http://github.com/moteus/lua-llthreads2", | ||
10 | license = "MIT/X11", | ||
11 | detailed = [[ | ||
12 | This is drop-in replacement for `lua-llthread` module. | ||
13 | In additional module supports: thread join with zero timeout; logging thread errors with | ||
14 | custom logger; run detached joinable threads; pass cfunctions as argument to child thread. | ||
15 | ]], | ||
16 | } | ||
17 | dependencies = { | ||
18 | "lua >= 5.1, < 5.3", | ||
19 | } | ||
20 | build = { | ||
21 | type = "builtin", | ||
22 | platforms = { | ||
23 | unix = { | ||
24 | modules = { | ||
25 | llthreads = { | ||
26 | libraries = {"pthread"}, | ||
27 | } | ||
28 | } | ||
29 | }, | ||
30 | windows = { | ||
31 | modules = { | ||
32 | llthreads = { | ||
33 | libraries = {"kernel32"}, | ||
34 | } | ||
35 | } | ||
36 | } | ||
37 | }, | ||
38 | modules = { | ||
39 | llthreads = { | ||
40 | sources = { "src/l52util.c", "src/llthread.c" }, | ||
41 | defines = { "LLTHREAD_MODULE_NAME=llthreads" }, | ||
42 | } | ||
43 | } | ||
44 | } \ No newline at end of file | ||
diff --git a/llthreads2/rockspecs/lua-llthreads2-compat-0.1.1-1.rockspec b/llthreads2/rockspecs/lua-llthreads2-compat-0.1.1-1.rockspec new file mode 100644 index 0000000..75ef40e --- /dev/null +++ b/llthreads2/rockspecs/lua-llthreads2-compat-0.1.1-1.rockspec | |||
@@ -0,0 +1,44 @@ | |||
1 | package = "lua-llthreads2-compat" | ||
2 | version = "0.1.1-1" | ||
3 | source = { | ||
4 | url = "https://github.com/moteus/lua-llthreads2/archive/v0.1.1.zip", | ||
5 | dir = "lua-llthreads2-0.1.1", | ||
6 | } | ||
7 | description = { | ||
8 | summary = "Low-Level threads for Lua", | ||
9 | homepage = "http://github.com/moteus/lua-llthreads2", | ||
10 | license = "MIT/X11", | ||
11 | detailed = [[ | ||
12 | This is drop-in replacement for `lua-llthread` module. | ||
13 | In additional module supports: thread join with zero timeout; logging thread errors with | ||
14 | custom logger; run detached joinable threads; pass cfunctions as argument to child thread. | ||
15 | ]], | ||
16 | } | ||
17 | dependencies = { | ||
18 | "lua >= 5.1, < 5.3", | ||
19 | } | ||
20 | build = { | ||
21 | type = "builtin", | ||
22 | platforms = { | ||
23 | unix = { | ||
24 | modules = { | ||
25 | llthreads = { | ||
26 | libraries = {"pthread"}, | ||
27 | } | ||
28 | } | ||
29 | }, | ||
30 | windows = { | ||
31 | modules = { | ||
32 | llthreads = { | ||
33 | libraries = {"kernel32"}, | ||
34 | } | ||
35 | } | ||
36 | } | ||
37 | }, | ||
38 | modules = { | ||
39 | llthreads = { | ||
40 | sources = { "src/l52util.c", "src/llthread.c" }, | ||
41 | defines = { "LLTHREAD_MODULE_NAME=llthreads" }, | ||
42 | } | ||
43 | } | ||
44 | } \ No newline at end of file | ||
diff --git a/llthreads2/rockspecs/lua-llthreads2-compat-scm-0.rockspec b/llthreads2/rockspecs/lua-llthreads2-compat-scm-0.rockspec new file mode 100644 index 0000000..ac81a15 --- /dev/null +++ b/llthreads2/rockspecs/lua-llthreads2-compat-scm-0.rockspec | |||
@@ -0,0 +1,44 @@ | |||
1 | package = "lua-llthreads2-compat" | ||
2 | version = "scm-0" | ||
3 | source = { | ||
4 | url = "https://github.com/moteus/lua-llthreads2/archive/master.zip", | ||
5 | dir = "lua-llthreads2-master", | ||
6 | } | ||
7 | description = { | ||
8 | summary = "Low-Level threads for Lua", | ||
9 | homepage = "http://github.com/moteus/lua-llthreads2", | ||
10 | license = "MIT/X11", | ||
11 | detailed = [[ | ||
12 | This is drop-in replacement for `lua-llthread` module. | ||
13 | In additional module supports: thread join with zero timeout; logging thread errors with | ||
14 | custom logger; run detached joinable threads; pass cfunctions as argument to child thread. | ||
15 | ]], | ||
16 | } | ||
17 | dependencies = { | ||
18 | "lua >= 5.1, < 5.3", | ||
19 | } | ||
20 | build = { | ||
21 | type = "builtin", | ||
22 | platforms = { | ||
23 | unix = { | ||
24 | modules = { | ||
25 | llthreads = { | ||
26 | libraries = {"pthread"}, | ||
27 | } | ||
28 | } | ||
29 | }, | ||
30 | windows = { | ||
31 | modules = { | ||
32 | llthreads = { | ||
33 | libraries = {"kernel32"}, | ||
34 | } | ||
35 | } | ||
36 | } | ||
37 | }, | ||
38 | modules = { | ||
39 | llthreads = { | ||
40 | sources = { "src/l52util.c", "src/llthread.c" }, | ||
41 | defines = { "LLTHREAD_MODULE_NAME=llthreads" }, | ||
42 | } | ||
43 | } | ||
44 | } \ No newline at end of file | ||
diff --git a/llthreads2/rockspecs/lua-llthreads2-scm-0.rockspec b/llthreads2/rockspecs/lua-llthreads2-scm-0.rockspec new file mode 100644 index 0000000..87f9b15 --- /dev/null +++ b/llthreads2/rockspecs/lua-llthreads2-scm-0.rockspec | |||
@@ -0,0 +1,44 @@ | |||
1 | package = "lua-llthreads2" | ||
2 | version = "scm-0" | ||
3 | source = { | ||
4 | url = "https://github.com/moteus/lua-llthreads2/archive/master.zip", | ||
5 | dir = "lua-llthreads2-master", | ||
6 | } | ||
7 | description = { | ||
8 | summary = "Low-Level threads for Lua", | ||
9 | homepage = "http://github.com/moteus/lua-llthreads2", | ||
10 | license = "MIT/X11", | ||
11 | detailed = [[ | ||
12 | This is drop-in replacement for `lua-llthread` module but the module called `llthreads2`. | ||
13 | In additional module supports: thread join with zero timeout; logging thread errors with | ||
14 | custom logger; run detached joinable threads; pass cfunctions as argument to child thread. | ||
15 | ]], | ||
16 | } | ||
17 | dependencies = { | ||
18 | "lua >= 5.1, < 5.3", | ||
19 | } | ||
20 | build = { | ||
21 | type = "builtin", | ||
22 | platforms = { | ||
23 | unix = { | ||
24 | modules = { | ||
25 | llthreads2 = { | ||
26 | libraries = {"pthread"}, | ||
27 | } | ||
28 | } | ||
29 | }, | ||
30 | windows = { | ||
31 | modules = { | ||
32 | llthreads2 = { | ||
33 | libraries = {"kernel32"}, | ||
34 | } | ||
35 | } | ||
36 | } | ||
37 | }, | ||
38 | modules = { | ||
39 | llthreads2 = { | ||
40 | sources = { "src/l52util.c", "src/llthread.c" }, | ||
41 | defines = { "LLTHREAD_MODULE_NAME=llthreads2" }, | ||
42 | } | ||
43 | } | ||
44 | } \ No newline at end of file | ||
diff --git a/llthreads2/src/copy.inc b/llthreads2/src/copy.inc new file mode 100644 index 0000000..21ba261 --- /dev/null +++ b/llthreads2/src/copy.inc | |||
@@ -0,0 +1,170 @@ | |||
1 | /****************************************************************************** | ||
2 | * Copyright (c) 2011 by Robert G. Jakabosky <bobby@sharedrealm.com> | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
5 | * of this software and associated documentation files (the "Software"), to deal | ||
6 | * in the Software without restriction, including without limitation the rights | ||
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
8 | * copies of the Software, and to permit persons to whom the Software is | ||
9 | * furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
20 | * THE SOFTWARE. | ||
21 | ******************************************************************************/ | ||
22 | |||
23 | /* maximum recursive depth of table copies. */ | ||
24 | #define MAX_COPY_DEPTH 30 | ||
25 | |||
26 | typedef struct { | ||
27 | lua_State *from_L; | ||
28 | lua_State *to_L; | ||
29 | int has_cache; | ||
30 | int cache_idx; | ||
31 | int is_arg; | ||
32 | } llthread_copy_state; | ||
33 | |||
34 | static int llthread_copy_table_from_cache(llthread_copy_state *state, int idx) { | ||
35 | void *ptr; | ||
36 | |||
37 | /* convert table to pointer for lookup in cache. */ | ||
38 | ptr = (void *)lua_topointer(state->from_L, idx); | ||
39 | if(ptr == NULL) return 0; /* can't convert to pointer. */ | ||
40 | |||
41 | /* check if we need to create the cache. */ | ||
42 | if(!state->has_cache) { | ||
43 | lua_newtable(state->to_L); | ||
44 | lua_replace(state->to_L, state->cache_idx); | ||
45 | state->has_cache = 1; | ||
46 | } | ||
47 | |||
48 | lua_pushlightuserdata(state->to_L, ptr); | ||
49 | lua_rawget(state->to_L, state->cache_idx); | ||
50 | if(lua_isnil(state->to_L, -1)) { | ||
51 | /* not in cache. */ | ||
52 | lua_pop(state->to_L, 1); | ||
53 | /* create new table and add to cache. */ | ||
54 | lua_newtable(state->to_L); | ||
55 | lua_pushlightuserdata(state->to_L, ptr); | ||
56 | lua_pushvalue(state->to_L, -2); | ||
57 | lua_rawset(state->to_L, state->cache_idx); | ||
58 | return 0; | ||
59 | } | ||
60 | /* found table in cache. */ | ||
61 | return 1; | ||
62 | } | ||
63 | |||
64 | static int llthread_copy_value(llthread_copy_state *state, int depth, int idx) { | ||
65 | const char *str; | ||
66 | size_t str_len; | ||
67 | int kv_pos; | ||
68 | |||
69 | /* Maximum recursive depth */ | ||
70 | if(++depth > MAX_COPY_DEPTH) { | ||
71 | return luaL_error(state->from_L, "Hit maximum copy depth (%d > %d).", depth, MAX_COPY_DEPTH); | ||
72 | } | ||
73 | |||
74 | /* only support string/number/boolean/nil/table/lightuserdata. */ | ||
75 | switch(lua_type(state->from_L, idx)) { | ||
76 | case LUA_TNIL: | ||
77 | lua_pushnil(state->to_L); | ||
78 | break; | ||
79 | case LUA_TNUMBER: | ||
80 | lua_pushnumber(state->to_L, lua_tonumber(state->from_L, idx)); | ||
81 | break; | ||
82 | case LUA_TBOOLEAN: | ||
83 | lua_pushboolean(state->to_L, lua_toboolean(state->from_L, idx)); | ||
84 | break; | ||
85 | case LUA_TSTRING: | ||
86 | str = lua_tolstring(state->from_L, idx, &(str_len)); | ||
87 | lua_pushlstring(state->to_L, str, str_len); | ||
88 | break; | ||
89 | case LUA_TLIGHTUSERDATA: | ||
90 | lua_pushlightuserdata(state->to_L, lua_touserdata(state->from_L, idx)); | ||
91 | break; | ||
92 | case LUA_TTABLE: | ||
93 | /* make sure there is room on the new state for 3 values (table,key,value) */ | ||
94 | if(!lua_checkstack(state->to_L, 3)) { | ||
95 | return luaL_error(state->from_L, "To stack overflow!"); | ||
96 | } | ||
97 | /* make room on from stack for key/value pairs. */ | ||
98 | luaL_checkstack(state->from_L, 2, "From stack overflow!"); | ||
99 | |||
100 | /* check cache for table. */ | ||
101 | if(llthread_copy_table_from_cache(state, idx)) { | ||
102 | /* found in cache don't need to copy table. */ | ||
103 | break; | ||
104 | } | ||
105 | lua_pushnil(state->from_L); | ||
106 | while (lua_next(state->from_L, idx) != 0) { | ||
107 | /* key is at (top - 1), value at (top), but we need to normalize these | ||
108 | * to positive indices */ | ||
109 | kv_pos = lua_gettop(state->from_L); | ||
110 | /* copy key */ | ||
111 | llthread_copy_value(state, depth, kv_pos - 1); | ||
112 | /* copy value */ | ||
113 | llthread_copy_value(state, depth, kv_pos); | ||
114 | /* Copied key and value are now at -2 and -1 in state->to_L. */ | ||
115 | lua_settable(state->to_L, -3); | ||
116 | /* Pop value for next iteration */ | ||
117 | lua_pop(state->from_L, 1); | ||
118 | } | ||
119 | break; | ||
120 | case LUA_TFUNCTION: | ||
121 | if(lua_iscfunction(state->from_L, idx)){ | ||
122 | lua_CFunction fn = lua_tocfunction(state->from_L, idx); | ||
123 | lua_pushcfunction(state->to_L, fn); | ||
124 | break; | ||
125 | } | ||
126 | case LUA_TUSERDATA: | ||
127 | case LUA_TTHREAD: | ||
128 | default: | ||
129 | if (state->is_arg) { | ||
130 | return luaL_argerror(state->from_L, idx, "function/userdata/thread types un-supported."); | ||
131 | } else { | ||
132 | /* convert un-supported types to an error string. */ | ||
133 | lua_pushfstring(state->to_L, "Un-supported value: %s: %p", | ||
134 | lua_typename(state->from_L, lua_type(state->from_L, idx)), lua_topointer(state->from_L, idx)); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | return 1; | ||
139 | } | ||
140 | |||
141 | static int llthread_copy_values(lua_State *from_L, lua_State *to_L, int idx, int top, int is_arg) { | ||
142 | llthread_copy_state state; | ||
143 | int nvalues = 0; | ||
144 | int n; | ||
145 | |||
146 | nvalues = (top - idx) + 1; | ||
147 | /* make sure there is room on the new state for the values. */ | ||
148 | if(!lua_checkstack(to_L, nvalues + 1)) { | ||
149 | return luaL_error(from_L, "To stack overflow!"); | ||
150 | } | ||
151 | |||
152 | /* setup copy state. */ | ||
153 | state.from_L = from_L; | ||
154 | state.to_L = to_L; | ||
155 | state.is_arg = is_arg; | ||
156 | state.has_cache = 0; /* don't create cache table unless it is needed. */ | ||
157 | lua_pushnil(to_L); | ||
158 | state.cache_idx = lua_gettop(to_L); | ||
159 | |||
160 | nvalues = 0; | ||
161 | for(n = idx; n <= top; n++) { | ||
162 | llthread_copy_value(&state, 0, n); | ||
163 | ++nvalues; | ||
164 | } | ||
165 | |||
166 | /* remove cache table. */ | ||
167 | lua_remove(to_L, state.cache_idx); | ||
168 | |||
169 | return nvalues; | ||
170 | } | ||
diff --git a/llthreads2/src/l52util.c b/llthreads2/src/l52util.c new file mode 100644 index 0000000..9d44a40 --- /dev/null +++ b/llthreads2/src/l52util.c | |||
@@ -0,0 +1,126 @@ | |||
1 | #include "l52util.h" | ||
2 | |||
3 | #include <memory.h> | ||
4 | #include <assert.h> | ||
5 | |||
6 | #if LUA_VERSION_NUM >= 502 | ||
7 | |||
8 | int luaL_typerror (lua_State *L, int narg, const char *tname) { | ||
9 | const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, | ||
10 | luaL_typename(L, narg)); | ||
11 | return luaL_argerror(L, narg, msg); | ||
12 | } | ||
13 | |||
14 | #ifndef luaL_register | ||
15 | |||
16 | void luaL_register (lua_State *L, const char *libname, const luaL_Reg *l){ | ||
17 | if(libname) lua_newtable(L); | ||
18 | luaL_setfuncs(L, l, 0); | ||
19 | } | ||
20 | |||
21 | #endif | ||
22 | |||
23 | #else | ||
24 | |||
25 | void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup){ | ||
26 | luaL_checkstack(L, nup, "too many upvalues"); | ||
27 | for (; l->name != NULL; l++) { /* fill the table with given functions */ | ||
28 | int i; | ||
29 | for (i = 0; i < nup; i++) /* copy upvalues to the top */ | ||
30 | lua_pushvalue(L, -nup); | ||
31 | lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ | ||
32 | lua_setfield(L, -(nup + 2), l->name); | ||
33 | } | ||
34 | lua_pop(L, nup); /* remove upvalues */ | ||
35 | } | ||
36 | |||
37 | void lua_rawgetp(lua_State *L, int index, const void *p){ | ||
38 | index = lua_absindex(L, index); | ||
39 | lua_pushlightuserdata(L, (void *)p); | ||
40 | lua_rawget(L, index); | ||
41 | } | ||
42 | |||
43 | void lua_rawsetp (lua_State *L, int index, const void *p){ | ||
44 | index = lua_absindex(L, index); | ||
45 | lua_pushlightuserdata(L, (void *)p); | ||
46 | lua_insert(L, -2); | ||
47 | lua_rawset(L, index); | ||
48 | } | ||
49 | |||
50 | void lutil_require(lua_State *L, const char* name, lua_CFunction fn, int glb) { | ||
51 | // @fixme generate error if we can not load module | ||
52 | lua_cpcall(L, fn, NULL); | ||
53 | } | ||
54 | |||
55 | #endif | ||
56 | |||
57 | int lutil_newmetatablep (lua_State *L, const void *p) { | ||
58 | lua_rawgetp(L, LUA_REGISTRYINDEX, p); | ||
59 | if (!lua_isnil(L, -1)) /* name already in use? */ | ||
60 | return 0; /* leave previous value on top, but return 0 */ | ||
61 | lua_pop(L, 1); | ||
62 | |||
63 | lua_newtable(L); /* create metatable */ | ||
64 | lua_pushvalue(L, -1); /* duplicate metatable to set*/ | ||
65 | lua_rawsetp(L, LUA_REGISTRYINDEX, p); | ||
66 | |||
67 | return 1; | ||
68 | } | ||
69 | |||
70 | void lutil_getmetatablep (lua_State *L, const void *p) { | ||
71 | lua_rawgetp(L, LUA_REGISTRYINDEX, p); | ||
72 | } | ||
73 | |||
74 | void lutil_setmetatablep (lua_State *L, const void *p) { | ||
75 | lutil_getmetatablep(L, p); | ||
76 | assert(lua_istable(L,-1)); | ||
77 | lua_setmetatable (L, -2); | ||
78 | } | ||
79 | |||
80 | int lutil_isudatap (lua_State *L, int ud, const void *p) { | ||
81 | if (lua_isuserdata(L, ud)){ | ||
82 | if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ | ||
83 | int res; | ||
84 | lutil_getmetatablep(L,p); /* get correct metatable */ | ||
85 | res = lua_rawequal(L, -1, -2); /* does it have the correct mt? */ | ||
86 | lua_pop(L, 2); /* remove both metatables */ | ||
87 | return res; | ||
88 | } | ||
89 | } | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | void *lutil_checkudatap (lua_State *L, int ud, const void *p) { | ||
94 | void *up = lua_touserdata(L, ud); | ||
95 | if (up != NULL) { /* value is a userdata? */ | ||
96 | if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ | ||
97 | lutil_getmetatablep(L,p); /* get correct metatable */ | ||
98 | if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ | ||
99 | lua_pop(L, 2); /* remove both metatables */ | ||
100 | return up; | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | luaL_typerror(L, ud, p); /* else error */ | ||
105 | return NULL; /* to avoid warnings */ | ||
106 | } | ||
107 | |||
108 | int lutil_createmetap (lua_State *L, const void *p, const luaL_Reg *methods, int nup) { | ||
109 | if (!lutil_newmetatablep(L, p)) | ||
110 | return 0; | ||
111 | |||
112 | lua_insert(L, -1 - nup); /* move mt prior upvalues */ | ||
113 | luaL_setfuncs (L, methods, nup); /* define methods */ | ||
114 | lua_pushliteral (L, "__index"); /* define metamethods */ | ||
115 | lua_pushvalue (L, -2); | ||
116 | lua_settable (L, -3); | ||
117 | |||
118 | return 1; | ||
119 | } | ||
120 | |||
121 | void *lutil_newudatap_impl(lua_State *L, size_t size, const void *p){ | ||
122 | void *obj = lua_newuserdata (L, size); | ||
123 | memset(obj, 0, size); | ||
124 | lutil_setmetatablep(L, p); | ||
125 | return obj; | ||
126 | } | ||
diff --git a/llthreads2/src/l52util.h b/llthreads2/src/l52util.h new file mode 100644 index 0000000..38a87db --- /dev/null +++ b/llthreads2/src/l52util.h | |||
@@ -0,0 +1,57 @@ | |||
1 | #ifndef _LZUTILS_H_9B43D914_9652_4E22_9A43_8073502BF3F4_ | ||
2 | #define _LZUTILS_H_9B43D914_9652_4E22_9A43_8073502BF3F4_ | ||
3 | |||
4 | #include "lua.h" | ||
5 | #include "lauxlib.h" | ||
6 | |||
7 | #if LUA_VERSION_NUM >= 502 // lua 5.2 | ||
8 | |||
9 | // lua_rawgetp | ||
10 | // lua_rawsetp | ||
11 | // luaL_setfuncs | ||
12 | // lua_absindex | ||
13 | |||
14 | #ifndef lua_objlen | ||
15 | |||
16 | #define lua_objlen lua_rawlen | ||
17 | |||
18 | #endif | ||
19 | |||
20 | int luaL_typerror (lua_State *L, int narg, const char *tname); | ||
21 | |||
22 | #ifndef luaL_register | ||
23 | |||
24 | void luaL_register (lua_State *L, const char *libname, const luaL_Reg *l); | ||
25 | |||
26 | #endif | ||
27 | |||
28 | #define lutil_require luaL_requiref | ||
29 | |||
30 | #else // lua 5.1 | ||
31 | |||
32 | // functions form lua 5.2 | ||
33 | |||
34 | # define lua_absindex(L, i) (((i)>0)?(i):((i)<=LUA_REGISTRYINDEX?(i):(lua_gettop(L)+(i)+1))) | ||
35 | # define lua_rawlen lua_objlen | ||
36 | |||
37 | void lua_rawgetp (lua_State *L, int index, const void *p); | ||
38 | void lua_rawsetp (lua_State *L, int index, const void *p); | ||
39 | void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup); | ||
40 | |||
41 | void lutil_require(lua_State *L, const char* name, lua_CFunction fn, int glb); | ||
42 | |||
43 | #endif | ||
44 | |||
45 | int lutil_newmetatablep (lua_State *L, const void *p); | ||
46 | void lutil_getmetatablep (lua_State *L, const void *p); | ||
47 | void lutil_setmetatablep (lua_State *L, const void *p); | ||
48 | |||
49 | #define lutil_newudatap(L, TTYPE, TNAME) (TTYPE *)lutil_newudatap_impl(L, sizeof(TTYPE), TNAME) | ||
50 | int lutil_isudatap (lua_State *L, int ud, const void *p); | ||
51 | void *lutil_checkudatap (lua_State *L, int ud, const void *p); | ||
52 | int lutil_createmetap (lua_State *L, const void *p, const luaL_Reg *methods, int nup); | ||
53 | |||
54 | void *lutil_newudatap_impl (lua_State *L, size_t size, const void *p); | ||
55 | |||
56 | #endif | ||
57 | |||
diff --git a/llthreads2/src/llthread.c b/llthreads2/src/llthread.c new file mode 100644 index 0000000..0ffa727 --- /dev/null +++ b/llthreads2/src/llthread.c | |||
@@ -0,0 +1,746 @@ | |||
1 | #if !defined(_WIN32) && !defined(USE_PTHREAD) | ||
2 | # define USE_PTHREAD | ||
3 | #endif | ||
4 | |||
5 | #define LLTHREAD_VERSION_MAJOR 0 | ||
6 | #define LLTHREAD_VERSION_MINOR 1 | ||
7 | #define LLTHREAD_VERSION_PATCH 0 | ||
8 | #define LLTHREAD_VERSION_COMMENT "" | ||
9 | |||
10 | #ifndef USE_PTHREAD | ||
11 | # include <windows.h> | ||
12 | # include <process.h> | ||
13 | #else | ||
14 | # include <pthread.h> | ||
15 | #endif | ||
16 | |||
17 | #include <stdlib.h> | ||
18 | #include <stdio.h> | ||
19 | #include <memory.h> | ||
20 | #include <assert.h> | ||
21 | #include <errno.h> | ||
22 | #include <lualib.h> | ||
23 | #include "l52util.h" | ||
24 | #include "traceback.inc" | ||
25 | #include "copy.inc" | ||
26 | |||
27 | /*export*/ | ||
28 | #ifdef _WIN32 | ||
29 | # define LLTHREADS_EXPORT_API __declspec(dllexport) | ||
30 | #else | ||
31 | # define LLTHREADS_EXPORT_API LUALIB_API | ||
32 | #endif | ||
33 | |||
34 | /* wrap strerror_s(). */ | ||
35 | #ifdef _WIN32 | ||
36 | # ifdef __GNUC__ | ||
37 | # ifndef strerror_r | ||
38 | # define strerror_r(errno, buf, buflen) do { \ | ||
39 | strncpy((buf), strerror(errno), (buflen)-1); \ | ||
40 | (buf)[(buflen)-1] = '\0'; \ | ||
41 | } while(0) | ||
42 | # endif | ||
43 | # else | ||
44 | # ifndef strerror_r | ||
45 | # define strerror_r(errno, buf, buflen) strerror_s((buf), (buflen), (errno)) | ||
46 | # endif | ||
47 | # endif | ||
48 | #endif | ||
49 | |||
50 | #ifndef USE_PTHREAD | ||
51 | # define OS_THREAD_RETURN unsigned int __stdcall | ||
52 | # define INVALID_THREAD INVALID_HANDLE_VALUE | ||
53 | # define INFINITE_JOIN_TIMEOUT INFINITE | ||
54 | # define JOIN_OK 0 | ||
55 | # define JOIN_ETIMEDOUT 1 | ||
56 | # define JOIN_FAIL 2 | ||
57 | typedef DWORD join_timeout_t; | ||
58 | typedef HANDLE os_thread_t; | ||
59 | #else | ||
60 | # define OS_THREAD_RETURN void * | ||
61 | # define INFINITE_JOIN_TIMEOUT -1 | ||
62 | # define JOIN_OK 0 | ||
63 | # define JOIN_ETIMEDOUT ETIMEDOUT | ||
64 | typedef int join_timeout_t; | ||
65 | typedef pthread_t os_thread_t; | ||
66 | #endif | ||
67 | |||
68 | #define ERROR_LEN 1024 | ||
69 | |||
70 | #define flags_t unsigned char | ||
71 | |||
72 | #define FLAG_NONE (flags_t)0 | ||
73 | #define FLAG_STARTED (flags_t)1<<0 | ||
74 | #define FLAG_DETACHED (flags_t)1<<1 | ||
75 | #define FLAG_JOINED (flags_t)1<<2 | ||
76 | #define FLAG_JOINABLE (flags_t)1<<3 | ||
77 | |||
78 | /*At least one flag*/ | ||
79 | #define FLAG_IS_SET(O, F) (O->flags & (flags_t)(F)) | ||
80 | #define FLAG_SET(O, F) O->flags |= (flags_t)(F) | ||
81 | #define FLAG_UNSET(O, F) O->flags &= ~((flags_t)(F)) | ||
82 | #define IS(O, F) FLAG_IS_SET(O, FLAG_##F) | ||
83 | #define SET(O, F) FLAG_SET(O, FLAG_##F) | ||
84 | |||
85 | #define ALLOC_STRUCT(S) (S*)calloc(1, sizeof(S)) | ||
86 | #define FREE_STRUCT(O) free(O) | ||
87 | |||
88 | #ifndef LLTHREAD_MODULE_NAME | ||
89 | # define LLTHREAD_MODULE_NAME llthreads | ||
90 | #endif | ||
91 | |||
92 | #define CAT(S1,S2) S1##S2 | ||
93 | |||
94 | #define LLTHREAD_OPEN_NAME_IMPL(NAME) CAT(luaopen_, NAME) | ||
95 | |||
96 | #define LLTHREAD_OPEN_NAME LLTHREAD_OPEN_NAME_IMPL(LLTHREAD_MODULE_NAME) | ||
97 | |||
98 | LLTHREADS_EXPORT_API int LLTHREAD_OPEN_NAME(lua_State *L); | ||
99 | |||
100 | #define LLTHREAD_NAME "LLThread" | ||
101 | static const char *LLTHREAD_TAG = LLTHREAD_NAME; | ||
102 | static const char *LLTHREAD_LOGGER_HOLDER = LLTHREAD_NAME " logger holder"; | ||
103 | |||
104 | typedef struct llthread_child_t { | ||
105 | lua_State *L; | ||
106 | int status; | ||
107 | flags_t flags; | ||
108 | } llthread_child_t; | ||
109 | |||
110 | typedef struct llthread_t { | ||
111 | llthread_child_t *child; | ||
112 | os_thread_t thread; | ||
113 | flags_t flags; | ||
114 | } llthread_t; | ||
115 | |||
116 | static int fail(lua_State *L, const char *msg){ | ||
117 | lua_pushnil(L); | ||
118 | lua_pushstring(L, msg); | ||
119 | return 2; | ||
120 | } | ||
121 | |||
122 | //{ logger interface | ||
123 | void llthread_log(lua_State *L, const char *hdr, const char *msg){ | ||
124 | int top = lua_gettop(L); | ||
125 | lua_rawgetp(L, LUA_REGISTRYINDEX, LLTHREAD_LOGGER_HOLDER); | ||
126 | if(lua_isnil(L, -1)){ | ||
127 | lua_pop(L, 1); | ||
128 | fputs(hdr, stderr); | ||
129 | fputs(msg, stderr); | ||
130 | fputc('\n', stderr); | ||
131 | fflush(stderr); | ||
132 | return; | ||
133 | } | ||
134 | lua_pushstring(L, hdr); | ||
135 | lua_pushstring(L, msg); | ||
136 | lua_concat(L, 2); | ||
137 | lua_pcall(L, 1, 0, 0); | ||
138 | lua_settop(L, top); | ||
139 | } | ||
140 | //} | ||
141 | |||
142 | //{ llthread_child | ||
143 | |||
144 | static void open_thread_libs(lua_State *L){ | ||
145 | #define L_REGLIB(L, name) lua_pushcfunction(L, luaopen_##name); lua_setfield(L, -2) | ||
146 | |||
147 | int top = lua_gettop(L); | ||
148 | |||
149 | #ifndef LLTHREAD_REGISTER_STD_LIBRARY | ||
150 | |||
151 | luaL_openlibs(L); | ||
152 | lua_getglobal(L, "package"); lua_getfield(L, -1, "preload"); lua_remove(L, -2); | ||
153 | |||
154 | #else | ||
155 | |||
156 | lutil_require(L, "_G", luaopen_base, 1); | ||
157 | lutil_require(L, "package", luaopen_package, 1); | ||
158 | lua_settop(L, top); | ||
159 | |||
160 | /* get package.preload */ | ||
161 | lua_getglobal(L, "package"); lua_getfield(L, -1, "preload"); lua_remove(L, -2); | ||
162 | L_REGLIB(L, io, 1); | ||
163 | L_REGLIB(L, os, 1); | ||
164 | L_REGLIB(L, math, 1); | ||
165 | L_REGLIB(L, table, 1); | ||
166 | L_REGLIB(L, string, 1); | ||
167 | |||
168 | #ifdef LUA_DBLIBNAME | ||
169 | L_REGLIB(L, debug, 1); | ||
170 | #endif | ||
171 | |||
172 | /* @fixme find out luaopen_XXX at runtime */ | ||
173 | #ifdef LUA_JITLIBNAME | ||
174 | L_REGLIB(L, bit, 1); | ||
175 | L_REGLIB(L, jit, 1); | ||
176 | L_REGLIB(L, ffi, 1); | ||
177 | #elif defined LUA_BITLIBNAME | ||
178 | L_REGLIB(L, bit32, 1); | ||
179 | #endif | ||
180 | |||
181 | #endif | ||
182 | |||
183 | #ifdef LLTHREAD_REGISTER_THREAD_LIBRARY | ||
184 | L_REGLIB(L, llthreads, 0); | ||
185 | #endif | ||
186 | |||
187 | lua_settop(L, top); | ||
188 | |||
189 | #undef L_REGLIB | ||
190 | } | ||
191 | |||
192 | static llthread_child_t *llthread_child_new() { | ||
193 | llthread_child_t *this = ALLOC_STRUCT(llthread_child_t); | ||
194 | if(!this) return NULL; | ||
195 | |||
196 | memset(this, 0, sizeof(llthread_child_t)); | ||
197 | |||
198 | /* create new lua_State for the thread. */ | ||
199 | /* open standard libraries. */ | ||
200 | this->L = luaL_newstate(); | ||
201 | open_thread_libs(this->L); | ||
202 | |||
203 | return this; | ||
204 | } | ||
205 | |||
206 | static void llthread_child_destroy(llthread_child_t *this) { | ||
207 | lua_close(this->L); | ||
208 | FREE_STRUCT(this); | ||
209 | } | ||
210 | |||
211 | static OS_THREAD_RETURN llthread_child_thread_run(void *arg) { | ||
212 | llthread_child_t *this = (llthread_child_t *)arg; | ||
213 | lua_State *L = this->L; | ||
214 | int nargs = lua_gettop(L) - 1; | ||
215 | |||
216 | /* push traceback function as first value on stack. */ | ||
217 | lua_pushcfunction(this->L, traceback); | ||
218 | lua_insert(L, 1); | ||
219 | |||
220 | this->status = lua_pcall(L, nargs, LUA_MULTRET, 1); | ||
221 | |||
222 | /* alwasy print errors here, helps with debugging bad code. */ | ||
223 | if(this->status != 0) { | ||
224 | llthread_log(L, "Error from thread: ", lua_tostring(L, -1)); | ||
225 | } | ||
226 | |||
227 | if(IS(this, DETACHED) || !IS(this, JOINABLE)) { | ||
228 | /* thread is detached, so it must clean-up the child state. */ | ||
229 | llthread_child_destroy(this); | ||
230 | this = NULL; | ||
231 | } | ||
232 | |||
233 | #ifndef USE_PTHREAD | ||
234 | if(this) { | ||
235 | /* attached thread, don't close thread handle. */ | ||
236 | _endthreadex(0); | ||
237 | } else { | ||
238 | /* detached thread, close thread handle. */ | ||
239 | _endthread(); | ||
240 | } | ||
241 | return 0; | ||
242 | #else | ||
243 | return this; | ||
244 | #endif | ||
245 | } | ||
246 | |||
247 | //} | ||
248 | |||
249 | //{ llthread | ||
250 | |||
251 | static void llthread_validate(llthread_t *this){ | ||
252 | /* describe valid state of llthread_t object | ||
253 | * from after create and before destroy | ||
254 | */ | ||
255 | if(!IS(this, STARTED)){ | ||
256 | assert(!IS(this, DETACHED)); | ||
257 | assert(!IS(this, JOINED)); | ||
258 | assert(!IS(this, JOINABLE)); | ||
259 | return; | ||
260 | } | ||
261 | |||
262 | if(IS(this, DETACHED)){ | ||
263 | if(!IS(this, JOINABLE)) assert(this->child == NULL); | ||
264 | else assert(this->child != NULL); | ||
265 | } | ||
266 | } | ||
267 | |||
268 | static int llthread_detach(llthread_t *this); | ||
269 | |||
270 | static int llthread_join(llthread_t *this, join_timeout_t timeout); | ||
271 | |||
272 | static llthread_t *llthread_new() { | ||
273 | llthread_t *this = ALLOC_STRUCT(llthread_t); | ||
274 | if(!this) return NULL; | ||
275 | |||
276 | this->flags = FLAG_NONE; | ||
277 | #ifndef USE_PTHREAD | ||
278 | this->thread = INVALID_THREAD; | ||
279 | #endif | ||
280 | this->child = llthread_child_new(); | ||
281 | if(!this->child){ | ||
282 | FREE_STRUCT(this); | ||
283 | return NULL; | ||
284 | } | ||
285 | |||
286 | return this; | ||
287 | } | ||
288 | |||
289 | static void llthread_cleanup_child(llthread_t *this) { | ||
290 | if(this->child) { | ||
291 | llthread_child_destroy(this->child); | ||
292 | this->child = NULL; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | static void llthread_destroy(llthread_t *this) { | ||
297 | do{ | ||
298 | /* thread not started */ | ||
299 | if(!IS(this, STARTED)){ | ||
300 | llthread_cleanup_child(this); | ||
301 | break; | ||
302 | } | ||
303 | |||
304 | /* DETACHED */ | ||
305 | if(IS(this, DETACHED)){ | ||
306 | if(IS(this, JOINABLE)){ | ||
307 | llthread_detach(this); | ||
308 | } | ||
309 | break; | ||
310 | } | ||
311 | |||
312 | /* ATTACHED */ | ||
313 | if(!IS(this, JOINED)){ | ||
314 | llthread_join(this, INFINITE_JOIN_TIMEOUT); | ||
315 | if(!IS(this, JOINED)){ | ||
316 | /* @todo use current lua state to logging */ | ||
317 | /* | ||
318 | * char buf[ERROR_LEN]; | ||
319 | * strerror_r(errno, buf, ERROR_LEN); | ||
320 | * llthread_log(L, "Error can not join thread on gc: ", buf); | ||
321 | */ | ||
322 | } | ||
323 | } | ||
324 | if(IS(this, JOINABLE)){ | ||
325 | llthread_cleanup_child(this); | ||
326 | } | ||
327 | |||
328 | }while(0); | ||
329 | |||
330 | FREE_STRUCT(this); | ||
331 | } | ||
332 | |||
333 | static int llthread_push_args(lua_State *L, llthread_child_t *child, int idx, int top) { | ||
334 | return llthread_copy_values(L, child->L, idx, top, 1 /* is_arg */); | ||
335 | } | ||
336 | |||
337 | static int llthread_push_results(lua_State *L, llthread_child_t *child, int idx, int top) { | ||
338 | return llthread_copy_values(child->L, L, idx, top, 0 /* is_arg */); | ||
339 | } | ||
340 | |||
341 | static int llthread_detach(llthread_t *this){ | ||
342 | int rc = 0; | ||
343 | |||
344 | assert(IS(this, STARTED)); | ||
345 | assert(this->child != NULL); | ||
346 | |||
347 | this->child = NULL; | ||
348 | |||
349 | /*we can not detach joined thread*/ | ||
350 | if(IS(this, JOINED)) | ||
351 | return 0; | ||
352 | |||
353 | #ifdef USE_PTHREAD | ||
354 | rc = pthread_detach(this->thread); | ||
355 | #else | ||
356 | assert(this->thread != INVALID_THREAD); | ||
357 | CloseHandle(this->thread); | ||
358 | this->thread = INVALID_THREAD; | ||
359 | #endif | ||
360 | return rc; | ||
361 | } | ||
362 | |||
363 | /* | detached | joinable || join | which thread | gc | detach | | ||
364 | * | | || return | destroy child | calls | on | | ||
365 | * ------------------------------------------------------------------------ | ||
366 | * | false | falas || <NONE> | child | join | <NEVER> | | ||
367 | * *| false | true || Lua values | parent | join | <NEVER> | | ||
368 | * *| true | false || <ERROR> | child | <NONE> | start | | ||
369 | * | true | true || <NONE> | child | detach | gc | | ||
370 | * ------------------------------------------------------------------------ | ||
371 | * * llthread behavior. | ||
372 | */ | ||
373 | static int llthread_start(llthread_t *this, int start_detached, int joinable) { | ||
374 | llthread_child_t *child = this->child; | ||
375 | int rc = 0; | ||
376 | |||
377 | llthread_validate(this); | ||
378 | |||
379 | if(joinable) SET(child, JOINABLE); | ||
380 | if(start_detached) SET(child, DETACHED); | ||
381 | |||
382 | #ifndef USE_PTHREAD | ||
383 | this->thread = (HANDLE)_beginthreadex(NULL, 0, llthread_child_thread_run, child, 0, NULL); | ||
384 | if(INVALID_THREAD == this->thread){ | ||
385 | rc = -1; | ||
386 | } | ||
387 | #else | ||
388 | rc = pthread_create(&(this->thread), NULL, llthread_child_thread_run, child); | ||
389 | #endif | ||
390 | |||
391 | if(rc == 0) { | ||
392 | SET(this, STARTED); | ||
393 | if(joinable) SET(this, JOINABLE); | ||
394 | if(start_detached) SET(this, DETACHED); | ||
395 | if((start_detached)&&(!joinable)){ | ||
396 | rc = llthread_detach(this); | ||
397 | } | ||
398 | } | ||
399 | |||
400 | llthread_validate(this); | ||
401 | |||
402 | return rc; | ||
403 | } | ||
404 | |||
405 | static int llthread_join(llthread_t *this, join_timeout_t timeout) { | ||
406 | llthread_validate(this); | ||
407 | |||
408 | if(IS(this, JOINED)){ | ||
409 | return JOIN_OK; | ||
410 | } else{ | ||
411 | #ifndef USE_PTHREAD | ||
412 | DWORD ret = 0; | ||
413 | if(INVALID_THREAD == this->thread) return JOIN_OK; | ||
414 | ret = WaitForSingleObject( this->thread, timeout ); | ||
415 | if( ret == WAIT_OBJECT_0){ /* Destroy the thread object. */ | ||
416 | CloseHandle( this->thread ); | ||
417 | this->thread = INVALID_THREAD; | ||
418 | SET(this, JOINED); | ||
419 | |||
420 | llthread_validate(this); | ||
421 | |||
422 | return JOIN_OK; | ||
423 | } | ||
424 | else if( ret == WAIT_TIMEOUT ){ | ||
425 | return JOIN_ETIMEDOUT; | ||
426 | } | ||
427 | return JOIN_FAIL; | ||
428 | #else | ||
429 | int rc; | ||
430 | if(timeout == 0){ | ||
431 | rc = pthread_kill(this->thread, 0); | ||
432 | if(rc == 0){ /* still alive */ | ||
433 | return JOIN_ETIMEDOUT; | ||
434 | } | ||
435 | |||
436 | if(rc != ESRCH){ | ||
437 | /*@fixme what else it can be ?*/ | ||
438 | return rc; | ||
439 | } | ||
440 | |||
441 | /*thread dead so we call join to free pthread_t struct */ | ||
442 | } | ||
443 | |||
444 | /* @todo use pthread_tryjoin_np/pthread_timedjoin_np to support timeout */ | ||
445 | |||
446 | /* then join the thread. */ | ||
447 | rc = pthread_join(this->thread, NULL); | ||
448 | if((rc == 0) || (rc == ESRCH)) { | ||
449 | SET(this, JOINED); | ||
450 | rc = JOIN_OK; | ||
451 | } | ||
452 | |||
453 | llthread_validate(this); | ||
454 | |||
455 | return rc; | ||
456 | #endif | ||
457 | } | ||
458 | } | ||
459 | |||
460 | static int llthread_alive(llthread_t *this) { | ||
461 | llthread_validate(this); | ||
462 | |||
463 | if(IS(this, JOINED)){ | ||
464 | return JOIN_OK; | ||
465 | } else{ | ||
466 | #ifndef USE_PTHREAD | ||
467 | DWORD ret = 0; | ||
468 | if(INVALID_THREAD == this->thread) return JOIN_OK; | ||
469 | ret = WaitForSingleObject( this->thread, 0 ); | ||
470 | if( ret == WAIT_OBJECT_0) return JOIN_OK; | ||
471 | if( ret == WAIT_TIMEOUT ) return JOIN_ETIMEDOUT; | ||
472 | return JOIN_FAIL; | ||
473 | #else | ||
474 | int rc = pthread_kill(this->thread, 0); | ||
475 | if(rc == 0){ /* still alive */ | ||
476 | return JOIN_ETIMEDOUT; | ||
477 | } | ||
478 | |||
479 | if(rc != ESRCH){ | ||
480 | /*@fixme what else it can be ?*/ | ||
481 | return rc; | ||
482 | } | ||
483 | |||
484 | return JOIN_OK; | ||
485 | #endif | ||
486 | } | ||
487 | } | ||
488 | |||
489 | static llthread_t *llthread_create(lua_State *L, const char *code, size_t code_len) { | ||
490 | llthread_t *this = llthread_new(); | ||
491 | llthread_child_t *child = this->child; | ||
492 | |||
493 | /* load Lua code into child state. */ | ||
494 | int rc = luaL_loadbuffer(child->L, code, code_len, code); | ||
495 | if(rc != 0) { | ||
496 | /* copy error message to parent state. */ | ||
497 | size_t len; const char *str = lua_tolstring(child->L, -1, &len); | ||
498 | if(str != NULL) { | ||
499 | lua_pushlstring(L, str, len); | ||
500 | } else { | ||
501 | /* non-string error message. */ | ||
502 | lua_pushfstring(L, "luaL_loadbuffer() failed to load Lua code: rc=%d", rc); | ||
503 | } | ||
504 | llthread_destroy(this); | ||
505 | lua_error(L); | ||
506 | return NULL; | ||
507 | } | ||
508 | |||
509 | /* copy extra args from main state to child state. */ | ||
510 | /* Push all args after the Lua code. */ | ||
511 | llthread_push_args(L, child, 3, lua_gettop(L)); | ||
512 | |||
513 | llthread_validate(this); | ||
514 | |||
515 | return this; | ||
516 | } | ||
517 | |||
518 | //} | ||
519 | |||
520 | //{ Lua interface to llthread | ||
521 | |||
522 | static llthread_t *l_llthread_at (lua_State *L, int i) { | ||
523 | llthread_t **this = (llthread_t **)lutil_checkudatap (L, i, LLTHREAD_TAG); | ||
524 | luaL_argcheck (L, this != NULL, i, "thread expected"); | ||
525 | luaL_argcheck (L, *this != NULL, i, "thread expected"); | ||
526 | // luaL_argcheck (L, !(counter->flags & FLAG_DESTROYED), 1, "PDH Counter is destroyed"); | ||
527 | return *this; | ||
528 | } | ||
529 | |||
530 | static int l_llthread_delete(lua_State *L) { | ||
531 | llthread_t **pthis = (llthread_t **)lutil_checkudatap (L, 1, LLTHREAD_TAG); | ||
532 | luaL_argcheck (L, pthis != NULL, 1, "thread expected"); | ||
533 | if(*pthis == NULL) return 0; | ||
534 | llthread_destroy(*pthis); | ||
535 | *pthis = NULL; | ||
536 | |||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | static int l_llthread_start(lua_State *L) { | ||
541 | llthread_t *this = l_llthread_at(L, 1); | ||
542 | int start_detached = lua_toboolean(L, 2); | ||
543 | int joinable, rc; | ||
544 | |||
545 | if(!lua_isnone(L, 3)) joinable = lua_toboolean(L, 3); | ||
546 | else joinable = start_detached ? 0 : 1; | ||
547 | |||
548 | if(IS(this, STARTED)) { | ||
549 | return fail(L, "Thread already started."); | ||
550 | } | ||
551 | |||
552 | rc = llthread_start(this, start_detached, joinable); | ||
553 | if(rc != 0) { | ||
554 | char buf[ERROR_LEN]; | ||
555 | strerror_r(errno, buf, ERROR_LEN); | ||
556 | return fail(L, buf); | ||
557 | } | ||
558 | |||
559 | lua_settop(L, 1); // return this | ||
560 | return 1; | ||
561 | } | ||
562 | |||
563 | static int l_llthread_join(lua_State *L) { | ||
564 | llthread_t *this = l_llthread_at(L, 1); | ||
565 | llthread_child_t *child = this->child; | ||
566 | int rc; | ||
567 | |||
568 | if(!IS(this, STARTED )) { | ||
569 | return fail(L, "Can't join a thread that hasn't be started."); | ||
570 | } | ||
571 | if( IS(this, DETACHED) && !IS(this, JOINABLE)) { | ||
572 | return fail(L, "Can't join a thread that has been detached."); | ||
573 | } | ||
574 | if( IS(this, JOINED )) { | ||
575 | return fail(L, "Can't join a thread that has already been joined."); | ||
576 | } | ||
577 | |||
578 | /* join the thread. */ | ||
579 | rc = llthread_join(this, luaL_optint(L, 2, INFINITE_JOIN_TIMEOUT)); | ||
580 | |||
581 | if(child && IS(this, JOINED)) { | ||
582 | int top; | ||
583 | |||
584 | if(IS(this, DETACHED) || !IS(this, JOINABLE)){ | ||
585 | /*child lua state has been destroyed by child thread*/ | ||
586 | /*@todo return thread exit code*/ | ||
587 | lua_pushboolean(L, 1); | ||
588 | lua_pushnumber(L, 0); | ||
589 | return 2; | ||
590 | } | ||
591 | |||
592 | /* copy values from child lua state */ | ||
593 | if(child->status != 0) { | ||
594 | const char *err_msg = lua_tostring(child->L, -1); | ||
595 | lua_pushboolean(L, 0); | ||
596 | lua_pushfstring(L, "Error from child thread: %s", err_msg); | ||
597 | top = 2; | ||
598 | } else { | ||
599 | lua_pushboolean(L, 1); | ||
600 | top = lua_gettop(child->L); | ||
601 | /* return results to parent thread. */ | ||
602 | llthread_push_results(L, child, 2, top); | ||
603 | } | ||
604 | |||
605 | llthread_cleanup_child(this); | ||
606 | return top; | ||
607 | } | ||
608 | |||
609 | if( rc == JOIN_ETIMEDOUT ){ | ||
610 | return fail(L, "timeout"); | ||
611 | } | ||
612 | |||
613 | { | ||
614 | char buf[ERROR_LEN]; | ||
615 | strerror_r(errno, buf, ERROR_LEN); | ||
616 | |||
617 | /* llthread_cleanup_child(this); */ | ||
618 | |||
619 | return fail(L, buf); | ||
620 | } | ||
621 | |||
622 | } | ||
623 | |||
624 | static int l_llthread_alive(lua_State *L) { | ||
625 | llthread_t *this = l_llthread_at(L, 1); | ||
626 | llthread_child_t *child = this->child; | ||
627 | int rc; | ||
628 | |||
629 | if(!IS(this, STARTED )) { | ||
630 | return fail(L, "Can't join a thread that hasn't be started."); | ||
631 | } | ||
632 | if( IS(this, DETACHED) && !IS(this, JOINABLE)) { | ||
633 | return fail(L, "Can't join a thread that has been detached."); | ||
634 | } | ||
635 | if( IS(this, JOINED )) { | ||
636 | return fail(L, "Can't join a thread that has already been joined."); | ||
637 | } | ||
638 | |||
639 | /* join the thread. */ | ||
640 | rc = llthread_alive(this); | ||
641 | |||
642 | if( rc == JOIN_ETIMEDOUT ){ | ||
643 | lua_pushboolean(L, 1); | ||
644 | return 1; | ||
645 | } | ||
646 | |||
647 | if(rc == JOIN_OK){ | ||
648 | lua_pushboolean(L, 0); | ||
649 | return 1; | ||
650 | } | ||
651 | |||
652 | { | ||
653 | char buf[ERROR_LEN]; | ||
654 | strerror_r(errno, buf, ERROR_LEN); | ||
655 | |||
656 | /* llthread_cleanup_child(this); */ | ||
657 | |||
658 | return fail(L, buf); | ||
659 | } | ||
660 | |||
661 | } | ||
662 | |||
663 | static int l_llthread_new(lua_State *L) { | ||
664 | size_t lua_code_len; const char *lua_code = luaL_checklstring(L, 1, &lua_code_len); | ||
665 | llthread_t **this = lutil_newudatap(L, llthread_t*, LLTHREAD_TAG); | ||
666 | lua_insert(L, 2); /*move self prior args*/ | ||
667 | *this = llthread_create(L, lua_code, lua_code_len); | ||
668 | |||
669 | lua_settop(L, 2); | ||
670 | return 1; | ||
671 | } | ||
672 | |||
673 | static const struct luaL_Reg l_llthread_meth[] = { | ||
674 | {"start", l_llthread_start }, | ||
675 | {"join", l_llthread_join }, | ||
676 | {"alive", l_llthread_alive }, | ||
677 | {"__gc", l_llthread_delete }, | ||
678 | |||
679 | {NULL, NULL} | ||
680 | }; | ||
681 | |||
682 | //} | ||
683 | |||
684 | //{ version | ||
685 | |||
686 | static int l_llthread_version(lua_State *L){ | ||
687 | lua_pushnumber(L, LLTHREAD_VERSION_MAJOR); | ||
688 | lua_pushnumber(L, LLTHREAD_VERSION_MINOR); | ||
689 | lua_pushnumber(L, LLTHREAD_VERSION_PATCH); | ||
690 | #ifdef LLTHREAD_VERSION_COMMENT | ||
691 | if(LLTHREAD_VERSION_COMMENT[0]){ | ||
692 | lua_pushliteral(L, LLTHREAD_VERSION_COMMENT); | ||
693 | return 4; | ||
694 | } | ||
695 | #endif | ||
696 | return 3; | ||
697 | } | ||
698 | |||
699 | static int l_llthread_push_version(lua_State *L){ | ||
700 | lua_pushnumber(L, LLTHREAD_VERSION_MAJOR); | ||
701 | lua_pushliteral(L, "."); | ||
702 | lua_pushnumber(L, LLTHREAD_VERSION_MINOR); | ||
703 | lua_pushliteral(L, "."); | ||
704 | lua_pushnumber(L, LLTHREAD_VERSION_PATCH); | ||
705 | #ifdef LLTHREAD_VERSION_COMMENT | ||
706 | if(LLTHREAD_VERSION_COMMENT[0]){ | ||
707 | lua_pushliteral(L, "-"LLTHREAD_VERSION_COMMENT); | ||
708 | lua_concat(L, 6); | ||
709 | } | ||
710 | else | ||
711 | #endif | ||
712 | lua_concat(L, 5); | ||
713 | return 1; | ||
714 | } | ||
715 | |||
716 | //} | ||
717 | |||
718 | static int l_llthread_set_logger(lua_State *L){ | ||
719 | lua_settop(L, 1); | ||
720 | luaL_argcheck(L, lua_isfunction(L, 1), 1, "function expected"); | ||
721 | lua_rawsetp(L, LUA_REGISTRYINDEX, LLTHREAD_LOGGER_HOLDER); | ||
722 | return 0; | ||
723 | } | ||
724 | |||
725 | static const struct luaL_Reg l_llthreads_lib[] = { | ||
726 | {"new", l_llthread_new }, | ||
727 | {"set_logger", l_llthread_set_logger }, | ||
728 | {"version", l_llthread_version }, | ||
729 | |||
730 | {NULL, NULL} | ||
731 | }; | ||
732 | |||
733 | LLTHREADS_EXPORT_API int LLTHREAD_OPEN_NAME(lua_State *L) { | ||
734 | int top = lua_gettop(L); | ||
735 | lutil_createmetap(L, LLTHREAD_TAG, l_llthread_meth, 0); | ||
736 | lua_settop(L, top); | ||
737 | |||
738 | lua_newtable(L); | ||
739 | luaL_setfuncs(L, l_llthreads_lib, 0); | ||
740 | |||
741 | lua_pushliteral(L, "_VERSION"); | ||
742 | l_llthread_push_version(L); | ||
743 | lua_rawset(L, -3); | ||
744 | |||
745 | return 1; | ||
746 | } | ||
diff --git a/llthreads2/src/traceback.inc b/llthreads2/src/traceback.inc new file mode 100644 index 0000000..af2f5a1 --- /dev/null +++ b/llthreads2/src/traceback.inc | |||
@@ -0,0 +1,56 @@ | |||
1 | /****************************************************************************** | ||
2 | * traceback() function from Lua 5.1/5.2 source. | ||
3 | * Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved. | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining | ||
6 | * a copy of this software and associated documentation files (the | ||
7 | * "Software"), to deal in the Software without restriction, including | ||
8 | * without limitation the rights to use, copy, modify, merge, publish, | ||
9 | * distribute, sublicense, and/or sell copies of the Software, and to | ||
10 | * permit persons to whom the Software is furnished to do so, subject to | ||
11 | * the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be | ||
14 | * included in all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
19 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
20 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
21 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
22 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
23 | ******************************************************************************/ | ||
24 | #if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM == 501) | ||
25 | /* from Lua 5.1 */ | ||
26 | static int traceback (lua_State *L) { | ||
27 | if (!lua_isstring(L, 1)) /* 'message' not a string? */ | ||
28 | return 1; /* keep it intact */ | ||
29 | lua_getglobal(L, "debug"); | ||
30 | if (!lua_istable(L, -1)) { | ||
31 | lua_pop(L, 1); | ||
32 | return 1; | ||
33 | } | ||
34 | lua_getfield(L, -1, "traceback"); | ||
35 | if (!lua_isfunction(L, -1)) { | ||
36 | lua_pop(L, 2); | ||
37 | return 1; | ||
38 | } | ||
39 | lua_pushvalue(L, 1); /* pass error message */ | ||
40 | lua_pushinteger(L, 2); /* skip this function and traceback */ | ||
41 | lua_call(L, 2, 1); /* call debug.traceback */ | ||
42 | return 1; | ||
43 | } | ||
44 | #else | ||
45 | /* from Lua 5.2 */ | ||
46 | static int traceback (lua_State *L) { | ||
47 | const char *msg = lua_tostring(L, 1); | ||
48 | if (msg) | ||
49 | luaL_traceback(L, L, msg, 1); | ||
50 | else if (!lua_isnoneornil(L, 1)) { /* is there an error object? */ | ||
51 | if (!luaL_callmeta(L, 1, "__tostring")) /* try its 'tostring' metamethod */ | ||
52 | lua_pushliteral(L, "(no error message)"); | ||
53 | } | ||
54 | return 1; | ||
55 | } | ||
56 | #endif | ||
diff --git a/llthreads2/test/test_alive.lua b/llthreads2/test/test_alive.lua new file mode 100644 index 0000000..ecce163 --- /dev/null +++ b/llthreads2/test/test_alive.lua | |||
@@ -0,0 +1,35 @@ | |||
1 | local llthreads = require"llthreads" | ||
2 | local utils = require "utils" | ||
3 | local sleep = utils.sleep | ||
4 | |||
5 | local include = utils.thread_init .. [[ | ||
6 | local llthreads = require"llthreads" | ||
7 | local sleep = require "utils".sleep | ||
8 | ]] | ||
9 | |||
10 | local thread = llthreads.new(include .. [[ | ||
11 | sleep(5) | ||
12 | return 1,2,3 | ||
13 | ]]) | ||
14 | |||
15 | assert(nil == thread:alive()) | ||
16 | |||
17 | thread:start() | ||
18 | |||
19 | assert(true == thread:alive()) | ||
20 | |||
21 | for i = 1, 10 do | ||
22 | if not thread:alive() then break end | ||
23 | sleep(1) | ||
24 | end | ||
25 | |||
26 | assert(false == thread:alive()) | ||
27 | |||
28 | local ok,a,b,c = thread:join(0) | ||
29 | assert(ok == true) | ||
30 | assert(a == 1) | ||
31 | assert(b == 2) | ||
32 | assert(c == 3) | ||
33 | |||
34 | print("Done!") | ||
35 | |||
diff --git a/llthreads2/test/test_join_detach.lua b/llthreads2/test/test_join_detach.lua new file mode 100644 index 0000000..533a36f --- /dev/null +++ b/llthreads2/test/test_join_detach.lua | |||
@@ -0,0 +1,59 @@ | |||
1 | local llthreads = require"llthreads" | ||
2 | local utils = require "utils" | ||
3 | |||
4 | do | ||
5 | |||
6 | local thread = llthreads.new(utils.thread_init .. [[ | ||
7 | local sleep = require"utils".sleep | ||
8 | while true do sleep(1) end | ||
9 | ]]) | ||
10 | |||
11 | -- detached + joindable | ||
12 | thread:start(true, true) | ||
13 | |||
14 | local ok, err = thread:join(0) | ||
15 | print("thread:join(0): ", ok, err) | ||
16 | assert(ok == nil) | ||
17 | assert(err == "timeout") | ||
18 | |||
19 | end | ||
20 | |||
21 | -- enforce collect `thread` object | ||
22 | -- we should not hungup | ||
23 | for i = 1, 10 do collectgarbage("collect") end | ||
24 | |||
25 | |||
26 | do | ||
27 | |||
28 | local thread = llthreads.new(utils.thread_init .. [[ | ||
29 | local sleep = require"utils".sleep | ||
30 | sleep(1) | ||
31 | ]]) | ||
32 | |||
33 | -- detached + joindable | ||
34 | thread:start(true, true) | ||
35 | |||
36 | local ok, err = thread:join(0) | ||
37 | print("thread:join(0): ", ok, err) | ||
38 | assert(ok == nil) | ||
39 | assert(err == "timeout") | ||
40 | |||
41 | for i = 1, 12 do | ||
42 | utils.sleep(5) | ||
43 | ok, err = thread:join(0) | ||
44 | print("thread:join(0)#" .. i .. ": ", ok, err) | ||
45 | if ok then break end | ||
46 | assert(err == 'timeout') | ||
47 | end | ||
48 | |||
49 | assert(ok) | ||
50 | |||
51 | end | ||
52 | |||
53 | -- enforce collect `thread` object | ||
54 | -- we should not get av | ||
55 | for i = 1, 10 do collectgarbage("collect") end | ||
56 | |||
57 | |||
58 | print("Done!") | ||
59 | |||
diff --git a/llthreads2/test/test_join_error.lua b/llthreads2/test/test_join_error.lua new file mode 100644 index 0000000..90780b1 --- /dev/null +++ b/llthreads2/test/test_join_error.lua | |||
@@ -0,0 +1,24 @@ | |||
1 | local llthreads = require "llthreads" | ||
2 | local utils = require "utils" | ||
3 | local sleep = utils.sleep | ||
4 | |||
5 | local include = utils.thread_init .. [[ | ||
6 | local llthreads = require"llthreads" | ||
7 | local sleep = require "utils".sleep | ||
8 | ]] | ||
9 | |||
10 | local thread = llthreads.new(include .. [[ | ||
11 | sleep(5) | ||
12 | ]]) | ||
13 | |||
14 | thread:start() | ||
15 | |||
16 | local ok, err = thread:join() | ||
17 | assert(ok == true) | ||
18 | assert(err == nil) | ||
19 | |||
20 | local res, ok, err = pcall(thread.join, thread) | ||
21 | assert(res == true) | ||
22 | assert(ok == nil) | ||
23 | assert(err ~= nil) | ||
24 | |||
diff --git a/llthreads2/test/test_join_timeout.lua b/llthreads2/test/test_join_timeout.lua new file mode 100644 index 0000000..b9cf155 --- /dev/null +++ b/llthreads2/test/test_join_timeout.lua | |||
@@ -0,0 +1,23 @@ | |||
1 | local llthreads = require"llthreads" | ||
2 | local utils = require "utils" | ||
3 | local sleep = utils.sleep | ||
4 | |||
5 | local include = utils.thread_init .. [[ | ||
6 | local llthreads = require"llthreads" | ||
7 | local sleep = require "utils".sleep | ||
8 | ]] | ||
9 | |||
10 | local thread = llthreads.new(include .. [[ | ||
11 | sleep(5) | ||
12 | ]]) | ||
13 | thread:start() | ||
14 | local ok, err = thread:join(0) | ||
15 | print("thread:join(0): ", ok, err) | ||
16 | assert(ok == nil) | ||
17 | assert(err == "timeout") | ||
18 | |||
19 | local ok, err = thread:join() | ||
20 | print("thread:join(): ", ok, err) | ||
21 | assert(ok, err) | ||
22 | print("Done!") | ||
23 | |||
diff --git a/llthreads2/test/test_llthreads.lua b/llthreads2/test/test_llthreads.lua new file mode 100644 index 0000000..e0e214b --- /dev/null +++ b/llthreads2/test/test_llthreads.lua | |||
@@ -0,0 +1,60 @@ | |||
1 | -- Copyright (c) 2011 by Robert G. Jakabosky <bobby@sharedrealm.com> | ||
2 | -- | ||
3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy | ||
4 | -- of this software and associated documentation files (the "Software"), to deal | ||
5 | -- in the Software without restriction, including without limitation the rights | ||
6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
7 | -- copies of the Software, and to permit persons to whom the Software is | ||
8 | -- furnished to do so, subject to the following conditions: | ||
9 | -- | ||
10 | -- The above copyright notice and this permission notice shall be included in | ||
11 | -- all copies or substantial portions of the Software. | ||
12 | -- | ||
13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
19 | -- THE SOFTWARE. | ||
20 | |||
21 | local llthreads = require"llthreads" | ||
22 | local sleep = require"utils".sleep | ||
23 | |||
24 | print("LLThreads version : ", llthreads._VERSION) | ||
25 | |||
26 | local function detached_thread(...) | ||
27 | local thread = llthreads.new([[ print("print_detached_thread:", ...) ]], ...) | ||
28 | -- start detached thread | ||
29 | assert(thread:start(true)) | ||
30 | return thread | ||
31 | end | ||
32 | |||
33 | local function print_thread(...) | ||
34 | local thread = llthreads.new([[ print("print_thread:", ...); ]], ...) | ||
35 | -- start joinable thread | ||
36 | assert(thread:start()) | ||
37 | return thread | ||
38 | end | ||
39 | |||
40 | local function pass_through_thread(...) | ||
41 | local thread = llthreads.new([[ return "pass_thread:", ... ]], ...) | ||
42 | -- start joinable thread | ||
43 | assert(thread:start()) | ||
44 | return thread | ||
45 | end | ||
46 | |||
47 | local thread1 = detached_thread("number:", 1234, "nil:", nil, "bool:", true) | ||
48 | |||
49 | sleep(1) | ||
50 | |||
51 | local thread2 = print_thread("number:", 1234, "nil:", nil, "bool:", true) | ||
52 | print("thread2:join: results # = ", select('#', thread2:join())) | ||
53 | |||
54 | sleep(1) | ||
55 | |||
56 | local thread3 = pass_through_thread("number:", 1234, "nil:", nil, "bool:", true) | ||
57 | print("thread3:join:", thread3:join()) | ||
58 | |||
59 | sleep(1) | ||
60 | |||
diff --git a/llthreads2/test/test_load_llthreads2.lua b/llthreads2/test/test_load_llthreads2.lua new file mode 100644 index 0000000..11bf0a0 --- /dev/null +++ b/llthreads2/test/test_load_llthreads2.lua | |||
@@ -0,0 +1,7 @@ | |||
1 | local llthreads = require"llthreads2" | ||
2 | |||
3 | llthreads.new([[ | ||
4 | local os = require "os" | ||
5 | print("Done!") | ||
6 | os.exit(0) | ||
7 | ]]):start():join() \ No newline at end of file | ||
diff --git a/llthreads2/test/test_logger.lua b/llthreads2/test/test_logger.lua new file mode 100644 index 0000000..f85a896 --- /dev/null +++ b/llthreads2/test/test_logger.lua | |||
@@ -0,0 +1,24 @@ | |||
1 | local utils = require "utils" | ||
2 | |||
3 | require "llthreads".new(utils.thread_init .. [[ | ||
4 | require "string" | ||
5 | |||
6 | require "llthreads".set_logger(function(msg) | ||
7 | if type(msg) ~= 'string' then | ||
8 | print("ERROR! Invalid error message: ", msg) | ||
9 | os.exit(-2) | ||
10 | end | ||
11 | if not msg:find("SOME ERROR", nil, true) then | ||
12 | print("ERROR! Invalid error message: ", msg) | ||
13 | os.exit(-1) | ||
14 | end | ||
15 | print("Done!") | ||
16 | os.exit(0) | ||
17 | end) | ||
18 | |||
19 | error("SOME ERROR") | ||
20 | ]]):start():join() | ||
21 | |||
22 | print("ERROR! Logger has not been call!") | ||
23 | os.exit(-1) | ||
24 | |||
diff --git a/llthreads2/test/test_pass_cfunction.lua b/llthreads2/test/test_pass_cfunction.lua new file mode 100644 index 0000000..86fcd3d --- /dev/null +++ b/llthreads2/test/test_pass_cfunction.lua | |||
@@ -0,0 +1,17 @@ | |||
1 | local llthreads = require"llthreads" | ||
2 | local utils = require"utils" | ||
3 | |||
4 | local thread = llthreads.new(utils.thread_init .. [[ | ||
5 | require "llthreads" | ||
6 | local fn = ... | ||
7 | |||
8 | if type(fn) ~= 'function' then | ||
9 | print("ERROR! No function : ", fn, type(fn)) | ||
10 | os.exit(-2) | ||
11 | end | ||
12 | |||
13 | fn("print('Done!'); require'os'.exit(0)"):start():join() | ||
14 | ]], llthreads.new) | ||
15 | |||
16 | print(thread:start():join()) | ||
17 | os.exit(-1) \ No newline at end of file | ||
diff --git a/llthreads2/test/test_register_ffi.lua b/llthreads2/test/test_register_ffi.lua new file mode 100644 index 0000000..e98167f --- /dev/null +++ b/llthreads2/test/test_register_ffi.lua | |||
@@ -0,0 +1,14 @@ | |||
1 | if jit then | ||
2 | local llthreads = require "llthreads" | ||
3 | local thread = llthreads.new([[ | ||
4 | if not package.preload.ffi then | ||
5 | print("ffi does not register in thread") | ||
6 | os.exit(-1) | ||
7 | end | ||
8 | local ok, err = pcall(require, "ffi") | ||
9 | if not ok then | ||
10 | print("can not load ffi: ", err) | ||
11 | os.exit(-2) | ||
12 | end | ||
13 | ]]):start():join() | ||
14 | end | ||
diff --git a/llthreads2/test/test_register_llthreads.lua b/llthreads2/test/test_register_llthreads.lua new file mode 100644 index 0000000..5b234a9 --- /dev/null +++ b/llthreads2/test/test_register_llthreads.lua | |||
@@ -0,0 +1,15 @@ | |||
1 | -- Test if you build module with | ||
2 | -- LLTHREAD_REGISTER_THREAD_LIBRARY | ||
3 | |||
4 | local llthreads = require "llthreads" | ||
5 | local thread = llthreads.new([[ | ||
6 | if not package.preload.llthreads then | ||
7 | print("llthreads does not register in thread") | ||
8 | os.exit(-1) | ||
9 | end | ||
10 | local ok, err = pcall(require, "llthreads") | ||
11 | if not ok then | ||
12 | print("can not load llthreads: ", err) | ||
13 | os.exit(-2) | ||
14 | end | ||
15 | ]]):start():join() | ||
diff --git a/llthreads2/test/test_table_copy.lua b/llthreads2/test/test_table_copy.lua new file mode 100644 index 0000000..0408ad3 --- /dev/null +++ b/llthreads2/test/test_table_copy.lua | |||
@@ -0,0 +1,134 @@ | |||
1 | -- Copyright (c) 2011 by Robert G. Jakabosky <bobby@sharedrealm.com> | ||
2 | -- | ||
3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy | ||
4 | -- of this software and associated documentation files (the "Software"), to deal | ||
5 | -- in the Software without restriction, including without limitation the rights | ||
6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
7 | -- copies of the Software, and to permit persons to whom the Software is | ||
8 | -- furnished to do so, subject to the following conditions: | ||
9 | -- | ||
10 | -- The above copyright notice and this permission notice shall be included in | ||
11 | -- all copies or substantial portions of the Software. | ||
12 | -- | ||
13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
19 | -- THE SOFTWARE. | ||
20 | |||
21 | local llthreads = require"llthreads" | ||
22 | |||
23 | local sleep | ||
24 | local status, socket = pcall(require,"socket") | ||
25 | if status then | ||
26 | sleep = function(secs) | ||
27 | return socket.sleep(secs) | ||
28 | end | ||
29 | else | ||
30 | sleep = function(secs) | ||
31 | os.execute("sleep " .. tonumber(secs)) | ||
32 | end | ||
33 | end | ||
34 | |||
35 | local dump_code = [==[ | ||
36 | local function dump_recur(seen, obj, depth) | ||
37 | local out | ||
38 | local t = type(obj) | ||
39 | -- if not a table just convert to string. | ||
40 | if t ~= "table" then | ||
41 | if t == "string" then | ||
42 | return '"' .. obj .. '"' | ||
43 | end | ||
44 | return tostring(obj) | ||
45 | end | ||
46 | -- check if this table has been seen already. | ||
47 | if seen[obj] then | ||
48 | return "Already dumped " .. tostring(obj) | ||
49 | end | ||
50 | seen[obj] = true | ||
51 | -- restrict max depth. | ||
52 | if depth >= 10 then | ||
53 | return "{... max depth reached ...}" | ||
54 | end | ||
55 | depth = depth + 1 | ||
56 | -- output table key/value pairs | ||
57 | local tabs = string.rep(" ",depth) | ||
58 | local out = "{\n" | ||
59 | for k,v in pairs(obj) do | ||
60 | if type(k) ~= "number" then | ||
61 | out = out .. tabs .. '[' .. dump_recur(seen, k, depth) .. '] = ' .. | ||
62 | dump_recur(seen, v, depth) .. ',\n' | ||
63 | else | ||
64 | out = out .. tabs .. '[' .. k .. '] = ' .. dump_recur(seen, v, depth) .. ',\n' | ||
65 | end | ||
66 | end | ||
67 | return out .. tabs:sub(1,-3) .. "}" | ||
68 | end | ||
69 | |||
70 | local obj = ... | ||
71 | local seen = {} | ||
72 | return dump_recur(seen, obj, 0) | ||
73 | ]==] | ||
74 | |||
75 | local dump = (loadstring or load)(dump_code) | ||
76 | |||
77 | local child_code = [==[ | ||
78 | local dump = (loadstring or load)[[ | ||
79 | ]==] .. dump_code .. [==[ | ||
80 | ]] | ||
81 | local args = ... | ||
82 | |||
83 | print("Child thread args:", dump(args)) | ||
84 | |||
85 | -- return all values. | ||
86 | return ... | ||
87 | ]==] | ||
88 | |||
89 | local function test_thread_value_copying(...) | ||
90 | local args = {...} | ||
91 | print("Main thread args:", dump(args)) | ||
92 | local thread = llthreads.new(child_code, args) | ||
93 | -- start joinable thread | ||
94 | assert(thread:start()) | ||
95 | |||
96 | local status, results = thread:join() | ||
97 | print("Main thread results:", dump(results)) | ||
98 | end | ||
99 | |||
100 | -- create some tables. | ||
101 | local a1 = { "a1" } | ||
102 | local a2 = { "a2" } | ||
103 | local a3 = { "a3" } | ||
104 | local a4 = { "a4" } | ||
105 | local b1 = { a1, a2, a3, a4 } | ||
106 | local b2 = { a1=a1, a2=a2, a3=a3, a4=a4 } | ||
107 | |||
108 | -- | ||
109 | -- no loops | ||
110 | -- | ||
111 | test_thread_value_copying(b1, b2) | ||
112 | |||
113 | local top = {} | ||
114 | -- self reference. | ||
115 | top.top = top | ||
116 | top[top] = top | ||
117 | -- nested reference. | ||
118 | top.sub1 = { sub2 = { sub3 = { top } } } | ||
119 | |||
120 | -- | ||
121 | -- loops | ||
122 | -- | ||
123 | test_thread_value_copying(top) | ||
124 | |||
125 | -- | ||
126 | -- Test max depth | ||
127 | -- | ||
128 | local outer = {} | ||
129 | for n=1,100 do | ||
130 | outer = {outer} | ||
131 | end | ||
132 | local status, err = pcall(test_thread_value_copying,outer) | ||
133 | assert(not status, "Assertion failed: max depth test failed.") | ||
134 | |||
diff --git a/llthreads2/test/test_threads.lua b/llthreads2/test/test_threads.lua new file mode 100644 index 0000000..459604d --- /dev/null +++ b/llthreads2/test/test_threads.lua | |||
@@ -0,0 +1,67 @@ | |||
1 | -- Copyright (c) 2011 by Ross Anderson <ross_j_anderson@yahoo.com> | ||
2 | -- | ||
3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy | ||
4 | -- of this software and associated documentation files (the "Software"), to deal | ||
5 | -- in the Software without restriction, including without limitation the rights | ||
6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
7 | -- copies of the Software, and to permit persons to whom the Software is | ||
8 | -- furnished to do so, subject to the following conditions: | ||
9 | -- | ||
10 | -- The above copyright notice and this permission notice shall be included in | ||
11 | -- all copies or substantial portions of the Software. | ||
12 | -- | ||
13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
19 | -- THE SOFTWARE. | ||
20 | |||
21 | -- Sub-thread processing example in Lua using llthreads - 1,000 quick sub-thread execution | ||
22 | |||
23 | -- luajit sub_threads.lua | ||
24 | |||
25 | local llthreads = require"llthreads" | ||
26 | local utils = require "utils" | ||
27 | |||
28 | local num_threads = tonumber(arg[1] or 1000) | ||
29 | |||
30 | -- level 0 string literal enclosure [[ ]] of child execution code | ||
31 | local thread_code = utils.thread_init .. [[ | ||
32 | |||
33 | local num_threads = ... | ||
34 | print("CHILD: received from ROOT params:", ...) | ||
35 | local llthreads = require"llthreads" -- need to re-declare this under this scope | ||
36 | local t = {} -- thread storage table | ||
37 | |||
38 | -- create a new child sub-thread execution code - it requires level 1 literal string [=[ ]=] enclosures, level 2 would be [==[ ]==] | ||
39 | local executed_child_code = [=[ | ||
40 | return "Hello from child sub-thread, new input params:", ... | ||
41 | ]=] | ||
42 | |||
43 | -- create 1000 sub-threads - which creates an incremental 30% / 20% utilization spike on the two AMD cpu cores | ||
44 | print("CHILD: Create sub threads:", num_threads) | ||
45 | for i=1,num_threads do | ||
46 | -- create child sub-thread with code to execute and the input parmeters | ||
47 | local thread = llthreads.new(executed_child_code , "number:", 1000 + i, "nil:", nil, "bool:", true) | ||
48 | assert(thread:start()) -- start new child sub-thread | ||
49 | table.insert(t, thread) -- append the thread at the end of the thread table | ||
50 | end | ||
51 | |||
52 | -- wait (block) for all child sub-threads to complete before returning to ROOT | ||
53 | while true do | ||
54 | -- always wait on the first element, since order is not important | ||
55 | print("CHILD: sub-thread returned: ", t[1]:join()) | ||
56 | table.remove(t,1) -- always remove the first element | ||
57 | if (#t == 0) then break end | ||
58 | end | ||
59 | return ... -- return the parents' input params back to the root | ||
60 | ]] | ||
61 | |||
62 | -- create child thread. | ||
63 | local thread = llthreads.new(thread_code, num_threads, "number:", 1000, "nil:", nil, "bool:", true) | ||
64 | -- start joinable child thread. | ||
65 | assert(thread:start()) | ||
66 | -- wait for all child and child sub-threads to finish | ||
67 | print("ROOT: child returned: ", thread:join()) | ||
diff --git a/llthreads2/test/utils.lua b/llthreads2/test/utils.lua new file mode 100644 index 0000000..d9b5fe5 --- /dev/null +++ b/llthreads2/test/utils.lua | |||
@@ -0,0 +1,63 @@ | |||
1 | local lua_version_t | ||
2 | local function lua_version() | ||
3 | if not lua_version_t then | ||
4 | local version = rawget(_G,"_VERSION") | ||
5 | local maj,min = version:match("^Lua (%d+)%.(%d+)$") | ||
6 | if maj then lua_version_t = {tonumber(maj),tonumber(min)} | ||
7 | elseif not math.mod then lua_version_t = {5,2} | ||
8 | elseif table.pack and not pack then lua_version_t = {5,2} | ||
9 | else lua_version_t = {5,2} end | ||
10 | end | ||
11 | return lua_version_t[1], lua_version_t[2] | ||
12 | end | ||
13 | |||
14 | local LUA_MAJOR, LUA_MINOR = lua_version() | ||
15 | local IS_LUA_51 = (LUA_MAJOR == 5) and (LUA_MINOR == 1) | ||
16 | local IS_LUA_52 = (LUA_MAJOR == 5) and (LUA_MINOR == 2) | ||
17 | |||
18 | local LUA_INIT = "LUA_INIT" | ||
19 | local LUA_INIT_VER | ||
20 | if not IS_LUA_51 then | ||
21 | LUA_INIT_VER = LUA_INIT .. "_" .. LUA_MAJOR .. "_" .. LUA_MINOR | ||
22 | end | ||
23 | |||
24 | LUA_INIT = LUA_INIT_VER and os.getenv( LUA_INIT_VER ) or os.getenv( LUA_INIT ) or "" | ||
25 | |||
26 | LUA_INIT = [[do | ||
27 | local lua_init = ]] .. ("%q"):format(LUA_INIT) .. [[ | ||
28 | if lua_init and #lua_init > 0 then | ||
29 | if lua_init:sub(1,1) == '@' then | ||
30 | dofile(lua_init:sub(2)) | ||
31 | else | ||
32 | assert((loadstring or load)(lua_init))() | ||
33 | end | ||
34 | end | ||
35 | end;]] | ||
36 | |||
37 | local sleep | ||
38 | local status, socket = pcall(require,"socket") | ||
39 | if status then | ||
40 | sleep = function(secs) | ||
41 | return socket.sleep(secs) | ||
42 | end | ||
43 | end | ||
44 | |||
45 | if not sleep then | ||
46 | local status, ztimer = pcall(require, "lzmq.timer") | ||
47 | if status then | ||
48 | sleep = function(secs) | ||
49 | ztimer.sleep(secs * 1000) | ||
50 | end | ||
51 | end | ||
52 | end | ||
53 | |||
54 | if not sleep then | ||
55 | sleep = function(secs) | ||
56 | os.execute("sleep " .. tonumber(secs)) | ||
57 | end | ||
58 | end | ||
59 | |||
60 | return { | ||
61 | thread_init = LUA_INIT, | ||
62 | sleep = sleep, | ||
63 | } | ||