Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Y
ygopro-core
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
ygopro-core
Commits
f3fa58dd
Commit
f3fa58dd
authored
Jan 13, 2016
by
Argon.Sun
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
coroutine
parent
ae695015
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
179 additions
and
0 deletions
+179
-0
coroutine.h
coroutine.h
+179
-0
No files found.
coroutine.h
0 → 100644
View file @
f3fa58dd
#include <stdint.h>
#include <functional>
#ifdef COROUTINE_IMPLEMENT_USINT_THREAD
#include <thread>
#include <mutex>
#include <condition_variable>
template
<
typename
YIELD_TYPE
=
int32_t
,
typename
RESUME_TYPE
=
int32_t
>
class
Coroutine
{
public:
Coroutine
(
std
::
function
<
void
(
Coroutine
*
,
RESUME_TYPE
)
>
co_fun
)
{
coroutine_func
=
co_fun
;
std
::
unique_lock
<
std
::
mutex
>
lock
(
switch_lock
);
std
::
thread
([
this
]()
{
coroutine_proc
();
}).
detach
();
yield_con
.
wait
(
lock
);
}
bool
resume
(
RESUME_TYPE
v
=
RESUME_TYPE
())
{
if
(
finished
)
return
false
;
std
::
unique_lock
<
std
::
mutex
>
lock
(
switch_lock
);
resume_value
=
v
;
resume_con
.
notify_one
();
yield_con
.
wait
(
lock
);
return
!
finished
;
}
RESUME_TYPE
yield
(
YIELD_TYPE
v
)
{
std
::
unique_lock
<
std
::
mutex
>
lock
(
switch_lock
);
yield_value
=
v
;
yield_con
.
notify_one
();
resume_con
.
wait
(
lock
);
return
resume_value
;
}
inline
YIELD_TYPE
get_yield_value
()
{
return
yield_value
;
}
inline
bool
is_finished
()
{
return
finished
;
}
protected:
void
coroutine_proc
()
{
{
std
::
unique_lock
<
std
::
mutex
>
lock
(
switch_lock
);
yield_con
.
notify_one
();
resume_con
.
wait
(
lock
);
}
coroutine_func
(
this
,
resume_value
);
finished
=
true
;
yield_con
.
notify_one
();
}
std
::
function
<
void
(
Coroutine
*
,
RESUME_TYPE
)
>
coroutine_func
;
std
::
mutex
switch_lock
;
std
::
condition_variable
yield_con
;
std
::
condition_variable
resume_con
;
YIELD_TYPE
yield_value
=
YIELD_TYPE
();
RESUME_TYPE
resume_value
=
RESUME_TYPE
();
bool
finished
=
false
;
};
#else // use local context system
#ifdef _WIN32
// use fiber library on windows
#include <windows.h>
template
<
typename
YIELD_TYPE
=
int32_t
,
typename
RESUME_TYPE
=
int32_t
>
class
Coroutine
{
public:
Coroutine
(
std
::
function
<
void
(
Coroutine
*
,
RESUME_TYPE
)
>
co_fun
,
size_t
stack_size
=
0
)
{
coroutine_func
=
co_fun
;
parent
=
GetCurrentFiber
();
if
(
parent
==
(
LPVOID
)
0x1E00
)
parent
=
ConvertThreadToFiber
(
0
);
if
(
GetFiberData
()
==
nullptr
)
{
static_counter
()
++
;
is_thread
=
true
;
}
child
=
CreateFiber
(
stack_size
,
&
coroutine_proc
,
this
);
}
~
Coroutine
()
{
DeleteFiber
(
child
);
if
(
is_thread
&&
--
static_counter
()
==
0
)
ConvertFiberToThread
();
}
bool
resume
(
RESUME_TYPE
v
=
RESUME_TYPE
())
{
if
(
finished
)
return
false
;
resume_value
=
v
;
SwitchToFiber
(
child
);
return
!
finished
;
}
RESUME_TYPE
yield
(
YIELD_TYPE
v
)
{
yield_value
=
v
;
SwitchToFiber
(
parent
);
return
resume_value
;
}
inline
YIELD_TYPE
get_yield_value
()
{
return
yield_value
;
}
inline
bool
is_finished
()
{
return
finished
;
}
protected:
static
void
WINAPI
coroutine_proc
(
LPVOID
param
)
{
Coroutine
*
co
=
reinterpret_cast
<
Coroutine
*>
(
param
);
co
->
coroutine_func
(
co
,
co
->
resume_value
);
co
->
finished
=
true
;
SwitchToFiber
(
co
->
parent
);
}
inline
int32_t
&
static_counter
()
{
static
thread_local
int32_t
coroutine_counter
;
return
coroutine_counter
;
}
std
::
function
<
void
(
Coroutine
*
,
RESUME_TYPE
)
>
coroutine_func
;
LPVOID
parent
;
LPVOID
child
;
YIELD_TYPE
yield_value
=
YIELD_TYPE
();
RESUME_TYPE
resume_value
=
RESUME_TYPE
();
bool
is_thread
=
false
;
bool
finished
=
false
;
};
#else
#ifdef __MACH__
#define _XOPEN_SOURCE
#endif
#include <ucontext.h>
template
<
typename
YIELD_TYPE
=
int32_t
,
typename
RESUME_TYPE
=
int32_t
>
class
Coroutine
{
public:
Coroutine
(
std
::
function
<
void
(
Coroutine
*
,
RESUME_TYPE
)
>
co_fun
,
size_t
stack_size
=
0x10000
)
{
coroutine_func
=
co_fun
;
getcontext
(
&
child
);
child
.
uc_link
=
&
parent
;
child
.
uc_stack
.
ss_sp
=
malloc
(
stack_size
);
child
.
uc_stack
.
ss_size
=
stack_size
;
child
.
uc_stack
.
ss_flags
=
0
;
makecontext
(
&
child
,
(
void
(
*
)(
void
))
coroutine_proc
,
1
,
this
);
}
~
Coroutine
()
{
free
(
child
.
uc_stack
.
ss_sp
);
}
bool
resume
(
RESUME_TYPE
v
=
RESUME_TYPE
())
{
if
(
finished
)
return
false
;
resume_value
=
v
;
swapcontext
(
&
parent
,
&
child
);
return
!
finished
;
}
RESUME_TYPE
yield
(
YIELD_TYPE
v
)
{
yield_value
=
v
;
swapcontext
(
&
child
,
&
parent
);
return
resume_value
;
}
inline
YIELD_TYPE
get_yield_value
()
{
return
yield_value
;
}
inline
bool
is_finished
()
{
return
finished
;
}
protected:
static
void
coroutine_proc
(
Coroutine
*
ycon
)
{
ycon
->
coroutine_func
(
ycon
,
ycon
->
resume_value
);
ycon
->
finished
=
true
;
}
std
::
function
<
void
(
Coroutine
*
,
RESUME_TYPE
)
>
coroutine_func
;
ucontext_t
parent
;
ucontext_t
child
;
YIELD_TYPE
yield_value
=
YIELD_TYPE
();
RESUME_TYPE
resume_value
=
RESUME_TYPE
();
bool
finished
=
false
;
};
#endif // _WIN32
#endif // use thread
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment