Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
3bff2b3c
Commit
3bff2b3c
authored
Sep 23, 2003
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Authors: Juraj Hercek <juraj@syncad.com>, Eric Frias <efrias@syncad.com>
Implemented pthread conditions.
parent
9d481e32
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
250 additions
and
14 deletions
+250
-14
pthread.c
dlls/kernel/pthread.c
+231
-1
pthread.h
include/wine/pthread.h
+7
-0
pthread.c
scheduler/pthread.c
+12
-13
No files found.
dlls/kernel/pthread.c
View file @
3bff2b3c
...
...
@@ -304,6 +304,230 @@ static int wine_pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
return
0
;
}
/***** CONDITIONS *****/
/* The condition code is basically cut-and-pasted from Douglas
* Schmidt's paper:
* "Strategies for Implementing POSIX Condition Variables on Win32",
* at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html and
* http://www.cs.wustl.edu/~schmidt/win32-cv-2.html.
* This paper formed the basis for the condition variable
* impementation used in the ACE library.
*/
/* Possible problems with ACE:
* - unimplemented pthread_mutexattr_init
*/
typedef
struct
{
/* Number of waiting threads. */
int
waiters_count
;
/* Serialize access to <waiters_count>. */
CRITICAL_SECTION
waiters_count_lock
;
/*
* Semaphore used to queue up threads waiting for the condition to
* become signaled.
*/
HANDLE
sema
;
/*
* An auto-reset event used by the broadcast/signal thread to wait
* for all the waiting thread(s) to wake up and be released from the
* semaphore.
*/
HANDLE
waiters_done
;
/*
* Keeps track of whether we were broadcasting or signaling. This
* allows us to optimize the code if we're just signaling.
*/
size_t
was_broadcast
;
}
wine_cond_detail
;
/* see wine_mutex above for comments */
typedef
struct
{
wine_cond_detail
*
cond
;
}
*
wine_cond
;
static
void
wine_cond_real_init
(
pthread_cond_t
*
cond
)
{
wine_cond_detail
*
detail
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
wine_cond_detail
));
detail
->
waiters_count
=
0
;
detail
->
was_broadcast
=
0
;
detail
->
sema
=
CreateSemaphoreW
(
NULL
,
0
,
0x7fffffff
,
NULL
);
detail
->
waiters_done
=
CreateEventW
(
NULL
,
FALSE
,
FALSE
,
NULL
);
RtlInitializeCriticalSection
(
&
detail
->
waiters_count_lock
);
if
(
InterlockedCompareExchangePointer
((
void
**
)
&
(((
wine_cond
)
cond
)
->
cond
),
detail
,
NULL
)
!=
NULL
)
{
/* too late, some other thread already did it */
P_OUTPUT
(
"FIXME:pthread_cond_init:expect troubles...
\n
"
);
CloseHandle
(
detail
->
sema
);
RtlDeleteCriticalSection
(
&
detail
->
waiters_count_lock
);
CloseHandle
(
detail
->
waiters_done
);
HeapFree
(
GetProcessHeap
(),
0
,
detail
);
}
}
int
wine_pthread_cond_init
(
pthread_cond_t
*
cond
,
const
pthread_condattr_t
*
cond_attr
)
{
/* The same as for wine_pthread_mutex_init, we postpone initialization
until condition is really used.*/
((
wine_cond
)
cond
)
->
cond
=
NULL
;
return
0
;
}
int
wine_pthread_cond_destroy
(
pthread_cond_t
*
cond
)
{
wine_cond_detail
*
detail
=
((
wine_cond
)
cond
)
->
cond
;
if
(
!
detail
)
return
0
;
CloseHandle
(
detail
->
sema
);
RtlDeleteCriticalSection
(
&
detail
->
waiters_count_lock
);
CloseHandle
(
detail
->
waiters_done
);
HeapFree
(
GetProcessHeap
(),
0
,
detail
);
((
wine_cond
)
cond
)
->
cond
=
NULL
;
return
0
;
}
int
wine_pthread_cond_signal
(
pthread_cond_t
*
cond
)
{
int
have_waiters
;
wine_cond_detail
*
detail
;
if
(
!
((
wine_cond
)
cond
)
->
cond
)
wine_cond_real_init
(
cond
);
detail
=
((
wine_cond
)
cond
)
->
cond
;
RtlEnterCriticalSection
(
&
detail
->
waiters_count_lock
);
have_waiters
=
detail
->
waiters_count
>
0
;
RtlLeaveCriticalSection
(
&
detail
->
waiters_count_lock
);
/* If there aren't any waiters, then this is a no-op. */
if
(
have_waiters
)
ReleaseSemaphore
(
detail
->
sema
,
1
,
NULL
);
return
0
;
}
int
wine_pthread_cond_broadcast
(
pthread_cond_t
*
cond
)
{
int
have_waiters
=
0
;
wine_cond_detail
*
detail
;
if
(
!
((
wine_cond
)
cond
)
->
cond
)
wine_cond_real_init
(
cond
);
detail
=
((
wine_cond
)
cond
)
->
cond
;
/*
* This is needed to ensure that <waiters_count> and <was_broadcast> are
* consistent relative to each other.
*/
RtlEnterCriticalSection
(
&
detail
->
waiters_count_lock
);
if
(
detail
->
waiters_count
>
0
)
{
/*
* We are broadcasting, even if there is just one waiter...
* Record that we are broadcasting, which helps optimize
* <pthread_cond_wait> for the non-broadcast case.
*/
detail
->
was_broadcast
=
1
;
have_waiters
=
1
;
}
if
(
have_waiters
)
{
/* Wake up all the waiters atomically. */
ReleaseSemaphore
(
detail
->
sema
,
detail
->
waiters_count
,
NULL
);
RtlLeaveCriticalSection
(
&
detail
->
waiters_count_lock
);
/* Wait for all the awakened threads to acquire the counting semaphore. */
WaitForSingleObject
(
detail
->
waiters_done
,
INFINITE
);
/*
* This assignment is okay, even without the <waiters_count_lock> held
* because no other waiter threads can wake up to access it.
*/
detail
->
was_broadcast
=
0
;
}
else
RtlLeaveCriticalSection
(
&
detail
->
waiters_count_lock
);
return
0
;
}
int
wine_pthread_cond_wait
(
pthread_cond_t
*
cond
,
pthread_mutex_t
*
mutex
)
{
wine_cond_detail
*
detail
;
int
last_waiter
;
if
(
!
((
wine_cond
)
cond
)
->
cond
)
wine_cond_real_init
(
cond
);
detail
=
((
wine_cond
)
cond
)
->
cond
;
/* Avoid race conditions. */
RtlEnterCriticalSection
(
&
detail
->
waiters_count_lock
);
detail
->
waiters_count
++
;
RtlLeaveCriticalSection
(
&
detail
->
waiters_count_lock
);
RtlLeaveCriticalSection
(
((
wine_mutex
)
mutex
)
->
critsect
);
WaitForSingleObject
(
detail
->
sema
,
INFINITE
);
/* Reacquire lock to avoid race conditions. */
RtlEnterCriticalSection
(
&
detail
->
waiters_count_lock
);
/* We're no longer waiting... */
detail
->
waiters_count
--
;
/* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
last_waiter
=
detail
->
was_broadcast
&&
detail
->
waiters_count
==
0
;
RtlLeaveCriticalSection
(
&
detail
->
waiters_count_lock
);
/*
* If we're the last waiter thread during this particular broadcast
* then let all the other threads proceed.
*/
if
(
last_waiter
)
SetEvent
(
detail
->
waiters_done
);
RtlEnterCriticalSection
(((
wine_mutex
)
mutex
)
->
critsect
);
return
0
;
}
int
wine_pthread_cond_timedwait
(
pthread_cond_t
*
cond
,
pthread_mutex_t
*
mutex
,
const
struct
timespec
*
abstime
)
{
DWORD
ms
=
abstime
->
tv_sec
*
1000
+
abstime
->
tv_nsec
/
1000000
;
int
last_waiter
;
wine_cond_detail
*
detail
;
if
(
!
((
wine_cond
)
cond
)
->
cond
)
wine_cond_real_init
(
cond
);
detail
=
((
wine_cond
)
cond
)
->
cond
;
/* Avoid race conditions. */
RtlEnterCriticalSection
(
&
detail
->
waiters_count_lock
);
detail
->
waiters_count
++
;
RtlLeaveCriticalSection
(
&
detail
->
waiters_count_lock
);
RtlLeaveCriticalSection
(((
wine_mutex
)
mutex
)
->
critsect
);
WaitForSingleObject
(
detail
->
sema
,
ms
);
/* Reacquire lock to avoid race conditions. */
RtlEnterCriticalSection
(
&
detail
->
waiters_count_lock
);
/* We're no longer waiting... */
detail
->
waiters_count
--
;
/* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
last_waiter
=
detail
->
was_broadcast
&&
detail
->
waiters_count
==
0
;
RtlLeaveCriticalSection
(
&
detail
->
waiters_count_lock
);
/*
* If we're the last waiter thread during this particular broadcast
* then let all the other threads proceed.
*/
if
(
last_waiter
)
SetEvent
(
detail
->
waiters_done
);
RtlEnterCriticalSection
(((
wine_mutex
)
mutex
)
->
critsect
);
return
0
;
}
/***** MISC *****/
static
pthread_t
wine_pthread_self
(
void
)
...
...
@@ -353,5 +577,11 @@ static const struct wine_pthread_functions functions =
wine_pthread_rwlock_tryrdlock
,
/* ptr_pthread_rwlock_tryrdlock */
wine_pthread_rwlock_wrlock
,
/* ptr_pthread_rwlock_wrlock */
wine_pthread_rwlock_trywrlock
,
/* ptr_pthread_rwlock_trywrlock */
wine_pthread_rwlock_unlock
/* ptr_pthread_rwlock_unlock */
wine_pthread_rwlock_unlock
,
/* ptr_pthread_rwlock_unlock */
wine_pthread_cond_init
,
/* ptr_pthread_cond_init */
wine_pthread_cond_destroy
,
/* ptr_pthread_cond_destroy */
wine_pthread_cond_signal
,
/* ptr_pthread_cond_signal */
wine_pthread_cond_broadcast
,
/* ptr_pthread_cond_broadcast */
wine_pthread_cond_wait
,
/* ptr_pthread_cond_wait */
wine_pthread_cond_timedwait
/* ptr_pthread_cond_timedwait */
};
include/wine/pthread.h
View file @
3bff2b3c
...
...
@@ -56,6 +56,13 @@ struct wine_pthread_functions
int
(
*
ptr_pthread_rwlock_wrlock
)(
pthread_rwlock_t
*
rwlock
);
int
(
*
ptr_pthread_rwlock_trywrlock
)(
pthread_rwlock_t
*
rwlock
);
int
(
*
ptr_pthread_rwlock_unlock
)(
pthread_rwlock_t
*
rwlock
);
int
(
*
ptr_pthread_cond_init
)(
pthread_cond_t
*
cond
,
const
pthread_condattr_t
*
cond_attr
);
int
(
*
ptr_pthread_cond_destroy
)(
pthread_cond_t
*
cond
);
int
(
*
ptr_pthread_cond_signal
)(
pthread_cond_t
*
cond
);
int
(
*
ptr_pthread_cond_broadcast
)(
pthread_cond_t
*
cond
);
int
(
*
ptr_pthread_cond_wait
)(
pthread_cond_t
*
cond
,
pthread_mutex_t
*
mutex
);
int
(
*
ptr_pthread_cond_timedwait
)(
pthread_cond_t
*
cond
,
pthread_mutex_t
*
mutex
,
const
struct
timespec
*
abstime
);
};
extern
void
wine_pthread_init_process
(
const
struct
wine_pthread_functions
*
functions
);
...
...
scheduler/pthread.c
View file @
3bff2b3c
...
...
@@ -563,47 +563,46 @@ void __pthread_cleanup_upto(jmp_buf target, char *frame)
}
/***** CONDITIONS *****/
/* not implemented right now */
int
__pthread_cond_init
(
pthread_cond_t
*
cond
,
const
pthread_condattr_t
*
cond_attr
)
{
P_OUTPUT
(
"FIXME:pthread_cond_init
\n
"
)
;
return
0
;
if
(
!
funcs
.
ptr_pthread_cond_init
)
return
0
;
return
funcs
.
ptr_pthread_cond_init
(
cond
,
cond_attr
)
;
}
strong_alias
(
__pthread_cond_init
,
pthread_cond_init
);
int
__pthread_cond_destroy
(
pthread_cond_t
*
cond
)
{
P_OUTPUT
(
"FIXME:pthread_cond_destroy
\n
"
)
;
return
0
;
if
(
!
funcs
.
ptr_pthread_cond_destroy
)
return
0
;
return
funcs
.
ptr_pthread_cond_destroy
(
cond
)
;
}
strong_alias
(
__pthread_cond_destroy
,
pthread_cond_destroy
);
int
__pthread_cond_signal
(
pthread_cond_t
*
cond
)
{
P_OUTPUT
(
"FIXME:pthread_cond_signal
\n
"
)
;
return
0
;
if
(
!
funcs
.
ptr_pthread_cond_signal
)
return
0
;
return
funcs
.
ptr_pthread_cond_signal
(
cond
)
;
}
strong_alias
(
__pthread_cond_signal
,
pthread_cond_signal
);
int
__pthread_cond_broadcast
(
pthread_cond_t
*
cond
)
{
P_OUTPUT
(
"FIXME:pthread_cond_broadcast
\n
"
)
;
return
0
;
if
(
!
funcs
.
ptr_pthread_cond_broadcast
)
return
0
;
return
funcs
.
ptr_pthread_cond_broadcast
(
cond
)
;
}
strong_alias
(
__pthread_cond_broadcast
,
pthread_cond_broadcast
);
int
__pthread_cond_wait
(
pthread_cond_t
*
cond
,
pthread_mutex_t
*
mutex
)
{
P_OUTPUT
(
"FIXME:pthread_cond_wait
\n
"
)
;
return
0
;
if
(
!
funcs
.
ptr_pthread_cond_wait
)
return
0
;
return
funcs
.
ptr_pthread_cond_wait
(
cond
,
mutex
)
;
}
strong_alias
(
__pthread_cond_wait
,
pthread_cond_wait
);
int
__pthread_cond_timedwait
(
pthread_cond_t
*
cond
,
pthread_mutex_t
*
mutex
,
const
struct
timespec
*
abstime
)
{
P_OUTPUT
(
"FIXME:pthread_cond_timedwait
\n
"
)
;
return
0
;
if
(
!
funcs
.
ptr_pthread_cond_timedwait
)
return
0
;
return
funcs
.
ptr_pthread_cond_timedwait
(
cond
,
mutex
,
abstime
)
;
}
strong_alias
(
__pthread_cond_timedwait
,
pthread_cond_timedwait
);
...
...
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