Merge pull request #12499 from fjtrujy/psp-remove-pthread

[PSP] Remove embedded PTE from RA and use the one provided by the toolchain
This commit is contained in:
Autechre 2021-06-07 15:52:35 +02:00 committed by GitHub
commit 681983d1b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 2 additions and 13085 deletions

View File

@ -19,7 +19,7 @@ ifeq ($(WHOLE_ARCHIVE_LINK), 1)
WHOLE_END := -Wl,--no-whole-archive
endif
INCDIR = deps deps/stb deps/7zip deps/pthreads deps/pthreads/platform/psp deps/pthreads/platform/helper libretro-common/include libretro-common/include/compat/zlib
INCDIR = deps deps/stb deps/7zip libretro-common/include libretro-common/include/compat/zlib
CFLAGS = $(OPTIMIZE_LV) -G0 -std=gnu99 -ffast-math -fsingle-precision-constant
ASFLAGS = $(CFLAGS)
@ -27,7 +27,7 @@ RARCH_DEFINES = -DPSP -D_MIPS_ARCH_ALLEGREX -DHAVE_LANGEXTRA -DHAVE_ZLIB -DHAVE_
LIBDIR =
LDFLAGS =
LIBS = $(WHOLE_START) -lretro_psp1 $(WHOLE_END) -lstdc++ -lpspgu -lpspgum -lm -lpspaudio -lpspfpu -lpsppower -lpsprtc
LIBS = $(WHOLE_START) -lretro_psp1 $(WHOLE_END) -lstdc++ -lpspgu -lpspgum -lm -lpspaudio -lpspfpu -lpsppower -lpsprtc -lpthread-psp
ifeq ($(HAVE_THREADS), 1)
RARCH_DEFINES += -DHAVE_THREADS

476
deps/pthreads/ANNOUNCE vendored
View File

@ -1,476 +0,0 @@
PTHREADS-WIN32 RELEASE 2.8.0 (2006-12-22)
-----------------------------------------
Web Site: http://sources.redhat.com/pthreads-win32/
FTP Site: ftp://sources.redhat.com/pub/pthreads-win32
Maintainer: Ross Johnson <rpj@callisto.canberra.edu.au>
We are pleased to announce the availability of a new release of
Pthreads-win32, an Open Source Software implementation of the
Threads component of the POSIX 1003.1 2001 Standard for Microsoft's
Win32 environment. Some functions from other sections of POSIX
1003.1 2001 are also supported including semaphores and scheduling
functions.
Some common non-portable functions are also implemented for
additional compatibility, as are a few functions specific
to pthreads-win32 for easier integration with Win32 applications.
Pthreads-win32 is free software, distributed under the GNU Lesser
General Public License (LGPL).
Acknowledgements
----------------
This library is based originally on a Win32 pthreads
implementation contributed by John Bossom <John.Bossom@cognos.com>.
The implementation of Condition Variables uses algorithms developed
by Alexander Terekhov and Louis Thomas.
The implementation of POSIX mutexes has been improved by Thomas Pfaff
and later by Alexander Terekhov.
The implementation of Spinlocks and Barriers was contributed
by Ross Johnson.
The implementation of read/write locks was contributed by
Aurelio Medina and improved by Alexander Terekhov.
Many others have contributed significant time and effort to solve crutial
problems in order to make the library workable, robust and reliable.
Thanks to Xavier Leroy for granting permission to use and modify his
LinuxThreads manual pages.
Thanks to The Open Group for making the Single Unix Specification
publicly available - many of the manual pages included in the package
were extracted from it.
There is also a separate CONTRIBUTORS file. This file and others are
on the web site:
http://sources.redhat.com/pthreads-win32
As much as possible, the ChangeLog file acknowledges contributions to the
code base in more detail.
Changes since the last release
------------------------------
These are now documented in the NEWS file.
See the ChangeLog file also.
Known Bugs
----------
These are now documented in the BUGS file.
Level of standards conformance
------------------------------
The following POSIX 1003.1 2001 options are defined and set to 200112L:
_POSIX_THREADS
_POSIX_THREAD_SAFE_FUNCTIONS
_POSIX_THREAD_ATTR_STACKSIZE
_POSIX_THREAD_PRIORITY_SCHEDULING
_POSIX_SEMAPHORES
_POSIX_READER_WRITER_LOCKS
_POSIX_SPIN_LOCKS
_POSIX_BARRIERS
The following POSIX 1003.1 2001 options are defined and set to -1:
_POSIX_THREAD_ATTR_STACKADDR
_POSIX_THREAD_PRIO_INHERIT
_POSIX_THREAD_PRIO_PROTECT
_POSIX_THREAD_PROCESS_SHARED
The following POSIX 1003.1 2001 limits are defined and set:
_POSIX_THREAD_THREADS_MAX
_POSIX_SEM_VALUE_MAX
_POSIX_SEM_NSEMS_MAX
_POSIX_THREAD_KEYS_MAX
_POSIX_THREAD_DESTRUCTOR_ITERATIONS
PTHREAD_STACK_MIN
PTHREAD_THREADS_MAX
SEM_VALUE_MAX
SEM_NSEMS_MAX
PTHREAD_KEYS_MAX
PTHREAD_DESTRUCTOR_ITERATIONS
The following functions are implemented:
---------------------------
PThreads
---------------------------
pthread_attr_init
pthread_attr_destroy
pthread_attr_getdetachstate
pthread_attr_getstackaddr
pthread_attr_getstacksize
pthread_attr_setdetachstate
pthread_attr_setstackaddr
pthread_attr_setstacksize
pthread_create
pthread_detach
pthread_equal
pthread_exit
pthread_join
pthread_once
pthread_self
pthread_cancel
pthread_cleanup_pop
pthread_cleanup_push
pthread_setcancelstate
pthread_setcanceltype
pthread_testcancel
---------------------------
Thread Specific Data
---------------------------
pthread_key_create
pthread_key_delete
pthread_setspecific
pthread_getspecific
---------------------------
Mutexes
---------------------------
pthread_mutexattr_init
pthread_mutexattr_destroy
pthread_mutexattr_getpshared
pthread_mutexattr_setpshared
pthread_mutexattr_gettype
pthread_mutexattr_settype (types: PTHREAD_MUTEX_DEFAULT
PTHREAD_MUTEX_NORMAL
PTHREAD_MUTEX_ERRORCHECK
PTHREAD_MUTEX_RECURSIVE )
pthread_mutex_init
pthread_mutex_destroy
pthread_mutex_lock
pthread_mutex_trylock
pthread_mutex_timedlock
pthread_mutex_unlock
---------------------------
Condition Variables
---------------------------
pthread_condattr_init
pthread_condattr_destroy
pthread_condattr_getpshared
pthread_condattr_setpshared
pthread_cond_init
pthread_cond_destroy
pthread_cond_wait
pthread_cond_timedwait
pthread_cond_signal
pthread_cond_broadcast
---------------------------
Read/Write Locks
---------------------------
pthread_rwlock_init
pthread_rwlock_destroy
pthread_rwlock_tryrdlock
pthread_rwlock_trywrlock
pthread_rwlock_rdlock
pthread_rwlock_timedrdlock
pthread_rwlock_rwlock
pthread_rwlock_timedwrlock
pthread_rwlock_unlock
pthread_rwlockattr_init
pthread_rwlockattr_destroy
pthread_rwlockattr_getpshared
pthread_rwlockattr_setpshared
---------------------------
Spin Locks
---------------------------
pthread_spin_init
pthread_spin_destroy
pthread_spin_lock
pthread_spin_unlock
pthread_spin_trylock
---------------------------
Barriers
---------------------------
pthread_barrier_init
pthread_barrier_destroy
pthread_barrier_wait
pthread_barrierattr_init
pthread_barrierattr_destroy
pthread_barrierattr_getpshared
pthread_barrierattr_setpshared
---------------------------
Semaphores
---------------------------
sem_init
sem_destroy
sem_post
sem_wait
sem_trywait
sem_timedwait
sem_getvalue (# free if +ve, # of waiters if -ve)
sem_open (returns an error ENOSYS)
sem_close (returns an error ENOSYS)
sem_unlink (returns an error ENOSYS)
---------------------------
RealTime Scheduling
---------------------------
pthread_attr_getschedparam
pthread_attr_setschedparam
pthread_attr_getinheritsched
pthread_attr_setinheritsched
pthread_attr_getschedpolicy (only supports SCHED_OTHER)
pthread_attr_setschedpolicy (only supports SCHED_OTHER)
pthread_getschedparam
pthread_setschedparam
pthread_getconcurrency
pthread_setconcurrency
pthread_attr_getscope
pthread_attr_setscope (only supports PTHREAD_SCOPE_SYSTEM)
sched_get_priority_max
sched_get_priority_min
sched_rr_get_interval (returns an error ENOTSUP)
sched_setscheduler (only supports SCHED_OTHER)
sched_getscheduler (only supports SCHED_OTHER)
sched_yield
---------------------------
Signals
---------------------------
pthread_sigmask
pthread_kill (only supports zero sig value,
for thread validity checking)
---------------------------
Non-portable routines (see the README.NONPORTABLE file for usage)
---------------------------
pthread_getw32threadhandle_np
pthread_timechange_handler_np
pthread_delay_np
pthread_mutexattr_getkind_np
pthread_mutexattr_setkind_np (types: PTHREAD_MUTEX_FAST_NP,
PTHREAD_MUTEX_ERRORCHECK_NP,
PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ADAPTIVE_NP,
PTHREAD_MUTEX_TIMED_NP)
pthread_num_processors_np
pthread_win32_process_attach_np (Required when statically linking
the library)
pthread_win32_process_detach_np (Required when statically linking
the library)
pthread_win32_thread_attach_np (Required when statically linking
the library)
pthread_win32_thread_detach_np (Required when statically linking
the library)
---------------------------
Static Initializers
---------------------------
PTHREAD_ONCE_INIT
PTHREAD_MUTEX_INITIALIZER
PTHREAD_RECURSIVE_MUTEX_INITIALIZER
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
PTHREAD_ERRORCHECK_MUTEX_INITIALIZER
PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
PTHREAD_COND_INITIALIZER
PTHREAD_RWLOCK_INITIALIZER
PTHREAD_SPINLOCK_INITIALIZER
---------------------------
Thread-Safe C Runtime Library (macros)
---------------------------
strtok_r
asctime_r
ctime_r
gmtime_r
localtime_r
rand_r
The following functions are not implemented:
---------------------------
RealTime Scheduling
---------------------------
pthread_mutex_getprioceiling
pthread_mutex_setprioceiling
pthread_mutex_attr_getprioceiling
pthread_mutex_attr_getprotocol
pthread_mutex_attr_setprioceiling
pthread_mutex_attr_setprotocol
---------------------------
Fork Handlers
---------------------------
pthread_atfork
---------------------------
Stdio
---------------------------
flockfile
ftrylockfile
funlockfile
getc_unlocked
getchar_unlocked
putc_unlocked
putchar_unlocked
---------------------------
Thread-Safe C Runtime Library
---------------------------
readdir_r
getgrgid_r
getgrnam_r
getpwuid_r
getpwnam_r
---------------------------
Signals
---------------------------
sigtimedwait
sigwait
sigwaitinfo
---------------------------
General
---------------------------
sysconf
The library includes two non-API functions for creating cancellation
points in applications and libraries:
pthreadCancelableWait
pthreadCancelableTimedWait
Availability
------------
The prebuilt DLL, export libs (for both MSVC and Mingw32), and the header
files (pthread.h, semaphore.h, sched.h) are available along with the
complete source code.
The source code can be found at:
ftp://sources.redhat.com/pub/pthreads-win32
and as individual source code files at
ftp://sources.redhat.com/pub/pthreads-win32/source
The pre-built DLL, export libraries and include files can be found at:
ftp://sources.redhat.com/pub/pthreads-win32/dll-latest
Mailing List
------------
There is a mailing list for discussing pthreads on Win32. To join,
send email to:
pthreads-win32-subscribe@sourceware.cygnus.com
Application Development Environments
------------------------------------
See the README file for more information.
MSVC:
MSVC using SEH works. Distribute pthreadVSE.dll with your application.
MSVC using C++ EH works. Distribute pthreadVCE.dll with your application.
MSVC using C setjmp/longjmp works. Distribute pthreadVC.dll with your application.
Mingw32:
See the FAQ, Questions 6 and 10.
Mingw using C++ EH works. Distribute pthreadGCE.dll with your application.
Mingw using C setjmp/longjmp works. Distribute pthreadGC.dll with your application.
Cygwin: (http://sourceware.cygnus.com/cygwin/)
Developers using Cygwin will not need pthreads-win32 since it has POSIX threads
support. Refer to its documentation for details and extent.
UWIN:
UWIN is a complete Unix-like environment for Windows from AT&T. Pthreads-win32
doesn't currently support UWIN (and vice versa), but that may change in the
future.
Generally:
For convenience, the following pre-built files are available on the FTP site
(see Availability above):
pthread.h - for POSIX 1c threads
semaphore.h - for POSIX 1b semaphores
sched.h - for POSIX 1b scheduling
pthreadVCE.dll - built with MSVC++ compiler using C++ EH
pthreadVCE.lib
pthreadVC.dll - built with MSVC compiler using C setjmp/longjmp
pthreadVC.lib
pthreadVSE.dll - built with MSVC compiler using SEH
pthreadVSE.lib
pthreadGCE.dll - built with Mingw32 G++ 2.95.2-1
pthreadGC.dll - built with Mingw32 GCC 2.95.2-1 using setjmp/longjmp
libpthreadGCE.a - derived from pthreadGCE.dll
libpthreadGC.a - derived from pthreadGC.dll
gcc.dll - needed if distributing applications that use
pthreadGCE.dll (but see the FAQ Q 10 for the latest
related information)
These are the only files you need in order to build POSIX threads
applications for Win32 using either MSVC or Mingw32.
See the FAQ file in the source tree for additional information.
Documentation
-------------
For the authoritative reference, see the online POSIX
standard reference at:
http://www.OpenGroup.org
For POSIX Thread API programming, several reference books are
available:
Programming with POSIX Threads
David R. Butenhof
Addison-Wesley (pub)
Pthreads Programming
By Bradford Nichols, Dick Buttlar & Jacqueline Proulx Farrell
O'Reilly (pub)
On the web: see the links at the bottom of the pthreads-win32 site:
http://sources.redhat.com/pthreads-win32/
Currently, there is no documentation included in the package apart
from the copious comments in the source code.
Enjoy!
Ross Johnson

View File

@ -1,129 +0,0 @@
Contributors (in approximate order of appearance)
[See also the ChangeLog file where individuals are
attributed in log entries. Likewise in the FAQ file.]
Ben Elliston bje at cygnus dot com
Initiated the project;
setup the project infrastructure (CVS, web page, etc.);
early prototype routines.
Ross Johnson rpj at callisto dot canberra dot edu dot au
early prototype routines;
ongoing project coordination/maintenance;
implementation of spin locks and barriers;
various enhancements;
bug fixes;
documentation;
testsuite.
Robert Colquhoun rjc at trump dot net dot au
Early bug fixes.
John E. Bossom John dot Bossom at cognos dot com
Contributed substantial original working implementation;
bug fixes;
ongoing guidance and standards interpretation.
Anders Norlander anorland at hem2 dot passagen dot se
Early enhancements and runtime checking for supported
Win32 routines.
Tor Lillqvist tml at iki dot fi
General enhancements;
early bug fixes to condition variables.
Scott Lightner scott at curriculum dot com
Bug fix.
Kevin Ruland Kevin dot Ruland at anheuser-busch dot com
Various bug fixes.
Mike Russo miker at eai dot com
Bug fix.
Mark E. Armstrong avail at pacbell dot net
Bug fixes.
Lorin Hochstein lmh at xiphos dot ca
general bug fixes; bug fixes to condition variables.
Peter Slacik Peter dot Slacik at tatramed dot sk
Bug fixes.
Mumit Khan khan at xraylith dot wisc dot edu
Fixes to work with Mingw32.
Milan Gardian mg at tatramed dot sk
Bug fixes and reports/analyses of obscure problems.
Aurelio Medina aureliom at crt dot com
First implementation of read-write locks.
Graham Dumpleton Graham dot Dumpleton at ra dot pad dot otc dot telstra dot com dot au
Bug fix in condition variables.
Tristan Savatier tristan at mpegtv dot com
WinCE port.
Erik Hensema erik at hensema dot xs4all dot nl
Bug fixes.
Rich Peters rpeters at micro-magic dot com
Todd Owen towen at lucidcalm dot dropbear dot id dot au
Bug fixes to dll loading.
Jason Nye jnye at nbnet dot nb dot ca
Implementation of async cancelation.
Fred Forester fforest at eticomm dot net
Kevin D. Clark kclark at cabletron dot com
David Baggett dmb at itasoftware dot com
Bug fixes.
Paul Redondo paul at matchvision dot com
Scott McCaskill scott at 3dfx dot com
Bug fixes.
Jef Gearhart jgearhart at tpssys dot com
Bug fix.
Arthur Kantor akantor at bexusa dot com
Mutex enhancements.
Steven Reddie smr at essemer dot com dot au
Bug fix.
Alexander Terekhov TEREKHOV at de dot ibm dot com
Re-implemented and improved read-write locks;
(with Louis Thomas) re-implemented and improved
condition variables;
enhancements to semaphores;
enhancements to mutexes;
new mutex implementation in 'futex' style;
suggested a robust implementation of pthread_once
similar to that implemented by V.Kliathcko;
system clock change handling re CV timeouts;
bug fixes.
Thomas Pfaff tpfaff at gmx dot net
Changes to make C version usable with C++ applications;
re-implemented mutex routines to avoid Win32 mutexes
and TryEnterCriticalSection;
procedure to fix Mingw32 thread-safety issues.
Franco Bez franco dot bez at gmx dot de
procedure to fix Mingw32 thread-safety issues.
Louis Thomas lthomas at arbitrade dot com
(with Alexander Terekhov) re-implemented and improved
condition variables.
David Korn dgk at research dot att dot com
Ported to UWIN.
Phil Frisbie, Jr. phil at hawksoft dot com
Bug fix.
Ralf Brese Ralf dot Brese at pdb4 dot siemens dot de
Bug fix.
prionx at juno dot com prionx at juno dot com
Bug fixes.
Max Woodbury mtew at cds dot duke dot edu
POSIX versioning conditionals;
reduced namespace pollution;
idea to separate routines to reduce statically
linked image sizes.
Rob Fanner rfanner at stonethree dot com
Bug fix.
Michael Johnson michaelj at maine dot rr dot com
Bug fix.
Nicolas Barry boozai at yahoo dot com
Bug fixes.
Piet van Bruggen pietvb at newbridges dot nl
Bug fix.
Makoto Kato raven at oldskool dot jp
AMD64 port.
Panagiotis E. Hadjidoukas peh at hpclab dot ceid dot upatras dot gr
Contributed the QueueUserAPCEx package which
makes preemptive async cancelation possible.
Will Bryant will dot bryant at ecosm dot com
Borland compiler patch and makefile.
Anuj Goyal anuj dot goyal at gmail dot com
Port to Digital Mars compiler.
Gottlob Frege gottlobfrege at gmail dot com
re-implemented pthread_once (version 2)
(pthread_once cancellation added by rpj).
Vladimir Kliatchko vladimir at kliatchko dot com
reimplemented pthread_once with the same form
as described by A.Terekhov (later version 2);
implementation of MCS (Mellor-Crummey/Scott) locks.

150
deps/pthreads/COPYING vendored
View File

@ -1,150 +0,0 @@
pthreads-win32 - a POSIX threads library for Microsoft Windows
This file is Copyrighted
------------------------
This file is covered under the following Copyright:
Copyright (C) 2001,2006 Ross P. Johnson
All rights reserved.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Pthreads-win32 is covered by the GNU Lesser General Public License
------------------------------------------------------------------
Pthreads-win32 is open software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation version 2.1 of the
License.
Pthreads-win32 is several binary link libraries, several modules,
associated interface definition files and scripts used to control
its compilation and installation.
Pthreads-win32 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
A copy of the GNU Lesser General Public License is distributed with
pthreads-win32 under the filename:
COPYING.LIB
You should have received a copy of the version 2.1 GNU Lesser General
Public License with pthreads-win32; if not, write to:
Free Software Foundation, Inc.
59 Temple Place
Suite 330
Boston, MA 02111-1307
USA
The contact addresses for pthreads-win32 is as follows:
Web: http://sources.redhat.com/pthreads-win32
Email: Ross Johnson
Please use: Firstname.Lastname@homemail.com.au
Pthreads-win32 copyrights and exception files
---------------------------------------------
With the exception of the files listed below, Pthreads-win32
is covered under the following GNU Lesser General Public License
Copyrights:
Pthreads-win32 - POSIX Threads Library for Win32
Copyright(C) 1998 John E. Bossom
Copyright(C) 1999,2006 Pthreads-win32 contributors
The current list of contributors is contained
in the file CONTRIBUTORS included with the source
code distribution. The current list of CONTRIBUTORS
can also be seen at the following WWW location:
http://sources.redhat.com/pthreads-win32/contributors.html
Contact Email: Ross Johnson
Please use: Firstname.Lastname@homemail.com.au
These files are not covered under one of the Copyrights listed above:
COPYING
COPYING.LIB
tests/rwlock7.c
This file, COPYING, is distributed under the Copyright found at the
top of this file. It is important to note that you may distribute
verbatim copies of this file but you may not modify this file.
The file COPYING.LIB, which contains a copy of the version 2.1
GNU Lesser General Public License, is itself copyrighted by the
Free Software Foundation, Inc. Please note that the Free Software
Foundation, Inc. does NOT have a copyright over Pthreads-win32,
only the COPYING.LIB that is supplied with pthreads-win32.
The file tests/rwlock7.c is derived from code written by
Dave Butenhof for his book 'Programming With POSIX(R) Threads'.
The original code was obtained by free download from his website
http://home.earthlink.net/~anneart/family/Threads/source.html
and did not contain a copyright or author notice. It is assumed to
be freely distributable.
In all cases one may use and distribute these exception files freely.
And because one may freely distribute the LGPL covered files, the
entire pthreads-win32 source may be freely used and distributed.
General Copyleft and License info
---------------------------------
For general information on Copylefts, see:
http://www.gnu.org/copyleft/
For information on GNU Lesser General Public Licenses, see:
http://www.gnu.org/copyleft/lesser.html
http://www.gnu.org/copyleft/lesser.txt
Why pthreads-win32 did not use the GNU General Public License
-------------------------------------------------------------
The goal of the pthreads-win32 project has been to
provide a quality and complete implementation of the POSIX
threads API for Microsoft Windows within the limits imposed
by virtue of it being a stand-alone library and not
linked directly to other POSIX compliant libraries. For
example, some functions and features, such as those based
on POSIX signals, are missing.
Pthreads-win32 is a library, available in several different
versions depending on supported compilers, and may be used
as a dynamically linked module or a statically linked set of
binary modules. It is not an application on it's own.
It was fully intended that pthreads-win32 be usable with
commercial software not covered by either the GPL or the LGPL
licenses. Pthreads-win32 has many contributors to it's
code base, many of whom have done so because they have
used the library in commercial or proprietry software
projects.
Releasing pthreads-win32 under the LGPL ensures that the
library can be used widely, while at the same time ensures
that bug fixes and improvements to the pthreads-win32 code
itself is returned to benefit all current and future users
of the library.
Although pthreads-win32 makes it possible for applications
that use POSIX threads to be ported to Win32 platforms, the
broader goal of the project is to encourage the use of open
standards, and in particular, to make it just a little easier
for developers writing Win32 applications to consider
widening the potential market for their products.

View File

@ -1,504 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@ -1,516 +0,0 @@
/*
* implement.h
*
* Definitions that don't need to be public.
*
* Keeps all the internals out of pthread.h
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef _IMPLEMENT_H
#define _IMPLEMENT_H
#include "pte_osal.h"
/* use local include files during development */
#include "semaphore.h"
#include "sched.h"
typedef enum
{
/*
* This enumeration represents the state of the thread;
* The thread is still "alive" if the numeric value of the
* state is greater or equal "PThreadStateRunning".
*/
PThreadStateInitial = 0, /* Thread not running */
PThreadStateRunning, /* Thread alive & kicking */
PThreadStateSuspended, /* Thread alive but suspended */
PThreadStateCancelPending, /* Thread alive but is */
/* has cancelation pending. */
PThreadStateCanceling, /* Thread alive but is */
/* in the process of terminating */
/* due to a cancellation request */
PThreadStateException, /* Thread alive but exiting */
/* due to an exception */
PThreadStateLast
}
PThreadState;
typedef struct pte_thread_t_ pte_thread_t;
struct pte_thread_t_
{
pte_osThreadHandle threadId; /* OS specific thread handle */
// pthread_t ptHandle; /* This thread's permanent pthread_t handle */
pte_thread_t * prevReuse; /* Links threads on reuse stack */
volatile PThreadState state;
void *exitStatus;
void *parms;
int ptErrno;
int detachState;
pthread_mutex_t threadLock; /* Used for serialised access to public thread state */
int sched_priority; /* As set, not as currently is */
pthread_mutex_t cancelLock; /* Used for async-cancel safety */
int cancelState;
int cancelType;
int cancelEvent;
jmp_buf start_mark;
int implicit:
1;
void *keys;
void *nextAssoc;
unsigned int x; /* Extra information - reuse count etc */
};
/*
* Special value to mark attribute objects as valid.
*/
#define PTE_ATTR_VALID ((unsigned long) 0xC4C0FFEE)
struct pthread_attr_t_
{
unsigned long valid;
void *stackaddr;
size_t stacksize;
int detachstate;
struct sched_param param;
int inheritsched;
int contentionscope;
};
/*
* ====================
* ====================
* Semaphores, Mutexes and Condition Variables
* ====================
* ====================
*/
struct sem_t_
{
int value;
pthread_mutex_t lock;
pte_osSemaphoreHandle sem;
};
#define PTE_OBJECT_AUTO_INIT ((void *) -1)
#define PTE_OBJECT_INVALID 0
struct pthread_mutex_t_
{
pte_osSemaphoreHandle handle;
int lock_idx;
/* Provides exclusive access to mutex state
via the Interlocked* mechanism.
0: unlocked/free.
1: locked - no other waiters.
-1: locked - with possible other waiters.
*/
int recursive_count; /* Number of unlocks a thread needs to perform
before the lock is released (recursive
mutexes only). */
int kind; /* Mutex type. */
pthread_t ownerThread;
};
struct pthread_mutexattr_t_
{
int pshared;
int kind;
};
/*
* Possible values, other than PTE_OBJECT_INVALID,
* for the "interlock" element in a spinlock.
*
* In this implementation, when a spinlock is initialised,
* the number of cpus available to the process is checked.
* If there is only one cpu then "interlock" is set equal to
* PTE_SPIN_USE_MUTEX and u.mutex is a initialised mutex.
* If the number of cpus is greater than 1 then "interlock"
* is set equal to PTE_SPIN_UNLOCKED and the number is
* stored in u.cpus. This arrangement allows the spinlock
* routines to attempt an InterlockedCompareExchange on "interlock"
* immediately and, if that fails, to try the inferior mutex.
*
* "u.cpus" isn't used for anything yet, but could be used at
* some point to optimise spinlock behaviour.
*/
#define PTE_SPIN_UNLOCKED (1)
#define PTE_SPIN_LOCKED (2)
#define PTE_SPIN_USE_MUTEX (3)
struct pthread_spinlock_t_
{
int interlock; /* Locking element for multi-cpus. */
union
{
int cpus; /* No. of cpus if multi cpus, or */
pthread_mutex_t mutex; /* mutex if single cpu. */
} u;
};
struct pthread_barrier_t_
{
unsigned int nCurrentBarrierHeight;
unsigned int nInitialBarrierHeight;
int iStep;
int pshared;
sem_t semBarrierBreeched[2];
};
struct pthread_barrierattr_t_
{
int pshared;
};
struct pthread_key_t_
{
unsigned key;
void (*destructor) (void *);
pthread_mutex_t keyLock;
void *threads;
};
typedef struct ThreadParms ThreadParms;
typedef struct ThreadKeyAssoc ThreadKeyAssoc;
struct ThreadParms
{
pthread_t tid;
void *(*start) (void *);
void *arg;
};
struct pthread_cond_t_
{
long nWaitersBlocked; /* Number of threads blocked */
long nWaitersGone; /* Number of threads timed out */
long nWaitersToUnblock; /* Number of threads to unblock */
sem_t semBlockQueue; /* Queue up threads waiting for the */
/* condition to become signalled */
sem_t semBlockLock; /* Semaphore that guards access to */
/* | waiters blocked count/block queue */
/* +-> Mandatory Sync.LEVEL-1 */
pthread_mutex_t mtxUnblockLock; /* Mutex that guards access to */
/* | waiters (to)unblock(ed) counts */
/* +-> Optional* Sync.LEVEL-2 */
pthread_cond_t next; /* Doubly linked list */
pthread_cond_t prev;
};
struct pthread_condattr_t_
{
int pshared;
};
#define PTE_RWLOCK_MAGIC 0xfacade2
struct pthread_rwlock_t_
{
pthread_mutex_t mtxExclusiveAccess;
pthread_mutex_t mtxSharedAccessCompleted;
pthread_cond_t cndSharedAccessCompleted;
int nSharedAccessCount;
int nExclusiveAccessCount;
int nCompletedSharedAccessCount;
int nMagic;
};
struct pthread_rwlockattr_t_
{
int pshared;
};
/*
* MCS lock queue node - see pte_MCS_lock.c
*/
struct pte_mcs_node_t_
{
struct pte_mcs_node_t_ **lock; /* ptr to tail of queue */
struct pte_mcs_node_t_ *next; /* ptr to successor in queue */
unsigned int readyFlag; /* set after lock is released by
predecessor */
unsigned int nextFlag; /* set after 'next' ptr is set by
successor */
};
typedef struct pte_mcs_node_t_ pte_mcs_local_node_t;
typedef struct pte_mcs_node_t_ *pte_mcs_lock_t;
struct ThreadKeyAssoc
{
/*
* Purpose:
* This structure creates an association between a thread and a key.
* It is used to implement the implicit invocation of a user defined
* destroy routine for thread specific data registered by a user upon
* exiting a thread.
*
* Graphically, the arrangement is as follows, where:
*
* K - Key with destructor
* (head of chain is key->threads)
* T - Thread that has called pthread_setspecific(Kn)
* (head of chain is thread->keys)
* A - Association. Each association is a node at the
* intersection of two doubly-linked lists.
*
* T1 T2 T3
* | | |
* | | |
* K1 -----+-----A-----A----->
* | | |
* | | |
* K2 -----A-----A-----+----->
* | | |
* | | |
* K3 -----A-----+-----A----->
* | | |
* | | |
* V V V
*
* Access to the association is guarded by two locks: the key's
* general lock (guarding the row) and the thread's general
* lock (guarding the column). This avoids the need for a
* dedicated lock for each association, which not only consumes
* more handles but requires that: before the lock handle can
* be released - both the key must be deleted and the thread
* must have called the destructor. The two-lock arrangement
* allows the resources to be freed as soon as either thread or
* key is concluded.
*
* To avoid deadlock: whenever both locks are required, the key
* and thread locks are always acquired in the order: key lock
* then thread lock. An exception to this exists when a thread
* calls the destructors, however this is done carefully to
* avoid deadlock.
*
* An association is created when a thread first calls
* pthread_setspecific() on a key that has a specified
* destructor.
*
* An association is destroyed either immediately after the
* thread calls the key destructor function on thread exit, or
* when the key is deleted.
*
* Attributes:
* thread
* reference to the thread that owns the
* association. This is actually the pointer to the
* thread struct itself. Since the association is
* destroyed before the thread exits, this can never
* point to a different logical thread to the one that
* created the assoc, i.e. after thread struct reuse.
*
* key
* reference to the key that owns the association.
*
* nextKey
* The pthread_t->keys attribute is the head of a
* chain of associations that runs through the nextKey
* link. This chain provides the 1 to many relationship
* between a pthread_t and all pthread_key_t on which
* it called pthread_setspecific.
*
* prevKey
* Similarly.
*
* nextThread
* The pthread_key_t->threads attribute is the head of
* a chain of assoctiations that runs through the
* nextThreads link. This chain provides the 1 to many
* relationship between a pthread_key_t and all the
* PThreads that have called pthread_setspecific for
* this pthread_key_t.
*
* prevThread
* Similarly.
*
* Notes:
* 1) As soon as either the key or the thread is no longer
* referencing the association, it can be destroyed. The
* association will be removed from both chains.
*
* 2) An association is only created by
* pthread_setspecific if the user provided a
* destroyRoutine when they created the key.
*
*
*/
pte_thread_t * thread;
pthread_key_t key;
ThreadKeyAssoc *nextKey;
ThreadKeyAssoc *nextThread;
ThreadKeyAssoc *prevKey;
ThreadKeyAssoc *prevThread;
};
/*
* Services available through EXCEPTION_PTE_SERVICES
* and also used [as parameters to pte_throw()] as
* generic exception selectors.
*/
#define PTE_EPS_EXIT (1)
#define PTE_EPS_CANCEL (2)
/* Useful macros */
#define PTE_MAX(a,b) ((a)<(b)?(b):(a))
#define PTE_MIN(a,b) ((a)>(b)?(b):(a))
/* Thread Reuse stack bottom marker. Must not be NULL or any valid pointer to memory. */
#define PTE_THREAD_REUSE_EMPTY ((pte_thread_t *) 1)
extern int pte_processInitialized;
extern pte_thread_t * pte_threadReuseTop;
extern pte_thread_t * pte_threadReuseBottom;
extern pthread_key_t pte_selfThreadKey;
extern pthread_key_t pte_cleanupKey;
extern pthread_cond_t pte_cond_list_head;
extern pthread_cond_t pte_cond_list_tail;
extern int pte_mutex_default_kind;
extern int pte_concurrency;
extern int pte_features;
extern pte_osMutexHandle pte_thread_reuse_lock;
extern pte_osMutexHandle pte_mutex_test_init_lock;
extern pte_osMutexHandle pte_cond_list_lock;
extern pte_osMutexHandle pte_cond_test_init_lock;
extern pte_osMutexHandle pte_rwlock_test_init_lock;
extern pte_osMutexHandle pte_spinlock_test_init_lock;
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
/*
* =====================
* =====================
* Forward Declarations
* =====================
* =====================
*/
int pte_is_attr (const pthread_attr_t * attr);
int pte_cond_check_need_init (pthread_cond_t * cond);
int pte_mutex_check_need_init (pthread_mutex_t * mutex);
int pte_rwlock_check_need_init (pthread_rwlock_t * rwlock);
int pte_spinlock_check_need_init (pthread_spinlock_t * lock);
int pte_processInitialize (void);
void pte_processTerminate (void);
void pte_threadDestroy (pthread_t tid);
void pte_threadExitAndDestroy (pthread_t tid);
void pte_pop_cleanup_all (int execute);
pthread_t pte_new (void);
pthread_t pte_threadReusePop (void);
void pte_threadReusePush (pthread_t thread);
int pte_getprocessors (int *count);
int pte_setthreadpriority (pthread_t thread, int policy, int priority);
void pte_rwlock_cancelwrwait (void *arg);
int pte_threadStart (void *vthreadParms);
void pte_callUserDestroyRoutines (pthread_t thread);
int pte_tkAssocCreate (pte_thread_t * thread, pthread_key_t key);
void pte_tkAssocDestroy (ThreadKeyAssoc * assoc);
int sem_wait_nocancel (sem_t * sem);
unsigned int pte_relmillisecs (const struct timespec * abstime);
void pte_mcs_lock_acquire (pte_mcs_lock_t * lock, pte_mcs_local_node_t * node);
void pte_mcs_lock_release (pte_mcs_local_node_t * node);
/* Declared in private.c */
void pte_throw (unsigned int exception);
int pte_cancellable_wait (pte_osSemaphoreHandle semHandle, unsigned int* timeout);
#define PTE_ATOMIC_EXCHANGE pte_osAtomicExchange
#define PTE_ATOMIC_EXCHANGE_ADD pte_osAtomicExchangeAdd
#define PTE_ATOMIC_COMPARE_EXCHANGE pte_osAtomicCompareExchange
#define PTE_ATOMIC_DECREMENT pte_osAtomicDecrement
#define PTE_ATOMIC_INCREMENT pte_osAtomicIncrement
int pte_thread_detach_np();
int pte_thread_detach_and_exit_np();
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _IMPLEMENT_H */

View File

@ -1,90 +0,0 @@
/***
* errno.h - system wide error numbers (set by system calls)
*
* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
*
* Purpose:
* This file defines the system-wide error numbers (set by
* system calls). Conforms to the XENIX standard. Extended
* for compatibility with Uniforum standard.
* [System V]
*
* [Public]
*
****/
#ifndef _INC_ERRNO
#define _INC_ERRNO
#ifdef __cplusplus
extern "C"
{
#endif
/* declare reference to errno */
extern int errno;
/* Error Codes */
#define EPERM 1
#define ENOENT 2
#define ESRCH 3
#define EINTR 4
#define EIO 5
#define ENXIO 6
#define E2BIG 7
#define ENOEXEC 8
#define EBADF 9
#define ECHILD 10
#define EAGAIN 11
#define ENOMEM 12
#define EACCES 13
#define EFAULT 14
#define EBUSY 16
#define EEXIST 17
#define EXDEV 18
#define ENODEV 19
#define ENOTDIR 20
#define EISDIR 21
#define EINVAL 22
#define ENFILE 23
#define EMFILE 24
#define ENOTTY 25
#define EFBIG 27
#define ENOSPC 28
#define ESPIPE 29
#define EROFS 30
#define EMLINK 31
#define EPIPE 32
#define EDOM 33
#define ERANGE 34
#define EDEADLK 36
/* defined differently in winsock.h on WinCE */
#ifndef ENAMETOOLONG
#define ENAMETOOLONG 38
#endif
#define ENOLCK 39
#define ENOSYS 40
/* defined differently in winsock.h on WinCE */
#ifndef ENOTEMPTY
#define ENOTEMPTY 41
#endif
#define EILSEQ 42
/*
* Support EDEADLOCK for compatibiity with older MS-C versions.
*/
#define EDEADLOCK EDEADLK
#ifdef __cplusplus
}
#endif
#endif /* _INC_ERRNO */

View File

@ -1,163 +0,0 @@
/*
* tls-helper.c
*
* Description:
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include "tls-helper.h"
static int *keysUsed;
/* We don't protect this - it's only written on startup */
static int maxTlsValues;
pte_osMutexHandle globalTlsLock;
pte_osResult pteTlsGlobalInit(int maxEntries)
{
int i;
pte_osResult result;
pte_osMutexCreate(&globalTlsLock);
keysUsed = (int *) malloc(maxEntries * sizeof(int));
if (keysUsed != NULL)
{
for (i=0;i<maxEntries;i++)
keysUsed[i] = 0;
maxTlsValues = maxEntries;
result = PTE_OS_OK;
}
else
result = PTE_OS_NO_RESOURCES;
return result;
}
void * pteTlsThreadInit(void)
{
int i;
void **pTlsStruct = (void **) malloc(maxTlsValues * sizeof(void*));
/* PTE library assumes that keys are initialized to zero */
for (i=0; i<maxTlsValues;i++)
pTlsStruct[i] = 0;
return (void *) pTlsStruct;
}
pte_osResult pteTlsAlloc(unsigned int *pKey)
{
int i;
pte_osResult result = PTE_OS_NO_RESOURCES;
pte_osMutexLock(globalTlsLock);
for (i=0;i<maxTlsValues;i++)
{
if (keysUsed[i] == 0)
{
keysUsed[i] = 1;
*pKey = i+1;
result = PTE_OS_OK;
break;
}
}
pte_osMutexUnlock(globalTlsLock);
return result;
}
void * pteTlsGetValue(void *pTlsThreadStruct, unsigned int index)
{
void **pTls = (void **) pTlsThreadStruct;
if (keysUsed[index-1])
{
if (pTls != NULL)
return pTls[index-1];
}
return NULL;
}
pte_osResult pteTlsSetValue(void *pTlsThreadStruct, unsigned int index, void * value)
{
pte_osResult result;
void ** pTls = (void **) pTlsThreadStruct;
if (pTls != NULL)
{
pTls[index-1] = value;
result = PTE_OS_OK;
}
else
result = PTE_OS_INVALID_PARAM;
return result;
}
pte_osResult pteTlsFree(unsigned int index)
{
pte_osResult result;
if (keysUsed != NULL)
{
pte_osMutexLock(globalTlsLock);
keysUsed[index-1] = 0;
pte_osMutexUnlock(globalTlsLock);
result = PTE_OS_OK;
}
else
result = PTE_OS_GENERAL_FAILURE;
return result;
}
void pteTlsThreadDestroy(void * pTlsThreadStruct)
{
free(pTlsThreadStruct);
}
void pteTlsGlobalDestroy(void)
{
pte_osMutexDelete(globalTlsLock);
free(keysUsed);
}

View File

@ -1,47 +0,0 @@
/*
* tls-helper.h
*
* Description:
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef _TLS_HELPER_H_
#define _TLS_HELPER_H_
#include "../psp/pte_osal.h"
/* @todo document.. */
pte_osResult pteTlsGlobalInit(int maxEntries);
void * pteTlsThreadInit(void);
pte_osResult pteTlsAlloc(unsigned int *pKey);
void * pteTlsGetValue(void *pTlsThreadStruct, unsigned int index);
pte_osResult pteTlsSetValue(void *pTlsThreadStruct, unsigned int index, void * value);
pte_osResult pteTlsFree(unsigned int index);
void pteTlsThreadDestroy(void * pTlsThreadStruct);
void pteTlsGlobalDestroy(void);
#endif // _TLS_HELPER_H_

View File

@ -1,51 +0,0 @@
VPATH = ../..:../helper
TARGET_LIB = libpthread-psp.a
MUTEX_OBJS = pthread_mutex.o
MUTEXATTR_OBJS = pthread_mutexattr.o
SUPPORT_OBJS = pte.o pthread.o
THREAD_OBJS = sched.o
TLS_OBJS = pthread_key.o
MISC_OBJS = pthread_get.o
SEM_OBJS = sem.o
BARRIER_OBJS = pthread_barrier.o pthread_barrierattr.o
SPIN_OBJS = pthread_spin.o
CONDVAR_OBJS = pthread_cond.o pthread_condattr.o
RWLOCK_OBJS = pthread_rwlock.o pthread_rwlockattr.o
CANCEL_OBJS = pthread.o pthread_set.o
OS_OBJS = psp_osal.o tls-helper.o
OBJS = $(MUTEX_OBJS) $(MUTEXATTR_OBJS) $(THREAD_OBJS) $(SUPPORT_OBJS) $(TLS_OBJS) $(MISC_OBJS) $(SEM_OBJS) $(BARRIER_OBJS) $(SPIN_OBJS) $(CONDVAR_OBJS) $(RWLOCK_OBJS) $(CANCEL_OBJS) $(OS_OBJS)
INCDIR =
CFLAGS = $(GLOBAL_CFLAGS) -G0 -O2 -Wall -g -fno-strict-aliasing -I../.. -I../helper
CXXFLAGS = $(CFLAGS) -fexceptions -fno-rtti -Werror
ASFLAGS = $(CFLAGS)
LDFLAGS =
LIBS =
PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak
test :
make -C ../../tests test
install: $(TARGET_LIB)
@cp -v $(TARGET_LIB) `psp-config --psp-prefix`/lib
@cp -v *.h `psp-config --psp-prefix`/include
@echo "Done."

View File

@ -1,842 +0,0 @@
/*
* psp_osal.c
*
* Description:
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* For ftime */
#include <sys/time.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <pspkerror.h>
#include "pte_osal.h"
#include "../../pthread.h"
#include "../helper/tls-helper.h"
#define MAX_PSP_UID 2048 /* SWAG */
#define DEFAULT_STACK_SIZE_BYTES 4096
#define PSP_MAX_TLS 32
#if 1
#define PSP_DEBUG(x) printf(x)
#else
#define PSP_DEBUG(x)
#endif
/* TLS key used to access pspThreadData struct for reach thread. */
static unsigned int threadDataKey;
/*
* Data stored on a per-thread basis - allocated in pte_osThreadCreate
* and freed in pte_osThreadDelete.
*/
typedef struct pspThreadData
{
/* Entry point and parameters to thread's main function */
pte_osThreadEntryPoint entryPoint;
void * argv;
/* Semaphore used for cancellation. Posted to by pte_osThreadCancel,
polled in pte_osSemaphoreCancellablePend */
SceUID cancelSem;
} pspThreadData;
/* Structure used to emulate TLS on non-POSIX threads.
* This limits us to one non-POSIX thread that can
* call pthread functions. */
static void *globalTls;
/* Helper functions */
static pspThreadData *getThreadData(SceUID threadHandle);
static void *getTlsStructFromThread(SceUID thid);
/* A new thread's stub entry point. It retrieves the real entry point from the per thread control
* data as well as any parameters to this function, and then calls the entry point.
*/
int pspStubThreadEntry (unsigned int argc, void *argv)
{
int result;
pspThreadData *pThreadData;
pThreadData = getThreadData(sceKernelGetThreadId());
result = (*(pThreadData->entryPoint))(pThreadData->argv);
return result;
}
/****************************************************************************
*
* Initialization
*
***************************************************************************/
pte_osResult pte_osInit(void)
{
pte_osResult result;
pspThreadData *pThreadData;
char cancelSemName[64];
/* Allocate and initialize TLS support */
result = pteTlsGlobalInit(PSP_MAX_TLS);
if (result == PTE_OS_OK)
{
/* Allocate a key that we use to store control information (e.g. cancellation semaphore) per thread */
result = pteTlsAlloc(&threadDataKey);
if (result == PTE_OS_OK)
{
/* Initialize the structure used to emulate TLS for
* non-POSIX threads
*/
globalTls = pteTlsThreadInit();
/* Also create a "thread data" structure for a single non-POSIX thread. */
/* Allocate some memory for our per-thread control data. We use this for:
* 1. Entry point and parameters for the user thread's main function.
* 2. Semaphore used for thread cancellation.
*/
pThreadData = (pspThreadData *) malloc(sizeof(pspThreadData));
if (pThreadData == NULL)
{
result = PTE_OS_NO_RESOURCES;
}
else
{
/* Save a pointer to our per-thread control data as a TLS value */
pteTlsSetValue(globalTls, threadDataKey, pThreadData);
/* Create a semaphore used to cancel threads */
snprintf(cancelSemName, sizeof(cancelSemName), "pthread_cancelSemGlobal");
pThreadData->cancelSem = sceKernelCreateSema(cancelSemName,
0, /* attributes (default) */
0, /* initial value */
255, /* maximum value */
0); /* options (default) */
result = PTE_OS_OK;
}
}
}
return result;
}
/****************************************************************************
*
* Threads
*
***************************************************************************/
pte_osResult pte_osThreadCreate(pte_osThreadEntryPoint entryPoint,
int stackSize,
int initialPriority,
void *argv,
pte_osThreadHandle* ppte_osThreadHandle)
{
char threadName[64];
char cancelSemName[64];
static int threadNum = 1;
int pspAttr;
void *pTls;
SceUID threadId;
pte_osResult result;
pspThreadData *pThreadData;
if (threadNum++ > MAX_PSP_UID)
threadNum = 0;
/* Make sure that the stack we're going to allocate is big enough */
if (stackSize < DEFAULT_STACK_SIZE_BYTES)
stackSize = DEFAULT_STACK_SIZE_BYTES;
/* Allocate TLS structure for this thread. */
pTls = pteTlsThreadInit();
if (pTls == NULL)
{
PSP_DEBUG("pteTlsThreadInit: PTE_OS_NO_RESOURCES\n");
result = PTE_OS_NO_RESOURCES;
goto FAIL0;
}
/* Allocate some memory for our per-thread control data. We use this for:
* 1. Entry point and parameters for the user thread's main function.
* 2. Semaphore used for thread cancellation.
*/
pThreadData = (pspThreadData *) malloc(sizeof(pspThreadData));
if (pThreadData == NULL)
{
pteTlsThreadDestroy(pTls);
PSP_DEBUG("malloc(pspThreadData): PTE_OS_NO_RESOURCES\n");
result = PTE_OS_NO_RESOURCES;
goto FAIL0;
}
/* Save a pointer to our per-thread control data as a TLS value */
pteTlsSetValue(pTls, threadDataKey, pThreadData);
pThreadData->entryPoint = entryPoint;
pThreadData->argv = argv;
/* Create a semaphore used to cancel threads */
snprintf(cancelSemName, sizeof(cancelSemName), "pthread_cancelSem%04d", threadNum);
pThreadData->cancelSem = sceKernelCreateSema(cancelSemName,
0, /* attributes (default) */
0, /* initial value */
255, /* maximum value */
0); /* options (default) */
/* In order to emulate TLS functionality, we append the address of the TLS structure that we
* allocated above to the thread's name. To set or get TLS values for this thread, the user
* needs to get the name of the thread from the OS and then parse the name to extract
* a pointer to the TLS structure.
*/
snprintf(threadName, sizeof(threadName), "pthread%04d__%x", threadNum, (unsigned int) pTls);
pspAttr = 0;
#if 0
printf("%s %p %d %d %d\n",threadName, pspStubThreadEntry, initialPriority, stackSize, pspAttr);
#endif
threadId = sceKernelCreateThread(threadName,
pspStubThreadEntry,
initialPriority,
stackSize,
pspAttr,
NULL);
if (threadId == (SceUID) SCE_KERNEL_ERROR_NO_MEMORY)
{
free(pThreadData);
pteTlsThreadDestroy(pTls);
PSP_DEBUG("sceKernelCreateThread: PTE_OS_NO_RESOURCES\n");
result = PTE_OS_NO_RESOURCES;
}
else if (threadId < 0)
{
free(pThreadData);
pteTlsThreadDestroy(pTls);
PSP_DEBUG("sceKernelCreateThread: PTE_OS_GENERAL_FAILURE\n");
result = PTE_OS_GENERAL_FAILURE;
}
else
{
*ppte_osThreadHandle = threadId;
result = PTE_OS_OK;
}
FAIL0:
return result;
}
pte_osResult pte_osThreadStart(pte_osThreadHandle osThreadHandle)
{
sceKernelStartThread(osThreadHandle, 0, NULL);
return PTE_OS_OK;
}
pte_osResult pte_osThreadDelete(pte_osThreadHandle handle)
{
void *pTls = getTlsStructFromThread(handle);
pspThreadData *pThreadData = getThreadData(handle);
sceKernelDeleteSema(pThreadData->cancelSem);
free(pThreadData);
pteTlsThreadDestroy(pTls);
sceKernelDeleteThread(handle);
return PTE_OS_OK;
}
pte_osResult pte_osThreadExitAndDelete(pte_osThreadHandle handle)
{
pte_osThreadDelete(handle);
sceKernelExitDeleteThread(0);
return PTE_OS_OK;
}
void pte_osThreadExit(void)
{
sceKernelExitThread(0);
}
/*
* This has to be cancellable, so we can't just call sceKernelWaitThreadEnd.
* Instead, poll on this in a loop, like we do for a cancellable semaphore.
*/
pte_osResult pte_osThreadWaitForEnd(pte_osThreadHandle threadHandle)
{
pte_osResult result;
pspThreadData *pThreadData = getThreadData(sceKernelGetThreadId());
while (1)
{
SceKernelThreadRunStatus info;
/* Poll task to see if it has ended */
memset(&info,0,sizeof(info));
info.size = sizeof(info);
sceKernelReferThreadRunStatus(threadHandle, &info);
if (info.status == PSP_THREAD_STOPPED)
{
/* Thread has ended */
result = PTE_OS_OK;
break;
}
else
{
SceKernelSemaInfo semInfo;
if (pThreadData != NULL)
{
SceUID osResult;
osResult = sceKernelReferSemaStatus(pThreadData->cancelSem, &semInfo);
if (osResult == SCE_KERNEL_ERROR_OK)
{
if (semInfo.currentCount > 0)
{
result = PTE_OS_INTERRUPTED;
break;
}
/* Nothing found and not timed out yet; let's yield so we're not
* in busy loop.
*/
else
sceKernelDelayThread(POLLING_DELAY_IN_us);
}
else
{
result = PTE_OS_GENERAL_FAILURE;
break;
}
}
}
}
return result;
}
pte_osThreadHandle pte_osThreadGetHandle(void)
{
return sceKernelGetThreadId();
}
int pte_osThreadGetPriority(pte_osThreadHandle threadHandle)
{
SceKernelThreadInfo thinfo;
thinfo.size = sizeof(SceKernelThreadInfo);
sceKernelReferThreadStatus(threadHandle, &thinfo);
return thinfo.currentPriority;
}
pte_osResult pte_osThreadSetPriority(pte_osThreadHandle threadHandle, int newPriority)
{
sceKernelChangeThreadPriority(threadHandle, newPriority);
return PTE_OS_OK;
}
pte_osResult pte_osThreadCancel(pte_osThreadHandle threadHandle)
{
pspThreadData *pThreadData = getThreadData(threadHandle);
SceUID osResult = sceKernelSignalSema(pThreadData->cancelSem, 1);
if (osResult == SCE_KERNEL_ERROR_OK)
return PTE_OS_OK;
return PTE_OS_GENERAL_FAILURE;
}
pte_osResult pte_osThreadCheckCancel(pte_osThreadHandle threadHandle)
{
SceKernelSemaInfo semInfo;
SceUID osResult;
pte_osResult result;
pspThreadData *pThreadData = getThreadData(threadHandle);
if (pThreadData != NULL)
{
osResult = sceKernelReferSemaStatus(pThreadData->cancelSem, &semInfo);
if (osResult == SCE_KERNEL_ERROR_OK)
{
if (semInfo.currentCount > 0)
result = PTE_OS_INTERRUPTED;
else
result = PTE_OS_OK;
}
/* sceKernelReferSemaStatus returned an error */
else
result = PTE_OS_GENERAL_FAILURE;
}
/* For some reason, we couldn't get thread data */
else
result = PTE_OS_GENERAL_FAILURE;
return result;
}
void pte_osThreadSleep(unsigned int msecs)
{
sceKernelDelayThread(msecs*1000);
}
int pte_osThreadGetMinPriority(void)
{
return 17;
}
int pte_osThreadGetMaxPriority(void)
{
return 30;
}
int pte_osThreadGetDefaultPriority(void)
{
return 18;
}
/****************************************************************************
*
* Mutexes
*
****************************************************************************/
pte_osResult pte_osMutexCreate(pte_osMutexHandle *pHandle)
{
static int mutexCtr = 0;
char mutexName[32];
pte_osMutexHandle handle;
if (mutexCtr++ > MAX_PSP_UID)
mutexCtr = 0;
snprintf(mutexName,sizeof(mutexName),"mutex%d",mutexCtr);
handle = sceKernelCreateSema(mutexName,
0, /* attributes (default) */
1, /* initial value */
1, /* maximum value */
0); /* options (default) */
*pHandle = handle;
return PTE_OS_OK;
}
pte_osResult pte_osMutexDelete(pte_osMutexHandle handle)
{
sceKernelDeleteSema(handle);
return PTE_OS_OK;
}
pte_osResult pte_osMutexLock(pte_osMutexHandle handle)
{
sceKernelWaitSema(handle, 1, NULL);
return PTE_OS_OK;
}
pte_osResult pte_osMutexTimedLock(pte_osMutexHandle handle, unsigned int timeoutMsecs)
{
SceUInt timeoutUsecs = timeoutMsecs*1000;
int status = sceKernelWaitSema(handle, 1, &timeoutUsecs);
/* Assume that any error from sceKernelWaitSema was due to a timeout */
if (status < 0)
return PTE_OS_TIMEOUT;
return PTE_OS_OK;
}
pte_osResult pte_osMutexUnlock(pte_osMutexHandle handle)
{
sceKernelSignalSema(handle, 1);
return PTE_OS_OK;
}
/****************************************************************************
*
* Semaphores
*
***************************************************************************/
pte_osResult pte_osSemaphoreCreate(int initialValue, pte_osSemaphoreHandle *pHandle)
{
pte_osSemaphoreHandle handle;
static int semCtr = 0;
char semName[32];
if (semCtr++ > MAX_PSP_UID)
semCtr = 0;
snprintf(semName,sizeof(semName),"pthread_sem%d",semCtr);
handle = sceKernelCreateSema(semName,
0, /* attributes (default) */
initialValue, /* initial value */
SEM_VALUE_MAX, /* maximum value */
0); /* options (default) */
*pHandle = handle;
return PTE_OS_OK;
}
pte_osResult pte_osSemaphoreDelete(pte_osSemaphoreHandle handle)
{
sceKernelDeleteSema(handle);
return PTE_OS_OK;
}
pte_osResult pte_osSemaphorePost(pte_osSemaphoreHandle handle, int count)
{
sceKernelSignalSema(handle, count);
return PTE_OS_OK;
}
pte_osResult pte_osSemaphorePend(pte_osSemaphoreHandle handle, unsigned int *pTimeoutMsecs)
{
unsigned int timeoutUsecs;
unsigned int *pTimeoutUsecs;
SceUInt result;
pte_osResult osResult;
if (pTimeoutMsecs == NULL)
pTimeoutUsecs = NULL;
else
{
timeoutUsecs = *pTimeoutMsecs * 1000;
pTimeoutUsecs = &timeoutUsecs;
}
result = sceKernelWaitSema(handle, 1, pTimeoutUsecs);
if (result == SCE_KERNEL_ERROR_OK)
return PTE_OS_OK;
if (result == SCE_KERNEL_ERROR_WAIT_TIMEOUT)
return PTE_OS_TIMEOUT;
return PTE_OS_GENERAL_FAILURE;
}
/*
* Pend on a semaphore- and allow the pend to be cancelled.
*
* PSP OS provides no functionality to asynchronously interrupt a blocked call. We simulte
* this by polling on the main semaphore and the cancellation semaphore and sleeping in a loop.
*/
pte_osResult pte_osSemaphoreCancellablePend(pte_osSemaphoreHandle semHandle, unsigned int *pTimeout)
{
pspThreadData *pThreadData;
pThreadData = getThreadData(sceKernelGetThreadId());
clock_t start_time;
pte_osResult result = PTE_OS_OK;
unsigned int timeout;
unsigned char timeoutEnabled;
start_time = clock();
// clock() is in microseconds, timeout as passed in was in milliseconds
if (pTimeout == NULL)
{
timeout = 0;
timeoutEnabled = 0;
}
else
{
timeout = *pTimeout * 1000;
timeoutEnabled = 1;
}
while (1)
{
SceUInt semTimeout;
int status;
/* Poll semaphore */
semTimeout = 0;
status = sceKernelWaitSema(semHandle, 1, &semTimeout);
if (status == SCE_KERNEL_ERROR_OK)
{
/* User semaphore posted to */
result = PTE_OS_OK;
break;
}
else if ((timeoutEnabled) && ((clock() - start_time) > timeout))
{
/* Timeout expired */
result = PTE_OS_TIMEOUT;
break;
}
else
{
SceKernelSemaInfo semInfo;
if (pThreadData != NULL)
{
SceUID osResult;
osResult = sceKernelReferSemaStatus(pThreadData->cancelSem, &semInfo);
if (osResult == SCE_KERNEL_ERROR_OK)
{
if (semInfo.currentCount > 0)
{
result = PTE_OS_INTERRUPTED;
break;
}
/* Nothing found and not timed out yet; let's yield so we're not
* in busy loop.
*/
else
sceKernelDelayThread(POLLING_DELAY_IN_us);
}
else
{
result = PTE_OS_GENERAL_FAILURE;
break;
}
}
}
}
return result;
}
/****************************************************************************
*
* Atomic Operations
*
***************************************************************************/
int pte_osAtomicExchange(int *ptarg, int val)
{
int intc = pspSdkDisableInterrupts();
int origVal = *ptarg;
*ptarg = val;
pspSdkEnableInterrupts(intc);
return origVal;
}
int pte_osAtomicCompareExchange(int *pdest, int exchange, int comp)
{
int intc = pspSdkDisableInterrupts();
int origVal = *pdest;
if (*pdest == comp)
*pdest = exchange;
pspSdkEnableInterrupts(intc);
return origVal;
}
int pte_osAtomicExchangeAdd(int volatile* pAddend, int value)
{
int intc = pspSdkDisableInterrupts();
int origVal = *pAddend;
*pAddend += value;
pspSdkEnableInterrupts(intc);
return origVal;
}
int pte_osAtomicDecrement(int *pdest)
{
int val;
int intc = pspSdkDisableInterrupts();
(*pdest)--;
val = *pdest;
pspSdkEnableInterrupts(intc);
return val;
}
int pte_osAtomicIncrement(int *pdest)
{
int val;
int intc = pspSdkDisableInterrupts();
(*pdest)++;
val = *pdest;
pspSdkEnableInterrupts(intc);
return val;
}
/****************************************************************************
*
* Helper functions
*
***************************************************************************/
static pspThreadData *getThreadData(SceUID threadHandle)
{
void *pTls = getTlsStructFromThread(threadHandle);
pspThreadData *pThreadData = (pspThreadData *)
pteTlsGetValue(pTls, threadDataKey);
return pThreadData;
}
static void *getTlsStructFromThread(SceUID thid)
{
SceKernelThreadInfo thinfo;
unsigned int ptr;
unsigned int thrNum;
int numMatches;
thinfo.size = sizeof(SceKernelThreadInfo);
sceKernelReferThreadStatus(thid, &thinfo);
numMatches = sscanf(thinfo.name,"pthread%04d__%x", &thrNum, &ptr);
/* If we were called from a pthread, use the TLS allocated when the thread
* was created. Otherwise, we were called from a non-pthread, so use the
* "global". This is a pretty bad hack, but necessary due to lack of TLS on PSP.
*/
if (numMatches == 2)
return (void *) ptr;
return globalTls;
}
/****************************************************************************
*
* Thread Local Storage
*
***************************************************************************/
pte_osResult pte_osTlsSetValue(unsigned int key, void * value)
{
void *pTls = getTlsStructFromThread(sceKernelGetThreadId());
return pteTlsSetValue(pTls, key, value);
}
void * pte_osTlsGetValue(unsigned int index)
{
void *pTls = getTlsStructFromThread(sceKernelGetThreadId());
return (void *) pteTlsGetValue(pTls, index);
}
pte_osResult pte_osTlsAlloc(unsigned int *pKey)
{
void *pTls = getTlsStructFromThread(sceKernelGetThreadId());
return pteTlsAlloc(pKey);
}
pte_osResult pte_osTlsFree(unsigned int index)
{
return pteTlsFree(index);
}
/****************************************************************************
*
* Miscellaneous
*
***************************************************************************/
int ftime(struct timeb *tb)
{
struct timeval tv;
struct timezone tz;
gettimeofday(&tv, &tz);
tb->time = tv.tv_sec;
tb->millitm = tv.tv_usec / 1000;
tb->timezone = tz.tz_minuteswest;
tb->dstflag = tz.tz_dsttime;
return 0;
}

View File

@ -1,63 +0,0 @@
/*
* psp_osal.h
*
* Description:
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <pspsdk.h>
typedef SceUID pte_osThreadHandle;
typedef SceUID pte_osSemaphoreHandle;
typedef SceUID pte_osMutexHandle;
#define OS_IS_HANDLE_VALID(x) ((x) > 0)
#define OS_MAX_SIMUL_THREADS 10
#define OS_DEFAULT_PRIO 11
#define OS_MIN_PRIO 17
#define OS_MAX_PRIO 32
#if 0
#define HAVE_THREAD_SAFE_ERRNO
#endif
#define POLLING_DELAY_IN_us 100
#define OS_MAX_SEM_VALUE 254
int PspInterlockedExchange(int *ptarg, int val);
int PspInterlockedCompareExchange(int *pdest, int exchange, int comp);
int PspInterlockedExchangeAdd(int volatile* pAddend, int value);
int PspInterlockedDecrement(int *pdest);
int PspInterlockedIncrement(int *pdest);

View File

@ -1,9 +0,0 @@
#ifndef _OS_SUPPORT_H_
#define _OS_SUPPORT_H_
/* Platform specific one must be included first */
#include "psp_osal.h"
#include "pte_generic_osal.h"
#endif /* _OS_SUPPORT_H */

View File

@ -1,12 +0,0 @@
/* pte_types.h */
#ifndef PTE_TYPES_H
#define PTE_TYPES_H
#include <errno.h>
#include <sys/types.h>
#include <sys/timeb.h>
typedef int pid_t;
#endif /* PTE_TYPES_H */

View File

@ -1,64 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspsdk.h>
#include <pspctrl.h>
PSP_MODULE_INFO("Pthread Test", 0, 1, 1);
extern void pte_test_main();
#ifdef JNS
#define printf pspDebugScreenPrintf
#endif
/* Exit callback */
int exit_callback(int arg1, int arg2, void *common)
{
sceKernelExitGame();
return 0;
}
/* Callback thread */
int CallbackThread(SceSize args, void *argp)
{
int cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
sceKernelRegisterExitCallback(cbid);
sceKernelSleepThreadCB();
return 0;
}
/* Sets up the callback thread and returns its thread id */
int SetupCallbacks(void)
{
int thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, 0, 0);
if (thid >= 0)
sceKernelStartThread(thid, 0, 0);
return thid;
}
int main(void)
{
SceCtrlData pad;
pspDebugScreenInit();
SetupCallbacks();
pte_test_main();
while (1)
{
sceCtrlReadBufferPositive(&pad, 1);
if (pad.Buttons & PSP_CTRL_UP)
{
printf("Exiting...\n");
return 0;
}
}
return 0;
}

1059
deps/pthreads/pte.c vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,449 +0,0 @@
/*
* pte_cancellable_wait.c
*
* Description:
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef _GENERIC_OS_SUPPORT_H_
#define _GENERIC_OS_SUPPORT_H_
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/** @name Misc */
//@{
typedef enum pte_osResult
{
/** Operation completed successfully */
PTE_OS_OK = 0,
/** Operation failed because there insufficient resources */
PTE_OS_NO_RESOURCES,
/** Operation failed due to a general failure */
PTE_OS_GENERAL_FAILURE,
/** Operation did not complete because a user specified timeout expired. */
PTE_OS_TIMEOUT,
/** The operation was interrupted before it could complete. */
PTE_OS_INTERRUPTED,
/** An invalid parameter was specified */
PTE_OS_INVALID_PARAM
} pte_osResult;
/**
* Provides a hook for the OSAL to implement any OS specific initialization. This is guaranteed to be
* called before any other OSAL function.
*/
pte_osResult pte_osInit(void);
//@}
/** @name Mutexes */
//@{
/**
* Creates a mutex
*
* @param pHandle Set to the handle of the newly created mutex.
*
* @return PTE_OS_OK - Mutex successfully created
* @return PTE_OS_NO_RESOURCESs - Insufficient resources to create mutex
*/
pte_osResult pte_osMutexCreate(pte_osMutexHandle *pHandle);
/**
* Deletes a mutex and frees any associated resources.
*
* @param handle Handle of mutex to delete.
*
* @return PTE_OS_OK - Mutex successfully deleted.
*/
pte_osResult pte_osMutexDelete(pte_osMutexHandle handle);
/**
* Locks the mutex
*
* @param handle Handle of mutex to lock.
*
* @return PTE_OS_OK - Mutex successfully locked.
*/
pte_osResult pte_osMutexLock(pte_osMutexHandle handle);
/**
* Locks the mutex, returning after @p timeoutMsecs if the resources is not
* available. Can be used for polling mutex by using @p timeoutMsecs of zero.
*
* @param handle Handle of mutex to lock.
* @param timeoutMsecs Number of milliseconds to wait for resource before returning.
*
* @return PTE_OS_OK - Mutex successfully locked.
* @return PTE_OS_TIMEOUT - Timeout expired before lock was obtained.
*/
pte_osResult pte_osMutexTimedLock(pte_osMutexHandle handle, unsigned int timeoutMsecs);
/**
* Unlocks the mutex
*
* @param handle Handle of mutex to unlock
*
* @return PTE_OS_OK - Mutex successfully unlocked.
*/
pte_osResult pte_osMutexUnlock(pte_osMutexHandle handle);
//@}
/** @name Threads */
//@{
typedef int (*pte_osThreadEntryPoint)(void *params);
/**
* Creates a new thread. The thread must be started in a suspended state - it will be
* explicitly started when pte_osThreadStart() is called.
*
* @param entryPoint Entry point to the new thread.
* @param stackSize The initial stack size, in bytes. Note that this can be considered a minimum -
* for instance if the OS requires a larger stack space than what the caller specified.
* @param initialPriority The priority that the new thread should be initially set to.
* @param argv Parameter to pass to the new thread.
* @param ppte_osThreadHandle set to the handle of the new thread.
*
* @return PTE_OS_OK - New thread successfully created.
* @return PTE_OS_NO_RESOURCESs - Insufficient resources to create thread
*/
pte_osResult pte_osThreadCreate(pte_osThreadEntryPoint entryPoint,
int stackSize,
int initialPriority,
void *argv,
pte_osThreadHandle* ppte_osThreadHandle);
/**
* Starts executing the specified thread.
*
* @param osThreadHandle handle of the thread to start.
*
* @return PTE_OS_OK - thread successfully started.
*/
pte_osResult pte_osThreadStart(pte_osThreadHandle osThreadHandle);
/**
* Causes the current thread to stop executing.
*
* @return Never returns (thread terminated)
*/
void pte_osThreadExit();
/**
* Waits for the specified thread to end. If the thread has already terminated, this returns
* immediately.
*
* @param threadHandle Handle fo thread to wait for.
*
* @return PTE_OS_OK - specified thread terminated.
*/
pte_osResult pte_osThreadWaitForEnd(pte_osThreadHandle threadHandle);
/**
* Returns the handle of the currently executing thread.
*/
pte_osThreadHandle pte_osThreadGetHandle(void);
/**
* Returns the priority of the specified thread.
*/
int pte_osThreadGetPriority(pte_osThreadHandle threadHandle);
/**
* Sets the priority of the specified thread.
*
* @return PTE_OS_OK - thread priority successfully set
*/
pte_osResult pte_osThreadSetPriority(pte_osThreadHandle threadHandle, int newPriority);
/**
* Frees resources associated with the specified thread. This is called after the thread has terminated
* and is no longer needed (e.g. after pthread_join returns). This call will always be made
* from a different context than that of the target thread.
*/
pte_osResult pte_osThreadDelete(pte_osThreadHandle handle);
/**
* Frees resources associated with the specified thread and then causes the thread to exit.
* This is called after the thread has terminated and is no longer needed (e.g. after
* pthread_join returns). This call will always be made from the context of the target thread.
*/
pte_osResult pte_osThreadExitAndDelete(pte_osThreadHandle handle);
/**
* Cancels the specified thread. This should cause pte_osSemaphoreCancellablePend() and for pte_osThreadCheckCancel()
* to return @p PTE_OS_INTERRUPTED.
*
* @param threadHandle handle to the thread to cancel.
*
* @return Thread successfully canceled.
*/
pte_osResult pte_osThreadCancel(pte_osThreadHandle threadHandle);
/**
* Check if pte_osThreadCancel() has been called on the specified thread.
*
* @param threadHandle handle of thread to check the state of.
*
* @return PTE_OS_OK - Thread has not been cancelled
* @return PTE_OS_INTERRUPTED - Thread has been cancelled.
*/
pte_osResult pte_osThreadCheckCancel(pte_osThreadHandle threadHandle);
/**
* Causes the current thread to sleep for the specified number of milliseconds.
*/
void pte_osThreadSleep(unsigned int msecs);
/**
* Returns the maximum allowable priority
*/
int pte_osThreadGetMaxPriority();
/**
* Returns the minimum allowable priority
*/
int pte_osThreadGetMinPriority();
/**
* Returns the priority that should be used if the caller to pthread_create doesn't
* explicitly set one.
*/
int pte_osThreadGetDefaultPriority();
//@}
/** @name Semaphores */
//@{
/**
* Creates a semaphore
*
* @param initialValue Initial value of the semaphore
* @param pHandle Set to the handle of the newly created semaphore.
*
* @return PTE_OS_OK - Semaphore successfully created
* @return PTE_OS_NO_RESOURCESs - Insufficient resources to create semaphore
*/
pte_osResult pte_osSemaphoreCreate(int initialValue, pte_osSemaphoreHandle *pHandle);
/**
* Deletes a semaphore and frees any associated resources.
*
* @param handle Handle of semaphore to delete.
*
* @return PTE_OS_OK - Semaphore successfully deleted.
*/
pte_osResult pte_osSemaphoreDelete(pte_osSemaphoreHandle handle);
/**
* Posts to the semaphore
*
* @param handle Semaphore to release
* @param count Amount to increment the semaphore by.
*
* @return PTE_OS_OK - semaphore successfully released.
*/
pte_osResult pte_osSemaphorePost(pte_osSemaphoreHandle handle, int count);
/**
* Acquire a semaphore, returning after @p timeoutMsecs if the semaphore is not
* available. Can be used for polling a semaphore by using @p timeoutMsecs of zero.
*
* @param handle Handle of semaphore to acquire.
* @param pTimeout Pointer to the number of milliseconds to wait to acquire the semaphore
* before returning. If set to NULL, wait forever.
*
* @return PTE_OS_OK - Semaphore successfully acquired.
* @return PTE_OS_TIMEOUT - Timeout expired before semaphore was obtained.
*/
pte_osResult pte_osSemaphorePend(pte_osSemaphoreHandle handle, unsigned int *pTimeout);
/**
* Acquire a semaphore, returning after @p timeoutMsecs if the semaphore is not
* available. Can be used for polling a semaphore by using @p timeoutMsecs of zero.
* Call must return immediately if pte_osThreadCancel() is called on the thread waiting for
* the semaphore.
*
* @param handle Handle of semaphore to acquire.
* @param pTimeout Pointer to the number of milliseconds to wait to acquire the semaphore
* before returning. If set to NULL, wait forever.
*
* @return PTE_OS_OK - Semaphore successfully acquired.
* @return PTE_OS_TIMEOUT - Timeout expired before semaphore was obtained.
*/
pte_osResult pte_osSemaphoreCancellablePend(pte_osSemaphoreHandle handle, unsigned int *pTimeout);
//@}
/** @name Thread Local Storage */
//@{
/**
* Sets the thread specific value for the specified key for the
* currently executing thread.
*
* @param index The TLS key for the value.
* @param value The value to save
*/
pte_osResult pte_osTlsSetValue(unsigned int key, void * value);
/**
* Retrieves the thread specific value for the specified key for
* the currently executing thread. If a value has not been set
* for this key, NULL should be returned (i.e. TLS values default
* to NULL).
*
* @param index The TLS key for the value.
*
* @return The value associated with @p key for the current thread.
*/
void * pte_osTlsGetValue(unsigned int key);
/**
* Initializes the OS TLS support. This is called by the PTE library
* prior to performing ANY TLS operation.
*/
void pte_osTlsInit(void);
/**
* Allocates a new TLS key.
*
* @param pKey On success will be set to the newly allocated key.
*
* @return PTE_OS_OK - TLS key successfully allocated.
* @return PTE_OS_NO_RESOURCESs - Insufficient resources to allocate key (e.g.
* maximum number of keys reached).
*/
pte_osResult pte_osTlsAlloc(unsigned int *pKey);
/**
* Frees the specified TLS key.
*
* @param index TLS key to free
*
* @return PTE_OS_OK - TLS key was successfully freed.
*/
pte_osResult pte_osTlsFree(unsigned int key);
//@}
/** @name Atomic operations */
//@{
/**
* Sets the target to the specified value as an atomic operation.
*
* \code
* origVal = *ptarg
* *ptarg = val
* return origVal
* \endcode
*
* @param pTarg Pointer to the value to be exchanged.
* @param val Value to be exchanged
*
* @return original value of destination
*/
int pte_osAtomicExchange(int *pTarg, int val);
/**
* Performs an atomic compare-and-exchange oepration on the specified
* value. That is:
*
* \code
* origVal = *pdest
* if (*pdest == comp)
* then *pdest = exchange
* return origVal
* \endcode
*
* @param pdest Pointer to the destination value.
* @param exchange Exchange value (value to set destination to if destination == comparand)
* @param comp The value to compare to destination.
*
* @return Original value of destination
*/
int pte_osAtomicCompareExchange(int *pdest, int exchange, int comp);
/**
* Adds the value to target as an atomic operation
*
* \code
* origVal = *pdest
* *pAddend += value
* return origVal
* \endcode
*
* @param pdest Pointer to the variable to be updated.
* @param value Value to be added to the variable.
*
* @return Original value of destination
*/
int pte_osAtomicExchangeAdd(int volatile* pdest, int value);
/**
* Decrements the destination.
*
* \code
* origVal = *pdest
* *pdest++
* return origVal
* \endcode
*
* @param pdest Destination value to decrement
*
* @return Original destination value
*/
int pte_osAtomicDecrement(int *pdest);
/**
* Increments the destination value
*
* \code
* origVal = *pdest;
* *pdest++;
* return origVal;
*/
int pte_osAtomicIncrement(int *pdest);
//@}
struct timeb;
int ftime(struct timeb *tb);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _OS_SUPPORT_H_

View File

@ -1,396 +0,0 @@
/*
* pte_main.c
*
* Description:
* This translation unit instantiates data associated with the implementation
* as a whole.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include "pte_osal.h"
#include "pthread.h"
#include "implement.h"
int pte_processInitialized = PTE_FALSE;
pte_thread_t * pte_threadReuseTop = PTE_THREAD_REUSE_EMPTY;
pte_thread_t * pte_threadReuseBottom = PTE_THREAD_REUSE_EMPTY;
pthread_key_t pte_selfThreadKey = NULL;
pthread_key_t pte_cleanupKey = NULL;
pthread_cond_t pte_cond_list_head = NULL;
pthread_cond_t pte_cond_list_tail = NULL;
int pte_concurrency = 0;
/* What features have been auto-detaected */
int pte_features = 0;
unsigned char pte_smp_system = PTE_TRUE; /* Safer if assumed true initially. */
/*
* Global lock for managing pthread_t struct reuse.
*/
pte_osMutexHandle pte_thread_reuse_lock;
/*
* Global lock for testing internal state of statically declared mutexes.
*/
pte_osMutexHandle pte_mutex_test_init_lock;
/*
* Global lock for testing internal state of PTHREAD_COND_INITIALIZER
* created condition variables.
*/
pte_osMutexHandle pte_cond_test_init_lock;
/*
* Global lock for testing internal state of PTHREAD_RWLOCK_INITIALIZER
* created read/write locks.
*/
pte_osMutexHandle pte_rwlock_test_init_lock;
/*
* Global lock for testing internal state of PTHREAD_SPINLOCK_INITIALIZER
* created spin locks.
*/
pte_osMutexHandle pte_spinlock_test_init_lock;
/*
* Global lock for condition variable linked list. The list exists
* to wake up CVs when a WM_TIMECHANGE message arrives. See
* w32_TimeChangeHandler.c.
*/
pte_osMutexHandle pte_cond_list_lock;
int pthread_create (pthread_t * tid,
const pthread_attr_t * attr,
void *(*start) (void *), void *arg)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function creates a thread running the start function,
* passing it the parameter value, 'arg'. The 'attr'
* argument specifies optional creation attributes.
* The identity of the new thread is returned
* via 'tid', which should not be NULL.
*
* PARAMETERS
* tid
* pointer to an instance of pthread_t
*
* attr
* optional pointer to an instance of pthread_attr_t
*
* start
* pointer to the starting routine for the new thread
*
* arg
* optional parameter passed to 'start'
*
*
* DESCRIPTION
* This function creates a thread running the start function,
* passing it the parameter value, 'arg'. The 'attr'
* argument specifies optional creation attributes.
* The identity of the new thread is returned
* via 'tid', which should not be the NULL pointer.
*
* RESULTS
* 0 successfully created thread,
* EINVAL attr invalid,
* EAGAIN insufficient resources.
*
* ------------------------------------------------------
*/
{
pthread_t thread;
pte_thread_t * tp;
int result = EAGAIN;
int run = PTE_TRUE;
ThreadParms *parms = NULL;
long stackSize;
int priority = 0;
pthread_t self;
pte_osResult osResult;
register pthread_attr_t a = NULL;
/*
* Before doing anything, check that tid can be stored through
* without invoking a memory protection error (segfault).
* Make sure that the assignment below can't be optimised out by the compiler.
* This is assured by conditionally assigning *tid again at the end.
*/
if (attr != NULL)
a = *attr;
if ((thread = pte_new ()) == NULL)
goto FAIL0;
tp = (pte_thread_t *) thread;
priority = tp->sched_priority;
if ((parms = (ThreadParms *) malloc (sizeof (*parms))) == NULL)
goto FAIL0;
parms->tid = thread;
parms->start = start;
parms->arg = arg;
if (a != NULL)
{
stackSize = a->stacksize;
tp->detachState = a->detachstate;
priority = a->param.sched_priority;
if ( (priority > pte_osThreadGetMaxPriority()) ||
(priority < pte_osThreadGetMinPriority()) )
{
result = EINVAL;
goto FAIL0;
}
/* Everything else */
/*
* Thread priority must be set to a valid system level
* without altering the value set by pthread_attr_setschedparam().
*/
if (PTHREAD_INHERIT_SCHED == a->inheritsched)
{
/*
* If the thread that called pthread_create() is an OS thread
* then the inherited priority could be the result of a temporary
* system adjustment. This is not the case for POSIX threads.
*/
self = pthread_self ();
priority = ((pte_thread_t *) self)->sched_priority;
}
}
else
{
/*
* Default stackSize
*/
stackSize = PTHREAD_STACK_MIN;
}
tp->state = run ? PThreadStateInitial : PThreadStateSuspended;
tp->keys = NULL;
/*
* Threads must be started in suspended mode and resumed if necessary
* after _beginthreadex returns us the handle. Otherwise we set up a
* race condition between the creating and the created threads.
* Note that we also retain a local copy of the handle for use
* by us in case thread.p->threadH gets NULLed later but before we've
* finished with it here.
*/
result = pthread_mutex_lock (&tp->threadLock);
if (result == 0)
{
/*
* Must record the thread's sched_priority as given,
* not as finally adjusted.
*/
tp->sched_priority = priority;
(void) pthread_mutex_unlock (&tp->threadLock);
}
osResult = pte_osThreadCreate(pte_threadStart,
stackSize,
priority,
parms,
&(tp->threadId));
if (osResult == PTE_OS_OK)
{
pte_osThreadStart(tp->threadId);
result = 0;
}
else
{
tp->threadId = 0;
result = EAGAIN;
goto FAIL0;
}
/*
* Fall Through Intentionally
*/
/*
* ------------
* Failure Code
* ------------
*/
FAIL0:
if (result != 0)
{
pte_threadDestroy (thread);
tp = NULL;
if (parms != NULL)
free (parms);
}
else
{
if (tid != NULL)
*tid = thread;
}
return (result);
}
/*
* The functions pte_pop_cleanup and pte_push_cleanup
* are implemented here for applications written in C with no
* C++ destructor support.
*/
pte_cleanup_t *pte_pop_cleanup (int execute)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function pops the most recently pushed cleanup
* handler. If execute is nonzero, then the cleanup handler
* is executed if non-null.
*
* PARAMETERS
* execute
* if nonzero, execute the cleanup handler
*
*
* DESCRIPTION
* This function pops the most recently pushed cleanup
* handler. If execute is nonzero, then the cleanup handler
* is executed if non-null.
* NOTE: specify 'execute' as nonzero to avoid duplication
* of common cleanup code.
*
* RESULTS
* N/A
*
* ------------------------------------------------------
*/
{
pte_cleanup_t *cleanup;
cleanup = (pte_cleanup_t *) pthread_getspecific (pte_cleanupKey);
if (cleanup != NULL)
{
if (execute && (cleanup->routine != NULL))
{
(*cleanup->routine) (cleanup->arg);
}
pthread_setspecific (pte_cleanupKey, (void *) cleanup->prev);
}
return (cleanup);
} /* pte_pop_cleanup */
void
pte_push_cleanup (pte_cleanup_t * cleanup,
pte_cleanup_callback_t routine, void *arg)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function pushes a new cleanup handler onto the thread's stack
* of cleanup handlers. Each cleanup handler pushed onto the stack is
* popped and invoked with the argument 'arg' when
* a) the thread exits by calling 'pthread_exit',
* b) when the thread acts on a cancellation request,
* c) or when the thread calls pthread_cleanup_pop with a nonzero
* 'execute' argument
*
* PARAMETERS
* cleanup
* a pointer to an instance of pthread_cleanup_t,
*
* routine
* pointer to a cleanup handler,
*
* arg
* parameter to be passed to the cleanup handler
*
*
* DESCRIPTION
* This function pushes a new cleanup handler onto the thread's stack
* of cleanup handlers. Each cleanup handler pushed onto the stack is
* popped and invoked with the argument 'arg' when
* a) the thread exits by calling 'pthread_exit',
* b) when the thread acts on a cancellation request,
* c) or when the thrad calls pthread_cleanup_pop with a nonzero
* 'execute' argument
* NOTE: pthread_push_cleanup, pte_pop_cleanup must be paired
* in the same lexical scope.
*
* RESULTS
* pthread_cleanup_t *
* pointer to the previous cleanup
*
* ------------------------------------------------------
*/
{
cleanup->routine = routine;
cleanup->arg = arg;
cleanup->prev = (pte_cleanup_t *) pthread_getspecific (pte_cleanupKey);
pthread_setspecific (pte_cleanupKey, (void *) cleanup);
}

1017
deps/pthreads/pthread.c vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,891 +0,0 @@
/* This is an implementation of the threads API of POSIX 1003.1-2001.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined( PTHREAD_H )
#define PTHREAD_H
#include <pte_types.h>
#include <sched.h>
#define PTE_VERSION 2,8,0,0
#define PTE_VERSION_STRING "2, 8, 0, 0\0"
/* There are two implementations of cancel cleanup.
* Note that pthread.h is included in both application
* compilation units and also internally for the library.
* The code here and within the library aims to work
* for all reasonable combinations of environments.
*
* The two implementations are:
*
* C
* C++
*
*/
/*
* Define defaults for cleanup code.
* Note: Unless the build explicitly defines one of the following, then
* we default to standard C style cleanup. This style uses setjmp/longjmp
* in the cancelation and thread exit implementations and therefore won't
* do stack unwinding if linked to applications that have it (e.g.
* C++ apps). This is currently consistent with most/all commercial Unix
* POSIX threads implementations.
*/
#undef PTE_LEVEL
#if defined(_POSIX_SOURCE)
#define PTE_LEVEL 0
/* Early POSIX */
#endif
#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309
#undef PTE_LEVEL
#define PTE_LEVEL 1
/* Include 1b, 1c and 1d */
#endif
#if defined(INCLUDE_NP)
#undef PTE_LEVEL
#define PTE_LEVEL 2
/* Include Non-Portable extensions */
#endif
#define PTE_LEVEL_MAX 3
#if !defined(PTE_LEVEL)
#define PTE_LEVEL PTE_LEVEL_MAX
/* Include everything */
#endif
/*
* -------------------------------------------------------------
*
*
* Module: pthread.h
*
* Purpose:
* Provides an implementation of PThreads based upon the
* standard:
*
* POSIX 1003.1-2001
* and
* The Single Unix Specification version 3
*
* (these two are equivalent)
*
* in order to enhance code portability between Windows,
* various commercial Unix implementations, and Linux.
*
* See the ANNOUNCE file for a full list of conforming
* routines and defined constants, and a list of missing
* routines and constants not defined in this implementation.
*
* Authors:
* There have been many contributors to this library.
* The initial implementation was contributed by
* John Bossom, and several others have provided major
* sections or revisions of parts of the implementation.
* Often significant effort has been contributed to
* find and fix important bugs and other problems to
* improve the reliability of the library, which sometimes
* is not reflected in the amount of code which changed as
* result.
* As much as possible, the contributors are acknowledged
* in the ChangeLog file in the source code distribution
* where their changes are noted in detail.
*
* Contributors are listed in the CONTRIBUTORS file.
*
* As usual, all bouquets go to the contributors, and all
* brickbats go to the project maintainer.
*
* Maintainer:
* The code base for this project is coordinated and
* eventually pre-tested, packaged, and made available by
*
* Ross Johnson <rpj@callisto.canberra.edu.au>
*
* QA Testers:
* Ultimately, the library is tested in the real world by
* a host of competent and demanding scientists and
* engineers who report bugs and/or provide solutions
* which are then fixed or incorporated into subsequent
* versions of the library. Each time a bug is fixed, a
* test case is written to prove the fix and ensure
* that later changes to the code don't reintroduce the
* same error. The number of test cases is slowly growing
* and therefore so is the code reliability.
*
* Compliance:
* See the file ANNOUNCE for the list of implemented
* and not-implemented routines and defined options.
* Of course, these are all defined is this file as well.
*
* Web site:
* The source code and other information about this library
* are available from
*
* http://sources.redhat.com/pthreads-win32/
*
* -------------------------------------------------------------
*/
#include <time.h>
#include <setjmp.h>
#include <limits.h>
/*
* Boolean values to make us independent of system includes.
*/
enum
{
PTE_FALSE = 0,
PTE_TRUE = (! PTE_FALSE)
};
/*
* -------------------------------------------------------------
*
* POSIX 1003.1-2001 Options
* =========================
*
* Options are normally set in <unistd.h>, which is not provided
* with pthreads-embedded.
*
* For conformance with the Single Unix Specification (version 3), all of the
* options below are defined, and have a value of either -1 (not supported)
* or 200112L (supported).
*
* These options can neither be left undefined nor have a value of 0, because
* either indicates that sysconf(), which is not implemented, may be used at
* runtime to check the status of the option.
*
* _POSIX_THREADS (== 200112L)
* If == 200112L, you can use threads
*
* _POSIX_THREAD_ATTR_STACKSIZE (== 200112L)
* If == 200112L, you can control the size of a thread's
* stack
* pthread_attr_getstacksize
* pthread_attr_setstacksize
*
* _POSIX_THREAD_ATTR_STACKADDR (== -1)
* If == 200112L, you can allocate and control a thread's
* stack. If not supported, the following functions
* will return ENOSYS, indicating they are not
* supported:
* pthread_attr_getstackaddr
* pthread_attr_setstackaddr
*
* _POSIX_THREAD_PRIORITY_SCHEDULING (== -1)
* If == 200112L, you can use realtime scheduling.
* This option indicates that the behaviour of some
* implemented functions conforms to the additional TPS
* requirements in the standard. E.g. rwlocks favour
* writers over readers when threads have equal priority.
*
* _POSIX_THREAD_PRIO_INHERIT (== -1)
* If == 200112L, you can create priority inheritance
* mutexes.
* pthread_mutexattr_getprotocol +
* pthread_mutexattr_setprotocol +
*
* _POSIX_THREAD_PRIO_PROTECT (== -1)
* If == 200112L, you can create priority ceiling mutexes
* Indicates the availability of:
* pthread_mutex_getprioceiling
* pthread_mutex_setprioceiling
* pthread_mutexattr_getprioceiling
* pthread_mutexattr_getprotocol +
* pthread_mutexattr_setprioceiling
* pthread_mutexattr_setprotocol +
*
* _POSIX_THREAD_PROCESS_SHARED (== -1)
* If set, you can create mutexes and condition
* variables that can be shared with another
* process.If set, indicates the availability
* of:
* pthread_mutexattr_getpshared
* pthread_mutexattr_setpshared
* pthread_condattr_getpshared
* pthread_condattr_setpshared
*
* _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L)
* If == 200112L you can use the special *_r library
* functions that provide thread-safe behaviour
*
* _POSIX_READER_WRITER_LOCKS (== 200112L)
* If == 200112L, you can use read/write locks
*
* _POSIX_SPIN_LOCKS (== 200112L)
* If == 200112L, you can use spin locks
*
* _POSIX_BARRIERS (== 200112L)
* If == 200112L, you can use barriers
*
* + These functions provide both 'inherit' and/or
* 'protect' protocol, based upon these macro
* settings.
*
* -------------------------------------------------------------
*/
/*
* POSIX Options
*/
#undef _POSIX_THREADS
#define _POSIX_THREADS 200112L
#undef _POSIX_READER_WRITER_LOCKS
#define _POSIX_READER_WRITER_LOCKS 200112L
#undef _POSIX_SPIN_LOCKS
#define _POSIX_SPIN_LOCKS 200112L
#undef _POSIX_BARRIERS
#define _POSIX_BARRIERS 200112L
#undef _POSIX_THREAD_SAFE_FUNCTIONS
#define _POSIX_THREAD_SAFE_FUNCTIONS 200112L
#undef _POSIX_THREAD_ATTR_STACKSIZE
#define _POSIX_THREAD_ATTR_STACKSIZE 200112L
/*
* The following options are not supported
*/
#undef _POSIX_THREAD_ATTR_STACKADDR
#define _POSIX_THREAD_ATTR_STACKADDR -1
#undef _POSIX_THREAD_PRIO_INHERIT
#define _POSIX_THREAD_PRIO_INHERIT -1
#undef _POSIX_THREAD_PRIO_PROTECT
#define _POSIX_THREAD_PRIO_PROTECT -1
/* TPS is not fully supported. */
#undef _POSIX_THREAD_PRIORITY_SCHEDULING
#define _POSIX_THREAD_PRIORITY_SCHEDULING -1
#undef _POSIX_THREAD_PROCESS_SHARED
#define _POSIX_THREAD_PROCESS_SHARED -1
/*
* POSIX 1003.1-2001 Limits
* ===========================
*
* These limits are normally set in <limits.h>, which is not provided with
* pthreads-embedded.
*
* PTHREAD_DESTRUCTOR_ITERATIONS
* Maximum number of attempts to destroy
* a thread's thread-specific data on
* termination (must be at least 4)
*
* PTHREAD_KEYS_MAX
* Maximum number of thread-specific data keys
* available per process (must be at least 128)
*
* PTHREAD_STACK_MIN
* Minimum supported stack size for a thread
*
* PTHREAD_THREADS_MAX
* Maximum number of threads supported per
* process (must be at least 64).
*
* SEM_NSEMS_MAX
* The maximum number of semaphores a process can have.
* (must be at least 256)
*
* SEM_VALUE_MAX
* The maximum value a semaphore can have.
* (must be at least 32767)
*
*/
#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS
#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4
#undef PTHREAD_DESTRUCTOR_ITERATIONS
#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS
#undef _POSIX_THREAD_KEYS_MAX
#define _POSIX_THREAD_KEYS_MAX 128
#undef PTHREAD_KEYS_MAX
#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX
#undef PTHREAD_STACK_MIN
#define PTHREAD_STACK_MIN 0
#undef _POSIX_THREAD_THREADS_MAX
#define _POSIX_THREAD_THREADS_MAX 64
/* Arbitrary value */
#undef PTHREAD_THREADS_MAX
#define PTHREAD_THREADS_MAX 2019
#undef _POSIX_SEM_NSEMS_MAX
#define _POSIX_SEM_NSEMS_MAX 256
/* Arbitrary value */
#undef SEM_NSEMS_MAX
#define SEM_NSEMS_MAX 1024
#undef _POSIX_SEM_VALUE_MAX
#define _POSIX_SEM_VALUE_MAX 32767
#undef SEM_VALUE_MAX
#define SEM_VALUE_MAX INT_MAX
/*
* Generic handle type - intended to extend uniqueness beyond
* that available with a simple pointer. It should scale for either
* IA-32 or IA-64.
*/
typedef struct
{
void * p; /* Pointer to actual object */
unsigned int x; /* Extra information - reuse count etc */
} pte_handle_t;
typedef /* pte_handle_t */ void * pthread_t;
typedef struct pthread_attr_t_ * pthread_attr_t;
typedef struct pthread_once_t_ pthread_once_t;
typedef struct pthread_key_t_ * pthread_key_t;
typedef struct pthread_mutex_t_ * pthread_mutex_t;
typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t;
typedef struct pthread_cond_t_ * pthread_cond_t;
typedef struct pthread_condattr_t_ * pthread_condattr_t;
typedef struct pthread_rwlock_t_ * pthread_rwlock_t;
typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t;
typedef struct pthread_spinlock_t_ * pthread_spinlock_t;
typedef struct pthread_barrier_t_ * pthread_barrier_t;
typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t;
/*
* ====================
* ====================
* POSIX Threads
* ====================
* ====================
*/
enum
{
/*
* pthread_attr_{get,set}detachstate
*/
PTHREAD_CREATE_JOINABLE = 0, /* Default */
PTHREAD_CREATE_DETACHED = 1,
/*
* pthread_attr_{get,set}inheritsched
*/
PTHREAD_INHERIT_SCHED = 0,
PTHREAD_EXPLICIT_SCHED = 1, /* Default */
/*
* pthread_{get,set}scope
*/
PTHREAD_SCOPE_PROCESS = 0,
PTHREAD_SCOPE_SYSTEM = 1, /* Default */
PTHREAD_SCOPE_PROCESS_VFPU = 2, /* PSP specific */
/*
* pthread_setcancelstate paramters
*/
PTHREAD_CANCEL_ENABLE = 0, /* Default */
PTHREAD_CANCEL_DISABLE = 1,
/*
* pthread_setcanceltype parameters
*/
PTHREAD_CANCEL_ASYNCHRONOUS = 0,
PTHREAD_CANCEL_DEFERRED = 1, /* Default */
/*
* pthread_mutexattr_{get,set}pshared
* pthread_condattr_{get,set}pshared
*/
PTHREAD_PROCESS_PRIVATE = 0,
PTHREAD_PROCESS_SHARED = 1,
/*
* pthread_barrier_wait
*/
PTHREAD_BARRIER_SERIAL_THREAD = -1
};
/*
* ====================
* ====================
* Cancelation
* ====================
* ====================
*/
#define PTHREAD_CANCELED ((void *) -1)
/*
* ====================
* ====================
* Once Key
* ====================
* ====================
*/
#define PTHREAD_ONCE_INIT { PTE_FALSE, 0, 0, 0}
struct pthread_once_t_
{
int state;
void * semaphore;
int numSemaphoreUsers;
int done; /* indicates if user function has been executed */
// void * lock;
// int reserved1;
// int reserved2;
};
/*
* ====================
* ====================
* Object initialisers
* ====================
* ====================
*/
#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) -1)
#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t) -2)
#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t) -3)
/*
* Compatibility with LinuxThreads
*/
#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER
#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER
#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) -1)
#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) -1)
#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t) -1)
/*
* Mutex types.
*/
enum
{
/* Compatibility with LinuxThreads */
PTHREAD_MUTEX_FAST_NP,
PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ERRORCHECK_NP,
PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP,
PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP,
/* For compatibility with POSIX */
PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP,
PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
};
typedef struct pte_cleanup_t pte_cleanup_t;
typedef void (* pte_cleanup_callback_t)(void *);
struct pte_cleanup_t
{
pte_cleanup_callback_t routine;
void *arg;
struct pte_cleanup_t *prev;
};
/*
* C implementation of PThreads cancel cleanup
*/
#define pthread_cleanup_push( _rout, _arg ) \
{ \
pte_cleanup_t _cleanup; \
\
pte_push_cleanup( &_cleanup, (pte_cleanup_callback_t) (_rout), (_arg) ); \
#define pthread_cleanup_pop( _execute ) \
(void) pte_pop_cleanup( _execute ); \
}
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/*
* ===============
* ===============
* Methods
* ===============
* ===============
*/
int pthread_init (void);
void pthread_terminate (void);
/*
* PThread Attribute Functions
*/
int pthread_attr_init (pthread_attr_t * attr);
int pthread_attr_destroy (pthread_attr_t * attr);
int pthread_attr_getdetachstate (const pthread_attr_t * attr,
int *detachstate);
int pthread_attr_getstackaddr (const pthread_attr_t * attr,
void **stackaddr);
int pthread_attr_getstacksize (const pthread_attr_t * attr,
size_t * stacksize);
int pthread_attr_setdetachstate (pthread_attr_t * attr,
int detachstate);
int pthread_attr_setstackaddr (pthread_attr_t * attr,
void *stackaddr);
int pthread_attr_setstacksize (pthread_attr_t * attr,
size_t stacksize);
int pthread_attr_getschedparam (const pthread_attr_t *attr,
struct sched_param *param);
int pthread_attr_setschedparam (pthread_attr_t *attr,
const struct sched_param *param);
int pthread_attr_setschedpolicy (pthread_attr_t *,
int);
int pthread_attr_getschedpolicy (pthread_attr_t *,
int *);
int pthread_attr_setinheritsched(pthread_attr_t * attr,
int inheritsched);
int pthread_attr_getinheritsched(pthread_attr_t * attr,
int * inheritsched);
int pthread_attr_setscope (pthread_attr_t *,
int);
int pthread_attr_getscope (const pthread_attr_t *,
int *);
/*
* PThread Functions
*/
int pthread_create (pthread_t * tid,
const pthread_attr_t * attr,
void *(*start) (void *),
void *arg);
int pthread_detach (pthread_t tid);
int pthread_equal (pthread_t t1,
pthread_t t2);
void pthread_exit (void *value_ptr);
int pthread_join (pthread_t thread,
void **value_ptr);
pthread_t pthread_self (void);
int pthread_cancel (pthread_t thread);
int pthread_setcancelstate (int state,
int *oldstate);
int pthread_setcanceltype (int type,
int *oldtype);
void pthread_testcancel (void);
int pthread_once (pthread_once_t * once_control,
void (*init_routine) (void));
#if PTE_LEVEL >= PTE_LEVEL_MAX
pte_cleanup_t * pte_pop_cleanup (int execute);
void pte_push_cleanup (pte_cleanup_t * cleanup,
void (*routine) (void *),
void *arg);
#endif /* PTE_LEVEL >= PTE_LEVEL_MAX */
/*
* Thread Specific Data Functions
*/
int pthread_key_create (pthread_key_t * key,
void (*destructor) (void *));
int pthread_key_delete (pthread_key_t key);
int pthread_setspecific (pthread_key_t key,
const void *value);
void * pthread_getspecific (pthread_key_t key);
/*
* Mutex Attribute Functions
*/
int pthread_mutexattr_init (pthread_mutexattr_t * attr);
int pthread_mutexattr_destroy (pthread_mutexattr_t * attr);
int pthread_mutexattr_getpshared (const pthread_mutexattr_t
* attr,
int *pshared);
int pthread_mutexattr_setpshared (pthread_mutexattr_t * attr,
int pshared);
int pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind);
int pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind);
/*
* Barrier Attribute Functions
*/
int pthread_barrierattr_init (pthread_barrierattr_t * attr);
int pthread_barrierattr_destroy (pthread_barrierattr_t * attr);
int pthread_barrierattr_getpshared (const pthread_barrierattr_t
* attr,
int *pshared);
int pthread_barrierattr_setpshared (pthread_barrierattr_t * attr,
int pshared);
/*
* Mutex Functions
*/
int pthread_mutex_init (pthread_mutex_t * mutex,
const pthread_mutexattr_t * attr);
int pthread_mutex_destroy (pthread_mutex_t * mutex);
int pthread_mutex_lock (pthread_mutex_t * mutex);
int pthread_mutex_timedlock(pthread_mutex_t *mutex,
const struct timespec *abstime);
int pthread_mutex_trylock (pthread_mutex_t * mutex);
int pthread_mutex_unlock (pthread_mutex_t * mutex);
/*
* Spinlock Functions
*/
int pthread_spin_init (pthread_spinlock_t * lock, int pshared);
int pthread_spin_destroy (pthread_spinlock_t * lock);
int pthread_spin_lock (pthread_spinlock_t * lock);
int pthread_spin_trylock (pthread_spinlock_t * lock);
int pthread_spin_unlock (pthread_spinlock_t * lock);
/*
* Barrier Functions
*/
int pthread_barrier_init (pthread_barrier_t * barrier,
const pthread_barrierattr_t * attr,
unsigned int count);
int pthread_barrier_destroy (pthread_barrier_t * barrier);
int pthread_barrier_wait (pthread_barrier_t * barrier);
/*
* Condition Variable Attribute Functions
*/
int pthread_condattr_init (pthread_condattr_t * attr);
int pthread_condattr_destroy (pthread_condattr_t * attr);
int pthread_condattr_getpshared (const pthread_condattr_t * attr,
int *pshared);
int pthread_condattr_setpshared (pthread_condattr_t * attr,
int pshared);
/*
* Condition Variable Functions
*/
int pthread_cond_init (pthread_cond_t * cond,
const pthread_condattr_t * attr);
int pthread_cond_destroy (pthread_cond_t * cond);
int pthread_cond_wait (pthread_cond_t * cond,
pthread_mutex_t * mutex);
int pthread_cond_timedwait (pthread_cond_t * cond,
pthread_mutex_t * mutex,
const struct timespec *abstime);
int pthread_cond_signal (pthread_cond_t * cond);
int pthread_cond_broadcast (pthread_cond_t * cond);
/*
* Scheduling
*/
int pthread_setschedparam (pthread_t thread,
int policy,
const struct sched_param *param);
int pthread_getschedparam (pthread_t thread,
int *policy,
struct sched_param *param);
int pthread_setconcurrency (int);
int pthread_getconcurrency (void);
/*
* Read-Write Lock Functions
*/
int pthread_rwlock_init(pthread_rwlock_t *lock,
const pthread_rwlockattr_t *attr);
int pthread_rwlock_destroy(pthread_rwlock_t *lock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *);
int pthread_rwlock_trywrlock(pthread_rwlock_t *);
int pthread_rwlock_rdlock(pthread_rwlock_t *lock);
int pthread_rwlock_timedrdlock(pthread_rwlock_t *lock,
const struct timespec *abstime);
int pthread_rwlock_wrlock(pthread_rwlock_t *lock);
int pthread_rwlock_timedwrlock(pthread_rwlock_t *lock,
const struct timespec *abstime);
int pthread_rwlock_unlock(pthread_rwlock_t *lock);
int pthread_rwlockattr_init (pthread_rwlockattr_t * attr);
int pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr);
int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr,
int *pshared);
int pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr,
int pshared);
#if PTE_LEVEL >= PTE_LEVEL_MAX - 1
/*
* Signal Functions. Should be defined in <signal.h> but we might
* already have signal.h that don't define these.
*/
int pthread_kill(pthread_t thread, int sig);
/*
* Non-portable functions
*/
/*
* Compatibility with Linux.
*/
int pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr,
int kind);
int pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr,
int *kind);
/*
* Possibly supported by other POSIX threads implementations
*/
int pthread_delay_np (struct timespec * interval);
int pthread_num_processors_np(void);
/*
* Register a system time change with the library.
* Causes the library to perform various functions
* in response to the change. Should be called whenever
* the application's top level window receives a
* WM_TIMECHANGE message. It can be passed directly to
* pthread_create() as a new thread if desired.
*/
void * pthread_timechange_handler_np(void *);
#endif /*PTE_LEVEL >= PTE_LEVEL_MAX - 1 */
#ifdef __cplusplus
}
#endif /* cplusplus */
#if PTE_LEVEL >= PTE_LEVEL_MAX
#endif /* PTE_LEVEL >= PTE_LEVEL_MAX */
/*
* Some compiler environments don't define some things.
*/
# define _ftime ftime
# define _timeb timeb
#undef PTE_LEVEL
#undef PTE_LEVEL_MAX
#endif /* PTHREAD_H */

View File

@ -1,581 +0,0 @@
/*
* pthread_attr.c
*
* Description:
* This translation unit implements operations on thread attribute objects.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include <string.h>
#include "pthread.h"
#include "implement.h"
#include "sched.h"
int
pthread_attr_destroy (pthread_attr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Destroys a thread attributes object.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_attr_t
*
*
* DESCRIPTION
* Destroys a thread attributes object.
*
* NOTES:
* 1) Does not affect threads created with 'attr'.
*
* RESULTS
* 0 successfully destroyed attr,
* EINVAL 'attr' is invalid.
*
* ------------------------------------------------------
*/
{
if (pte_is_attr (attr) != 0)
return EINVAL;
/*
* Set the attribute object to a specific invalid value.
*/
(*attr)->valid = 0;
free (*attr);
*attr = NULL;
return 0;
}
int pthread_attr_getdetachstate (const pthread_attr_t * attr, int *detachstate)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function determines whether threads created with
* 'attr' will run detached.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_attr_t
*
* detachstate
* pointer to an integer into which is returned one
* of:
*
* PTHREAD_CREATE_JOINABLE
* Thread ID is valid, must be joined
*
* PTHREAD_CREATE_DETACHED
* Thread ID is invalid, cannot be joined,
* canceled, or modified
*
*
* DESCRIPTION
* This function determines whether threads created with
* 'attr' will run detached.
*
* NOTES:
* 1) You cannot join or cancel detached threads.
*
* RESULTS
* 0 successfully retrieved detach state,
* EINVAL 'attr' is invalid
*
* ------------------------------------------------------
*/
{
if (pte_is_attr (attr) != 0 || detachstate == NULL)
{
*detachstate = PTHREAD_CREATE_DETACHED;
return EINVAL;
}
*detachstate = (*attr)->detachstate;
return 0;
}
int pthread_attr_getinheritsched (pthread_attr_t * attr, int *inheritsched)
{
if (pte_is_attr (attr) != 0 || inheritsched == NULL)
return EINVAL;
*inheritsched = (*attr)->inheritsched;
return 0;
}
int pthread_attr_getschedparam (const pthread_attr_t * attr,
struct sched_param *param)
{
if (pte_is_attr (attr) != 0 || param == NULL)
return EINVAL;
memcpy (param, &(*attr)->param, sizeof (*param));
return 0;
}
int pthread_attr_getschedpolicy (pthread_attr_t * attr, int *policy)
{
if (pte_is_attr (attr) != 0 || policy == NULL)
return EINVAL;
/*
* Validate the policy arg.
* Check that a policy constant wasn't passed rather than &policy.
*/
if (policy <= (int *) SCHED_MAX)
return EINVAL;
*policy = SCHED_OTHER;
return 0;
}
int pthread_attr_getscope (const pthread_attr_t * attr, int *contentionscope)
{
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
*contentionscope = (*attr)->contentionscope;
return 0;
#else
return ENOSYS;
#endif
}
int pthread_attr_getstackaddr (const pthread_attr_t * attr, void **stackaddr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function determines the address of the stack
* on which threads created with 'attr' will run.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_attr_t
*
* stackaddr
* pointer into which is returned the stack address.
*
*
* DESCRIPTION
* This function determines the address of the stack
* on which threads created with 'attr' will run.
*
* NOTES:
* 1) Function supported only if this macro is
* defined:
*
* _POSIX_THREAD_ATTR_STACKADDR
*
* 2) Create only one thread for each stack
* address..
*
* RESULTS
* 0 successfully retreived stack address,
* EINVAL 'attr' is invalid
* ENOSYS function not supported
*
* ------------------------------------------------------
*/
{
#if defined( _POSIX_THREAD_ATTR_STACKADDR )
if (pte_is_attr (attr) != 0)
return EINVAL;
*stackaddr = (*attr)->stackaddr;
return 0;
#else
return ENOSYS;
#endif /* _POSIX_THREAD_ATTR_STACKADDR */
}
int
pthread_attr_getstacksize (const pthread_attr_t * attr, size_t * stacksize)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function determines the size of the stack on
* which threads created with 'attr' will run.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_attr_t
*
* stacksize
* pointer to size_t into which is returned the
* stack size, in bytes.
*
*
* DESCRIPTION
* This function determines the size of the stack on
* which threads created with 'attr' will run.
*
* NOTES:
* 1) Function supported only if this macro is
* defined:
*
* _POSIX_THREAD_ATTR_STACKSIZE
*
* 2) Use on newly created attributes object to
* find the default stack size.
*
* RESULTS
* 0 successfully retrieved stack size,
* EINVAL 'attr' is invalid
* ENOSYS function not supported
*
* ------------------------------------------------------
*/
{
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
if (pte_is_attr (attr) != 0)
return EINVAL;
/* Everything is okay. */
*stacksize = (*attr)->stacksize;
return 0;
#else
return ENOSYS;
#endif /* _POSIX_THREAD_ATTR_STACKSIZE */
}
int pthread_attr_init (pthread_attr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Initializes a thread attributes object with default
* attributes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_attr_t
*
*
* DESCRIPTION
* Initializes a thread attributes object with default
* attributes.
*
* NOTES:
* 1) Used to define thread attributes
*
* RESULTS
* 0 successfully initialized attr,
* ENOMEM insufficient memory for attr.
*
* ------------------------------------------------------
*/
{
pthread_attr_t attr_result;
/* This is disallowed. */
if (attr == NULL)
return EINVAL;
attr_result = (pthread_attr_t) malloc (sizeof (*attr_result));
if (attr_result == NULL)
return ENOMEM;
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
/*
* Default to zero size?
*/
attr_result->stacksize = 0;
#endif
#ifdef _POSIX_THREAD_ATTR_STACKADDR
/* FIXME: Set this to something sensible when we support it. */
attr_result->stackaddr = NULL;
#endif
attr_result->detachstate = PTHREAD_CREATE_JOINABLE;
/*
* Win32 sets new threads to THREAD_PRIORITY_NORMAL and
* not to that of the parent thread. We choose to default to
* this arrangement.
*/
attr_result->param.sched_priority = pte_osThreadGetDefaultPriority();
attr_result->inheritsched = PTHREAD_EXPLICIT_SCHED;
attr_result->contentionscope = PTHREAD_SCOPE_SYSTEM;
attr_result->valid = PTE_ATTR_VALID;
*attr = attr_result;
return 0;
}
int pthread_attr_setdetachstate (pthread_attr_t * attr, int detachstate)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function specifies whether threads created with
* 'attr' will run detached.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_attr_t
*
* detachstate
* an integer containing one of:
*
* PTHREAD_CREATE_JOINABLE
* Thread ID is valid, must be joined
*
* PTHREAD_CREATE_DETACHED
* Thread ID is invalid, cannot be joined,
* canceled, or modified
*
*
* DESCRIPTION
* This function specifies whether threads created with
* 'attr' will run detached.
*
* NOTES:
* 1) You cannot join or cancel detached threads.
*
* RESULTS
* 0 successfully set detach state,
* EINVAL 'attr' or 'detachstate' is invalid
*
* ------------------------------------------------------
*/
{
if (pte_is_attr (attr) != 0)
return EINVAL;
if (detachstate != PTHREAD_CREATE_JOINABLE &&
detachstate != PTHREAD_CREATE_DETACHED)
return EINVAL;
(*attr)->detachstate = detachstate;
return 0;
}
int pthread_attr_setinheritsched (pthread_attr_t * attr, int inheritsched)
{
if (pte_is_attr (attr) != 0)
return EINVAL;
if (PTHREAD_INHERIT_SCHED != inheritsched
&& PTHREAD_EXPLICIT_SCHED != inheritsched)
return EINVAL;
(*attr)->inheritsched = inheritsched;
return 0;
}
int pthread_attr_setschedparam (pthread_attr_t * attr,
const struct sched_param *param)
{
int priority;
if (pte_is_attr (attr) != 0 || param == NULL)
return EINVAL;
priority = param->sched_priority;
/* Validate priority level. */
if (priority < sched_get_priority_min (SCHED_OTHER) ||
priority > sched_get_priority_max (SCHED_OTHER))
{
return EINVAL;
}
memcpy (&(*attr)->param, param, sizeof (*param));
return 0;
}
int pthread_attr_setschedpolicy (pthread_attr_t * attr, int policy)
{
if (pte_is_attr (attr) != 0)
return EINVAL;
if (policy != SCHED_OTHER)
return ENOTSUP;
return 0;
}
int pthread_attr_setscope (pthread_attr_t * attr, int contentionscope)
{
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
switch (contentionscope)
{
case PTHREAD_SCOPE_SYSTEM:
(*attr)->contentionscope = contentionscope;
return 0;
case PTHREAD_SCOPE_PROCESS:
return ENOTSUP;
default:
return EINVAL;
}
#else
return ENOSYS;
#endif
}
int pthread_attr_setstackaddr (pthread_attr_t * attr, void *stackaddr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Threads created with 'attr' will run on the stack
* starting at 'stackaddr'.
* Stack must be at least PTHREAD_STACK_MIN bytes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_attr_t
*
* stacksize
* stack size, in bytes.
*
*
* DESCRIPTION
* Threads created with 'attr' will run on the stack
* starting at 'stackaddr'.
* Stack must be at least PTHREAD_STACK_MIN bytes.
*
* NOTES:
* 1) Function supported only if this macro is
* defined:
*
* _POSIX_THREAD_ATTR_STACKADDR
*
* 2) Create only one thread for each stack
* address..
*
* 3) Ensure that stackaddr is aligned.
*
* RESULTS
* 0 successfully set stack address,
* EINVAL 'attr' is invalid
* ENOSYS function not supported
*
* ------------------------------------------------------
*/
{
#if defined( _POSIX_THREAD_ATTR_STACKADDR )
if (pte_is_attr (attr) != 0)
return EINVAL;
(*attr)->stackaddr = stackaddr;
return 0;
#else
return ENOSYS;
#endif /* _POSIX_THREAD_ATTR_STACKADDR */
}
int pthread_attr_setstacksize (pthread_attr_t * attr, size_t stacksize)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function specifies the size of the stack on
* which threads created with 'attr' will run.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_attr_t
*
* stacksize
* stack size, in bytes.
*
*
* DESCRIPTION
* This function specifies the size of the stack on
* which threads created with 'attr' will run.
*
* NOTES:
* 1) Function supported only if this macro is
* defined:
*
* _POSIX_THREAD_ATTR_STACKSIZE
*
* 2) Find the default first (using
* pthread_attr_getstacksize), then increase
* by multiplying.
*
* 3) Only use if thread needs more than the
* default.
*
* RESULTS
* 0 successfully set stack size,
* EINVAL 'attr' is invalid or stacksize too
* small or too big.
* ENOSYS function not supported
*
* ------------------------------------------------------
*/
{
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
#if PTHREAD_STACK_MIN > 0
/* Verify that the stack size is within range. */
if (stacksize < PTHREAD_STACK_MIN)
return EINVAL;
#endif
if (pte_is_attr (attr) != 0)
return EINVAL;
/* Everything is okay. */
(*attr)->stacksize = stacksize;
return 0;
#else
return ENOSYS;
#endif /* _POSIX_THREAD_ATTR_STACKSIZE */
}

View File

@ -1,163 +0,0 @@
/*
* pthread_barrier.c
*
* Description:
* This translation unit implements barrier primitives.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include "pthread.h"
#include "implement.h"
int pthread_barrier_destroy (pthread_barrier_t * barrier)
{
int result = 0;
pthread_barrier_t b;
if (barrier == NULL || *barrier == (pthread_barrier_t) PTE_OBJECT_INVALID)
return EINVAL;
b = *barrier;
*barrier = NULL;
if (0 == (result = sem_destroy (&(b->semBarrierBreeched[0]))))
{
if (0 == (result = sem_destroy (&(b->semBarrierBreeched[1]))))
{
(void) free (b);
return 0;
}
(void) sem_init (&(b->semBarrierBreeched[0]), b->pshared, 0);
}
*barrier = b;
return (result);
}
int pthread_barrier_init (pthread_barrier_t * barrier,
const pthread_barrierattr_t * attr, unsigned int count)
{
pthread_barrier_t b;
if (barrier == NULL || count == 0)
return EINVAL;
if (NULL != (b = (pthread_barrier_t) calloc (1, sizeof (*b))))
{
b->pshared = (attr != NULL && *attr != NULL
? (*attr)->pshared : PTHREAD_PROCESS_PRIVATE);
b->nCurrentBarrierHeight = b->nInitialBarrierHeight = count;
b->iStep = 0;
/*
* Two semaphores are used in the same way as two stepping
* stones might be used in crossing a stream. Once all
* threads are safely on one stone, the other stone can
* be moved ahead, and the threads can start moving to it.
* If some threads decide to eat their lunch before moving
* then the other threads have to wait.
*/
if (0 == sem_init (&(b->semBarrierBreeched[0]), b->pshared, 0))
{
if (0 == sem_init (&(b->semBarrierBreeched[1]), b->pshared, 0))
{
*barrier = b;
return 0;
}
(void) sem_destroy (&(b->semBarrierBreeched[0]));
}
(void) free (b);
}
return ENOMEM;
}
int pthread_barrier_wait (pthread_barrier_t * barrier)
{
int result;
int step;
pthread_barrier_t b;
if (barrier == NULL || *barrier == (pthread_barrier_t) PTE_OBJECT_INVALID)
return EINVAL;
b = *barrier;
step = b->iStep;
if (0 == PTE_ATOMIC_DECREMENT ((int *) &(b->nCurrentBarrierHeight)))
{
/* Must be done before posting the semaphore. */
b->nCurrentBarrierHeight = b->nInitialBarrierHeight;
/*
* There is no race condition between the semaphore wait and post
* because we are using two alternating semas and all threads have
* entered barrier_wait and checked nCurrentBarrierHeight before this
* barrier's sema can be posted. Any threads that have not quite
* entered sem_wait below when the multiple_post has completed
* will nevertheless continue through the semaphore (barrier)
* and will not be left stranded.
*/
result = (b->nInitialBarrierHeight > 1
? sem_post_multiple (&(b->semBarrierBreeched[step]),
b->nInitialBarrierHeight - 1) : 0);
}
else
{
/*
* Use the non-cancelable version of sem_wait().
*/
result = sem_wait (&(b->semBarrierBreeched[step]));
// result = sem_wait_nocancel (&(b->semBarrierBreeched[step]));
}
/*
* The first thread across will be the PTHREAD_BARRIER_SERIAL_THREAD.
* This also sets up the alternate semaphore as the next barrier.
*/
if (0 == result)
{
result = (step ==
PTE_ATOMIC_COMPARE_EXCHANGE (& (b->iStep),(1L - step),step) ?
PTHREAD_BARRIER_SERIAL_THREAD : 0);
}
return (result);
}

View File

@ -1,257 +0,0 @@
/*
* pthread_barrier_attr.c
*
* Description:
* This translation unit implements barrier primitives.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include "pthread.h"
#include "implement.h"
int
pthread_barrierattr_destroy (pthread_barrierattr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Destroys a barrier attributes object. The object can
* no longer be used.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_barrierattr_t
*
*
* DESCRIPTION
* Destroys a barrier attributes object. The object can
* no longer be used.
*
* NOTES:
* 1) Does not affect barrieres created using 'attr'
*
* RESULTS
* 0 successfully released attr,
* EINVAL 'attr' is invalid.
*
* ------------------------------------------------------
*/
{
int result = 0;
if (attr == NULL || *attr == NULL)
result = EINVAL;
else
{
pthread_barrierattr_t ba = *attr;
*attr = NULL;
free (ba);
}
return (result);
}
int
pthread_barrierattr_getpshared (const pthread_barrierattr_t * attr,
int *pshared)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Determine whether barriers created with 'attr' can be
* shared between processes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_barrierattr_t
*
* pshared
* will be set to one of:
*
* PTHREAD_PROCESS_SHARED
* May be shared if in shared memory
*
* PTHREAD_PROCESS_PRIVATE
* Cannot be shared.
*
*
* DESCRIPTION
* Mutexes creatd with 'attr' can be shared between
* processes if pthread_barrier_t variable is allocated
* in memory shared by these processes.
* NOTES:
* 1) pshared barriers MUST be allocated in shared
* memory.
* 2) The following macro is defined if shared barriers
* are supported:
* _POSIX_THREAD_PROCESS_SHARED
*
* RESULTS
* 0 successfully retrieved attribute,
* EINVAL 'attr' is invalid,
*
* ------------------------------------------------------
*/
{
int result;
if ((attr != NULL && *attr != NULL) && (pshared != NULL))
{
*pshared = (*attr)->pshared;
result = 0;
}
else
result = EINVAL;
return (result);
}
int pthread_barrierattr_init (pthread_barrierattr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Initializes a barrier attributes object with default
* attributes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_barrierattr_t
*
*
* DESCRIPTION
* Initializes a barrier attributes object with default
* attributes.
*
* NOTES:
* 1) Used to define barrier types
*
* RESULTS
* 0 successfully initialized attr,
* ENOMEM insufficient memory for attr.
*
* ------------------------------------------------------
*/
{
int result = 0;
pthread_barrierattr_t ba = (pthread_barrierattr_t) calloc (1, sizeof (*ba));
if (ba == NULL)
result = ENOMEM;
else
ba->pshared = PTHREAD_PROCESS_PRIVATE;
*attr = ba;
return (result);
}
int pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, int pshared)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Barriers created with 'attr' can be shared between
* processes if pthread_barrier_t variable is allocated
* in memory shared by these processes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_barrierattr_t
*
* pshared
* must be one of:
*
* PTHREAD_PROCESS_SHARED
* May be shared if in shared memory
*
* PTHREAD_PROCESS_PRIVATE
* Cannot be shared.
*
* DESCRIPTION
* Mutexes creatd with 'attr' can be shared between
* processes if pthread_barrier_t variable is allocated
* in memory shared by these processes.
*
* NOTES:
* 1) pshared barriers MUST be allocated in shared
* memory.
*
* 2) The following macro is defined if shared barriers
* are supported:
* _POSIX_THREAD_PROCESS_SHARED
*
* RESULTS
* 0 successfully set attribute,
* EINVAL 'attr' or pshared is invalid,
* ENOSYS PTHREAD_PROCESS_SHARED not supported,
*
* ------------------------------------------------------
*/
{
int result;
if ((attr != NULL && *attr != NULL) &&
((pshared == PTHREAD_PROCESS_SHARED) ||
(pshared == PTHREAD_PROCESS_PRIVATE)))
{
if (pshared == PTHREAD_PROCESS_SHARED)
{
#if !defined( _POSIX_THREAD_PROCESS_SHARED )
result = ENOSYS;
pshared = PTHREAD_PROCESS_PRIVATE;
#else
result = 0;
#endif /* _POSIX_THREAD_PROCESS_SHARED */
}
else
result = 0;
(*attr)->pshared = pshared;
}
else
result = EINVAL;
return (result);
} /* pthread_barrierattr_setpshared */

View File

@ -1,807 +0,0 @@
/*
* pthread_cond.c
*
* Description:
* This translation unit implements condition variables and their primitives.
*
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include "pthread.h"
#include "implement.h"
/*
* Arguments for cond_wait_cleanup, since we can only pass a
* single void * to it.
*/
typedef struct
{
pthread_mutex_t *mutexPtr;
pthread_cond_t cv;
int *resultPtr;
} pte_cond_wait_cleanup_args_t;
static void pte_cond_wait_cleanup (void *args)
{
pte_cond_wait_cleanup_args_t *cleanup_args =
(pte_cond_wait_cleanup_args_t *) args;
pthread_cond_t cv = cleanup_args->cv;
int *resultPtr = cleanup_args->resultPtr;
int nSignalsWasLeft;
int result;
/*
* Whether we got here as a result of signal/broadcast or because of
* timeout on wait or thread cancellation we indicate that we are no
* longer waiting. The waiter is responsible for adjusting waiters
* (to)unblock(ed) counts (protected by unblock lock).
*/
if ((result = pthread_mutex_lock (&(cv->mtxUnblockLock))) != 0)
{
*resultPtr = result;
return;
}
if (0 != (nSignalsWasLeft = cv->nWaitersToUnblock))
{
--(cv->nWaitersToUnblock);
}
else if (INT_MAX / 2 == ++(cv->nWaitersGone))
{
/* Use the non-cancellable version of sem_wait() */
// if (sem_wait_nocancel (&(cv->semBlockLock)) != 0)
if (sem_wait (&(cv->semBlockLock)) != 0)
{
*resultPtr = errno;
/*
* This is a fatal error for this CV,
* so we deliberately don't unlock
* cv->mtxUnblockLock before returning.
*/
return;
}
cv->nWaitersBlocked -= cv->nWaitersGone;
if (sem_post (&(cv->semBlockLock)) != 0)
{
*resultPtr = errno;
/*
* This is a fatal error for this CV,
* so we deliberately don't unlock
* cv->mtxUnblockLock before returning.
*/
return;
}
cv->nWaitersGone = 0;
}
if ((result = pthread_mutex_unlock (&(cv->mtxUnblockLock))) != 0)
{
*resultPtr = result;
return;
}
if (1 == nSignalsWasLeft)
{
if (sem_post (&(cv->semBlockLock)) != 0)
{
*resultPtr = errno;
return;
}
}
/*
* XSH: Upon successful return, the mutex has been locked and is owned
* by the calling thread.
*/
if ((result = pthread_mutex_lock (cleanup_args->mutexPtr)) != 0)
*resultPtr = result;
}
static int pte_cond_timedwait (pthread_cond_t * cond,
pthread_mutex_t * mutex, const struct timespec *abstime)
{
int result = 0;
pthread_cond_t cv;
pte_cond_wait_cleanup_args_t cleanup_args;
if (cond == NULL || *cond == NULL)
return EINVAL;
/*
* We do a quick check to see if we need to do more work
* to initialise a static condition variable. We check
* again inside the guarded section of pte_cond_check_need_init()
* to avoid race conditions.
*/
if (*cond == PTHREAD_COND_INITIALIZER)
result = pte_cond_check_need_init (cond);
if (result != 0 && result != EBUSY)
return result;
cv = *cond;
/* Thread can be cancelled in sem_wait() but this is OK */
if (sem_wait (&(cv->semBlockLock)) != 0)
return errno;
++(cv->nWaitersBlocked);
if (sem_post (&(cv->semBlockLock)) != 0)
return errno;
/*
* Setup this waiter cleanup handler
*/
cleanup_args.mutexPtr = mutex;
cleanup_args.cv = cv;
cleanup_args.resultPtr = &result;
pthread_cleanup_push (pte_cond_wait_cleanup, (void *) &cleanup_args);
/*
* Now we can release 'mutex' and...
*/
if ((result = pthread_mutex_unlock (mutex)) == 0)
{
/*
* ...wait to be awakened by
* pthread_cond_signal, or
* pthread_cond_broadcast, or
* timeout, or
* thread cancellation
*
* Note:
*
* sem_timedwait is a cancellation point,
* hence providing the mechanism for making
* pthread_cond_wait a cancellation point.
* We use the cleanup mechanism to ensure we
* re-lock the mutex and adjust (to)unblock(ed) waiters
* counts if we are cancelled, timed out or signalled.
*/
if (sem_timedwait (&(cv->semBlockQueue), abstime) != 0)
result = errno;
}
/*
* Always cleanup
*/
pthread_cleanup_pop (1);
/*
* "result" can be modified by the cleanup handler.
*/
return result;
}
int
pthread_cond_destroy (pthread_cond_t * cond)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function destroys a condition variable
*
*
* PARAMETERS
* cond
* pointer to an instance of pthread_cond_t
*
*
* DESCRIPTION
* This function destroys a condition variable.
*
* NOTES:
* 1) A condition variable can be destroyed
* immediately after all the threads that
* are blocked on it are awakened. e.g.
*
* struct list {
* pthread_mutex_t lm;
* ...
* }
*
* struct elt {
* key k;
* int busy;
* pthread_cond_t notbusy;
* ...
* }
*
*
* struct elt *
* list_find(struct list *lp, key k)
* {
* struct elt *ep;
*
* pthread_mutex_lock(&lp->lm);
* while ((ep = find_elt(l,k) != NULL) && ep->busy)
* pthread_cond_wait(&ep->notbusy, &lp->lm);
* if (ep != NULL)
* ep->busy = 1;
* pthread_mutex_unlock(&lp->lm);
* return(ep);
* }
*
* delete_elt(struct list *lp, struct elt *ep)
* {
* pthread_mutex_lock(&lp->lm);
* assert(ep->busy);
* ... remove ep from list ...
* ep->busy = 0;
* (A) pthread_cond_broadcast(&ep->notbusy);
* pthread_mutex_unlock(&lp->lm);
* (B) pthread_cond_destroy(&rp->notbusy);
* free(ep);
* }
*
* In this example, the condition variable
* and its list element may be freed (line B)
* immediately after all threads waiting for
* it are awakened (line A), since the mutex
* and the code ensure that no other thread
* can touch the element to be deleted.
*
* RESULTS
* 0 successfully released condition variable,
* EINVAL 'cond' is invalid,
* EBUSY 'cond' is in use,
*
* ------------------------------------------------------
*/
{
pthread_cond_t cv;
int result = 0, result1 = 0, result2 = 0;
/*
* Assuming any race condition here is harmless.
*/
if (cond == NULL || *cond == NULL)
return EINVAL;
if (*cond != PTHREAD_COND_INITIALIZER)
{
pte_osMutexLock (pte_cond_list_lock);
cv = *cond;
/*
* Close the gate; this will synchronize this thread with
* all already signaled waiters to let them retract their
* waiter status - SEE NOTE 1 ABOVE!!!
*/
if (sem_wait (&(cv->semBlockLock)) != 0)
return errno;
/*
* !TRY! lock mtxUnblockLock; try will detect busy condition
* and will not cause a deadlock with respect to concurrent
* signal/broadcast.
*/
if ((result = pthread_mutex_trylock (&(cv->mtxUnblockLock))) != 0)
{
(void) sem_post (&(cv->semBlockLock));
return result;
}
/*
* Check whether cv is still busy (still has waiters)
*/
if (cv->nWaitersBlocked > cv->nWaitersGone)
{
if (sem_post (&(cv->semBlockLock)) != 0)
result = errno;
result1 = pthread_mutex_unlock (&(cv->mtxUnblockLock));
result2 = EBUSY;
}
else
{
/*
* Now it is safe to destroy
*/
*cond = NULL;
if (sem_destroy (&(cv->semBlockLock)) != 0)
result = errno;
if (sem_destroy (&(cv->semBlockQueue)) != 0)
result1 = errno;
if ((result2 = pthread_mutex_unlock (&(cv->mtxUnblockLock))) == 0)
result2 = pthread_mutex_destroy (&(cv->mtxUnblockLock));
/* Unlink the CV from the list */
if (pte_cond_list_head == cv)
pte_cond_list_head = cv->next;
else
cv->prev->next = cv->next;
if (pte_cond_list_tail == cv)
pte_cond_list_tail = cv->prev;
else
cv->next->prev = cv->prev;
(void) free (cv);
}
pte_osMutexUnlock(pte_cond_list_lock);
}
else
{
/*
* See notes in pte_cond_check_need_init() above also.
*/
pte_osMutexLock (pte_cond_test_init_lock);
/*
* Check again.
*/
if (*cond == PTHREAD_COND_INITIALIZER)
{
/*
* This is all we need to do to destroy a statically
* initialised cond that has not yet been used (initialised).
* If we get to here, another thread waiting to initialise
* this cond will get an EINVAL. That's OK.
*/
*cond = NULL;
}
else
{
/*
* The cv has been initialised while we were waiting
* so assume it's in use.
*/
result = EBUSY;
}
pte_osMutexUnlock(pte_cond_test_init_lock);
}
return ((result != 0) ? result : ((result1 != 0) ? result1 : result2));
}
int pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function initializes a condition variable.
*
* PARAMETERS
* cond
* pointer to an instance of pthread_cond_t
*
* attr
* specifies optional creation attributes.
*
*
* DESCRIPTION
* This function initializes a condition variable.
*
* RESULTS
* 0 successfully created condition variable,
* EINVAL 'attr' is invalid,
* EAGAIN insufficient resources (other than
* memory,
* ENOMEM insufficient memory,
* EBUSY 'cond' is already initialized,
*
* ------------------------------------------------------
*/
{
int result;
pthread_cond_t cv = NULL;
if (cond == NULL)
return EINVAL;
if ((attr != NULL && *attr != NULL) &&
((*attr)->pshared == PTHREAD_PROCESS_SHARED))
{
/*
* Creating condition variable that can be shared between
* processes.
*/
result = ENOSYS;
goto DONE;
}
cv = (pthread_cond_t) calloc (1, sizeof (*cv));
if (cv == NULL)
{
result = ENOMEM;
goto DONE;
}
cv->nWaitersBlocked = 0;
cv->nWaitersToUnblock = 0;
cv->nWaitersGone = 0;
if (sem_init (&(cv->semBlockLock), 0, 1) != 0)
{
result = errno;
goto FAIL0;
}
if (sem_init (&(cv->semBlockQueue), 0, 0) != 0)
{
result = errno;
goto FAIL1;
}
if ((result = pthread_mutex_init (&(cv->mtxUnblockLock), 0)) != 0)
{
goto FAIL2;
}
result = 0;
goto DONE;
/*
* -------------
* Failed...
* -------------
*/
FAIL2:
(void) sem_destroy (&(cv->semBlockQueue));
FAIL1:
(void) sem_destroy (&(cv->semBlockLock));
FAIL0:
(void) free (cv);
cv = NULL;
DONE:
if (0 == result)
{
pte_osMutexLock (pte_cond_list_lock);
cv->next = NULL;
cv->prev = pte_cond_list_tail;
if (pte_cond_list_tail != NULL)
pte_cond_list_tail->next = cv;
pte_cond_list_tail = cv;
if (pte_cond_list_head == NULL)
pte_cond_list_head = cv;
pte_osMutexUnlock(pte_cond_list_lock);
}
*cond = cv;
return result;
}
static int pte_cond_unblock (pthread_cond_t * cond, int unblockAll)
/*
* Notes.
*
* Does not use the external mutex for synchronisation,
* therefore semBlockLock is needed.
* mtxUnblockLock is for LEVEL-2 synch. LEVEL-2 is the
* state where the external mutex is not necessarily locked by
* any thread, ie. between cond_wait unlocking and re-acquiring
* the lock after having been signaled or a timeout or
* cancellation.
*
* Uses the following CV elements:
* nWaitersBlocked
* nWaitersToUnblock
* nWaitersGone
* mtxUnblockLock
* semBlockLock
* semBlockQueue
*/
{
int result;
pthread_cond_t cv;
int nSignalsToIssue;
if (cond == NULL || *cond == NULL)
return EINVAL;
cv = *cond;
/*
* No-op if the CV is static and hasn't been initialised yet.
* Assuming that any race condition is harmless.
*/
if (cv == PTHREAD_COND_INITIALIZER)
return 0;
if ((result = pthread_mutex_lock (&(cv->mtxUnblockLock))) != 0)
return result;
if (0 != cv->nWaitersToUnblock)
{
if (0 == cv->nWaitersBlocked)
return pthread_mutex_unlock (&(cv->mtxUnblockLock));
if (unblockAll)
{
cv->nWaitersToUnblock += (nSignalsToIssue = cv->nWaitersBlocked);
cv->nWaitersBlocked = 0;
}
else
{
nSignalsToIssue = 1;
cv->nWaitersToUnblock++;
cv->nWaitersBlocked--;
}
}
else if (cv->nWaitersBlocked > cv->nWaitersGone)
{
/* Use the non-cancellable version of sem_wait() */
// if (sem_wait_nocancel (&(cv->semBlockLock)) != 0)
if (sem_wait (&(cv->semBlockLock)) != 0)
{
result = errno;
(void) pthread_mutex_unlock (&(cv->mtxUnblockLock));
return result;
}
if (0 != cv->nWaitersGone)
{
cv->nWaitersBlocked -= cv->nWaitersGone;
cv->nWaitersGone = 0;
}
if (unblockAll)
{
nSignalsToIssue = cv->nWaitersToUnblock = cv->nWaitersBlocked;
cv->nWaitersBlocked = 0;
}
else
{
nSignalsToIssue = cv->nWaitersToUnblock = 1;
cv->nWaitersBlocked--;
}
}
else
return pthread_mutex_unlock (&(cv->mtxUnblockLock));
if ((result = pthread_mutex_unlock (&(cv->mtxUnblockLock))) == 0)
{
if (sem_post_multiple (&(cv->semBlockQueue), nSignalsToIssue) != 0)
result = errno;
}
return result;
}
int pthread_cond_signal (pthread_cond_t * cond)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function signals a condition variable, waking
* one waiting thread.
* If SCHED_FIFO or SCHED_RR policy threads are waiting
* the highest priority waiter is awakened; otherwise,
* an unspecified waiter is awakened.
*
* PARAMETERS
* cond
* pointer to an instance of pthread_cond_t
*
*
* DESCRIPTION
* This function signals a condition variable, waking
* one waiting thread.
* If SCHED_FIFO or SCHED_RR policy threads are waiting
* the highest priority waiter is awakened; otherwise,
* an unspecified waiter is awakened.
*
* NOTES:
*
* 1) Use when any waiter can respond and only one need
* respond (all waiters being equal).
*
* RESULTS
* 0 successfully signaled condition,
* EINVAL 'cond' is invalid,
*
* ------------------------------------------------------
*/
{
/*
* The '0'(FALSE) unblockAll arg means unblock ONE waiter.
*/
return (pte_cond_unblock (cond, 0));
} /* pthread_cond_signal */
int
pthread_cond_broadcast (pthread_cond_t * cond)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function broadcasts the condition variable,
* waking all current waiters.
*
* PARAMETERS
* cond
* pointer to an instance of pthread_cond_t
*
*
* DESCRIPTION
* This function signals a condition variable, waking
* all waiting threads.
*
* NOTES:
*
* 1) Use when more than one waiter may respond to
* predicate change or if any waiting thread may
* not be able to respond
*
* RESULTS
* 0 successfully signalled condition to all
* waiting threads,
* EINVAL 'cond' is invalid
* ENOSPC a required resource has been exhausted,
*
* ------------------------------------------------------
*/
{
/*
* The TRUE unblockAll arg means unblock ALL waiters.
*/
return (pte_cond_unblock (cond, PTE_TRUE));
}
int pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function waits on a condition variable until
* awakened by a signal or broadcast.
*
* Caller MUST be holding the mutex lock; the
* lock is released and the caller is blocked waiting
* on 'cond'. When 'cond' is signaled, the mutex
* is re-acquired before returning to the caller.
*
* PARAMETERS
* cond
* pointer to an instance of pthread_cond_t
*
* mutex
* pointer to an instance of pthread_mutex_t
*
*
* DESCRIPTION
* This function waits on a condition variable until
* awakened by a signal or broadcast.
*
* NOTES:
*
* 1) The function must be called with 'mutex' LOCKED
* by the calling thread, or undefined behaviour
* will result.
*
* 2) This routine atomically releases 'mutex' and causes
* the calling thread to block on the condition variable.
* The blocked thread may be awakened by
* pthread_cond_signal or
* pthread_cond_broadcast.
*
* Upon successful completion, the 'mutex' has been locked and
* is owned by the calling thread.
*
*
* RESULTS
* 0 caught condition; mutex released,
* EINVAL 'cond' or 'mutex' is invalid,
* EINVAL different mutexes for concurrent waits,
* EINVAL mutex is not held by the calling thread,
*
* ------------------------------------------------------
*/
{
/*
* The NULL abstime arg means INFINITE waiting.
*/
return (pte_cond_timedwait (cond, mutex, NULL));
} /* pthread_cond_wait */
int
pthread_cond_timedwait (pthread_cond_t * cond,
pthread_mutex_t * mutex,
const struct timespec *abstime)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function waits on a condition variable either until
* awakened by a signal or broadcast; or until the time
* specified by abstime passes.
*
* PARAMETERS
* cond
* pointer to an instance of pthread_cond_t
*
* mutex
* pointer to an instance of pthread_mutex_t
*
* abstime
* pointer to an instance of (const struct timespec)
*
*
* DESCRIPTION
* This function waits on a condition variable either until
* awakened by a signal or broadcast; or until the time
* specified by abstime passes.
*
* NOTES:
* 1) The function must be called with 'mutex' LOCKED
* by the calling thread, or undefined behaviour
* will result.
*
* 2) This routine atomically releases 'mutex' and causes
* the calling thread to block on the condition variable.
* The blocked thread may be awakened by
* pthread_cond_signal or
* pthread_cond_broadcast.
*
*
* RESULTS
* 0 caught condition; mutex released,
* EINVAL 'cond', 'mutex', or abstime is invalid,
* EINVAL different mutexes for concurrent waits,
* EINVAL mutex is not held by the calling thread,
* ETIMEDOUT abstime ellapsed before cond was signaled.
*
* ------------------------------------------------------
*/
{
if (abstime == NULL)
{
return EINVAL;
}
return (pte_cond_timedwait (cond, mutex, abstime));
}

View File

@ -1,259 +0,0 @@
/*
* condvar_attr_destroy.c
*
* Description:
* This translation unit implements condition variables and their primitives.
*
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include "pthread.h"
#include "implement.h"
int
pthread_condattr_destroy (pthread_condattr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Destroys a condition variable attributes object.
* The object can no longer be used.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_condattr_t
*
*
* DESCRIPTION
* Destroys a condition variable attributes object.
* The object can no longer be used.
*
* NOTES:
* 1) Does not affect condition variables created
* using 'attr'
*
* RESULTS
* 0 successfully released attr,
* EINVAL 'attr' is invalid.
*
* ------------------------------------------------------
*/
{
int result = 0;
if (attr == NULL || *attr == NULL)
result = EINVAL;
else
{
(void) free (*attr);
*attr = NULL;
result = 0;
}
return result;
}
int pthread_condattr_getpshared (const pthread_condattr_t * attr, int *pshared)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Determine whether condition variables created with 'attr'
* can be shared between processes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_condattr_t
*
* pshared
* will be set to one of:
*
* PTHREAD_PROCESS_SHARED
* May be shared if in shared memory
*
* PTHREAD_PROCESS_PRIVATE
* Cannot be shared.
*
*
* DESCRIPTION
* Condition Variables created with 'attr' can be shared
* between processes if pthread_cond_t variable is allocated
* in memory shared by these processes.
* NOTES:
* 1) pshared condition variables MUST be allocated in
* shared memory.
*
* 2) The following macro is defined if shared mutexes
* are supported:
* _POSIX_THREAD_PROCESS_SHARED
*
* RESULTS
* 0 successfully retrieved attribute,
* EINVAL 'attr' or 'pshared' is invalid,
*
* ------------------------------------------------------
*/
{
int result;
if ((attr != NULL && *attr != NULL) && (pshared != NULL))
{
*pshared = (*attr)->pshared;
result = 0;
}
else
result = EINVAL;
return result;
}
int pthread_condattr_init (pthread_condattr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Initializes a condition variable attributes object
* with default attributes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_condattr_t
*
*
* DESCRIPTION
* Initializes a condition variable attributes object
* with default attributes.
*
* NOTES:
* 1) Use to define condition variable types
* 2) It is up to the application to ensure
* that it doesn't re-init an attribute
* without destroying it first. Otherwise
* a memory leak is created.
*
* RESULTS
* 0 successfully initialized attr,
* ENOMEM insufficient memory for attr.
*
* ------------------------------------------------------
*/
{
pthread_condattr_t attr_result;
int result = 0;
attr_result = (pthread_condattr_t) calloc (1, sizeof (*attr_result));
if (attr_result == NULL)
result = ENOMEM;
*attr = attr_result;
return result;
}
int pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Mutexes created with 'attr' can be shared between
* processes if pthread_mutex_t variable is allocated
* in memory shared by these processes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_mutexattr_t
*
* pshared
* must be one of:
*
* PTHREAD_PROCESS_SHARED
* May be shared if in shared memory
*
* PTHREAD_PROCESS_PRIVATE
* Cannot be shared.
*
* DESCRIPTION
* Mutexes creatd with 'attr' can be shared between
* processes if pthread_mutex_t variable is allocated
* in memory shared by these processes.
*
* NOTES:
* 1) pshared mutexes MUST be allocated in shared
* memory.
*
* 2) The following macro is defined if shared mutexes
* are supported:
* _POSIX_THREAD_PROCESS_SHARED
*
* RESULTS
* 0 successfully set attribute,
* EINVAL 'attr' or pshared is invalid,
* ENOSYS PTHREAD_PROCESS_SHARED not supported,
*
* ------------------------------------------------------
*/
{
int result;
if ((attr != NULL && *attr != NULL)
&& ((pshared == PTHREAD_PROCESS_SHARED)
|| (pshared == PTHREAD_PROCESS_PRIVATE)))
{
if (pshared == PTHREAD_PROCESS_SHARED)
{
#if !defined( _POSIX_THREAD_PROCESS_SHARED )
result = ENOSYS;
pshared = PTHREAD_PROCESS_PRIVATE;
#else
result = 0;
#endif /* _POSIX_THREAD_PROCESS_SHARED */
}
else
result = 0;
(*attr)->pshared = pshared;
}
else
result = EINVAL;
return result;
}

View File

@ -1,111 +0,0 @@
/*
* pthread_get.c
*
* Description:
* This translation unit implements miscellaneous thread functions.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include "pthread.h"
#include "implement.h"
#include "sched.h"
int pthread_getconcurrency (void)
{
return pte_concurrency;
}
int pthread_getschedparam (pthread_t thread, int *policy,
struct sched_param *param)
{
int result;
/* Validate the thread id. */
result = pthread_kill (thread, 0);
if (0 != result)
return result;
/*
* Validate the policy and param args.
* Check that a policy constant wasn't passed rather than &policy.
*/
if (policy <= (int *) SCHED_MAX || param == NULL)
return EINVAL;
/* Fill out the policy. */
*policy = SCHED_OTHER;
/*
* This function must return the priority value set by
* the most recent pthread_setschedparam() or pthread_create()
* for the target thread. It must not return the actual thread
* priority as altered by any system priority adjustments etc.
*/
param->sched_priority = ((pte_thread_t *)thread)->sched_priority;
return 0;
}
void *pthread_getspecific (pthread_key_t key)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function returns the current value of key in the
* calling thread. If no value has been set for 'key' in
* the thread, NULL is returned.
*
* PARAMETERS
* key
* an instance of pthread_key_t
*
*
* DESCRIPTION
* This function returns the current value of key in the
* calling thread. If no value has been set for 'key' in
* the thread, NULL is returned.
*
* RESULTS
* key value or NULL on failure
*
* ------------------------------------------------------
*/
{
if (key == NULL)
return NULL;
return pte_osTlsGetValue (key->key);
}

View File

@ -1,204 +0,0 @@
/*
* pthread_key.c
*
* Description:
* POSIX thread functions which implement thread-specific data (TSD).
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include "pte_osal.h"
#include "pthread.h"
#include "implement.h"
int
pthread_key_create (pthread_key_t * key, void (*destructor) (void *))
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function creates a thread-specific data key visible
* to all threads. All existing and new threads have a value
* NULL for key until set using pthread_setspecific. When any
* thread with a non-NULL value for key terminates, 'destructor'
* is called with key's current value for that thread.
*
* PARAMETERS
* key
* pointer to an instance of pthread_key_t
*
*
* DESCRIPTION
* This function creates a thread-specific data key visible
* to all threads. All existing and new threads have a value
* NULL for key until set using pthread_setspecific. When any
* thread with a non-NULL value for key terminates, 'destructor'
* is called with key's current value for that thread.
*
* RESULTS
* 0 successfully created semaphore,
* EAGAIN insufficient resources or PTHREAD_KEYS_MAX
* exceeded,
* ENOMEM insufficient memory to create the key,
*
* ------------------------------------------------------
*/
{
int result = 0;
pthread_key_t newkey;
if ((newkey = (pthread_key_t) calloc (1, sizeof (*newkey))) == NULL)
result = ENOMEM;
else
{
pte_osResult osResult = pte_osTlsAlloc(&(newkey->key));
if (osResult != PTE_OS_OK)
{
result = EAGAIN;
free (newkey);
newkey = NULL;
}
else if (destructor != NULL)
{
/*
* Have to manage associations between thread and key;
* Therefore, need a lock that allows multiple threads
* to gain exclusive access to the key->threads list.
*
* The mutex will only be created when it is first locked.
*/
newkey->keyLock = PTHREAD_MUTEX_INITIALIZER;
newkey->destructor = destructor;
}
}
*key = newkey;
return (result);
}
int pthread_key_delete (pthread_key_t key)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function deletes a thread-specific data key. This
* does not change the value of the thread specific data key
* for any thread and does not run the key's destructor
* in any thread so it should be used with caution.
*
* PARAMETERS
* key
* pointer to an instance of pthread_key_t
*
*
* DESCRIPTION
* This function deletes a thread-specific data key. This
* does not change the value of the thread specific data key
* for any thread and does not run the key's destructor
* in any thread so it should be used with caution.
*
* RESULTS
* 0 successfully deleted the key,
* EINVAL key is invalid,
*
* ------------------------------------------------------
*/
{
int result = 0;
if (key != NULL)
{
if (key->threads != NULL &&
key->destructor != NULL &&
pthread_mutex_lock (&(key->keyLock)) == 0)
{
ThreadKeyAssoc *assoc;
/*
* Run through all Thread<-->Key associations
* for this key.
*
* While we hold at least one of the locks guarding
* the assoc, we know that the assoc pointed to by
* key->threads is valid.
*/
while ((assoc = (ThreadKeyAssoc *) key->threads) != NULL)
{
pte_thread_t * thread = assoc->thread;
/* Finished */
if (assoc == NULL)
break;
if (pthread_mutex_lock (&(thread->threadLock)) == 0)
{
/*
* Since we are starting at the head of the key's threads
* chain, this will also point key->threads at the next assoc.
* While we hold key->keyLock, no other thread can insert
* a new assoc via pthread_setspecific.
*/
pte_tkAssocDestroy (assoc);
(void) pthread_mutex_unlock (&(thread->threadLock));
}
else
{
/* Thread or lock is no longer valid? */
pte_tkAssocDestroy (assoc);
}
}
pthread_mutex_unlock (&(key->keyLock));
}
pte_osTlsFree (key->key);
if (key->destructor != NULL)
{
/* A thread could be holding the keyLock */
while (EBUSY == (result = pthread_mutex_destroy (&(key->keyLock))))
pte_osThreadSleep(1); /* Ugly. */
}
free (key);
}
return (result);
}

View File

@ -1,500 +0,0 @@
/*
* pthread_mutex.c
*
* Description:
* This translation unit implements mutual exclusion (mutex) primitives.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pte_osal.h>
#include "pthread.h"
#include "implement.h"
#define TEST_IE InterlockedExchange
int pthread_mutex_destroy (pthread_mutex_t * mutex)
{
int result = 0;
pthread_mutex_t mx;
/*
* Let the system deal with invalid pointers.
*/
/*
* Check to see if we have something to delete.
*/
if (*mutex < PTHREAD_ERRORCHECK_MUTEX_INITIALIZER)
{
mx = *mutex;
result = pthread_mutex_trylock (&mx);
/*
* If trylock succeeded and the mutex is not recursively locked it
* can be destroyed.
*/
if (result == 0)
{
if (mx->kind != PTHREAD_MUTEX_RECURSIVE || 1 == mx->recursive_count)
{
/*
* FIXME!!!
* The mutex isn't held by another thread but we could still
* be too late invalidating the mutex below since another thread
* may already have entered mutex_lock and the check for a valid
* *mutex != NULL.
*
* Note that this would be an unusual situation because it is not
* common that mutexes are destroyed while they are still in
* use by other threads.
*/
*mutex = NULL;
result = pthread_mutex_unlock (&mx);
if (result == 0)
{
pte_osSemaphoreDelete(mx->handle);
free(mx);
}
else
{
/*
* Restore the mutex before we return the error.
*/
*mutex = mx;
}
}
else /* mx->recursive_count > 1 */
{
/*
* The mutex must be recursive and already locked by us (this thread).
*/
mx->recursive_count--; /* Undo effect of pthread_mutex_trylock() above */
result = EBUSY;
}
}
}
else
{
/*
* See notes in pte_mutex_check_need_init() above also.
*/
pte_osMutexLock (pte_mutex_test_init_lock);
/*
* Check again.
*/
if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER)
{
/*
* This is all we need to do to destroy a statically
* initialised mutex that has not yet been used (initialised).
* If we get to here, another thread
* waiting to initialise this mutex will get an EINVAL.
*/
*mutex = NULL;
}
else
{
/*
* The mutex has been initialised while we were waiting
* so assume it's in use.
*/
result = EBUSY;
}
pte_osMutexUnlock(pte_mutex_test_init_lock);
}
return (result);
}
int pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t * attr)
{
int result = 0;
pthread_mutex_t mx;
if (mutex == NULL)
return EINVAL;
mx = (pthread_mutex_t) calloc (1, sizeof (*mx));
if (mx == NULL)
result = ENOMEM;
else
{
mx->lock_idx = 0;
mx->recursive_count = 0;
mx->kind = (attr == NULL || *attr == NULL
? PTHREAD_MUTEX_DEFAULT : (*attr)->kind);
mx->ownerThread = NULL;
pte_osSemaphoreCreate(0,&mx->handle);
}
*mutex = mx;
return (result);
}
int pthread_mutex_lock (pthread_mutex_t * mutex)
{
int result = 0;
pthread_mutex_t mx;
/*
* Let the system deal with invalid pointers.
*/
if (*mutex == NULL)
return EINVAL;
/*
* We do a quick check to see if we need to do more work
* to initialise a static mutex. We check
* again inside the guarded section of pte_mutex_check_need_init()
* to avoid race conditions.
*/
if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER)
{
if ((result = pte_mutex_check_need_init (mutex)) != 0)
return (result);
}
mx = *mutex;
if (mx->kind == PTHREAD_MUTEX_NORMAL)
{
if (PTE_ATOMIC_EXCHANGE(
&mx->lock_idx,
1) != 0)
{
while (PTE_ATOMIC_EXCHANGE(&mx->lock_idx,-1) != 0)
{
if (pte_osSemaphorePend(mx->handle,NULL) != PTE_OS_OK)
{
result = EINVAL;
break;
}
}
}
}
else
{
pthread_t self = pthread_self();
if (PTE_ATOMIC_COMPARE_EXCHANGE(&mx->lock_idx,1,0) == 0)
{
mx->recursive_count = 1;
mx->ownerThread = self;
}
else
{
if (pthread_equal (mx->ownerThread, self))
{
if (mx->kind == PTHREAD_MUTEX_RECURSIVE)
mx->recursive_count++;
else
result = EDEADLK;
}
else
{
while (PTE_ATOMIC_EXCHANGE(&mx->lock_idx,-1) != 0)
{
if (pte_osSemaphorePend(mx->handle,NULL) != PTE_OS_OK)
{
result = EINVAL;
break;
}
}
if (0 == result)
{
mx->recursive_count = 1;
mx->ownerThread = self;
}
}
}
}
return (result);
}
static int pte_timed_eventwait (pte_osSemaphoreHandle event, const struct timespec *abstime)
/*
* ------------------------------------------------------
* DESCRIPTION
* This function waits on an event until signaled or until
* abstime passes.
* If abstime has passed when this routine is called then
* it returns a result to indicate this.
*
* If 'abstime' is a NULL pointer then this function will
* block until it can successfully decrease the value or
* until interrupted by a signal.
*
* This routine is not a cancelation point.
*
* RESULTS
* 0 successfully signaled,
* ETIMEDOUT abstime passed
* EINVAL 'event' is not a valid event,
*
* ------------------------------------------------------
*/
{
unsigned int milliseconds;
pte_osResult status;
int retval;
if (abstime == NULL)
status = pte_osSemaphorePend(event, NULL);
else
{
/*
* Calculate timeout as milliseconds from current system time.
*/
milliseconds = pte_relmillisecs (abstime);
status = pte_osSemaphorePend(event, &milliseconds);
}
if (status == PTE_OS_TIMEOUT)
{
retval = ETIMEDOUT;
}
else
{
retval = 0;
}
return retval;
}
int pthread_mutex_timedlock (pthread_mutex_t * mutex,
const struct timespec *abstime)
{
int result;
pthread_mutex_t mx;
/*
* Let the system deal with invalid pointers.
*/
/*
* We do a quick check to see if we need to do more work
* to initialise a static mutex. We check
* again inside the guarded section of pte_mutex_check_need_init()
* to avoid race conditions.
*/
if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER)
{
if ((result = pte_mutex_check_need_init (mutex)) != 0)
return (result);
}
mx = *mutex;
if (mx->kind == PTHREAD_MUTEX_NORMAL)
{
if (PTE_ATOMIC_EXCHANGE(&mx->lock_idx,1) != 0)
{
while (PTE_ATOMIC_EXCHANGE(&mx->lock_idx,-1) != 0)
{
if (0 != (result = pte_timed_eventwait (mx->handle, abstime)))
return result;
}
}
}
else
{
pthread_t self = pthread_self();
if (PTE_ATOMIC_COMPARE_EXCHANGE(&mx->lock_idx,1,0) == 0)
{
mx->recursive_count = 1;
mx->ownerThread = self;
}
else
{
if (pthread_equal (mx->ownerThread, self))
{
if (mx->kind == PTHREAD_MUTEX_RECURSIVE)
mx->recursive_count++;
else
return EDEADLK;
}
else
{
while (PTE_ATOMIC_EXCHANGE(&mx->lock_idx,-1) != 0)
{
if (0 != (result = pte_timed_eventwait (mx->handle, abstime)))
return result;
}
mx->recursive_count = 1;
mx->ownerThread = self;
}
}
}
return 0;
}
int pthread_mutex_trylock (pthread_mutex_t * mutex)
{
int result = 0;
pthread_mutex_t mx;
/*
* Let the system deal with invalid pointers.
*/
/*
* We do a quick check to see if we need to do more work
* to initialise a static mutex. We check
* again inside the guarded section of pte_mutex_check_need_init()
* to avoid race conditions.
*/
if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER)
{
if ((result = pte_mutex_check_need_init (mutex)) != 0)
return (result);
}
mx = *mutex;
if (0 == PTE_ATOMIC_COMPARE_EXCHANGE (&mx->lock_idx,1,0))
{
if (mx->kind != PTHREAD_MUTEX_NORMAL)
{
mx->recursive_count = 1;
mx->ownerThread = pthread_self ();
}
}
else
{
if (mx->kind == PTHREAD_MUTEX_RECURSIVE &&
pthread_equal (mx->ownerThread, pthread_self ()))
mx->recursive_count++;
else
result = EBUSY;
}
return (result);
}
int pthread_mutex_unlock (pthread_mutex_t * mutex)
{
int result = 0;
pthread_mutex_t mx = *mutex;
/*
* Let the system deal with invalid pointers.
*/
/*
* If the thread calling us holds the mutex then there is no
* race condition. If another thread holds the
* lock then we shouldn't be in here.
*/
if (mx < PTHREAD_ERRORCHECK_MUTEX_INITIALIZER)
{
if (mx->kind == PTHREAD_MUTEX_NORMAL)
{
int idx;
idx = PTE_ATOMIC_EXCHANGE (&mx->lock_idx,0);
if (idx != 0)
{
if (idx < 0)
{
/*
* Someone may be waiting on that mutex.
*/
if (pte_osSemaphorePost(mx->handle,1) != PTE_OS_OK)
result = EINVAL;
}
}
else
{
/*
* Was not locked (so can't be owned by us).
*/
result = EPERM;
}
}
else
{
if (pthread_equal (mx->ownerThread, pthread_self ()))
{
if (mx->kind != PTHREAD_MUTEX_RECURSIVE
|| 0 == --mx->recursive_count)
{
mx->ownerThread = NULL;
if (PTE_ATOMIC_EXCHANGE (&mx->lock_idx,0) < 0)
{
if (pte_osSemaphorePost(mx->handle,1) != PTE_OS_OK)
result = EINVAL;
}
}
}
else
result = EPERM;
}
}
else
result = EINVAL;
return (result);
}

View File

@ -1,377 +0,0 @@
/*
* pthread_mutexattr.c
*
* Description:
* This translation unit implements mutual exclusion (mutex) primitives.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include "pthread.h"
#include "implement.h"
int pthread_mutexattr_destroy (pthread_mutexattr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Destroys a mutex attributes object. The object can
* no longer be used.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_mutexattr_t
*
*
* DESCRIPTION
* Destroys a mutex attributes object. The object can
* no longer be used.
*
* NOTES:
* 1) Does not affect mutexes created using 'attr'
*
* RESULTS
* 0 successfully released attr,
* EINVAL 'attr' is invalid.
*
* ------------------------------------------------------
*/
{
int result = 0;
if (attr == NULL || *attr == NULL)
result = EINVAL;
else
{
pthread_mutexattr_t ma = *attr;
*attr = NULL;
free (ma);
}
return (result);
}
int pthread_mutexattr_getkind_np (pthread_mutexattr_t * attr, int *kind)
{
return pthread_mutexattr_gettype (attr, kind);
}
int pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind)
{
int result = 0;
if (attr != NULL && *attr != NULL && kind != NULL)
*kind = (*attr)->kind;
else
result = EINVAL;
return (result);
}
int pthread_mutexattr_getpshared (const pthread_mutexattr_t * attr, int *pshared)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Determine whether mutexes created with 'attr' can be
* shared between processes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_mutexattr_t
*
* pshared
* will be set to one of:
*
* PTHREAD_PROCESS_SHARED
* May be shared if in shared memory
*
* PTHREAD_PROCESS_PRIVATE
* Cannot be shared.
*
*
* DESCRIPTION
* Mutexes creatd with 'attr' can be shared between
* processes if pthread_mutex_t variable is allocated
* in memory shared by these processes.
* NOTES:
* 1) pshared mutexes MUST be allocated in shared
* memory.
* 2) The following macro is defined if shared mutexes
* are supported:
* _POSIX_THREAD_PROCESS_SHARED
*
* RESULTS
* 0 successfully retrieved attribute,
* EINVAL 'attr' is invalid,
*
* ------------------------------------------------------
*/
{
int result;
if ((attr != NULL && *attr != NULL) && (pshared != NULL))
{
*pshared = (*attr)->pshared;
result = 0;
}
else
result = EINVAL;
return (result);
}
int pthread_mutexattr_init (pthread_mutexattr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Initializes a mutex attributes object with default
* attributes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_mutexattr_t
*
*
* DESCRIPTION
* Initializes a mutex attributes object with default
* attributes.
*
* NOTES:
* 1) Used to define mutex types
*
* RESULTS
* 0 successfully initialized attr,
* ENOMEM insufficient memory for attr.
*
* ------------------------------------------------------
*/
{
int result = 0;
pthread_mutexattr_t ma = (pthread_mutexattr_t) calloc (1, sizeof (*ma));
if (ma == NULL)
result = ENOMEM;
else
{
ma->pshared = PTHREAD_PROCESS_PRIVATE;
ma->kind = PTHREAD_MUTEX_DEFAULT;
}
*attr = ma;
return (result);
}
int pthread_mutexattr_setkind_np (pthread_mutexattr_t * attr, int kind)
{
return pthread_mutexattr_settype (attr, kind);
}
int pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, int pshared)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Mutexes created with 'attr' can be shared between
* processes if pthread_mutex_t variable is allocated
* in memory shared by these processes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_mutexattr_t
*
* pshared
* must be one of:
*
* PTHREAD_PROCESS_SHARED
* May be shared if in shared memory
*
* PTHREAD_PROCESS_PRIVATE
* Cannot be shared.
*
* DESCRIPTION
* Mutexes creatd with 'attr' can be shared between
* processes if pthread_mutex_t variable is allocated
* in memory shared by these processes.
*
* NOTES:
* 1) pshared mutexes MUST be allocated in shared
* memory.
*
* 2) The following macro is defined if shared mutexes
* are supported:
* _POSIX_THREAD_PROCESS_SHARED
*
* RESULTS
* 0 successfully set attribute,
* EINVAL 'attr' or pshared is invalid,
* ENOSYS PTHREAD_PROCESS_SHARED not supported,
*
* ------------------------------------------------------
*/
{
int result;
if ((attr != NULL && *attr != NULL) &&
((pshared == PTHREAD_PROCESS_SHARED) ||
(pshared == PTHREAD_PROCESS_PRIVATE)))
{
if (pshared == PTHREAD_PROCESS_SHARED)
{
#if !defined( _POSIX_THREAD_PROCESS_SHARED )
result = ENOSYS;
pshared = PTHREAD_PROCESS_PRIVATE;
#else
result = 0;
#endif /* _POSIX_THREAD_PROCESS_SHARED */
}
else
result = 0;
(*attr)->pshared = pshared;
}
else
result = EINVAL;
return (result);
}
int pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind)
/*
* ------------------------------------------------------
*
* DOCPUBLIC
* The pthread_mutexattr_settype() and
* pthread_mutexattr_gettype() functions respectively set and
* get the mutex type attribute. This attribute is set in the
* type parameter to these functions.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_mutexattr_t
*
* type
* must be one of:
*
* PTHREAD_MUTEX_DEFAULT
*
* PTHREAD_MUTEX_NORMAL
*
* PTHREAD_MUTEX_ERRORCHECK
*
* PTHREAD_MUTEX_RECURSIVE
*
* DESCRIPTION
* The pthread_mutexattr_settype() and
* pthread_mutexattr_gettype() functions respectively set and
* get the mutex type attribute. This attribute is set in the
* type parameter to these functions. The default value of the
* type attribute is PTHREAD_MUTEX_DEFAULT.
*
* The type of mutex is contained in the type attribute of the
* mutex attributes. Valid mutex types include:
*
* PTHREAD_MUTEX_NORMAL
* This type of mutex does not detect deadlock. A
* thread attempting to relock this mutex without
* first unlocking it will deadlock. Attempting to
* unlock a mutex locked by a different thread
* results in undefined behavior. Attempting to
* unlock an unlocked mutex results in undefined
* behavior.
*
* PTHREAD_MUTEX_ERRORCHECK
* This type of mutex provides error checking. A
* thread attempting to relock this mutex without
* first unlocking it will return with an error. A
* thread attempting to unlock a mutex which another
* thread has locked will return with an error. A
* thread attempting to unlock an unlocked mutex will
* return with an error.
*
* PTHREAD_MUTEX_DEFAULT
* Same as PTHREAD_MUTEX_NORMAL.
*
* PTHREAD_MUTEX_RECURSIVE
* A thread attempting to relock this mutex without
* first unlocking it will succeed in locking the
* mutex. The relocking deadlock which can occur with
* mutexes of type PTHREAD_MUTEX_NORMAL cannot occur
* with this type of mutex. Multiple locks of this
* mutex require the same number of unlocks to
* release the mutex before another thread can
* acquire the mutex. A thread attempting to unlock a
* mutex which another thread has locked will return
* with an error. A thread attempting to unlock an
* unlocked mutex will return with an error. This
* type of mutex is only supported for mutexes whose
* process shared attribute is
* PTHREAD_PROCESS_PRIVATE.
*
* RESULTS
* 0 successfully set attribute,
* EINVAL 'attr' or 'type' is invalid,
*
* ------------------------------------------------------
*/
{
int result = 0;
if ((attr != NULL && *attr != NULL))
{
switch (kind)
{
case PTHREAD_MUTEX_FAST_NP:
case PTHREAD_MUTEX_RECURSIVE_NP:
case PTHREAD_MUTEX_ERRORCHECK_NP:
(*attr)->kind = kind;
break;
default:
result = EINVAL;
break;
}
}
else
result = EINVAL;
return (result);
}

View File

@ -1,676 +0,0 @@
/*
* pthread_rwlock.c
*
* Description:
* This translation unit implements read/write lock primitives.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include "pthread.h"
#include "implement.h"
int pthread_rwlock_destroy (pthread_rwlock_t * rwlock)
{
pthread_rwlock_t rwl;
int result = 0, result1 = 0, result2 = 0;
if (rwlock == NULL || *rwlock == NULL)
return EINVAL;
if (*rwlock != PTHREAD_RWLOCK_INITIALIZER)
{
rwl = *rwlock;
if (rwl->nMagic != PTE_RWLOCK_MAGIC)
return EINVAL;
if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0)
return result;
if ((result =
pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
/*
* Check whether any threads own/wait for the lock (wait for ex.access);
* report "BUSY" if so.
*/
if (rwl->nExclusiveAccessCount > 0
|| rwl->nSharedAccessCount > rwl->nCompletedSharedAccessCount)
{
result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted));
result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
result2 = EBUSY;
}
else
{
rwl->nMagic = 0;
if ((result =
pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
pthread_mutex_unlock (&rwl->mtxExclusiveAccess);
return result;
}
if ((result =
pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))) != 0)
return result;
*rwlock = NULL; /* Invalidate rwlock before anything else */
result = pthread_cond_destroy (&(rwl->cndSharedAccessCompleted));
result1 = pthread_mutex_destroy (&(rwl->mtxSharedAccessCompleted));
result2 = pthread_mutex_destroy (&(rwl->mtxExclusiveAccess));
(void) free (rwl);
}
}
else
{
/*
* See notes in pte_rwlock_check_need_init() above also.
*/
pte_osMutexLock (pte_rwlock_test_init_lock);
/*
* Check again.
*/
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
{
/*
* This is all we need to do to destroy a statically
* initialised rwlock that has not yet been used (initialised).
* If we get to here, another thread
* waiting to initialise this rwlock will get an EINVAL.
*/
*rwlock = NULL;
}
/*
* The rwlock has been initialised while we were waiting
* so assume it's in use.
*/
else
result = EBUSY;
pte_osMutexUnlock(pte_rwlock_test_init_lock);
}
return ((result != 0) ? result : ((result1 != 0) ? result1 : result2));
}
int pthread_rwlock_init (pthread_rwlock_t * rwlock,
const pthread_rwlockattr_t * attr)
{
int result;
pthread_rwlock_t rwl = 0;
if (rwlock == NULL)
return EINVAL;
if (attr != NULL && *attr != NULL)
{
result = EINVAL; /* Not supported */
goto DONE;
}
rwl = (pthread_rwlock_t) calloc (1, sizeof (*rwl));
if (rwl == NULL)
{
result = ENOMEM;
goto DONE;
}
rwl->nSharedAccessCount = 0;
rwl->nExclusiveAccessCount = 0;
rwl->nCompletedSharedAccessCount = 0;
result = pthread_mutex_init (&rwl->mtxExclusiveAccess, NULL);
if (result != 0)
{
goto FAIL0;
}
result = pthread_mutex_init (&rwl->mtxSharedAccessCompleted, NULL);
if (result != 0)
{
goto FAIL1;
}
result = pthread_cond_init (&rwl->cndSharedAccessCompleted, NULL);
if (result != 0)
{
goto FAIL2;
}
rwl->nMagic = PTE_RWLOCK_MAGIC;
result = 0;
goto DONE;
FAIL2:
(void) pthread_mutex_destroy (&(rwl->mtxSharedAccessCompleted));
FAIL1:
(void) pthread_mutex_destroy (&(rwl->mtxExclusiveAccess));
FAIL0:
(void) free (rwl);
rwl = NULL;
DONE:
*rwlock = rwl;
return result;
}
int pthread_rwlock_rdlock (pthread_rwlock_t * rwlock)
{
int result;
pthread_rwlock_t rwl;
if (rwlock == NULL || *rwlock == NULL)
return EINVAL;
/*
* We do a quick check to see if we need to do more work
* to initialise a static rwlock. We check
* again inside the guarded section of pte_rwlock_check_need_init()
* to avoid race conditions.
*/
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
{
result = pte_rwlock_check_need_init (rwlock);
if (result != 0 && result != EBUSY)
return result;
}
rwl = *rwlock;
if (rwl->nMagic != PTE_RWLOCK_MAGIC)
return EINVAL;
if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0)
return result;
if (++rwl->nSharedAccessCount == INT_MAX)
{
if ((result =
pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount;
rwl->nCompletedSharedAccessCount = 0;
if ((result =
pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
}
return (pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)));
}
int pthread_rwlock_timedrdlock (pthread_rwlock_t * rwlock,
const struct timespec *abstime)
{
int result;
pthread_rwlock_t rwl;
if (rwlock == NULL || *rwlock == NULL)
return EINVAL;
/*
* We do a quick check to see if we need to do more work
* to initialise a static rwlock. We check
* again inside the guarded section of pte_rwlock_check_need_init()
* to avoid race conditions.
*/
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
{
result = pte_rwlock_check_need_init (rwlock);
if (result != 0 && result != EBUSY)
{
return result;
}
}
rwl = *rwlock;
if (rwl->nMagic != PTE_RWLOCK_MAGIC)
{
return EINVAL;
}
if ((result =
pthread_mutex_timedlock (&(rwl->mtxExclusiveAccess), abstime)) != 0)
{
return result;
}
if (++rwl->nSharedAccessCount == INT_MAX)
{
if ((result =
pthread_mutex_timedlock (&(rwl->mtxSharedAccessCompleted),
abstime)) != 0)
{
if (result == ETIMEDOUT)
{
++rwl->nCompletedSharedAccessCount;
}
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount;
rwl->nCompletedSharedAccessCount = 0;
if ((result =
pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
}
return (pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)));
}
int pthread_rwlock_timedwrlock (pthread_rwlock_t * rwlock,
const struct timespec *abstime)
{
int result;
pthread_rwlock_t rwl;
if (rwlock == NULL || *rwlock == NULL)
return EINVAL;
/*
* We do a quick check to see if we need to do more work
* to initialise a static rwlock. We check
* again inside the guarded section of pte_rwlock_check_need_init()
* to avoid race conditions.
*/
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
{
result = pte_rwlock_check_need_init (rwlock);
if (result != 0 && result != EBUSY)
{
return result;
}
}
rwl = *rwlock;
if (rwl->nMagic != PTE_RWLOCK_MAGIC)
{
return EINVAL;
}
if ((result =
pthread_mutex_timedlock (&(rwl->mtxExclusiveAccess), abstime)) != 0)
{
return result;
}
if ((result =
pthread_mutex_timedlock (&(rwl->mtxSharedAccessCompleted),
abstime)) != 0)
{
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
if (rwl->nExclusiveAccessCount == 0)
{
if (rwl->nCompletedSharedAccessCount > 0)
{
rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount;
rwl->nCompletedSharedAccessCount = 0;
}
if (rwl->nSharedAccessCount > 0)
{
rwl->nCompletedSharedAccessCount = -rwl->nSharedAccessCount;
/*
* This routine may be a cancelation point
* according to POSIX 1003.1j section 18.1.2.
*/
pthread_cleanup_push (pte_rwlock_cancelwrwait, (void *) rwl);
do
{
result =
pthread_cond_timedwait (&(rwl->cndSharedAccessCompleted),
&(rwl->mtxSharedAccessCompleted),
abstime);
}
while (result == 0 && rwl->nCompletedSharedAccessCount < 0);
pthread_cleanup_pop ((result != 0) ? 1 : 0);
if (result == 0)
{
rwl->nSharedAccessCount = 0;
}
}
}
if (result == 0)
rwl->nExclusiveAccessCount++;
return result;
}
int pthread_rwlock_tryrdlock (pthread_rwlock_t * rwlock)
{
int result;
pthread_rwlock_t rwl;
if (rwlock == NULL || *rwlock == NULL)
return EINVAL;
/*
* We do a quick check to see if we need to do more work
* to initialise a static rwlock. We check
* again inside the guarded section of pte_rwlock_check_need_init()
* to avoid race conditions.
*/
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
{
result = pte_rwlock_check_need_init (rwlock);
if (result != 0 && result != EBUSY)
{
return result;
}
}
rwl = *rwlock;
if (rwl->nMagic != PTE_RWLOCK_MAGIC)
{
return EINVAL;
}
if ((result = pthread_mutex_trylock (&(rwl->mtxExclusiveAccess))) != 0)
{
return result;
}
if (++rwl->nSharedAccessCount == INT_MAX)
{
if ((result =
pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount;
rwl->nCompletedSharedAccessCount = 0;
if ((result =
pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
}
return (pthread_mutex_unlock (&rwl->mtxExclusiveAccess));
}
int pthread_rwlock_trywrlock (pthread_rwlock_t * rwlock)
{
int result, result1;
pthread_rwlock_t rwl;
if (rwlock == NULL || *rwlock == NULL)
return EINVAL;
/*
* We do a quick check to see if we need to do more work
* to initialise a static rwlock. We check
* again inside the guarded section of pte_rwlock_check_need_init()
* to avoid race conditions.
*/
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
{
result = pte_rwlock_check_need_init (rwlock);
if (result != 0 && result != EBUSY)
{
return result;
}
}
rwl = *rwlock;
if (rwl->nMagic != PTE_RWLOCK_MAGIC)
{
return EINVAL;
}
if ((result = pthread_mutex_trylock (&(rwl->mtxExclusiveAccess))) != 0)
{
return result;
}
if ((result =
pthread_mutex_trylock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return ((result1 != 0) ? result1 : result);
}
if (rwl->nExclusiveAccessCount == 0)
{
if (rwl->nCompletedSharedAccessCount > 0)
{
rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount;
rwl->nCompletedSharedAccessCount = 0;
}
if (rwl->nSharedAccessCount > 0)
{
if ((result =
pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
if ((result =
pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))) == 0)
{
result = EBUSY;
}
}
else
{
rwl->nExclusiveAccessCount = 1;
}
}
else
{
result = EBUSY;
}
return result;
}
int pthread_rwlock_unlock (pthread_rwlock_t * rwlock)
{
int result, result1;
pthread_rwlock_t rwl;
if (rwlock == NULL || *rwlock == NULL)
return (EINVAL);
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
{
/*
* Assume any race condition here is harmless.
*/
return 0;
}
rwl = *rwlock;
if (rwl->nMagic != PTE_RWLOCK_MAGIC)
{
return EINVAL;
}
if (rwl->nExclusiveAccessCount == 0)
{
if ((result =
pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
return result;
}
if (++rwl->nCompletedSharedAccessCount == 0)
{
result = pthread_cond_signal (&(rwl->cndSharedAccessCompleted));
}
result1 = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted));
}
else
{
rwl->nExclusiveAccessCount--;
result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted));
result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
}
return ((result != 0) ? result : result1);
}
int pthread_rwlock_wrlock (pthread_rwlock_t * rwlock)
{
int result;
pthread_rwlock_t rwl;
if (rwlock == NULL || *rwlock == NULL)
return EINVAL;
/*
* We do a quick check to see if we need to do more work
* to initialise a static rwlock. We check
* again inside the guarded section of pte_rwlock_check_need_init()
* to avoid race conditions.
*/
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
{
result = pte_rwlock_check_need_init (rwlock);
if (result != 0 && result != EBUSY)
return result;
}
rwl = *rwlock;
if (rwl->nMagic != PTE_RWLOCK_MAGIC)
return EINVAL;
if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0)
return result;
if ((result = pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
if (rwl->nExclusiveAccessCount == 0)
{
if (rwl->nCompletedSharedAccessCount > 0)
{
rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount;
rwl->nCompletedSharedAccessCount = 0;
}
if (rwl->nSharedAccessCount > 0)
{
rwl->nCompletedSharedAccessCount = -rwl->nSharedAccessCount;
/*
* This routine may be a cancelation point
* according to POSIX 1003.1j section 18.1.2.
*/
pthread_cleanup_push (pte_rwlock_cancelwrwait, (void *) rwl);
do
{
result = pthread_cond_wait (&(rwl->cndSharedAccessCompleted),
&(rwl->mtxSharedAccessCompleted));
}
while (result == 0 && rwl->nCompletedSharedAccessCount < 0);
pthread_cleanup_pop ((result != 0) ? 1 : 0);
if (result == 0)
rwl->nSharedAccessCount = 0;
}
}
if (result == 0)
rwl->nExclusiveAccessCount++;
return result;
}

View File

@ -1,259 +0,0 @@
/*
* pthread_rwlockattr_destroy.c
*
* Description:
* This translation unit implements read/write lock primitives.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include "pthread.h"
#include "implement.h"
int
pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Destroys a rwlock attributes object. The object can
* no longer be used.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_rwlockattr_t
*
*
* DESCRIPTION
* Destroys a rwlock attributes object. The object can
* no longer be used.
*
* NOTES:
* 1) Does not affect rwlockss created using 'attr'
*
* RESULTS
* 0 successfully released attr,
* EINVAL 'attr' is invalid.
*
* ------------------------------------------------------
*/
{
int result = 0;
if (attr == NULL || *attr == NULL)
{
result = EINVAL;
}
else
{
pthread_rwlockattr_t rwa = *attr;
*attr = NULL;
free (rwa);
}
return (result);
}
int
pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr,
int *pshared)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Determine whether rwlocks created with 'attr' can be
* shared between processes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_rwlockattr_t
*
* pshared
* will be set to one of:
*
* PTHREAD_PROCESS_SHARED
* May be shared if in shared memory
*
* PTHREAD_PROCESS_PRIVATE
* Cannot be shared.
*
*
* DESCRIPTION
* Rwlocks creatd with 'attr' can be shared between
* processes if pthread_rwlock_t variable is allocated
* in memory shared by these processes.
* NOTES:
* 1) pshared rwlocks MUST be allocated in shared
* memory.
* 2) The following macro is defined if shared rwlocks
* are supported:
* _POSIX_THREAD_PROCESS_SHARED
*
* RESULTS
* 0 successfully retrieved attribute,
* EINVAL 'attr' is invalid,
*
* ------------------------------------------------------
*/
{
int result;
if ((attr != NULL && *attr != NULL) && (pshared != NULL))
{
*pshared = (*attr)->pshared;
result = 0;
}
else
result = EINVAL;
return (result);
}
int pthread_rwlockattr_init (pthread_rwlockattr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Initializes a rwlock attributes object with default
* attributes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_rwlockattr_t
*
*
* DESCRIPTION
* Initializes a rwlock attributes object with default
* attributes.
*
* RESULTS
* 0 successfully initialized attr,
* ENOMEM insufficient memory for attr.
*
* ------------------------------------------------------
*/
{
int result = 0;
pthread_rwlockattr_t rwa;
rwa = (pthread_rwlockattr_t) calloc (1, sizeof (*rwa));
if (rwa == NULL)
result = ENOMEM;
else
rwa->pshared = PTHREAD_PROCESS_PRIVATE;
*attr = rwa;
return (result);
}
int pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, int pshared)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Rwlocks created with 'attr' can be shared between
* processes if pthread_rwlock_t variable is allocated
* in memory shared by these processes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_rwlockattr_t
*
* pshared
* must be one of:
*
* PTHREAD_PROCESS_SHARED
* May be shared if in shared memory
*
* PTHREAD_PROCESS_PRIVATE
* Cannot be shared.
*
* DESCRIPTION
* Rwlocks creatd with 'attr' can be shared between
* processes if pthread_rwlock_t variable is allocated
* in memory shared by these processes.
*
* NOTES:
* 1) pshared rwlocks MUST be allocated in shared
* memory.
*
* 2) The following macro is defined if shared rwlocks
* are supported:
* _POSIX_THREAD_PROCESS_SHARED
*
* RESULTS
* 0 successfully set attribute,
* EINVAL 'attr' or pshared is invalid,
* ENOSYS PTHREAD_PROCESS_SHARED not supported,
*
* ------------------------------------------------------
*/
{
int result;
if ((attr != NULL && *attr != NULL) &&
((pshared == PTHREAD_PROCESS_SHARED) ||
(pshared == PTHREAD_PROCESS_PRIVATE)))
{
if (pshared == PTHREAD_PROCESS_SHARED)
{
#if !defined( _POSIX_THREAD_PROCESS_SHARED )
result = ENOSYS;
pshared = PTHREAD_PROCESS_PRIVATE;
#else
result = 0;
#endif /* _POSIX_THREAD_PROCESS_SHARED */
}
else
result = 0;
(*attr)->pshared = pshared;
}
else
result = EINVAL;
return (result);
} /* pthread_rwlockattr_setpshared */

View File

@ -1,399 +0,0 @@
/*
* pthread_set.c
*
* Description:
* POSIX thread functions related to state.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include "pthread.h"
#include "implement.h"
#include "sched.h"
int pthread_setcancelstate (int state, int *oldstate)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function atomically sets the calling thread's
* cancelability state to 'state' and returns the previous
* cancelability state at the location referenced by
* 'oldstate'
*
* PARAMETERS
* state,
* oldstate
* PTHREAD_CANCEL_ENABLE
* cancellation is enabled,
*
* PTHREAD_CANCEL_DISABLE
* cancellation is disabled
*
*
* DESCRIPTION
* This function atomically sets the calling thread's
* cancelability state to 'state' and returns the previous
* cancelability state at the location referenced by
* 'oldstate'.
*
* NOTES:
* 1) Use to disable cancellation around 'atomic' code that
* includes cancellation points
*
* COMPATIBILITY ADDITIONS
* If 'oldstate' is NULL then the previous state is not returned
* but the function still succeeds. (Solaris)
*
* RESULTS
* 0 successfully set cancelability type,
* EINVAL 'state' is invalid
*
* ------------------------------------------------------
*/
{
int result = 0;
pthread_t self = pthread_self ();
pte_thread_t * sp = (pte_thread_t *) self;
if (sp == NULL
|| (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE))
return EINVAL;
/*
* Lock for async-cancel safety.
*/
(void) pthread_mutex_lock (&sp->cancelLock);
if (oldstate != NULL)
*oldstate = sp->cancelState;
sp->cancelState = state;
/*
* Check if there is a pending asynchronous cancel
*/
if (state == PTHREAD_CANCEL_ENABLE
&& (sp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS)
&& (pte_osThreadCheckCancel(sp->threadId) == PTE_OS_INTERRUPTED) )
{
sp->state = PThreadStateCanceling;
sp->cancelState = PTHREAD_CANCEL_DISABLE;
(void) pthread_mutex_unlock (&sp->cancelLock);
pte_throw (PTE_EPS_CANCEL);
/* Never reached */
}
(void) pthread_mutex_unlock (&sp->cancelLock);
return (result);
}
int pthread_setcanceltype (int type, int *oldtype)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function atomically sets the calling thread's
* cancelability type to 'type' and returns the previous
* cancelability type at the location referenced by
* 'oldtype'
*
* PARAMETERS
* type,
* oldtype
* PTHREAD_CANCEL_DEFERRED
* only deferred cancelation is allowed,
*
* PTHREAD_CANCEL_ASYNCHRONOUS
* Asynchronous cancellation is allowed
*
*
* DESCRIPTION
* This function atomically sets the calling thread's
* cancelability type to 'type' and returns the previous
* cancelability type at the location referenced by
* 'oldtype'
*
* NOTES:
* 1) Use with caution; most code is not safe for use
* with asynchronous cancelability.
*
* COMPATIBILITY ADDITIONS
* If 'oldtype' is NULL then the previous type is not returned
* but the function still succeeds. (Solaris)
*
* RESULTS
* 0 successfully set cancelability type,
* EINVAL 'type' is invalid
* EPERM Async cancellation is not supported.
*
* ------------------------------------------------------
*/
{
int result = 0;
pthread_t self = pthread_self ();
pte_thread_t * sp = (pte_thread_t *) self;
#ifndef PTE_SUPPORT_ASYNC_CANCEL
if (type == PTHREAD_CANCEL_ASYNCHRONOUS)
{
/* Async cancellation is not supported at this time. See notes in
* pthread_cancel.
*/
return EPERM;
}
#endif /* PTE_SUPPORT_ASYNC_CANCEL */
if (sp == NULL
|| (type != PTHREAD_CANCEL_DEFERRED
&& type != PTHREAD_CANCEL_ASYNCHRONOUS))
return EINVAL;
/*
* Lock for async-cancel safety.
*/
(void) pthread_mutex_lock (&sp->cancelLock);
if (oldtype != NULL)
*oldtype = sp->cancelType;
sp->cancelType = type;
/*
* Check if there is a pending asynchronous cancel
*/
if (sp->cancelState == PTHREAD_CANCEL_ENABLE
&& (type == PTHREAD_CANCEL_ASYNCHRONOUS)
&& (pte_osThreadCheckCancel(sp->threadId) == PTE_OS_INTERRUPTED) )
{
sp->state = PThreadStateCanceling;
sp->cancelState = PTHREAD_CANCEL_DISABLE;
(void) pthread_mutex_unlock (&sp->cancelLock);
pte_throw (PTE_EPS_CANCEL);
/* Never reached */
}
(void) pthread_mutex_unlock (&sp->cancelLock);
return (result);
}
int pthread_setconcurrency (int level)
{
if (level < 0)
return EINVAL;
pte_concurrency = level;
return 0;
}
int pthread_setschedparam (pthread_t thread, int policy,
const struct sched_param *param)
{
int result;
/* Validate the thread id. */
result = pthread_kill (thread, 0);
if (0 != result)
return result;
/* Validate the scheduling policy. */
if (policy < SCHED_MIN || policy > SCHED_MAX)
return EINVAL;
/* Ensure the policy is SCHED_OTHER. */
if (policy != SCHED_OTHER)
return ENOTSUP;
return (pte_setthreadpriority (thread, policy, param->sched_priority));
}
int
pte_setthreadpriority (pthread_t thread, int policy, int priority)
{
int prio;
int result;
pte_thread_t * tp = (pte_thread_t *) thread;
prio = priority;
/* Validate priority level. */
if (prio < sched_get_priority_min (policy) ||
prio > sched_get_priority_max (policy))
return EINVAL;
result = pthread_mutex_lock (&tp->threadLock);
if (0 == result)
{
/* If this fails, the current priority is unchanged. */
if (0 != pte_osThreadSetPriority(tp->threadId, prio))
result = EINVAL;
else
{
/*
* Must record the thread's sched_priority as given,
* not as finally adjusted.
*/
tp->sched_priority = priority;
}
(void) pthread_mutex_unlock (&tp->threadLock);
}
return result;
}
int pthread_setspecific (pthread_key_t key, const void *value)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function sets the value of the thread specific
* key in the calling thread.
*
* PARAMETERS
* key
* an instance of pthread_key_t
* value
* the value to set key to
*
*
* DESCRIPTION
* This function sets the value of the thread specific
* key in the calling thread.
*
* RESULTS
* 0 successfully set value
* EAGAIN could not set value
* ENOENT SERIOUS!!
*
* ------------------------------------------------------
*/
{
pthread_t self;
int result = 0;
if (key != pte_selfThreadKey)
{
/*
* Using pthread_self will implicitly create
* an instance of pthread_t for the current
* thread if one wasn't explicitly created
*/
self = pthread_self ();
if (self == NULL)
return ENOENT;
}
else
{
/*
* Resolve catch-22 of registering thread with selfThread
* key
*/
pte_thread_t * sp = (pte_thread_t *) pthread_getspecific (pte_selfThreadKey);
if (sp == NULL)
{
if (value == NULL)
return ENOENT;
self = *((pthread_t *) value);
}
else
self = sp;
}
result = 0;
if (key != NULL)
{
if (self != NULL && key->destructor != NULL && value != NULL)
{
/*
* Only require associations if we have to
* call user destroy routine.
* Don't need to locate an existing association
* when setting data to NULL since the
* data is stored with the operating system; not
* on the association; setting assoc to NULL short
* circuits the search.
*/
ThreadKeyAssoc *assoc;
if (pthread_mutex_lock(&(key->keyLock)) == 0)
{
pte_thread_t * sp = (pte_thread_t *) self;
(void) pthread_mutex_lock(&(sp->threadLock));
assoc = (ThreadKeyAssoc *) sp->keys;
/*
* Locate existing association
*/
while (assoc != NULL)
{
/*
* Association already exists
*/
if (assoc->key == key)
break;
assoc = assoc->nextKey;
}
/*
* create an association if not found
*/
if (assoc == NULL)
result = pte_tkAssocCreate (sp, key);
(void) pthread_mutex_unlock(&(sp->threadLock));
}
(void) pthread_mutex_unlock(&(key->keyLock));
}
if (result == 0)
{
if (pte_osTlsSetValue (key->key, (void *) value) != PTE_OS_OK)
result = EAGAIN;
}
}
return (result);
}

View File

@ -1,295 +0,0 @@
/*
* pthread_spin.c
*
* Description:
* This translation unit implements spin lock primitives.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include "pthread.h"
#include "implement.h"
int
pthread_spin_destroy (pthread_spinlock_t * lock)
{
register pthread_spinlock_t s;
int result = 0;
if (lock == NULL || *lock == NULL)
{
return EINVAL;
}
if ((s = *lock) != PTHREAD_SPINLOCK_INITIALIZER)
{
if (s->interlock == PTE_SPIN_USE_MUTEX)
{
result = pthread_mutex_destroy (&(s->u.mutex));
}
else if (PTE_SPIN_UNLOCKED !=
PTE_ATOMIC_COMPARE_EXCHANGE (
& (s->interlock),
(int) PTE_OBJECT_INVALID,
PTE_SPIN_UNLOCKED))
{
result = EINVAL;
}
if (0 == result)
{
/*
* We are relying on the application to ensure that all other threads
* have finished with the spinlock before destroying it.
*/
*lock = NULL;
(void) free (s);
}
}
else
{
/*
* See notes in pte_spinlock_check_need_init() above also.
*/
pte_osMutexLock (pte_spinlock_test_init_lock);
/*
* Check again.
*/
if (*lock == PTHREAD_SPINLOCK_INITIALIZER)
{
/*
* This is all we need to do to destroy a statically
* initialised spinlock that has not yet been used (initialised).
* If we get to here, another thread
* waiting to initialise this mutex will get an EINVAL.
*/
*lock = NULL;
}
else
{
/*
* The spinlock has been initialised while we were waiting
* so assume it's in use.
*/
result = EBUSY;
}
pte_osMutexUnlock(pte_spinlock_test_init_lock);
}
return (result);
}
int pthread_spin_init (pthread_spinlock_t * lock, int pshared)
{
pthread_spinlock_t s;
int cpus = 0;
int result = 0;
if (lock == NULL)
return EINVAL;
if (0 != pte_getprocessors (&cpus))
{
cpus = 1;
}
if (cpus > 1)
{
if (pshared == PTHREAD_PROCESS_SHARED)
{
/*
* Creating spinlock that can be shared between
* processes.
*/
#if _POSIX_THREAD_PROCESS_SHARED >= 0
/*
* Not implemented yet.
*/
#error ERROR [__FILE__, line __LINE__]: Process shared spin locks are not supported yet.
#else
return ENOSYS;
#endif /* _POSIX_THREAD_PROCESS_SHARED */
}
}
s = (pthread_spinlock_t) calloc (1, sizeof (*s));
if (s == NULL)
{
return ENOMEM;
}
if (cpus > 1)
{
s->u.cpus = cpus;
s->interlock = PTE_SPIN_UNLOCKED;
}
else
{
pthread_mutexattr_t ma;
result = pthread_mutexattr_init (&ma);
if (0 == result)
{
ma->pshared = pshared;
result = pthread_mutex_init (&(s->u.mutex), &ma);
if (0 == result)
{
s->interlock = PTE_SPIN_USE_MUTEX;
}
}
(void) pthread_mutexattr_destroy (&ma);
}
if (0 == result)
{
*lock = s;
}
else
{
(void) free (s);
*lock = NULL;
}
return (result);
}
int pthread_spin_lock (pthread_spinlock_t * lock)
{
register pthread_spinlock_t s;
if (NULL == lock || NULL == *lock)
return (EINVAL);
if (*lock == PTHREAD_SPINLOCK_INITIALIZER)
{
int result;
if ((result = pte_spinlock_check_need_init (lock)) != 0)
return (result);
}
s = *lock;
while ( PTE_SPIN_LOCKED ==
PTE_ATOMIC_COMPARE_EXCHANGE (&(s->interlock),
PTE_SPIN_LOCKED,
PTE_SPIN_UNLOCKED))
{
}
if (s->interlock == PTE_SPIN_LOCKED)
return 0;
if (s->interlock == PTE_SPIN_USE_MUTEX)
return pthread_mutex_lock (&(s->u.mutex));
return EINVAL;
}
int pthread_spin_trylock (pthread_spinlock_t * lock)
{
register pthread_spinlock_t s;
if (NULL == lock || NULL == *lock)
return (EINVAL);
if (*lock == PTHREAD_SPINLOCK_INITIALIZER)
{
int result;
if ((result = pte_spinlock_check_need_init (lock)) != 0)
return (result);
}
s = *lock;
switch ((long)
PTE_ATOMIC_COMPARE_EXCHANGE (&(s->interlock),
PTE_SPIN_LOCKED,
PTE_SPIN_UNLOCKED))
{
case PTE_SPIN_UNLOCKED:
return 0;
case PTE_SPIN_LOCKED:
return EBUSY;
case PTE_SPIN_USE_MUTEX:
return pthread_mutex_trylock (&(s->u.mutex));
}
return EINVAL;
}
int pthread_spin_unlock (pthread_spinlock_t * lock)
{
register pthread_spinlock_t s;
if (NULL == lock || NULL == *lock)
return (EINVAL);
s = *lock;
if (s == PTHREAD_SPINLOCK_INITIALIZER)
return EPERM;
switch ((long)
PTE_ATOMIC_COMPARE_EXCHANGE (&(s->interlock),
PTE_SPIN_UNLOCKED,
PTE_SPIN_LOCKED))
{
case PTE_SPIN_LOCKED:
return 0;
case PTE_SPIN_UNLOCKED:
return EPERM;
case PTE_SPIN_USE_MUTEX:
return pthread_mutex_unlock (&(s->u.mutex));
}
return EINVAL;
}

101
deps/pthreads/sched.c vendored
View File

@ -1,101 +0,0 @@
/*
* sched_setscheduler.c
*
* Description:
* POSIX thread functions that deal with thread scheduling.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include "pte_osal.h"
#include "pthread.h"
#include "implement.h"
#include "sched.h"
int
sched_setscheduler (pid_t pid, int policy)
{
errno = EPERM;
return -1;
}
int
sched_yield (void)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function indicates that the calling thread is
* willing to give up some time slices to other threads.
*
* PARAMETERS
* N/A
*
*
* DESCRIPTION
* This function indicates that the calling thread is
* willing to give up some time slices to other threads.
* NOTE: Since this is part of POSIX 1003.1b
* (realtime extensions), it is defined as returning
* -1 if an error occurs and sets errno to the actual
* error.
*
* RESULTS
* 0 successfully created semaphore,
* ENOSYS sched_yield not supported,
*
* ------------------------------------------------------
*/
{
pte_osThreadSleep (1);
return 0;
}
int
sched_get_priority_min (int policy)
{
return pte_osThreadGetMinPriority();
}
int
sched_get_priority_max (int policy)
{
return pte_osThreadGetMaxPriority();
}

137
deps/pthreads/sched.h vendored
View File

@ -1,137 +0,0 @@
/*
* Module: sched.h
*
* Purpose:
* Provides an implementation of POSIX realtime extensions
* as defined in
*
* POSIX 1003.1b-1993 (POSIX.1b)
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef _SCHED_H
#define _SCHED_H
#include <pte_types.h>
#undef PTE_LEVEL
#if defined(_POSIX_SOURCE)
#define PTE_LEVEL 0
/* Early POSIX */
#endif
#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309
#undef PTE_LEVEL
#define PTE_LEVEL 1
/* Include 1b, 1c and 1d */
#endif
#if defined(INCLUDE_NP)
#undef PTE_LEVEL
#define PTE_LEVEL 2
/* Include Non-Portable extensions */
#endif
#define PTE_LEVEL_MAX 3
#if !defined(PTE_LEVEL)
#define PTE_LEVEL PTE_LEVEL_MAX
/* Include everything */
#endif
/*
*
*/
/* Thread scheduling policies */
enum
{
SCHED_OTHER = 0,
SCHED_FIFO,
SCHED_RR,
SCHED_MIN = SCHED_OTHER,
SCHED_MAX = SCHED_RR
};
struct sched_param
{
int sched_priority;
};
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
int sched_yield (void);
int sched_get_priority_min (int policy);
int sched_get_priority_max (int policy);
int sched_setscheduler (pid_t pid, int policy);
/*
* Note that this macro returns ENOTSUP rather than
* ENOSYS as might be expected. However, returning ENOSYS
* should mean that sched_get_priority_{min,max} are
* not implemented as well as sched_rr_get_interval.
* This is not the case, since we just don't support
* round-robin scheduling. Therefore I have chosen to
* return the same value as sched_setscheduler when
* SCHED_RR is passed to it.
*/
#define sched_rr_get_interval(_pid, _interval) \
( errno = ENOTSUP, (int) -1 )
#ifdef __cplusplus
} /* End of extern "C" */
#endif /* __cplusplus */
#undef PTE_LEVEL
#undef PTE_LEVEL_MAX
#endif /* !_SCHED_H */

895
deps/pthreads/sem.c vendored
View File

@ -1,895 +0,0 @@
/*
* -------------------------------------------------------------
*
* Module: sem.c
*
* Purpose:
* Semaphores aren't actually part of the PThreads standard.
* They are defined by the POSIX Standard:
*
* POSIX 1003.1b-1993 (POSIX.1b)
*
* -------------------------------------------------------------
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include "pte_osal.h"
#include "pthread.h"
#include "semaphore.h"
#include "implement.h"
typedef struct
{
sem_t sem;
int * resultPtr;
} sem_timedwait_cleanup_args_t;
static void pte_sem_wait_cleanup(void * sem)
{
sem_t s = (sem_t) sem;
unsigned int timeout;
if (pthread_mutex_lock (&s->lock) == 0)
{
/*
* If sema is destroyed do nothing, otherwise:-
* If the sema is posted between us being cancelled and us locking
* the sema again above then we need to consume that post but cancel
* anyway. If we don't get the semaphore we indicate that we're no
* longer waiting.
*/
timeout = 0;
if (pte_osSemaphorePend(s->sem, &timeout) != PTE_OS_OK)
{
++s->value;
/*
* Don't release the W32 sema, it doesn't need adjustment
* because it doesn't record the number of waiters.
*/
}
(void) pthread_mutex_unlock (&s->lock);
}
}
static void pte_sem_timedwait_cleanup (void * args)
{
sem_timedwait_cleanup_args_t * a = (sem_timedwait_cleanup_args_t *)args;
sem_t s = a->sem;
if (pthread_mutex_lock (&s->lock) == 0)
{
/*
* We either timed out or were cancelled.
* If someone has posted between then and now we try to take the semaphore.
* Otherwise the semaphore count may be wrong after we
* return. In the case of a cancellation, it is as if we
* were cancelled just before we return (after taking the semaphore)
* which is ok.
*/
unsigned int timeout = 0;
if (pte_osSemaphorePend(s->sem, &timeout) == PTE_OS_OK)
{
/* We got the semaphore on the second attempt */
*(a->resultPtr) = 0;
}
else
{
/* Indicate we're no longer waiting */
s->value++;
/*
* Don't release the OS sema, it doesn't need adjustment
* because it doesn't record the number of waiters.
*/
}
(void) pthread_mutex_unlock (&s->lock);
}
}
int sem_close (sem_t * sem)
{
errno = ENOSYS;
return -1;
}
int sem_destroy (sem_t * sem)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function destroys an unnamed semaphore.
*
* PARAMETERS
* sem
* pointer to an instance of sem_t
*
* DESCRIPTION
* This function destroys an unnamed semaphore.
*
* RESULTS
* 0 successfully destroyed semaphore,
* -1 failed, error in errno
* ERRNO
* EINVAL 'sem' is not a valid semaphore,
* ENOSYS semaphores are not supported,
* EBUSY threads (or processes) are currently
* blocked on 'sem'
*
* ------------------------------------------------------
*/
{
int result = 0;
sem_t s = NULL;
if (sem == NULL || *sem == NULL)
result = EINVAL;
else
{
s = *sem;
if ((result = pthread_mutex_lock (&s->lock)) == 0)
{
if (s->value < 0)
{
(void) pthread_mutex_unlock (&s->lock);
result = EBUSY;
}
else
{
/* There are no threads currently blocked on this semaphore. */
pte_osResult osResult = pte_osSemaphoreDelete(s->sem);
if (osResult != PTE_OS_OK)
{
(void) pthread_mutex_unlock (&s->lock);
result = EINVAL;
}
else
{
/*
* Invalidate the semaphore handle when we have the lock.
* Other sema operations should test this after acquiring the lock
* to check that the sema is still valid, i.e. before performing any
* operations. This may only be necessary before the sema op routine
* returns so that the routine can return EINVAL - e.g. if setting
* s->value to SEM_VALUE_MAX below does force a fall-through.
*/
*sem = NULL;
/* Prevent anyone else actually waiting on or posting this sema.
*/
s->value = SEM_VALUE_MAX;
(void) pthread_mutex_unlock (&s->lock);
do
{
/* Give other threads a chance to run and exit any sema op
* routines. Due to the SEM_VALUE_MAX value, if sem_post or
* sem_wait were blocked by us they should fall through.
*/
pte_osThreadSleep(1);
}
while (pthread_mutex_destroy (&s->lock) == EBUSY);
}
}
}
}
if (result != 0)
{
errno = result;
return -1;
}
free (s);
return 0;
}
int
sem_getvalue (sem_t * sem, int *sval)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function stores the current count value of the
* semaphore.
* RESULTS
*
* Return value
*
* 0 sval has been set.
* -1 failed, error in errno
*
* in global errno
*
* EINVAL 'sem' is not a valid semaphore,
* ENOSYS this function is not supported,
*
*
* PARAMETERS
*
* sem pointer to an instance of sem_t
*
* sval pointer to int.
*
* DESCRIPTION
* This function stores the current count value of the semaphore
* pointed to by sem in the int pointed to by sval.
*/
{
if (sem == NULL || *sem == NULL || sval == NULL)
{
errno = EINVAL;
return -1;
}
else
{
long value;
register sem_t s = *sem;
int result = 0;
if ((result = pthread_mutex_lock(&s->lock)) == 0)
{
if (*sem == NULL)
{
(void) pthread_mutex_unlock (&s->lock);
errno = EINVAL;
return -1;
}
value = s->value;
(void) pthread_mutex_unlock(&s->lock);
*sval = value;
}
return result;
}
}
int
sem_init (sem_t * sem, int pshared, unsigned int value)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function initializes a semaphore. The
* initial value of the semaphore is 'value'
*
* PARAMETERS
* sem
* pointer to an instance of sem_t
*
* pshared
* if zero, this semaphore may only be shared between
* threads in the same process.
* if nonzero, the semaphore can be shared between
* processes
*
* value
* initial value of the semaphore counter
*
* DESCRIPTION
* This function initializes a semaphore. The
* initial value of the semaphore is set to 'value'.
*
* RESULTS
* 0 successfully created semaphore,
* -1 failed, error in errno
* ERRNO
* EINVAL 'sem' is not a valid semaphore, or
* 'value' >= SEM_VALUE_MAX
* ENOMEM out of memory,
* ENOSPC a required resource has been exhausted,
* ENOSYS semaphores are not supported,
* EPERM the process lacks appropriate privilege
*
* ------------------------------------------------------
*/
{
int result = 0;
sem_t s = NULL;
if (pshared != 0)
{
/*
* Creating a semaphore that can be shared between
* processes
*/
result = EPERM;
}
else if (value > (unsigned int)SEM_VALUE_MAX)
{
result = EINVAL;
}
else
{
s = (sem_t) calloc (1, sizeof (*s));
if (NULL == s)
{
result = ENOMEM;
}
else
{
s->value = value;
if (pthread_mutex_init(&s->lock, NULL) == 0)
{
pte_osResult osResult = pte_osSemaphoreCreate(0, &s->sem);
if (osResult != PTE_OS_OK)
{
(void) pthread_mutex_destroy(&s->lock);
result = ENOSPC;
}
}
else
{
result = ENOSPC;
}
if (result != 0)
{
free(s);
}
}
}
if (result != 0)
{
errno = result;
return -1;
}
*sem = s;
return 0;
}
int sem_open (const char *name, int oflag, mode_t mode, unsigned int value)
{
errno = ENOSYS;
return -1;
}
int
sem_post (sem_t * sem)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function posts a wakeup to a semaphore.
*
* PARAMETERS
* sem
* pointer to an instance of sem_t
*
* DESCRIPTION
* This function posts a wakeup to a semaphore. If there
* are waiting threads (or processes), one is awakened;
* otherwise, the semaphore value is incremented by one.
*
* RESULTS
* 0 successfully posted semaphore,
* -1 failed, error in errno
* ERRNO
* EINVAL 'sem' is not a valid semaphore,
* ENOSYS semaphores are not supported,
* ERANGE semaphore count is too big
*
* ------------------------------------------------------
*/
{
int result = 0;
sem_t s = *sem;
if (s == NULL)
result = EINVAL;
else if ((result = pthread_mutex_lock (&s->lock)) == 0)
{
/* See sem_destroy.c
*/
if (*sem == NULL)
{
(void) pthread_mutex_unlock (&s->lock);
result = EINVAL;
return -1;
}
if (s->value < SEM_VALUE_MAX)
{
pte_osResult osResult = pte_osSemaphorePost(s->sem, 1);
if (++s->value <= 0
&& (osResult != PTE_OS_OK))
{
s->value--;
result = EINVAL;
}
}
else
result = ERANGE;
(void) pthread_mutex_unlock (&s->lock);
}
if (result != 0)
{
errno = result;
return -1;
}
return 0;
}
int
sem_post_multiple (sem_t * sem, int count)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function posts multiple wakeups to a semaphore.
*
* PARAMETERS
* sem
* pointer to an instance of sem_t
*
* count
* counter, must be greater than zero.
*
* DESCRIPTION
* This function posts multiple wakeups to a semaphore. If there
* are waiting threads (or processes), n <= count are awakened;
* the semaphore value is incremented by count - n.
*
* RESULTS
* 0 successfully posted semaphore,
* -1 failed, error in errno
* ERRNO
* EINVAL 'sem' is not a valid semaphore
* or count is less than or equal to zero.
* ERANGE semaphore count is too big
*
* ------------------------------------------------------
*/
{
int result = 0;
long waiters;
sem_t s = *sem;
if (s == NULL || count <= 0)
result = EINVAL;
else if ((result = pthread_mutex_lock (&s->lock)) == 0)
{
/* See sem_destroy.c
*/
if (*sem == NULL)
{
(void) pthread_mutex_unlock (&s->lock);
result = EINVAL;
return -1;
}
if (s->value <= (SEM_VALUE_MAX - count))
{
waiters = -s->value;
s->value += count;
if (waiters > 0)
{
pte_osSemaphorePost(s->sem, (waiters<=count)?waiters:count);
result = 0;
}
/*
else
{
s->value -= count;
result = EINVAL;
}
*/
}
else
{
result = ERANGE;
}
(void) pthread_mutex_unlock (&s->lock);
}
if (result != 0)
{
errno = result;
return -1;
}
return 0;
}
int
sem_timedwait (sem_t * sem, const struct timespec *abstime)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function waits on a semaphore possibly until
* 'abstime' time.
*
* PARAMETERS
* sem
* pointer to an instance of sem_t
*
* abstime
* pointer to an instance of struct timespec
*
* DESCRIPTION
* This function waits on a semaphore. If the
* semaphore value is greater than zero, it decreases
* its value by one. If the semaphore value is zero, then
* the calling thread (or process) is blocked until it can
* successfully decrease the value or until interrupted by
* a signal.
*
* If 'abstime' is a NULL pointer then this function will
* block until it can successfully decrease the value or
* until interrupted by a signal.
*
* RESULTS
* 0 successfully decreased semaphore,
* -1 failed, error in errno
* ERRNO
* EINVAL 'sem' is not a valid semaphore,
* ENOSYS semaphores are not supported,
* EINTR the function was interrupted by a signal,
* EDEADLK a deadlock condition was detected.
* ETIMEDOUT abstime elapsed before success.
*
* ------------------------------------------------------
*/
{
int result = 0;
sem_t s = *sem;
pthread_testcancel();
if (sem == NULL)
result = EINVAL;
else
{
unsigned int milliseconds;
unsigned int *pTimeout;
if (abstime == NULL)
{
pTimeout = NULL;
}
else
{
/*
* Calculate timeout as milliseconds from current system time.
*/
milliseconds = pte_relmillisecs (abstime);
pTimeout = &milliseconds;
}
if ((result = pthread_mutex_lock (&s->lock)) == 0)
{
int v;
/* See sem_destroy.c
*/
if (*sem == NULL)
{
(void) pthread_mutex_unlock (&s->lock);
errno = EINVAL;
return -1;
}
v = --s->value;
(void) pthread_mutex_unlock (&s->lock);
if (v < 0)
{
{
sem_timedwait_cleanup_args_t cleanup_args;
cleanup_args.sem = s;
cleanup_args.resultPtr = &result;
/* Must wait */
pthread_cleanup_push(pte_sem_timedwait_cleanup, (void *) &cleanup_args);
result = pte_cancellable_wait(s->sem,pTimeout);
pthread_cleanup_pop(result);
}
}
}
}
if (result != 0)
{
errno = result;
return -1;
}
return 0;
}
int sem_trywait (sem_t * sem)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function tries to wait on a semaphore.
*
* PARAMETERS
* sem
* pointer to an instance of sem_t
*
* DESCRIPTION
* This function tries to wait on a semaphore. If the
* semaphore value is greater than zero, it decreases
* its value by one. If the semaphore value is zero, then
* this function returns immediately with the error EAGAIN
*
* RESULTS
* 0 successfully decreased semaphore,
* -1 failed, error in errno
* ERRNO
* EAGAIN the semaphore was already locked,
* EINVAL 'sem' is not a valid semaphore,
* ENOTSUP sem_trywait is not supported,
* EINTR the function was interrupted by a signal,
* EDEADLK a deadlock condition was detected.
*
* ------------------------------------------------------
*/
{
int result = 0;
sem_t s = *sem;
if (s == NULL)
result = EINVAL;
else if ((result = pthread_mutex_lock (&s->lock)) == 0)
{
/* See sem_destroy.c
*/
if (*sem == NULL)
{
(void) pthread_mutex_unlock (&s->lock);
errno = EINVAL;
return -1;
}
if (s->value > 0)
s->value--;
else
result = EAGAIN;
(void) pthread_mutex_unlock (&s->lock);
}
if (result != 0)
{
errno = result;
return -1;
}
return 0;
}
int sem_unlink (const char *name)
{
errno = ENOSYS;
return -1;
}
int sem_wait (sem_t * sem)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function waits on a semaphore.
*
* PARAMETERS
* sem
* pointer to an instance of sem_t
*
* DESCRIPTION
* This function waits on a semaphore. If the
* semaphore value is greater than zero, it decreases
* its value by one. If the semaphore value is zero, then
* the calling thread (or process) is blocked until it can
* successfully decrease the value or until interrupted by
* a signal.
*
* RESULTS
* 0 successfully decreased semaphore,
* -1 failed, error in errno
* ERRNO
* EINVAL 'sem' is not a valid semaphore,
* ENOSYS semaphores are not supported,
* EINTR the function was interrupted by a signal,
* EDEADLK a deadlock condition was detected.
*
* ------------------------------------------------------
*/
{
int result = 0;
sem_t s = *sem;
pthread_testcancel();
if (s == NULL)
{
result = EINVAL;
}
else
{
if ((result = pthread_mutex_lock (&s->lock)) == 0)
{
int v;
/* See sem_destroy.c
*/
if (*sem == NULL)
{
(void) pthread_mutex_unlock (&s->lock);
errno = EINVAL;
return -1;
}
v = --s->value;
(void) pthread_mutex_unlock (&s->lock);
if (v < 0)
{
/* Must wait */
pthread_cleanup_push(pte_sem_wait_cleanup, (void *) s);
result = pte_cancellable_wait(s->sem,NULL);
/* Cleanup if we're canceled or on any other error */
pthread_cleanup_pop(result);
// Wait was cancelled, indicate that we're no longer waiting on this semaphore.
/*
if (result == PTE_OS_INTERRUPTED)
{
result = EINTR;
++s->value;
}
*/
}
}
}
if (result != 0)
{
errno = result;
return -1;
}
return 0;
} /* sem_wait */
int
sem_wait_nocancel (sem_t * sem)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function waits on a semaphore, and doesn't
* allow cancellation.
*
* PARAMETERS
* sem
* pointer to an instance of sem_t
*
* DESCRIPTION
* This function waits on a semaphore. If the
* semaphore value is greater than zero, it decreases
* its value by one. If the semaphore value is zero, then
* the calling thread (or process) is blocked until it can
* successfully decrease the value or until interrupted by
* a signal.
*
* RESULTS
* 0 successfully decreased semaphore,
* -1 failed, error in errno
* ERRNO
* EINVAL 'sem' is not a valid semaphore,
* ENOSYS semaphores are not supported,
* EINTR the function was interrupted by a signal,
* EDEADLK a deadlock condition was detected.
*
* ------------------------------------------------------
*/
{
int result = 0;
sem_t s = *sem;
pthread_testcancel();
if (s == NULL)
{
result = EINVAL;
}
else
{
if ((result = pthread_mutex_lock (&s->lock)) == 0)
{
int v;
/* See sem_destroy.c
*/
if (*sem == NULL)
{
(void) pthread_mutex_unlock (&s->lock);
errno = EINVAL;
return -1;
}
v = --s->value;
(void) pthread_mutex_unlock (&s->lock);
if (v < 0)
{
pte_osSemaphorePend(s->sem, NULL);
}
}
}
if (result != 0)
{
errno = result;
return -1;
}
return 0;
}

View File

@ -1,114 +0,0 @@
/*
* Module: semaphore.h
*
* Purpose:
* Semaphores aren't actually part of the PThreads standard.
* They are defined by the POSIX Standard:
*
* POSIX 1003.1b-1993 (POSIX.1b)
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined( SEMAPHORE_H )
#define SEMAPHORE_H
#if defined(_POSIX_SOURCE)
#define PTE_LEVEL 0
/* Early POSIX */
#endif
#if defined(INCLUDE_NP)
#undef PTE_LEVEL
#define PTE_LEVEL 2
/* Include Non-Portable extensions */
#endif
/*
*
*/
#define _POSIX_SEMAPHORES
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
typedef struct sem_t_ * sem_t;
int sem_init (sem_t * sem,
int pshared,
unsigned int value);
int sem_destroy (sem_t * sem);
int sem_trywait (sem_t * sem);
int sem_wait (sem_t * sem);
int sem_timedwait (sem_t * sem,
const struct timespec * abstime);
int sem_post (sem_t * sem);
int sem_post_multiple (sem_t * sem,
int count);
int sem_open (const char * name,
int oflag,
mode_t mode,
unsigned int value);
int sem_close (sem_t * sem);
int sem_unlink (const char * name);
int sem_getvalue (sem_t * sem,
int * sval);
#ifdef __cplusplus
} /* End of extern "C" */
#endif /* __cplusplus */
#endif /* !SEMAPHORE_H */

View File

@ -1254,26 +1254,6 @@ THREAD
#if defined(XENON)
#include "../thread/xenon_sdl_threads.c"
#elif defined(PSP)
#include "../deps/pthreads/platform/helper/tls-helper.c"
#include "../deps/pthreads/platform/psp/psp_osal.c"
#include "../deps/pthreads/pte_main.c"
#include "../deps/pthreads/pte.c"
#include "../deps/pthreads/pthread_attr.c"
#include "../deps/pthreads/pthread_barrier.c"
#include "../deps/pthreads/pthread_cond.c"
#include "../deps/pthreads/pthread_condattr.c"
#include "../deps/pthreads/pthread_get.c"
#include "../deps/pthreads/pthread_key.c"
#include "../deps/pthreads/pthread_mutex.c"
#include "../deps/pthreads/pthread_mutexattr.c"
#include "../deps/pthreads/pthread_rwlock.c"
#include "../deps/pthreads/pthread_rwlockattr.c"
#include "../deps/pthreads/pthread_set.c"
#include "../deps/pthreads/pthread_spin.c"
#include "../deps/pthreads/pthread.c"
#include "../deps/pthreads/sched.c"
#include "../deps/pthreads/sem.c"
#endif
#include "../libretro-common/rthreads/rthreads.c"