mirror of
https://github.com/love2d/love.git
synced 2026-08-12 08:30:56 +02:00
Removed lanes.
This commit is contained in:
@@ -3909,98 +3909,6 @@
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="lanes"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\src\libraries\lanes\lanes.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)\libraries\lanes\"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)\libraries\lanes\"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\libraries\lanes\lanes.h"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="lanes"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\src\libraries\lanes\lanes\lanes.c"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)\libraries\lanes\lanes\"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)\libraries\lanes\lanes\"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\libraries\lanes\lanes\threading.c"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)\libraries\lanes\lanes\"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)\libraries\lanes\lanes\"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\libraries\lanes\lanes\tools.c"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)\libraries\lanes\lanes\"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)\libraries\lanes\lanes\"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="scripts"
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
|
||||
#include "lanes.h"
|
||||
|
||||
// Lanes open function.
|
||||
extern "C"
|
||||
{
|
||||
int luaopen_lanes( lua_State *L );
|
||||
}
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace lanes
|
||||
{
|
||||
|
||||
// Opens the lanes.lua file.
|
||||
static int open_lanes(lua_State * L)
|
||||
{
|
||||
#include "lanes/lanes.lua.h"
|
||||
lua_getglobal(L, "lanes");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int open(lua_State * L)
|
||||
{
|
||||
luax_preload(L, open_lanes, "lanes");
|
||||
luax_preload(L, luaopen_lanes, "lua51-lanes");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // lanes
|
||||
} // love
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
|
||||
#ifndef LOVE_LANES_LANES_H
|
||||
#define LOVE_LANES_LANES_H
|
||||
|
||||
// LOVE
|
||||
#include <common/runtime.h>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace lanes
|
||||
{
|
||||
int open(lua_State * L);
|
||||
|
||||
} // lanes
|
||||
} // love
|
||||
|
||||
#endif // LOVE_LANES_LANES_H
|
||||
@@ -1,214 +0,0 @@
|
||||
/* bin2c.lua generated code -- DO NOT EDIT
|
||||
*
|
||||
* To use from C source:
|
||||
* char my_chunk[]=
|
||||
* #include "my.lch"
|
||||
*/
|
||||
{
|
||||
27, 76,117, 97, 81, 0, 1, 4, 4, 4, 8, 0, 12, 0, 0, 0, 64,107,101,101,
|
||||
112,101,114, 46,108,117, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 9,
|
||||
45, 0, 0, 0, 5, 0, 0, 0, 69, 64, 0, 0, 28, 64, 0, 1, 5, 0, 0, 0,
|
||||
69,128, 0, 0, 70,192,192, 0, 28,128, 0, 1, 69, 0, 0, 0,133,128, 0, 0,
|
||||
134, 0, 65, 1, 92,128, 0, 1,164, 0, 0, 0, 0, 0,128, 0,202, 0, 0, 0,
|
||||
10, 1, 0, 0, 74, 1, 0, 0,164, 65, 0, 0, 0, 0,128, 1, 0, 0, 0, 2,
|
||||
0, 0,128, 2,228,129, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 36,194, 0, 0,
|
||||
0, 0, 0, 3, 7, 66, 1, 0, 36, 2, 1, 0, 0, 0, 0, 3, 0, 0, 0, 0,
|
||||
7,130, 1, 0, 36, 66, 1, 0, 0, 0, 0, 3, 7,194, 1, 0, 36,130, 1, 0,
|
||||
0, 0, 0, 3, 7, 2, 2, 0, 36,194, 1, 0, 0, 0, 0, 3, 7, 66, 2, 0,
|
||||
36, 2, 2, 0, 0, 0,128, 1, 0, 0, 0, 2, 0, 0,128, 2, 7,130, 2, 0,
|
||||
30, 0,128, 0, 11, 0, 0, 0, 4, 7, 0, 0, 0, 97,115,115,101,114,116, 0,
|
||||
4, 13, 0, 0, 0,110,105,108, 95,115,101,110,116,105,110,101,108, 0, 4, 6,
|
||||
0, 0, 0,116, 97, 98,108,101, 0, 4, 7, 0, 0, 0,114,101,109,111,118,101,
|
||||
0, 4, 7, 0, 0, 0, 99,111,110, 99, 97,116, 0, 4, 5, 0, 0, 0,115,101,
|
||||
110,100, 0, 4, 8, 0, 0, 0,114,101, 99,101,105,118,101, 0, 4, 6, 0, 0,
|
||||
0,108,105,109,105,116, 0, 4, 4, 0, 0, 0,115,101,116, 0, 4, 4, 0, 0,
|
||||
0,103,101,116, 0, 4, 6, 0, 0, 0, 99,108,101, 97,114, 0, 9, 0, 0, 0,
|
||||
0, 0, 0, 0, 46, 0, 0, 0, 50, 0, 0, 0, 1, 0, 3, 6, 16, 0, 0, 0,
|
||||
69, 0, 0, 0, 90, 0, 0, 0, 22,192, 2,128, 69, 0, 0, 0, 70, 64,192, 0,
|
||||
75,128,192, 0,196, 0, 0, 0, 10, 1, 0, 0,101, 1, 0, 0, 34, 65, 0, 0,
|
||||
65,193, 0, 0,220,128,128, 1, 1, 1, 1, 0,213, 0,129, 1, 92, 64,128, 1,
|
||||
30, 0,128, 0, 5, 0, 0, 0, 4, 3, 0, 0, 0,105,111, 0, 4, 7, 0, 0,
|
||||
0,115,116,100,101,114,114, 0, 4, 6, 0, 0, 0,119,114,105,116,101, 0, 4,
|
||||
2, 0, 0, 0, 9, 0, 4, 2, 0, 0, 0, 10, 0, 0, 0, 0, 0, 16, 0, 0,
|
||||
0, 47, 0, 0, 0, 47, 0, 0, 0, 47, 0, 0, 0, 48, 0, 0, 0, 48, 0, 0,
|
||||
0, 48, 0, 0, 0, 48, 0, 0, 0, 48, 0, 0, 0, 48, 0, 0, 0, 48, 0, 0,
|
||||
0, 48, 0, 0, 0, 48, 0, 0, 0, 48, 0, 0, 0, 48, 0, 0, 0, 48, 0, 0,
|
||||
0, 50, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 97,114,103, 0, 0, 0, 0,
|
||||
0, 15, 0, 0, 0, 1, 0, 0, 0, 13, 0, 0, 0,116, 97, 98,108,101, 95, 99,
|
||||
111,110, 99, 97,116, 0, 0, 0, 0, 0, 84, 0, 0, 0, 93, 0, 0, 0, 3, 1,
|
||||
0, 4, 21, 0, 0, 0, 68, 0, 0, 0, 70, 0,128, 0, 90, 64, 0, 0, 22, 0,
|
||||
2,128, 68, 0, 0, 0,138, 0, 0, 0, 73,128, 0, 0, 68, 0,128, 0,138, 0,
|
||||
0, 0, 73,128, 0, 0, 68, 0, 0, 1,138, 0, 0, 0, 73,128, 0, 0, 68, 0,
|
||||
0, 0, 70, 0,128, 0,132, 0,128, 0,134, 0, 0, 1,196, 0, 0, 1,198, 0,
|
||||
128, 1, 94, 0, 0, 2, 30, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0,
|
||||
0, 0, 87, 0, 0, 0, 87, 0, 0, 0, 87, 0, 0, 0, 87, 0, 0, 0, 88, 0,
|
||||
0, 0, 88, 0, 0, 0, 88, 0, 0, 0, 89, 0, 0, 0, 89, 0, 0, 0, 89, 0,
|
||||
0, 0, 90, 0, 0, 0, 90, 0, 0, 0, 90, 0, 0, 0, 92, 0, 0, 0, 92, 0,
|
||||
0, 0, 92, 0, 0, 0, 92, 0, 0, 0, 92, 0, 0, 0, 92, 0, 0, 0, 92, 0,
|
||||
0, 0, 93, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0,117,100, 0, 0, 0, 0,
|
||||
0, 20, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 95,100, 97,116, 97, 0, 10,
|
||||
0, 0, 0, 95,105,110, 99,111,109,105,110,103, 0, 8, 0, 0, 0, 95,108,105,
|
||||
109,105,116,115, 0, 0, 0, 0, 0, 96, 0, 0, 0,106, 0, 0, 0, 2, 3, 0,
|
||||
16, 40, 0, 0, 0,197, 0, 0, 0, 27, 1, 0, 0, 22,128, 0,128, 27, 1,128,
|
||||
0, 22, 0, 0,128, 0, 1, 0, 1,220, 64, 0, 1,196, 0, 0, 0, 0, 1,128,
|
||||
0,220, 0, 1, 1,133, 65, 0, 0,198,129,128, 1,156,129, 0, 1,197,129, 0,
|
||||
0, 6,130, 0, 2, 26, 66, 0, 0, 22, 0, 0,128, 10, 2, 0, 0,220, 1, 1,
|
||||
1, 22, 64, 1,128, 0, 3, 0, 3, 65,195, 0, 0,133, 67, 0, 0,192, 3,128,
|
||||
5,156,131, 0, 1,149,129, 3, 6,225,129, 0, 0, 22,192,253,127,196, 1,128,
|
||||
0, 1, 2, 1, 0, 64, 2, 0, 0,129, 66, 1, 0,197, 66, 0, 0, 0, 3, 0,
|
||||
1,220,130, 0, 1, 1,131, 1, 0, 21, 2, 3, 4, 64, 2, 0, 3,220, 65,128,
|
||||
1, 30, 0,128, 0, 7, 0, 0, 0, 4, 7, 0, 0, 0, 97,115,115,101,114,116,
|
||||
0, 4, 9, 0, 0, 0,116,111,115,116,114,105,110,103, 0, 4, 7, 0, 0, 0,
|
||||
105,112, 97,105,114,115, 0, 4, 3, 0, 0, 0, 44, 32, 0, 4, 5, 0, 0, 0,
|
||||
42, 42, 42, 32, 0, 4, 3, 0, 0, 0, 32, 40, 0, 4, 4, 0, 0, 0, 41, 58,
|
||||
32, 0, 0, 0, 0, 0, 40, 0, 0, 0, 97, 0, 0, 0, 97, 0, 0, 0, 97, 0,
|
||||
0, 0, 97, 0, 0, 0, 97, 0, 0, 0, 97, 0, 0, 0, 97, 0, 0, 0, 99, 0,
|
||||
0, 0, 99, 0, 0, 0, 99, 0, 0, 0,101, 0, 0, 0,101, 0, 0, 0,101, 0,
|
||||
0, 0,102, 0, 0, 0,102, 0, 0, 0,102, 0, 0, 0,102, 0, 0, 0,102, 0,
|
||||
0, 0,102, 0, 0, 0,102, 0, 0, 0,103, 0, 0, 0,103, 0, 0, 0,103, 0,
|
||||
0, 0,103, 0, 0, 0,103, 0, 0, 0,103, 0, 0, 0,102, 0, 0, 0,103, 0,
|
||||
0, 0,105, 0, 0, 0,105, 0, 0, 0,105, 0, 0, 0,105, 0, 0, 0,105, 0,
|
||||
0, 0,105, 0, 0, 0,105, 0, 0, 0,105, 0, 0, 0,105, 0, 0, 0,105, 0,
|
||||
0, 0,105, 0, 0, 0,106, 0, 0, 0, 12, 0, 0, 0, 6, 0, 0, 0,116,105,
|
||||
116,108,101, 0, 0, 0, 0, 0, 39, 0, 0, 0, 3, 0, 0, 0,117,100, 0, 0,
|
||||
0, 0, 0, 39, 0, 0, 0, 4, 0, 0, 0,107,101,121, 0, 0, 0, 0, 0, 39,
|
||||
0, 0, 0, 5, 0, 0, 0,100, 97,116, 97, 0, 10, 0, 0, 0, 39, 0, 0, 0,
|
||||
9, 0, 0, 0,105,110, 99,111,109,105,110,103, 0, 10, 0, 0, 0, 39, 0, 0,
|
||||
0, 2, 0, 0, 0, 95, 0, 10, 0, 0, 0, 39, 0, 0, 0, 2, 0, 0, 0,115,
|
||||
0, 13, 0, 0, 0, 39, 0, 0, 0, 16, 0, 0, 0, 40,102,111,114, 32,103,101,
|
||||
110,101,114, 97,116,111,114, 41, 0, 19, 0, 0, 0, 28, 0, 0, 0, 12, 0, 0,
|
||||
0, 40,102,111,114, 32,115,116, 97,116,101, 41, 0, 19, 0, 0, 0, 28, 0, 0,
|
||||
0, 14, 0, 0, 0, 40,102,111,114, 32, 99,111,110,116,114,111,108, 41, 0, 19,
|
||||
0, 0, 0, 28, 0, 0, 0, 2, 0, 0, 0, 95, 0, 20, 0, 0, 0, 26, 0, 0,
|
||||
0, 2, 0, 0, 0,118, 0, 20, 0, 0, 0, 26, 0, 0, 0, 2, 0, 0, 0, 7,
|
||||
0, 0, 0,116, 97, 98,108,101,115, 0, 3, 0, 0, 0, 87, 82, 0, 0, 0, 0,
|
||||
0,121, 0, 0, 0,158, 0, 0, 0, 1, 2, 3, 16, 56, 0, 0, 0,196, 0, 0,
|
||||
0, 0, 1, 0, 0,220, 0, 1, 1,133, 1, 0, 0,193, 65, 0, 0, 37, 2, 0,
|
||||
0,156,129, 0, 0, 23,128, 64, 3, 22, 64, 0,128,194, 1,128, 0,222, 1, 0,
|
||||
1,198, 65, 0, 2, 23,192,192, 3, 22, 64, 0,128,202, 1, 0, 0, 9,193,129,
|
||||
0,198, 65,128, 1,218, 1, 0, 0, 22, 0, 1,128,198, 65, 0, 2,212, 1,128,
|
||||
3,204,193, 1,130,218, 65, 0, 0, 22, 0, 0,128,193,129, 0, 0, 6, 66,128,
|
||||
2, 26, 2, 0, 0, 22, 0, 1,128, 76,130,129, 3, 24, 64, 2, 4, 22, 64, 0,
|
||||
128, 66, 2, 0, 0, 94, 2, 0, 1, 65, 2, 1, 0,128, 2, 0, 3,193, 2, 1,
|
||||
0, 96,130, 3,128, 69, 3, 0, 0,128, 3, 0, 6,229, 3, 0, 0, 92,131, 0,
|
||||
0, 23,192,192, 6, 22, 0, 0,128, 69, 67, 1, 0, 23,128,192, 3, 22,128, 0,
|
||||
128,201, 64,131, 0,193, 1, 1, 0, 22,128, 0,128,134, 67, 0, 2,137, 67,131,
|
||||
3,204, 1,193, 3, 95,194,251,127, 66, 2,128, 0, 94, 2, 0, 1, 30, 0,128,
|
||||
0, 6, 0, 0, 0, 4, 7, 0, 0, 0,115,101,108,101, 99,116, 0, 4, 2, 0,
|
||||
0, 0, 35, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
|
||||
0,240, 63, 4, 13, 0, 0, 0,110,105,108, 95,115,101,110,116,105,110,101,108,
|
||||
0, 0, 0, 0, 0, 56, 0, 0, 0,123, 0, 0, 0,123, 0, 0, 0,123, 0, 0,
|
||||
0,125, 0, 0, 0,125, 0, 0, 0,125, 0, 0, 0,125, 0, 0, 0,126, 0, 0,
|
||||
0,126, 0, 0, 0,126, 0, 0, 0,126, 0, 0, 0,130, 0, 0, 0,130, 0, 0,
|
||||
0,130, 0, 0, 0,131, 0, 0, 0,131, 0, 0, 0,134, 0, 0, 0,134, 0, 0,
|
||||
0,134, 0, 0, 0,134, 0, 0, 0,134, 0, 0, 0,134, 0, 0, 0,134, 0, 0,
|
||||
0,134, 0, 0, 0,134, 0, 0, 0,135, 0, 0, 0,137, 0, 0, 0,137, 0, 0,
|
||||
0,137, 0, 0, 0,137, 0, 0, 0,137, 0, 0, 0,138, 0, 0, 0,138, 0, 0,
|
||||
0,141, 0, 0, 0,141, 0, 0, 0,141, 0, 0, 0,141, 0, 0, 0,142, 0, 0,
|
||||
0,142, 0, 0, 0,142, 0, 0, 0,142, 0, 0, 0,145, 0, 0, 0,145, 0, 0,
|
||||
0,146, 0, 0, 0,149, 0, 0, 0,149, 0, 0, 0,150, 0, 0, 0,151, 0, 0,
|
||||
0,151, 0, 0, 0,153, 0, 0, 0,153, 0, 0, 0,154, 0, 0, 0,141, 0, 0,
|
||||
0,157, 0, 0, 0,157, 0, 0, 0,158, 0, 0, 0, 14, 0, 0, 0, 3, 0, 0,
|
||||
0,117,100, 0, 0, 0, 0, 0, 55, 0, 0, 0, 4, 0, 0, 0,107,101,121, 0,
|
||||
0, 0, 0, 0, 55, 0, 0, 0, 4, 0, 0, 0, 97,114,103, 0, 0, 0, 0, 0,
|
||||
55, 0, 0, 0, 5, 0, 0, 0,100, 97,116, 97, 0, 3, 0, 0, 0, 55, 0, 0,
|
||||
0, 9, 0, 0, 0,105,110, 99,111,109,105,110,103, 0, 3, 0, 0, 0, 55, 0,
|
||||
0, 0, 7, 0, 0, 0,108,105,109,105,116,115, 0, 3, 0, 0, 0, 55, 0, 0,
|
||||
0, 2, 0, 0, 0,110, 0, 7, 0, 0, 0, 55, 0, 0, 0, 4, 0, 0, 0,108,
|
||||
101,110, 0, 25, 0, 0, 0, 55, 0, 0, 0, 2, 0, 0, 0,109, 0, 26, 0, 0,
|
||||
0, 55, 0, 0, 0, 12, 0, 0, 0, 40,102,111,114, 32,105,110,100,101,120, 41,
|
||||
0, 36, 0, 0, 0, 53, 0, 0, 0, 12, 0, 0, 0, 40,102,111,114, 32,108,105,
|
||||
109,105,116, 41, 0, 36, 0, 0, 0, 53, 0, 0, 0, 11, 0, 0, 0, 40,102,111,
|
||||
114, 32,115,116,101,112, 41, 0, 36, 0, 0, 0, 53, 0, 0, 0, 2, 0, 0, 0,
|
||||
105, 0, 37, 0, 0, 0, 52, 0, 0, 0, 4, 0, 0, 0,118, 97,108, 0, 41, 0,
|
||||
0, 0, 52, 0, 0, 0, 1, 0, 0, 0, 7, 0, 0, 0,116, 97, 98,108,101,115,
|
||||
0, 0, 0, 0, 0,167, 0, 0, 0,189, 0, 0, 0, 2, 1, 3, 14, 40, 0, 0,
|
||||
0,132, 0, 0, 0,192, 0, 0, 0,156, 0, 1, 1, 65, 1, 0, 0,133, 65, 0,
|
||||
0,193,129, 0, 0, 37, 2, 0, 0,156,129, 0, 0,193, 1, 0, 0, 96,193, 6,
|
||||
128, 69, 66, 0, 0,128, 2, 0, 4,229, 2, 0, 0, 92,130, 0, 0,134, 66, 2,
|
||||
1, 87,192, 64, 5, 22, 0, 5,128,198, 66,130, 1,218, 2, 0, 0, 22, 64, 2,
|
||||
128,198, 66,130, 1,198, 2,192, 5, 87,192,192, 5, 22, 64, 1,128,196, 2,128,
|
||||
0, 6, 67,130, 1, 65, 3, 0, 0,220,130,128, 1,137,192,130, 4, 22, 0, 0,
|
||||
128,137,192,192, 4,197, 2, 1, 0, 23,192, 2, 5, 22, 0, 0,128,131, 2, 0,
|
||||
5,192, 2, 0, 5, 0, 3,128, 4,222, 2,128, 1, 95,129,248,127, 30, 0,128,
|
||||
0, 5, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 4, 7, 0, 0, 0,115,
|
||||
101,108,101, 99,116, 0, 4, 2, 0, 0, 0, 35, 0, 0, 4, 13, 0, 0, 0,110,
|
||||
105,108, 95,115,101,110,116,105,110,101,108, 0, 0, 0, 0, 0, 40, 0, 0, 0,
|
||||
169, 0, 0, 0,169, 0, 0, 0,169, 0, 0, 0,171, 0, 0, 0,171, 0, 0, 0,
|
||||
171, 0, 0, 0,171, 0, 0, 0,171, 0, 0, 0,171, 0, 0, 0,171, 0, 0, 0,
|
||||
172, 0, 0, 0,172, 0, 0, 0,172, 0, 0, 0,172, 0, 0, 0,173, 0, 0, 0,
|
||||
175, 0, 0, 0,175, 0, 0, 0,176, 0, 0, 0,176, 0, 0, 0,176, 0, 0, 0,
|
||||
176, 0, 0, 0,176, 0, 0, 0,176, 0, 0, 0,176, 0, 0, 0,178, 0, 0, 0,
|
||||
178, 0, 0, 0,178, 0, 0, 0,178, 0, 0, 0,178, 0, 0, 0,178, 0, 0, 0,
|
||||
180, 0, 0, 0,182, 0, 0, 0,182, 0, 0, 0,182, 0, 0, 0,183, 0, 0, 0,
|
||||
185, 0, 0, 0,185, 0, 0, 0,185, 0, 0, 0,171, 0, 0, 0,189, 0, 0, 0,
|
||||
11, 0, 0, 0, 3, 0, 0, 0,117,100, 0, 0, 0, 0, 0, 39, 0, 0, 0, 4,
|
||||
0, 0, 0, 97,114,103, 0, 0, 0, 0, 0, 39, 0, 0, 0, 5, 0, 0, 0,100,
|
||||
97,116, 97, 0, 3, 0, 0, 0, 39, 0, 0, 0, 9, 0, 0, 0,105,110, 99,111,
|
||||
109,105,110,103, 0, 3, 0, 0, 0, 39, 0, 0, 0, 2, 0, 0, 0, 95, 0, 3,
|
||||
0, 0, 0, 39, 0, 0, 0, 12, 0, 0, 0, 40,102,111,114, 32,105,110,100,101,
|
||||
120, 41, 0, 9, 0, 0, 0, 39, 0, 0, 0, 12, 0, 0, 0, 40,102,111,114, 32,
|
||||
108,105,109,105,116, 41, 0, 9, 0, 0, 0, 39, 0, 0, 0, 11, 0, 0, 0, 40,
|
||||
102,111,114, 32,115,116,101,112, 41, 0, 9, 0, 0, 0, 39, 0, 0, 0, 2, 0,
|
||||
0, 0,105, 0, 10, 0, 0, 0, 38, 0, 0, 0, 4, 0, 0, 0,107,101,121, 0,
|
||||
14, 0, 0, 0, 38, 0, 0, 0, 4, 0, 0, 0,118, 97,108, 0, 15, 0, 0, 0,
|
||||
38, 0, 0, 0, 2, 0, 0, 0, 7, 0, 0, 0,116, 97, 98,108,101,115, 0, 13,
|
||||
0, 0, 0,116, 97, 98,108,101, 95,114,101,109,111,118,101, 0, 0, 0, 0, 0,
|
||||
195, 0, 0, 0,200, 0, 0, 0, 1, 3, 0, 6, 5, 0, 0, 0,196, 0, 0, 0,
|
||||
0, 1, 0, 0,220, 0, 1, 1, 73,129,128, 0, 30, 0,128, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 5, 0, 0, 0,197, 0, 0, 0,197, 0, 0, 0,197, 0, 0, 0,
|
||||
199, 0, 0, 0,200, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0,117,100, 0, 0,
|
||||
0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,107,101,121, 0, 0, 0, 0, 0, 4,
|
||||
0, 0, 0, 2, 0, 0, 0,110, 0, 0, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0,
|
||||
0, 95, 0, 3, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 95, 0, 3, 0, 0,
|
||||
0, 4, 0, 0, 0, 7, 0, 0, 0,108,105,109,105,116,115, 0, 3, 0, 0, 0,
|
||||
4, 0, 0, 0, 1, 0, 0, 0, 7, 0, 0, 0,116, 97, 98,108,101,115, 0, 0,
|
||||
0, 0, 0,206, 0, 0, 0,214, 0, 0, 0, 1, 3, 0, 6, 6, 0, 0, 0,196,
|
||||
0, 0, 0, 0, 1, 0, 0,220, 0, 1, 1,201,128,128, 0, 9, 1,192, 0, 30,
|
||||
0,128, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0,208, 0, 0, 0,
|
||||
208, 0, 0, 0,208, 0, 0, 0,212, 0, 0, 0,213, 0, 0, 0,214, 0, 0, 0,
|
||||
6, 0, 0, 0, 3, 0, 0, 0,117,100, 0, 0, 0, 0, 0, 5, 0, 0, 0, 4,
|
||||
0, 0, 0,107,101,121, 0, 0, 0, 0, 0, 5, 0, 0, 0, 4, 0, 0, 0,118,
|
||||
97,108, 0, 0, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0,100, 97,116, 97, 0,
|
||||
3, 0, 0, 0, 5, 0, 0, 0, 9, 0, 0, 0,105,110, 99,111,109,105,110,103,
|
||||
0, 3, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 95, 0, 3, 0, 0, 0, 5,
|
||||
0, 0, 0, 1, 0, 0, 0, 7, 0, 0, 0,116, 97, 98,108,101,115, 0, 0, 0,
|
||||
0, 0,220, 0, 0, 0,229, 0, 0, 0, 1, 2, 0, 7, 10, 0, 0, 0,132, 0,
|
||||
0, 0,192, 0, 0, 0,156, 0, 1, 1, 70, 65, 0, 1,133, 1, 0, 0, 23,128,
|
||||
129, 2, 22, 0, 0,128, 67, 1,128, 2, 94, 1, 0, 1, 30, 0,128, 0, 1, 0,
|
||||
0, 0, 4, 13, 0, 0, 0,110,105,108, 95,115,101,110,116,105,110,101,108, 0,
|
||||
0, 0, 0, 0, 10, 0, 0, 0,222, 0, 0, 0,222, 0, 0, 0,222, 0, 0, 0,
|
||||
224, 0, 0, 0,225, 0, 0, 0,225, 0, 0, 0,225, 0, 0, 0,226, 0, 0, 0,
|
||||
228, 0, 0, 0,229, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0,117,100, 0, 0,
|
||||
0, 0, 0, 9, 0, 0, 0, 4, 0, 0, 0,107,101,121, 0, 0, 0, 0, 0, 9,
|
||||
0, 0, 0, 5, 0, 0, 0,100, 97,116, 97, 0, 3, 0, 0, 0, 9, 0, 0, 0,
|
||||
2, 0, 0, 0, 95, 0, 3, 0, 0, 0, 9, 0, 0, 0, 2, 0, 0, 0, 95, 0,
|
||||
3, 0, 0, 0, 9, 0, 0, 0, 4, 0, 0, 0,118, 97,108, 0, 4, 0, 0, 0,
|
||||
9, 0, 0, 0, 1, 0, 0, 0, 7, 0, 0, 0,116, 97, 98,108,101,115, 0, 0,
|
||||
0, 0, 0,237, 0, 0, 0,242, 0, 0, 0, 3, 1, 0, 2, 7, 0, 0, 0, 68,
|
||||
0, 0, 0, 73, 0, 64, 0, 68, 0,128, 0, 73, 0, 64, 0, 68, 0, 0, 1, 73,
|
||||
0, 64, 0, 30, 0,128, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0,
|
||||
239, 0, 0, 0,239, 0, 0, 0,240, 0, 0, 0,240, 0, 0, 0,241, 0, 0, 0,
|
||||
241, 0, 0, 0,242, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0,117,100, 0, 0,
|
||||
0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 95,100, 97,116, 97,
|
||||
0, 10, 0, 0, 0, 95,105,110, 99,111,109,105,110,103, 0, 8, 0, 0, 0, 95,
|
||||
108,105,109,105,116,115, 0, 45, 0, 0, 0, 39, 0, 0, 0, 39, 0, 0, 0, 39,
|
||||
0, 0, 0, 43, 0, 0, 0, 43, 0, 0, 0, 43, 0, 0, 0, 43, 0, 0, 0, 44,
|
||||
0, 0, 0, 44, 0, 0, 0, 44, 0, 0, 0, 44, 0, 0, 0, 50, 0, 0, 0, 50,
|
||||
0, 0, 0, 59, 0, 0, 0, 68, 0, 0, 0, 77, 0, 0, 0, 93, 0, 0, 0, 93,
|
||||
0, 0, 0, 93, 0, 0, 0, 93, 0, 0, 0,106, 0, 0, 0,106, 0, 0, 0,106,
|
||||
0, 0, 0,158, 0, 0, 0,158, 0, 0, 0,121, 0, 0, 0,189, 0, 0, 0,189,
|
||||
0, 0, 0,189, 0, 0, 0,167, 0, 0, 0,200, 0, 0, 0,200, 0, 0, 0,195,
|
||||
0, 0, 0,214, 0, 0, 0,214, 0, 0, 0,206, 0, 0, 0,229, 0, 0, 0,229,
|
||||
0, 0, 0,220, 0, 0, 0,242, 0, 0, 0,242, 0, 0, 0,242, 0, 0, 0,242,
|
||||
0, 0, 0,237, 0, 0, 0,242, 0, 0, 0, 8, 0, 0, 0, 13, 0, 0, 0,116,
|
||||
97, 98,108,101, 95,114,101,109,111,118,101, 0, 7, 0, 0, 0, 44, 0, 0, 0,
|
||||
13, 0, 0, 0,116, 97, 98,108,101, 95, 99,111,110, 99, 97,116, 0, 11, 0, 0,
|
||||
0, 44, 0, 0, 0, 3, 0, 0, 0, 87, 82, 0, 13, 0, 0, 0, 44, 0, 0, 0,
|
||||
6, 0, 0, 0, 95,100, 97,116, 97, 0, 14, 0, 0, 0, 44, 0, 0, 0, 10, 0,
|
||||
0, 0, 95,105,110, 99,111,109,105,110,103, 0, 15, 0, 0, 0, 44, 0, 0, 0,
|
||||
8, 0, 0, 0, 95,108,105,109,105,116,115, 0, 16, 0, 0, 0, 44, 0, 0, 0,
|
||||
7, 0, 0, 0,116, 97, 98,108,101,115, 0, 20, 0, 0, 0, 44, 0, 0, 0, 6,
|
||||
0, 0, 0, 68, 69, 66, 85, 71, 0, 23, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0,
|
||||
0,};
|
||||
|
||||
@@ -1,244 +0,0 @@
|
||||
--
|
||||
-- KEEPER.LUA
|
||||
--
|
||||
-- Keeper state logic
|
||||
--
|
||||
-- This code is read in for each "keeper state", which are the hidden, inter-
|
||||
-- mediate data stores used by Lanes inter-state communication objects.
|
||||
--
|
||||
-- Author: Asko Kauppi <akauppi@gmail.com>
|
||||
--
|
||||
--[[
|
||||
===============================================================================
|
||||
|
||||
Copyright (C) 2008 Asko Kauppi <akauppi@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
===============================================================================
|
||||
]]--
|
||||
|
||||
-- unique key instead of 'nil' in queues
|
||||
--
|
||||
assert( nil_sentinel )
|
||||
|
||||
-- We only need to have base and table libraries (and io for debugging)
|
||||
--
|
||||
local table_remove= assert( table.remove )
|
||||
local table_concat= assert( table.concat )
|
||||
|
||||
local function WR(...)
|
||||
if io then
|
||||
io.stderr:write( table_concat({...},'\t').."\n" )
|
||||
end
|
||||
end
|
||||
|
||||
-----
|
||||
-- Actual data store
|
||||
--
|
||||
-- { [linda_deep_ud]= { key= val [, ...] }
|
||||
-- ...
|
||||
-- }
|
||||
--
|
||||
local _data= {}
|
||||
|
||||
-----
|
||||
-- Entries queued for use when the existing 'data[ud][key]' entry is consumed.
|
||||
--
|
||||
-- { [linda_deep_ud]= { key= { val [, ... } [, ...] }
|
||||
-- ...
|
||||
-- }
|
||||
--
|
||||
local _incoming= {}
|
||||
|
||||
-----
|
||||
-- Length limits (if any) for queues
|
||||
--
|
||||
-- 0: don't queue values at all; ':send()' waits if the slot is not vacant
|
||||
-- N: allow N values to be queued (slot itself + N-1); wait if full
|
||||
-- nil: no limits, '_incoming' may grow endlessly
|
||||
--
|
||||
local _limits= {}
|
||||
|
||||
-----
|
||||
-- data_tbl, incoming_tbl, limits_tbl = tables( linda_deep_ud )
|
||||
--
|
||||
-- Gives appropriate tables for a certain Linda (creates them if needed)
|
||||
--
|
||||
local function tables( ud )
|
||||
-- tables are created either all or nothing
|
||||
--
|
||||
if not _data[ud] then
|
||||
_data[ud]= {}
|
||||
_incoming[ud]= {}
|
||||
_limits[ud]= {}
|
||||
end
|
||||
return _data[ud], _incoming[ud], _limits[ud]
|
||||
end
|
||||
|
||||
|
||||
local function DEBUG(title,ud,key)
|
||||
assert( title and ud and key )
|
||||
|
||||
local data,incoming,_= tables(ud)
|
||||
|
||||
local s= tostring(data[key])
|
||||
for _,v in ipairs( incoming[key] or {} ) do
|
||||
s= s..", "..tostring(v)
|
||||
end
|
||||
WR( "*** "..title.." ("..tostring(key).."): ", s )
|
||||
end
|
||||
|
||||
|
||||
-----
|
||||
-- bool= send( linda_deep_ud, key, ... )
|
||||
--
|
||||
-- Send new data (1..N) to 'key' slot. This send is atomic; all the values
|
||||
-- end up one after each other (this is why having possibility for sending
|
||||
-- multiple values in one call is deemed important).
|
||||
--
|
||||
-- If the queue has a limit, values are sent only if all of them fit in.
|
||||
--
|
||||
-- Returns: 'true' if all the values were placed
|
||||
-- 'false' if sending would exceed the queue limit (wait & retry)
|
||||
--
|
||||
function send( ud, key, ... )
|
||||
|
||||
local data,incoming,limits= tables(ud)
|
||||
|
||||
local n= select('#',...)
|
||||
if n==0 then return true end -- nothing to send
|
||||
|
||||
-- Initialize queue for all keys that have been used with ':send()'
|
||||
--
|
||||
if incoming[key]==nil then
|
||||
incoming[key]= {}
|
||||
end
|
||||
|
||||
local len= data[key] and 1+#incoming[key] or 0
|
||||
local m= limits[key]
|
||||
|
||||
if m and len+n > m then
|
||||
return false -- would exceed the limit; try again later
|
||||
end
|
||||
|
||||
for i=1,n do
|
||||
local val= select(i,...)
|
||||
|
||||
-- 'nil' in the data replaced by sentinel
|
||||
if val==nil then
|
||||
val= nil_sentinel
|
||||
end
|
||||
|
||||
if len==0 then
|
||||
data[key]= val
|
||||
len= 1
|
||||
else
|
||||
incoming[key][len]= val
|
||||
len= len+1
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
-----
|
||||
-- [val, key]= receive( linda_deep_ud, key [, ...] )
|
||||
--
|
||||
-- Read any of the given keys, consuming the data found. Keys are read in
|
||||
-- order.
|
||||
--
|
||||
function receive( ud, ... )
|
||||
|
||||
local data,incoming,_= tables(ud)
|
||||
|
||||
for i=1,select('#',...) do
|
||||
local key= select(i,...)
|
||||
local val= data[key]
|
||||
|
||||
if val~=nil then
|
||||
if incoming[key] and incoming[key][1]~=nil then
|
||||
-- pop [1] from 'incoming[key]' into the actual slot
|
||||
data[key]= table_remove( incoming[key], 1 )
|
||||
else
|
||||
data[key]= nil -- empty the slot
|
||||
end
|
||||
if val==nil_sentinel then
|
||||
val= nil
|
||||
end
|
||||
return val, key
|
||||
end
|
||||
end
|
||||
--return nil
|
||||
end
|
||||
|
||||
|
||||
-----
|
||||
-- = limit( linda_deep_ud, key, uint )
|
||||
--
|
||||
function limit( ud, key, n )
|
||||
|
||||
local _,_,limits= tables(ud)
|
||||
|
||||
limits[key]= n
|
||||
end
|
||||
|
||||
|
||||
-----
|
||||
-- void= set( linda_deep_ud, key, [val] )
|
||||
--
|
||||
function set( ud, key, val )
|
||||
|
||||
local data,incoming,_= tables(ud)
|
||||
|
||||
-- Setting a key to 'nil' really clears it; only queing uses sentinels.
|
||||
--
|
||||
data[key]= val
|
||||
incoming[key]= nil
|
||||
end
|
||||
|
||||
|
||||
-----
|
||||
-- [val]= get( linda_deep_ud, key )
|
||||
--
|
||||
function get( ud, key )
|
||||
|
||||
local data,_,_= tables(ud)
|
||||
|
||||
local val= data[key]
|
||||
if val==nil_sentinel then
|
||||
val= nil
|
||||
end
|
||||
return val
|
||||
end
|
||||
|
||||
|
||||
-----
|
||||
-- void= clear( linda_deep_ud )
|
||||
--
|
||||
-- Clear the data structures used for a Linda (at its destructor)
|
||||
--
|
||||
function clear( ud )
|
||||
|
||||
_data[ud]= nil
|
||||
_incoming[ud]= nil
|
||||
_limits[ud]= nil
|
||||
end
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,611 +0,0 @@
|
||||
--
|
||||
-- LANES.LUA
|
||||
--
|
||||
-- Multithreading and -core support for Lua
|
||||
--
|
||||
-- Author: Asko Kauppi <akauppi@gmail.com>
|
||||
--
|
||||
-- History:
|
||||
-- Jun-08 AKa: major revise
|
||||
-- 15-May-07 AKa: pthread_join():less version, some speedup & ability to
|
||||
-- handle more threads (~ 8000-9000, up from ~ 5000)
|
||||
-- 26-Feb-07 AKa: serialization working (C side)
|
||||
-- 17-Sep-06 AKa: started the module (serialization)
|
||||
--
|
||||
--[[
|
||||
===============================================================================
|
||||
|
||||
Copyright (C) 2007-08 Asko Kauppi <akauppi@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
===============================================================================
|
||||
]]--
|
||||
|
||||
module( "lanes", package.seeall )
|
||||
|
||||
require "lua51-lanes"
|
||||
assert( type(lanes)=="table" )
|
||||
|
||||
local mm= lanes
|
||||
|
||||
local linda_id= assert( mm.linda_id )
|
||||
|
||||
local thread_new= assert(mm.thread_new)
|
||||
local thread_status= assert(mm.thread_status)
|
||||
local thread_join= assert(mm.thread_join)
|
||||
local thread_cancel= assert(mm.thread_cancel)
|
||||
|
||||
local _single= assert(mm._single)
|
||||
local _version= assert(mm._version)
|
||||
|
||||
local _deep_userdata= assert(mm._deep_userdata)
|
||||
|
||||
local now_secs= assert( mm.now_secs )
|
||||
local wakeup_conv= assert( mm.wakeup_conv )
|
||||
local timer_gateway= assert( mm.timer_gateway )
|
||||
|
||||
local max_prio= assert( mm.max_prio )
|
||||
|
||||
-- This check is for sublanes requiring Lanes
|
||||
--
|
||||
-- TBD: We could also have the C level expose 'string.gmatch' for us. But this is simpler.
|
||||
--
|
||||
if not string then
|
||||
error( "To use 'lanes', you will also need to have 'string' available.", 2 )
|
||||
end
|
||||
|
||||
--
|
||||
-- Cache globals for code that might run under sandboxing
|
||||
--
|
||||
local assert= assert
|
||||
local string_gmatch= assert( string.gmatch )
|
||||
local select= assert( select )
|
||||
local type= assert( type )
|
||||
local pairs= assert( pairs )
|
||||
local tostring= assert( tostring )
|
||||
local error= assert( error )
|
||||
local setmetatable= assert( setmetatable )
|
||||
local rawget= assert( rawget )
|
||||
|
||||
ABOUT=
|
||||
{
|
||||
author= "Asko Kauppi <akauppi@gmail.com>",
|
||||
description= "Running multiple Lua states in parallel",
|
||||
license= "MIT/X11",
|
||||
copyright= "Copyright (c) 2007-08, Asko Kauppi",
|
||||
version= _version,
|
||||
}
|
||||
|
||||
|
||||
-- Making copies of necessary system libs will pass them on as upvalues;
|
||||
-- only the first state doing "require 'lanes'" will need to have 'string'
|
||||
-- and 'table' visible.
|
||||
--
|
||||
local function WR(str)
|
||||
io.stderr:write( str.."\n" )
|
||||
end
|
||||
|
||||
local function DUMP( tbl )
|
||||
if not tbl then return end
|
||||
local str=""
|
||||
for k,v in pairs(tbl) do
|
||||
str= str..k.."="..tostring(v).."\n"
|
||||
end
|
||||
WR(str)
|
||||
end
|
||||
|
||||
|
||||
---=== Laning ===---
|
||||
|
||||
-- lane_h[1..n]: lane results, same as via 'lane_h:join()'
|
||||
-- lane_h[0]: can be read to make sure a thread has finished (always gives 'true')
|
||||
-- lane_h[-1]: error message, without propagating the error
|
||||
--
|
||||
-- Reading a Lane result (or [0]) propagates a possible error in the lane
|
||||
-- (and execution does not return). Cancelled lanes give 'nil' values.
|
||||
--
|
||||
-- lane_h.state: "pending"/"running"/"waiting"/"done"/"error"/"cancelled"
|
||||
--
|
||||
local lane_mt= {
|
||||
__index= function( me, k )
|
||||
if type(k) == "number" then
|
||||
-- 'me[0]=true' marks we've already taken in the results
|
||||
--
|
||||
if not rawget( me, 0 ) then
|
||||
-- Wait indefinately; either propagates an error or
|
||||
-- returns the return values
|
||||
--
|
||||
me[0]= true -- marker, even on errors
|
||||
|
||||
local t= { thread_join(me._ud) } -- wait indefinate
|
||||
--
|
||||
-- { ... } "done": regular return, 0..N results
|
||||
-- { } "cancelled"
|
||||
-- { nil, err_str, stack_tbl } "error"
|
||||
|
||||
local st= thread_status(me._ud)
|
||||
if st=="done" then
|
||||
-- Use 'pairs' and not 'ipairs' so that nil holes in
|
||||
-- the returned values are tolerated.
|
||||
--
|
||||
for i,v in pairs(t) do
|
||||
me[i]= v
|
||||
end
|
||||
elseif st=="error" then
|
||||
assert( t[1]==nil and t[2] and type(t[3])=="table" )
|
||||
me[-1]= t[2]
|
||||
-- me[-2] could carry the stack table, but even
|
||||
-- me[-1] is rather unnecessary (and undocumented);
|
||||
-- use ':join()' instead. --AKa 22-Jan-2009
|
||||
elseif st=="cancelled" then
|
||||
-- do nothing
|
||||
else
|
||||
error( "Unexpected status: "..st )
|
||||
end
|
||||
end
|
||||
|
||||
-- Check errors even if we'd first peeked them via [-1]
|
||||
-- and then came for the actual results.
|
||||
--
|
||||
local err= rawget(me, -1)
|
||||
if err~=nil and k~=-1 then
|
||||
-- Note: Lua 5.1 interpreter is not prepared to show
|
||||
-- non-string errors, so we use 'tostring()' here
|
||||
-- to get meaningful output. --AKa 22-Jan-2009
|
||||
--
|
||||
-- Also, the stack dump we get is no good; it only
|
||||
-- lists our internal Lanes functions. There seems
|
||||
-- to be no way to switch it off, though.
|
||||
|
||||
-- Level 3 should show the line where 'h[x]' was read
|
||||
-- but this only seems to work for string messages
|
||||
-- (Lua 5.1.4). No idea, why. --AKa 22-Jan-2009
|
||||
--
|
||||
error( tostring(err), 3 ) -- level 3 should show the line where 'h[x]' was read
|
||||
end
|
||||
return rawget( me, k )
|
||||
--
|
||||
elseif k=="status" then -- me.status
|
||||
return thread_status(me._ud)
|
||||
--
|
||||
else
|
||||
error( "Unknown key: "..k )
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
-----
|
||||
-- h= lanes.gen( [libs_str|opt_tbl [, ...],] lane_func ) ( [...] )
|
||||
--
|
||||
-- 'libs': nil: no libraries available (default)
|
||||
-- "": only base library ('assert', 'print', 'unpack' etc.)
|
||||
-- "math,os": math + os + base libraries (named ones + base)
|
||||
-- "*": all standard libraries available
|
||||
--
|
||||
-- 'opt': .priority: int (-2..+2) smaller is lower priority (0 = default)
|
||||
--
|
||||
-- .cancelstep: bool | uint
|
||||
-- false: cancellation check only at pending Linda operations
|
||||
-- (send/receive) so no runtime performance penalty (default)
|
||||
-- true: adequate cancellation check (same as 100)
|
||||
-- >0: cancellation check every x Lua lines (small number= faster
|
||||
-- reaction but more performance overhead)
|
||||
--
|
||||
-- .globals: table of globals to set for a new thread (passed by value)
|
||||
--
|
||||
-- ... (more options may be introduced later) ...
|
||||
--
|
||||
-- Calling with a function parameter ('lane_func') ends the string/table
|
||||
-- modifiers, and prepares a lane generator. One can either finish here,
|
||||
-- and call the generator later (maybe multiple times, with different parameters)
|
||||
-- or add on actual thread arguments to also ignite the thread on the same call.
|
||||
--
|
||||
local lane_proxy
|
||||
|
||||
local valid_libs= {
|
||||
["package"]= true,
|
||||
["table"]= true,
|
||||
["io"]= true,
|
||||
["os"]= true,
|
||||
["string"]= true,
|
||||
["math"]= true,
|
||||
["debug"]= true,
|
||||
--
|
||||
["base"]= true,
|
||||
["coroutine"]= true,
|
||||
["*"]= true
|
||||
}
|
||||
|
||||
function gen( ... )
|
||||
local opt= {}
|
||||
local libs= nil
|
||||
local lev= 2 -- level for errors
|
||||
|
||||
local n= select('#',...)
|
||||
|
||||
if n==0 then
|
||||
error( "No parameters!" )
|
||||
end
|
||||
|
||||
for i=1,n-1 do
|
||||
local v= select(i,...)
|
||||
if type(v)=="string" then
|
||||
libs= libs and libs..","..v or v
|
||||
elseif type(v)=="table" then
|
||||
for k,vv in pairs(v) do
|
||||
opt[k]= vv
|
||||
end
|
||||
elseif v==nil then
|
||||
-- skip
|
||||
else
|
||||
error( "Bad parameter: "..tostring(v) )
|
||||
end
|
||||
end
|
||||
|
||||
local func= select(n,...)
|
||||
if type(func)~="function" then
|
||||
error( "Last parameter not function: "..tostring(func) )
|
||||
end
|
||||
|
||||
-- Check 'libs' already here, so the error goes in the right place
|
||||
-- (otherwise will be noticed only once the generator is called)
|
||||
--
|
||||
if libs then
|
||||
for s in string_gmatch(libs, "[%a*]+") do
|
||||
if not valid_libs[s] then
|
||||
error( "Bad library name: "..s )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local prio, cs, g_tbl
|
||||
|
||||
for k,v in pairs(opt) do
|
||||
if k=="priority" then prio= v
|
||||
elseif k=="cancelstep" then cs= (v==true) and 100 or
|
||||
(v==false) and 0 or
|
||||
type(v)=="number" and v or
|
||||
error( "Bad cancelstep: "..tostring(v), lev )
|
||||
elseif k=="globals" then g_tbl= v
|
||||
--..
|
||||
elseif k==1 then error( "unkeyed option: ".. tostring(v), lev )
|
||||
else error( "Bad option: ".. tostring(k), lev )
|
||||
end
|
||||
end
|
||||
|
||||
-- Lane generator
|
||||
--
|
||||
return function(...)
|
||||
return lane_proxy( thread_new( func, libs, cs, prio, g_tbl,
|
||||
... ) ) -- args
|
||||
end
|
||||
end
|
||||
|
||||
lane_proxy= function( ud )
|
||||
local proxy= {
|
||||
_ud= ud,
|
||||
|
||||
-- void= me:cancel()
|
||||
--
|
||||
cancel= function(me) thread_cancel(me._ud) end,
|
||||
|
||||
-- [...] | [nil,err,stack_tbl]= me:join( [wait_secs=-1] )
|
||||
--
|
||||
join= function( me, wait )
|
||||
return thread_join( me._ud, wait )
|
||||
end,
|
||||
}
|
||||
assert( proxy._ud )
|
||||
setmetatable( proxy, lane_mt )
|
||||
|
||||
return proxy
|
||||
end
|
||||
|
||||
|
||||
---=== Lindas ===---
|
||||
|
||||
-- We let the C code attach methods to userdata directly
|
||||
|
||||
-----
|
||||
-- linda_ud= lanes.linda()
|
||||
--
|
||||
function linda()
|
||||
local proxy= _deep_userdata( linda_id )
|
||||
assert( (type(proxy) == "userdata") and getmetatable(proxy) )
|
||||
return proxy
|
||||
end
|
||||
|
||||
|
||||
---=== Timers ===---
|
||||
|
||||
--
|
||||
-- On first 'require "lanes"', a timer lane is spawned that will maintain
|
||||
-- timer tables and sleep in between the timer events. All interaction with
|
||||
-- the timer lane happens via a 'timer_gateway' Linda, which is common to
|
||||
-- all that 'require "lanes"'.
|
||||
--
|
||||
-- Linda protocol to timer lane:
|
||||
--
|
||||
-- TGW_KEY: linda_h, key, [wakeup_at_secs], [repeat_secs]
|
||||
--
|
||||
local TGW_KEY= "(timer control)" -- the key does not matter, a 'weird' key may help debugging
|
||||
local first_time_key= "first time"
|
||||
|
||||
local first_time= timer_gateway:get(first_time_key) == nil
|
||||
timer_gateway:set(first_time_key,true)
|
||||
|
||||
--
|
||||
-- Timer lane; initialize only on the first 'require "lanes"' instance (which naturally
|
||||
-- has 'table' always declared)
|
||||
--
|
||||
if first_time then
|
||||
local table_remove= assert( table.remove )
|
||||
local table_insert= assert( table.insert )
|
||||
|
||||
--
|
||||
-- { [deep_linda_lightuserdata]= { [deep_linda_lightuserdata]=linda_h,
|
||||
-- [key]= { wakeup_secs [,period_secs] } [, ...] },
|
||||
-- }
|
||||
--
|
||||
-- Collection of all running timers, indexed with linda's & key.
|
||||
--
|
||||
-- Note that we need to use the deep lightuserdata identifiers, instead
|
||||
-- of 'linda_h' themselves as table indices. Otherwise, we'd get multiple
|
||||
-- entries for the same timer.
|
||||
--
|
||||
-- The 'hidden' reference to Linda proxy is used in 'check_timers()' but
|
||||
-- also important to keep the Linda alive, even if all outside world threw
|
||||
-- away pointers to it (which would ruin uniqueness of the deep pointer).
|
||||
-- Now we're safe.
|
||||
--
|
||||
local collection= {}
|
||||
|
||||
--
|
||||
-- set_timer( linda_h, key [,wakeup_at_secs [,period_secs]] )
|
||||
--
|
||||
local function set_timer( linda, key, wakeup_at, period )
|
||||
|
||||
assert( wakeup_at==nil or wakeup_at>0.0 )
|
||||
assert( period==nil or period>0.0 )
|
||||
|
||||
local linda_deep= linda:deep()
|
||||
assert( linda_deep )
|
||||
|
||||
-- Find or make a lookup for this timer
|
||||
--
|
||||
local t1= collection[linda_deep]
|
||||
if not t1 then
|
||||
t1= { [linda_deep]= linda } -- proxy to use the Linda
|
||||
collection[linda_deep]= t1
|
||||
end
|
||||
|
||||
if wakeup_at==nil then
|
||||
-- Clear the timer
|
||||
--
|
||||
t1[key]= nil
|
||||
|
||||
-- Remove empty tables from collection; speeds timer checks and
|
||||
-- lets our 'safety reference' proxy be gc:ed as well.
|
||||
--
|
||||
local empty= true
|
||||
for k,_ in pairs(t1) do
|
||||
if k~= linda_deep then
|
||||
empty= false; break
|
||||
end
|
||||
end
|
||||
if empty then
|
||||
collection[linda_deep]= nil
|
||||
end
|
||||
|
||||
-- Note: any unread timer value is left at 'linda[key]' intensionally;
|
||||
-- clearing a timer just stops it.
|
||||
else
|
||||
-- New timer or changing the timings
|
||||
--
|
||||
local t2= t1[key]
|
||||
if not t2 then
|
||||
t2= {}; t1[key]= t2
|
||||
end
|
||||
|
||||
t2[1]= wakeup_at
|
||||
t2[2]= period -- can be 'nil'
|
||||
end
|
||||
end
|
||||
|
||||
-----
|
||||
-- [next_wakeup_at]= check_timers()
|
||||
--
|
||||
-- Check timers, and wake up the ones expired (if any)
|
||||
--
|
||||
-- Returns the closest upcoming (remaining) wakeup time (or 'nil' if none).
|
||||
--
|
||||
local function check_timers()
|
||||
|
||||
local now= now_secs()
|
||||
local next_wakeup
|
||||
|
||||
for linda_deep,t1 in pairs(collection) do
|
||||
for key,t2 in pairs(t1) do
|
||||
--
|
||||
if key==linda_deep then
|
||||
-- no 'continue' in Lua :/
|
||||
else
|
||||
-- 't2': { wakeup_at_secs [,period_secs] }
|
||||
--
|
||||
local wakeup_at= t2[1]
|
||||
local period= t2[2] -- may be 'nil'
|
||||
|
||||
if wakeup_at <= now then
|
||||
local linda= t1[linda_deep]
|
||||
assert(linda)
|
||||
|
||||
linda:set( key, now )
|
||||
|
||||
-- 'pairs()' allows the values to be modified (and even
|
||||
-- removed) as far as keys are not touched
|
||||
|
||||
if not period then
|
||||
-- one-time timer; gone
|
||||
--
|
||||
t1[key]= nil
|
||||
wakeup_at= nil -- no 'continue' in Lua :/
|
||||
else
|
||||
-- repeating timer; find next wakeup (may jump multiple repeats)
|
||||
--
|
||||
repeat
|
||||
wakeup_at= wakeup_at+period
|
||||
until wakeup_at > now
|
||||
|
||||
t2[1]= wakeup_at
|
||||
end
|
||||
end
|
||||
|
||||
if wakeup_at and ((not next_wakeup) or (wakeup_at < next_wakeup)) then
|
||||
next_wakeup= wakeup_at
|
||||
end
|
||||
end
|
||||
end -- t2 loop
|
||||
end -- t1 loop
|
||||
|
||||
return next_wakeup -- may be 'nil'
|
||||
end
|
||||
|
||||
-----
|
||||
-- Snore loop (run as a lane on the background)
|
||||
--
|
||||
-- High priority, to get trustworthy timings.
|
||||
--
|
||||
-- We let the timer lane be a "free running" thread; no handle to it
|
||||
-- remains.
|
||||
--
|
||||
gen( "io", { priority=max_prio }, function()
|
||||
|
||||
while true do
|
||||
local next_wakeup= check_timers()
|
||||
|
||||
-- Sleep until next timer to wake up, or a set/clear command
|
||||
--
|
||||
local secs= next_wakeup and (next_wakeup - now_secs()) or nil
|
||||
local linda= timer_gateway:receive( secs, TGW_KEY )
|
||||
|
||||
if linda then
|
||||
local key= timer_gateway:receive( 0.0, TGW_KEY )
|
||||
local wakeup_at= timer_gateway:receive( 0.0, TGW_KEY )
|
||||
local period= timer_gateway:receive( 0.0, TGW_KEY )
|
||||
assert( key and wakeup_at and period )
|
||||
|
||||
set_timer( linda, key, wakeup_at, period>0 and period or nil )
|
||||
end
|
||||
end
|
||||
end )()
|
||||
end
|
||||
|
||||
-----
|
||||
-- = timer( linda_h, key_val, date_tbl|first_secs [,period_secs] )
|
||||
--
|
||||
function timer( linda, key, a, period )
|
||||
|
||||
if a==0.0 then
|
||||
-- Caller expects to get current time stamp in Linda, on return
|
||||
-- (like the timer had expired instantly); it would be good to set this
|
||||
-- as late as possible (to give most current time) but also we want it
|
||||
-- to precede any possible timers that might start striking.
|
||||
--
|
||||
linda:set( key, now_secs() )
|
||||
|
||||
if not period or period==0.0 then
|
||||
timer_gateway:send( TGW_KEY, linda, key, nil, nil ) -- clear the timer
|
||||
return -- nothing more to do
|
||||
end
|
||||
a= period
|
||||
end
|
||||
|
||||
local wakeup_at= type(a)=="table" and wakeup_conv(a) -- given point of time
|
||||
or now_secs()+a
|
||||
-- queue to timer
|
||||
--
|
||||
timer_gateway:send( TGW_KEY, linda, key, wakeup_at, period )
|
||||
end
|
||||
|
||||
|
||||
---=== Lock & atomic generators ===---
|
||||
|
||||
-- These functions are just surface sugar, but make solutions easier to read.
|
||||
-- Not many applications should even need explicit locks or atomic counters.
|
||||
|
||||
--
|
||||
-- lock_f= lanes.genlock( linda_h, key [,N_uint=1] )
|
||||
--
|
||||
-- = lock_f( +M ) -- acquire M
|
||||
-- ...locked...
|
||||
-- = lock_f( -M ) -- release M
|
||||
--
|
||||
-- Returns an access function that allows 'N' simultaneous entries between
|
||||
-- acquire (+M) and release (-M). For binary locks, use M==1.
|
||||
--
|
||||
function genlock( linda, key, N )
|
||||
linda:limit(key,N)
|
||||
linda:set(key,nil) -- clears existing data
|
||||
|
||||
--
|
||||
-- [true [, ...]= trues(uint)
|
||||
--
|
||||
local function trues(n)
|
||||
if n>0 then return true,trues(n-1) end
|
||||
end
|
||||
|
||||
return
|
||||
function(M)
|
||||
if M>0 then
|
||||
-- 'nil' timeout allows 'key' to be numeric
|
||||
linda:send( nil, key, trues(M) ) -- suspends until been able to push them
|
||||
else
|
||||
for i=1,-M do
|
||||
linda:receive( key )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- atomic_f= lanes.genatomic( linda_h, key [,initial_num=0.0] )
|
||||
--
|
||||
-- int= atomic_f( [diff_num=1.0] )
|
||||
--
|
||||
-- Returns an access function that allows atomic increment/decrement of the
|
||||
-- number in 'key'.
|
||||
--
|
||||
function genatomic( linda, key, initial_val )
|
||||
linda:limit(key,2) -- value [,true]
|
||||
linda:set(key,initial_val or 0.0) -- clears existing data (also queue)
|
||||
|
||||
return
|
||||
function(diff)
|
||||
-- 'nil' allows 'key' to be numeric
|
||||
linda:send( nil, key, true ) -- suspends until our 'true' is in
|
||||
local val= linda:get(key) + (diff or 1.0)
|
||||
linda:set( key, val ) -- releases the lock, by emptying queue
|
||||
return val
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--the end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,721 +0,0 @@
|
||||
/*
|
||||
* THREADING.C Copyright (c) 2007-08, Asko Kauppi
|
||||
*
|
||||
* Lua Lanes OS threading specific code.
|
||||
*
|
||||
* References:
|
||||
* <http://www.cse.wustl.edu/~schmidt/win32-cv-1.html>
|
||||
*/
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Copyright (C) 2007-08 Asko Kauppi <akauppi@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "threading.h"
|
||||
#include "lua.h"
|
||||
|
||||
#if !((defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC))
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(PLATFORM_LINUX) || defined(PLATFORM_CYGWIN)
|
||||
# include <sys/types.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* Linux needs to check, whether it's been run as root
|
||||
*/
|
||||
#ifdef PLATFORM_LINUX
|
||||
volatile bool_t sudo;
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// ".. selected for automatic inline expansion" (/O2 option)
|
||||
# pragma warning( disable : 4711 )
|
||||
// ".. type cast from function pointer ... to data pointer"
|
||||
# pragma warning( disable : 4054 )
|
||||
#endif
|
||||
|
||||
//#define THREAD_CREATE_RETRIES_MAX 20
|
||||
// loops (maybe retry forever?)
|
||||
|
||||
/*
|
||||
* FAIL is for unexpected API return values - essentially programming
|
||||
* error in _this_ code.
|
||||
*/
|
||||
#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
|
||||
static void FAIL( const char *funcname, int rc ) {
|
||||
fprintf( stderr, "%s() failed! (%d)\n", funcname, rc );
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Returns millisecond timing (in seconds) for the current time.
|
||||
*
|
||||
* Note: This function should be called once in single-threaded mode in Win32,
|
||||
* to get it initialized.
|
||||
*/
|
||||
time_d now_secs(void) {
|
||||
|
||||
#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
|
||||
/*
|
||||
* Windows FILETIME values are "100-nanosecond intervals since
|
||||
* January 1, 1601 (UTC)" (MSDN). Well, we'd want Unix Epoch as
|
||||
* the offset and it seems, so would they:
|
||||
*
|
||||
* <http://msdn.microsoft.com/en-us/library/ms724928(VS.85).aspx>
|
||||
*/
|
||||
SYSTEMTIME st;
|
||||
FILETIME ft;
|
||||
ULARGE_INTEGER uli;
|
||||
static ULARGE_INTEGER uli_epoch; // Jan 1st 1970 0:0:0
|
||||
|
||||
if (uli_epoch.HighPart==0) {
|
||||
st.wYear= 1970;
|
||||
st.wMonth= 1; // Jan
|
||||
st.wDay= 1;
|
||||
st.wHour= st.wMinute= st.wSecond= st.wMilliseconds= 0;
|
||||
|
||||
if (!SystemTimeToFileTime( &st, &ft ))
|
||||
FAIL( "SystemTimeToFileTime", GetLastError() );
|
||||
|
||||
uli_epoch.LowPart= ft.dwLowDateTime;
|
||||
uli_epoch.HighPart= ft.dwHighDateTime;
|
||||
}
|
||||
|
||||
GetSystemTime( &st ); // current system date/time in UTC
|
||||
if (!SystemTimeToFileTime( &st, &ft ))
|
||||
FAIL( "SystemTimeToFileTime", GetLastError() );
|
||||
|
||||
uli.LowPart= ft.dwLowDateTime;
|
||||
uli.HighPart= ft.dwHighDateTime;
|
||||
|
||||
/* 'double' has less accuracy than 64-bit int, but if it were to degrade,
|
||||
* it would do so gracefully. In practise, the integer accuracy is not
|
||||
* of the 100ns class but just 1ms (Windows XP).
|
||||
*/
|
||||
# if 1
|
||||
// >= 2.0.3 code
|
||||
return (double) ((uli.QuadPart - uli_epoch.QuadPart)/10000) / 1000.0;
|
||||
# elif 0
|
||||
// fix from Kriss Daniels, see:
|
||||
// <http://luaforge.net/forum/forum.php?thread_id=22704&forum_id=1781>
|
||||
//
|
||||
// "seem to be getting negative numbers from the old version, probably number
|
||||
// conversion clipping, this fixes it and maintains ms resolution"
|
||||
//
|
||||
// This was a bad fix, and caused timer test 5 sec timers to disappear.
|
||||
// --AKa 25-Jan-2009
|
||||
//
|
||||
return ((double)((signed)((uli.QuadPart/10000) - (uli_epoch.QuadPart/10000)))) / 1000.0;
|
||||
# else
|
||||
// <= 2.0.2 code
|
||||
return (double)(uli.QuadPart - uli_epoch.QuadPart) / 10000000.0;
|
||||
# endif
|
||||
#else
|
||||
struct timeval tv;
|
||||
// {
|
||||
// time_t tv_sec; /* seconds since Jan. 1, 1970 */
|
||||
// suseconds_t tv_usec; /* and microseconds */
|
||||
// };
|
||||
|
||||
int rc= gettimeofday( &tv, NULL /*time zone not used any more (in Linux)*/ );
|
||||
assert( rc==0 );
|
||||
|
||||
return ((double)tv.tv_sec) + ((tv.tv_usec)/1000) / 1000.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*/
|
||||
time_d SIGNAL_TIMEOUT_PREPARE( double secs ) {
|
||||
if (secs<=0.0) return secs;
|
||||
else return now_secs() + secs;
|
||||
}
|
||||
|
||||
|
||||
#if !((defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC))
|
||||
/*
|
||||
* Prepare 'abs_secs' kind of timeout to 'timespec' format
|
||||
*/
|
||||
static void prepare_timeout( struct timespec *ts, time_d abs_secs ) {
|
||||
assert(ts);
|
||||
assert( abs_secs >= 0.0 );
|
||||
|
||||
if (abs_secs==0.0)
|
||||
abs_secs= now_secs();
|
||||
|
||||
ts->tv_sec= floor( abs_secs );
|
||||
ts->tv_nsec= ((long)((abs_secs - ts->tv_sec) * 1000.0 +0.5)) * 1000000UL; // 1ms = 1000000ns
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*---=== Threading ===---*/
|
||||
|
||||
//---
|
||||
// It may be meaningful to explicitly limit the new threads' C stack size.
|
||||
// We should know how much Lua needs in the C stack, all Lua side allocations
|
||||
// are done in heap so they don't count.
|
||||
//
|
||||
// Consequence of _not_ limiting the stack is running out of virtual memory
|
||||
// with 1000-5000 threads on 32-bit systems.
|
||||
//
|
||||
// Note: using external C modules may be affected by the stack size check.
|
||||
// if having problems, set back to '0' (default stack size of the system).
|
||||
//
|
||||
// Win32: 64K (?)
|
||||
// Win64: xxx
|
||||
//
|
||||
// Linux x86: 2MB Ubuntu 7.04 via 'pthread_getstacksize()'
|
||||
// Linux x64: xxx
|
||||
// Linux ARM: xxx
|
||||
//
|
||||
// OS X 10.4.9: 512K <http://developer.apple.com/qa/qa2005/qa1419.html>
|
||||
// valid values N * 4KB
|
||||
//
|
||||
#ifndef _THREAD_STACK_SIZE
|
||||
# if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PLATFORM_CYGWIN)
|
||||
# define _THREAD_STACK_SIZE 0
|
||||
// Win32: does it work with less?
|
||||
# elif (defined PLATFORM_OSX)
|
||||
# define _THREAD_STACK_SIZE (524288/2) // 262144
|
||||
// OS X: "make test" works on 65536 and even below
|
||||
// "make perftest" works on >= 4*65536 == 262144 (not 3*65536)
|
||||
# elif (defined PLATFORM_LINUX) && (defined __i386)
|
||||
# define _THREAD_STACK_SIZE (2097152/16) // 131072
|
||||
// Linux x86 (Ubuntu 7.04): "make perftest" works on /16 (not on /32)
|
||||
# elif (defined PLATFORM_BSD) && (defined __i386)
|
||||
# define _THREAD_STACK_SIZE (1048576/8) // 131072
|
||||
// FreeBSD 6.2 SMP i386: ("gmake perftest" works on /8 (not on /16)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
|
||||
//
|
||||
void MUTEX_INIT( MUTEX_T *ref ) {
|
||||
*ref= CreateMutex( NULL /*security attr*/, FALSE /*not locked*/, NULL );
|
||||
if (!ref) FAIL( "CreateMutex", GetLastError() );
|
||||
}
|
||||
void MUTEX_FREE( MUTEX_T *ref ) {
|
||||
if (!CloseHandle(*ref)) FAIL( "CloseHandle (mutex)", GetLastError() );
|
||||
*ref= NULL;
|
||||
}
|
||||
void MUTEX_LOCK( MUTEX_T *ref ) {
|
||||
DWORD rc= WaitForSingleObject(*ref,INFINITE);
|
||||
if (rc!=0) FAIL( "WaitForSingleObject", rc==WAIT_FAILED ? GetLastError() : rc );
|
||||
}
|
||||
void MUTEX_UNLOCK( MUTEX_T *ref ) {
|
||||
if (!ReleaseMutex(*ref))
|
||||
FAIL( "ReleaseMutex", GetLastError() );
|
||||
}
|
||||
/* MSDN: "If you would like to use the CRT in ThreadProc, use the
|
||||
_beginthreadex function instead (of CreateThread)."
|
||||
MSDN: "you can create at most 2028 threads"
|
||||
*/
|
||||
void
|
||||
THREAD_CREATE( THREAD_T *ref,
|
||||
THREAD_RETURN_T (__stdcall *func)( void * ),
|
||||
// Note: Visual C++ requires '__stdcall' where it is
|
||||
void *data, int prio /* -3..+3 */ ) {
|
||||
|
||||
HANDLE h= (HANDLE)_beginthreadex( NULL, // security
|
||||
_THREAD_STACK_SIZE,
|
||||
func,
|
||||
data,
|
||||
0, // flags (0/CREATE_SUSPENDED)
|
||||
NULL // thread id (not used)
|
||||
);
|
||||
|
||||
if (h == INVALID_HANDLE_VALUE) FAIL( "CreateThread", GetLastError() );
|
||||
|
||||
if (prio!= 0) {
|
||||
int win_prio= (prio == +3) ? THREAD_PRIORITY_TIME_CRITICAL :
|
||||
(prio == +2) ? THREAD_PRIORITY_HIGHEST :
|
||||
(prio == +1) ? THREAD_PRIORITY_ABOVE_NORMAL :
|
||||
(prio == -1) ? THREAD_PRIORITY_BELOW_NORMAL :
|
||||
(prio == -2) ? THREAD_PRIORITY_LOWEST :
|
||||
THREAD_PRIORITY_IDLE; // -3
|
||||
|
||||
if (!SetThreadPriority( h, win_prio ))
|
||||
FAIL( "SetThreadPriority", GetLastError() );
|
||||
}
|
||||
*ref= h;
|
||||
}
|
||||
//
|
||||
bool_t THREAD_WAIT( THREAD_T *ref, double secs ) {
|
||||
long ms= (long)((secs*1000.0)+0.5);
|
||||
|
||||
DWORD rc= WaitForSingleObject( *ref, ms<0 ? INFINITE:ms /*timeout*/ );
|
||||
//
|
||||
// (WAIT_ABANDONED)
|
||||
// WAIT_OBJECT_0 success (0)
|
||||
// WAIT_TIMEOUT
|
||||
// WAIT_FAILED more info via GetLastError()
|
||||
|
||||
if (rc == WAIT_TIMEOUT) return FALSE;
|
||||
if (rc != 0) FAIL( "WaitForSingleObject", rc );
|
||||
*ref= NULL; // thread no longer usable
|
||||
return TRUE;
|
||||
}
|
||||
//
|
||||
void THREAD_KILL( THREAD_T *ref ) {
|
||||
if (!TerminateThread( *ref, 0 )) FAIL("TerminateThread", GetLastError());
|
||||
*ref= NULL;
|
||||
}
|
||||
//
|
||||
void SIGNAL_INIT( SIGNAL_T *ref ) {
|
||||
// 'manual reset' event type selected, to be able to wake up all the
|
||||
// waiting threads.
|
||||
//
|
||||
HANDLE h= CreateEvent( NULL, // security attributes
|
||||
TRUE, // TRUE: manual event
|
||||
FALSE, // Initial state
|
||||
NULL ); // name
|
||||
|
||||
if (h == NULL) FAIL( "CreateEvent", GetLastError() );
|
||||
*ref= h;
|
||||
}
|
||||
void SIGNAL_FREE( SIGNAL_T *ref ) {
|
||||
if (!CloseHandle(*ref)) FAIL( "CloseHandle (event)", GetLastError() );
|
||||
*ref= NULL;
|
||||
}
|
||||
//
|
||||
bool_t SIGNAL_WAIT( SIGNAL_T *ref, MUTEX_T *mu_ref, time_d abs_secs ) {
|
||||
DWORD rc;
|
||||
long ms;
|
||||
|
||||
if (abs_secs<0.0)
|
||||
ms= INFINITE;
|
||||
else if (abs_secs==0.0)
|
||||
ms= 0;
|
||||
else {
|
||||
ms= (long) ((abs_secs - now_secs())*1000.0 + 0.5);
|
||||
|
||||
// If the time already passed, still try once (ms==0). A short timeout
|
||||
// may have turned negative or 0 because of the two time samples done.
|
||||
//
|
||||
if (ms<0) ms= 0;
|
||||
}
|
||||
|
||||
// Unlock and start a wait, atomically (like condition variables do)
|
||||
//
|
||||
rc= SignalObjectAndWait( *mu_ref, // "object to signal" (unlock)
|
||||
*ref, // "object to wait on"
|
||||
ms,
|
||||
FALSE ); // not alertable
|
||||
|
||||
// All waiting locks are woken here; each competes for the lock in turn.
|
||||
//
|
||||
// Note: We must get the lock even if we've timed out; it makes upper
|
||||
// level code equivalent to how PThread does it.
|
||||
//
|
||||
MUTEX_LOCK(mu_ref);
|
||||
|
||||
if (rc==WAIT_TIMEOUT) return FALSE;
|
||||
if (rc!=0) FAIL( "SignalObjectAndWait", rc );
|
||||
return TRUE;
|
||||
}
|
||||
void SIGNAL_ALL( SIGNAL_T *ref ) {
|
||||
/*
|
||||
* MSDN tries to scare that 'PulseEvent' is bad, unreliable and should not be
|
||||
* used. Use condition variables instead (wow, they have that!?!); which will
|
||||
* ONLY WORK on Vista and 2008 Server, it seems... so MS, isn't it.
|
||||
*
|
||||
* I refuse to believe that; using 'PulseEvent' is probably just as good as
|
||||
* using Windows (XP) in the first place. Just don't use APC's (asynchronous
|
||||
* process calls) in your C side coding.
|
||||
*/
|
||||
// PulseEvent on manual event:
|
||||
//
|
||||
// Release ALL threads waiting for it (and go instantly back to unsignalled
|
||||
// status = future threads to start a wait will wait)
|
||||
//
|
||||
if (!PulseEvent( *ref ))
|
||||
FAIL( "PulseEvent", GetLastError() );
|
||||
}
|
||||
#else
|
||||
// PThread (Linux, OS X, ...)
|
||||
//
|
||||
// On OS X, user processes seem to be able to change priorities.
|
||||
// On Linux, SCHED_RR and su privileges are required.. !-(
|
||||
//
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
//
|
||||
static void _PT_FAIL( int rc, const char *name, const char *file, uint_t line ) {
|
||||
const char *why= (rc==EINVAL) ? "EINVAL" :
|
||||
(rc==EBUSY) ? "EBUSY" :
|
||||
(rc==EPERM) ? "EPERM" :
|
||||
(rc==ENOMEM) ? "ENOMEM" :
|
||||
(rc==ESRCH) ? "ESRCH" :
|
||||
//...
|
||||
"";
|
||||
fprintf( stderr, "%s %d: %s failed, %d %s\n", file, line, name, rc, why );
|
||||
abort();
|
||||
}
|
||||
#define PT_CALL( call ) { int rc= call; if (rc!=0) _PT_FAIL( rc, #call, __FILE__, __LINE__ ); }
|
||||
//
|
||||
void SIGNAL_INIT( SIGNAL_T *ref ) {
|
||||
PT_CALL( pthread_cond_init(ref,NULL /*attr*/) );
|
||||
}
|
||||
void SIGNAL_FREE( SIGNAL_T *ref ) {
|
||||
PT_CALL( pthread_cond_destroy(ref) );
|
||||
}
|
||||
//
|
||||
/*
|
||||
* Timeout is given as absolute since we may have fake wakeups during
|
||||
* a timed out sleep. A Linda with some other key read, or just because
|
||||
* PThread cond vars can wake up unwantedly.
|
||||
*/
|
||||
bool_t SIGNAL_WAIT( SIGNAL_T *ref, pthread_mutex_t *mu, time_d abs_secs ) {
|
||||
if (abs_secs<0.0) {
|
||||
PT_CALL( pthread_cond_wait( ref, mu ) ); // infinite
|
||||
} else {
|
||||
int rc;
|
||||
struct timespec ts;
|
||||
|
||||
assert( abs_secs != 0.0 );
|
||||
prepare_timeout( &ts, abs_secs );
|
||||
|
||||
rc= pthread_cond_timedwait( ref, mu, &ts );
|
||||
|
||||
if (rc==ETIMEDOUT) return FALSE;
|
||||
if (rc) { _PT_FAIL( rc, "pthread_cond_timedwait()", __FILE__, __LINE__ ); }
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
//
|
||||
void SIGNAL_ONE( SIGNAL_T *ref ) {
|
||||
PT_CALL( pthread_cond_signal(ref) ); // wake up ONE (or no) waiting thread
|
||||
}
|
||||
//
|
||||
void SIGNAL_ALL( SIGNAL_T *ref ) {
|
||||
PT_CALL( pthread_cond_broadcast(ref) ); // wake up ALL waiting threads
|
||||
}
|
||||
//
|
||||
void THREAD_CREATE( THREAD_T* ref,
|
||||
THREAD_RETURN_T (*func)( void * ),
|
||||
void *data, int prio /* -2..+2 */ ) {
|
||||
pthread_attr_t _a;
|
||||
pthread_attr_t *a= &_a;
|
||||
struct sched_param sp;
|
||||
|
||||
PT_CALL( pthread_attr_init(a) );
|
||||
|
||||
#ifndef PTHREAD_TIMEDJOIN
|
||||
// We create a NON-JOINABLE thread. This is mainly due to the lack of
|
||||
// 'pthread_timedjoin()', but does offer other benefits (s.a. earlier
|
||||
// freeing of the thread's resources).
|
||||
//
|
||||
PT_CALL( pthread_attr_setdetachstate(a,PTHREAD_CREATE_DETACHED) );
|
||||
#endif
|
||||
|
||||
// Use this to find a system's default stack size (DEBUG)
|
||||
#if 0
|
||||
{ size_t n; pthread_attr_getstacksize( a, &n );
|
||||
fprintf( stderr, "Getstack: %u\n", (unsigned int)n ); }
|
||||
// 524288 on OS X
|
||||
// 2097152 on Linux x86 (Ubuntu 7.04)
|
||||
// 1048576 on FreeBSD 6.2 SMP i386
|
||||
#endif
|
||||
|
||||
#if (defined _THREAD_STACK_SIZE) && (_THREAD_STACK_SIZE > 0)
|
||||
PT_CALL( pthread_attr_setstacksize( a, _THREAD_STACK_SIZE ) );
|
||||
#endif
|
||||
|
||||
bool_t normal=
|
||||
#if defined(PLATFORM_LINUX) && defined(LINUX_SCHED_RR)
|
||||
!sudo; // with sudo, even normal thread must use SCHED_RR
|
||||
#else
|
||||
prio == 0; // create a default thread if
|
||||
#endif
|
||||
if (!normal) {
|
||||
// NB: PThreads priority handling is about as twisty as one can get it
|
||||
// (and then some). DON*T TRUST ANYTHING YOU READ ON THE NET!!!
|
||||
|
||||
// "The specified scheduling parameters are only used if the scheduling
|
||||
// parameter inheritance attribute is PTHREAD_EXPLICIT_SCHED."
|
||||
//
|
||||
PT_CALL( pthread_attr_setinheritsched( a, PTHREAD_EXPLICIT_SCHED ) );
|
||||
|
||||
//---
|
||||
// "Select the scheduling policy for the thread: one of SCHED_OTHER
|
||||
// (regular, non-real-time scheduling), SCHED_RR (real-time,
|
||||
// round-robin) or SCHED_FIFO (real-time, first-in first-out)."
|
||||
//
|
||||
// "Using the RR policy ensures that all threads having the same
|
||||
// priority level will be scheduled equally, regardless of their activity."
|
||||
//
|
||||
// "For SCHED_FIFO and SCHED_RR, the only required member of the
|
||||
// sched_param structure is the priority sched_priority. For SCHED_OTHER,
|
||||
// the affected scheduling parameters are implementation-defined."
|
||||
//
|
||||
// "The priority of a thread is specified as a delta which is added to
|
||||
// the priority of the process."
|
||||
//
|
||||
// ".. priority is an integer value, in the range from 1 to 127.
|
||||
// 1 is the least-favored priority, 127 is the most-favored."
|
||||
//
|
||||
// "Priority level 0 cannot be used: it is reserved for the system."
|
||||
//
|
||||
// "When you use specify a priority of -99 in a call to
|
||||
// pthread_setschedparam(), the priority of the target thread is
|
||||
// lowered to the lowest possible value."
|
||||
//
|
||||
// ...
|
||||
|
||||
// ** CONCLUSION **
|
||||
//
|
||||
// PThread priorities are _hugely_ system specific, and we need at
|
||||
// least OS specific settings. Hopefully, Linuxes and OS X versions
|
||||
// are uniform enough, among each other...
|
||||
//
|
||||
#ifdef PLATFORM_OSX
|
||||
// AK 10-Apr-07 (OS X PowerPC 10.4.9):
|
||||
//
|
||||
// With SCHED_RR, 26 seems to be the "normal" priority, where setting
|
||||
// it does not seem to affect the order of threads processed.
|
||||
//
|
||||
// With SCHED_OTHER, the range 25..32 is normal (maybe the same 26,
|
||||
// but the difference is not so clear with OTHER).
|
||||
//
|
||||
// 'sched_get_priority_min()' and '..max()' give 15, 47 as the
|
||||
// priority limits. This could imply, user mode applications won't
|
||||
// be able to use values outside of that range.
|
||||
//
|
||||
#define _PRIO_MODE SCHED_OTHER
|
||||
|
||||
// OS X 10.4.9 (PowerPC) gives ENOTSUP for process scope
|
||||
//#define _PRIO_SCOPE PTHREAD_SCOPE_PROCESS
|
||||
|
||||
#define _PRIO_HI 32 // seems to work (_carefully_ picked!)
|
||||
#define _PRIO_0 26 // detected
|
||||
#define _PRIO_LO 1 // seems to work (tested)
|
||||
|
||||
#elif defined(PLATFORM_LINUX)
|
||||
// (based on Ubuntu Linux 2.6.15 kernel)
|
||||
//
|
||||
// SCHED_OTHER is the default policy, but does not allow for priorities.
|
||||
// SCHED_RR allows priorities, all of which (1..99) are higher than
|
||||
// a thread with SCHED_OTHER policy.
|
||||
//
|
||||
// <http://kerneltrap.org/node/6080>
|
||||
// <http://en.wikipedia.org/wiki/Native_POSIX_Thread_Library>
|
||||
// <http://www.net.in.tum.de/~gregor/docs/pthread-scheduling.html>
|
||||
//
|
||||
// Manuals suggest checking #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING,
|
||||
// but even Ubuntu does not seem to define it.
|
||||
//
|
||||
#define _PRIO_MODE SCHED_RR
|
||||
|
||||
// NTLP 2.5: only system scope allowed (being the basic reason why
|
||||
// root privileges are required..)
|
||||
//#define _PRIO_SCOPE PTHREAD_SCOPE_PROCESS
|
||||
|
||||
#define _PRIO_HI 99
|
||||
#define _PRIO_0 50
|
||||
#define _PRIO_LO 1
|
||||
|
||||
#elif defined(PLATFORM_BSD)
|
||||
//
|
||||
// <http://www.net.in.tum.de/~gregor/docs/pthread-scheduling.html>
|
||||
//
|
||||
// "When control over the thread scheduling is desired, then FreeBSD
|
||||
// with the libpthread implementation is by far the best choice .."
|
||||
//
|
||||
#define _PRIO_MODE SCHED_OTHER
|
||||
#define _PRIO_SCOPE PTHREAD_SCOPE_PROCESS
|
||||
#define _PRIO_HI 31
|
||||
#define _PRIO_0 15
|
||||
#define _PRIO_LO 1
|
||||
|
||||
#elif defined(PLATFORM_CYGWIN)
|
||||
//
|
||||
// TBD: Find right values for Cygwin
|
||||
//
|
||||
#else
|
||||
#error "Unknown OS: not implemented!"
|
||||
#endif
|
||||
|
||||
#ifdef _PRIO_SCOPE
|
||||
PT_CALL( pthread_attr_setscope( a, _PRIO_SCOPE ) );
|
||||
#endif
|
||||
PT_CALL( pthread_attr_setschedpolicy( a, _PRIO_MODE ) );
|
||||
|
||||
#define _PRIO_AN (_PRIO_0 + ((_PRIO_HI-_PRIO_0)/2) )
|
||||
#define _PRIO_BN (_PRIO_LO + ((_PRIO_0-_PRIO_LO)/2) )
|
||||
|
||||
sp.sched_priority=
|
||||
(prio == +2) ? _PRIO_HI :
|
||||
(prio == +1) ? _PRIO_AN :
|
||||
#if defined(PLATFORM_LINUX) && defined(LINUX_SCHED_RR)
|
||||
(prio == 0) ? _PRIO_0 :
|
||||
#endif
|
||||
(prio == -1) ? _PRIO_BN : _PRIO_LO;
|
||||
|
||||
PT_CALL( pthread_attr_setschedparam( a, &sp ) );
|
||||
}
|
||||
|
||||
//---
|
||||
// Seems on OS X, _POSIX_THREAD_THREADS_MAX is some kind of system
|
||||
// thread limit (not userland thread). Actual limit for us is way higher.
|
||||
// PTHREAD_THREADS_MAX is not defined (even though man page refers to it!)
|
||||
//
|
||||
# ifndef THREAD_CREATE_RETRIES_MAX
|
||||
// Don't bother with retries; a failure is a failure
|
||||
//
|
||||
{
|
||||
int rc= pthread_create( ref, a, func, data );
|
||||
if (rc) _PT_FAIL( rc, "pthread_create()", __FILE__, __LINE__-1 );
|
||||
}
|
||||
# else
|
||||
# error "This code deprecated"
|
||||
/*
|
||||
// Wait slightly if thread creation has exchausted the system
|
||||
//
|
||||
{ uint_t retries;
|
||||
for( retries=0; retries<THREAD_CREATE_RETRIES_MAX; retries++ ) {
|
||||
|
||||
int rc= pthread_create( ref, a, func, data );
|
||||
//
|
||||
// OS X / Linux:
|
||||
// EAGAIN: ".. lacked the necessary resources to create
|
||||
// another thread, or the system-imposed limit on the
|
||||
// total number of threads in a process
|
||||
// [PTHREAD_THREADS_MAX] would be exceeded."
|
||||
// EINVAL: attr is invalid
|
||||
// Linux:
|
||||
// EPERM: no rights for given parameters or scheduling (no sudo)
|
||||
// ENOMEM: (known to fail with this code, too - not listed in man)
|
||||
|
||||
if (rc==0) break; // ok!
|
||||
|
||||
// In practise, exhaustion seems to be coming from memory, not a
|
||||
// maximum number of threads. Keep tuning... ;)
|
||||
//
|
||||
if (rc==EAGAIN) {
|
||||
//fprintf( stderr, "Looping (retries=%d) ", retries ); // DEBUG
|
||||
|
||||
// Try again, later.
|
||||
|
||||
Yield();
|
||||
} else {
|
||||
_PT_FAIL( rc, "pthread_create()", __FILE__, __LINE__ );
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
# endif
|
||||
|
||||
if (a) {
|
||||
PT_CALL( pthread_attr_destroy(a) );
|
||||
}
|
||||
}
|
||||
//
|
||||
/*
|
||||
* Wait for a thread to finish.
|
||||
*
|
||||
* 'mu_ref' is a lock we should use for the waiting; initially unlocked.
|
||||
* Same lock as passed to THREAD_EXIT.
|
||||
*
|
||||
* Returns TRUE for succesful wait, FALSE for timed out
|
||||
*/
|
||||
#ifdef PTHREAD_TIMEDJOIN
|
||||
bool_t THREAD_WAIT( THREAD_T *ref, double secs )
|
||||
#else
|
||||
bool_t THREAD_WAIT( THREAD_T *ref, SIGNAL_T *signal_ref, MUTEX_T *mu_ref, volatile enum e_status *st_ref, double secs )
|
||||
#endif
|
||||
{
|
||||
struct timespec ts_store;
|
||||
const struct timespec *timeout= NULL;
|
||||
bool_t done;
|
||||
|
||||
// Do timeout counting before the locks
|
||||
//
|
||||
#ifdef PTHREAD_TIMEDJOIN
|
||||
if (secs>=0.0) {
|
||||
#else
|
||||
if (secs>0.0) {
|
||||
#endif
|
||||
prepare_timeout( &ts_store, now_secs()+secs );
|
||||
timeout= &ts_store;
|
||||
}
|
||||
|
||||
#ifdef PTHREAD_TIMEDJOIN
|
||||
/* Thread is joinable
|
||||
*/
|
||||
if (!timeout) {
|
||||
PT_CALL( pthread_join( *ref, NULL /*ignore exit value*/ ));
|
||||
done= TRUE;
|
||||
} else {
|
||||
int rc= PTHREAD_TIMEDJOIN( *ref, NULL, timeout );
|
||||
if ((rc!=0) && (rc!=ETIMEDOUT)) {
|
||||
_PT_FAIL( rc, "PTHREAD_TIMEDJOIN", __FILE__, __LINE__-2 );
|
||||
}
|
||||
done= rc==0;
|
||||
}
|
||||
#else
|
||||
/* Since we've set the thread up as PTHREAD_CREATE_DETACHED, we cannot
|
||||
* join with it. Use the cond.var.
|
||||
*/
|
||||
MUTEX_LOCK( mu_ref );
|
||||
|
||||
// 'secs'==0.0 does not need to wait, just take the current status
|
||||
// within the 'mu_ref' locks
|
||||
//
|
||||
if (secs != 0.0) {
|
||||
while( *st_ref < DONE ) {
|
||||
if (!timeout) {
|
||||
PT_CALL( pthread_cond_wait( signal_ref, mu_ref ));
|
||||
} else {
|
||||
int rc= pthread_cond_timedwait( signal_ref, mu_ref, timeout );
|
||||
if (rc==ETIMEDOUT) break;
|
||||
if (rc!=0) _PT_FAIL( rc, "pthread_cond_timedwait", __FILE__, __LINE__-2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
done= *st_ref >= DONE; // DONE|ERROR_ST|CANCELLED
|
||||
|
||||
MUTEX_UNLOCK( mu_ref );
|
||||
#endif
|
||||
return done;
|
||||
}
|
||||
//
|
||||
void THREAD_KILL( THREAD_T *ref ) {
|
||||
pthread_cancel( *ref );
|
||||
}
|
||||
#endif
|
||||
|
||||
static const lua_Alloc alloc_f= 0;
|
||||
@@ -1,196 +0,0 @@
|
||||
/*
|
||||
* THREADING.H
|
||||
*/
|
||||
#ifndef THREADING_H
|
||||
#define THREADING_H
|
||||
|
||||
/* Platform detection
|
||||
*/
|
||||
#ifdef _WIN32_WCE
|
||||
#define PLATFORM_POCKETPC
|
||||
#elif (defined _WIN32)
|
||||
#define PLATFORM_WIN32
|
||||
#elif (defined __linux__)
|
||||
#define PLATFORM_LINUX
|
||||
#elif (defined __APPLE__) && (defined __MACH__)
|
||||
#define PLATFORM_OSX
|
||||
#elif (defined __NetBSD__) || (defined __FreeBSD__) || (defined BSD)
|
||||
#define PLATFORM_BSD
|
||||
#elif (defined __QNX__)
|
||||
#define PLATFORM_QNX
|
||||
#elif (defined __CYGWIN__)
|
||||
#define PLATFORM_CYGWIN
|
||||
#else
|
||||
#error "Unknown platform!"
|
||||
#endif
|
||||
|
||||
typedef int bool_t;
|
||||
#ifndef FALSE
|
||||
# define FALSE 0
|
||||
# define TRUE 1
|
||||
#endif
|
||||
|
||||
typedef unsigned int uint_t;
|
||||
|
||||
#if defined(PLATFORM_WIN32) && defined(__GNUC__)
|
||||
/* MinGW with MSVCR80.DLL */
|
||||
/* Do this BEFORE including time.h so that it is declaring _mktime32()
|
||||
* as it would have declared mktime().
|
||||
*/
|
||||
# define mktime _mktime32
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
/* Note: ERROR is a defined entity on Win32
|
||||
*/
|
||||
enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED };
|
||||
|
||||
|
||||
/*---=== Locks & Signals ===---
|
||||
*/
|
||||
|
||||
#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
// 'SignalObjectAndWait' needs this (targets Windows 2000 and above)
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#include <windows.h>
|
||||
#include <process.h>
|
||||
|
||||
// MSDN: http://msdn2.microsoft.com/en-us/library/ms684254.aspx
|
||||
//
|
||||
// CRITICAL_SECTION can be used for simple code protection. Mutexes are
|
||||
// needed for use with the SIGNAL system.
|
||||
//
|
||||
#define MUTEX_T HANDLE
|
||||
void MUTEX_INIT( MUTEX_T *ref );
|
||||
#define MUTEX_RECURSIVE_INIT(ref) MUTEX_INIT(ref) /* always recursive in Win32 */
|
||||
void MUTEX_FREE( MUTEX_T *ref );
|
||||
void MUTEX_LOCK( MUTEX_T *ref );
|
||||
void MUTEX_UNLOCK( MUTEX_T *ref );
|
||||
|
||||
typedef unsigned THREAD_RETURN_T;
|
||||
|
||||
#define SIGNAL_T HANDLE
|
||||
|
||||
#define YIELD() Sleep(0)
|
||||
#else
|
||||
// PThread (Linux, OS X, ...)
|
||||
//
|
||||
#include <pthread.h>
|
||||
|
||||
#ifdef PLATFORM_LINUX
|
||||
# define _MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
|
||||
#else
|
||||
/* OS X, ... */
|
||||
# define _MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE
|
||||
#endif
|
||||
|
||||
#define MUTEX_T pthread_mutex_t
|
||||
#define MUTEX_INIT(ref) pthread_mutex_init(ref,NULL)
|
||||
#define MUTEX_RECURSIVE_INIT(ref) \
|
||||
{ pthread_mutexattr_t a; pthread_mutexattr_init( &a ); \
|
||||
pthread_mutexattr_settype( &a, _MUTEX_RECURSIVE ); \
|
||||
pthread_mutex_init(ref,&a); pthread_mutexattr_destroy( &a ); \
|
||||
}
|
||||
#define MUTEX_FREE(ref) pthread_mutex_destroy(ref)
|
||||
#define MUTEX_LOCK(ref) pthread_mutex_lock(ref)
|
||||
#define MUTEX_UNLOCK(ref) pthread_mutex_unlock(ref)
|
||||
|
||||
typedef void * THREAD_RETURN_T;
|
||||
|
||||
typedef pthread_cond_t SIGNAL_T;
|
||||
|
||||
void SIGNAL_ONE( SIGNAL_T *ref );
|
||||
|
||||
// Yield is non-portable:
|
||||
//
|
||||
// OS X 10.4.8/9 has pthread_yield_np()
|
||||
// Linux 2.4 has pthread_yield() if _GNU_SOURCE is #defined
|
||||
// FreeBSD 6.2 has pthread_yield()
|
||||
// ...
|
||||
//
|
||||
#ifdef PLATFORM_OSX
|
||||
#define YIELD() pthread_yield_np()
|
||||
#else
|
||||
#define YIELD() pthread_yield()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void SIGNAL_INIT( SIGNAL_T *ref );
|
||||
void SIGNAL_FREE( SIGNAL_T *ref );
|
||||
void SIGNAL_ALL( SIGNAL_T *ref );
|
||||
|
||||
/*
|
||||
* 'time_d': <0.0 for no timeout
|
||||
* 0.0 for instant check
|
||||
* >0.0 absolute timeout in secs + ms
|
||||
*/
|
||||
typedef double time_d;
|
||||
time_d now_secs(void);
|
||||
|
||||
time_d SIGNAL_TIMEOUT_PREPARE( double rel_secs );
|
||||
|
||||
bool_t SIGNAL_WAIT( SIGNAL_T *ref, MUTEX_T *mu, time_d timeout );
|
||||
|
||||
|
||||
/*---=== Threading ===---
|
||||
*/
|
||||
|
||||
#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
|
||||
|
||||
typedef HANDLE THREAD_T;
|
||||
//
|
||||
void THREAD_CREATE( THREAD_T *ref,
|
||||
THREAD_RETURN_T (__stdcall *func)( void * ),
|
||||
void *data, int prio /* -3..+3 */ );
|
||||
|
||||
# define THREAD_PRIO_MIN (-3)
|
||||
# define THREAD_PRIO_MAX (+3)
|
||||
|
||||
#else
|
||||
/* Platforms that have a timed 'pthread_join()' can get away with a simpler
|
||||
* implementation. Others will use a condition variable.
|
||||
*/
|
||||
# ifdef USE_PTHREAD_TIMEDJOIN
|
||||
# ifdef PLATFORM_OSX
|
||||
# error "No 'pthread_timedjoin()' on this system"
|
||||
# else
|
||||
/* Linux, ... */
|
||||
# define PTHREAD_TIMEDJOIN pthread_timedjoin_np
|
||||
# endif
|
||||
# endif
|
||||
|
||||
typedef pthread_t THREAD_T;
|
||||
|
||||
void THREAD_CREATE( THREAD_T *ref,
|
||||
THREAD_RETURN_T (*func)( void * ),
|
||||
void *data, int prio /* -2..+2 */ );
|
||||
|
||||
# if defined(PLATFORM_LINUX)
|
||||
volatile bool_t sudo;
|
||||
# ifdef LINUX_SCHED_RR
|
||||
# define THREAD_PRIO_MIN (sudo ? -2 : 0)
|
||||
# else
|
||||
# define THREAD_PRIO_MIN (0)
|
||||
# endif
|
||||
# define THREAD_PRIO_MAX (sudo ? +2 : 0)
|
||||
# else
|
||||
# define THREAD_PRIO_MIN (-2)
|
||||
# define THREAD_PRIO_MAX (+2)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Win32 and PTHREAD_TIMEDJOIN allow waiting for a thread with a timeout.
|
||||
* Posix without PTHREAD_TIMEDJOIN needs to use a condition variable approach.
|
||||
*/
|
||||
#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN)
|
||||
bool_t THREAD_WAIT( THREAD_T *ref, double secs );
|
||||
#else
|
||||
bool_t THREAD_WAIT( THREAD_T *ref, SIGNAL_T *signal_ref, MUTEX_T *mu_ref, volatile enum e_status *st_ref, double secs );
|
||||
#endif
|
||||
|
||||
void THREAD_KILL( THREAD_T *ref );
|
||||
|
||||
#endif
|
||||
// THREADING_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* TOOLS.H
|
||||
*/
|
||||
#ifndef TOOLS_H
|
||||
#define TOOLS_H
|
||||
|
||||
#include "lua.h"
|
||||
#include "threading.h"
|
||||
// MUTEX_T
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
// Note: The < -10000 test is to leave registry/global/upvalue indices untouched
|
||||
//
|
||||
#define /*int*/ STACK_ABS(L,n) \
|
||||
( ((n) >= 0 || (n) <= -10000) ? (n) : lua_gettop(L) +(n) +1 )
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define _ASSERT_L(lua,c) /*nothing*/
|
||||
#define STACK_CHECK(L) /*nothing*/
|
||||
#define STACK_MID(L,c) /*nothing*/
|
||||
#define STACK_END(L,c) /*nothing*/
|
||||
#define STACK_DUMP(L) /*nothing*/
|
||||
#define DEBUG() /*nothing*/
|
||||
#else
|
||||
#define _ASSERT_L(lua,c) { if (!(c)) luaL_error( lua, "ASSERT failed: %s:%d '%s'", __FILE__, __LINE__, #c ); }
|
||||
//
|
||||
#define STACK_CHECK(L) { int _oldtop_##L = lua_gettop(L);
|
||||
#define STACK_MID(L,change) { int a= lua_gettop(L)-_oldtop_##L; int b= (change); \
|
||||
if (a != b) luaL_error( L, "STACK ASSERT failed (%d not %d): %s:%d", a, b, __FILE__, __LINE__ ); }
|
||||
#define STACK_END(L,change) STACK_MID(L,change) }
|
||||
|
||||
#define STACK_DUMP(L) luaG_dump(L);
|
||||
#define DEBUG() fprintf( stderr, "<<%s %d>>\n", __FILE__, __LINE__ );
|
||||
#endif
|
||||
#define ASSERT_L(c) _ASSERT_L(L,c)
|
||||
|
||||
#define STACK_GROW(L,n) { if (!lua_checkstack(L,n)) luaL_error( L, "Cannot grow stack!" ); }
|
||||
|
||||
#define LUAG_FUNC( func_name ) static int LG_##func_name( lua_State *L )
|
||||
|
||||
#define luaG_optunsigned(L,i,d) ((uint_t) luaL_optinteger(L,i,d))
|
||||
#define luaG_tounsigned(L,i) ((uint_t) lua_tointeger(L,i))
|
||||
|
||||
#define luaG_isany(L,i) (!lua_isnil(L,i))
|
||||
|
||||
#define luaG_typename( L, index ) lua_typename( L, lua_type(L,index) )
|
||||
|
||||
void luaG_dump( lua_State* L );
|
||||
|
||||
const char *luaG_openlibs( lua_State *L, const char *libs );
|
||||
|
||||
int luaG_deep_userdata( lua_State *L );
|
||||
void *luaG_todeep( lua_State *L, lua_CFunction idfunc, int index );
|
||||
|
||||
typedef struct {
|
||||
volatile int refcount;
|
||||
void *deep;
|
||||
} DEEP_PRELUDE;
|
||||
|
||||
void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *deep_userdata );
|
||||
|
||||
void luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n );
|
||||
void luaG_inter_move( lua_State *L, lua_State *L2, uint_t n );
|
||||
|
||||
// Lock for reference counter inc/dec locks (to be initialized by outside code)
|
||||
//
|
||||
extern MUTEX_T deep_lock;
|
||||
extern MUTEX_T mtid_lock;
|
||||
|
||||
#endif
|
||||
// TOOLS_H
|
||||
@@ -55,7 +55,6 @@
|
||||
|
||||
// Libraries.
|
||||
#include "libraries/luasocket/luasocket.h"
|
||||
#include "libraries/lanes/lanes.h"
|
||||
|
||||
// Scripts
|
||||
#include "scripts/boot.lua.h"
|
||||
@@ -136,7 +135,6 @@ extern "C" LOVE_EXPORT int luaopen_love(lua_State * L)
|
||||
}
|
||||
|
||||
love::luasocket::__open(L);
|
||||
love::lanes::open(L);
|
||||
|
||||
#endif // LOVE_BUILD_STANDALONE
|
||||
|
||||
|
||||
Reference in New Issue
Block a user