diff --git a/deps/pthreads/ANNOUNCE b/deps/pthreads/ANNOUNCE new file mode 100644 index 0000000000..97d94e7026 --- /dev/null +++ b/deps/pthreads/ANNOUNCE @@ -0,0 +1,476 @@ + 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 + + +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 . + +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 diff --git a/deps/pthreads/CONTRIBUTORS.ptw32 b/deps/pthreads/CONTRIBUTORS.ptw32 new file mode 100644 index 0000000000..e5b7325d16 --- /dev/null +++ b/deps/pthreads/CONTRIBUTORS.ptw32 @@ -0,0 +1,129 @@ +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. diff --git a/deps/pthreads/COPYING b/deps/pthreads/COPYING new file mode 100644 index 0000000000..5cfea0d0ed --- /dev/null +++ b/deps/pthreads/COPYING @@ -0,0 +1,150 @@ + 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. diff --git a/deps/pthreads/COPYING.LIB b/deps/pthreads/COPYING.LIB new file mode 100644 index 0000000000..b1e3f5a263 --- /dev/null +++ b/deps/pthreads/COPYING.LIB @@ -0,0 +1,504 @@ + 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. + + + Copyright (C) + + 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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/deps/pthreads/implement.h b/deps/pthreads/implement.h new file mode 100644 index 0000000000..61c67c6f0a --- /dev/null +++ b/deps/pthreads/implement.h @@ -0,0 +1,516 @@ +/* + * 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 */ diff --git a/deps/pthreads/need_errno.h b/deps/pthreads/need_errno.h new file mode 100644 index 0000000000..d5b50d5d0e --- /dev/null +++ b/deps/pthreads/need_errno.h @@ -0,0 +1,90 @@ +/*** +* 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 */ diff --git a/deps/pthreads/platform/helper/tls-helper.c b/deps/pthreads/platform/helper/tls-helper.c new file mode 100644 index 0000000000..b1dd72c347 --- /dev/null +++ b/deps/pthreads/platform/helper/tls-helper.c @@ -0,0 +1,163 @@ +/* + * 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 +#include + +#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 #include #include #include #include "pte_osal.h" #include "pthread.h" #include "tls-helper.h" /* For ftime */ #include #include #include #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; // printf("%s %p %d %d %d\n",threadName, pspStubThreadEntry, initialPriority, stackSize, pspAttr); 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) { pspThreadData *pThreadData; void *pTls; pTls = getTlsStructFromThread(handle); 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() { 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; 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; } else { /* Nothing found and not timed out yet; let's yield so we're not * in busy loop. */ 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) { SceUID osResult; pte_osResult result; pspThreadData *pThreadData; pThreadData = getThreadData(threadHandle); osResult = sceKernelSignalSema(pThreadData->cancelSem, 1); if (osResult == SCE_KERNEL_ERROR_OK) { result = PTE_OS_OK; } else { result = PTE_OS_GENERAL_FAILURE; } return result; } pte_osResult pte_osThreadCheckCancel(pte_osThreadHandle threadHandle) { pspThreadData *pThreadData; SceKernelSemaInfo semInfo; SceUID osResult; pte_osResult result; 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; } } else { /* sceKernelReferSemaStatus returned an error */ result = PTE_OS_GENERAL_FAILURE; } } else { /* For some reason, we couldn't get thread data */ result = PTE_OS_GENERAL_FAILURE; } return result; } void pte_osThreadSleep(unsigned int msecs) { sceKernelDelayThread(msecs*1000); } int pte_osThreadGetMinPriority() { return 17; } int pte_osThreadGetMaxPriority() { return 30; } int pte_osThreadGetDefaultPriority() { 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) { pte_osResult result; SceUInt timeoutUsecs = timeoutMsecs*1000; int status = sceKernelWaitSema(handle, 1, &timeoutUsecs); if (status < 0) { // Assume that any error from sceKernelWaitSema was due to a timeout result = PTE_OS_TIMEOUT; } else { result = PTE_OS_OK; } return result; } 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) { osResult = PTE_OS_OK; } else if (result == SCE_KERNEL_ERROR_WAIT_TIMEOUT) { osResult = PTE_OS_TIMEOUT; } else { osResult = PTE_OS_GENERAL_FAILURE; } return osResult; } /* * 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; } else { /* Nothing found and not timed out yet; let's yield so we're not * in busy loop. */ 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; origVal = *ptarg; *ptarg = val; pspSdkEnableInterrupts(intc); return origVal; } int pte_osAtomicCompareExchange(int *pdest, int exchange, int comp) { int intc = pspSdkDisableInterrupts(); int origVal; origVal = *pdest; if (*pdest == comp) { *pdest = exchange; } pspSdkEnableInterrupts(intc); return origVal; } int pte_osAtomicExchangeAdd(int volatile* pAddend, int value) { int origVal; int intc = pspSdkDisableInterrupts(); 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) { pspThreadData *pThreadData; void *pTls; pTls = getTlsStructFromThread(threadHandle); pThreadData = (pspThreadData *) pteTlsGetValue(pTls, threadDataKey); return pThreadData; } static void *getTlsStructFromThread(SceUID thid) { SceKernelThreadInfo thinfo; unsigned int ptr; unsigned int thrNum; void *pTls; 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) { pTls = (void *) ptr; } else { pTls = globalTls; } return pTls; } /**************************************************************************** * * Thread Local Storage * ***************************************************************************/ pte_osResult pte_osTlsSetValue(unsigned int key, void * value) { void *pTls; pTls = getTlsStructFromThread(sceKernelGetThreadId()); return pteTlsSetValue(pTls, key, value); } void * pte_osTlsGetValue(unsigned int index) { void *pTls; pTls = getTlsStructFromThread(sceKernelGetThreadId()); return (void *) pteTlsGetValue(pTls, index); } pte_osResult pte_osTlsAlloc(unsigned int *pKey) { void * pTls; 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; } \ No newline at end of file diff --git a/deps/pthreads/platform/psp/psp_osal.h b/deps/pthreads/platform/psp/psp_osal.h new file mode 100644 index 0000000000..33528ddba4 --- /dev/null +++ b/deps/pthreads/platform/psp/psp_osal.h @@ -0,0 +1,66 @@ +/* + * 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 + +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 + +//#define HAVE_THREAD_SAFE_ERRNO + +#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); + + + + diff --git a/deps/pthreads/platform/psp/pte_osal.h b/deps/pthreads/platform/psp/pte_osal.h new file mode 100644 index 0000000000..2fe8723cdd --- /dev/null +++ b/deps/pthreads/platform/psp/pte_osal.h @@ -0,0 +1,12 @@ + +#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 diff --git a/deps/pthreads/platform/psp/pte_types.h b/deps/pthreads/platform/psp/pte_types.h new file mode 100644 index 0000000000..4fc2b422b8 --- /dev/null +++ b/deps/pthreads/platform/psp/pte_types.h @@ -0,0 +1,12 @@ +/* pte_types.h */ + +#ifndef PTE_TYPES_H +#define PTE_TYPES_H + +#include +#include +#include + +typedef int pid_t; + +#endif /* PTE_TYPES_H */ diff --git a/deps/pthreads/platform/psp/pthread_main.c b/deps/pthreads/platform/psp/pthread_main.c new file mode 100644 index 0000000000..fb65bcf65e --- /dev/null +++ b/deps/pthreads/platform/psp/pthread_main.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include +#include + + +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; + + 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 = 0; + + 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; +} diff --git a/deps/pthreads/pte.c b/deps/pthreads/pte.c new file mode 100644 index 0000000000..00e6cc0c26 --- /dev/null +++ b/deps/pthreads/pte.c @@ -0,0 +1,1116 @@ +/* + * pte.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * 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 +#include +#include + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + +#include + +typedef long long int64_t; + +static struct pthread_mutexattr_t_ pte_recursive_mutexattr_s = +{ + PTHREAD_PROCESS_PRIVATE, PTHREAD_MUTEX_RECURSIVE +}; +static struct pthread_mutexattr_t_ pte_errorcheck_mutexattr_s = +{ + PTHREAD_PROCESS_PRIVATE, PTHREAD_MUTEX_ERRORCHECK +}; +static pthread_mutexattr_t pte_recursive_mutexattr = &pte_recursive_mutexattr_s; +static pthread_mutexattr_t pte_errorcheck_mutexattr = &pte_errorcheck_mutexattr_s; + +static int pte_thread_detach_common (unsigned char threadShouldExit) +{ + if (pte_processInitialized) + { + /* + * Don't use pthread_self() - to avoid creating an implicit POSIX thread handle + * unnecessarily. + */ + pte_thread_t * sp = (pte_thread_t *) pthread_getspecific (pte_selfThreadKey); + + if (sp != NULL) // otherwise OS thread with no implicit POSIX handle. + { + + pte_callUserDestroyRoutines (sp); + + (void) pthread_mutex_lock (&sp->cancelLock); + sp->state = PThreadStateLast; + + /* + * If the thread is joinable at this point then it MUST be joined + * or detached explicitly by the application. + */ + (void) pthread_mutex_unlock (&sp->cancelLock); + + if (sp->detachState == PTHREAD_CREATE_DETACHED) + { + if (threadShouldExit) + { + pte_threadExitAndDestroy (sp); + } + else + { + pte_threadDestroy (sp); + } + + // pte_osTlsSetValue (pte_selfThreadKey->key, NULL); + } + else + { + if (threadShouldExit) + { + pte_osThreadExit(); + } + } + } + } + + return 1; +} + +static void pte_threadDestroyCommon (pthread_t thread, unsigned char shouldThreadExit) +{ + pte_thread_t * tp = (pte_thread_t *) thread; + pte_thread_t threadCopy; + + if (tp != NULL) + { + /* + * Copy thread state so that the thread can be atomically NULLed. + */ + memcpy (&threadCopy, tp, sizeof (threadCopy)); + + /* + * Thread ID structs are never freed. They're NULLed and reused. + * This also sets the thread to PThreadStateInitial (invalid). + */ + pte_threadReusePush (thread); + + (void) pthread_mutex_destroy(&threadCopy.cancelLock); + (void) pthread_mutex_destroy(&threadCopy.threadLock); + + if (threadCopy.threadId != 0) + { + if (shouldThreadExit) + { + pte_osThreadExitAndDelete(threadCopy.threadId); + } + else + { + pte_osThreadDelete(threadCopy.threadId); + } + } + + + + } +} /* pte_threadDestroy */ + +void +pte_callUserDestroyRoutines (pthread_t thread) +/* + * ------------------------------------------------------------------- + * DOCPRIVATE + * + * This the routine runs through all thread keys and calls + * the destroy routines on the user's data for the current thread. + * It simulates the behaviour of POSIX Threads. + * + * PARAMETERS + * thread + * an instance of pthread_t + * + * RETURNS + * N/A + * ------------------------------------------------------------------- + */ +{ + ThreadKeyAssoc * assoc; + + if (thread != NULL) + { + int assocsRemaining; + int iterations = 0; + pte_thread_t * sp = (pte_thread_t *) thread; + + /* + * Run through all Thread<-->Key associations + * for the current thread. + * + * Do this process at most PTHREAD_DESTRUCTOR_ITERATIONS times. + */ + do + { + assocsRemaining = 0; + iterations++; + + (void) pthread_mutex_lock(&(sp->threadLock)); + /* + * The pointer to the next assoc is stored in the thread struct so that + * the assoc destructor in pthread_key_delete can adjust it + * if it deletes this assoc. This can happen if we fail to acquire + * both locks below, and are forced to release all of our locks, + * leaving open the opportunity for pthread_key_delete to get in + * before us. + */ + sp->nextAssoc = sp->keys; + (void) pthread_mutex_unlock(&(sp->threadLock)); + + for (;;) + { + void * value; + pthread_key_t k; + void (*destructor) (void *); + + /* + * First we need to serialise with pthread_key_delete by locking + * both assoc guards, but in the reverse order to our convention, + * so we must be careful to avoid deadlock. + */ + (void) pthread_mutex_lock(&(sp->threadLock)); + + if ((assoc = (ThreadKeyAssoc *)sp->nextAssoc) == NULL) + { + /* Finished */ + pthread_mutex_unlock(&(sp->threadLock)); + break; + } + else + { + /* + * assoc->key must be valid because assoc can't change or be + * removed from our chain while we hold at least one lock. If + * the assoc was on our key chain then the key has not been + * deleted yet. + * + * Now try to acquire the second lock without deadlocking. + * If we fail, we need to relinquish the first lock and the + * processor and then try to acquire them all again. + */ + if (pthread_mutex_trylock(&(assoc->key->keyLock)) == EBUSY) + { + pthread_mutex_unlock(&(sp->threadLock)); + pte_osThreadSleep(1); // Ugly but necessary to avoid priority effects. + /* + * Go around again. + * If pthread_key_delete has removed this assoc in the meantime, + * sp->nextAssoc will point to a new assoc. + */ + continue; + } + } + + /* We now hold both locks */ + + sp->nextAssoc = assoc->nextKey; + + /* + * Key still active; pthread_key_delete + * will block on these same mutexes before + * it can release actual key; therefore, + * key is valid and we can call the destroy + * routine; + */ + k = assoc->key; + destructor = k->destructor; + value = pte_osTlsGetValue(k->key); + pte_osTlsSetValue (k->key, NULL); + + // Every assoc->key exists and has a destructor + if (value != NULL && iterations <= PTHREAD_DESTRUCTOR_ITERATIONS) + { + /* + * Unlock both locks before the destructor runs. + * POSIX says pthread_key_delete can be run from destructors, + * and that probably includes with this key as target. + * pthread_setspecific can also be run from destructors and + * also needs to be able to access the assocs. + */ + (void) pthread_mutex_unlock(&(sp->threadLock)); + (void) pthread_mutex_unlock(&(k->keyLock)); + + assocsRemaining++; + +#ifdef __cplusplus + + try + { + /* + * Run the caller's cleanup routine. + */ + destructor (value); + } + catch (...) + { + /* + * A system unexpected exception has occurred + * running the user's destructor. + * We get control back within this block in case + * the application has set up it's own terminate + * handler. Since we are leaving the thread we + * should not get any internal pthreads + * exceptions. + */ + terminate (); + } + +#else /* __cplusplus */ + + /* + * Run the caller's cleanup routine. + */ + destructor (value); + +#endif /* __cplusplus */ + + } + else + { + /* + * Remove association from both the key and thread chains + * and reclaim it's memory resources. + */ + pte_tkAssocDestroy (assoc); + (void) pthread_mutex_unlock(&(sp->threadLock)); + (void) pthread_mutex_unlock(&(k->keyLock)); + } + } + } + while (assocsRemaining); + } +} + +int pte_cancellable_wait (pte_osSemaphoreHandle semHandle, unsigned int* timeout) +{ + pte_osResult osResult; + int result = EINVAL; + int cancelEnabled = 0; + pthread_t self = pthread_self(); + pte_thread_t *sp = (pte_thread_t *) self; + + if (sp != NULL) + { + /* + * Get cancelEvent handle + */ + if (sp->cancelState == PTHREAD_CANCEL_ENABLE) + cancelEnabled = 1; + } + + + if (cancelEnabled) + osResult = pte_osSemaphoreCancellablePend(semHandle, timeout); + else + osResult = pte_osSemaphorePend(semHandle, timeout); + + switch (osResult) + { + case PTE_OS_OK: + result = 0; + break; + + case PTE_OS_TIMEOUT: + result = ETIMEDOUT; + break; + + case PTE_OS_INTERRUPTED: + if (sp != NULL) + { + /* + * Should handle POSIX and implicit POSIX threads.. + * Make sure we haven't been async-canceled in the meantime. + */ + (void) pthread_mutex_lock (&sp->cancelLock); + if (sp->state < PThreadStateCanceling) + { + 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); + } + break; + default: + result = EINVAL; + } + + return (result); +} + +int pte_cond_check_need_init (pthread_cond_t * cond) +{ + int result = 0; + + /* + * The following guarded test is specifically for statically + * initialised condition variables (via PTHREAD_OBJECT_INITIALIZER). + * + * Note that by not providing this synchronisation we risk + * introducing race conditions into applications which are + * correctly written. + * + * Approach + * -------- + * We know that static condition variables will not be PROCESS_SHARED + * so we can serialise access to internal state using + * Win32 Critical Sections rather than Win32 Mutexes. + * + * If using a single global lock slows applications down too much, + * multiple global locks could be created and hashed on some random + * value associated with each mutex, the pointer perhaps. At a guess, + * a good value for the optimal number of global locks might be + * the number of processors + 1. + * + */ + + + pte_osMutexLock (pte_cond_test_init_lock); + + /* + * We got here possibly under race + * conditions. Check again inside the critical section. + * If a static cv has been destroyed, the application can + * re-initialise it only by calling pthread_cond_init() + * explicitly. + */ + if (*cond == PTHREAD_COND_INITIALIZER) + result = pthread_cond_init (cond, NULL); + /* + * The cv has been destroyed while we were waiting to + * initialise it, so the operation that caused the + * auto-initialisation should fail. + */ + else if (*cond == NULL) + result = EINVAL; + + + pte_osMutexUnlock(pte_cond_test_init_lock); + + return result; +} + +int pte_thread_detach_and_exit_np(void) +{ + return pte_thread_detach_common(1); +} + +int pte_thread_detach_np(void) +{ + return pte_thread_detach_common(0); +} + +/* + * pte_getprocessors() + * + * Get the number of CPUs available to the process. + * + * If the available number of CPUs is 1 then pthread_spin_lock() + * will block rather than spin if the lock is already owned. + * + * pthread_spin_init() calls this routine when initialising + * a spinlock. If the number of available processors changes + * (after a call to SetProcessAffinityMask()) then only + * newly initialised spinlocks will notice. + */ +int pte_getprocessors (int *count) +{ + int result = 0; + + *count = 1; + + return (result); +} + +int pte_is_attr (const pthread_attr_t * attr) +{ + /* Return 0 if the attr object is valid, non-zero otherwise. */ + + return (attr == NULL || + *attr == NULL || (*attr)->valid != PTE_ATTR_VALID); +} + +int pte_mutex_check_need_init (pthread_mutex_t * mutex) +{ + register int result = 0; + register pthread_mutex_t mtx; + + /* + * The following guarded test is specifically for statically + * initialised mutexes (via PTHREAD_MUTEX_INITIALIZER). + * + * Note that by not providing this synchronisation we risk + * introducing race conditions into applications which are + * correctly written. + * + * Approach + * -------- + * We know that static mutexes will not be PROCESS_SHARED + * so we can serialise access to internal state using + * critical sections rather than mutexes. + * + * If using a single global lock slows applications down too much, + * multiple global locks could be created and hashed on some random + * value associated with each mutex, the pointer perhaps. At a guess, + * a good value for the optimal number of global locks might be + * the number of processors + 1. + * + */ + + + pte_osMutexLock (pte_mutex_test_init_lock); + + /* + * We got here possibly under race + * conditions. Check again inside the critical section + * and only initialise if the mutex is valid (not been destroyed). + * If a static mutex has been destroyed, the application can + * re-initialise it only by calling pthread_mutex_init() + * explicitly. + */ + mtx = *mutex; + + if (mtx == PTHREAD_MUTEX_INITIALIZER) + { + result = pthread_mutex_init (mutex, NULL); + } + else if (mtx == PTHREAD_RECURSIVE_MUTEX_INITIALIZER) + { + result = pthread_mutex_init (mutex, &pte_recursive_mutexattr); + } + else if (mtx == PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) + { + result = pthread_mutex_init (mutex, &pte_errorcheck_mutexattr); + } + else if (mtx == NULL) + { + /* + * The mutex has been destroyed while we were waiting to + * initialise it, so the operation that caused the + * auto-initialisation should fail. + */ + result = EINVAL; + } + + pte_osMutexUnlock(pte_mutex_test_init_lock); + + return (result); +} + +pthread_t pte_new (void) +{ + pthread_t nil = NULL; + pte_thread_t * tp; + + /* + * If there's a reusable pthread_t then use it. + */ + pthread_t t = pte_threadReusePop (); + + if (NULL != t) + tp = (pte_thread_t *) t; + else + { + /* No reuse threads available */ + tp = (pte_thread_t *) calloc (1, sizeof(pte_thread_t)); + + if (tp == NULL) + return nil; + + /* ptHandle.p needs to point to it's parent pte_thread_t. */ + t = tp; + tp->x = 0; + } + + /* Set default state. */ + tp->sched_priority = pte_osThreadGetMinPriority(); + + tp->detachState = PTHREAD_CREATE_JOINABLE; + tp->cancelState = PTHREAD_CANCEL_ENABLE; + tp->cancelType = PTHREAD_CANCEL_DEFERRED; + tp->cancelLock = PTHREAD_MUTEX_INITIALIZER; + tp->threadLock = PTHREAD_MUTEX_INITIALIZER; + + return t; + +} + +unsigned int pte_relmillisecs (const struct timespec * abstime) +{ + const long long NANOSEC_PER_MILLISEC = 1000000; + const long long MILLISEC_PER_SEC = 1000; + unsigned int milliseconds; + long long tmpAbsMilliseconds; + long tmpCurrMilliseconds; + struct timeb currSysTime; + + /* + * Calculate timeout as milliseconds from current system time. + */ + + /* + * subtract current system time from abstime in a way that checks + * that abstime is never in the past, or is never equivalent to the + * defined INFINITE value (0xFFFFFFFF). + * + * Assume all integers are unsigned, i.e. cannot test if less than 0. + */ + tmpAbsMilliseconds = (int64_t)abstime->tv_sec * MILLISEC_PER_SEC; + tmpAbsMilliseconds += ((int64_t)abstime->tv_nsec + (NANOSEC_PER_MILLISEC/2)) / NANOSEC_PER_MILLISEC; + + /* get current system time */ + + _ftime(&currSysTime); + + tmpCurrMilliseconds = (int64_t) currSysTime.time * MILLISEC_PER_SEC; + tmpCurrMilliseconds += (int64_t) currSysTime.millitm; + + if (tmpAbsMilliseconds > tmpCurrMilliseconds) + { + milliseconds = (unsigned int) (tmpAbsMilliseconds - tmpCurrMilliseconds); + /* Timeouts must be finite */ + if (milliseconds == 0xFFFFFFFF) + milliseconds--; + } + /* The abstime given is in the past */ + else + milliseconds = 0; + + return milliseconds; +} + +/* + * How it works: + * A pthread_t is a struct which is normally passed/returned by + * value to/from pthreads routines. Applications are therefore storing + * a copy of the struct as it is at that time. + * + * The original pthread_t struct plus all copies of it contain the address of + * the thread state struct pte_thread_t_ (p), plus a reuse counter (x). Each + * pte_thread_t contains the original copy of it's pthread_t. + * Once malloced, a pte_thread_t_ struct is not freed until the process exits. + * + * The thread reuse stack is a simple LILO stack managed through a singly + * linked list element in the pte_thread_t. + * + * Each time a thread is destroyed, the pte_thread_t address is pushed onto the + * reuse stack after it's ptHandle's reuse counter has been incremented. + * + * The following can now be said from this: + * - two pthread_t's are identical if their pte_thread_t reference pointers + * are equal and their reuse counters are equal. That is, + * + * equal = (a.p == b.p && a.x == b.x) + * + * - a pthread_t copy refers to a destroyed thread if the reuse counter in + * the copy is not equal to the reuse counter in the original. + * + * threadDestroyed = (copy.x != ((pte_thread_t *)copy.p)->ptHandle.x) + * + */ + +/* + * Pop a clean pthread_t struct off the reuse stack. + */ + pthread_t +pte_threadReusePop (void) +{ + pthread_t t = NULL; + + + pte_osMutexLock (pte_thread_reuse_lock); + + if (PTE_THREAD_REUSE_EMPTY != pte_threadReuseTop) + { + pte_thread_t * tp; + + tp = pte_threadReuseTop; + + pte_threadReuseTop = tp->prevReuse; + + if (PTE_THREAD_REUSE_EMPTY == pte_threadReuseTop) + { + pte_threadReuseBottom = PTE_THREAD_REUSE_EMPTY; + } + + tp->prevReuse = NULL; + + t = tp; + } + + pte_osMutexUnlock(pte_thread_reuse_lock); + + return t; + +} + +/* + * Push a clean pthread_t struct onto the reuse stack. + * Must be re-initialised when reused. + * All object elements (mutexes, events etc) must have been either + * detroyed before this, or never initialised. + */ +void pte_threadReusePush (pthread_t thread) +{ + pte_thread_t * tp = (pte_thread_t *) thread; + pthread_t t; + + pte_osMutexLock (pte_thread_reuse_lock); + + t = tp; + memset(tp, 0, sizeof(pte_thread_t)); + + /* Must restore the original POSIX handle that we just wiped. */ + tp = t; + + /* Bump the reuse counter now */ +#ifdef PTE_THREAD_ID_REUSE_INCREMENT + tp->x += PTE_THREAD_ID_REUSE_INCREMENT; +#else + tp->x++; +#endif + + tp->prevReuse = PTE_THREAD_REUSE_EMPTY; + + if (PTE_THREAD_REUSE_EMPTY != pte_threadReuseBottom) + pte_threadReuseBottom->prevReuse = tp; + else + pte_threadReuseTop = tp; + + pte_threadReuseBottom = tp; + + pte_osMutexUnlock(pte_thread_reuse_lock); +} + +void pte_rwlock_cancelwrwait (void *arg) +{ + pthread_rwlock_t rwl = (pthread_rwlock_t) arg; + + rwl->nSharedAccessCount = -rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + + (void) pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted)); + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); +} + +int pte_rwlock_check_need_init (pthread_rwlock_t * rwlock) +{ + int result = 0; + + /* + * The following guarded test is specifically for statically + * initialised rwlocks (via PTHREAD_RWLOCK_INITIALIZER). + * + * Note that by not providing this synchronisation we risk + * introducing race conditions into applications which are + * correctly written. + * + * Approach + * -------- + * We know that static rwlocks will not be PROCESS_SHARED + * so we can serialise access to internal state using + * critical sections rather than mutexes. + * + * If using a single global lock slows applications down too much, + * multiple global locks could be created and hashed on some random + * value associated with each mutex, the pointer perhaps. At a guess, + * a good value for the optimal number of global locks might be + * the number of processors + 1. + * + */ + + + pte_osMutexLock (pte_rwlock_test_init_lock); + + /* + * We got here possibly under race + * conditions. Check again inside the critical section + * and only initialise if the rwlock is valid (not been destroyed). + * If a static rwlock has been destroyed, the application can + * re-initialise it only by calling pthread_rwlock_init() + * explicitly. + */ + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + result = pthread_rwlock_init (rwlock, NULL); + /* + * The rwlock has been destroyed while we were waiting to + * initialise it, so the operation that caused the + * auto-initialisation should fail. + */ + else if (*rwlock == NULL) + result = EINVAL; + + pte_osMutexUnlock(pte_rwlock_test_init_lock); + + return result; +} + +int pte_spinlock_check_need_init (pthread_spinlock_t * lock) +{ + int result = 0; + + /* + * The following guarded test is specifically for statically + * initialised spinlocks (via PTHREAD_SPINLOCK_INITIALIZER). + * + * Note that by not providing this synchronisation we risk + * introducing race conditions into applications which are + * correctly written. + */ + + + pte_osMutexLock (pte_spinlock_test_init_lock); + + /* + * We got here possibly under race + * conditions. Check again inside the critical section + * and only initialise if the spinlock is valid (not been destroyed). + * If a static spinlock has been destroyed, the application can + * re-initialise it only by calling pthread_spin_init() + * explicitly. + */ + if (*lock == PTHREAD_SPINLOCK_INITIALIZER) + result = pthread_spin_init (lock, PTHREAD_PROCESS_PRIVATE); + /* + * The spinlock has been destroyed while we were waiting to + * initialise it, so the operation that caused the + * auto-initialisation should fail. + */ + else if (*lock == NULL) + result = EINVAL; + + pte_osMutexUnlock(pte_spinlock_test_init_lock); + + return (result); +} + +void pte_threadDestroy (pthread_t thread) +{ + pte_threadDestroyCommon(thread,0); +} + +void pte_threadExitAndDestroy (pthread_t thread) +{ + pte_threadDestroyCommon(thread,1); +} + +#include + +int pte_threadStart (void *vthreadParms) +{ + ThreadParms * threadParms = (ThreadParms *) vthreadParms; + void *(*start) (void *); + void * arg; + + + int setjmp_rc; + + void * status = (void *) 0; + + pthread_t self = threadParms->tid; + pte_thread_t *sp = (pte_thread_t *) self; + start = threadParms->start; + arg = threadParms->arg; + // free (threadParms); + + pthread_setspecific (pte_selfThreadKey, sp); + + sp->state = PThreadStateRunning; + + setjmp_rc = setjmp (sp->start_mark); + + + if (0 == setjmp_rc) + { + + /* + * Run the caller's routine; + */ + sp->exitStatus = status = (*start) (arg); + } + else + { + switch (setjmp_rc) + { + case PTE_EPS_CANCEL: + status = sp->exitStatus = PTHREAD_CANCELED; + break; + case PTE_EPS_EXIT: + status = sp->exitStatus; + break; + default: + status = sp->exitStatus = PTHREAD_CANCELED; + break; + } + } + + /* + * We need to cleanup the pthread now if we have + * been statically linked, in which case the cleanup + * in dllMain won't get done. Joinable threads will + * only be partially cleaned up and must be fully cleaned + * up by pthread_join() or pthread_detach(). + * + * Note: if this library has been statically linked, + * implicitly created pthreads (those created + * for OS threads which have called pthreads routines) + * must be cleaned up explicitly by the application + * (by calling pte_thread_detach_np()). + */ + (void) pte_thread_detach_and_exit_np (); + + //pte_osThreadExit(status); + + /* + * Never reached. + */ + + return (unsigned) status; +} + + +/* + * pte_throw + * + * All canceled and explicitly exited POSIX threads go through + * here. This routine knows how to exit both POSIX initiated threads and + * 'implicit' POSIX threads for each of the possible language modes (C, + * C++). + */ +void pte_throw (unsigned int exception) +{ + /* + * Don't use pthread_self() to avoid creating an implicit POSIX thread handle + * unnecessarily. + */ + pte_thread_t * sp = (pte_thread_t *) pthread_getspecific (pte_selfThreadKey); + + + if (exception != PTE_EPS_CANCEL && exception != PTE_EPS_EXIT) + { + /* Should never enter here */ + exit (1); + } + + if (NULL == sp || sp->implicit) + { + /* + * We're inside a non-POSIX initialised OS thread + * so there is no point to jump or throw back to. Just do an + * explicit thread exit here after cleaning up POSIX + * residue (i.e. cleanup handlers, POSIX thread handle etc). + */ + unsigned exitCode = 0; + + switch (exception) + { + case PTE_EPS_CANCEL: + exitCode = (unsigned) PTHREAD_CANCELED; + break; + case PTE_EPS_EXIT: + exitCode = (unsigned) sp->exitStatus;; + break; + } + + pte_thread_detach_and_exit_np (); + + // pte_osThreadExit((void*)exitCode); + + } + + pte_pop_cleanup_all (1); + longjmp (sp->start_mark, exception); + + /* Never reached */ +} + +void pte_pop_cleanup_all (int execute) +{ + while (NULL != pte_pop_cleanup (execute)) { } +} + +unsigned int pte_get_exception_services_code (void) +{ + return (unsigned int) NULL; +} + +int pte_tkAssocCreate (pte_thread_t * sp, pthread_key_t key) + /* + * ------------------------------------------------------------------- + * This routine creates an association that + * is unique for the given (thread,key) combination.The association + * is referenced by both the thread and the key. + * This association allows us to determine what keys the + * current thread references and what threads a given key + * references. + * See the detailed description + * at the beginning of this file for further details. + * + * Notes: + * 1) New associations are pushed to the beginning of the + * chain so that the internal pte_selfThreadKey association + * is always last, thus allowing selfThreadExit to + * be implicitly called last by pthread_exit. + * 2) + * + * Parameters: + * thread + * current running thread. + * key + * key on which to create an association. + * Returns: + * 0 - if successful, + * ENOMEM - not enough memory to create assoc or other object + * EINVAL - an internal error occurred + * ENOSYS - an internal error occurred + * ------------------------------------------------------------------- + */ +{ + ThreadKeyAssoc *assoc; + + /* + * Have to create an association and add it + * to both the key and the thread. + * + * Both key->keyLock and thread->threadLock are locked on + * entry to this routine. + */ + assoc = (ThreadKeyAssoc *) calloc (1, sizeof (*assoc)); + + if (assoc == NULL) + { + return ENOMEM; + } + + assoc->thread = sp; + assoc->key = key; + + /* + * Register assoc with key + */ + assoc->prevThread = NULL; + assoc->nextThread = (ThreadKeyAssoc *) key->threads; + if (assoc->nextThread != NULL) + assoc->nextThread->prevThread = assoc; + key->threads = (void *) assoc; + + /* + * Register assoc with thread + */ + assoc->prevKey = NULL; + assoc->nextKey = (ThreadKeyAssoc *) sp->keys; + if (assoc->nextKey != NULL) + assoc->nextKey->prevKey = assoc; + sp->keys = (void *) assoc; + + return (0); +} + +void pte_tkAssocDestroy (ThreadKeyAssoc * assoc) + /* + * ------------------------------------------------------------------- + * This routine releases all resources for the given ThreadKeyAssoc + * once it is no longer being referenced + * ie) either the key or thread has stopped referencing it. + * + * Parameters: + * assoc + * an instance of ThreadKeyAssoc. + * Returns: + * N/A + * ------------------------------------------------------------------- + */ +{ + + /* + * Both key->keyLock and thread->threadLock are locked on + * entry to this routine. + */ + if (assoc != NULL) + { + ThreadKeyAssoc * prev, * next; + + /* Remove assoc from thread's keys chain */ + prev = assoc->prevKey; + next = assoc->nextKey; + if (prev != NULL) + prev->nextKey = next; + if (next != NULL) + next->prevKey = prev; + + /* We're at the head of the thread's keys chain */ + if (assoc->thread->keys == assoc) + assoc->thread->keys = next; + + if (assoc->thread->nextAssoc == assoc) + { + /* + * Thread is exiting and we're deleting the assoc to be processed next. + * Hand thread the assoc after this one. + */ + assoc->thread->nextAssoc = next; + } + + /* Remove assoc from key's threads chain */ + prev = assoc->prevThread; + next = assoc->nextThread; + if (prev != NULL) + prev->nextThread = next; + if (next != NULL) + next->prevThread = prev; + + /* We're at the head of the key's threads chain */ + if (assoc->key->threads == assoc) + assoc->key->threads = next; + + free (assoc); + } +} diff --git a/deps/pthreads/pte_generic_osal.h b/deps/pthreads/pte_generic_osal.h new file mode 100644 index 0000000000..3ce7f4964f --- /dev/null +++ b/deps/pthreads/pte_generic_osal.h @@ -0,0 +1,449 @@ +/* + * 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_ diff --git a/deps/pthreads/pte_main.c b/deps/pthreads/pte_main.c new file mode 100644 index 0000000000..7b6cfb686a --- /dev/null +++ b/deps/pthreads/pte_main.c @@ -0,0 +1,396 @@ +/* + * 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 +#include + +#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); +} diff --git a/deps/pthreads/pthread.c b/deps/pthreads/pthread.c new file mode 100644 index 0000000000..54d87b1339 --- /dev/null +++ b/deps/pthreads/pthread.c @@ -0,0 +1,1017 @@ +/* + * pthread.c + * + * Description: + * POSIX thread functions related to threads. + * + * -------------------------------------------------------------------------- + * + * 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 +#include +#include + +#include + +#include "pthread.h" +#include "implement.h" + +#define PTE_ONCE_STARTED 1 +#define PTE_ONCE_INIT 0 +#define PTE_ONCE_DONE 2 + +static void pte_once_init_routine_cleanup(void * arg) +{ + pthread_once_t * once_control = (pthread_once_t *) arg; + + (void) PTE_ATOMIC_EXCHANGE(&once_control->state,PTE_ONCE_INIT); + + /* MBR fence */ + if (PTE_ATOMIC_EXCHANGE_ADD((int*)&once_control->semaphore, 0L)) + pte_osSemaphorePost((pte_osSemaphoreHandle) once_control->semaphore, 1); +} + +void pthread_testcancel (void) +/* + * ------------------------------------------------------ + * DOCPUBLIC + * This function creates a deferred cancellation point + * in the calling thread. The call has no effect if the + * current cancelability state is + * PTHREAD_CANCEL_DISABLE + * + * PARAMETERS + * N/A + * + * + * DESCRIPTION + * This function creates a deferred cancellation point + * in the calling thread. The call has no effect if the + * current cancelability state is + * PTHREAD_CANCEL_DISABLE + * + * NOTES: + * 1) Cancellation is asynchronous. Use pthread_join + * to wait for termination of thread if necessary + * + * RESULTS + * N/A + * + * ------------------------------------------------------ + */ +{ + pthread_t self = pthread_self (); + pte_thread_t * sp = (pte_thread_t *) self; + + if (sp == NULL) + return; + + /* + * Pthread_cancel() will have set sp->state to PThreadStateCancelPending + * and set an event, so no need to enter kernel space if + * sp->state != PThreadStateCancelPending - that only slows us down. + */ + if (sp->state != PThreadStateCancelPending) + return; + + (void) pthread_mutex_lock (&sp->cancelLock); + + if (sp->cancelState != PTHREAD_CANCEL_DISABLE) + { + sp->state = PThreadStateCanceling; + sp->cancelState = PTHREAD_CANCEL_DISABLE; + + (void) pthread_mutex_unlock (&sp->cancelLock); + pte_throw (PTE_EPS_CANCEL); + } + + (void) pthread_mutex_unlock (&sp->cancelLock); +} + +void pthread_terminate(void) +{ + pte_thread_t * tp, * tpNext; + + if (!pte_processInitialized) + return; + + if (pte_selfThreadKey != NULL) + { + /* + * Release pte_selfThreadKey + */ + pthread_key_delete (pte_selfThreadKey); + + pte_selfThreadKey = NULL; + } + + if (pte_cleanupKey != NULL) + { + /* + * Release pte_cleanupKey + */ + pthread_key_delete (pte_cleanupKey); + + pte_cleanupKey = NULL; + } + + pte_osMutexLock (pte_thread_reuse_lock); + + + tp = pte_threadReuseTop; + while (tp != PTE_THREAD_REUSE_EMPTY) + { + tpNext = tp->prevReuse; + free (tp); + tp = tpNext; + } + + pte_osMutexUnlock(pte_thread_reuse_lock); + + pte_processInitialized = PTE_FALSE; +} + +int pthread_init(void) +{ + /* + * Ignore if already initialized. this is useful for + * programs that uses a non-dll pthread + * library. Such programs must call pte_processInitialize() explicitly, + * since this initialization routine is automatically called only when + * the dll is loaded. + */ + if (pte_processInitialized) + return PTE_TRUE; + + pte_processInitialized = PTE_TRUE; + + // Must happen before creating keys. + pte_osInit(); + + /* + * Initialize Keys + */ + if ((pthread_key_create (&pte_selfThreadKey, NULL) != 0) || + (pthread_key_create (&pte_cleanupKey, NULL) != 0)) + pthread_terminate(); + + /* + * Set up the global locks. + */ + pte_osMutexCreate (&pte_thread_reuse_lock); + pte_osMutexCreate (&pte_mutex_test_init_lock); + pte_osMutexCreate (&pte_cond_list_lock); + pte_osMutexCreate (&pte_cond_test_init_lock); + pte_osMutexCreate (&pte_rwlock_test_init_lock); + pte_osMutexCreate (&pte_spinlock_test_init_lock); + + return (pte_processInitialized); +} + +int pthread_join (pthread_t thread, void **value_ptr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function waits for 'thread' to terminate and + * returns the thread's exit value if 'value_ptr' is not + * NULL. This also detaches the thread on successful + * completion. + * + * PARAMETERS + * thread + * an instance of pthread_t + * + * value_ptr + * pointer to an instance of pointer to void + * + * + * DESCRIPTION + * This function waits for 'thread' to terminate and + * returns the thread's exit value if 'value_ptr' is not + * NULL. This also detaches the thread on successful + * completion. + * NOTE: detached threads cannot be joined or canceled + * + * RESULTS + * 0 'thread' has completed + * EINVAL thread is not a joinable thread, + * ESRCH no thread could be found with ID 'thread', + * ENOENT thread couldn't find it's own valid handle, + * EDEADLK attempt to join thread with self + * + * ------------------------------------------------------ + */ +{ + int result; + pthread_t self; + pte_thread_t * tp = (pte_thread_t *) thread; + + pte_osMutexLock (pte_thread_reuse_lock); + + if (NULL == tp + || ((pte_thread_t*)thread)->x != tp->x) + result = ESRCH; + else if (PTHREAD_CREATE_DETACHED == tp->detachState) + result = EINVAL; + else + result = 0; + + pte_osMutexUnlock(pte_thread_reuse_lock); + + if (result == 0) + { + /* + * The target thread is joinable and can't be reused before we join it. + */ + self = pthread_self(); + + if (NULL == self) + result = ENOENT; + else if (pthread_equal (self, thread)) + result = EDEADLK; + else + { + /* + * Pthread_join is a cancelation point. + * If we are canceled then our target thread must not be + * detached (destroyed). This is guarranteed because + * pthreadCancelableWait will not return if we + * are canceled. + */ + + result = pte_osThreadWaitForEnd(tp->threadId); + + if (PTE_OS_OK == result) + { + if (value_ptr != NULL) + *value_ptr = tp->exitStatus; + + /* + * The result of making multiple simultaneous calls to + * pthread_join() or pthread_detach() specifying the same + * target is undefined. + */ + result = pthread_detach (thread); + } + /* Call was cancelled, but still return success (per spec) */ + else if (result == PTE_OS_INTERRUPTED) + result = 0; + else + result = ESRCH; + } + } + + return (result); +} + +int pthread_cancel (pthread_t thread) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function requests cancellation of 'thread'. + * + * PARAMETERS + * thread + * reference to an instance of pthread_t + * + * + * DESCRIPTION + * This function requests cancellation of 'thread'. + * NOTE: cancellation is asynchronous; use pthread_join to + * wait for termination of 'thread' if necessary. + * + * RESULTS + * 0 successfully requested cancellation, + * ESRCH no thread found corresponding to 'thread', + * ENOMEM implicit self thread create failed. + * ------------------------------------------------------ + */ +{ + int result; + int cancel_self; + pthread_t self; + pte_thread_t * tp; + + result = pthread_kill (thread, 0); + + if (0 != result) + return result; + + if ((self = pthread_self ()) == NULL) + return ENOMEM; + + /* + * FIXME!! + * + * Can a thread cancel itself? + * + * The standard doesn't + * specify an error to be returned if the target + * thread is itself. + * + * If it may, then we need to ensure that a thread can't + * deadlock itself trying to cancel itself asyncronously + * (pthread_cancel is required to be an async-cancel + * safe function). + */ + cancel_self = pthread_equal (thread, self); + + tp = (pte_thread_t *) thread; + + /* + * Lock for async-cancel safety. + */ + (void) pthread_mutex_lock (&tp->cancelLock); + + if (tp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS + && tp->cancelState == PTHREAD_CANCEL_ENABLE + && tp->state < PThreadStateCanceling) + { + if (cancel_self) + { + tp->state = PThreadStateCanceling; + tp->cancelState = PTHREAD_CANCEL_DISABLE; + + (void) pthread_mutex_unlock (&tp->cancelLock); + pte_throw (PTE_EPS_CANCEL); + + /* Never reached */ + } + else + { + /* + * We don't support asynchronous cancellation for thread other than ourselves. + * as it requires significant platform and OS specific functionality (see below). + * + * We should never get here, as we don't allow the cancellability type to be + * sent to async. + * + * If you really wanted to implement async cancellation, you would probably need to + * do something like the Win32 implement did, which is: + * 1. Suspend the target thread. + * 2. Replace the PC for the target thread to a routine that throws an exception + * or does a longjmp, depending on cleanup method. + * 3. Resume the target thread. + * + * Note that most of the async cancellation code is still in here if anyone + * wanted to add the OS/platform specific stuff. + */ + (void) pthread_mutex_unlock (&tp->cancelLock); + + result = EPERM; + + } + } + else + { + /* + * Set for deferred cancellation. + */ + if (tp->state < PThreadStateCancelPending) + { + tp->state = PThreadStateCancelPending; + + if (pte_osThreadCancel(tp->threadId) != PTE_OS_OK) + result = ESRCH; + } + else if (tp->state >= PThreadStateCanceling) + result = ESRCH; + + (void) pthread_mutex_unlock (&tp->cancelLock); + } + + return (result); +} + +/* + * pthread_delay_np + * + * DESCRIPTION + * + * This routine causes a thread to delay execution for a specific period of time. + * This period ends at the current time plus the specified interval. The routine + * will not return before the end of the period is reached, but may return an + * arbitrary amount of time after the period has gone by. This can be due to + * system load, thread priorities, and system timer granularity. + * + * Specifying an interval of zero (0) seconds and zero (0) nanoseconds is + * allowed and can be used to force the thread to give up the processor or to + * deliver a pending cancelation request. + * + * The timespec structure contains the following two fields: + * + * tv_sec is an integer number of seconds. + * tv_nsec is an integer number of nanoseconds. + * + * Return Values + * + * If an error condition occurs, this routine returns an integer value indicating + * the type of error. Possible return values are as follows: + * + * 0 + * Successful completion. + * [EINVAL] + * The value specified by interval is invalid. + * + * Example + * + * The following code segment would wait for 5 and 1/2 seconds + * + * struct timespec tsWait; + * int intRC; + * + * tsWait.tv_sec = 5; + * tsWait.tv_nsec = 500000000L; + * intRC = pthread_delay_np(&tsWait); + */ +int pthread_delay_np (struct timespec *interval) +{ + unsigned int wait_time; + unsigned int secs_in_millisecs; + unsigned int millisecs; + pthread_t self; + pte_thread_t * sp; + + if (interval == NULL) + return EINVAL; + + if (interval->tv_sec == 0L && interval->tv_nsec == 0L) + { + pthread_testcancel (); + pte_osThreadSleep (1); + pthread_testcancel (); + return (0); + } + + /* convert secs to millisecs */ + secs_in_millisecs = interval->tv_sec * 1000L; + + /* convert nanosecs to millisecs (rounding up) */ + millisecs = (interval->tv_nsec + 999999L) / 1000000L; + + wait_time = secs_in_millisecs + millisecs; + + if (NULL == (self = pthread_self ())) + return ENOMEM; + + sp = (pte_thread_t *) self; + + if (sp->cancelState == PTHREAD_CANCEL_ENABLE) + { + pte_osResult cancelStatus; + /* + * Async cancelation won't catch us until wait_time is up. + * Deferred cancelation will cancel us immediately. + */ + cancelStatus = pte_osThreadCheckCancel(sp->threadId); + + if (cancelStatus == PTE_OS_INTERRUPTED) + { + /* + * Canceling! + */ + (void) pthread_mutex_lock (&sp->cancelLock); + if (sp->state < PThreadStateCanceling) + { + sp->state = PThreadStateCanceling; + sp->cancelState = PTHREAD_CANCEL_DISABLE; + (void) pthread_mutex_unlock (&sp->cancelLock); + + pte_throw (PTE_EPS_CANCEL); + } + + (void) pthread_mutex_unlock (&sp->cancelLock); + return ESRCH; + } + else if (cancelStatus != PTE_OS_OK) + return EINVAL; + } + else + + pte_osThreadSleep (wait_time); + + return (0); +} + +int pthread_detach (pthread_t thread) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function detaches the given thread. + * + * PARAMETERS + * thread + * an instance of a pthread_t + * + * + * DESCRIPTION + * This function detaches the given thread. You may use it to + * detach the main thread or to detach a joinable thread. + * NOTE: detached threads cannot be joined; + * storage is freed immediately on termination. + * + * RESULTS + * 0 successfully detached the thread, + * EINVAL thread is not a joinable thread, + * ENOSPC a required resource has been exhausted, + * ESRCH no thread could be found for 'thread', + * + * ------------------------------------------------------ + */ +{ + int result; + unsigned char destroyIt = PTE_FALSE; + pte_thread_t * tp = (pte_thread_t *) thread; + + pte_osMutexLock (pte_thread_reuse_lock); + + if (NULL == tp + || ((pte_thread_t*)thread)->x != tp->x) + result = ESRCH; + else if (PTHREAD_CREATE_DETACHED == tp->detachState) + result = EINVAL; + else + { + /* + * Joinable pte_thread_t structs are not scavenged until + * a join or detach is done. The thread may have exited already, + * but all of the state and locks etc are still there. + */ + result = 0; + + if (pthread_mutex_lock (&tp->cancelLock) == 0) + { + if (tp->state != PThreadStateLast) + tp->detachState = PTHREAD_CREATE_DETACHED; + else if (tp->detachState != PTHREAD_CREATE_DETACHED) + { + /* + * Thread is joinable and has exited or is exiting. + */ + destroyIt = PTE_TRUE; + } + (void) pthread_mutex_unlock (&tp->cancelLock); + } + else + { + /* cancelLock shouldn't fail, but if it does ... */ + result = ESRCH; + } + } + + pte_osMutexUnlock(pte_thread_reuse_lock); + + if (result == 0) + { + /* Thread is joinable */ + + if (destroyIt) + { + /* The thread has exited or is exiting but has not been joined or + * detached. Need to wait in case it's still exiting. + */ + pte_osThreadWaitForEnd(tp->threadId); + + pte_threadDestroy (thread); + } + } + + return (result); +} + +int pthread_equal (pthread_t t1, pthread_t t2) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function returns nonzero if t1 and t2 are equal, else + * returns nonzero + * + * PARAMETERS + * t1, + * t2 + * thread IDs + * + * + * DESCRIPTION + * This function returns nonzero if t1 and t2 are equal, else + * returns zero. + * + * RESULTS + * non-zero if t1 and t2 refer to the same thread, + * 0 t1 and t2 do not refer to the same thread + * + * ------------------------------------------------------ + */ +{ + /* + * We also accept NULL == NULL - treating NULL as a thread + * for this special case, because there is no error that we can return. + */ + int result = ( t1 == t2 && ((pte_thread_t*)t1)->x == ((pte_thread_t*)t2)->x ); + + return (result); +} + +void pthread_exit (void *value_ptr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function terminates the calling thread, returning + * the value 'value_ptr' to any joining thread. + * + * PARAMETERS + * value_ptr + * a generic data value (i.e. not the address of a value) + * + * + * DESCRIPTION + * This function terminates the calling thread, returning + * the value 'value_ptr' to any joining thread. + * NOTE: thread should be joinable. + * + * RESULTS + * N/A + * + * ------------------------------------------------------ + */ +{ + pte_thread_t * sp; + + /* + * Don't use pthread_self() to avoid creating an implicit POSIX thread handle + * unnecessarily. + */ + sp = (pte_thread_t *) pthread_getspecific (pte_selfThreadKey); + + if (NULL == sp) + { + /* + * A POSIX thread handle was never created. I.e. this is a + * Win32 thread that has never called a pthreads-win32 routine that + * required a POSIX handle. + * + * Implicit POSIX handles are cleaned up in pte_throw() now. + */ + + /* Terminate thread */ + pte_osThreadExit(); + + /* Never reached */ + } + + sp->exitStatus = value_ptr; + + pte_throw (PTE_EPS_EXIT); + + /* Never reached. */ +} + +int pthread_once (pthread_once_t * once_control, void (*init_routine) (void)) +/* + * ------------------------------------------------------ + * DOCPUBLIC + * If any thread in a process with a once_control parameter + * makes a call to pthread_once(), the first call will summon + * the init_routine(), but subsequent calls will not. The + * once_control parameter determines whether the associated + * initialization routine has been called. The init_routine() + * is complete upon return of pthread_once(). + * This function guarantees that one and only one thread + * executes the initialization routine, init_routine when + * access is controlled by the pthread_once_t control + * key. + * + * pthread_once() is not a cancelation point, but the init_routine + * can be. If it's cancelled then the effect on the once_control is + * as if pthread_once had never been entered. + * + * + * PARAMETERS + * once_control + * pointer to an instance of pthread_once_t + * + * init_routine + * pointer to an initialization routine + * + * + * DESCRIPTION + * See above. + * + * RESULTS + * 0 success, + * EINVAL once_control or init_routine is NULL + * + * ------------------------------------------------------ + */ +{ + int result; + int state; + pte_osSemaphoreHandle sema; + + if (once_control == NULL || init_routine == NULL) + { + result = EINVAL; + goto FAIL0; + } + else + { + result = 0; + } + + while ((state = + PTE_ATOMIC_COMPARE_EXCHANGE(&once_control->state, + PTE_ONCE_STARTED, + PTE_ONCE_INIT)) + != PTE_ONCE_DONE) + { + if (PTE_ONCE_INIT == state) + { + + + pthread_cleanup_push(pte_once_init_routine_cleanup, (void *) once_control); + (*init_routine)(); + pthread_cleanup_pop(0); + + (void) PTE_ATOMIC_EXCHANGE(&once_control->state,PTE_ONCE_DONE); + + /* + * we didn't create the semaphore. + * it is only there if there is someone waiting. + */ + if (PTE_ATOMIC_EXCHANGE_ADD((int*)&once_control->semaphore, 0L)) /* MBR fence */ + pte_osSemaphorePost((pte_osSemaphoreHandle) once_control->semaphore,once_control->numSemaphoreUsers); + } + else + { + PTE_ATOMIC_INCREMENT(&once_control->numSemaphoreUsers); + + if (!PTE_ATOMIC_EXCHANGE_ADD((int*)&once_control->semaphore, 0L)) /* MBR fence */ + { + pte_osSemaphoreCreate(0, (pte_osSemaphoreHandle*) &sema); + + if (PTE_ATOMIC_COMPARE_EXCHANGE((int *) &once_control->semaphore, + (int) sema, + 0)) + pte_osSemaphoreDelete((pte_osSemaphoreHandle)sema); + } + + /* + * Check 'state' again in case the initting thread has finished or + * cancelled and left before seeing that there was a semaphore. + */ + if (PTE_ATOMIC_EXCHANGE_ADD(&once_control->state, 0L) == PTE_ONCE_STARTED) + pte_osSemaphorePend((pte_osSemaphoreHandle) once_control->semaphore,NULL); + + if (0 == PTE_ATOMIC_DECREMENT(&once_control->numSemaphoreUsers)) + { + /* we were last */ + if ((sema = + (pte_osSemaphoreHandle) PTE_ATOMIC_EXCHANGE((int *) &once_control->semaphore,0))) + pte_osSemaphoreDelete(sema); + } + } + } + + /* + * ------------ + * Failure Code + * ------------ + */ +FAIL0: + return (result); +} + +pthread_t pthread_self (void) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function returns a reference to the current running + * thread. + * + * PARAMETERS + * N/A + * + * + * DESCRIPTION + * This function returns a reference to the current running + * thread. + * + * RESULTS + * pthread_t reference to the current thread + * + * ------------------------------------------------------ + */ +{ + pthread_t self; + pte_thread_t * sp; + + sp = (pte_thread_t *) pthread_getspecific (pte_selfThreadKey); + + if (sp != NULL) + self = sp; + else + { + /* + * Need to create an implicit 'self' for the currently + * executing thread. + * + * Note that this is a potential memory leak as there is + * no way to free the memory and any resources allocated + * by pte_new! + */ + self = pte_new (); + sp = (pte_thread_t *) self; + + if (sp != NULL) + { + /* + * This is a non-POSIX thread which has chosen to call + * a POSIX threads function for some reason. We assume that + * it isn't joinable, but we do assume that it's + * (deferred) cancelable. + */ + sp->implicit = 1; + sp->detachState = PTHREAD_CREATE_DETACHED; + + sp->threadId = pte_osThreadGetHandle(); + /* + * No need to explicitly serialise access to sched_priority + * because the new handle is not yet public. + */ + sp->sched_priority = 0; + + pthread_setspecific (pte_selfThreadKey, (void *) sp); + } + } + + return (self); +} + +/* + * Notes on handling system time adjustments (especially negative ones). + * --------------------------------------------------------------------- + * + * This solution was suggested by Alexander Terekhov, but any errors + * in the implementation are mine - [Ross Johnson] + * + * 1) The problem: threads doing a timedwait on a CV may expect to timeout + * at a specific absolute time according to a system timer. If the + * system clock is adjusted backwards then those threads sleep longer than + * expected. Also, pthreads-embedded converts absolute times to intervals in + * order to make use of the underlying OS, and so waiting threads may + * awake before their proper abstimes. + * + * 2) We aren't able to distinquish between threads on timed or untimed waits, + * so we wake them all at the time of the adjustment so that they can + * re-evaluate their conditions and re-compute their timeouts. + * + * 3) We rely on correctly written applications for this to work. Specifically, + * they must be able to deal properly with spurious wakeups. That is, + * they must re-test their condition upon wakeup and wait again if + * the condition is not satisfied. + */ + +void * +pthread_timechange_handler_np (void *arg) +/* + * ------------------------------------------------------ + * DOCPUBLIC + * Broadcasts all CVs to force re-evaluation and + * new timeouts if required. + * + * PARAMETERS + * NONE + * + * + * DESCRIPTION + * Broadcasts all CVs to force re-evaluation and + * new timeouts if required. + * + * This routine may be passed directly to pthread_create() + * as a new thread in order to run asynchronously. + * + * + * RESULTS + * 0 successfully broadcast all CVs + * EAGAIN Not all CVs were broadcast + * + * ------------------------------------------------------ + */ +{ + int result = 0; + pthread_cond_t cv; + + pte_osMutexLock (pte_cond_list_lock); + + cv = pte_cond_list_head; + + while (cv != NULL && 0 == result) + { + result = pthread_cond_broadcast (&cv); + cv = cv->next; + } + + pte_osMutexUnlock(pte_cond_list_lock); + + return (void *) (result != 0 ? EAGAIN : 0); +} + +int pthread_kill (pthread_t thread, int sig) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function requests that a signal be delivered to the + * specified thread. If sig is zero, error checking is + * performed but no signal is actually sent such that this + * function can be used to check for a valid thread ID. + * + * PARAMETERS + * thread reference to an instances of pthread_t + * sig signal. Currently only a value of 0 is supported. + * + * + * DESCRIPTION + * This function requests that a signal be delivered to the + * specified thread. If sig is zero, error checking is + * performed but no signal is actually sent such that this + * function can be used to check for a valid thread ID. + * + * RESULTS + * ESRCH the thread is not a valid thread ID, + * EINVAL the value of the signal is invalid + * or unsupported. + * 0 the signal was successfully sent. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + pte_thread_t * tp; + + pte_osMutexLock (pte_thread_reuse_lock); + + tp = (pte_thread_t *) thread; + + if (NULL == tp + || ((pte_thread_t*)thread)->x != tp->x + || 0 == tp->threadId) + result = ESRCH; + + pte_osMutexUnlock(pte_thread_reuse_lock); + + /* + * Currently does not support any signals. + */ + if (0 == result && 0 != sig) + result = EINVAL; + + return result; +} + +/* + * pthread_num_processors_np() + * + * Get the number of CPUs available to the process. + */ +int pthread_num_processors_np (void) +{ + int count; + + if (pte_getprocessors (&count) != 0) + count = 1; + + return (count); +} diff --git a/deps/pthreads/pthread.h b/deps/pthreads/pthread.h new file mode 100644 index 0000000000..805bdd752b --- /dev/null +++ b/deps/pthreads/pthread.h @@ -0,0 +1,891 @@ +/* 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 + +#include + +#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 + * + * 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 + +#include +#include + +/* + * 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 , 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 , 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 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 */ diff --git a/deps/pthreads/pthread_attr.c b/deps/pthreads/pthread_attr.c new file mode 100644 index 0000000000..462f5bad81 --- /dev/null +++ b/deps/pthreads/pthread_attr.c @@ -0,0 +1,581 @@ +/* + * 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 +#include + +#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 */ +} diff --git a/deps/pthreads/pthread_barrier.c b/deps/pthreads/pthread_barrier.c new file mode 100644 index 0000000000..23cd362122 --- /dev/null +++ b/deps/pthreads/pthread_barrier.c @@ -0,0 +1,163 @@ +/* + * 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 + +#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); +} diff --git a/deps/pthreads/pthread_barrierattr.c b/deps/pthreads/pthread_barrierattr.c new file mode 100644 index 0000000000..fc14ea78b2 --- /dev/null +++ b/deps/pthreads/pthread_barrierattr.c @@ -0,0 +1,257 @@ +/* + * 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 + +#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 */ diff --git a/deps/pthreads/pthread_cond.c b/deps/pthreads/pthread_cond.c new file mode 100644 index 0000000000..6d3f8eb47e --- /dev/null +++ b/deps/pthreads/pthread_cond.c @@ -0,0 +1,807 @@ +/* + * 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 + +#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)); +} diff --git a/deps/pthreads/pthread_condattr.c b/deps/pthreads/pthread_condattr.c new file mode 100644 index 0000000000..1002769506 --- /dev/null +++ b/deps/pthreads/pthread_condattr.c @@ -0,0 +1,259 @@ +/* + * 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 + +#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; + +} diff --git a/deps/pthreads/pthread_get.c b/deps/pthreads/pthread_get.c new file mode 100644 index 0000000000..812da5a882 --- /dev/null +++ b/deps/pthreads/pthread_get.c @@ -0,0 +1,111 @@ +/* + * 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); +} diff --git a/deps/pthreads/pthread_key.c b/deps/pthreads/pthread_key.c new file mode 100644 index 0000000000..63dfb8d978 --- /dev/null +++ b/deps/pthreads/pthread_key.c @@ -0,0 +1,204 @@ +/* + * 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 +#include + +#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); +} diff --git a/deps/pthreads/pthread_mutex.c b/deps/pthreads/pthread_mutex.c new file mode 100644 index 0000000000..489dc6fcdc --- /dev/null +++ b/deps/pthreads/pthread_mutex.c @@ -0,0 +1,500 @@ +/* + * 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 +#include +#include + +#include + +#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); +} diff --git a/deps/pthreads/pthread_mutexattr.c b/deps/pthreads/pthread_mutexattr.c new file mode 100644 index 0000000000..8b6481cd06 --- /dev/null +++ b/deps/pthreads/pthread_mutexattr.c @@ -0,0 +1,377 @@ +/* + * 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 + +#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); +} diff --git a/deps/pthreads/pthread_rwlock.c b/deps/pthreads/pthread_rwlock.c new file mode 100644 index 0000000000..47aa0c7e95 --- /dev/null +++ b/deps/pthreads/pthread_rwlock.c @@ -0,0 +1,676 @@ +/* + * 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 +#include +#include + +#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; +} diff --git a/deps/pthreads/pthread_rwlockattr.c b/deps/pthreads/pthread_rwlockattr.c new file mode 100644 index 0000000000..727183a25b --- /dev/null +++ b/deps/pthreads/pthread_rwlockattr.c @@ -0,0 +1,259 @@ +/* + * 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 +#include +#include + +#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 */ diff --git a/deps/pthreads/pthread_set.c b/deps/pthreads/pthread_set.c new file mode 100644 index 0000000000..3239760b03 --- /dev/null +++ b/deps/pthreads/pthread_set.c @@ -0,0 +1,399 @@ +/* + * 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); +} diff --git a/deps/pthreads/pthread_spin.c b/deps/pthreads/pthread_spin.c new file mode 100644 index 0000000000..242bf54135 --- /dev/null +++ b/deps/pthreads/pthread_spin.c @@ -0,0 +1,295 @@ +/* + * 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 + +#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; +} diff --git a/deps/pthreads/sched.c b/deps/pthreads/sched.c new file mode 100644 index 0000000000..64a337323a --- /dev/null +++ b/deps/pthreads/sched.c @@ -0,0 +1,101 @@ +/* + * 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 +#include + +#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(); +} diff --git a/deps/pthreads/sched.h b/deps/pthreads/sched.h new file mode 100644 index 0000000000..464d0395f9 --- /dev/null +++ b/deps/pthreads/sched.h @@ -0,0 +1,137 @@ +/* + * 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 + +#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 */ + diff --git a/deps/pthreads/sem.c b/deps/pthreads/sem.c new file mode 100644 index 0000000000..6a8d82ba0f --- /dev/null +++ b/deps/pthreads/sem.c @@ -0,0 +1,895 @@ +/* + * ------------------------------------------------------------- + * + * 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 +#include + +#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; +} diff --git a/deps/pthreads/semaphore.h b/deps/pthreads/semaphore.h new file mode 100644 index 0000000000..08388fbb1d --- /dev/null +++ b/deps/pthreads/semaphore.h @@ -0,0 +1,114 @@ +/* + * 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 */