Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
wine
Manage
Activity
Members
Labels
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Terraform modules
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Sebastian Mayr
wine
Commits
3bff2b3c
Commit
3bff2b3c
authored
21 years ago
by
Alexandre Julliard
Browse files
Options
Downloads
Patches
Plain Diff
Authors: Juraj Hercek <juraj@syncad.com>, Eric Frias <efrias@syncad.com>
Implemented pthread conditions.
parent
9d481e32
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
dlls/kernel/pthread.c
+231
-1
231 additions, 1 deletion
dlls/kernel/pthread.c
include/wine/pthread.h
+7
-0
7 additions, 0 deletions
include/wine/pthread.h
scheduler/pthread.c
+12
-13
12 additions, 13 deletions
scheduler/pthread.c
with
250 additions
and
14 deletions
dlls/kernel/pthread.c
+
231
−
1
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 */
};
This diff is collapsed.
Click to expand it.
include/wine/pthread.h
+
7
−
0
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
);
...
...
This diff is collapsed.
Click to expand it.
scheduler/pthread.c
+
12
−
13
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
);
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment