Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
别团等shy哥发育
redis
提交
6eb1ec22
R
redis
项目概览
别团等shy哥发育
/
redis
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
redis
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
6eb1ec22
编写于
4月 03, 2014
作者:
J
jonathan pickett
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
added Windows Service support to Redis
上级
e2a48cd7
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
564 addition
and
27 deletion
+564
-27
bin/release/redis-2.8.4.zip
bin/release/redis-2.8.4.zip
+0
-0
msvs/setups/documentation/Redis Release Notes.docx
msvs/setups/documentation/Redis Release Notes.docx
+0
-0
msvs/setups/documentation/RedisService.docx
msvs/setups/documentation/RedisService.docx
+0
-0
src/Win32_Interop/Win32_Interop.vcxproj
src/Win32_Interop/Win32_Interop.vcxproj
+2
-0
src/Win32_Interop/Win32_QFork.cpp
src/Win32_Interop/Win32_QFork.cpp
+40
-26
src/Win32_Interop/Win32_Service.h
src/Win32_Interop/Win32_Service.h
+35
-0
src/Win32_Interop/Win32_SmartHandle.h
src/Win32_Interop/Win32_SmartHandle.h
+46
-1
src/Win32_Interop/Win32_service.cpp
src/Win32_Interop/Win32_service.cpp
+435
-0
src/ae.c
src/ae.c
+6
-0
未找到文件。
bin/release/redis-2.8.4.zip
浏览文件 @
6eb1ec22
无法预览此类型文件
msvs/setups/documentation/Redis Release Notes.docx
浏览文件 @
6eb1ec22
无法预览此类型文件
msvs/setups/documentation/RedisService.docx
0 → 100644
浏览文件 @
6eb1ec22
文件已添加
src/Win32_Interop/Win32_Interop.vcxproj
浏览文件 @
6eb1ec22
...
...
@@ -19,6 +19,7 @@
<ClCompile
Include=
"Win32_QFork.cpp"
/>
<ClCompile
Include=
"Win32_QFork_impl.c"
/>
<ClCompile
Include=
"win32_rfdmap.cpp"
/>
<ClCompile
Include=
"Win32_service.cpp"
/>
<ClCompile
Include=
"Win32_variadicFunctor.cpp"
/>
<ClCompile
Include=
"win32_wsiocp.c"
/>
</ItemGroup>
...
...
@@ -31,6 +32,7 @@
<ClInclude
Include=
"Win32_QFork.h"
/>
<ClInclude
Include=
"Win32_QFork_impl.h"
/>
<ClInclude
Include=
"win32_rfdmap.h"
/>
<ClInclude
Include=
"Win32_Service.h"
/>
<ClInclude
Include=
"Win32_SmartHandle.h"
/>
<ClInclude
Include=
"Win32_variadicFunctor.h"
/>
<ClInclude
Include=
"win32_wsiocp.h"
/>
...
...
src/Win32_Interop/Win32_QFork.cpp
浏览文件 @
6eb1ec22
...
...
@@ -32,11 +32,13 @@
#include "Win32_QFork_impl.h"
#include "Win32_dlmalloc.h"
#include "Win32_SmartHandle.h"
#include "Win32_Service.h"
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <stdint.h>
#include <exception>
using
namespace
std
;
extern
"C"
...
...
@@ -784,7 +786,7 @@ BOOL BeginForkOperation(OperationType type, char* fileName, LPVOID globalData, i
char
arguments
[
_MAX_PATH
];
memset
(
arguments
,
0
,
_MAX_PATH
);
PROCESS_INFORMATION
pi
;
sprintf_s
(
arguments
,
_MAX_PATH
,
"%s %
ld
%ld"
,
qforkFlag
,
g_hQForkControlFileMap
,
GetCurrentProcessId
());
sprintf_s
(
arguments
,
_MAX_PATH
,
"%s %
p
%ld"
,
qforkFlag
,
g_hQForkControlFileMap
,
GetCurrentProcessId
());
if
(
FALSE
==
CreateProcessA
(
fileName
,
arguments
,
NULL
,
NULL
,
TRUE
,
0
,
NULL
,
NULL
,
&
si
,
&
pi
))
{
throw
system_error
(
GetLastError
(),
...
...
@@ -1171,33 +1173,45 @@ extern "C"
// is invoked so that the QFork allocator can be setup prior to anything
// Redis will allocate.
int
main
(
int
argc
,
char
*
argv
[])
{
try
{
#ifdef DEBUG_WITH_PROCMON
hProcMonDevice
=
CreateFile
(
L"
\\\\
.
\\
Global
\\
ProcmonDebugLogger"
,
GENERIC_READ
|
GENERIC_WRITE
,
FILE_SHARE_READ
|
FILE_SHARE_WRITE
|
FILE_SHARE_DELETE
,
NULL
,
OPEN_EXISTING
,
FILE_ATTRIBUTE_NORMAL
,
NULL
);
hProcMonDevice
=
CreateFile
(
L"
\\\\
.
\\
Global
\\
ProcmonDebugLogger"
,
GENERIC_READ
|
GENERIC_WRITE
,
FILE_SHARE_READ
|
FILE_SHARE_WRITE
|
FILE_SHARE_DELETE
,
NULL
,
OPEN_EXISTING
,
FILE_ATTRIBUTE_NORMAL
,
NULL
);
#endif
StartupStatus
status
=
QForkStartup
(
argc
,
argv
);
if
(
status
==
ssCONTINUE_AS_MASTER
)
{
int
retval
=
redis_main
(
argc
,
argv
);
QForkShutdown
();
return
retval
;
}
else
if
(
status
==
ssSLAVE_EXIT
)
{
// slave is done - clean up and exit
QForkShutdown
();
return
1
;
}
else
if
(
status
==
ssFAILED
)
{
// master or slave failed initialization
return
1
;
}
else
{
// unexpected status return
return
2
;
}
// service commands do not launch an instance of redis directly
if
(
HandleServiceCommands
(
argc
,
argv
)
==
TRUE
)
return
0
;
StartupStatus
status
=
QForkStartup
(
argc
,
argv
);
if
(
status
==
ssCONTINUE_AS_MASTER
)
{
int
retval
=
redis_main
(
argc
,
argv
);
QForkShutdown
();
return
retval
;
}
else
if
(
status
==
ssSLAVE_EXIT
)
{
// slave is done - clean up and exit
QForkShutdown
();
return
1
;
}
else
if
(
status
==
ssFAILED
)
{
// master or slave failed initialization
return
1
;
}
else
{
// unexpected status return
return
2
;
}
}
catch
(
std
::
system_error
syserr
)
{
printf
(
"main: system error caught. error code=0x%08x, message=%s
\n
"
,
syserr
.
code
().
value
(),
syserr
.
what
());
}
catch
(
std
::
runtime_error
runerr
)
{
printf
(
"main: runtime error caught. message=%s
\n
"
,
runerr
.
what
());
}
catch
(...)
{
printf
(
"main: other exception caught.
\n
"
);
}
}
}
src/Win32_Interop/Win32_Service.h
0 → 100644
浏览文件 @
6eb1ec22
/*
* Copyright (c), Microsoft Open Technologies, Inc.
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifdef __cplusplus
extern
"C"
{
#endif
BOOL
HandleServiceCommands
(
int
argc
,
char
**
argv
);
BOOL
ServiceStopIssued
();
#ifdef __cplusplus
}
#endif
src/Win32_Interop/Win32_SmartHandle.h
浏览文件 @
6eb1ec22
...
...
@@ -297,4 +297,49 @@ public:
{
Free
();
}
}
SmartVirtualMemoryPtr
;
\ No newline at end of file
}
SmartVirtualMemoryPtr
;
typedef
class
SmartServiceHandle
{
private:
SC_HANDLE
m_handle
;
public:
operator
SC_HANDLE
()
{
return
m_handle
;
}
SmartServiceHandle
&
operator
=
(
const
SC_HANDLE
handle
)
{
m_handle
=
handle
;
return
*
this
;
}
SmartServiceHandle
()
{
m_handle
=
NULL
;
}
SmartServiceHandle
(
const
SC_HANDLE
handle
)
{
m_handle
=
handle
;
}
BOOL
Valid
()
{
return
(
m_handle
!=
NULL
);
}
BOOL
Invalid
()
{
return
(
m_handle
==
NULL
);
}
~
SmartServiceHandle
()
{
CloseServiceHandle
(
m_handle
);
m_handle
=
NULL
;
}
}
SmartServiceHandle
;
\ No newline at end of file
src/Win32_Interop/Win32_service.cpp
0 → 100644
浏览文件 @
6eb1ec22
/*
* Copyright (c), Microsoft Open Technologies, Inc.
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
This code implements the following new command line arguments for redis:
--service-install [additional command line arguments to pass to redis when launched as a service]
This must be the first argument on the redis-server command line. Arguments after this are passed in the order they occur to redis when the
service is launched. The service will be configured as Autostart and will be launched as "NT AUTHORITY\NetworkService". Upon successful
installation a success message will be displayed and redis will exit. For instance:
redis-server --service-install redis.conf --loglevel verbose
This command does not start the service.
--service-uninstall
This will remove the redis service configuration information from the registry. Upon successful uninstallation a success message will be
displayed and redis will exit.
This does command not stop the service.
--service-start
This will start the redis service. Upon successful startup a success message will be displayed and redis will exit.
--service-stop
This will stop the redis service. Upon successful termination a success message will be displayed and redis will exit.
*** Since service configuration requires administrative privileges, these commands will only work under an elevated command prompt. ***
*/
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <algorithm>
#include <string>
#include <sstream>
#include <vector>
#include <iostream>
using
namespace
std
;
#include "Win32_SmartHandle.h"
#pragma comment(lib, "advapi32.lib")
#define SERVICE_NAME "Redis"
SERVICE_STATUS
g_ServiceStatus
=
{
0
};
HANDLE
g_ServiceStopEvent
=
INVALID_HANDLE_VALUE
;
vector
<
string
>
serviceRunArguments
;
SERVICE_STATUS_HANDLE
g_StatusHandle
;
const
ULONGLONG
cThirtySeconds
=
30
*
1000
;
extern
"C"
int
main
(
int
argc
,
char
**
argv
);
VOID
ServiceInstall
(
int
argc
,
char
**
argv
)
{
SmartServiceHandle
shSCManager
;
SmartServiceHandle
shService
;
CHAR
szPath
[
MAX_PATH
];
// build arguments to pass to service when it auto starts
if
(
!
GetModuleFileNameA
(
NULL
,
szPath
,
MAX_PATH
))
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"GetModuleFileNameA failed"
);
}
stringstream
args
;
for
(
int
a
=
0
;
a
<
argc
;
a
++
)
{
if
(
a
==
0
)
args
<<
"
\"
"
<<
szPath
<<
"
\"
"
;
if
(
a
>
0
)
args
<<
" "
;
if
(
a
==
1
)
{
// replace --service-install argument with --service-run
args
<<
"--service-run "
;
}
else
{
args
<<
argv
[
a
];
}
}
shSCManager
=
OpenSCManager
(
NULL
,
NULL
,
SC_MANAGER_ALL_ACCESS
);
if
(
shSCManager
.
Invalid
())
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"OpenSCManager failed"
);
}
shService
=
CreateServiceA
(
shSCManager
,
SERVICE_NAME
,
SERVICE_NAME
,
SERVICE_ALL_ACCESS
,
SERVICE_WIN32_OWN_PROCESS
,
SERVICE_AUTO_START
,
SERVICE_ERROR_NORMAL
,
args
.
str
().
c_str
(),
NULL
,
NULL
,
NULL
,
"NT AUTHORITY
\\
NetworkService"
,
NULL
);
if
(
shService
.
Invalid
())
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"CreateService failed"
);
}
cout
<<
"Redis successfully installed as a service."
<<
endl
;
}
VOID
ServiceStart
()
{
SmartServiceHandle
shSCManager
;
SmartServiceHandle
shService
;
shSCManager
=
OpenSCManager
(
NULL
,
NULL
,
SC_MANAGER_ALL_ACCESS
);
if
(
shSCManager
.
Invalid
())
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"OpenSCManager failed"
);
}
shService
=
OpenServiceA
(
shSCManager
,
SERVICE_NAME
,
SERVICE_ALL_ACCESS
);
if
(
shService
.
Invalid
())
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"OpenService failed"
);
}
if
(
FALSE
==
StartServiceA
(
shService
,
0
,
NULL
))
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"StartService failed"
);
}
// it will take atleast a couple of seconds for the service to start.
Sleep
(
2000
);
SERVICE_STATUS
status
;
ULONGLONG
start
=
GetTickCount64
();
while
(
QueryServiceStatus
(
shService
,
&
status
)
==
TRUE
)
{
if
(
status
.
dwCurrentState
==
SERVICE_RUNNING
)
{
cout
<<
"Redis service successfully started."
<<
endl
;
break
;
}
else
if
(
status
.
dwCurrentState
==
SERVICE_STOPPED
)
{
cout
<<
"Redis service failed to start."
<<
endl
;
break
;
}
ULONGLONG
current
=
GetTickCount64
();
if
(
current
-
start
>=
cThirtySeconds
)
{
cout
<<
"Redis service start timed out."
<<
endl
;
break
;
}
}
}
VOID
ServiceStop
()
{
SmartServiceHandle
shSCManager
;
SmartServiceHandle
shService
;
shSCManager
=
OpenSCManager
(
NULL
,
NULL
,
SC_MANAGER_ALL_ACCESS
);
if
(
shSCManager
.
Invalid
())
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"OpenSCManager failed"
);
}
shService
=
OpenServiceA
(
shSCManager
,
SERVICE_NAME
,
SERVICE_ALL_ACCESS
);
if
(
shService
.
Invalid
())
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"OpenService failed"
);
}
SERVICE_STATUS
status
;
if
(
FALSE
==
ControlService
(
shService
,
SERVICE_CONTROL_STOP
,
&
status
))
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"ChangeServiceConfig failed"
);
}
ULONGLONG
start
=
GetTickCount64
();
while
(
QueryServiceStatus
(
shService
,
&
status
)
==
TRUE
)
{
if
(
status
.
dwCurrentState
==
SERVICE_STOPPED
)
{
cout
<<
"Redis service successfully stopped."
<<
endl
;
break
;
}
ULONGLONG
current
=
GetTickCount64
();
if
(
current
-
start
>=
cThirtySeconds
)
{
cout
<<
"Redis service stop timed out."
<<
endl
;
break
;
}
}
}
VOID
ServiceUninstall
()
{
SmartServiceHandle
shSCManager
;
SmartServiceHandle
shService
;
shSCManager
=
OpenSCManager
(
NULL
,
NULL
,
SC_MANAGER_ALL_ACCESS
);
if
(
shSCManager
.
Invalid
())
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"OpenSCManager failed"
);
}
shService
=
OpenServiceA
(
shSCManager
,
SERVICE_NAME
,
SERVICE_ALL_ACCESS
);
if
(
shSCManager
.
Invalid
())
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"OpenService failed"
);
}
if
(
FALSE
==
DeleteService
(
shService
))
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"DeleteService failed"
);
}
cout
<<
"Redis service successfully uninstalled."
<<
endl
;
}
DWORD
WINAPI
ServiceWorkerThread
(
LPVOID
lpParam
)
{
try
{
int
argc
=
(
int
)(
serviceRunArguments
.
size
());
char
**
argv
=
new
char
*
[
argc
];
if
(
argv
==
nullptr
)
throw
std
::
runtime_error
(
"new() failed"
);
int
argIndex
=
0
;
for
each
(
string
arg
in
serviceRunArguments
)
{
argv
[
argIndex
]
=
new
char
[
arg
.
length
()
+
1
];
if
(
argv
[
argIndex
]
==
nullptr
)
throw
std
::
runtime_error
(
"new() failed"
);
memcpy_s
(
argv
[
argIndex
],
arg
.
length
()
+
1
,
arg
.
c_str
(),
arg
.
length
());
argv
[
argIndex
][
arg
.
size
()]
=
'\0'
;
++
argIndex
;
}
// When the service starts the current directory is %systemdir%. If the launching user does not have permission there(i.e., NETWORK SERVICE), the
// memory mapped file will not be able to be created. Thus Redis will fail to start. Setting the current directory to the executable directory
// should fix this.
char
szFilePath
[
MAX_PATH
];
if
(
GetModuleFileNameA
(
NULL
,
szFilePath
,
MAX_PATH
)
==
0
)
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"GetModuleFileName failed"
);
}
string
currentDir
=
szFilePath
;
auto
pos
=
currentDir
.
rfind
(
"
\\
"
);
currentDir
.
erase
(
pos
);
if
(
FALSE
==
SetCurrentDirectoryA
(
currentDir
.
c_str
()))
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"SetCurrentDirectory failed"
);
}
// call redis main without the --service-run argument
main
(
argc
,
argv
);
for
(
int
a
=
0
;
a
<
argc
;
a
++
)
{
delete
argv
[
a
];
argv
[
a
]
=
nullptr
;
}
delete
argv
;
argv
=
nullptr
;
return
ERROR_SUCCESS
;
}
catch
(
std
::
system_error
syserr
)
{
stringstream
err
;
err
<<
"ServiceWorkerThread: system error caught. error code=0x"
<<
hex
<<
syserr
.
code
().
value
()
<<
", message = "
<<
syserr
.
what
()
<<
endl
;
OutputDebugStringA
(
err
.
str
().
c_str
());
}
catch
(
std
::
runtime_error
runerr
)
{
stringstream
err
;
err
<<
"runtime error caught. message="
<<
runerr
.
what
()
<<
endl
;
OutputDebugStringA
(
err
.
str
().
c_str
());
}
catch
(...)
{
OutputDebugStringA
(
"ServiceWorkerThread: other exception caught.
\n
"
);
}
return
ERROR_PROCESS_ABORTED
;
}
VOID
WINAPI
ServiceCtrlHandler
(
DWORD
CtrlCode
)
{
switch
(
CtrlCode
)
{
case
SERVICE_CONTROL_STOP
:
if
(
g_ServiceStatus
.
dwCurrentState
!=
SERVICE_RUNNING
)
break
;
g_ServiceStatus
.
dwControlsAccepted
=
0
;
g_ServiceStatus
.
dwCurrentState
=
SERVICE_STOP_PENDING
;
g_ServiceStatus
.
dwWin32ExitCode
=
0
;
g_ServiceStatus
.
dwCheckPoint
=
4
;
if
(
SetServiceStatus
(
g_StatusHandle
,
&
g_ServiceStatus
)
==
FALSE
)
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"SetServiceStatus failed"
);
}
// This will signal the worker thread to start shutting down
SetEvent
(
g_ServiceStopEvent
);
break
;
default:
break
;
}
}
VOID
WINAPI
ServiceMain
(
DWORD
argc
,
LPTSTR
*
argv
)
{
DWORD
Status
=
E_FAIL
;
g_StatusHandle
=
RegisterServiceCtrlHandlerA
(
SERVICE_NAME
,
ServiceCtrlHandler
);
if
(
g_StatusHandle
==
NULL
)
{
return
;
}
ZeroMemory
(
&
g_ServiceStatus
,
sizeof
(
g_ServiceStatus
));
g_ServiceStatus
.
dwServiceType
=
SERVICE_WIN32_OWN_PROCESS
;
g_ServiceStatus
.
dwControlsAccepted
=
0
;
g_ServiceStatus
.
dwCurrentState
=
SERVICE_START_PENDING
;
g_ServiceStatus
.
dwWin32ExitCode
=
0
;
g_ServiceStatus
.
dwServiceSpecificExitCode
=
0
;
g_ServiceStatus
.
dwCheckPoint
=
0
;
if
(
SetServiceStatus
(
g_StatusHandle
,
&
g_ServiceStatus
)
==
FALSE
)
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"SetServiceStatus failed"
);
}
g_ServiceStopEvent
=
CreateEvent
(
NULL
,
TRUE
,
FALSE
,
NULL
);
if
(
g_ServiceStopEvent
==
NULL
)
{
g_ServiceStatus
.
dwControlsAccepted
=
0
;
g_ServiceStatus
.
dwCurrentState
=
SERVICE_STOPPED
;
g_ServiceStatus
.
dwWin32ExitCode
=
GetLastError
();
g_ServiceStatus
.
dwCheckPoint
=
1
;
if
(
SetServiceStatus
(
g_StatusHandle
,
&
g_ServiceStatus
)
==
FALSE
)
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"SetServiceStatus failed"
);
}
return
;
}
g_ServiceStatus
.
dwControlsAccepted
=
SERVICE_ACCEPT_STOP
;
g_ServiceStatus
.
dwCurrentState
=
SERVICE_RUNNING
;
g_ServiceStatus
.
dwWin32ExitCode
=
0
;
g_ServiceStatus
.
dwCheckPoint
=
0
;
if
(
SetServiceStatus
(
g_StatusHandle
,
&
g_ServiceStatus
)
==
FALSE
)
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"SetServiceStatus failed"
);
}
HANDLE
hThread
=
CreateThread
(
NULL
,
0
,
ServiceWorkerThread
,
NULL
,
0
,
NULL
);
WaitForSingleObject
(
hThread
,
INFINITE
);
CloseHandle
(
g_ServiceStopEvent
);
g_ServiceStatus
.
dwControlsAccepted
=
0
;
g_ServiceStatus
.
dwCurrentState
=
SERVICE_STOPPED
;
g_ServiceStatus
.
dwWin32ExitCode
=
0
;
g_ServiceStatus
.
dwCheckPoint
=
3
;
if
(
SetServiceStatus
(
g_StatusHandle
,
&
g_ServiceStatus
)
==
FALSE
)
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"SetServiceStatus failed"
);
}
}
void
ServiceRun
()
{
SERVICE_TABLE_ENTRYA
ServiceTable
[]
=
{
{
SERVICE_NAME
,
(
LPSERVICE_MAIN_FUNCTIONA
)
ServiceMain
},
{
NULL
,
NULL
}
};
if
(
StartServiceCtrlDispatcherA
(
ServiceTable
)
==
FALSE
)
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"StartServiceCtrlDispatcherA failed"
);
}
}
void
BuildServiceRunArguments
(
int
argc
,
char
**
argv
)
{
// build argument list to be used by ServiceRun
for
(
int
n
=
0
;
n
<
argc
;
n
++
)
{
if
(
n
==
0
)
{
CHAR
szPath
[
MAX_PATH
];
if
(
!
GetModuleFileNameA
(
NULL
,
szPath
,
MAX_PATH
))
{
throw
std
::
system_error
(
GetLastError
(),
system_category
(),
"GetModuleFileNameA failed"
);
}
stringstream
ss
;
ss
<<
"
\"
"
<<
szPath
<<
"
\"
"
;
serviceRunArguments
.
push_back
(
ss
.
str
());
}
else
if
(
n
==
1
)
{
// bypass --service-run argument
continue
;
}
else
{
serviceRunArguments
.
push_back
(
argv
[
n
]);
}
}
}
extern
"C"
BOOL
HandleServiceCommands
(
int
argc
,
char
**
argv
)
{
try
{
if
(
argc
>
1
)
{
string
servicearg
=
argv
[
1
];
std
::
transform
(
servicearg
.
begin
(),
servicearg
.
end
(),
servicearg
.
begin
(),
::
tolower
);
if
(
servicearg
==
"--service-install"
)
{
ServiceInstall
(
argc
,
argv
);
return
TRUE
;
}
else
if
(
servicearg
==
"--service-uninstall"
)
{
ServiceUninstall
();
return
TRUE
;
}
else
if
(
servicearg
==
"--service-run"
)
{
BuildServiceRunArguments
(
argc
,
argv
);
ServiceRun
();
return
TRUE
;
}
else
if
(
servicearg
==
"--service-start"
)
{
ServiceStart
();
return
TRUE
;
}
else
if
(
servicearg
==
"--service-stop"
)
{
ServiceStop
();
return
TRUE
;
}
}
// not a service command. start redis normally.
return
FALSE
;
}
catch
(
std
::
system_error
syserr
)
{
stringstream
err
;
err
<<
"HandleServiceCommands: system error caught. error code=0x"
<<
hex
<<
syserr
.
code
().
value
()
<<
", message = "
<<
syserr
.
what
()
<<
endl
;
OutputDebugStringA
(
err
.
str
().
c_str
());
exit
(
1
);
}
catch
(
std
::
runtime_error
runerr
)
{
stringstream
err
;
err
<<
"HandleServiceCommands: runtime error caught. message="
<<
runerr
.
what
()
<<
endl
;
OutputDebugStringA
(
err
.
str
().
c_str
());
exit
(
1
);
}
catch
(...)
{
OutputDebugStringA
(
"HandleServiceCommands: other exception caught."
);
exit
(
1
);
}
}
extern
"C"
BOOL
ServiceStopIssued
()
{
if
(
g_ServiceStopEvent
==
INVALID_HANDLE_VALUE
)
return
FALSE
;
return
(
WaitForSingleObject
(
g_ServiceStopEvent
,
0
)
==
WAIT_OBJECT_0
)
?
TRUE
:
FALSE
;
}
src/ae.c
浏览文件 @
6eb1ec22
...
...
@@ -40,6 +40,7 @@
#include <sys/types.h>
#include <sys/timeb.h>
#include "..\..\src\win32_Interop\Win32_FDAPI.h"
#include "..\..\src\win32_Interop\Win32_Service.h"
#endif
#include <stdlib.h>
#include <string.h>
...
...
@@ -381,6 +382,11 @@ int aeProcessEvents(aeEventLoop *eventLoop, int flags)
{
int
processed
=
0
,
numevents
;
#ifdef _WIN32
if
(
ServiceStopIssued
()
==
TRUE
)
aeStop
(
eventLoop
);
#endif
/* Nothing to do? return ASAP */
if
(
!
(
flags
&
AE_TIME_EVENTS
)
&&
!
(
flags
&
AE_FILE_EVENTS
))
return
0
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录