Compare commits

...
364 Commits
Author SHA1 Message Date
Autechre 4a6dc36b1c Update CHANGES.md 2021-07-04 02:39:40 +02:00
Autechre c6967f56bd Merge pull request #12606 from jdgleaver/hide-add-to-favourites
Hide 'Add to Favorites' when viewing an entry of the favorites playlist
2021-07-02 23:20:56 +02:00
jdgleaver 0e654c8e9e Hide 'Add to Favorites' when viewing an entry of the favorites playlist 2021-07-02 16:29:11 +01:00
Autechre e1270742b9 Merge pull request #12582 from markwkidd/input-drivers
add comments in order to document input_driver.h
2021-07-02 00:21:09 +02:00
Autechre 1c87853496 Merge pull request #12595 from IlDucci/translationsupdatewithscript
Fetch translations from Crowdin 30-Jun-2021
2021-07-01 09:03:32 +02:00
Autechre 119788593c Merge pull request #12598 from markwkidd/input-cleanup
remove unused enum input_device_type from input_driver.h
2021-07-01 04:29:51 +02:00
Mark W. Kidd fb2b3695d9 remove unused enum input_device_type 2021-06-30 19:05:56 -04:00
IlDucci aacf2bed34 Fetch translations from Crowdin 30-Jun-2021 2021-06-30 14:54:34 +02:00
Autechre badd588652 Merge pull request #12590 from jdgleaver/playlist-path-id-cache
(Playlist) Optimise scanning of large rom sets
2021-06-30 05:08:10 +02:00
Autechre a40c3767bb Merge pull request #12591 from jdgleaver/qt-default-core-fix
(Qt) Fix default core detection when playlist file name does not match 'db_name'
2021-06-30 05:07:57 +02:00
Mark W. Kidd b0831bf1a0 comment documentation for input_driver.h 2021-06-29 20:12:44 -04:00
jdgleaver d1f7d8af0d (Qt) Fix default core detection when playlist file name does not match 'db_name' 2021-06-29 16:51:20 +01:00
jdgleaver f7f007519c (Playlist) Optimise scanning of large rom sets 2021-06-29 14:50:19 +01:00
Autechre 92a098ee02 Merge pull request #12586 from jdgleaver/archive-delim-fix
Fix archive delimiter detection when file path contains no slashes
2021-06-29 00:10:46 +02:00
M4xw d00c2a6407 [Libnx] Style nits 2021-06-28 17:38:17 +02:00
M4xw 991b43d4ee [Libnx] Changed PSM Defines 2021-06-28 17:38:17 +02:00
p-sam ac8a977492 Replace deprecated HID APIs 2021-06-28 17:38:17 +02:00
p-sam 1bc588acbd Fix building with libnx 4.0.0 2021-06-28 17:38:17 +02:00
jdgleaver eafeb83d0b Fix archive delimiter detection when file path contains no slashes 2021-06-28 10:40:37 +01:00
Autechre 2e215bda5b Update CHANGES.md 2021-06-27 07:03:00 +02:00
twinaphex 0a5fd837a2 Bump up version to 1.9.6 2021-06-27 06:43:27 +02:00
Autechre edf10b576f Merge pull request #12580 from john-parton/bugfix/rg350_stripping
Remove bash-ism which was preventing strip from working on OpenDingux
2021-06-27 06:08:32 +02:00
twinaphex 46dcf1204e Revert "Backport tunip3 - replace win32 functions with UWP safe variants in UWP vfs driver"
This reverts commit 585af66b5c.
2021-06-27 05:39:48 +02:00
John Parton 5feeb362b1 Remove bash-ism which was preventing strip from working on OpenDingux 2021-06-26 21:08:22 -05:00
Autechre 67358fb145 Merge pull request #12578 from libretro/revert-12571-bugfix/rg350_stripping
Revert "Fix strip on rg350 and rg350_odbeta"
2021-06-26 23:45:13 +02:00
Autechre 41fbbda8e8 Revert "Fix strip on rg350 and rg350_odbeta" 2021-06-26 23:45:06 +02:00
Autechre bd1d39d7fb Merge pull request #12571 from john-parton/bugfix/rg350_stripping
Fix strip on rg350 and rg350_odbeta
2021-06-26 19:09:45 +02:00
twinaphex b2c7fae912 desc.Flags should also be commented out for now 2021-06-26 05:46:37 +02:00
twinaphex 13e88ebe74 (D3D11) Disable tear control support for UWP for now 2021-06-26 05:40:41 +02:00
John Parton d5d6b1d91e Make stripping conditional again on rg350 builds (remove bashism) 2021-06-25 12:09:36 -05:00
John Parton 8915d82fd6 Always strip on rg350 and rg350_odbeta 2021-06-25 00:32:38 -05:00
Autechre 0785d4aa72 Merge pull request #12565 from Jamiras/measured_unlock
(cheevos) reset cached progress each time menu is opened
2021-06-24 05:48:23 +02:00
Jamiras 0744683c2b reset cached progress each time menu is opened 2021-06-23 17:29:12 -06:00
twinaphex 55afe18872 Move D3D11Draw call back for now - should make OSK work again and
shaders
2021-06-23 19:34:06 +02:00
Autechre f83e614b4e Merge pull request #12563 from IlDucci/translationsupdatewithscript2
'Fetch translations from Crowdin 23-Jun-2021'
2021-06-23 18:46:30 +02:00
Autechre 5dc070f041 Merge pull request #12562 from jdgleaver/input-adc-type-improvements
'Analog to Digital Type' usability improvements
2021-06-23 18:46:05 +02:00
twinaphex 585af66b5c Backport tunip3 - replace win32 functions with UWP safe variants in UWP vfs driver 2021-06-23 18:45:07 +02:00
IlDucci c8241f3f21 'Fetch translations from Crowdin 23-Jun-2021' 2021-06-23 16:00:53 +02:00
jdgleaver 3a82cf980d 'Analog to Digital Type' usability improvements 2021-06-23 14:28:45 +01:00
Autechre 7b47f5f49a Merge pull request #12556 from sonninnos/winraw-mouse
(WINRAW) Mouse access violation fix
2021-06-23 00:19:37 +02:00
Autechre 94e4b1883a Merge pull request #12557 from grant2258/logging
fix up logging that can confuse users
2021-06-23 00:18:40 +02:00
Grant c73592d379 skip mouse with no button errors and keep the rest 2021-06-22 23:00:50 +01:00
Grant 4ba0ba4c70 fix up logging that can confuse users 2021-06-22 22:06:19 +01:00
sonninnos 11dba60ea7 (WINRAW) Mouse access violation fix 2021-06-22 19:47:56 +03:00
twinaphex 97ad8cbfd2 Remove this code for Vulkan over X too 2021-06-22 18:26:32 +02:00
twinaphex b5be2006f2 Remove commented out code 2021-06-22 18:25:54 +02:00
Autechre 8ec39ca7ec Merge pull request #12550 from grant2258/fix_x11
fix x11 threaded videoc segfault
2021-06-22 18:24:32 +02:00
Autechre bd937eb49f Merge pull request #12536 from grant2258/udev
only add mouse if it has buttons and add vebose device friendly names
2021-06-22 17:23:19 +02:00
Autechre 23b810b820 Merge pull request #12552 from stenzek/fix-d3d11-again
(d3d11) Fix non-vsynced output without flip, black screens in fullscreen
2021-06-22 13:40:01 +02:00
Connor McLaughlin 322aeb4e46 (d3d11) Don't pass ALLOW_TEARING to present when unsupported 2021-06-22 14:04:32 +10:00
Connor McLaughlin ed2d6b1730 (d3d11) Don't draw content without a texture bound 2021-06-22 14:04:32 +10:00
Connor McLaughlin 9afa30af5e (d3d11) Disable DXGI's ALT+ENTER handling 2021-06-22 14:04:31 +10:00
Connor McLaughlin 5d3719df44 (gfx) Fix uninitialized variables in gfx_display_draw_cursor 2021-06-22 13:52:13 +10:00
twinaphex 3f00d2f041 (Resampler) Cleanups 2021-06-22 01:14:32 +02:00
twinaphex a30a86a09c (D3D11) Fixes Xbox again, do tear control checks only for non-UWP
- TODO/FIXME still has to be resolved, see comment at line 1362
2021-06-22 00:41:56 +02:00
Grant bd10e5bdc3 fix x11 threaded videoc segfault 2021-06-21 21:12:26 +01:00
twinaphex 0e1d5ba30e Silence some warnings; cleanup 2021-06-21 21:15:03 +02:00
Autechre 10f42d7034 Merge pull request #12549 from sonninnos/xmb-opacity
(XMB) Icon opacity fix
2021-06-21 20:48:19 +02:00
Autechre 6986caed5b Merge pull request #11388 from pjft/dual-lightgun
Change udev driver for dual lightgun support in X11
2021-06-21 18:06:35 +02:00
sonninnos c802a549f6 (XMB) Icon opacity fix 2021-06-21 16:46:58 +03:00
Autechre 0a75b51b29 Merge pull request #12534 from jdgleaver/input-port-remapping
Add support for mapping multiple controllers to a single input device
2021-06-21 15:28:34 +02:00
Autechre 0c64ac0bde Merge pull request #12423 from markwkidd/lightgun-bind
bind lightgun trigger to first mouse button by default
2021-06-21 14:12:25 +02:00
Autechre 15b0f5478f Merge pull request #12485 from Kopert/master
Add support for core and directory overrides of switchres.ini files
2021-06-21 14:12:15 +02:00
Autechre a6b0199204 Merge pull request #12511 from markwkidd/android-input-fix
[Android input driver] do not duplicate port 0 mouse and gun inputs to other ports
2021-06-21 14:12:02 +02:00
jdgleaver 973f5cda6d Add support for mapping multiple controllers to a single input device 2021-06-21 12:42:38 +01:00
twinaphex 46a318db45 C89 buildfix 2021-06-20 23:02:55 +02:00
Autechre 7949a9c8ad Merge pull request #12528 from IlDucci/crowdinfix-20210615
Fix Encore Mode on Github, minor English change
2021-06-20 16:55:07 +02:00
Autechre 2ae11b7222 Merge pull request #12541 from sonninnos/xmb-dynamic
(XMB) Dynamic wallpaper improvement
2021-06-20 16:54:49 +02:00
Autechre f05c124c98 Merge pull request #12540 from sonninnos/d3d12
D3D12 Updates
2021-06-20 14:59:11 +02:00
Alcaro 5f182fa564 Don't send speech input as command line argument (#12539)
* Don't send speech input as command line argument

* Fix a C++-only construct, and simplify some stuff
2021-06-20 14:39:14 +02:00
Kopert c2d5003f80 Add support for switchres.ini core and directory overrides 2021-06-20 02:31:10 -03:00
Grant 6e2709d62a cleanup 2021-06-19 08:47:35 +01:00
Grant eef86d5f72 fix game focus mode 2021-06-19 07:59:06 +01:00
Grant 863aaa5b9d Revert "fix game focus mode on udev as well"
This reverts commit 54eed63418.
2021-06-19 07:44:02 +01:00
Grant 54eed63418 fix game focus mode on udev as well 2021-06-19 07:00:09 +01:00
sonninnos 7695298dfc (XMB) Dynamic wallpaper improvement 2021-06-18 23:03:34 +03:00
sonninnos 917fb1f796 D3D12 Updates:
- Relocated 'd3d12_gfx_sync()'
- Fixed swap interval option
- Cleanups
2021-06-18 21:54:36 +03:00
Jamiras 81075aa5fa put challenge indicator above leaderboard trackers (#12530) 2021-06-18 18:00:48 +02:00
Tony ff7982fbcd (XMB) Dynamic wallpaper fix (#12531) 2021-06-18 18:00:37 +02:00
Grant 7915b040a9 only add mouse if it ha buttons and add vebose device friendly names 2021-06-18 03:55:25 +01:00
twinaphex a129764f0d Change C++ comment to C 2021-06-17 05:45:59 +02:00
Alcaro aeddcb54e0 Plug this so-called high-risk vuln (#12533)
https://www.reddit.com/r/RetroArch/comments/o0p1vy/retroarch_for_windows_versions_190_194_highrisk/

https://labs.bishopfox.com/advisories/retroarch-for-windows-version-1.9.0
2021-06-17 05:44:17 +02:00
Michael BurgardtandMichael Burgardt 10f0073778 adjust h2json and json2h scripts to be comment agnostic (#12532)
Co-authored-by: Michael Burgardt <[email protected]>
2021-06-16 17:21:57 +02:00
twinaphex 8b6e58eebd Buildfix for D3D11 - courtesy of Stenzek 2021-06-16 16:07:38 +02:00
Tony 49bd8d2d27 (XAudio+DSound) Fail instead of crash (#12527) 2021-06-16 15:35:20 +02:00
Connor McLaughlin 946d87cf89 (gfx/d3d11) Don't use allow tearing flag with blit swap chains (#12529) 2021-06-16 15:19:27 +02:00
IlDucci 138d5b3a4e Fix Encore Mode on Github, minor English change
- Fixes the Encore Mode string being misread by the Crowdin scripts.
 - Minor change on MENU_ENUM_SUBLABEL_CRT_SWITCH_HIRES_MENU's structure (by @DisasterMo, he asked me to do so).
2021-06-15 11:33:50 +02:00
Víctor "IlDucci cdba9accdf [Localization] Manually updating the .h translation files (#12494)
Second attempt at manually updating the translations from Crowdin. Built locally today.

Huge thanks to @DisasterMo for helping with the required edits on the python files (not uploaded to avoid messing with guoyunhe's setup)!

Moving the comment that breaks the script to a better position.
2021-06-15 03:04:49 +02:00
tunip3 963350a0f2 Add expanded resources Rescap to increase performance of UWP version in app mode on Xbox (#12525)
* add expanded resources rescap

* add expanded resources rescap
2021-06-15 03:04:10 +02:00
Michael Burgardt dd48b65687 Fix Switchres menu texts (#12526) 2021-06-15 03:03:10 +02:00
jdgleaver 642d6c9fb8 (Ozone) Ensure sidebar display status is updated correctly when performing rapid menu navigation (#12524) 2021-06-14 13:58:39 +02:00
twinaphex 6738fa57aa Bump up version to 1.9.5 2021-06-13 03:07:51 +02:00
jdgleaver d40d7c389b (Dingux) Fix black screens when triggering gfx driver reinitialisation via menu actions (#12521) 2021-06-13 00:37:48 +02:00
jdgleaver 3c2e3f1ce9 Add enhanced search functionality to the 'Manage Cores' menu (#12516) 2021-06-11 21:17:32 +02:00
twinaphex 766c59d469 Apply this to make MSVC 2005 compile with new resampler 2021-06-11 12:07:16 +02:00
twinaphex 7492f5d60c Revert "Add HAVE_GRIFFIN fallback for now"
This reverts commit dc50ff584e.
2021-06-11 12:05:59 +02:00
twinaphex bd9c35d379 Revert "Rollback changes for now until we can get this compiling on MSVC 2005 on"
This reverts commit 08481e2a68.
2021-06-11 12:05:48 +02:00
Jamiras 5d4069cf8f update to rcheevos 10.1 (#12512) 2021-06-10 17:20:00 +02:00
dankcushions 0caeed6e1d Make alsathread default for all alsa devices with threads. (#12515) 2021-06-10 17:19:52 +02:00
Bernhard Schelling 98194ce135 Allow the 8 analog stick directions to be used as keys for core keyboard mappings (#12506) 2021-06-10 17:00:33 +02:00
Michael Burgardt 4dcda032d0 Added list entry enumeration to XMB (#12427) 2021-06-10 16:02:19 +02:00
Mark W. Kidd f74fddf3fd do not duplicate port 0 mouse and gun inputs to other ports 2021-06-09 17:20:13 -04:00
twinaphex 08481e2a68 Rollback changes for now until we can get this compiling on MSVC 2005 on
the commandline (it builds with the VS solution file but not CLI)
2021-06-09 16:39:43 +02:00
twinaphex dc50ff584e Add HAVE_GRIFFIN fallback for now 2021-06-09 16:33:32 +02:00
Tony 3647bdef0f (D3D) Logging + dupe code cleanups (#12501) 2021-06-09 06:33:14 +02:00
Jamiras 75fcd63b4a (cheevos) use common functionality moved into rcheevos (#12504)
* user rcheevos for disallowed_settings

* use rcheevos for memory map
2021-06-09 06:32:34 +02:00
Tony 27cacffe54 Fix frame delay limit in conf read (#12507) 2021-06-09 06:32:01 +02:00
Autechre 74d85e3269 Backport optimizations from foobar2K 2021-06-09 06:05:14 +02:00
twinaphex 9d92888846 Add else path for defining SR_CONFIG_PATH 2021-06-07 19:15:37 +02:00
jdgleaver adfabcb742 Fix '--disable-crtswitchres' configure option (#12500) 2021-06-07 17:39:18 +02:00
twinaphex 620302ddaa (Switchres) Fix debug 2021-06-07 15:59:39 +02:00
Autechre da9f87c63f Update CHANGES.md 2021-06-07 15:54:08 +02:00
Autechre fe2fd18aad Merge pull request #12496 from sonninnos/framedelay-range
Extend frame delay range
2021-06-07 15:53:09 +02:00
Autechre 1c61068291 Merge pull request #12498 from JustMeDaFaq/master
Fixing UWP builds
2021-06-07 15:52:55 +02:00
Autechre 681983d1b2 Merge pull request #12499 from fjtrujy/psp-remove-pthread
[PSP] Remove embedded PTE from RA and use the one provided by the toolchain
2021-06-07 15:52:35 +02:00
Francisco Javier Trujillo Mata ec627a9c00 Remove embedded PTE from RA and use the one provided by the toolchain 2021-06-07 12:48:13 +02:00
JustMeDaFaq 462cedb654 Update d3d12.c 2021-06-07 12:04:53 +02:00
JustMeDaFaq f1347829c2 Update d3d11.c 2021-06-07 12:03:58 +02:00
sonninnos b08169255d Extend frame delay range 2021-06-07 03:13:08 +03:00
Autechre 610b0b7095 Update CHANGES.md 2021-06-06 22:16:25 +02:00
Autechre caf3f3dadd Merge pull request #12480 from sonninnos/d3d-title
(D3D) Add common window title for D3D9+
2021-06-06 21:48:16 +02:00
sonninnos 04962e1741 (D3D) Add common window title for D3D9+ 2021-06-06 22:24:47 +03:00
Autechre 44e2530fbb Update CHANGES.md 2021-06-06 21:18:02 +02:00
Autechre 52b827155f Merge pull request #12479 from sonninnos/d3d-tearflag
(D3D11+12) Allow fastforward in fullscreen
2021-06-06 21:14:26 +02:00
Autechre 3eecf92f8f Merge pull request #12493 from alphanu1/master
Ver 0.10.0 SR2 (Switchres API) Implimantation
2021-06-06 18:32:58 +02:00
Ben 9184a9d04c Ver 0.10.0 SR2 (Switchres API) Implimantation
merged SR updates

Fixed sub labels

fixed PI compiile

Removed SR makefile
2021-06-06 09:05:10 -07:00
Autechre 5534fd7275 Merge pull request #12490 from Alcaro/patch-12
Shut up a string truncation warning
2021-06-05 21:19:48 +02:00
Alcaro 8e06aa2417 Shut up a string truncation warning 2021-06-05 20:53:45 +02:00
Autechre f57fcd4048 Merge pull request #12489 from Jamiras/cheevos_challenge_indicators
(cheevos) address travis errors
2021-06-05 17:37:06 +02:00
Autechre 4b4576ed62 Merge pull request #12457 from libretro/vita-sounds
VIta: Enable menu sounds
2021-06-05 17:31:22 +02:00
Jamiras 9f8092dc27 address travis errors 2021-06-05 08:10:14 -06:00
Autechre e40f0d308b Merge pull request #12488 from Jamiras/cheevos_challenge_indicators
(cheevos) challenge indicators
2021-06-05 16:02:38 +02:00
Autechre 2259e9b38e Merge pull request #12403 from alphanu1/master
New Switchres (CRT Resolution switching) For Retroarch
2021-06-05 00:27:00 +02:00
twinaphex e44f0749a1 Put this behind HAVE_LANGEXTRA 2021-06-04 20:50:21 +02:00
Jamiras 3fe52bb7fb add toggle/setting for challenge indicators 2021-06-04 12:32:01 -06:00
Autechre 2edc6d6e6a Update CHANGES.md 2021-06-04 20:20:46 +02:00
Autechre fce9da5e76 Merge pull request #12445 from toshixm/CJK_folding_rev2
Improve message wrapping with CJK languages
2021-06-04 20:14:55 +02:00
Ben 4b2f27eff8 Ver 0.9.2 SR2 (Switchres API) Implimantation
Fixed SR close match refresh bug.
Added menu high resolution option.
Fixed desktop restore bug cuusing endless resolution change requests.
Fixed file conflicts
Added destop restore resolution back in for manu only.
Pulled Switchres fixes.
Added better PI rsolution support.

Ver 0.7 SR2 (Switchres API) Implimantation

Removed HH experimetal check. This is better done via teh switchres.ini at present.
Fixed refresh rate bug. Now new resolution and refesh is added correctly.
Removed SR deinit from menu restore. Meanu now stays at last content resolution.

Ver 0.6.2 SR2 (Switchres API) Implimantation

Fixed super resolution bug casuing abnormal video size and aspect ratio
Fixed logging issue casuing seg falts on RA exit

Ver 0.6 SR2 (Switchres API) Implimantation

Ver 0.2 SR2 (Switchres API) Implimantation

Added forced super resolutions.
Added Multi-monitor/monitor selection support.
Added desktop resolution restore when switching back to menu only.
Added new menu items for 31KHz standard and 120hz monitor profiles.
Added new menu item INI. load monitor profile from switchrss.ini.
Fixed winraw driver. Coordinates new refreshed after a resolution change.
Fixed Menu aspect ratio in super resolutions.
Removed static glabals. These have been added to videocrt_switch struct.

Ver 0.1 SR2 (Switchres API) Implimantation

Removed old CRTSwitchRes method. Added new SR2 API implimantaion.
Resolution swithcing is now done by switchres libs. Both Linux and Windows
working with native and super resolutions. Working multi-monitor support
with monitor index selection. Working 31KHz support with standard and 120Hxz
modes. The monitor index selection is still done via the RA UI. Only choose
native and 15KHz form the CRT options in the RA UI as all options are now set
in the switchres.ini. All other CRT optoins in the RA UI currently do nothing.

Added SR wrapper to fix compile issues. Added back RPi functionality

Fixed windows resize/scaling issues on resolution change

Thanks @Calamity no more need for crt_switch_driver_refresh()

Fix broken case after prevous commit

Monitor preset options 15/31KHz now active. Added new meu option.

Moitor persets can now be choosen fom the RA UI. 15KHz and 31KHz will set
arcade_15 and aracde_31 respectivly. New option INI, if this is chosen your
monitor preset will be selected from your switchres.ini file.

Added 3KHhz, 120Hz. for old RA users. Renamed 31KHz to 31 KHz,  Standard

Fixed winraw input coordinates after switching resolution.

Code cleanup

Fixed menu aspect ratio issue

Added menu resolution restore after closing content

Fixed aspect ratio after menu resolution restore.

code clean up

Fxed menu Resulition Restore Aspect Ratio. When SR uses non integer scalled resolution.

super width bug with restoring menu resolution fix

added super resolution check after setting desktop resolutoion variables

when menu active only sr_deinit() used to restore desktop mode.

Fixed menu sr_deinit bug. now setting sr_active false

Removed static globals, added them to video_switch struct

Fixex compile bug due to comment //

Fixed compile issues doe to c++ comments in teh switchres_wrapper.h

Temporarily removed SR2 logging to fix compile isses for c90

added logging back in. Removed support for winnt and osx

Added define for C89. Disabled SR if defined C89

Removed all RA compile fixes fro C89 C90 etc. Swithing now working again.

Put Switchres behind HAVE_SR2. HAVE_SR2=no by default. --enable-sr2

Ver 0.5 SR2 Implimentation.

Ver 0.4 SR2 Implimantation.

Bake SR inside RA

Removed temporary log files

Disable switchres when C89/C99 builds.

Removed C89 and C90 checks for SR

Fixed switchres_wrapper.h location

Ver 0.3 SR2 Implimenation

Dissable logging for C89 __STDC__

Fix For RPi

fixed missing EOL

fixed RPi function definition

added vidrocrt_switch stuct to RPI funcion

fixed xoffset for RPi

Removed old RPi function call

SR disabled for videocore until VC4 switching ported

Reverted back to state 5c8a56c Bake SR inside RA

Use native win32 api for threads.

Fix static lib linking
LIBERROR would be defined twice otherwise + improper function names prefixed by __imp_

Added lidstc++ to makefile.common for switchres

Fixed RPi switching. Disabled Switchres for videocore unill it is ported.

removed RAA.log. Should not exist

Added check for when SR fails to set mode with an aspect ratio fix.

added video driver re init for RPi

GB, GBA and GBC core check, adjusted reseolutions and scale. Please turn on integer scalling in the RA UI

Added logas back in. Checking STDC verstion >= C11

Fixed c89 for loop declaration.

Code clean up. Added new functions

Fix resolution switching bug introduces with HH code clean up.

Fixed menu restore bug on closw content after code clean up

Moved SR logging to relevant RA logs

Update makefile. Checks for X11 and xrandr

fixed makefile

Use native win32 api for threads.

Fix static lib linking
LIBERROR would be defined twice otherwise + improper function names prefixed by __imp_

Update switchres_wrapper.* header comments

Update year copyright

DRMKMS: build only if libdrm has the required version

XRANDR: build only if xrandr is available

Simplified maklefile

Fixed RPI compile error with unsued functions.

As before

Disable Griffin. No switching support available. Never has been

Removed log file 1

Added Win32 static define

Added SR source

Removed Videocore check on destroy SR

Moved SR deinit to trigger earlier on RA exit.

Fixed compile error after upstream rebase

Fixed aspect ration bug cused by super resolutions. Temporarily disbabled SR logging

Re inabled runtim eSR loggind. Disableed all RARCH logging on retro_deinit_drivers

Removed srdeinit from menu restore. Menu stays in current reolution until a fix can be found

Fixed refresh rate changes when no reolution change is detected.

Forgot to add teh resolution cahge in with the refresh change oops

Fixed endless no detection log.

Removed HH check. This can been better adjusted using the switchres.ini

fixed compile issue

Added better PI crt switching and fixed typo

Pulled Swicthres fixes. Updated desktop restore resolution.

removed unused makefile

Lockec menu refresh to 60hz

fixed missing new line

Fixed file conflicts

Forced 640x480@60 for menu

Added high resolution menu option

Removed item logg checker

Fixed typos

Removed unused functions

Fixed SR close match refesh bug.

Fixed typo
2021-06-04 08:32:56 -07:00
Jamiras 7919a87b97 show challenge indicators 2021-06-03 19:53:17 -06:00
sonninnos 8584b122e1 (D3D11+12) Allow fastforward in fullscreen 2021-06-04 04:31:11 +03:00
Autechre ec7e528094 Merge pull request #12466 from christianhaitian/master
Add nmcli to wifi drivers
2021-06-03 20:08:42 +02:00
Autechre f0c9c542a2 Merge pull request #12469 from CTCaer/unix-sysfs-battery-fix
plat: unix: get better battery stats on sysfs nodes
2021-06-03 20:06:44 +02:00
Autechre 4ed88ec68a Merge pull request #12477 from jdgleaver/archive-hash-fix
Fix loading of archived content with file names containing '#' characters
2021-06-03 20:06:36 +02:00
Autechre 140b8f5e0a Merge pull request #12474 from Jamiras/cheevos_menu
(cheevos) group achievements by category in quick menu
2021-06-03 19:42:09 +02:00
jdgleaver b5df2b883a Fix loading of archived content with file names containing '#' characters 2021-06-03 16:40:13 +01:00
toshixm 4fab84ca9e improve message wrapping with CJK languages 2021-06-03 21:09:35 +09:00
Autechre d8a5505204 Merge pull request #12473 from jdgleaver/content-data-api
Add API extension for setting 'need_fullpath' based on content file extension and to request persistent frontend content data buffers
2021-06-03 13:11:56 +02:00
Autechre b81ec7d631 Merge pull request #12446 from toshixm/fix_12440
fix garbled characters when converting encodings
2021-06-03 00:17:53 +02:00
Jamiras f8479c2b5a address travis warnings 2021-06-02 06:37:54 -06:00
Jamiras 69f3dda90a sort recently unlocked so newest unlocks are first 2021-06-02 06:34:54 -06:00
Jamiras a06b303879 remove unused structure 2021-06-01 21:52:10 -06:00
Jamiras ef9beea9f8 use info icon for headers; use server default image while downloading badges 2021-06-01 21:27:02 -06:00
Jamiras cd8f6ede4e support for almost there, active challenge, and recently unlocked categories 2021-06-01 19:38:10 -06:00
Jamiras e76265e1aa group achievements by category 2021-06-01 15:23:18 -06:00
Autechre 6443d6f019 Merge pull request #12472 from meleu/master
CHEEVOS: relabel 'Start Active' with 'Encore Mode'
2021-06-01 17:59:09 +02:00
Jamiras 293e797146 move menu code to separate file 2021-06-01 09:02:12 -06:00
jdgleaver 55c855267e Add API extension for setting 'need_fullpath' based on content file extension and to request persistent frontend content data buffers 2021-06-01 15:28:39 +01:00
meleu 73a5ec9f42 relabel 'Start Active' with 'Encore Mode' 2021-06-01 08:16:03 -03:00
CTCaer 86f8670d0b plat: unix: get better battery stats on sysfs nodes
This addresses 2 issues:

1. Input controllers report battery supplies.
   That causes wrong charging status or capacities if they report percentages instead of levels.
   Such supplies normally report scope attributes that report Unknown or Device type of power supply.
   If reported value is System or the attribute is missing, it's considered a System supply and used.

2. Various systems have backup batteries.
   That causes the wrong capacity to be reported depending on order of node creation.
   This is addressed by keeping track of these and calculating an average.
2021-05-31 18:36:49 +03:00
Autechre 6772b89872 Update CHANGES.md 2021-05-31 16:15:09 +02:00
Autechre d95e46c2bd Merge pull request #12458 from CTCaer/x-monitor-swap-fullscreen-fix
X11: fix fullscreen when swapping monitors/resolution
2021-05-31 16:14:04 +02:00
Christian_Haitian 74d9f976a8 Add wifi configuration menu
Enable with --enable-wifi during
configuration before make.
Credit to valadaa48 for the
code and configuration.
2021-05-31 02:20:34 +00:00
Autechre b1a3ea72c9 Update CHANGES.md 2021-05-30 04:22:55 +02:00
Autechre ab888629a5 Merge pull request #12456 from libretro/pstvscaling
Vita: Fix scaling on PSTV when not using 720p
2021-05-30 04:22:31 +02:00
CTCaer a8028d5e8e X11: fix fullscreen when swapping monitors/resolution
Most DEs have the tendency to lose focus when monitor is getting swapped or the resolution changes.
That causes X11 exiting fullscreen and setting a lower resolution to fit desktop.
Pushing the window back to top, automatically fixes that and X11 enforces fullscreen again and new max resolution.

Additionally, XConfigure events are now checked and preferred over XGetWindowAttributes.
That saves several to hundreds μs per frame.
2021-05-29 22:19:19 +03:00
Francisco José García García cc1e080dfe VIta: Enable menu sounds 2021-05-29 20:22:37 +02:00
Francisco José García García 35f7ef3cc2 Vita: Fix scaling on PSTV when not using 720p 2021-05-29 19:05:35 +02:00
twinaphex c226bd87f4 Bump version to 1.9.4 2021-05-29 09:23:37 +02:00
Autechre c0b7c34264 Update version.dtd 2021-05-29 09:22:08 +02:00
Autechre 5cf7b57064 Update version.all 2021-05-29 09:21:49 +02:00
Autechre adf6a7ff20 Merge pull request #12450 from libretro/kivutar/fixnota
Try to fix notarization issue
2021-05-29 06:05:04 +02:00
Jean-André Santoni 5a7cebf7da Last fix 2021-05-29 11:03:35 +07:00
Jean-André Santoni 4a8fdaed84 Don't duplicate bundle IDs 2021-05-29 10:54:26 +07:00
Jean-André Santoni 4441219df9 Always prefix bundle ID with com 2021-05-29 10:51:00 +07:00
Autechre 750ad9aa7b Update CHANGES.md 2021-05-28 21:27:19 +02:00
Autechre 0d7a028ce3 Merge pull request #12444 from Jamiras/info_crash 2021-05-28 08:50:21 +02:00
toshixm 84975d71ea fix garbled characters when conveting to local encoding 2021-05-28 15:20:19 +09:00
Jamiras 45c0dc4486 fix crash by restoring incorrectly eliminated line 2021-05-27 21:34:51 -06:00
Jamiras 2c21e3df8b (cheevos) upgrade to rcheevos 10.0 (#12442)
* update rcheevos to v10.0.0

* changes for rcheevos 10

* map virtual tracks in cd_open_track_handler

* address travis warnings
2021-05-27 21:01:00 +02:00
Autechre 138f41160f Merge pull request #12443 from libretro/vitafreetexture
Vita: wait before free texture
2021-05-27 19:53:43 +02:00
Francisco José García García 194de13afb Vita: wait before free texture 2021-05-27 18:41:44 +02:00
Autechre 2c7c8def4c Merge pull request #12435 from toshixm/refactor_word_wrap 2021-05-27 17:31:45 +02:00
Autechre ff3928224e Merge pull request #12441 from jdgleaver/overlay-show-inputs-fix 2021-05-27 17:31:02 +02:00
toshixm a39c38f267 refactor word_wrap() 2021-05-27 19:55:37 +09:00
jdgleaver 8e54b4cec9 (Show Inputs on Overlay) DISABLE_MENU=1 buildfix + Qt settings update 2021-05-26 18:15:23 +01:00
twinaphex 0dfb2b57fb use snprintf instead of multiple consecutive strlcpy/strlcats 2021-05-26 05:22:18 +02:00
twinaphex a84c9022af Cleanups 2021-05-25 21:31:39 +02:00
twinaphex 0a5d4288f5 Rollback runloop changes - will require a rethink in how we approach
this
2021-05-25 20:41:39 +02:00
Autechre 3c6ac487d0 Merge pull request #12438 from jdgleaver/overlay-show-inputs-redux
Add option to select between 'touched' elements and physical controller inputs when showing inputs on overlays
2021-05-25 19:04:17 +02:00
jdgleaver 466bd3be7f Add option to select between 'touched' elements and physical controller inputs when showing inputs on overlays 2021-05-25 18:01:52 +01:00
Autechre 5dc7b7f7c7 Merge pull request #12437 from DisasterMo/inconsistencies_fix
Fixed some inconsistencies in the RetroArch texts
2021-05-25 18:09:21 +02:00
Michael Burgardt 3e814bc4b6 Fixed some inconsistencies in the RetroArch texts 2021-05-25 17:13:55 +02:00
twinaphex f70b6fbf58 Revert "Go through p_runloop pointer"
This reverts commit 30a90adc47.
2021-05-25 05:27:06 +02:00
twinaphex 30a90adc47 Go through p_runloop pointer 2021-05-25 05:19:43 +02:00
twinaphex 621a0b61f6 Move more state to runloop_state (in preparation of removing path_clear
and path_is_empty)
2021-05-24 20:38:56 +02:00
twinaphex 244a2ad052 Simplify video_thread_get_ptr - get rid of unused p_rarch pointer
in dir_free_shader
2021-05-24 19:22:55 +02:00
Autechre bb04b0b9d3 Merge pull request #12432 from DisasterMo/crowdin_sync
Fixed a tiny bug in the Crowdin sync script
2021-05-24 18:51:41 +02:00
Autechre e616b41b62 Merge pull request #12431 from yoshisuga/ios_disable_core_info_cache
[iOS/tvOS] Disable core info caching for iOS
2021-05-24 18:42:51 +02:00
twinaphex fb8c73508b Apply diff patch taking care of issues 2021-05-24 18:40:40 +02:00
Michael Burgardt f2a73d1b14 Fixed a tiny bug in the Crowdin sync script 2021-05-24 12:43:48 +02:00
twinaphex 2b4f2525d0 move more runloop functions over to runloop.c 2021-05-24 02:57:40 +02:00
twinaphex 75175ddbce move more runloop functiosn to runloop.c 2021-05-24 02:27:55 +02:00
Yoshi Sugawara 4dcbd3e383 [iOS/tvOS] Disable core info caching for iOS 2021-05-23 08:33:14 -10:00
twinaphex b48ab663b0 Move BSV runloop code over to runloop.c 2021-05-23 02:20:01 +02:00
twinaphex 364d518726 More runloop_state changes 2021-05-23 01:54:33 +02:00
twinaphex d1c7d97b10 Split up code to runloop.c 2021-05-22 23:09:00 +02:00
Autechre f8b6443b91 Update CHANGES.md 2021-05-22 18:52:52 +02:00
Autechre 8344ed9db5 Update CHANGES.md 2021-05-22 18:52:08 +02:00
Autechre 76f3d0c1b7 Merge pull request #12429 from libretro/pstv720p
[VITA] Support for 720p on PSTV when using unlock framebuffer in Sharpscale plugin
2021-05-22 18:51:38 +02:00
Francisco José García García 52af69e6cd Vita: support for 720p in PSTV & Sharpscale plugin 2021-05-22 17:29:03 +02:00
Francisco José García García d6b1836919 Vita: arrange compile flags 2021-05-22 17:29:03 +02:00
twinaphex 7c483340fc Start creating a distinction between runloop_ and retroarch_ prefix
functions
2021-05-22 16:51:55 +02:00
twinaphex 33de17548b Fix regression caused by core info file caching - Downloads was no
longer showing up in Load Content
2021-05-22 16:25:05 +02:00
twinaphex 9cd19d4944 Silence warning - ret was never used 2021-05-22 16:05:26 +02:00
twinaphex 89e4cac3f1 Small cleanups 2021-05-22 07:33:05 +02:00
twinaphex 29e9027ec0 Cleanup find_driver_* functions - don't pass p_rarch through it 2021-05-22 05:37:14 +02:00
twinaphex 68c377cd55 Move more to runloop_state 2021-05-22 02:57:02 +02:00
twinaphex 706ab17b2c Remove p_rarch passing around where it's no longer needed 2021-05-22 02:14:32 +02:00
twinaphex fede9eee4b Get rid of unused variables 2021-05-22 01:31:29 +02:00
twinaphex d84a2ef700 Move boolean state variables from p_rarch to runloop_state 2021-05-22 01:25:59 +02:00
twinaphex 4ba92b1643 Move more runloop state over to runloop_state 2021-05-22 00:25:01 +02:00
twinaphex 57a728fd41 Rename audio_out_rate to audio_output_sample_rate 2021-05-21 22:36:46 +02:00
twinaphex bc8f98358b Cleanup in audio_driver_init_internal 2021-05-21 22:30:16 +02:00
twinaphex 3887db349e Get rid of unused variable 2021-05-21 22:26:46 +02:00
twinaphex 98448960f5 Move audio_driver_mixer_volume_gain to runloop_state struct 2021-05-21 22:25:36 +02:00
twinaphex 22a2b5ac1c Move more variables to runloop_state 2021-05-21 22:20:26 +02:00
twinaphex 6e4620cebc Prevent warning on Griffin builds 2021-05-21 21:25:43 +02:00
twinaphex 458d636861 Move more runloop state to runloop state struct 2021-05-21 21:23:06 +02:00
twinaphex 64c01e620d Rename retroarch_get_runloop_fastforward_* function 2021-05-21 20:09:50 +02:00
twinaphex 57c4802ab4 Remove unused variable 2021-05-21 20:02:22 +02:00
twinaphex 74f1bf59b9 Refactors - plenty of runloop state functions no longer pass p_rarch
around, so get rid of it
2021-05-21 19:52:09 +02:00
Autechre cacbd451dc Update CHANGES.md 2021-05-21 17:48:36 +02:00
Autechre 7174563f7d Merge pull request #12426 from jdgleaver/overlay-remap-fix
Prevent duplicate inputs when using remaps with input overlays
2021-05-21 17:46:32 +02:00
jdgleaver d5f862ee07 Prevent duplicate inputs when using remaps with input overlays 2021-05-21 16:31:11 +01:00
twinaphex f66d4ea33c Remove unused variables 2021-05-21 17:14:13 +02:00
twinaphex 0797fd957a menu_entries_get_core_title - cut down on amount of lines of code 2021-05-21 17:10:20 +02:00
twinaphex b45acf2223 MSVC buildfixes 2021-05-21 17:09:55 +02:00
twinaphex 30143f15f2 Simplify menu_entries_get_core_title 2021-05-21 16:54:43 +02:00
twinaphex 24389bbcd5 Small cleanups to task_content.c 2021-05-21 16:30:02 +02:00
twinaphex 2e50b57643 task_content_disc.c - header include cleanups 2021-05-21 14:10:44 +02:00
Autechre 5b995dec26 Update CHANGES.md 2021-05-21 14:08:55 +02:00
Autechre 5ae4524176 Merge pull request #12424 from libretro/pstvinput 2021-05-21 13:13:28 +02:00
Francisco José García García 87a7795331 [VITA] Fix input driver for PSTV 2021-05-21 10:54:02 +02:00
Autechre 44fc3666ed Merge pull request #12421 from jdgleaver/task-content-cleanup-1 2021-05-21 06:16:38 +02:00
markwkidd cea6b17391 bind trigger to first mouse button by default 2021-05-20 22:50:49 -04:00
jdgleaver 334a43a7c5 Prevent unnecessary extraction (to disk) of compressed content files + task_content.c clean-ups 2021-05-20 17:08:51 +01:00
Autechre 29475a904f Merge pull request #12419 from crystalct/master
Change default video driver name for PSL1GHT
2021-05-20 05:30:26 +02:00
U-LAPTOP-0BS9KNOH\crystal 159602d697 Change default video driver name for PSL1GHT 2021-05-19 22:50:34 +02:00
twinaphex de88edf56c Fix header include now that defines/ files are in libretro-common 2021-05-19 16:47:40 +02:00
twinaphex 4fb6bc9f33 Fix another camelcase variable 2021-05-19 16:13:05 +02:00
twinaphex b82a20ea0c We don't want camelcase notation variable names for RetroArch 2021-05-19 16:11:26 +02:00
twinaphex 8291b18771 Small cleanup to cheevos content loading part 2021-05-19 16:05:42 +02:00
twinaphex 181824eb00 (Tasks/content) Split up CDROM code into tasks/task_content_disc.c 2021-05-19 15:53:38 +02:00
twinaphex 7a2115670a Fix relative path includes 2021-05-19 15:41:40 +02:00
Autechre 951999e5ce Merge pull request #12416 from crystalct/master
PSL1GHT salamander build fix
2021-05-19 14:48:03 +02:00
U-LAPTOP-0BS9KNOH\crystal 23acacf436 PSL1GHT salamander build fix 2021-05-19 00:31:09 +02:00
twinaphex 925c459aed Use single snprintf instead of multiple strlcpy/strlcat calls in
several places
2021-05-18 23:18:09 +02:00
twinaphex 0482892a9c Get rid of return variable for snprintf 2021-05-18 23:09:45 +02:00
Autechre dd922bfc2c Merge pull request #12413 from Jamiras/cheevos_sprintf
(cheevos) replace sprintf with snprintf
2021-05-18 22:55:13 +02:00
twinaphex 35543ecd91 Move defines files over to libretro-common 2021-05-18 22:15:04 +02:00
twinaphex e08290acb0 Less strlcpy/strlcat concatenation of strings 2021-05-18 21:06:29 +02:00
twinaphex e34c84d791 Use snprintf in more situations 2021-05-18 20:19:19 +02:00
twinaphex 2e4b734159 Cleanups - replace several messy strlcpy/strlcats with one single
snprintf
2021-05-18 20:09:48 +02:00
twinaphex 3b64752f4f Simplify strlcpy/strlcat combinations to single snprintf 2021-05-18 20:01:51 +02:00
twinaphex 9829051841 win32_localize_menu - replace strcmp call with string_is_not_equal 2021-05-18 19:49:57 +02:00
twinaphex fc2a011a5c Use single snprintf call where possible instead of multiple
strlcpy/strlcat calls
2021-05-18 19:36:20 +02:00
twinaphex 0e7ff6ea4e - Avoid some repeated strlcpy/strlcat calls one after another; replace
it with a single snprintf call under the assumption it will probably
still be faster
- In some instances, the first time the string was manipulated on was
with a strlcat call instead of an strlcpy - change this
2021-05-18 19:27:54 +02:00
twinaphex e784cc1aaf Cleanup some accessibiliyt-related code - pre-initialize strings
normally, don't use weird string_is_equal check which checks if string
is empty, etc.
2021-05-18 19:02:10 +02:00
twinaphex e4a8f42ad1 win32_localize_menu - get rid of direct strcpy/strcat calls 2021-05-18 18:53:30 +02:00
Autechre a04fe66032 Merge pull request #12380 from stenzek/vulkan-software-fb
(video/vulkan) Avoid caching stale mapped GPU texture as frame data
2021-05-18 18:01:47 +02:00
Jamiras 9669cff16b fix travis error 2021-05-18 09:46:03 -06:00
Jamiras 09439332f3 implement feedback 2021-05-18 09:40:53 -06:00
Jamiras 216deda910 replace sprintf with snprintf 2021-05-18 08:31:44 -06:00
twinaphex 7bbdd6d18a Prefer using snprintf instead of insecure sprintf 2021-05-18 15:14:08 +02:00
twinaphex b037da7264 (vita/launcher) Use snprintf 2021-05-18 15:07:58 +02:00
twinaphex ef35adc9d6 platform_ps2.c - Use snprintf 2021-05-18 14:15:18 +02:00
twinaphex f6a8480f21 (platform_psp.c) Switch to strlcpys instead of sprintf 2021-05-18 13:57:23 +02:00
Autechre d3b3b40ea7 Update CHANGES.md 2021-05-18 13:43:43 +02:00
Autechre 6972cc2bc6 Merge pull request #12398 from DisasterMo/playlist_entry_enumeration
(ozone) Added simple playlist entry enumeration
2021-05-18 13:19:35 +02:00
twinaphex 74cef32c1d Cleanups 2021-05-18 00:57:46 +02:00
Michael Burgardt d50be7a0ab Added simple playlist entry enumeration to ozone; added toggle option by jdgleaver 2021-05-17 18:49:25 +02:00
twinaphex d228e5f759 Small style nits 2021-05-17 15:58:04 +02:00
Autechre 10546594de Update CHANGES.md 2021-05-17 15:54:39 +02:00
Autechre e9b5f009cc Merge pull request #12411 from jdgleaver/max-users-dropdown-fix
(XMB) Fix display of 'Maximum Users' menu entry dropdown list
2021-05-17 15:52:14 +02:00
twinaphex d6ec36c707 Enable 'Cache Core Info Files' by default for all platforms 2021-05-17 15:47:28 +02:00
jdgleaver be84700d0a (XMB) Fix display of 'Maximum Users' menu entry dropdown list 2021-05-17 14:41:57 +01:00
Autechre ad5b2d614a Merge pull request #12401 from davidgfnet/br3
Add brightness restore hook
2021-05-17 13:24:50 +02:00
Autechre 9e87040c02 Merge pull request #12406 from guoyunhe/crowdin
Fetch translations from Crowdin
2021-05-17 13:24:39 +02:00
Autechre 90abd49892 Merge pull request #12410 from Alcaro/master
rpng: Fix some memory corruption if processing broken input
2021-05-17 13:22:51 +02:00
Alcaro 654aae58d6 rpng: Fix some memory corruption if processing broken input 2021-05-17 08:43:53 +02:00
twinaphex e6adca7679 rarch_init_core_options_path - NULL termination of strings is already
done outside by caller
2021-05-17 00:56:29 +02:00
Autechre 095f6d4377 Merge pull request #12407 from crystalct/master
PSL1GHT joypad restored
2021-05-16 23:01:32 +02:00
Autechre b946b146f3 Merge pull request #12408 from LazyFunker/master
Fix typo
2021-05-16 23:00:39 +02:00
LazyFunker 4e0f8bf621 Fix typo 2021-05-16 20:44:31 +02:00
unknown de4343caeb PSL1GHT joypad restored 2021-05-16 20:04:43 +02:00
Autechre a9426925cf Update config.def.h 2021-05-16 19:27:07 +02:00
Autechre aebdc8b747 Merge pull request #12404 from mudlord/master
Look into fixing CVE-2021-28927
2021-05-16 18:43:34 +02:00
Guo Yunhe c9d4775ffc Fetch translations from Crowdin 2021-05-17 00:09:21 +08:00
mudlord 3b8bd1a6e8 There. 2021-05-16 18:28:59 +10:00
mudlord 734401440d People are never happy. 2021-05-16 18:20:52 +10:00
mudlord 9fbf3b9732 Whoops 2021-05-16 17:58:43 +10:00
mudlord 67b180d63d Look into fixing CVE-2021-28927 2021-05-16 17:55:14 +10:00
David Guillen Fandos c378665af5 Add brightness restore hook
This is out of the unix frontend driver on purpose, since settings do
not seem to be available at init() time.
2021-05-15 21:20:37 +02:00
Autechre 3187c87451 Update CHANGES.md 2021-05-15 20:07:09 +02:00
twinaphex 122be0cc64 Bump version to 1.9.3 2021-05-15 19:57:59 +02:00
Autechre 6b13e3f050 Merge pull request #12397 from jdgleaver/info-cache-default
Enable core info cache by default on all 'console' platforms
2021-05-14 17:58:04 +02:00
jdgleaver 87e248f4eb Enable core info cache by default on all 'console' platforms 2021-05-14 16:49:30 +01:00
Autechre 2be7106055 Merge pull request #12395 from jdgleaver/auto-shader-delay-fix
Fix 'Auto-Shader Delay' functionality
2021-05-14 16:15:15 +02:00
jdgleaver 0a24f5f38a Fix 'Auto-Shader Delay' functionality 2021-05-14 13:47:46 +01:00
Autechre 6189fd3f42 Merge pull request #12392 from alttpo/fix-network-cmd-recvfrom
command: initialize netcmd->cmd_source_len before recvfrom()
2021-05-14 13:06:59 +02:00
Autechre 29d5a692d0 Merge pull request #12393 from jdgleaver/rgui-config-save-fix
(RGUI) Fix saving of config files/overrides when 'Lock Menu Aspect Ratio' is enabled
2021-05-14 13:06:36 +02:00
jdgleaver 358cafa978 (RGUI) Fix saving of config files/overrides when 'Lock Menu Aspect Ratio' is enabled 2021-05-14 10:50:18 +01:00
jsd1982 b3eebbd5ec command: initialize netcmd->cmd_source_len before recvfrom() 2021-05-13 22:13:10 -05:00
Autechre cc5b491e21 Merge pull request #12390 from jdgleaver/emscripten-load-content-fix
Fix content loading via file browser on platforms with 'broken' core handling (i.e. emscripten)
2021-05-13 17:35:39 +02:00
Autechre bf0b9f536a Merge pull request #11547 from jdgleaver/ff-callback
Add API extension for cores to override frontend fast-forward state
2021-05-13 16:40:06 +02:00
jdgleaver 6f471e0660 Fix content loading via file browser on platforms with 'broken' core handling (i.e. emscripten) 2021-05-13 15:32:25 +01:00
jdgleaver 484c4ad51e Add API extension for cores to override frontend fast-forward state 2021-05-13 13:16:37 +01:00
Autechre 66c77af4a6 Merge pull request #12381 from GavinDarkglider/master
Fix typo in HAVE_LAKKA_SWITCH stuff that is breaking HAVE_LAKKA build…
2021-05-12 16:08:15 +02:00
Autechre 667568b0b8 Merge pull request #12386 from Ryunam/ozone-themes-id
Updates to Ozone (follow-up to #12382)
2021-05-12 16:02:07 +02:00
twinaphex f3ff36ac34 Fix some targets - no comma at end of enumerator list 2021-05-12 16:01:31 +02:00
Autechre feaefbef04 Merge pull request #12385 from jdgleaver/static-reload-core-fix
(Static Platforms) Ensure 'Always Reload Core on Run Content' setting is applied when loading content via the file browser
2021-05-12 16:00:43 +02:00
Ryunam a16aba2138 Updates to Ozone 2021-05-12 15:28:26 +02:00
jdgleaver 50d27fada9 (Static Platforms) Ensure 'Always Reload Core on Run Content' setting is applied when loading content via the file browser 2021-05-12 10:59:07 +01:00
Autechre a6d92de0b2 Merge pull request #12382 from Ryunam/ozone-themes-id
Minor updates to Ozone themes code
2021-05-12 09:18:02 +02:00
Autechre 89391ccf9a Merge pull request #12287 from LazyFunker/master
Some fixes for UWP/XBox
2021-05-12 09:17:53 +02:00
Autechre e430f832cc Merge pull request #12383 from davidgfnet/cpufreq2
CPU governor/frequency part 2
2021-05-12 09:17:42 +02:00
David Guillen Fandos 9280340fe0 CPU governor/frequency part 2
This adds managed policies and settings to store them and reload them at
startup. Only for Lakka builds!
2021-05-12 02:16:25 +02:00
Ryunam 85466225de Minor updates to Ozone themes code 2021-05-11 19:35:38 +02:00
Stenzek c9aaf598bb (video/vulkan) Avoid caching stale mapped GPU texture as frame data
At best, this results in junk on screen, at worst we could crash.

It's not a perfect fix, there's still a scenario where this breaks: when
fast forwarding is enabled, and we swap from vsync-off to vsync-on when
pausing/rendering the menu, the swap chain (and textures) gets
recreated, and the frame data is completely lost.

There isn't much we can do about this without more intrusive changes,
such as preserving the textures inbetween swap chain reinits.
2021-05-11 09:49:39 -07:00
Stenzek 92e795aa28 (main) Remove null check from video_driver_set_cached_frame_ptr
The only call sites here use NULL as a parameter, and it makes
sense to clear it, since the intent is to remove a potentially
dangling pointer.
2021-05-11 09:49:39 -07:00
Ronald Brown fa2c789c3f Fix typo in HAVE_LAKKA_SWITCH stuff that is breaking HAVE_LAKKA building. 2021-05-10 23:31:00 -07:00
Autechre 475213aa0a Merge pull request #12378 from davidgfnet/master
Moving more stuff from samples to tests
2021-05-11 03:16:04 +02:00
David Guillen Fandos 32d6eeaf07 Moving more stuff from samples to tests
Reworked the test a bit to make it separate from RA's build system for
simplicity.
Reworked the testing a bit to ensure coverage is properly generated.
This needs more work since it's rather manual and verbose
2021-05-10 19:45:50 +02:00
Autechre 6f95e7819a Merge pull request #12364 from davidgfnet/master
Add more tests and coverage generation
2021-05-09 19:57:40 +02:00
GavinDarkglider f24f827c4c Updates For Lakka Switch build. (#12369) 2021-05-07 20:58:30 +02:00
Autechre 53a266728b Merge pull request #12368 from jdgleaver/core-info-fix 2021-05-07 14:28:18 +02:00
Autechre 215ed2ccf6 Merge pull request #12367 from jdgleaver/core-info-cache-whitespace 2021-05-07 14:28:01 +02:00
jdgleaver a671b6394c (Core Info) Fix core detection on platforms that support cores with multiple file extensions 2021-05-07 10:58:09 +01:00
jdgleaver dec1fd097c Skip whitespace when writing compressed core info cache files 2021-05-07 10:16:21 +01:00
David Guillen Fandos a0f0d7bed2 Add more tests and coverage generation 2021-05-06 18:43:56 +02:00
Autechre 6a21eca5df Merge pull request #12363 from jdgleaver/core-info-cache-updates 2021-05-06 16:13:55 +02:00
jdgleaver c37f540b72 Core Info Cache Improvements
- Core info cache can now be enabled/disabled on all platforms via a new `Settings > Core > Cache Core Info Files` option
- Core info cache file has been renamed from `.cache` to `core_info.cache` (i.e. it is no longer a 'hidden' file on Unix platforms, so can be deleted easily)
- The core info cache file is now compressed (rzip) to further reduce disk IO
- The presence of a `core_info.refresh` file in the core info directory will force a one-time refresh of the info cache. This file is generated automatically when toggling on the `Cache Core Info Files` option, and we will also add it to core info file packaging such that updating info files (either manually or via the online updater) will force a refresh
- The core info cache no longer contains 'core is locked' and 'firmware missing' data fields; these are 'dynamic' properties that must be determined at runtime
- The 'core is locked' status is now determined on core info intialisation by parsing the core directory listing, rather than by performing indivdual 'lock file exists' checks. This minimises file IO, and greatly improves performance on devices with slow storage
- While parsing the core info cache file, we now avoid unnecessary `strdup()`s when adding entries to the resultant cache list
- Memory leaks (potential and real) have been fixed, and safety checks added
- Build errors have been fixed
2021-05-06 15:00:55 +01:00
Autechre 5aba614b60 Merge pull request #12350 from bulzipke/master 2021-05-06 15:57:50 +02:00
Autechre 0680505ebf Merge pull request #12354 from njordan64/generic-queue-linked-list
Adding a generic queue and linked list.
2021-05-05 22:49:11 +02:00
Norman Jordan 528af55abd Adding a generic queue and linked list.
Both accept (void *) values. Also added some unit tests using CHECK.
2021-05-05 10:41:13 -07:00
Autechre 1167dde73a Merge pull request #12359 from njordan64/shader_vulkan_fix
Added a missing include.
2021-05-05 18:18:42 +02:00
Autechre b3abdefb9a Merge pull request #12358 from bulzipke/fix-msvc-build
Fix windows msvc build
2021-05-05 18:18:33 +02:00
Norman Jordan 1b0ae7a0b2 Added a missing include. 2021-05-05 01:52:04 -07:00
bulzipke f3daf070e1 Fix windows msvc build 2021-05-05 15:32:15 +09:00
Autechre 6241909a08 Merge pull request #12356 from jdgleaver/warn-fix
Fix 'unhandled enum' compiler warning on non-LAKKA platforms
2021-05-04 16:04:33 +02:00
Autechre 7fbb7a8007 Merge pull request #12355 from jdgleaver/3ds-disable-screensaver
(3DS) Disable menu screensaver animations in XMB/GLUI
2021-05-04 16:04:24 +02:00
bulzipke e96cbcac04 (3DS) Build core info cache 2021-05-04 23:01:17 +09:00
jdgleaver 0706cdea4c Fix 'unhandled enum' compiler warning on non-LAKKA platforms 2021-05-04 12:35:01 +01:00
jdgleaver 07099797bd (3DS) Disable menu screensaver animations in XMB/GLUI 2021-05-04 11:44:30 +01:00
Jean-André Santoni 77967f0148 Merge pull request #12348 from libretro/kivutar/lutroweb
Add lutro to web.libretro.com
2021-05-02 14:13:43 +07:00
Jean-André Santoni 56e40e8204 Add lutro to web.libretro.com 2021-05-02 13:04:20 +07:00
Autechre 218c6f30b9 Merge pull request #12346 from davidgfnet/cpufreq1 2021-05-02 05:15:56 +02:00
David Guillen Fandos b2c20e8ce0 Initial support for tweaking CPU governors/scaling policies
This is, at the moment, aimed at Lakka only.
2021-05-01 18:35:38 +02:00
Autechre 76eeee2c9a Merge pull request #12345 from devnexen/fbsd_build_fix
FreeBSD build fix proposal
2021-05-01 17:26:44 +02:00
David Carlier 3b7e0a8db1 FreeBSD build fix proposal 2021-05-01 15:37:14 +01:00
LazyFunker c5e5cf28af Force resolution on UWP 2021-04-20 11:47:32 +02:00
LazyFunker 8ff0430370 Disable mipmap generation for UWP 2021-04-20 10:29:17 +02:00
pjft 0a83817f25 Merge branch 'master' into dual-lightgun 2021-01-18 11:23:44 +00:00
pjft f8b4289811 Change udev driver for dual lightgun support in X11 2020-09-28 21:25:51 +01:00
406 changed files with 48335 additions and 23582 deletions

No files matched your search

+2
View File
@@ -9,6 +9,8 @@
*.map
*.swp
*.cache
*.gcda
*.gcno
.tmp
.tmp.c
.tmp.cxx
+101
View File
@@ -1,5 +1,106 @@
# Future
# 1.9.6
- ARCHIVE: Fix archive delimiter detection when file path contains no slashes
- ANDROID: Do not duplicate port 0 mouse and gun inputs to other ports
- AUDIO/XAUDIO2: Fail instead of crashing when disconnecting an audio device
- CHEEVOS: Reset cached progress each time menu is opened
- CRT/SWITCHRES: Add support for switchres.ini core and directory overrides
- D3D11: Don't use allow tearing flag with blit swap chains. Also disables the flip model if the allow tearing flag is not supported.
- D3D11: Disable DXGI's ALT+ENTER handling
- D3D11: Don't pass ALLOW_TEARING when unsupported
- D3D11: Fix non-vsynced output without flip, black screens in fullscreen
- D3D12: Relcoated 'd3d12_gfx_sync'
- D3D12: Fixed swap interval option
- GFX: Fix uninitialized variables in gfx_display_draw_cursor
- HISTORY: Hide 'Add to Favorites' when viewing an entry of the favorites playlist
- INPUT: 'Analog to Digital Type' usability improvements
- INPUT: Add support for mapping multiple controllers to a single input device
- INPUT/REMAPPING: Add support for mapping multiple controllers to a single input device
- INPUT/LIGHTGUN: Bind lightgun trigger to first mouse button by default
- INPUT/WINDOWS/RAWINPUT: Mouse access violation fix
- INPUT/UDEV: Only add mouse if it has buttons and add vebose device friendly names
- INPUT/UDEV: Skip mouse with no button errors and keep the rest
- INPUT/UDEV: Fix Game Focus mode
- INPUT/UDEV/X11: Change udev driver for dual lightgun support in X11
- LIBNX/SWITCH: Update to libnx 4.0.0
- LOCALIZATION: Fetch translations from Crowdin
- LOCALIZATION: Fix Switchres menu texts
- MENU/OZONE: Ensure sidebar display status is updated correctly when performing rapid menu navigation
- MENU/XMB: Dynamic wallpaper fix
- MENU/XMB: Icon opacity fix
- MENU/QT/WIMP: Fix default core detection when playlist file name does not match 'db_name'
- PLAYLISTS: Optimise scanning of large rom sets
- SECURITY: Plug so-called high-risk vulnerability related to Powershell - avoid injection - don't send speech input as commandline argument
- UWP/XBOX: Add expanded resources Rescap to increase performance of UWP version in app mode on Xbox
- WINDOWS/INSTALLER: Add smarter isEmptyDir reference implementation that looks for subdirectories from NSIS documentation
- WINDOWS/INSTALLER: Register new function DirectorySet that is called when pressing the "Next" button on the MUI_PAGE_DIRECTORY, aka the install folder selection GUI. DirectorySet contains the criteria for an acceptable folder, which are:
- `IfFileExists "$INSTDIR\retroarch.exe"` returns 1
- `IfFileExists "$INSTDIR\*.*` returns 0, there is no existing folder
- `IfFileExists "$INSTDIR\*.*"` returns 1, there is a folder, and `isEmptyDir` returns 1, therefore the folder is empty, including of subdirectories
- X11: Fix threaded video segfault
# 1.9.5
- ALSATHREAD: Make alsathread default for all ALSA devices with threads
- ARCHIVE: Fix loading of archived content with file names containing '#' characters
- CHEEVOS: Upgrade to rcheevos 10.1
- CHEEVOS: Challenge indicators
- CHEEVOS: Group achievements by category in quick menu
- CHEEVOS: Relabel 'Start Active' with 'Encore Mode'
- D3D10: Window title should now update
- D3D11: Window title should now update
- D3D11: Allow fastforward in fullscreen
- D3D12: Window title should now update
- D3D12: Allow fastforward in fullscreen
- CRT/SWITCHRES: New implementation
- FONTS: Improve message wrapping with CJK languages
- FONTS: Fix garbled characters when converting encodings
- INPUT: Allow the 8 analog stick directions to be used as keys for core keyboard mappings
- LIBRETRO: Add API extension for setting 'need_fullpath' based on content file extension and to request persistent frontend content data buffers
- MENU/SEARCH: Add enhanced search functionality to the 'Manage Cores' menu
- OPENDINGUX: Fix black screens when triggering gfx driver initialisation via menu actions
- UNIX: Get better battery stats on sysfs nodes
- VIDEO: Extend Frame Delay range to 19 to accommodate PAL land too
- WIFI/LAKKA: Add nmcli to wifi drivers
- WIFI/LAKKA: Add wifi configuration menu
- X11: fix fullscreen when swapping monitors/resolution
# 1.9.4
- CHEEVOS: update rcheevos to v10.0.0
- CONTENT LOADING/FILE IO: Prevent unnecessary extraction (to disk) of compressed content files when need_fullpath is false
- CORE INFO/FILE IO: Enable core info cache by default now for all platforms
- CORE INFO/REGRESSION FIX: Fix regression caused by core info file caching - Downloads was no longer showing up in Load Content
- FILE IO/COMPRESSED: Ability to load content inside ZIP files directly into RAM
- INPUT/OVERLAYS: Add option to select between 'touched' elements and physical controller inputs when showing inputs on overlays
- INPUT REMAPPING/OVERLAYS: Prevent duplicate inputs when using remaps with input overlays
- LAKKA: Add brightness restore hook
- LOCALIZATION: Fetch translations from Crowdin
- MENU/OZONE: Added simple playlist entry enumeration
- MENU/XMB: Fix display of 'Maximum Users' menu entry dropdown list
- PS3/PSL1GHT: Joypad driver works again
- PSTV: Fix Vita input driver for PSTV
- PSTV: Support for 720p on PSTV when using 'Unlock framebuffer' in Sharpscale plugin
- PSTV: Fix scaling on PSTV when not using 720p
- RPNG: Fix some memory corruption if processing broken input PNG file
- SECURITY: Fix CVE-2021-28927
# 1.9.3
- 3DS: Disable menu screensaver animations in XMB/GLUI
- COMMAND: Initialize netcmd->cmd_source_len before recvfrom()
- CONTENT LOADING/STATICALLY LINKED: Ensure 'Always Reload Core on Run Content' setting is applied when loading content via the file browser
- CONTENT LOADING/EMSCRIPTEN: Fix content loading via file browser on platforms with 'broken' core handling (i.e. emscripten)
- CORE INFO: Skip whitespace when writing compressed core info cache files
- CORE INFO/FILE IO: Core Info cache; significant file I/O performance improvements on systems with slow disk file I/O
- CORE INFO/FILE IO: Enable core info cache by default on all 'console' platforms
- FREEBSD: FreeBSD build fix
- LAKKA: Support for tweaking CPU governors/scaling policies
- LAKKA: This adds managed policies and settings to store them and reload them at startup
- LIBRETRO API: Add API extension for cores to override frontend fast-forward state
- MENU/RGUI: Fix saving of config files/overrides when 'Lock Menu Aspect Ratio' is enabled
- SHADERS: Fix 'Auto-Shader Delay' functionality
- UWP/D3D11: Disable mipmap generation
- UWP/XBOX: Add 'Force 4K resolution' option (Force the resolution to the fullscreen size on Xbox, if set to 0, a fixed value of 3840 x 2160 will be used)
# 1.9.2
- 3DS: Enable graphics widgets / overlays
- 3DS: Load texture images as BGR colors
+47 -4
View File
@@ -275,6 +275,10 @@ OBJ += \
$(LIBRETRO_COMM_DIR)/memmap/memalign.o \
$(LIBRETRO_COMM_DIR)/file/nbio/nbio_stdio.o
OBJ += \
$(LIBRETRO_COMM_DIR)/lists/linked_list.o \
$(LIBRETRO_COMM_DIR)/queues/generic_queue.o
ifneq ($(findstring Linux,$(OS)),)
OBJ += $(LIBRETRO_COMM_DIR)/file/nbio/nbio_linux.o
endif
@@ -300,7 +304,6 @@ OBJ += \
input/common/input_hid_common.o \
led/led_driver.o \
gfx/video_coord_array.o \
gfx/video_crt_switch.o \
gfx/gfx_display.o \
gfx/gfx_animation.o \
gfx/gfx_thumbnail_path.o \
@@ -764,6 +767,12 @@ endif
ifeq ($(HAVE_LAKKA), 1)
OBJ += wifi/drivers/connmanctl.o
OBJ += misc/cpufreq/cpufreq.o
endif
ifeq ($(HAVE_WIFI), 1)
OBJ += wifi/drivers/nmcli.o
DEFINES += -DHAVE_WIFI
endif
# Audio
@@ -1985,7 +1994,8 @@ ifeq ($(HAVE_CDROM), 1)
DEFINES += -DHAVE_CDROM
OBJ += $(LIBRETRO_COMM_DIR)/cdrom/cdrom.o \
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation_cdrom.o \
$(LIBRETRO_COMM_DIR)/media/media_detect_cd.o
$(LIBRETRO_COMM_DIR)/media/media_detect_cd.o \
tasks/task_content_disc.o
endif
ifeq ($(HAVE_RTGA), 1)
@@ -2101,8 +2111,7 @@ ifeq ($(HAVE_NETWORKING), 1)
INCLUDE_DIRS += -Ideps/rcheevos/include
OBJ += cheevos/cheevos.o \
cheevos/badges.o \
cheevos/cheevos_memory.o \
cheevos/cheevos_menu.o \
cheevos/cheevos_parser.o \
$(LIBRETRO_COMM_DIR)/formats/cdfs/cdfs.o \
deps/rcheevos/src/rcheevos/alloc.o \
@@ -2114,6 +2123,7 @@ ifeq ($(HAVE_NETWORKING), 1)
deps/rcheevos/src/rcheevos/lboard.o \
deps/rcheevos/src/rcheevos/memref.o \
deps/rcheevos/src/rcheevos/operand.o \
deps/rcheevos/src/rcheevos/rc_libretro.o \
deps/rcheevos/src/rcheevos/richpresence.o \
deps/rcheevos/src/rcheevos/runtime.o \
deps/rcheevos/src/rcheevos/runtime_progress.o \
@@ -2263,6 +2273,39 @@ ifeq ($(HAVE_FFMPEG), 1)
INCLUDE_DIRS += -Iffmpeg
endif
# CRT mode switching
ifeq ($(HAVE_CRTSWITCHRES), 1)
INCLUDE_DIRS += -I$(DEPS_DIR)/switchres
OBJ += gfx/video_crt_switch.o \
$(DEPS_DIR)/switchres/monitor.o \
$(DEPS_DIR)/switchres/modeline.o \
$(DEPS_DIR)/switchres/switchres.o \
$(DEPS_DIR)/switchres/display.o \
$(DEPS_DIR)/switchres/custom_video.o \
$(DEPS_DIR)/switchres/log.o \
$(DEPS_DIR)/switchres/switchres_wrapper.o \
$(DEPS_DIR)/switchres/edid.o
ifneq ($(findstring Win32,$(OS)),)
OBJ += $(DEPS_DIR)/switchres/display_windows.o \
$(DEPS_DIR)/switchres/custom_video_ati_family.o \
$(DEPS_DIR)/switchres/custom_video_ati.o \
$(DEPS_DIR)/switchres/custom_video_adl.o \
$(DEPS_DIR)/switchres/custom_video_pstrip.o \
$(DEPS_DIR)/switchres/resync_windows.o
endif
ifneq ($(findstring Linux,$(OS)),)
OBJ += $(DEPS_DIR)/switchres/display_linux.o
ifeq ($(HAVE_X11)$(HAVE_XRANDR), 11)
OBJ += $(DEPS_DIR)/switchres/custom_video_xrandr.o
DEFINES += -DSR_WITH_XRANDR
endif
endif
ifneq ($(findstring Win32,$(OS)),)
DEFINES += -DSR_WIN32_STATIC
endif
LIBS += -lstdc++
endif
ifeq ($(HAVE_COMPRESSION), 1)
DEFINES += -DHAVE_COMPRESSION
OBJ += tasks/task_decompress.o
+1 -1
View File
@@ -490,7 +490,7 @@ else ifeq ($(platform), windows_msvc2005_x86)
CXX = cl.exe
LD = link.exe
PLATCFLAGS += -D_WIN32 -D_WIN32_WINNT=0x0410 -D__STDC_CONSTANT_MACROS -D_MBCS -D__SSE__
PLATCFLAGS += -D_WIN32 -D_WIN32_WINNT=0x0410 -D__STDC_CONSTANT_MACROS -D_MBCS
PLATCFLAGS += -DHAVE_OPENGL -DHAVE_OPENGL1 -DHAVE_GLSL -DHAVE_OZONE -DHAVE_GFX_WIDGETS -DHAVE_CC_RESAMPLER
PLATCFLAGS += -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_ASSETS -DHAVE_UPDATE_CORES -DHAVE_CDROM
PLATCFLAGS += -bigobj
+1 -1
View File
@@ -30,7 +30,7 @@ CORE_PATH = pkg/psl1ght/pkg/USRDIR/cores/CORE.SELF
INCLUDE += -I. -Ips3/gcmgl/include/export -Ips3/include -Ideps -Ideps/stb -Ilibretro-common/include/compat/zlib -Ilibretro-common/include $(LIBPSL1GHT_INC) -Iinclude -Idefines
LIBDIRS += -L.
MACHDEP := -D__PSL1GHT__ -mcpu=cell
MACHDEP := -D__PSL1GHT__ -D__PS3__ -mcpu=cell
CFLAGS += -Wall $(MACHDEP) $(INCLUDE)
LDFLAGS := $(MACHDEP)
LIBS := -lretro_psl1ght -laudio -lrsx -lgcm_sys -lnet -lio -lsysutil -lsysmodule -lm -ljpgdec -lpngdec -llv2 -lnet -lnetctl -lsysfs
+4 -3
View File
@@ -27,13 +27,14 @@ ELF_TARGET := retroarch_psl1ght_salamander.elf
ELF_TARGET_NONSTRIPPED := retroarch_psl1ght_salamander_nonstripped.elf
EBOOT_PATH = pkg/psl1ght/pkg/USRDIR/EBOOT.BIN
INCLUDE += -I. -Ips3/gcmgl/include/export -Ips3/include -Ideps -Ideps/stb -Ilibretro-common/include/compat/zlib -Ilibretro-common/include $(LIBPSL1GHT_INC) -Iinclude
INCLUDE += -I. -Ips3/gcmgl/include/export -Ips3/include -Ideps -Ideps/stb -Ilibretro-common/include/compat/zlib \
-Ilibretro-common/include $(LIBPSL1GHT_INC) -Iinclude -Idefines
LIBDIRS += -L.
MACHDEP := -D__PSL1GHT__ -mcpu=cell -mhard-float -fmodulo-sched -ffunction-sections -fdata-sections
MACHDEP := -D__PS3__ -D__PSL1GHT__ -mcpu=cell -mhard-float -fmodulo-sched -ffunction-sections -fdata-sections
CFLAGS += -Wall $(MACHDEP) $(INCLUDE)
LDFLAGS := $(MACHDEP)
LIBS := -lgcm_sys -lrsx -lsysutil -lio -lnet -lsysmodule -lrt -llv2 -lm
LIBS := -lgcm_sys -lrsx -lsysutil -lio -lnet -lsysmodule -lrt -llv2 -lm -lsysfs
# system platform
system_platform = unix
+2 -2
View File
@@ -19,7 +19,7 @@ ifeq ($(WHOLE_ARCHIVE_LINK), 1)
WHOLE_END := -Wl,--no-whole-archive
endif
INCDIR = deps deps/stb deps/7zip deps/pthreads deps/pthreads/platform/psp deps/pthreads/platform/helper libretro-common/include libretro-common/include/compat/zlib
INCDIR = deps deps/stb deps/7zip libretro-common/include libretro-common/include/compat/zlib
CFLAGS = $(OPTIMIZE_LV) -G0 -std=gnu99 -ffast-math -fsingle-precision-constant
ASFLAGS = $(CFLAGS)
@@ -27,7 +27,7 @@ RARCH_DEFINES = -DPSP -D_MIPS_ARCH_ALLEGREX -DHAVE_LANGEXTRA -DHAVE_ZLIB -DHAVE_
LIBDIR =
LDFLAGS =
LIBS = $(WHOLE_START) -lretro_psp1 $(WHOLE_END) -lstdc++ -lpspgu -lpspgum -lm -lpspaudio -lpspfpu -lpsppower -lpsprtc
LIBS = $(WHOLE_START) -lretro_psp1 $(WHOLE_END) -lstdc++ -lpspgu -lpspgum -lm -lpspaudio -lpspfpu -lpsppower -lpsprtc -lpthread-psp
ifeq ($(HAVE_THREADS), 1)
RARCH_DEFINES += -DHAVE_THREADS
+3 -1
View File
@@ -219,7 +219,9 @@ opk: $(TARGET)
echo "$$DESKTOP_ENTRY" > default.gcw0.desktop
rm -f $(OPK_NAME)
cp media/ico_src/icon32.png retroarch.png
if [ $$STRIP_BIN -eq 1 ]; then $(STRIP) --strip-unneeded retroarch; fi
ifeq ($(STRIP_BIN),1)
$(STRIP) --strip-unneeded retroarch
endif
$(GCW0_MK_SQUASH_FS) retroarch default.gcw0.desktop retroarch.png $(OPK_NAME) -all-root -no-xattrs -noappend -no-exports
rm -f default.gcw0.desktop retroarch.png
+3 -1
View File
@@ -219,7 +219,9 @@ opk: $(TARGET)
echo "$$DESKTOP_ENTRY" > default.gcw0.desktop
rm -f $(OPK_NAME)
cp media/ico_src/icon32.png retroarch.png
if [ $$STRIP_BIN -eq 1 ]; then $(STRIP) --strip-unneeded retroarch; fi
ifeq ($(STRIP_BIN),1)
$(STRIP) --strip-unneeded retroarch
endif
$(GCW0_MK_SQUASH_FS) retroarch default.gcw0.desktop retroarch.png $(OPK_NAME) -all-root -no-xattrs -noappend -no-exports
rm -f default.gcw0.desktop retroarch.png
+6 -4
View File
@@ -13,7 +13,7 @@ PC_DEVELOPMENT_UDP_PORT =
OBJ :=
SCE_LIBC_SIZE := 4194304
DEFINES := -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_ASSETS
DEFINES := -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_ASSETS -DHAVE_STB_VORBIS
INCDIRS :=
ifeq ($(GRIFFIN_BUILD), 1)
@@ -113,16 +113,18 @@ LD := $(CXX)
LIBDIRS := -L.
ARCHFLAGS := -march=armv7-a -mfpu=neon -mfloat-abi=hard -DVITA -DSCE_LIBC_SIZE=$(SCE_LIBC_SIZE)
CFLAGS += $(ARCHFLAGS) -mword-relocations -fno-optimize-sibling-calls -O2
CFLAGS += $(ARCHFLAGS) -mword-relocations -fno-optimize-sibling-calls
ifeq ($(DEBUG), 1)
CFLAGS += -g
CFLAGS += -g -Og
else
CFLAGS += -O2
endif
ASFLAGS := $(CFLAGS)
LDFLAGS := -Wl,-q
CFLAGS += -Wall -ffast-math -g
CFLAGS += -Wall -ffast-math
CFLAGS += -DRARCH_INTERNAL -DHAVE_SCREENSHOTS -DRARCH_CONSOLE
CFLAGS += -DHAVE_DSP_FILTER
CFLAGS += -DHAVE_VIDEO_FILTER
+2 -1
View File
@@ -546,7 +546,8 @@ static ssize_t dsound_write(void *data, const void *buf_, size_t size)
break;
if (avail == 0)
WaitForSingleObject(ds->event, INFINITE);
if (!(WaitForSingleObject(ds->event, 50) == WAIT_OBJECT_0))
return -1;
}
}
+1 -1
View File
@@ -28,7 +28,7 @@
#include <retro_inline.h>
#include "../../retroarch.h"
#include "../../defines/gx_defines.h"
#include <defines/gx_defines.h>
typedef struct
{
+1 -1
View File
@@ -21,7 +21,7 @@
#include "../../retroarch.h"
#include "../../defines/ps3_defines.h"
#include <defines/ps3_defines.h>
#define AUDIO_BLOCKS 8
#define AUDIO_CHANNELS 2
@@ -144,7 +144,7 @@ static void *libnx_audren_thread_audio_init(const char *device, unsigned rate, u
int mpid;
size_t mempool_size;
unsigned real_latency;
uint32_t thread_priority;
int32_t thread_priority;
RARCH_LOG("[Audio]: Using libnx_audren_thread driver\n");
+2 -1
View File
@@ -371,7 +371,8 @@ static ssize_t xa_write(void *data, const void *buf, size_t size)
XAUDIO2_BUFFER xa2buffer;
while (handle->buffers == MAX_BUFFERS - 1)
WaitForSingleObject(handle->hEvent, INFINITE);
if (!(WaitForSingleObject(handle->hEvent, 50) == WAIT_OBJECT_0))
return -1;
xa2buffer.Flags = 0;
xa2buffer.AudioBytes = handle->bufsize;
+1 -1
View File
@@ -1,6 +1,6 @@
#include <errno.h>
#include <reent.h>
#include "../../defines/psp_defines.h"
#include <defines/psp_defines.h>
#include <psp2/kernel/sysmem.h>
#include <psp2/kernel/threadmgr.h>
-91
View File
@@ -1,91 +0,0 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2015-2016 - Andre Leiradella
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <file/file_path.h>
#include "../file_path_special.h"
#include "../configuration.h"
#include "../gfx/gfx_display.h"
#include "badges.h"
#ifdef HAVE_MENU
#define CHEEVOS_MENU_BADGE_LIMIT 256
/* TODO/FIXME - public global variables */
static uintptr_t cheevos_badge_menu_texture_list[CHEEVOS_MENU_BADGE_LIMIT] = { 0 };
void cheevos_reset_menu_badges(void)
{
int index;
for (index = 0; index < CHEEVOS_MENU_BADGE_LIMIT; ++index)
{
if (cheevos_badge_menu_texture_list[index])
video_driver_texture_unload(&cheevos_badge_menu_texture_list[index]);
}
memset(&cheevos_badge_menu_texture_list, 0,
sizeof(cheevos_badge_menu_texture_list));
}
void cheevos_set_menu_badge(int index, const char *badge, bool locked)
{
settings_t *settings = config_get_ptr();
if (index >= CHEEVOS_MENU_BADGE_LIMIT)
return;
if (!settings || !settings->bools.cheevos_badges_enable)
cheevos_badge_menu_texture_list[index] = 0;
else
cheevos_badge_menu_texture_list[index] =
cheevos_get_badge_texture(badge, locked);
}
uintptr_t cheevos_get_menu_badge_texture(int index)
{
if (index < CHEEVOS_MENU_BADGE_LIMIT)
return cheevos_badge_menu_texture_list[index];
return 0;
}
#endif
uintptr_t cheevos_get_badge_texture(const char *badge, bool locked)
{
char badge_file[24];
char fullpath[PATH_MAX_LENGTH];
uintptr_t tex = 0;
if (!badge)
return 0;
fullpath[0] = badge_file[0] = '\0';
strlcpy(badge_file, badge, sizeof(badge_file));
if (locked)
strlcat(badge_file, "_lock", sizeof(badge_file));
strlcat(badge_file, FILE_PATH_PNG_EXTENSION, sizeof(badge_file));
fill_pathname_application_special(fullpath, sizeof(fullpath),
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES);
if (!gfx_display_reset_textures_list(badge_file, fullpath,
&tex, TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL))
tex = 0;
return tex;
}
-35
View File
@@ -1,35 +0,0 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2015-2018 - Andre Leiradella
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __RARCH_CHEEVOS_BADGE_H
#define __RARCH_CHEEVOS_BADGE_H
#include <stdint.h>
#include <retro_common_api.h>
#include <boolean.h>
RETRO_BEGIN_DECLS
#ifdef HAVE_MENU
void cheevos_reset_menu_badges(void);
void cheevos_set_menu_badge(int index, const char *badge, bool locked);
uintptr_t cheevos_get_menu_badge_texture(int index);
#endif
uintptr_t cheevos_get_badge_texture(const char* badge, bool locked);
RETRO_END_DECLS
#endif
+329 -677
View File
File diff suppressed because it is too large. Load diff
+8 -33
View File
@@ -21,64 +21,39 @@
#include <boolean.h>
#include "../verbosity.h"
#include <retro_common_api.h>
RETRO_BEGIN_DECLS
typedef struct rcheevos_ctx_desc
{
unsigned idx;
char *s;
size_t len;
} rcheevos_ctx_desc_t;
enum
{
RCHEEVOS_ACTIVE_SOFTCORE = 1 << 0,
RCHEEVOS_ACTIVE_HARDCORE = 1 << 1,
RCHEEVOS_ACTIVE_UNOFFICIAL = 1 << 2
};
bool rcheevos_load(const void *data);
size_t rcheevos_get_serialize_size(void);
bool rcheevos_get_serialized_data(void* buffer);
bool rcheevos_set_serialized_data(void* buffer);
void rcheevos_reset_game(bool widgets_ready);
void rcheevos_populate_menu(void* data);
void rcheevos_populate_hardcore_pause_menu(void* data);
void rcheevos_get_achievement_state(unsigned index, char* buffer, size_t buffer_size);
bool rcheevos_get_description(rcheevos_ctx_desc_t *desc);
void rcheevos_pause_hardcore(void);
bool rcheevos_unload(void);
void rcheevos_test(void);
void rcheevos_reset_game(bool widgets_ready);
void rcheevos_pause_hardcore(void);
void rcheevos_hardcore_enabled_changed(void);
void rcheevos_toggle_hardcore_paused(void);
bool rcheevos_hardcore_active(void);
void rcheevos_validate_config_settings(void);
void rcheevos_leaderboards_enabled_changed(void);
void rcheevos_test(void);
void rcheevos_set_support_cheevos(bool state);
bool rcheevos_get_support_cheevos(void);
const char* rcheevos_get_hash(void);
const char *rcheevos_get_richpresence(void);
int rcheevos_get_richpresence(char buffer[], int buffer_size);
uintptr_t rcheevos_get_badge_texture(const char *badge, bool locked);
uint8_t* rcheevos_patch_address(unsigned address);
bool rcheevos_hardcore_active(void);
RETRO_END_DECLS
#endif /* __RARCH_CHEEVOS_CHEEVOS_H */
+158
View File
@@ -0,0 +1,158 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2015-2018 - Andre Leiradella
* Copyright (C) 2019-2021 - Brian Weiss
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __RARCH_CHEEVOS_LOCALS_H
#define __RARCH_CHEEVOS_LOCALS_H
#include "../deps/rcheevos/include/rc_runtime.h"
#include "../deps/rcheevos/src/rcheevos/rc_libretro.h"
#include <../command.h>
#include <../verbosity.h>
#include <boolean.h>
#include <queues/task_queue.h>
#ifdef HAVE_THREADS
#include <rthreads/rthreads.h>
#endif
#include <retro_common_api.h>
RETRO_BEGIN_DECLS
/************************************************************************
* Logging *
************************************************************************/
/* Define this macro to get extra-verbose log for cheevos. */
#define CHEEVOS_VERBOSE
#define RCHEEVOS_TAG "[RCHEEVOS]: "
#define CHEEVOS_FREE(p) do { void* q = (void*)p; if (q) free(q); } while (0)
#ifdef CHEEVOS_VERBOSE
#define CHEEVOS_LOG RARCH_LOG
#define CHEEVOS_ERR RARCH_ERR
#else
void rcheevos_log(const char *fmt, ...);
#define CHEEVOS_LOG rcheevos_log
#define CHEEVOS_ERR RARCH_ERR
#endif
/************************************************************************
* State *
************************************************************************/
enum
{
RCHEEVOS_ACTIVE_SOFTCORE = 1 << 0,
RCHEEVOS_ACTIVE_HARDCORE = 1 << 1,
RCHEEVOS_ACTIVE_UNOFFICIAL = 1 << 2
};
typedef struct rcheevos_racheevo_t
{
const char* title;
const char* description;
const char* badge;
const char* memaddr;
unsigned id;
unsigned points;
retro_time_t unlock_time;
uint8_t active;
#ifdef HAVE_MENU
uint8_t menu_bucket;
uint8_t menu_progress;
uint8_t menu_badge_grayscale;
uintptr_t menu_badge_texture;
#endif
} rcheevos_racheevo_t;
typedef struct rcheevos_ralboard_t
{
const char* title;
const char* description;
const char* mem;
unsigned id;
unsigned format;
} rcheevos_ralboard_t;
typedef struct rcheevos_rapatchdata_t
{
char* title;
rcheevos_racheevo_t* core;
rcheevos_racheevo_t* unofficial;
rcheevos_ralboard_t* lboards;
char* richpresence_script;
unsigned game_id;
unsigned console_id;
unsigned core_count;
unsigned unofficial_count;
unsigned lboard_count;
} rcheevos_rapatchdata_t;
#ifdef HAVE_MENU
typedef struct rcheevos_menuitem_t
{
rcheevos_racheevo_t* cheevo;
enum msg_hash_enums state_label_idx;
} rcheevos_menuitem_t;
void rcheevos_menu_reset_badges(void);
#endif
typedef struct rcheevos_locals_t
{
rc_runtime_t runtime; /* rcheevos runtime state */
rcheevos_rapatchdata_t patchdata; /* achievement/leaderboard data from the server */
rc_libretro_memory_regions_t memory;/* achievement addresses to core memory mappings */
retro_task_t* task; /* load task */
#ifdef HAVE_THREADS
slock_t* task_lock; /* mutex for starting/stopping load task */
enum event_command queued_command; /* action queued by background thread to be run on main thread */
#endif
char token[32]; /* user's session token */
char hash[33]; /* retroachievements hash for current content */
char user_agent_prefix[128]; /* RetroArch/OS version information */
#ifdef HAVE_MENU
rcheevos_menuitem_t* menuitems; /* array of items for the achievements quick menu */
unsigned menuitem_capacity; /* maximum number of items in the menuitems array */
unsigned menuitem_count; /* current number of items in the menuitems array */
#endif
bool hardcore_active; /* hardcore functionality is active */
bool loaded; /* load task has completed */
bool core_supports; /* false if core explicitly disables achievements */
bool leaderboards_enabled; /* leaderboards are enabled */
bool leaderboard_notifications; /* leaderboard notifications are enabled */
bool leaderboard_trackers; /* leaderboard trackers are enabled */
} rcheevos_locals_t;
rcheevos_locals_t* get_rcheevos_locals(void);
RETRO_END_DECLS
#endif /* __RARCH_CHEEVOS_LOCALS_H */
-352
View File
@@ -1,352 +0,0 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2015-2016 - Andre Leiradella
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "cheevos_memory.h"
#include "util.h"
#include "../retroarch.h"
#include "../verbosity.h"
#include "../deps/rcheevos/include/rcheevos.h"
#include <stdio.h>
uint8_t* rcheevos_memory_find(
const rcheevos_memory_regions_t* regions, unsigned address)
{
unsigned i;
for (i = 0; i < regions->count; ++i)
{
const size_t size = regions->size[i];
if (address < size)
{
if (regions->data[i] == NULL)
break;
return &regions->data[i][address];
}
address -= size;
}
return NULL;
}
static const char* rcheevos_memory_type(int type)
{
switch (type)
{
case RC_MEMORY_TYPE_SAVE_RAM:
return "SRAM";
case RC_MEMORY_TYPE_VIDEO_RAM:
return "VRAM";
case RC_MEMORY_TYPE_UNUSED:
return "UNUSED";
default:
break;
}
return "SYSTEM RAM";
}
static void rcheevos_memory_register_region(rcheevos_memory_regions_t* regions,
int type, uint8_t* data, size_t size, const char* description)
{
if (size == 0)
return;
if (regions->count == MAX_MEMORY_REGIONS)
{
CHEEVOS_LOG(RCHEEVOS_TAG "Too many memory memory regions to register\n");
return;
}
if (!data && regions->count > 0 && !regions->data[regions->count - 1])
{
/* extend null region */
regions->size[regions->count - 1] += size;
}
else if (data && regions->count > 0 &&
data == (regions->data[regions->count - 1] + regions->size[regions->count - 1]))
{
/* extend non-null region */
regions->size[regions->count - 1] += size;
}
else
{
/* create new region */
regions->data[regions->count] = data;
regions->size[regions->count] = size;
++regions->count;
}
regions->total_size += size;
CHEEVOS_LOG(RCHEEVOS_TAG "Registered 0x%04X bytes of %s at $%06X (%s)\n", (unsigned)size,
rcheevos_memory_type(type), (unsigned)(regions->total_size - size), description);
}
static void rcheevos_memory_init_without_regions(
rcheevos_memory_regions_t* regions)
{
/* no regions specified, assume system RAM followed by save RAM */
char description[64];
retro_ctx_memory_info_t meminfo;
snprintf(description, sizeof(description), "offset 0x%06x", 0);
meminfo.id = RETRO_MEMORY_SYSTEM_RAM;
core_get_memory(&meminfo);
rcheevos_memory_register_region(regions, RC_MEMORY_TYPE_SYSTEM_RAM, (uint8_t*)meminfo.data, meminfo.size, description);
meminfo.id = RETRO_MEMORY_SAVE_RAM;
core_get_memory(&meminfo);
rcheevos_memory_register_region(regions, RC_MEMORY_TYPE_SAVE_RAM, (uint8_t*)meminfo.data, meminfo.size, description);
}
static const rarch_memory_descriptor_t* rcheevos_memory_get_descriptor(const rarch_memory_map_t* mmap, unsigned real_address)
{
const rarch_memory_descriptor_t* desc = mmap->descriptors;
const rarch_memory_descriptor_t* end = desc + mmap->num_descriptors;
if (mmap->num_descriptors == 0)
return NULL;
for (; desc < end; desc++)
{
if (desc->core.select == 0)
{
/* if select is 0, attempt to explcitly match the address */
if (real_address >= desc->core.start && real_address < desc->core.start + desc->core.len)
return desc;
}
else
{
/* otherwise, attempt to match the address by matching the select bits */
if (((desc->core.start ^ real_address) & desc->core.select) == 0)
{
/* sanity check - make sure the descriptor is large enough to hold the target address */
if (real_address - desc->core.start < desc->core.len)
return desc;
}
}
}
return NULL;
}
void rcheevos_memory_init_from_memory_map(rcheevos_memory_regions_t* regions, const rarch_memory_map_t* mmap, const rc_memory_regions_t* console_regions)
{
char description[64];
unsigned i;
uint8_t* region_start;
uint8_t* desc_start;
size_t desc_size;
size_t offset;
for (i = 0; i < console_regions->num_regions; ++i)
{
const rc_memory_region_t* console_region = &console_regions->region[i];
size_t console_region_size = console_region->end_address - console_region->start_address + 1;
unsigned real_address = console_region->real_address;
while (console_region_size > 0)
{
const rarch_memory_descriptor_t* desc = rcheevos_memory_get_descriptor(mmap, real_address);
if (!desc)
{
if (console_region->type != RC_MEMORY_TYPE_UNUSED)
{
CHEEVOS_LOG(RCHEEVOS_TAG "Could not map region starting at $%06X\n",
real_address - console_region->real_address + console_region->start_address);
}
rcheevos_memory_register_region(regions, console_region->type, NULL, console_region_size, "null filler");
break;
}
offset = real_address - desc->core.start;
snprintf(description, sizeof(description),
"descriptor %u, offset 0x%06X",
(int)(desc - mmap->descriptors) + 1, (int)offset);
if (desc->core.ptr)
{
desc_start = (uint8_t*)desc->core.ptr + desc->core.offset;
region_start = desc_start + offset;
}
else
region_start = NULL;
desc_size = desc->core.len - offset;
if (console_region_size > desc_size)
{
if (desc_size == 0)
{
if (console_region->type != RC_MEMORY_TYPE_UNUSED)
{
CHEEVOS_LOG(RCHEEVOS_TAG "Could not map region starting at $%06X\n",
real_address - console_region->real_address + console_region->start_address);
}
rcheevos_memory_register_region(regions, console_region->type, NULL, console_region_size, "null filler");
console_region_size = 0;
}
else
{
rcheevos_memory_register_region(regions, console_region->type, region_start, desc_size, description);
console_region_size -= desc_size;
real_address += desc_size;
}
}
else
{
rcheevos_memory_register_region(regions, console_region->type, region_start, console_region_size, description);
console_region_size = 0;
}
}
}
}
static unsigned rcheevos_memory_console_region_to_ram_type(int region_type)
{
switch (region_type)
{
case RC_MEMORY_TYPE_SAVE_RAM:
return RETRO_MEMORY_SAVE_RAM;
case RC_MEMORY_TYPE_VIDEO_RAM:
return RETRO_MEMORY_VIDEO_RAM;
default:
break;
}
return RETRO_MEMORY_SYSTEM_RAM;
}
static void rcheevos_memory_init_from_unmapped_memory(rcheevos_memory_regions_t* regions, const rc_memory_regions_t* console_regions, int console)
{
char description[64];
unsigned i;
for (i = 0; i < console_regions->num_regions; ++i)
{
size_t offset;
unsigned j;
retro_ctx_memory_info_t meminfo;
const rc_memory_region_t* console_region = &console_regions->region[i];
const size_t console_region_size =
console_region->end_address - console_region->start_address + 1;
unsigned base_address = 0;
meminfo.id = rcheevos_memory_console_region_to_ram_type(console_region->type);
for (j = 0; j <= i; ++j)
{
const rc_memory_region_t* console_region2 = &console_regions->region[j];
if (rcheevos_memory_console_region_to_ram_type(
console_region2->type) == meminfo.id)
{
base_address = console_region2->start_address;
break;
}
}
offset = console_region->start_address - base_address;
core_get_memory(&meminfo);
if (offset < meminfo.size)
{
meminfo.size -= offset;
if (meminfo.data)
{
snprintf(description, sizeof(description),
"offset 0x%06X", (int)offset);
meminfo.data = (uint8_t*)meminfo.data + offset;
}
else
snprintf(description, sizeof(description), "null filler");
}
else
{
if (console_region->type != RC_MEMORY_TYPE_UNUSED)
{
CHEEVOS_LOG(RCHEEVOS_TAG "Could not map region starting at $%06X\n", console_region->start_address);
}
meminfo.data = NULL;
meminfo.size = 0;
}
if (console_region_size > meminfo.size)
{
/* want more than what is available, take what we can and null fill the rest */
rcheevos_memory_register_region(regions, console_region->type, (uint8_t*)meminfo.data, meminfo.size, description);
rcheevos_memory_register_region(regions, console_region->type, NULL, console_region_size - meminfo.size, "null filler");
}
else
{
/* only take as much as we need */
rcheevos_memory_register_region(regions, console_region->type, (uint8_t*)meminfo.data, console_region_size, description);
}
}
}
void rcheevos_memory_destroy(rcheevos_memory_regions_t* regions)
{
memset(regions, 0, sizeof(*regions));
}
bool rcheevos_memory_init(rcheevos_memory_regions_t* regions, int console)
{
unsigned i;
const rc_memory_regions_t* console_regions = rc_console_memory_regions(console);
rcheevos_memory_regions_t new_regions;
bool has_valid_region = false;
if (!regions)
return false;
memset(&new_regions, 0, sizeof(new_regions));
if (console_regions == NULL || console_regions->num_regions == 0)
{
rcheevos_memory_init_without_regions(&new_regions);
}
else
{
rarch_system_info_t* system = runloop_get_system_info();
if (system->mmaps.num_descriptors != 0)
rcheevos_memory_init_from_memory_map(&new_regions, &system->mmaps, console_regions);
else
rcheevos_memory_init_from_unmapped_memory(&new_regions, console_regions, console);
}
/* determine if any valid regions were found */
for (i = 0; i < new_regions.count; i++)
{
if (new_regions.data[i])
{
has_valid_region = true;
break;
}
}
memcpy(regions, &new_regions, sizeof(*regions));
return has_valid_region;
}
+709
View File
@@ -0,0 +1,709 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2019-2021 - Brian Weiss
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "cheevos_locals.h"
#include "../gfx/gfx_display.h"
#ifdef HAVE_MENU
#include "cheevos.h"
#include "../deps/rcheevos/include/rc_runtime_types.h"
#include "../file_path_special.h"
#include "../menu/menu_driver.h"
#include "../menu/menu_entries.h"
#include <features/features_cpu.h>
enum rcheevos_menuitem_bucket
{
RCHEEVOS_MENUITEM_BUCKET_UNKNOWN = 0,
RCHEEVOS_MENUITEM_BUCKET_LOCKED,
RCHEEVOS_MENUITEM_BUCKET_UNLOCKED,
RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED,
RCHEEVOS_MENUITEM_BUCKET_RECENTLY_UNLOCKED,
RCHEEVOS_MENUITEM_BUCKET_ACTIVE_CHALLENGE,
RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE
};
static void rcheevos_menu_update_bucket(rcheevos_racheevo_t* cheevo)
{
cheevo->menu_progress = 0;
if (!cheevo->memaddr)
{
/* non-active unsupported achievement */
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED;
}
else if (!(cheevo->active & RCHEEVOS_ACTIVE_HARDCORE))
{
/* non-active unlocked in hardcore achievement */
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_UNLOCKED;
}
else
{
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
rc_trigger_t* trigger;
if (!rcheevos_locals->hardcore_active && !(cheevo->active & RCHEEVOS_ACTIVE_SOFTCORE))
{
/* non-active unlocked in softcore achievement in softcore mode */
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_UNLOCKED;
return;
}
/* active achievement */
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_LOCKED;
trigger = rc_runtime_get_achievement(&rcheevos_locals->runtime, cheevo->id);
if (trigger)
{
if (trigger->measured_value && trigger->measured_target)
{
const unsigned long clamped_value = (unsigned long)
MIN(trigger->measured_value, trigger->measured_target);
cheevo->menu_progress =
(uint8_t)((clamped_value * 100) / trigger->measured_target);
}
if (trigger->state == RC_TRIGGER_STATE_PRIMED)
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_ACTIVE_CHALLENGE;
else if (cheevo->menu_progress >= 80)
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE;
}
}
}
static void rcheevos_menu_update_buckets(bool cheevos_test_unofficial)
{
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
rcheevos_racheevo_t* cheevo = rcheevos_locals->patchdata.core;
rcheevos_racheevo_t* stop = cheevo + rcheevos_locals->patchdata.core_count;
while (cheevo < stop)
{
rcheevos_menu_update_bucket(cheevo);
++cheevo;
}
if (cheevos_test_unofficial)
{
cheevo = rcheevos_locals->patchdata.unofficial;
stop = cheevo + rcheevos_locals->patchdata.unofficial_count;
while (cheevo < stop)
{
rcheevos_menu_update_bucket(cheevo);
++cheevo;
}
}
}
bool rcheevos_menu_get_state(unsigned menu_offset, char *buffer, size_t len)
{
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
if (menu_offset < rcheevos_locals->menuitem_count)
{
const rcheevos_menuitem_t* menuitem = &rcheevos_locals->menuitems[menu_offset];
const rcheevos_racheevo_t* cheevo = menuitem->cheevo;
if (cheevo)
{
if (cheevo->menu_progress)
{
snprintf(buffer, len, "%s - %d%%",
msg_hash_to_str(menuitem->state_label_idx),
cheevo->menu_progress);
}
else
{
strlcpy(buffer, msg_hash_to_str(menuitem->state_label_idx), len);
}
return true;
}
}
if (buffer)
buffer[0] = '\0';
return false;
}
bool rcheevos_menu_get_sublabel(unsigned menu_offset, char *buffer, size_t len)
{
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
if (menu_offset < rcheevos_locals->menuitem_count)
{
const rcheevos_racheevo_t* cheevo = rcheevos_locals->menuitems[menu_offset].cheevo;
if (cheevo && buffer)
{
strlcpy(buffer, cheevo->description, len);
return true;
}
}
if (buffer)
buffer[0] = '\0';
return false;
}
void rcheevos_menu_reset_badges(void)
{
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
rcheevos_racheevo_t* cheevo = rcheevos_locals->patchdata.core;
rcheevos_racheevo_t* stop = cheevo + rcheevos_locals->patchdata.core_count;
while (cheevo < stop)
{
if (cheevo->menu_badge_texture)
video_driver_texture_unload(&cheevo->menu_badge_texture);
++cheevo;
}
cheevo = rcheevos_locals->patchdata.unofficial;
stop = cheevo + rcheevos_locals->patchdata.unofficial_count;
while (cheevo < stop)
{
if (cheevo->menu_badge_texture)
video_driver_texture_unload(&cheevo->menu_badge_texture);
++cheevo;
}
}
static rcheevos_menuitem_t* rcheevos_menu_allocate(
rcheevos_locals_t* rcheevos_locals, rcheevos_racheevo_t* cheevo)
{
rcheevos_menuitem_t* menuitem;
if (rcheevos_locals->menuitem_count == rcheevos_locals->menuitem_capacity)
{
if (rcheevos_locals->menuitems)
{
rcheevos_menuitem_t* new_menuitems;
rcheevos_locals->menuitem_capacity += 32;
new_menuitems = (rcheevos_menuitem_t*)realloc(rcheevos_locals->menuitems,
rcheevos_locals->menuitem_capacity * sizeof(rcheevos_menuitem_t));
if (new_menuitems)
{
rcheevos_locals->menuitems = new_menuitems;
}
else
{
/* realloc failed */
CHEEVOS_ERR(RCHEEVOS_TAG " could not allocate space for %u menu items\n",
rcheevos_locals->menuitem_capacity);
rcheevos_locals->menuitem_capacity -= 32;
return NULL;
}
}
else
{
rcheevos_locals->menuitem_capacity = 64;
rcheevos_locals->menuitems = (rcheevos_menuitem_t*)
malloc(rcheevos_locals->menuitem_capacity * sizeof(rcheevos_menuitem_t));
if (!rcheevos_locals->menuitems)
{
/* malloc failed */
CHEEVOS_ERR(RCHEEVOS_TAG " could not allocate space for %u menu items\n",
rcheevos_locals->menuitem_capacity);
rcheevos_locals->menuitem_capacity = 0;
return NULL;
}
}
}
menuitem = &rcheevos_locals->menuitems[rcheevos_locals->menuitem_count++];
menuitem->cheevo = cheevo;
menuitem->state_label_idx = MSG_UNKNOWN;
return menuitem;
}
static void rcheevos_menu_append_header(rcheevos_locals_t* rcheevos_locals,
enum msg_hash_enums label)
{
rcheevos_menuitem_t* menuitem = rcheevos_menu_allocate(rcheevos_locals, NULL);
if (menuitem)
menuitem->state_label_idx = label;
}
static void rcheevos_menu_update_badge(rcheevos_racheevo_t* cheevo)
{
bool badge_grayscale = false;
switch (cheevo->menu_bucket)
{
case RCHEEVOS_MENUITEM_BUCKET_LOCKED:
case RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED:
case RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE:
case RCHEEVOS_MENUITEM_BUCKET_ACTIVE_CHALLENGE:
badge_grayscale = true;
break;
default:
badge_grayscale = false;
break;
}
if (!cheevo->menu_badge_texture || cheevo->menu_badge_grayscale != badge_grayscale)
{
uintptr_t new_badge_texture =
rcheevos_get_badge_texture(cheevo->badge, badge_grayscale);
if (new_badge_texture)
{
if (cheevo->menu_badge_texture)
video_driver_texture_unload(&cheevo->menu_badge_texture);
cheevo->menu_badge_texture = new_badge_texture;
cheevo->menu_badge_grayscale = badge_grayscale;
}
/* menu_badge_grayscale is overloaded such that any value greater than 1 indicates
* the server default image is being used */
else if (cheevo->menu_badge_grayscale < 2)
{
if (cheevo->menu_badge_texture)
video_driver_texture_unload(&cheevo->menu_badge_texture);
/* requested badge is not available, check for server default */
cheevo->menu_badge_texture =
rcheevos_get_badge_texture("00000", false);
if (cheevo->menu_badge_texture)
cheevo->menu_badge_grayscale = 2;
}
}
}
static void rcheevos_menu_append_items(rcheevos_locals_t* rcheevos_locals,
bool cheevos_test_unofficial, enum rcheevos_menuitem_bucket bucket)
{
const settings_t *settings = config_get_ptr();
rcheevos_racheevo_t* cheevo = rcheevos_locals->patchdata.core;
rcheevos_racheevo_t* stop = cheevo + rcheevos_locals->patchdata.core_count;
bool processing_unofficial = false;
const unsigned first_index = rcheevos_locals->menuitem_count;
do
{
if (cheevo == stop)
{
if (!cheevos_test_unofficial || processing_unofficial)
break;
processing_unofficial = true;
cheevo = rcheevos_locals->patchdata.unofficial;
stop = cheevo + rcheevos_locals->patchdata.unofficial_count;
continue;
}
if (cheevo->menu_bucket == bucket)
{
rcheevos_menuitem_t* menuitem = rcheevos_menu_allocate(rcheevos_locals, cheevo);
if (!menuitem)
return;
switch (cheevo->menu_bucket)
{
case RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED:
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNSUPPORTED_ENTRY;
break;
case RCHEEVOS_MENUITEM_BUCKET_RECENTLY_UNLOCKED:
{
/* insert the item such that the unlock times are descending */
unsigned entry_index = rcheevos_locals->menuitem_count - 1;
while (entry_index > first_index)
{
rcheevos_menuitem_t* prev_menuitem = menuitem - 1;
if (prev_menuitem->cheevo->unlock_time >= cheevo->unlock_time)
break;
memcpy(menuitem, prev_menuitem, sizeof(rcheevos_menuitem_t));
menuitem = prev_menuitem;
--entry_index;
}
menuitem->cheevo = cheevo;
}
/* fallthrough to RCHEEVOS_MENUITEM_BUCKET_UNLOCKED */
case RCHEEVOS_MENUITEM_BUCKET_UNLOCKED:
if (!(cheevo->active & RCHEEVOS_ACTIVE_HARDCORE))
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY_HARDCORE;
else
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY;
break;
case RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE:
{
/* insert the item such that the progresses are descending */
unsigned entry_index = rcheevos_locals->menuitem_count - 1;
while (entry_index > first_index)
{
rcheevos_menuitem_t* prev_menuitem = menuitem - 1;
if (prev_menuitem->cheevo->menu_progress >= cheevo->menu_progress)
break;
memcpy(menuitem, prev_menuitem, sizeof(rcheevos_menuitem_t));
menuitem = prev_menuitem;
--entry_index;
}
menuitem->cheevo = cheevo;
}
/* fallthrough to default */
default:
if (processing_unofficial)
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNOFFICIAL_ENTRY;
else if (!(cheevo->active & RCHEEVOS_ACTIVE_SOFTCORE))
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY;
else
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY;
break;
}
if (cheevo->badge && cheevo->badge[0] && settings &&
settings->bools.cheevos_badges_enable)
{
rcheevos_menu_update_badge(cheevo);
}
}
++cheevo;
} while (true);
}
uintptr_t rcheevos_menu_get_badge_texture(unsigned menu_offset)
{
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
if (menu_offset < rcheevos_locals->menuitem_count)
{
rcheevos_racheevo_t* cheevo = rcheevos_locals->menuitems[menu_offset].cheevo;
if (cheevo)
{
/* if we're using the placeholder badge, check to see if the real badge
* has become available (do this roughly once a second) */
if (cheevo->menu_badge_grayscale >= 2)
{
if (++cheevo->menu_badge_grayscale == 64)
{
cheevo->menu_badge_grayscale = 2;
rcheevos_menu_update_badge(cheevo);
}
}
return cheevo->menu_badge_texture;
}
}
return 0;
}
void rcheevos_menu_populate_hardcore_pause_submenu(void* data)
{
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
menu_displaylist_info_t* info = (menu_displaylist_info_t*)data;
const settings_t* settings = config_get_ptr();
const bool cheevos_hardcore_mode_enable = settings->bools.cheevos_hardcore_mode_enable;
if (cheevos_hardcore_mode_enable && rcheevos_locals->loaded)
{
if (rcheevos_locals->hardcore_active)
{
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE_CANCEL),
msg_hash_to_str(MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE_CANCEL),
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_CANCEL,
MENU_SETTING_ACTION_CLOSE, 0, 0);
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE),
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE),
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE,
MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS, 0, 0);
}
else
{
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME_CANCEL),
msg_hash_to_str(MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME_CANCEL),
MENU_ENUM_LABEL_ACHIEVEMENT_RESUME_CANCEL,
MENU_SETTING_ACTION_CLOSE, 0, 0);
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME),
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_RESUME),
MENU_ENUM_LABEL_ACHIEVEMENT_RESUME,
MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS, 0, 0);
}
}
}
void rcheevos_menu_populate(void* data)
{
menu_displaylist_info_t* info = (menu_displaylist_info_t*)data;
rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
const settings_t* settings = config_get_ptr();
const bool cheevos_test_unofficial = settings->bools.cheevos_test_unofficial;
unsigned num_locked = 0;
unsigned num_unlocked = 0;
unsigned num_recently_unlocked = 0;
unsigned num_unsupported = 0;
unsigned num_active_challenges = 0;
unsigned num_almost_there = 0;
if (rcheevos_locals->loaded)
{
const retro_time_t now = cpu_features_get_time_usec();
const retro_time_t recent_unlock_time = now - (10 * 60 * 1000000); /* 10 minutes ago */
bool processing_unofficial = false;
rcheevos_racheevo_t* cheevo = NULL;
rcheevos_racheevo_t* stop = NULL;
/* first menu item is the Pause/Resume Hardcore option (unless hardcore is disabled) */
if (settings->bools.cheevos_enable && settings->bools.cheevos_hardcore_mode_enable)
{
if (rcheevos_locals->hardcore_active)
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE_MENU),
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU,
MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS, 0, 0);
else
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE_MENU),
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU,
MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS, 0, 0);
}
/* update the bucket for each achievement */
rcheevos_menu_update_buckets(cheevos_test_unofficial);
/* count items in each bucket */
cheevo = rcheevos_locals->patchdata.core;
stop = cheevo + rcheevos_locals->patchdata.core_count;
do
{
if (cheevo == stop)
{
if (!cheevos_test_unofficial || processing_unofficial)
break;
processing_unofficial = true;
cheevo = rcheevos_locals->patchdata.unofficial;
stop = cheevo + rcheevos_locals->patchdata.unofficial_count;
continue;
}
switch (cheevo->menu_bucket)
{
case RCHEEVOS_MENUITEM_BUCKET_UNLOCKED:
if (cheevo->unlock_time && cheevo->unlock_time >= recent_unlock_time)
{
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_RECENTLY_UNLOCKED;
++num_recently_unlocked;
}
else
{
++num_unlocked;
}
break;
case RCHEEVOS_MENUITEM_BUCKET_LOCKED:
++num_locked;
break;
case RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED:
++num_unsupported;
break;
case RCHEEVOS_MENUITEM_BUCKET_ACTIVE_CHALLENGE:
++num_active_challenges;
break;
case RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE:
++num_almost_there;
break;
}
++cheevo;
} while(true);
if (!rcheevos_locals->menuitems)
{
/* reserve space for all achievements and up to 6 headers before we need to realloc */
rcheevos_locals->menuitem_capacity = rcheevos_locals->patchdata.core_count + 6;
if (cheevos_test_unofficial)
rcheevos_locals->menuitem_capacity += rcheevos_locals->patchdata.unofficial_count;
rcheevos_locals->menuitems = (rcheevos_menuitem_t*)
malloc(rcheevos_locals->menuitem_capacity * sizeof(rcheevos_menuitem_t));
if (!rcheevos_locals->menuitems)
rcheevos_locals->menuitem_capacity = 0;
}
}
/* reset menu */
rcheevos_locals->menuitem_count = 0;
/* active challenges */
if (num_active_challenges)
{
rcheevos_menu_append_header(rcheevos_locals,
MENU_ENUM_LABEL_VALUE_CHEEVOS_ACTIVE_CHALLENGES_ENTRY);
rcheevos_menu_append_items(rcheevos_locals, cheevos_test_unofficial,
RCHEEVOS_MENUITEM_BUCKET_ACTIVE_CHALLENGE);
}
/* recently unlocked */
if (num_recently_unlocked)
{
rcheevos_menu_append_header(rcheevos_locals,
MENU_ENUM_LABEL_VALUE_CHEEVOS_RECENTLY_UNLOCKED_ENTRY);
rcheevos_menu_append_items(rcheevos_locals, cheevos_test_unofficial,
RCHEEVOS_MENUITEM_BUCKET_RECENTLY_UNLOCKED);
}
/* almost there */
if (num_almost_there)
{
rcheevos_menu_append_header(rcheevos_locals,
MENU_ENUM_LABEL_VALUE_CHEEVOS_ALMOST_THERE_ENTRY);
rcheevos_menu_append_items(rcheevos_locals, cheevos_test_unofficial,
RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE);
}
/* locked */
if (num_locked)
{
if (rcheevos_locals->menuitem_count > 0)
{
rcheevos_menu_append_header(rcheevos_locals,
MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY);
}
rcheevos_menu_append_items(rcheevos_locals, cheevos_test_unofficial,
RCHEEVOS_MENUITEM_BUCKET_LOCKED);
}
/* unlocked */
if (num_unlocked)
{
if (rcheevos_locals->menuitem_count > 0)
{
rcheevos_menu_append_header(rcheevos_locals,
MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY);
}
rcheevos_menu_append_items(rcheevos_locals, cheevos_test_unofficial,
RCHEEVOS_MENUITEM_BUCKET_UNLOCKED);
}
if (rcheevos_locals->menuitem_count > 0)
{
/* convert to menu entries */
rcheevos_menuitem_t* menuitem = rcheevos_locals->menuitems;
rcheevos_menuitem_t* stop = menuitem + rcheevos_locals->menuitem_count;
char buffer[128];
unsigned idx = 0;
do
{
if (menuitem->cheevo)
{
menu_entries_append_enum(info->list, menuitem->cheevo->title,
menuitem->cheevo->description,
MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY,
MENU_SETTINGS_CHEEVOS_START + idx, 0, 0);
}
else
{
snprintf(buffer, sizeof(buffer), "----- %s -----",
msg_hash_to_str(menuitem->state_label_idx));
menu_entries_append_enum(info->list, buffer, "",
MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY,
MENU_SETTINGS_CHEEVOS_START + idx, 0, 0);
}
++idx;
++menuitem;
} while (menuitem != stop);
}
else
{
/* no achievements found */
if (!rcheevos_locals->core_supports)
{
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE),
msg_hash_to_str(MENU_ENUM_LABEL_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE),
MENU_ENUM_LABEL_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE,
FILE_TYPE_NONE, 0, 0);
}
else if (!rcheevos_locals->token[0])
{
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_LOGGED_IN),
msg_hash_to_str(MENU_ENUM_LABEL_NOT_LOGGED_IN),
MENU_ENUM_LABEL_NOT_LOGGED_IN,
FILE_TYPE_NONE, 0, 0);
}
else
{
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ACHIEVEMENTS_TO_DISPLAY),
msg_hash_to_str(MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY),
MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY,
FILE_TYPE_NONE, 0, 0);
}
}
}
#endif /* HAVE_MENU */
uintptr_t rcheevos_get_badge_texture(const char *badge, bool locked)
{
char badge_file[24];
char fullpath[PATH_MAX_LENGTH];
uintptr_t tex = 0;
if (!badge)
return 0;
snprintf(badge_file, sizeof(badge_file), "%s%s%s", badge,
locked ? "_lock" : "", FILE_PATH_PNG_EXTENSION);
fill_pathname_application_special(fullpath, sizeof(fullpath),
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES);
if (!gfx_display_reset_textures_list(badge_file, fullpath,
&tex, TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL))
{
tex = 0;
}
return tex;
}
@@ -1,5 +1,6 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2015-2018 - Andre Leiradella
* Copyright (C) 2019-2021 - Brian Weiss
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
@@ -12,33 +13,29 @@
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __RARCH_CHEEVOS_MEMORY_H
#define __RARCH_CHEEVOS_MEMORY_H
#ifndef __RARCH_CHEEVOS_MENU_H
#define __RARCH_CHEEVOS_MENU_H
#ifdef HAVE_MENU
#include <stdint.h>
#include <stdlib.h>
#include <boolean.h>
#include <retro_common_api.h>
RETRO_BEGIN_DECLS
#define MAX_MEMORY_REGIONS 32
typedef struct
{
uint8_t* data[MAX_MEMORY_REGIONS];
size_t size[MAX_MEMORY_REGIONS];
size_t total_size;
unsigned count;
} rcheevos_memory_regions_t;
bool rcheevos_memory_init(rcheevos_memory_regions_t* regions, int console);
void rcheevos_memory_destroy(rcheevos_memory_regions_t* regions);
uint8_t* rcheevos_memory_find(const rcheevos_memory_regions_t* regions,
unsigned address);
void rcheevos_menu_populate(void* data);
void rcheevos_menu_populate_hardcore_pause_submenu(void* data);
bool rcheevos_menu_get_state(unsigned menu_offset, char* buffer, size_t buffer_size);
bool rcheevos_menu_get_sublabel(unsigned menu_offset, char* buffer, size_t buffer_size);
uintptr_t rcheevos_menu_get_badge_texture(unsigned menu_offset);
RETRO_END_DECLS
#endif
#endif /* HAVE_MENU */
#endif /* __RARCH_CHEEVOS_MENU_H */
+1 -1
View File
@@ -1,6 +1,6 @@
#include "cheevos_parser.h"
#include "util.h"
#include "cheevos_locals.h"
#include <encodings/utf.h>
#include <formats/rjson.h>
+1 -40
View File
@@ -16,49 +16,10 @@
#ifndef __RARCH_CHEEVOS_PARSER_H
#define __RARCH_CHEEVOS_PARSER_H
#include <stdint.h>
#include <stddef.h>
#include <boolean.h>
#include <retro_common_api.h>
#include "cheevos_locals.h"
RETRO_BEGIN_DECLS
typedef struct
{
const char* title;
const char* description;
const char* badge;
const char* memaddr;
unsigned points;
unsigned id;
unsigned active;
} rcheevos_racheevo_t;
typedef struct
{
const char* title;
const char* description;
const char* mem;
unsigned id;
unsigned format;
} rcheevos_ralboard_t;
typedef struct
{
char* title;
rcheevos_racheevo_t* core;
rcheevos_racheevo_t* unofficial;
rcheevos_ralboard_t* lboards;
char* richpresence_script;
unsigned game_id;
unsigned console_id;
unsigned core_count;
unsigned unofficial_count;
unsigned lboard_count;
} rcheevos_rapatchdata_t;
typedef void (*rcheevos_unlock_cb_t)(unsigned id, void* userdata);
int rcheevos_get_json_error(const char* json, char* token, size_t length);
-53
View File
@@ -1,53 +0,0 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2015-2016 - Andre Leiradella
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __RARCH_CHEEVOS_UTIL_H
#define __RARCH_CHEEVOS_UTIL_H
#include <retro_common_api.h>
RETRO_BEGIN_DECLS
/*****************************************************************************
Setup - mainly for debugging
*****************************************************************************/
/* Define this macro to get extra-verbose log for cheevos. */
#define CHEEVOS_VERBOSE
/*****************************************************************************
End of setup
*****************************************************************************/
#define RCHEEVOS_TAG "[RCHEEVOS]: "
#define CHEEVOS_FREE(p) do { void* q = (void*)p; if (q) free(q); } while (0)
#ifdef CHEEVOS_VERBOSE
#define CHEEVOS_LOG RARCH_LOG
#define CHEEVOS_ERR RARCH_ERR
#else
#define CHEEVOS_LOG rcheevos_log
#define CHEEVOS_ERR RARCH_ERR
void rcheevos_log(const char *fmt, ...);
#endif
RETRO_END_DECLS
#endif /* __RARCH_CHEEVOS_UTIL_H */
+1
View File
@@ -166,6 +166,7 @@ static void command_network_poll(command_t *handle)
char buf[1024];
buf[0] = '\0';
netcmd->cmd_source_len = sizeof(struct sockaddr_storage);
ret = recvfrom(netcmd->net_fd, buf, sizeof(buf) - 1, 0,
(struct sockaddr*)&netcmd->cmd_source,
&netcmd->cmd_source_len);
+29 -1
View File
@@ -48,6 +48,11 @@
#include "menu/menu_screensaver.h"
#endif
/* Required for 'show inputs on overlay' setting */
#if defined(HAVE_OVERLAY)
#include "../input/input_overlay.h"
#endif
#if defined(HW_RVL)
#define MAX_GAMMA_SETTING 30
#elif defined(GEKKO)
@@ -152,6 +157,8 @@
#define DEFAULT_CRT_SWITCH_PORCH_ADJUST 0
#define DEFAULT_CRT_SWITCH_HIRES_MENU true
#define DEFAULT_HISTORY_LIST_ENABLE true
#define DEFAULT_PLAYLIST_ENTRY_RENAME true
@@ -225,6 +232,9 @@
#define DEFAULT_FULLSCREEN_Y 0
#endif
/* Force 4k resolution */
#define DEFAULT_FORCE_RESOLUTION false
/* Number of threads to use for video recording */
#define DEFAULT_VIDEO_RECORD_THREADS 2
@@ -243,6 +253,11 @@
#endif
#define DEFAULT_CHECK_FIRMWARE_BEFORE_LOADING false
/* Specifies whether to cache core info
* into a single (compressed) file for improved
* load times on platforms with slow IO */
#define DEFAULT_CORE_INFO_CACHE_ENABLE true
/* Specifies whether to 'reload' (fork and quit)
* RetroArch when launching content with the
* currently loaded core
@@ -281,6 +296,7 @@
* Can reduce latency at cost of higher risk of stuttering.
*/
#define DEFAULT_FRAME_DELAY 0
#define MAXIMUM_FRAME_DELAY 19
/* Inserts black frame(s) inbetween frames.
* Useful for Higher Hz monitors (set to multiples of 60 Hz) who want to play 60 Hz
@@ -734,7 +750,15 @@ static const unsigned input_backtouch_toggle = false;
#define DEFAULT_OVERLAY_ENABLE_AUTOPREFERRED true
#define DEFAULT_SHOW_PHYSICAL_INPUTS true
#if defined(HAVE_OVERLAY)
#if defined(RARCH_MOBILE)
#define DEFAULT_OVERLAY_SHOW_INPUTS OVERLAY_SHOW_INPUT_TOUCHED
#else
#define DEFAULT_OVERLAY_SHOW_INPUTS OVERLAY_SHOW_INPUT_PHYSICAL
#endif
#endif
#define DEFAULT_OVERLAY_SHOW_INPUTS_PORT 0
#define DEFAULT_ALL_USERS_CONTROL_MENU false
@@ -1185,6 +1209,10 @@ static const int default_content_favorites_size = 200;
#define DEFAULT_PLAYLIST_SHOW_SUBLABELS true
#endif
/* Show the indices of playlist entries in
* a menu-driver-specific fashion */
#define DEFAULT_PLAYLIST_SHOW_ENTRY_IDX true
#define DEFAULT_PLAYLIST_FUZZY_ARCHIVE_MATCH false
#define DEFAULT_PLAYLIST_PORTABLE_PATHS false
+4 -4
View File
@@ -195,7 +195,7 @@ static const struct retro_keybind retro_keybinds_1[] = {
NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE,
MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_TRIGGER, RETROK_UNKNOWN,
RARCH_LIGHTGUN_TRIGGER, NO_BTN, NO_BTN, 0,
RARCH_LIGHTGUN_TRIGGER, RETRO_DEVICE_ID_MOUSE_LEFT, NO_BTN, 0,
true
},
{
@@ -750,7 +750,7 @@ static const struct retro_keybind retro_keybinds_1[] = {
NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE,
MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_TRIGGER, RETROK_UNKNOWN,
RARCH_LIGHTGUN_TRIGGER, NO_BTN, NO_BTN, 0,
RARCH_LIGHTGUN_TRIGGER, RETRO_DEVICE_ID_MOUSE_LEFT, NO_BTN, 0,
true
},
{
@@ -1304,7 +1304,7 @@ static const struct retro_keybind retro_keybinds_1[] = {
NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE,
MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_TRIGGER, RETROK_UNKNOWN,
RARCH_LIGHTGUN_TRIGGER, NO_BTN, NO_BTN, 0,
RARCH_LIGHTGUN_TRIGGER, RETRO_DEVICE_ID_MOUSE_LEFT, NO_BTN, 0,
true
},
{
@@ -1872,7 +1872,7 @@ static const struct retro_keybind retro_keybinds_rest[] = {
NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE,
MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_TRIGGER, RETROK_UNKNOWN,
RARCH_LIGHTGUN_TRIGGER, NO_BTN, NO_BTN, 0,
RARCH_LIGHTGUN_TRIGGER, RETRO_DEVICE_ID_MOUSE_LEFT, NO_BTN, 0,
true
},
{
+6
View File
@@ -350,6 +350,12 @@
#define SUPPORTS_CORETEXT false
#endif
#ifdef HAVE_CHECK
#define SUPPORTS_CHECK true
#else
#define SUPPORTS_CHECK false
#endif
#if !defined(_WIN32) && !defined(GLOBAL_CONFIG_DIR)
#if defined(__HAIKU__)
#define GLOBAL_CONFIG_DIR "/system/settings"
+124 -35
View File
@@ -93,6 +93,7 @@ enum video_driver_enum
VIDEO_GDI,
VIDEO_VGA,
VIDEO_FPGA,
VIDEO_RSX,
VIDEO_NULL
};
@@ -212,6 +213,7 @@ enum bluetooth_driver_enum
enum wifi_driver_enum
{
WIFI_CONNMANCTL = BLUETOOTH_NULL + 1,
WIFI_NMCLI,
WIFI_NULL
};
@@ -315,6 +317,8 @@ static const enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_VGA;
static const enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_FPGA;
#elif defined(HAVE_DYLIB) && !defined(ANDROID)
static const enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_EXT;
#elif defined(__PSL1GHT__)
static const enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_RSX;
#else
static const enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_NULL;
#endif
@@ -337,7 +341,7 @@ static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_CTR;
static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_SWITCH;
#elif defined(HAVE_PULSE)
static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_PULSE;
#elif defined(HAVE_ALSA) && defined(HAVE_VIDEOCORE)
#elif defined(HAVE_ALSA) && defined(HAVE_THREADS)
static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_ALSATHREAD;
#elif defined(HAVE_ALSA)
static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_ALSA;
@@ -465,7 +469,7 @@ static const enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_WIIU;
static const enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_XDK;
#elif defined(PS2)
static const enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_PS2;
#elif defined(__PS3__) && !defined(__PSL1GHT__)
#elif defined(__PS3__) || defined(__PSL1GHT__)
static const enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_PS3;
#elif defined(ORBIS)
static const enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_PS4;
@@ -867,6 +871,8 @@ const char *config_get_default_video(void)
return "vga";
case VIDEO_FPGA:
return "fpga";
case VIDEO_RSX:
return "rsx";
case VIDEO_NULL:
break;
}
@@ -1085,6 +1091,8 @@ const char *config_get_default_wifi(void)
{
case WIFI_CONNMANCTL:
return "connmanctl";
case WIFI_NMCLI:
return "nmcli";
case WIFI_NULL:
break;
}
@@ -1279,6 +1287,10 @@ static struct config_array_setting *populate_settings_array(settings_t *settings
SETTING_ARRAY("discord_app_id", settings->arrays.discord_app_id, true, DEFAULT_DISCORD_APP_ID, true);
SETTING_ARRAY("ai_service_url", settings->arrays.ai_service_url, true, DEFAULT_AI_SERVICE_URL, true);
SETTING_ARRAY("crt_switch_timings", settings->arrays.crt_switch_timings, false, NULL, true);
#ifdef HAVE_LAKKA
SETTING_ARRAY("cpu_main_gov", settings->arrays.cpu_main_gov, false, NULL, true);
SETTING_ARRAY("cpu_menu_gov", settings->arrays.cpu_menu_gov, false, NULL, true);
#endif
*size = count;
@@ -1448,6 +1460,7 @@ static struct config_bool_setting *populate_settings_bool(
SETTING_BOOL("frame_time_counter_reset_after_load_state", &settings->bools.frame_time_counter_reset_after_load_state, true, false, false);
SETTING_BOOL("frame_time_counter_reset_after_save_state", &settings->bools.frame_time_counter_reset_after_save_state, true, false, false);
SETTING_BOOL("crt_switch_resolution_use_custom_refresh_rate", &settings->bools.crt_switch_custom_refresh_enable, true, false, false);
SETTING_BOOL("crt_switch_hires_menu", &settings->bools.crt_switch_hires_menu, true, false, true);
SETTING_BOOL("ui_companion_start_on_boot", &settings->bools.ui_companion_start_on_boot, true, ui_companion_start_on_boot, false);
SETTING_BOOL("ui_companion_enable", &settings->bools.ui_companion_enable, true, ui_companion_enable, false);
SETTING_BOOL("ui_companion_toggle", &settings->bools.ui_companion_toggle, false, ui_companion_toggle, false);
@@ -1485,6 +1498,7 @@ static struct config_bool_setting *populate_settings_bool(
SETTING_BOOL("input_descriptor_hide_unbound", &settings->bools.input_descriptor_hide_unbound, true, input_descriptor_hide_unbound, false);
SETTING_BOOL("load_dummy_on_core_shutdown", &settings->bools.load_dummy_on_core_shutdown, true, DEFAULT_LOAD_DUMMY_ON_CORE_SHUTDOWN, false);
SETTING_BOOL("check_firmware_before_loading", &settings->bools.check_firmware_before_loading, true, DEFAULT_CHECK_FIRMWARE_BEFORE_LOADING, false);
SETTING_BOOL("core_info_cache_enable", &settings->bools.core_info_cache_enable, true, DEFAULT_CORE_INFO_CACHE_ENABLE, false);
#ifndef HAVE_DYNAMIC
SETTING_BOOL("always_reload_core_on_run_content", &settings->bools.always_reload_core_on_run_content, true, DEFAULT_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, false);
#endif
@@ -1527,6 +1541,9 @@ static struct config_bool_setting *populate_settings_bool(
SETTING_BOOL("auto_screenshot_filename", &settings->bools.auto_screenshot_filename, true, DEFAULT_AUTO_SCREENSHOT_FILENAME, false);
SETTING_BOOL("video_force_srgb_disable", &settings->bools.video_force_srgb_disable, true, false, false);
SETTING_BOOL("video_fullscreen", &settings->bools.video_fullscreen, true, DEFAULT_FULLSCREEN, false);
#ifdef __WINRT__
SETTING_BOOL("video_force_resolution", &settings->bools.video_force_resolution, true, DEFAULT_FORCE_RESOLUTION, false);
#endif
SETTING_BOOL("bundle_assets_extract_enable", &settings->bools.bundle_assets_extract_enable, true, DEFAULT_BUNDLE_ASSETS_EXTRACT_ENABLE, false);
SETTING_BOOL("video_vsync", &settings->bools.video_vsync, true, DEFAULT_VSYNC, false);
SETTING_BOOL("video_adaptive_vsync", &settings->bools.video_adaptive_vsync, true, DEFAULT_ADAPTIVE_VSYNC, false);
@@ -1726,6 +1743,7 @@ static struct config_bool_setting *populate_settings_bool(
SETTING_BOOL("cheevos_enable", &settings->bools.cheevos_enable, true, DEFAULT_CHEEVOS_ENABLE, false);
SETTING_BOOL("cheevos_test_unofficial", &settings->bools.cheevos_test_unofficial, true, false, false);
SETTING_BOOL("cheevos_hardcore_mode_enable", &settings->bools.cheevos_hardcore_mode_enable, true, false, false);
SETTING_BOOL("cheevos_challenge_indicators", &settings->bools.cheevos_challenge_indicators, true, true, false);
SETTING_BOOL("cheevos_richpresence_enable", &settings->bools.cheevos_richpresence_enable, true, true, false);
SETTING_BOOL("cheevos_unlock_sound_enable", &settings->bools.cheevos_unlock_sound_enable, true, false, false);
SETTING_BOOL("cheevos_verbose_enable", &settings->bools.cheevos_verbose_enable, true, false, false);
@@ -1736,7 +1754,6 @@ static struct config_bool_setting *populate_settings_bool(
#ifdef HAVE_OVERLAY
SETTING_BOOL("input_overlay_enable", &settings->bools.input_overlay_enable, true, config_overlay_enable_default(), false);
SETTING_BOOL("input_overlay_enable_autopreferred", &settings->bools.input_overlay_enable_autopreferred, true, DEFAULT_OVERLAY_ENABLE_AUTOPREFERRED, false);
SETTING_BOOL("input_overlay_show_physical_inputs", &settings->bools.input_overlay_show_physical_inputs, true, DEFAULT_SHOW_PHYSICAL_INPUTS, false);
SETTING_BOOL("input_overlay_hide_in_menu", &settings->bools.input_overlay_hide_in_menu, true, DEFAULT_OVERLAY_HIDE_IN_MENU, false);
SETTING_BOOL("input_overlay_hide_when_gamepad_connected", &settings->bools.input_overlay_hide_when_gamepad_connected, true, DEFAULT_OVERLAY_HIDE_WHEN_GAMEPAD_CONNECTED, false);
SETTING_BOOL("input_overlay_show_mouse_cursor", &settings->bools.input_overlay_show_mouse_cursor, true, DEFAULT_OVERLAY_SHOW_MOUSE_CURSOR, false);
@@ -1810,6 +1827,7 @@ static struct config_bool_setting *populate_settings_bool(
SETTING_BOOL("content_runtime_log", &settings->bools.content_runtime_log, true, DEFAULT_CONTENT_RUNTIME_LOG, false);
SETTING_BOOL("content_runtime_log_aggregate", &settings->bools.content_runtime_log_aggregate, true, DEFAULT_CONTENT_RUNTIME_LOG_AGGREGATE, false);
SETTING_BOOL("playlist_show_sublabels", &settings->bools.playlist_show_sublabels, true, DEFAULT_PLAYLIST_SHOW_SUBLABELS, false);
SETTING_BOOL("playlist_show_entry_idx", &settings->bools.playlist_show_entry_idx, true, DEFAULT_PLAYLIST_SHOW_ENTRY_IDX, false);
SETTING_BOOL("playlist_sort_alphabetical", &settings->bools.playlist_sort_alphabetical, true, DEFAULT_PLAYLIST_SORT_ALPHABETICAL, false);
SETTING_BOOL("playlist_fuzzy_archive_match", &settings->bools.playlist_fuzzy_archive_match, true, DEFAULT_PLAYLIST_FUZZY_ARCHIVE_MATCH, false);
SETTING_BOOL("playlist_portable_paths", &settings->bools.playlist_portable_paths, true, DEFAULT_PLAYLIST_PORTABLE_PATHS, false);
@@ -2023,7 +2041,7 @@ static struct config_uint_setting *populate_settings_uint(
SETTING_UINT("ozone_menu_color_theme", &settings->uints.menu_ozone_color_theme, true, DEFAULT_OZONE_COLOR_THEME, false);
#endif
#endif
SETTING_UINT("audio_out_rate", &settings->uints.audio_out_rate, true, DEFAULT_OUTPUT_RATE, false);
SETTING_UINT("audio_out_rate", &settings->uints.audio_output_sample_rate, true, DEFAULT_OUTPUT_RATE, false);
SETTING_UINT("custom_viewport_width", &settings->video_viewport_custom.width, false, 0 /* TODO */, false);
SETTING_UINT("crt_switch_resolution_super", &settings->uints.crt_switch_resolution_super, true, DEFAULT_CRT_SWITCH_RESOLUTION_SUPER, false);
SETTING_UINT("custom_viewport_height", &settings->video_viewport_custom.height, false, 0 /* TODO */, false);
@@ -2060,7 +2078,12 @@ static struct config_uint_setting *populate_settings_uint(
SETTING_UINT("bundle_assets_extract_version_current", &settings->uints.bundle_assets_extract_version_current, true, 0, false);
#endif
SETTING_UINT("bundle_assets_extract_last_version", &settings->uints.bundle_assets_extract_last_version, true, 0, false);
SETTING_UINT("input_overlay_show_physical_inputs_port", &settings->uints.input_overlay_show_physical_inputs_port, true, 0, false);
#if defined(HAVE_OVERLAY)
SETTING_UINT("input_overlay_show_inputs", &settings->uints.input_overlay_show_inputs, true, DEFAULT_OVERLAY_SHOW_INPUTS, false);
SETTING_UINT("input_overlay_show_inputs_port", &settings->uints.input_overlay_show_inputs_port, true, DEFAULT_OVERLAY_SHOW_INPUTS_PORT, false);
#endif
SETTING_UINT("video_msg_bgcolor_red", &settings->uints.video_msg_bgcolor_red, true, message_bgcolor_red, false);
SETTING_UINT("video_msg_bgcolor_green", &settings->uints.video_msg_bgcolor_green, true, message_bgcolor_green, false);
SETTING_UINT("video_msg_bgcolor_blue", &settings->uints.video_msg_bgcolor_blue, true, message_bgcolor_blue, false);
@@ -2112,6 +2135,12 @@ static struct config_uint_setting *populate_settings_uint(
SETTING_UINT("video_black_frame_insertion", &settings->uints.video_black_frame_insertion, true, DEFAULT_BLACK_FRAME_INSERTION, false);
#ifdef HAVE_LAKKA
SETTING_UINT("cpu_scaling_mode", &settings->uints.cpu_scaling_mode, true, 0, false);
SETTING_UINT("cpu_min_freq", &settings->uints.cpu_min_freq, true, 1, false);
SETTING_UINT("cpu_max_freq", &settings->uints.cpu_max_freq, true, ~0U, false);
#endif
*size = count;
return tmp;
@@ -2406,10 +2435,8 @@ void config_set_defaults(void *data)
#endif
input_config_reset();
#ifdef HAVE_CONFIGFILE
input_remapping_deinit();
input_remapping_set_defaults();
#endif
input_remapping_set_defaults(false);
/* Verify that binds are in proper order. */
for (i = 0; i < MAX_USERS; i++)
@@ -2432,7 +2459,7 @@ void config_set_defaults(void *data)
for (i = 0; i < MAX_USERS; i++)
{
settings->uints.input_joypad_map[i] = i;
settings->uints.input_joypad_index[i] = i;
#ifdef SWITCH /* Switch prefered default dpad mode */
settings->uints.input_analog_dpad_mode[i] = ANALOG_DPAD_LSTICK;
#else
@@ -3167,7 +3194,7 @@ static bool config_load_file(global_t *global,
buf[0] = '\0';
snprintf(buf, sizeof(buf), "input_player%u_joypad_index", i + 1);
CONFIG_GET_INT_BASE(conf, settings, uints.input_joypad_map[i], buf);
CONFIG_GET_INT_BASE(conf, settings, uints.input_joypad_index[i], buf);
snprintf(buf, sizeof(buf), "input_player%u_analog_dpad_mode", i + 1);
CONFIG_GET_INT_BASE(conf, settings, uints.input_analog_dpad_mode[i], buf);
@@ -3251,8 +3278,8 @@ static bool config_load_file(global_t *global,
if (settings->uints.video_hard_sync_frames > 3)
settings->uints.video_hard_sync_frames = 3;
if (settings->uints.video_frame_delay > 15)
settings->uints.video_frame_delay = 15;
if (settings->uints.video_frame_delay > MAXIMUM_FRAME_DELAY)
settings->uints.video_frame_delay = MAXIMUM_FRAME_DELAY;
settings->uints.video_swap_interval = MAX(settings->uints.video_swap_interval, 1);
settings->uints.video_swap_interval = MIN(settings->uints.video_swap_interval, 4);
@@ -3641,20 +3668,23 @@ bool config_load_override(void *data)
{
char temp_path[PATH_MAX_LENGTH];
temp_path[0] = '\0';
RARCH_LOG("[Overrides]: Content dir-specific overrides found at \"%s\".\n",
content_path);
if (should_append)
{
RARCH_LOG("[Overrides]: Content dir-specific overrides stacking on top of previous overrides.\n");
strlcpy(temp_path, path_get(RARCH_PATH_CONFIG_APPEND), sizeof(temp_path));
strlcat(temp_path, "|", sizeof(temp_path));
strlcat(temp_path, content_path, sizeof(temp_path));
snprintf(temp_path, sizeof(temp_path),
"%s|%s",
path_get(RARCH_PATH_CONFIG_APPEND),
content_path
);
}
else
{
temp_path[0] = '\0';
strlcpy(temp_path, content_path, sizeof(temp_path));
}
path_set(RARCH_PATH_CONFIG_APPEND, temp_path);
@@ -3670,20 +3700,23 @@ bool config_load_override(void *data)
{
char temp_path[PATH_MAX_LENGTH];
temp_path[0] = '\0';
RARCH_LOG("[Overrides]: Game-specific overrides found at \"%s\".\n",
game_path);
if (should_append)
{
RARCH_LOG("[Overrides]: Game-specific overrides stacking on top of previous overrides.\n");
strlcpy(temp_path, path_get(RARCH_PATH_CONFIG_APPEND), sizeof(temp_path));
strlcat(temp_path, "|", sizeof(temp_path));
strlcat(temp_path, game_path, sizeof(temp_path));
snprintf(temp_path, sizeof(temp_path),
"%s|%s",
path_get(RARCH_PATH_CONFIG_APPEND),
game_path
);
}
else
{
temp_path[0] = '\0';
strlcpy(temp_path, game_path, sizeof(temp_path));
}
path_set(RARCH_PATH_CONFIG_APPEND, temp_path);
@@ -3821,9 +3854,7 @@ bool config_load_remap(const char *directory_input_remapping,
FILE_PATH_REMAP_EXTENSION,
sizeof(game_path));
#ifdef HAVE_CONFIGFILE
input_remapping_set_defaults();
#endif
input_remapping_set_defaults(false);
/* If a game remap file exists, load it. */
if ((new_conf = config_file_new_from_path_to_string(game_path)))
@@ -4194,7 +4225,7 @@ bool config_save_file(const char *path)
snprintf(cfg, sizeof(cfg), "input_device_p%u", i + 1);
config_set_int(conf, cfg, settings->uints.input_device[i]);
snprintf(cfg, sizeof(cfg), "input_player%u_joypad_index", i + 1);
config_set_int(conf, cfg, settings->uints.input_joypad_map[i]);
config_set_int(conf, cfg, settings->uints.input_joypad_index[i]);
snprintf(cfg, sizeof(cfg), "input_libretro_device_p%u", i + 1);
config_set_int(conf, cfg, input_config_get_device(i));
snprintf(cfg, sizeof(cfg), "input_player%u_analog_dpad_mode", i + 1);
@@ -4457,11 +4488,11 @@ bool config_save_overrides(enum override_type type, void *data)
config_set_int(conf, cfg, overrides->uints.input_device[i]);
}
if (settings->uints.input_joypad_map[i]
!= overrides->uints.input_joypad_map[i])
if (settings->uints.input_joypad_index[i]
!= overrides->uints.input_joypad_index[i])
{
snprintf(cfg, sizeof(cfg), "input_player%u_joypad_index", i + 1);
config_set_int(conf, cfg, overrides->uints.input_joypad_map[i]);
config_set_int(conf, cfg, overrides->uints.input_joypad_index[i]);
}
}
@@ -4574,7 +4605,7 @@ bool input_remapping_load_file(void *data, const char *path)
if (!string_is_empty(global->name.remapfile))
{
input_remapping_deinit();
input_remapping_set_defaults();
input_remapping_set_defaults(false);
}
global->name.remapfile = strdup(path);
@@ -4582,9 +4613,6 @@ bool input_remapping_load_file(void *data, const char *path)
{
char s1[32], s2[32], s3[32];
global->old_analog_dpad_mode[i] = settings->uints.input_analog_dpad_mode[i];
global->old_libretro_device[i] = settings->uints.input_libretro_device[i];
s1[0] = '\0';
s2[0] = '\0';
s3[0] = '\0';
@@ -4629,9 +4657,12 @@ bool input_remapping_load_file(void *data, const char *path)
else
{
char stk_ident[128];
char key_ident[128];
int stk_remap = -1;
int key_remap = -1;
stk_ident[0] = '\0';
key_ident[0] = '\0';
fill_pathname_join_delim(stk_ident, s3,
key_string, '$', sizeof(stk_ident));
@@ -4650,6 +4681,15 @@ bool input_remapping_load_file(void *data, const char *path)
configuration_set_uint(settings,
settings->uints.input_remap_ids[i][j], stk_remap);
}
fill_pathname_join_delim(key_ident, s2,
key_string, '_', sizeof(key_ident));
if (!config_get_int(conf, key_ident, &key_remap))
key_remap = RETROK_UNKNOWN;
configuration_set_uint(settings,
settings->uints.input_keymapper_ids[i][j], key_remap);
}
}
@@ -4658,8 +4698,18 @@ bool input_remapping_load_file(void *data, const char *path)
snprintf(s1, sizeof(s1), "input_libretro_device_p%u", i + 1);
CONFIG_GET_INT_BASE(conf, settings, uints.input_libretro_device[i], s1);
snprintf(s1, sizeof(s1), "input_remap_port_p%u", i + 1);
CONFIG_GET_INT_BASE(conf, settings, uints.input_remap_ports[i], s1);
}
input_remapping_update_port_map();
/* Whenever a remap file is loaded, subsequent
* changes to global remap-related parameters
* must be reset at the next core deinitialisation */
input_remapping_enable_global_config_restore();
return true;
}
@@ -4698,14 +4748,38 @@ bool input_remapping_save_file(const char *path)
return false;
}
for (i = 0; i < max_users; i++)
for (i = 0; i < MAX_USERS; i++)
{
char s1[32], s2[32], s3[32];
bool skip_port = true;
char s1[32];
char s2[32];
char s3[32];
s1[0] = '\0';
s2[0] = '\0';
s3[0] = '\0';
/* We must include all mapped ports + all those
* with an index less than max_users */
if (i < max_users)
skip_port = false;
else
{
/* Check whether current port is mapped
* to an input device */
for (j = 0; j < max_users; j++)
{
if (i == settings->uints.input_remap_ports[j])
{
skip_port = false;
break;
}
}
}
if (skip_port)
continue;
snprintf(s1, sizeof(s1), "input_player%u_btn", i + 1);
snprintf(s2, sizeof(s2), "input_player%u_key", i + 1);
snprintf(s3, sizeof(s3), "input_player%u_stk", i + 1);
@@ -4747,6 +4821,7 @@ bool input_remapping_save_file(const char *path)
{
char stk_ident[128];
unsigned remap_id = settings->uints.input_remap_ids[i][j];
unsigned keymap_id = settings->uints.input_keymapper_ids[i][j];
const char *key_string = key_strings[j];
stk_ident[0] = '\0';
fill_pathname_join_delim(stk_ident, s3,
@@ -4763,12 +4838,26 @@ bool input_remapping_save_file(const char *path)
config_set_int(conf, stk_ident,
settings->uints.input_remap_ids[i][j]);
}
if (keymap_id != RETROK_UNKNOWN)
{
char key_ident[128];
key_ident[0] = '\0';
fill_pathname_join_delim(key_ident, s2,
key_string, '_', sizeof(key_ident));
config_set_int(conf, key_ident,
settings->uints.input_keymapper_ids[i][j]);
}
}
snprintf(s1, sizeof(s1), "input_libretro_device_p%u", i + 1);
config_set_int(conf, s1, input_config_get_device(i));
snprintf(s1, sizeof(s1), "input_player%u_analog_dpad_mode", i + 1);
config_set_int(conf, s1, settings->uints.input_analog_dpad_mode[i]);
snprintf(s1, sizeof(s1), "input_remap_port_p%u", i + 1);
config_set_int(conf, s1, settings->uints.input_remap_ports[i]);
}
ret = config_file_write(conf, remap_file, true);
+23 -7
View File
@@ -67,7 +67,9 @@ enum crt_switch_type
{
CRT_SWITCH_NONE = 0,
CRT_SWITCH_15KHZ,
CRT_SWITCH_31KHZ
CRT_SWITCH_31KHZ,
CRT_SWITCH_32_120,
CRT_SWITCH_INI
};
enum override_type
@@ -120,7 +122,7 @@ typedef struct settings
unsigned placeholder;
unsigned input_split_joycon[MAX_USERS];
unsigned input_joypad_map[MAX_USERS];
unsigned input_joypad_index[MAX_USERS];
unsigned input_device[MAX_USERS];
unsigned input_mouse_index[MAX_USERS];
/* Set by autoconfiguration in joypad_autoconfig_dir.
@@ -128,13 +130,14 @@ typedef struct settings
unsigned input_libretro_device[MAX_USERS];
unsigned input_analog_dpad_mode[MAX_USERS];
unsigned input_keymapper_ids[MAX_USERS][RARCH_CUSTOM_BIND_LIST_END];
unsigned input_remap_ports[MAX_USERS];
unsigned input_remap_ids[MAX_USERS][RARCH_CUSTOM_BIND_LIST_END];
unsigned input_keymapper_ids[MAX_USERS][RARCH_CUSTOM_BIND_LIST_END];
unsigned input_remap_port_map[MAX_USERS][MAX_USERS + 1];
unsigned led_map[MAX_LEDS];
unsigned audio_out_rate;
unsigned audio_output_sample_rate;
unsigned audio_block_frames;
unsigned audio_latency;
@@ -266,7 +269,8 @@ typedef struct settings
unsigned camera_width;
unsigned camera_height;
unsigned input_overlay_show_physical_inputs_port;
unsigned input_overlay_show_inputs;
unsigned input_overlay_show_inputs_port;
unsigned run_ahead_frames;
@@ -288,6 +292,12 @@ typedef struct settings
unsigned core_updater_auto_backup_history_size;
unsigned video_black_frame_insertion;
unsigned quit_on_close_content;
#ifdef HAVE_LAKKA
unsigned cpu_scaling_mode;
unsigned cpu_min_freq;
unsigned cpu_max_freq;
#endif
} uints;
struct
@@ -387,6 +397,8 @@ typedef struct settings
char crt_switch_timings[255];
#ifdef HAVE_LAKKA
char timezone[TIMEZONE_LENGTH];
char cpu_main_gov[32];
char cpu_menu_gov[32];
#endif
} arrays;
@@ -508,6 +520,7 @@ typedef struct settings
#ifdef HAVE_VIDEO_LAYOUT
bool video_layout_enable;
#endif
bool video_force_resolution;
/* Accessibility */
bool accessibility_enable;
@@ -533,7 +546,6 @@ typedef struct settings
bool input_overlay_enable_autopreferred;
bool input_overlay_hide_in_menu;
bool input_overlay_hide_when_gamepad_connected;
bool input_overlay_show_physical_inputs;
bool input_overlay_show_mouse_cursor;
bool input_overlay_auto_rotate;
bool input_overlay_auto_scale;
@@ -688,6 +700,7 @@ typedef struct settings
bool kiosk_mode_enable;
bool crt_switch_custom_refresh_enable;
bool crt_switch_hires_menu;
/* Netplay */
bool netplay_public_announce;
@@ -723,6 +736,7 @@ typedef struct settings
bool cheevos_auto_screenshot;
bool cheevos_start_active;
bool cheevos_unlock_sound_enable;
bool cheevos_challenge_indicators;
/* Camera */
bool camera_allow;
@@ -777,6 +791,7 @@ typedef struct settings
bool network_remote_enable_user[MAX_USERS];
bool load_dummy_on_core_shutdown;
bool check_firmware_before_loading;
bool core_info_cache_enable;
#ifndef HAVE_DYNAMIC
bool always_reload_core_on_run_content;
#endif
@@ -816,6 +831,7 @@ typedef struct settings
bool playlist_sort_alphabetical;
bool playlist_show_sublabels;
bool playlist_show_entry_idx;
bool playlist_fuzzy_archive_match;
bool playlist_portable_paths;
+4
View File
@@ -124,6 +124,10 @@ bool content_set_subsystem_by_name(const char* subsystem_name);
/* Get the current subsystem "friendly name" */
void content_get_subsystem_friendly_name(const char* subsystem_name, char* subsystem_friendly_name, size_t len);
/* Sets overrides which modify frontend handling of
* specific content file types */
bool content_file_override_set(const struct retro_system_content_info_override *overrides);
RETRO_END_DECLS
#endif
+3 -18
View File
@@ -116,7 +116,6 @@ bool core_backup_get_backup_path(
const char *core_path, uint32_t crc, enum core_backup_mode backup_mode,
const char *dir_core_assets, char *backup_path, size_t len)
{
int n;
time_t current_time;
struct tm time_info;
const char *core_filename = NULL;
@@ -152,7 +151,7 @@ bool core_backup_get_backup_path(
rtime_localtime(&current_time, &time_info);
/* Generate backup filename */
n = snprintf(backup_filename, sizeof(backup_filename),
snprintf(backup_filename, sizeof(backup_filename),
"%s.%04u%02u%02uT%02u%02u%02u.%08x.%u%s",
core_filename,
(unsigned)time_info.tm_year + 1900,
@@ -165,10 +164,6 @@ bool core_backup_get_backup_path(
(unsigned)backup_mode,
FILE_PATH_CORE_BACKUP_EXTENSION);
if ((n < 0) || (n >= 128))
n = 0; /* Silence GCC warnings... */
(void)n;
/* Build final path */
fill_pathname_join(backup_path, backup_dir,
backup_filename, len);
@@ -712,7 +707,6 @@ bool core_backup_list_get_entry_timestamp_str(
enum core_backup_date_separator_type date_separator,
char *timestamp, size_t len)
{
int n;
const char *format_str = "";
if (!entry || (len < 20))
@@ -732,7 +726,7 @@ bool core_backup_list_get_entry_timestamp_str(
break;
}
n = snprintf(timestamp, len,
snprintf(timestamp, len,
format_str,
entry->date.year,
entry->date.month,
@@ -741,9 +735,6 @@ bool core_backup_list_get_entry_timestamp_str(
entry->date.minute,
entry->date.second);
if ((n < 0) || (n >= 32))
n = 0; /* Silence GCC warnings... */
(void)n;
return true;
}
@@ -754,15 +745,9 @@ bool core_backup_list_get_entry_crc_str(
const core_backup_list_entry_t *entry,
char *crc, size_t len)
{
int n;
if (!entry || (len < 9))
return false;
n = snprintf(crc, len, "%08x", entry->crc);
if ((n < 0) || (n >= 32))
n = 0; /* Silence GCC warnings... */
(void)n;
snprintf(crc, len, "%08x", entry->crc);
return true;
}
+1458 -96
View File
File diff suppressed because it is too large. Load diff
+8 -1
View File
@@ -89,6 +89,7 @@ typedef struct
bool database_match_archive_member;
bool is_experimental;
bool is_locked;
bool is_installed;
} core_info_t;
/* A subset of core_info parameters required for
@@ -156,7 +157,7 @@ bool core_info_get_current_core(core_info_t **core);
void core_info_deinit_list(void);
bool core_info_init_list(const char *path_info, const char *dir_cores,
const char *exts, bool show_hidden_files);
const char *exts, bool show_hidden_files, bool enable_cache);
bool core_info_get_list(core_info_list_t **core);
@@ -203,6 +204,12 @@ core_info_state_t *coreinfo_get_ptr(void);
bool core_info_core_file_id_is_equal(const char *core_path_a, const char *core_path_b);
/* When called, generates a temporary file
* that will force an info cache refresh the
* next time that core info is initialised with
* caching enabled */
bool core_info_cache_force_refresh(const char *path_info);
RETRO_END_DECLS
#endif /* CORE_INFO_H_ */
+2
View File
@@ -8,8 +8,10 @@
#define CProb UInt16
#undef kTopValue
#define kTopValue ((UInt32)1 << 24)
#define kNumModelBits 11
#undef kBitModelTotal
#define kBitModelTotal (1 << kNumModelBits)
#define kNumMoveBits 5
+4 -4
View File
@@ -144,7 +144,7 @@ int x86cpuid_GetFirm(const Cx86cpuid *p)
return -1;
}
BoolInt CPU_Is_InOrder()
BoolInt CPU_Is_InOrder(void)
{
Cx86cpuid p;
int firm;
@@ -175,7 +175,7 @@ BoolInt CPU_Is_InOrder()
#if !defined(MY_CPU_AMD64) && defined(_WIN32)
#include <windows.h>
static BoolInt CPU_Sys_Is_SSE_Supported()
static BoolInt CPU_Sys_Is_SSE_Supported(void)
{
OSVERSIONINFO vi;
vi.dwOSVersionInfoSize = sizeof(vi);
@@ -188,7 +188,7 @@ static BoolInt CPU_Sys_Is_SSE_Supported()
#define CHECK_SYS_SSE_SUPPORT
#endif
BoolInt CPU_Is_Aes_Supported()
BoolInt CPU_Is_Aes_Supported(void)
{
Cx86cpuid p;
CHECK_SYS_SSE_SUPPORT
@@ -197,7 +197,7 @@ BoolInt CPU_Is_Aes_Supported()
return (p.c >> 25) & 1;
}
BoolInt CPU_IsSupported_PageGB()
BoolInt CPU_IsSupported_PageGB(void)
{
Cx86cpuid cpuid;
if (!x86cpuid_CheckAndRead(&cpuid))
+3 -3
View File
@@ -325,9 +325,9 @@ int x86cpuid_GetFirm(const Cx86cpuid *p);
#define x86cpuid_GetModel(ver) (((ver >> 12) & 0xF0) | ((ver >> 4) & 0xF))
#define x86cpuid_GetStepping(ver) (ver & 0xF)
BoolInt CPU_Is_InOrder();
BoolInt CPU_Is_Aes_Supported();
BoolInt CPU_IsSupported_PageGB();
BoolInt CPU_Is_InOrder(void);
BoolInt CPU_Is_Aes_Supported(void);
BoolInt CPU_IsSupported_PageGB(void);
#endif
+4 -1
View File
@@ -205,6 +205,7 @@ typedef struct
#define kEndPosModelIndex 14
#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
#ifndef __LZMA_DEC_H
typedef
#ifdef _LZMA_PROB32
UInt32
@@ -212,6 +213,7 @@ typedef
UInt16
#endif
CLzmaProb;
#endif
#define LZMA_PB_MAX 4
#define LZMA_LC_MAX 8
@@ -973,7 +975,8 @@ MY_NO_INLINE static void MY_FAST_CALL LenPriceEnc_UpdateTables(
printf("\n MovePos %u", num);
#endif
*/
#undef MOVE_POS
#define MOVE_POS(p, num) { \
p->additionalOffset += (num); \
p->matchFinder.Skip(p->matchFinderObj, (UInt32)(num)); }
+15 -3
View File
@@ -11,6 +11,18 @@ extern "C" {
#define RGBA8(r,g,b,a) ((((a)&0xFF)<<24) | (((b)&0xFF)<<16) | (((g)&0xFF)<<8) | (((r)&0xFF)<<0))
typedef enum
{
VITA2D_VIDEO_MODE_960x544 = 0,
VITA2D_VIDEO_MODE_1280x720
} vita2d_video_mode;
typedef struct vita2d_video_mode_data {
int width;
int height;
int stride;
} vita2d_video_mode_data;
typedef struct vita2d_clear_vertex {
float x;
float y;
@@ -58,7 +70,7 @@ typedef struct vita2d_pgf vita2d_pgf;
int vita2d_init();
int vita2d_init_advanced(unsigned int temp_pool_size);
int vita2d_init_advanced_with_msaa(unsigned int temp_pool_size, SceGxmMultisampleMode msaa);
int vita2d_init_advanced_with_msaa(unsigned int temp_pool_size, SceGxmMultisampleMode msaa, vita2d_video_mode video_mode);
void vita2d_wait_rendering_done();
int vita2d_fini();
@@ -74,8 +86,8 @@ int vita2d_common_dialog_update();
void vita2d_set_clear_color(unsigned int color);
unsigned int vita2d_get_clear_color();
void vita2d_set_clear_color(unsigned int color);
unsigned int vita2d_get_clear_color();
vita2d_video_mode_data vita2d_get_video_mode_data();
void vita2d_set_vblank_wait(int enable);
void *vita2d_get_current_fb();
SceGxmContext *vita2d_get_context();
+144 -73
View File
@@ -18,9 +18,6 @@
/* Defines */
#define DISPLAY_WIDTH 960
#define DISPLAY_HEIGHT 544
#define DISPLAY_STRIDE_IN_PIXELS 1024
#define DISPLAY_COLOR_FORMAT SCE_GXM_COLOR_FORMAT_A8B8G8R8
#define DISPLAY_PIXEL_FORMAT SCE_DISPLAY_PIXELFORMAT_A8B8G8R8
#define DISPLAY_BUFFER_COUNT 3
@@ -44,6 +41,10 @@ extern const SceGxmProgram texture_tint_f_gxp;
/* Static variables */
static vita2d_video_mode_data video_mode_data;
static vita2d_video_mode video_mode_initial;
static SceGxmMultisampleMode current_msaa = SCE_GXM_MULTISAMPLE_4X;
static int pgf_module_was_loaded = 0;
static const SceGxmProgram *const clearVertexProgramGxp = &clear_v_gxp;
@@ -60,8 +61,8 @@ static float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
static unsigned int clear_color_u = 0xFF000000;
static int clip_rect_x_min = 0;
static int clip_rect_y_min = 0;
static int clip_rect_x_max = DISPLAY_WIDTH;
static int clip_rect_y_max = DISPLAY_HEIGHT;
static int clip_rect_x_max = 0;
static int clip_rect_y_max = 0;
static int vblank_wait = 1;
static int drawing = 0;
static int clipping_enabled = 0;
@@ -152,6 +153,101 @@ static void patcher_host_free(void *user_data, void *mem)
free(mem);
}
vita2d_video_mode_data vita2d_get_video_mode_data(){
return video_mode_data;
}
static int vita2d_switch_video_mode(vita2d_video_mode video_mode){
int i,x,y,err;
if(video_mode > video_mode_initial)
return -1;
switch (video_mode)
{
case VITA2D_VIDEO_MODE_960x544:
video_mode_data.width = 960;
video_mode_data.height = 544;
video_mode_data.stride = 960;
break;
case VITA2D_VIDEO_MODE_1280x720:
video_mode_data.width = 1280;
video_mode_data.height = 720;
video_mode_data.stride = 1280;
break;
default:
return -1;
break;
}
clip_rect_x_max = video_mode_data.width;
clip_rect_y_max = video_mode_data.height;
if(renderTarget != NULL){
sceGxmDestroyRenderTarget(renderTarget);
for (i = 0; i < DISPLAY_BUFFER_COUNT; i++) {
// clear the buffer then deallocate
memset(displayBufferData[i], 0, video_mode_data.height*video_mode_data.stride*4);
gpu_free(displayBufferUid[i]);
}
}
// allocate memory and sync objects for display buffers
for (i = 0; i < DISPLAY_BUFFER_COUNT; i++) {
// allocate memory for display
displayBufferData[i] = gpu_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW,
4*video_mode_data.stride*video_mode_data.height,
SCE_GXM_COLOR_SURFACE_ALIGNMENT,
SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
&displayBufferUid[i]);
// memset the buffer to black
for (y = 0; y < video_mode_data.height; y++) {
unsigned int *row = (unsigned int *)displayBufferData[i] + y*video_mode_data.stride;
for (x = 0; x < video_mode_data.width; x++) {
row[x] = 0xff000000;
}
}
// initialize a color surface for this display buffer
err = sceGxmColorSurfaceInit(
&displaySurface[i],
DISPLAY_COLOR_FORMAT,
SCE_GXM_COLOR_SURFACE_LINEAR,
(current_msaa == SCE_GXM_MULTISAMPLE_NONE) ? SCE_GXM_COLOR_SURFACE_SCALE_NONE : SCE_GXM_COLOR_SURFACE_SCALE_MSAA_DOWNSCALE,
SCE_GXM_OUTPUT_REGISTER_SIZE_32BIT,
video_mode_data.width,
video_mode_data.height,
video_mode_data.stride,
displayBufferData[i]);
}
// set up parameters
SceGxmRenderTargetParams renderTargetParams;
memset(&renderTargetParams, 0, sizeof(SceGxmRenderTargetParams));
renderTargetParams.flags = 0;
renderTargetParams.width = video_mode_data.width;
renderTargetParams.height = video_mode_data.height;
renderTargetParams.scenesPerFrame = 1;
renderTargetParams.multisampleMode = current_msaa;
renderTargetParams.multisampleLocations = 0;
renderTargetParams.driverMemBlock = -1; // Invalid UID
// create the render target
err = sceGxmCreateRenderTarget(&renderTargetParams, &renderTarget);
VITA2D_DEBUG("sceGxmCreateRenderTarget(): 0x%08X\n", err);
matrix_init_orthographic(_vita2d_ortho_matrix, 0.0f, video_mode_data.width, video_mode_data.height, 0.0f, 0.0f, 1.0f);
return 0;
}
static void display_callback(const void *callback_data)
{
SceDisplayFrameBuf framebuf;
@@ -160,11 +256,14 @@ static void display_callback(const void *callback_data)
memset(&framebuf, 0x00, sizeof(SceDisplayFrameBuf));
framebuf.size = sizeof(SceDisplayFrameBuf);
framebuf.base = display_data->address;
framebuf.pitch = DISPLAY_STRIDE_IN_PIXELS;
framebuf.pitch = video_mode_data.stride;
framebuf.pixelformat = DISPLAY_PIXEL_FORMAT;
framebuf.width = DISPLAY_WIDTH;
framebuf.height = DISPLAY_HEIGHT;
sceDisplaySetFrameBuf(&framebuf, SCE_DISPLAY_SETBUF_NEXTFRAME);
framebuf.width = video_mode_data.width;
framebuf.height = video_mode_data.height;
if(sceDisplaySetFrameBuf(&framebuf, SCE_DISPLAY_SETBUF_NEXTFRAME) == SCE_DISPLAY_ERROR_INVALID_RESOLUTION){
if(video_mode_initial)
vita2d_switch_video_mode(VITA2D_VIDEO_MODE_960x544);
}
if (vblank_wait) {
sceDisplayWaitVblankStart();
@@ -218,10 +317,10 @@ static void _vita2d_make_fragment_programs(vita2d_fragment_programs *out,
VITA2D_DEBUG("texture_tint sceGxmShaderPatcherCreateFragmentProgram(): 0x%08X\n", err);
}
static int vita2d_init_internal(unsigned int temp_pool_size, SceGxmMultisampleMode msaa)
static int vita2d_init_internal(unsigned int temp_pool_size, SceGxmMultisampleMode msaa, vita2d_video_mode video_mode)
{
int err;
unsigned int i, x, y;
unsigned int i;
UNUSED(err);
if (vita2d_initialized) {
@@ -229,6 +328,9 @@ static int vita2d_init_internal(unsigned int temp_pool_size, SceGxmMultisampleMo
return 1;
}
video_mode_initial = video_mode;
current_msaa = msaa;
SceGxmInitializeParams initializeParams;
memset(&initializeParams, 0, sizeof(SceGxmInitializeParams));
initializeParams.flags = 0;
@@ -284,65 +386,32 @@ static int vita2d_init_internal(unsigned int temp_pool_size, SceGxmMultisampleMo
err = sceGxmCreateContext(&contextParams, &_vita2d_context);
VITA2D_DEBUG("sceGxmCreateContext(): 0x%08X\n", err);
// set up parameters
SceGxmRenderTargetParams renderTargetParams;
memset(&renderTargetParams, 0, sizeof(SceGxmRenderTargetParams));
renderTargetParams.flags = 0;
renderTargetParams.width = DISPLAY_WIDTH;
renderTargetParams.height = DISPLAY_HEIGHT;
renderTargetParams.scenesPerFrame = 1;
renderTargetParams.multisampleMode = msaa;
renderTargetParams.multisampleLocations = 0;
renderTargetParams.driverMemBlock = -1; // Invalid UID
err = vita2d_switch_video_mode(video_mode);
if(err<0){
VITA2D_DEBUG("vita2d_switch_video_mode(): 0x%08X\n", err);
return err;
}
// create the render target
err = sceGxmCreateRenderTarget(&renderTargetParams, &renderTarget);
VITA2D_DEBUG("sceGxmCreateRenderTarget(): 0x%08X\n", err);
vita2d_display_data displayData;
displayData.address = displayBufferData[0];
display_callback(&displayData);
// allocate memory and sync objects for display buffers
for (i = 0; i < DISPLAY_BUFFER_COUNT; i++) {
// allocate memory for display
displayBufferData[i] = gpu_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW,
4*DISPLAY_STRIDE_IN_PIXELS*DISPLAY_HEIGHT,
SCE_GXM_COLOR_SURFACE_ALIGNMENT,
SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
&displayBufferUid[i]);
// memset the buffer to black
for (y = 0; y < DISPLAY_HEIGHT; y++) {
unsigned int *row = (unsigned int *)displayBufferData[i] + y*DISPLAY_STRIDE_IN_PIXELS;
for (x = 0; x < DISPLAY_WIDTH; x++) {
row[x] = 0xff000000;
}
}
// initialize a color surface for this display buffer
err = sceGxmColorSurfaceInit(
&displaySurface[i],
DISPLAY_COLOR_FORMAT,
SCE_GXM_COLOR_SURFACE_LINEAR,
(msaa == SCE_GXM_MULTISAMPLE_NONE) ? SCE_GXM_COLOR_SURFACE_SCALE_NONE : SCE_GXM_COLOR_SURFACE_SCALE_MSAA_DOWNSCALE,
SCE_GXM_OUTPUT_REGISTER_SIZE_32BIT,
DISPLAY_WIDTH,
DISPLAY_HEIGHT,
DISPLAY_STRIDE_IN_PIXELS,
displayBufferData[i]);
// create a sync object that we will associate with this buffer
err = sceGxmSyncObjectCreate(&displayBufferSync[i]);
}
// compute the memory footprint of the depth buffer
const unsigned int alignedWidth = ALIGN(DISPLAY_WIDTH, SCE_GXM_TILE_SIZEX);
const unsigned int alignedHeight = ALIGN(DISPLAY_HEIGHT, SCE_GXM_TILE_SIZEY);
const unsigned int alignedWidth = ALIGN(video_mode_data.width, SCE_GXM_TILE_SIZEX);
const unsigned int alignedHeight = ALIGN(video_mode_data.height, SCE_GXM_TILE_SIZEY);
unsigned int sampleCount = alignedWidth*alignedHeight;
unsigned int depthStrideInSamples = alignedWidth;
if (msaa == SCE_GXM_MULTISAMPLE_4X) {
if (current_msaa == SCE_GXM_MULTISAMPLE_4X) {
// samples increase in X and Y
sampleCount *= 4;
depthStrideInSamples *= 2;
} else if (msaa == SCE_GXM_MULTISAMPLE_2X) {
} else if (current_msaa == SCE_GXM_MULTISAMPLE_2X) {
// samples increase in Y only
sampleCount *= 2;
}
@@ -527,7 +596,7 @@ static int vita2d_init_internal(unsigned int temp_pool_size, SceGxmMultisampleMo
shaderPatcher,
clearFragmentProgramId,
SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4,
msaa,
current_msaa,
NULL,
clearVertexProgramGxp,
&clearFragmentProgram);
@@ -686,8 +755,8 @@ static int vita2d_init_internal(unsigned int temp_pool_size, SceGxmMultisampleMo
VITA2D_DEBUG("texture sceGxmShaderPatcherCreateVertexProgram(): 0x%08X\n", err);
// Create variations of the fragment program based on blending mode
_vita2d_make_fragment_programs(&_vita2d_fragmentPrograms.blend_mode_normal, &blend_info, msaa);
_vita2d_make_fragment_programs(&_vita2d_fragmentPrograms.blend_mode_add, &blend_info_add, msaa);
_vita2d_make_fragment_programs(&_vita2d_fragmentPrograms.blend_mode_normal, &blend_info, current_msaa);
_vita2d_make_fragment_programs(&_vita2d_fragmentPrograms.blend_mode_add, &blend_info_add, current_msaa);
// Default to "normal" blending mode (non-additive)
vita2d_set_blend_mode_add(0);
@@ -713,9 +782,9 @@ static int vita2d_init_internal(unsigned int temp_pool_size, SceGxmMultisampleMo
sizeof(void *),
SCE_GXM_MEMORY_ATTRIB_READ,
&poolUid);
matrix_init_orthographic(_vita2d_ortho_matrix, 0.0f, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0.0f, 0.0f, 1.0f);
matrix_init_orthographic(_vita2d_ortho_matrix, 0.0f, video_mode_data.width, video_mode_data.height, 0.0f, 0.0f, 1.0f);
backBufferIndex = 0;
frontBufferIndex = 0;
@@ -731,22 +800,23 @@ static int vita2d_init_internal(unsigned int temp_pool_size, SceGxmMultisampleMo
int vita2d_init()
{
return vita2d_init_internal(DEFAULT_TEMP_POOL_SIZE, SCE_GXM_MULTISAMPLE_NONE);
return vita2d_init_internal(DEFAULT_TEMP_POOL_SIZE, SCE_GXM_MULTISAMPLE_NONE, VITA2D_VIDEO_MODE_960x544);
}
int vita2d_init_advanced(unsigned int temp_pool_size)
{
return vita2d_init_internal(temp_pool_size, SCE_GXM_MULTISAMPLE_NONE);
return vita2d_init_internal(temp_pool_size, SCE_GXM_MULTISAMPLE_NONE, VITA2D_VIDEO_MODE_960x544);
}
int vita2d_init_advanced_with_msaa(unsigned int temp_pool_size, SceGxmMultisampleMode msaa)
int vita2d_init_advanced_with_msaa(unsigned int temp_pool_size, SceGxmMultisampleMode msaa, vita2d_video_mode video_mode)
{
return vita2d_init_internal(temp_pool_size, msaa);
return vita2d_init_internal(temp_pool_size, msaa, video_mode);
}
void vita2d_wait_rendering_done()
{
sceGxmFinish(_vita2d_context);
if(vita2d_initialized)
sceGxmFinish(_vita2d_context);
}
int vita2d_fini()
@@ -780,7 +850,7 @@ int vita2d_fini()
gpu_free(depthBufferUid);
for (i = 0; i < DISPLAY_BUFFER_COUNT; i++) {
// clear the buffer then deallocate
memset(displayBufferData[i], 0, DISPLAY_HEIGHT*DISPLAY_STRIDE_IN_PIXELS*4);
memset(displayBufferData[i], 0, video_mode_data.height*video_mode_data.stride*4);
gpu_free(displayBufferUid[i]);
// destroy the sync object
@@ -808,6 +878,7 @@ int vita2d_fini()
// destroy the render target
sceGxmDestroyRenderTarget(renderTarget);
renderTarget = NULL;
// destroy the _vita2d_context
sceGxmDestroyContext(_vita2d_context);
@@ -933,7 +1004,7 @@ int vita2d_get_clipping_enabled()
void vita2d_set_clip_rectangle(int x_min, int y_min, int x_max, int y_max)
{
vita2d_set_viewport(0,0,DISPLAY_WIDTH,DISPLAY_HEIGHT);
vita2d_set_viewport(0,0,video_mode_data.width,video_mode_data.height);
clipping_enabled = 1;
clip_rect_x_min = x_min;
clip_rect_y_min = y_min;
@@ -952,7 +1023,7 @@ void vita2d_set_clip_rectangle(int x_min, int y_min, int x_max, int y_max)
SCE_GXM_STENCIL_OP_ZERO,
0xFF,
0xFF);
vita2d_draw_rectangle(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0);
vita2d_draw_rectangle(0, 0, video_mode_data.width, video_mode_data.height, 0);
// set the stencil to 1 in the desired region
sceGxmSetFrontStencilFunc(
_vita2d_context,
@@ -1003,9 +1074,9 @@ int vita2d_common_dialog_update()
updateParam.renderTarget.colorFormat = DISPLAY_COLOR_FORMAT;
updateParam.renderTarget.surfaceType = SCE_GXM_COLOR_SURFACE_LINEAR;
updateParam.renderTarget.width = DISPLAY_WIDTH;
updateParam.renderTarget.height = DISPLAY_HEIGHT;
updateParam.renderTarget.strideInPixels = DISPLAY_STRIDE_IN_PIXELS;
updateParam.renderTarget.width = video_mode_data.width;
updateParam.renderTarget.height = video_mode_data.height;
updateParam.renderTarget.strideInPixels = video_mode_data.stride;
updateParam.renderTarget.colorSurfaceData = displayBufferData[backBufferIndex];
updateParam.renderTarget.depthSurfaceData = depthBufferData;
@@ -1100,7 +1171,7 @@ void vita2d_set_blend_mode_add(int enable)
}
void vita2d_set_viewport(int x, int y, int width, int height){
static float vh = DISPLAY_HEIGHT;
float vh = video_mode_data.height;
float sw = width / 2.;
float sh = height / 2.;
float x_scale = sw;
-476
View File
@@ -1,476 +0,0 @@
PTHREADS-WIN32 RELEASE 2.8.0 (2006-12-22)
-----------------------------------------
Web Site: http://sources.redhat.com/pthreads-win32/
FTP Site: ftp://sources.redhat.com/pub/pthreads-win32
Maintainer: Ross Johnson <[email protected]>
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 <[email protected]>.
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:
[email protected]
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
-129
View File
@@ -1,129 +0,0 @@
Contributors (in approximate order of appearance)
[See also the ChangeLog file where individuals are
attributed in log entries. Likewise in the FAQ file.]
Ben Elliston bje at cygnus dot com
Initiated the project;
setup the project infrastructure (CVS, web page, etc.);
early prototype routines.
Ross Johnson rpj at callisto dot canberra dot edu dot au
early prototype routines;
ongoing project coordination/maintenance;
implementation of spin locks and barriers;
various enhancements;
bug fixes;
documentation;
testsuite.
Robert Colquhoun rjc at trump dot net dot au
Early bug fixes.
John E. Bossom John dot Bossom at cognos dot com
Contributed substantial original working implementation;
bug fixes;
ongoing guidance and standards interpretation.
Anders Norlander anorland at hem2 dot passagen dot se
Early enhancements and runtime checking for supported
Win32 routines.
Tor Lillqvist tml at iki dot fi
General enhancements;
early bug fixes to condition variables.
Scott Lightner scott at curriculum dot com
Bug fix.
Kevin Ruland Kevin dot Ruland at anheuser-busch dot com
Various bug fixes.
Mike Russo miker at eai dot com
Bug fix.
Mark E. Armstrong avail at pacbell dot net
Bug fixes.
Lorin Hochstein lmh at xiphos dot ca
general bug fixes; bug fixes to condition variables.
Peter Slacik Peter dot Slacik at tatramed dot sk
Bug fixes.
Mumit Khan khan at xraylith dot wisc dot edu
Fixes to work with Mingw32.
Milan Gardian mg at tatramed dot sk
Bug fixes and reports/analyses of obscure problems.
Aurelio Medina aureliom at crt dot com
First implementation of read-write locks.
Graham Dumpleton Graham dot Dumpleton at ra dot pad dot otc dot telstra dot com dot au
Bug fix in condition variables.
Tristan Savatier tristan at mpegtv dot com
WinCE port.
Erik Hensema erik at hensema dot xs4all dot nl
Bug fixes.
Rich Peters rpeters at micro-magic dot com
Todd Owen towen at lucidcalm dot dropbear dot id dot au
Bug fixes to dll loading.
Jason Nye jnye at nbnet dot nb dot ca
Implementation of async cancelation.
Fred Forester fforest at eticomm dot net
Kevin D. Clark kclark at cabletron dot com
David Baggett dmb at itasoftware dot com
Bug fixes.
Paul Redondo paul at matchvision dot com
Scott McCaskill scott at 3dfx dot com
Bug fixes.
Jef Gearhart jgearhart at tpssys dot com
Bug fix.
Arthur Kantor akantor at bexusa dot com
Mutex enhancements.
Steven Reddie smr at essemer dot com dot au
Bug fix.
Alexander Terekhov TEREKHOV at de dot ibm dot com
Re-implemented and improved read-write locks;
(with Louis Thomas) re-implemented and improved
condition variables;
enhancements to semaphores;
enhancements to mutexes;
new mutex implementation in 'futex' style;
suggested a robust implementation of pthread_once
similar to that implemented by V.Kliathcko;
system clock change handling re CV timeouts;
bug fixes.
Thomas Pfaff tpfaff at gmx dot net
Changes to make C version usable with C++ applications;
re-implemented mutex routines to avoid Win32 mutexes
and TryEnterCriticalSection;
procedure to fix Mingw32 thread-safety issues.
Franco Bez franco dot bez at gmx dot de
procedure to fix Mingw32 thread-safety issues.
Louis Thomas lthomas at arbitrade dot com
(with Alexander Terekhov) re-implemented and improved
condition variables.
David Korn dgk at research dot att dot com
Ported to UWIN.
Phil Frisbie, Jr. phil at hawksoft dot com
Bug fix.
Ralf Brese Ralf dot Brese at pdb4 dot siemens dot de
Bug fix.
prionx at juno dot com prionx at juno dot com
Bug fixes.
Max Woodbury mtew at cds dot duke dot edu
POSIX versioning conditionals;
reduced namespace pollution;
idea to separate routines to reduce statically
linked image sizes.
Rob Fanner rfanner at stonethree dot com
Bug fix.
Michael Johnson michaelj at maine dot rr dot com
Bug fix.
Nicolas Barry boozai at yahoo dot com
Bug fixes.
Piet van Bruggen pietvb at newbridges dot nl
Bug fix.
Makoto Kato raven at oldskool dot jp
AMD64 port.
Panagiotis E. Hadjidoukas peh at hpclab dot ceid dot upatras dot gr
Contributed the QueueUserAPCEx package which
makes preemptive async cancelation possible.
Will Bryant will dot bryant at ecosm dot com
Borland compiler patch and makefile.
Anuj Goyal anuj dot goyal at gmail dot com
Port to Digital Mars compiler.
Gottlob Frege gottlobfrege at gmail dot com
re-implemented pthread_once (version 2)
(pthread_once cancellation added by rpj).
Vladimir Kliatchko vladimir at kliatchko dot com
reimplemented pthread_once with the same form
as described by A.Terekhov (later version 2);
implementation of MCS (Mellor-Crummey/Scott) locks.
-150
View File
@@ -1,150 +0,0 @@
pthreads-win32 - a POSIX threads library for Microsoft Windows
This file is Copyrighted
------------------------
This file is covered under the following Copyright:
Copyright (C) 2001,2006 Ross P. Johnson
All rights reserved.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Pthreads-win32 is covered by the GNU Lesser General Public License
------------------------------------------------------------------
Pthreads-win32 is open software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation version 2.1 of the
License.
Pthreads-win32 is several binary link libraries, several modules,
associated interface definition files and scripts used to control
its compilation and installation.
Pthreads-win32 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
A copy of the GNU Lesser General Public License is distributed with
pthreads-win32 under the filename:
COPYING.LIB
You should have received a copy of the version 2.1 GNU Lesser General
Public License with pthreads-win32; if not, write to:
Free Software Foundation, Inc.
59 Temple Place
Suite 330
Boston, MA 02111-1307
USA
The contact addresses for pthreads-win32 is as follows:
Web: http://sources.redhat.com/pthreads-win32
Email: Ross Johnson
Please use: [email protected]
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: [email protected]
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.
-504
View File
@@ -1,504 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
-516
View File
@@ -1,516 +0,0 @@
/*
* implement.h
*
* Definitions that don't need to be public.
*
* Keeps all the internals out of pthread.h
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef _IMPLEMENT_H
#define _IMPLEMENT_H
#include "pte_osal.h"
/* use local include files during development */
#include "semaphore.h"
#include "sched.h"
typedef enum
{
/*
* This enumeration represents the state of the thread;
* The thread is still "alive" if the numeric value of the
* state is greater or equal "PThreadStateRunning".
*/
PThreadStateInitial = 0, /* Thread not running */
PThreadStateRunning, /* Thread alive & kicking */
PThreadStateSuspended, /* Thread alive but suspended */
PThreadStateCancelPending, /* Thread alive but is */
/* has cancelation pending. */
PThreadStateCanceling, /* Thread alive but is */
/* in the process of terminating */
/* due to a cancellation request */
PThreadStateException, /* Thread alive but exiting */
/* due to an exception */
PThreadStateLast
}
PThreadState;
typedef struct pte_thread_t_ pte_thread_t;
struct pte_thread_t_
{
pte_osThreadHandle threadId; /* OS specific thread handle */
// pthread_t ptHandle; /* This thread's permanent pthread_t handle */
pte_thread_t * prevReuse; /* Links threads on reuse stack */
volatile PThreadState state;
void *exitStatus;
void *parms;
int ptErrno;
int detachState;
pthread_mutex_t threadLock; /* Used for serialised access to public thread state */
int sched_priority; /* As set, not as currently is */
pthread_mutex_t cancelLock; /* Used for async-cancel safety */
int cancelState;
int cancelType;
int cancelEvent;
jmp_buf start_mark;
int implicit:
1;
void *keys;
void *nextAssoc;
unsigned int x; /* Extra information - reuse count etc */
};
/*
* Special value to mark attribute objects as valid.
*/
#define PTE_ATTR_VALID ((unsigned long) 0xC4C0FFEE)
struct pthread_attr_t_
{
unsigned long valid;
void *stackaddr;
size_t stacksize;
int detachstate;
struct sched_param param;
int inheritsched;
int contentionscope;
};
/*
* ====================
* ====================
* Semaphores, Mutexes and Condition Variables
* ====================
* ====================
*/
struct sem_t_
{
int value;
pthread_mutex_t lock;
pte_osSemaphoreHandle sem;
};
#define PTE_OBJECT_AUTO_INIT ((void *) -1)
#define PTE_OBJECT_INVALID 0
struct pthread_mutex_t_
{
pte_osSemaphoreHandle handle;
int lock_idx;
/* Provides exclusive access to mutex state
via the Interlocked* mechanism.
0: unlocked/free.
1: locked - no other waiters.
-1: locked - with possible other waiters.
*/
int recursive_count; /* Number of unlocks a thread needs to perform
before the lock is released (recursive
mutexes only). */
int kind; /* Mutex type. */
pthread_t ownerThread;
};
struct pthread_mutexattr_t_
{
int pshared;
int kind;
};
/*
* Possible values, other than PTE_OBJECT_INVALID,
* for the "interlock" element in a spinlock.
*
* In this implementation, when a spinlock is initialised,
* the number of cpus available to the process is checked.
* If there is only one cpu then "interlock" is set equal to
* PTE_SPIN_USE_MUTEX and u.mutex is a initialised mutex.
* If the number of cpus is greater than 1 then "interlock"
* is set equal to PTE_SPIN_UNLOCKED and the number is
* stored in u.cpus. This arrangement allows the spinlock
* routines to attempt an InterlockedCompareExchange on "interlock"
* immediately and, if that fails, to try the inferior mutex.
*
* "u.cpus" isn't used for anything yet, but could be used at
* some point to optimise spinlock behaviour.
*/
#define PTE_SPIN_UNLOCKED (1)
#define PTE_SPIN_LOCKED (2)
#define PTE_SPIN_USE_MUTEX (3)
struct pthread_spinlock_t_
{
int interlock; /* Locking element for multi-cpus. */
union
{
int cpus; /* No. of cpus if multi cpus, or */
pthread_mutex_t mutex; /* mutex if single cpu. */
} u;
};
struct pthread_barrier_t_
{
unsigned int nCurrentBarrierHeight;
unsigned int nInitialBarrierHeight;
int iStep;
int pshared;
sem_t semBarrierBreeched[2];
};
struct pthread_barrierattr_t_
{
int pshared;
};
struct pthread_key_t_
{
unsigned key;
void (*destructor) (void *);
pthread_mutex_t keyLock;
void *threads;
};
typedef struct ThreadParms ThreadParms;
typedef struct ThreadKeyAssoc ThreadKeyAssoc;
struct ThreadParms
{
pthread_t tid;
void *(*start) (void *);
void *arg;
};
struct pthread_cond_t_
{
long nWaitersBlocked; /* Number of threads blocked */
long nWaitersGone; /* Number of threads timed out */
long nWaitersToUnblock; /* Number of threads to unblock */
sem_t semBlockQueue; /* Queue up threads waiting for the */
/* condition to become signalled */
sem_t semBlockLock; /* Semaphore that guards access to */
/* | waiters blocked count/block queue */
/* +-> Mandatory Sync.LEVEL-1 */
pthread_mutex_t mtxUnblockLock; /* Mutex that guards access to */
/* | waiters (to)unblock(ed) counts */
/* +-> Optional* Sync.LEVEL-2 */
pthread_cond_t next; /* Doubly linked list */
pthread_cond_t prev;
};
struct pthread_condattr_t_
{
int pshared;
};
#define PTE_RWLOCK_MAGIC 0xfacade2
struct pthread_rwlock_t_
{
pthread_mutex_t mtxExclusiveAccess;
pthread_mutex_t mtxSharedAccessCompleted;
pthread_cond_t cndSharedAccessCompleted;
int nSharedAccessCount;
int nExclusiveAccessCount;
int nCompletedSharedAccessCount;
int nMagic;
};
struct pthread_rwlockattr_t_
{
int pshared;
};
/*
* MCS lock queue node - see pte_MCS_lock.c
*/
struct pte_mcs_node_t_
{
struct pte_mcs_node_t_ **lock; /* ptr to tail of queue */
struct pte_mcs_node_t_ *next; /* ptr to successor in queue */
unsigned int readyFlag; /* set after lock is released by
predecessor */
unsigned int nextFlag; /* set after 'next' ptr is set by
successor */
};
typedef struct pte_mcs_node_t_ pte_mcs_local_node_t;
typedef struct pte_mcs_node_t_ *pte_mcs_lock_t;
struct ThreadKeyAssoc
{
/*
* Purpose:
* This structure creates an association between a thread and a key.
* It is used to implement the implicit invocation of a user defined
* destroy routine for thread specific data registered by a user upon
* exiting a thread.
*
* Graphically, the arrangement is as follows, where:
*
* K - Key with destructor
* (head of chain is key->threads)
* T - Thread that has called pthread_setspecific(Kn)
* (head of chain is thread->keys)
* A - Association. Each association is a node at the
* intersection of two doubly-linked lists.
*
* T1 T2 T3
* | | |
* | | |
* K1 -----+-----A-----A----->
* | | |
* | | |
* K2 -----A-----A-----+----->
* | | |
* | | |
* K3 -----A-----+-----A----->
* | | |
* | | |
* V V V
*
* Access to the association is guarded by two locks: the key's
* general lock (guarding the row) and the thread's general
* lock (guarding the column). This avoids the need for a
* dedicated lock for each association, which not only consumes
* more handles but requires that: before the lock handle can
* be released - both the key must be deleted and the thread
* must have called the destructor. The two-lock arrangement
* allows the resources to be freed as soon as either thread or
* key is concluded.
*
* To avoid deadlock: whenever both locks are required, the key
* and thread locks are always acquired in the order: key lock
* then thread lock. An exception to this exists when a thread
* calls the destructors, however this is done carefully to
* avoid deadlock.
*
* An association is created when a thread first calls
* pthread_setspecific() on a key that has a specified
* destructor.
*
* An association is destroyed either immediately after the
* thread calls the key destructor function on thread exit, or
* when the key is deleted.
*
* Attributes:
* thread
* reference to the thread that owns the
* association. This is actually the pointer to the
* thread struct itself. Since the association is
* destroyed before the thread exits, this can never
* point to a different logical thread to the one that
* created the assoc, i.e. after thread struct reuse.
*
* key
* reference to the key that owns the association.
*
* nextKey
* The pthread_t->keys attribute is the head of a
* chain of associations that runs through the nextKey
* link. This chain provides the 1 to many relationship
* between a pthread_t and all pthread_key_t on which
* it called pthread_setspecific.
*
* prevKey
* Similarly.
*
* nextThread
* The pthread_key_t->threads attribute is the head of
* a chain of assoctiations that runs through the
* nextThreads link. This chain provides the 1 to many
* relationship between a pthread_key_t and all the
* PThreads that have called pthread_setspecific for
* this pthread_key_t.
*
* prevThread
* Similarly.
*
* Notes:
* 1) As soon as either the key or the thread is no longer
* referencing the association, it can be destroyed. The
* association will be removed from both chains.
*
* 2) An association is only created by
* pthread_setspecific if the user provided a
* destroyRoutine when they created the key.
*
*
*/
pte_thread_t * thread;
pthread_key_t key;
ThreadKeyAssoc *nextKey;
ThreadKeyAssoc *nextThread;
ThreadKeyAssoc *prevKey;
ThreadKeyAssoc *prevThread;
};
/*
* Services available through EXCEPTION_PTE_SERVICES
* and also used [as parameters to pte_throw()] as
* generic exception selectors.
*/
#define PTE_EPS_EXIT (1)
#define PTE_EPS_CANCEL (2)
/* Useful macros */
#define PTE_MAX(a,b) ((a)<(b)?(b):(a))
#define PTE_MIN(a,b) ((a)>(b)?(b):(a))
/* Thread Reuse stack bottom marker. Must not be NULL or any valid pointer to memory. */
#define PTE_THREAD_REUSE_EMPTY ((pte_thread_t *) 1)
extern int pte_processInitialized;
extern pte_thread_t * pte_threadReuseTop;
extern pte_thread_t * pte_threadReuseBottom;
extern pthread_key_t pte_selfThreadKey;
extern pthread_key_t pte_cleanupKey;
extern pthread_cond_t pte_cond_list_head;
extern pthread_cond_t pte_cond_list_tail;
extern int pte_mutex_default_kind;
extern int pte_concurrency;
extern int pte_features;
extern pte_osMutexHandle pte_thread_reuse_lock;
extern pte_osMutexHandle pte_mutex_test_init_lock;
extern pte_osMutexHandle pte_cond_list_lock;
extern pte_osMutexHandle pte_cond_test_init_lock;
extern pte_osMutexHandle pte_rwlock_test_init_lock;
extern pte_osMutexHandle pte_spinlock_test_init_lock;
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
/*
* =====================
* =====================
* Forward Declarations
* =====================
* =====================
*/
int pte_is_attr (const pthread_attr_t * attr);
int pte_cond_check_need_init (pthread_cond_t * cond);
int pte_mutex_check_need_init (pthread_mutex_t * mutex);
int pte_rwlock_check_need_init (pthread_rwlock_t * rwlock);
int pte_spinlock_check_need_init (pthread_spinlock_t * lock);
int pte_processInitialize (void);
void pte_processTerminate (void);
void pte_threadDestroy (pthread_t tid);
void pte_threadExitAndDestroy (pthread_t tid);
void pte_pop_cleanup_all (int execute);
pthread_t pte_new (void);
pthread_t pte_threadReusePop (void);
void pte_threadReusePush (pthread_t thread);
int pte_getprocessors (int *count);
int pte_setthreadpriority (pthread_t thread, int policy, int priority);
void pte_rwlock_cancelwrwait (void *arg);
int pte_threadStart (void *vthreadParms);
void pte_callUserDestroyRoutines (pthread_t thread);
int pte_tkAssocCreate (pte_thread_t * thread, pthread_key_t key);
void pte_tkAssocDestroy (ThreadKeyAssoc * assoc);
int sem_wait_nocancel (sem_t * sem);
unsigned int pte_relmillisecs (const struct timespec * abstime);
void pte_mcs_lock_acquire (pte_mcs_lock_t * lock, pte_mcs_local_node_t * node);
void pte_mcs_lock_release (pte_mcs_local_node_t * node);
/* Declared in private.c */
void pte_throw (unsigned int exception);
int pte_cancellable_wait (pte_osSemaphoreHandle semHandle, unsigned int* timeout);
#define PTE_ATOMIC_EXCHANGE pte_osAtomicExchange
#define PTE_ATOMIC_EXCHANGE_ADD pte_osAtomicExchangeAdd
#define PTE_ATOMIC_COMPARE_EXCHANGE pte_osAtomicCompareExchange
#define PTE_ATOMIC_DECREMENT pte_osAtomicDecrement
#define PTE_ATOMIC_INCREMENT pte_osAtomicIncrement
int pte_thread_detach_np();
int pte_thread_detach_and_exit_np();
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _IMPLEMENT_H */
-90
View File
@@ -1,90 +0,0 @@
/***
* errno.h - system wide error numbers (set by system calls)
*
* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
*
* Purpose:
* This file defines the system-wide error numbers (set by
* system calls). Conforms to the XENIX standard. Extended
* for compatibility with Uniforum standard.
* [System V]
*
* [Public]
*
****/
#ifndef _INC_ERRNO
#define _INC_ERRNO
#ifdef __cplusplus
extern "C"
{
#endif
/* declare reference to errno */
extern int errno;
/* Error Codes */
#define EPERM 1
#define ENOENT 2
#define ESRCH 3
#define EINTR 4
#define EIO 5
#define ENXIO 6
#define E2BIG 7
#define ENOEXEC 8
#define EBADF 9
#define ECHILD 10
#define EAGAIN 11
#define ENOMEM 12
#define EACCES 13
#define EFAULT 14
#define EBUSY 16
#define EEXIST 17
#define EXDEV 18
#define ENODEV 19
#define ENOTDIR 20
#define EISDIR 21
#define EINVAL 22
#define ENFILE 23
#define EMFILE 24
#define ENOTTY 25
#define EFBIG 27
#define ENOSPC 28
#define ESPIPE 29
#define EROFS 30
#define EMLINK 31
#define EPIPE 32
#define EDOM 33
#define ERANGE 34
#define EDEADLK 36
/* defined differently in winsock.h on WinCE */
#ifndef ENAMETOOLONG
#define ENAMETOOLONG 38
#endif
#define ENOLCK 39
#define ENOSYS 40
/* defined differently in winsock.h on WinCE */
#ifndef ENOTEMPTY
#define ENOTEMPTY 41
#endif
#define EILSEQ 42
/*
* Support EDEADLOCK for compatibiity with older MS-C versions.
*/
#define EDEADLOCK EDEADLK
#ifdef __cplusplus
}
#endif
#endif /* _INC_ERRNO */
-163
View File
@@ -1,163 +0,0 @@
/*
* tls-helper.c
*
* Description:
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include "tls-helper.h"
static int *keysUsed;
/* We don't protect this - it's only written on startup */
static int maxTlsValues;
pte_osMutexHandle globalTlsLock;
pte_osResult pteTlsGlobalInit(int maxEntries)
{
int i;
pte_osResult result;
pte_osMutexCreate(&globalTlsLock);
keysUsed = (int *) malloc(maxEntries * sizeof(int));
if (keysUsed != NULL)
{
for (i=0;i<maxEntries;i++)
keysUsed[i] = 0;
maxTlsValues = maxEntries;
result = PTE_OS_OK;
}
else
result = PTE_OS_NO_RESOURCES;
return result;
}
void * pteTlsThreadInit(void)
{
int i;
void **pTlsStruct = (void **) malloc(maxTlsValues * sizeof(void*));
/* PTE library assumes that keys are initialized to zero */
for (i=0; i<maxTlsValues;i++)
pTlsStruct[i] = 0;
return (void *) pTlsStruct;
}
pte_osResult pteTlsAlloc(unsigned int *pKey)
{
int i;
pte_osResult result = PTE_OS_NO_RESOURCES;
pte_osMutexLock(globalTlsLock);
for (i=0;i<maxTlsValues;i++)
{
if (keysUsed[i] == 0)
{
keysUsed[i] = 1;
*pKey = i+1;
result = PTE_OS_OK;
break;
}
}
pte_osMutexUnlock(globalTlsLock);
return result;
}
void * pteTlsGetValue(void *pTlsThreadStruct, unsigned int index)
{
void **pTls = (void **) pTlsThreadStruct;
if (keysUsed[index-1])
{
if (pTls != NULL)
return pTls[index-1];
}
return NULL;
}
pte_osResult pteTlsSetValue(void *pTlsThreadStruct, unsigned int index, void * value)
{
pte_osResult result;
void ** pTls = (void **) pTlsThreadStruct;
if (pTls != NULL)
{
pTls[index-1] = value;
result = PTE_OS_OK;
}
else
result = PTE_OS_INVALID_PARAM;
return result;
}
pte_osResult pteTlsFree(unsigned int index)
{
pte_osResult result;
if (keysUsed != NULL)
{
pte_osMutexLock(globalTlsLock);
keysUsed[index-1] = 0;
pte_osMutexUnlock(globalTlsLock);
result = PTE_OS_OK;
}
else
result = PTE_OS_GENERAL_FAILURE;
return result;
}
void pteTlsThreadDestroy(void * pTlsThreadStruct)
{
free(pTlsThreadStruct);
}
void pteTlsGlobalDestroy(void)
{
pte_osMutexDelete(globalTlsLock);
free(keysUsed);
}
-47
View File
@@ -1,47 +0,0 @@
/*
* tls-helper.h
*
* Description:
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef _TLS_HELPER_H_
#define _TLS_HELPER_H_
#include "../psp/pte_osal.h"
/* @todo document.. */
pte_osResult pteTlsGlobalInit(int maxEntries);
void * pteTlsThreadInit(void);
pte_osResult pteTlsAlloc(unsigned int *pKey);
void * pteTlsGetValue(void *pTlsThreadStruct, unsigned int index);
pte_osResult pteTlsSetValue(void *pTlsThreadStruct, unsigned int index, void * value);
pte_osResult pteTlsFree(unsigned int index);
void pteTlsThreadDestroy(void * pTlsThreadStruct);
void pteTlsGlobalDestroy(void);
#endif // _TLS_HELPER_H_
-51
View File
@@ -1,51 +0,0 @@
VPATH = ../..:../helper
TARGET_LIB = libpthread-psp.a
MUTEX_OBJS = pthread_mutex.o
MUTEXATTR_OBJS = pthread_mutexattr.o
SUPPORT_OBJS = pte.o pthread.o
THREAD_OBJS = sched.o
TLS_OBJS = pthread_key.o
MISC_OBJS = pthread_get.o
SEM_OBJS = sem.o
BARRIER_OBJS = pthread_barrier.o pthread_barrierattr.o
SPIN_OBJS = pthread_spin.o
CONDVAR_OBJS = pthread_cond.o pthread_condattr.o
RWLOCK_OBJS = pthread_rwlock.o pthread_rwlockattr.o
CANCEL_OBJS = pthread.o pthread_set.o
OS_OBJS = psp_osal.o tls-helper.o
OBJS = $(MUTEX_OBJS) $(MUTEXATTR_OBJS) $(THREAD_OBJS) $(SUPPORT_OBJS) $(TLS_OBJS) $(MISC_OBJS) $(SEM_OBJS) $(BARRIER_OBJS) $(SPIN_OBJS) $(CONDVAR_OBJS) $(RWLOCK_OBJS) $(CANCEL_OBJS) $(OS_OBJS)
INCDIR =
CFLAGS = $(GLOBAL_CFLAGS) -G0 -O2 -Wall -g -fno-strict-aliasing -I../.. -I../helper
CXXFLAGS = $(CFLAGS) -fexceptions -fno-rtti -Werror
ASFLAGS = $(CFLAGS)
LDFLAGS =
LIBS =
PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak
test :
make -C ../../tests test
install: $(TARGET_LIB)
@cp -v $(TARGET_LIB) `psp-config --psp-prefix`/lib
@cp -v *.h `psp-config --psp-prefix`/include
@echo "Done."
-842
View File
@@ -1,842 +0,0 @@
/*
* psp_osal.c
*
* Description:
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* For ftime */
#include <sys/time.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <pspkerror.h>
#include "pte_osal.h"
#include "../../pthread.h"
#include "../helper/tls-helper.h"
#define MAX_PSP_UID 2048 /* SWAG */
#define DEFAULT_STACK_SIZE_BYTES 4096
#define PSP_MAX_TLS 32
#if 1
#define PSP_DEBUG(x) printf(x)
#else
#define PSP_DEBUG(x)
#endif
/* TLS key used to access pspThreadData struct for reach thread. */
static unsigned int threadDataKey;
/*
* Data stored on a per-thread basis - allocated in pte_osThreadCreate
* and freed in pte_osThreadDelete.
*/
typedef struct pspThreadData
{
/* Entry point and parameters to thread's main function */
pte_osThreadEntryPoint entryPoint;
void * argv;
/* Semaphore used for cancellation. Posted to by pte_osThreadCancel,
polled in pte_osSemaphoreCancellablePend */
SceUID cancelSem;
} pspThreadData;
/* Structure used to emulate TLS on non-POSIX threads.
* This limits us to one non-POSIX thread that can
* call pthread functions. */
static void *globalTls;
/* Helper functions */
static pspThreadData *getThreadData(SceUID threadHandle);
static void *getTlsStructFromThread(SceUID thid);
/* A new thread's stub entry point. It retrieves the real entry point from the per thread control
* data as well as any parameters to this function, and then calls the entry point.
*/
int pspStubThreadEntry (unsigned int argc, void *argv)
{
int result;
pspThreadData *pThreadData;
pThreadData = getThreadData(sceKernelGetThreadId());
result = (*(pThreadData->entryPoint))(pThreadData->argv);
return result;
}
/****************************************************************************
*
* Initialization
*
***************************************************************************/
pte_osResult pte_osInit(void)
{
pte_osResult result;
pspThreadData *pThreadData;
char cancelSemName[64];
/* Allocate and initialize TLS support */
result = pteTlsGlobalInit(PSP_MAX_TLS);
if (result == PTE_OS_OK)
{
/* Allocate a key that we use to store control information (e.g. cancellation semaphore) per thread */
result = pteTlsAlloc(&threadDataKey);
if (result == PTE_OS_OK)
{
/* Initialize the structure used to emulate TLS for
* non-POSIX threads
*/
globalTls = pteTlsThreadInit();
/* Also create a "thread data" structure for a single non-POSIX thread. */
/* Allocate some memory for our per-thread control data. We use this for:
* 1. Entry point and parameters for the user thread's main function.
* 2. Semaphore used for thread cancellation.
*/
pThreadData = (pspThreadData *) malloc(sizeof(pspThreadData));
if (pThreadData == NULL)
{
result = PTE_OS_NO_RESOURCES;
}
else
{
/* Save a pointer to our per-thread control data as a TLS value */
pteTlsSetValue(globalTls, threadDataKey, pThreadData);
/* Create a semaphore used to cancel threads */
snprintf(cancelSemName, sizeof(cancelSemName), "pthread_cancelSemGlobal");
pThreadData->cancelSem = sceKernelCreateSema(cancelSemName,
0, /* attributes (default) */
0, /* initial value */
255, /* maximum value */
0); /* options (default) */
result = PTE_OS_OK;
}
}
}
return result;
}
/****************************************************************************
*
* Threads
*
***************************************************************************/
pte_osResult pte_osThreadCreate(pte_osThreadEntryPoint entryPoint,
int stackSize,
int initialPriority,
void *argv,
pte_osThreadHandle* ppte_osThreadHandle)
{
char threadName[64];
char cancelSemName[64];
static int threadNum = 1;
int pspAttr;
void *pTls;
SceUID threadId;
pte_osResult result;
pspThreadData *pThreadData;
if (threadNum++ > MAX_PSP_UID)
threadNum = 0;
/* Make sure that the stack we're going to allocate is big enough */
if (stackSize < DEFAULT_STACK_SIZE_BYTES)
stackSize = DEFAULT_STACK_SIZE_BYTES;
/* Allocate TLS structure for this thread. */
pTls = pteTlsThreadInit();
if (pTls == NULL)
{
PSP_DEBUG("pteTlsThreadInit: PTE_OS_NO_RESOURCES\n");
result = PTE_OS_NO_RESOURCES;
goto FAIL0;
}
/* Allocate some memory for our per-thread control data. We use this for:
* 1. Entry point and parameters for the user thread's main function.
* 2. Semaphore used for thread cancellation.
*/
pThreadData = (pspThreadData *) malloc(sizeof(pspThreadData));
if (pThreadData == NULL)
{
pteTlsThreadDestroy(pTls);
PSP_DEBUG("malloc(pspThreadData): PTE_OS_NO_RESOURCES\n");
result = PTE_OS_NO_RESOURCES;
goto FAIL0;
}
/* Save a pointer to our per-thread control data as a TLS value */
pteTlsSetValue(pTls, threadDataKey, pThreadData);
pThreadData->entryPoint = entryPoint;
pThreadData->argv = argv;
/* Create a semaphore used to cancel threads */
snprintf(cancelSemName, sizeof(cancelSemName), "pthread_cancelSem%04d", threadNum);
pThreadData->cancelSem = sceKernelCreateSema(cancelSemName,
0, /* attributes (default) */
0, /* initial value */
255, /* maximum value */
0); /* options (default) */
/* In order to emulate TLS functionality, we append the address of the TLS structure that we
* allocated above to the thread's name. To set or get TLS values for this thread, the user
* needs to get the name of the thread from the OS and then parse the name to extract
* a pointer to the TLS structure.
*/
snprintf(threadName, sizeof(threadName), "pthread%04d__%x", threadNum, (unsigned int) pTls);
pspAttr = 0;
#if 0
printf("%s %p %d %d %d\n",threadName, pspStubThreadEntry, initialPriority, stackSize, pspAttr);
#endif
threadId = sceKernelCreateThread(threadName,
pspStubThreadEntry,
initialPriority,
stackSize,
pspAttr,
NULL);
if (threadId == (SceUID) SCE_KERNEL_ERROR_NO_MEMORY)
{
free(pThreadData);
pteTlsThreadDestroy(pTls);
PSP_DEBUG("sceKernelCreateThread: PTE_OS_NO_RESOURCES\n");
result = PTE_OS_NO_RESOURCES;
}
else if (threadId < 0)
{
free(pThreadData);
pteTlsThreadDestroy(pTls);
PSP_DEBUG("sceKernelCreateThread: PTE_OS_GENERAL_FAILURE\n");
result = PTE_OS_GENERAL_FAILURE;
}
else
{
*ppte_osThreadHandle = threadId;
result = PTE_OS_OK;
}
FAIL0:
return result;
}
pte_osResult pte_osThreadStart(pte_osThreadHandle osThreadHandle)
{
sceKernelStartThread(osThreadHandle, 0, NULL);
return PTE_OS_OK;
}
pte_osResult pte_osThreadDelete(pte_osThreadHandle handle)
{
void *pTls = getTlsStructFromThread(handle);
pspThreadData *pThreadData = getThreadData(handle);
sceKernelDeleteSema(pThreadData->cancelSem);
free(pThreadData);
pteTlsThreadDestroy(pTls);
sceKernelDeleteThread(handle);
return PTE_OS_OK;
}
pte_osResult pte_osThreadExitAndDelete(pte_osThreadHandle handle)
{
pte_osThreadDelete(handle);
sceKernelExitDeleteThread(0);
return PTE_OS_OK;
}
void pte_osThreadExit(void)
{
sceKernelExitThread(0);
}
/*
* This has to be cancellable, so we can't just call sceKernelWaitThreadEnd.
* Instead, poll on this in a loop, like we do for a cancellable semaphore.
*/
pte_osResult pte_osThreadWaitForEnd(pte_osThreadHandle threadHandle)
{
pte_osResult result;
pspThreadData *pThreadData = getThreadData(sceKernelGetThreadId());
while (1)
{
SceKernelThreadRunStatus info;
/* Poll task to see if it has ended */
memset(&info,0,sizeof(info));
info.size = sizeof(info);
sceKernelReferThreadRunStatus(threadHandle, &info);
if (info.status == PSP_THREAD_STOPPED)
{
/* Thread has ended */
result = PTE_OS_OK;
break;
}
else
{
SceKernelSemaInfo semInfo;
if (pThreadData != NULL)
{
SceUID osResult;
osResult = sceKernelReferSemaStatus(pThreadData->cancelSem, &semInfo);
if (osResult == SCE_KERNEL_ERROR_OK)
{
if (semInfo.currentCount > 0)
{
result = PTE_OS_INTERRUPTED;
break;
}
/* Nothing found and not timed out yet; let's yield so we're not
* in busy loop.
*/
else
sceKernelDelayThread(POLLING_DELAY_IN_us);
}
else
{
result = PTE_OS_GENERAL_FAILURE;
break;
}
}
}
}
return result;
}
pte_osThreadHandle pte_osThreadGetHandle(void)
{
return sceKernelGetThreadId();
}
int pte_osThreadGetPriority(pte_osThreadHandle threadHandle)
{
SceKernelThreadInfo thinfo;
thinfo.size = sizeof(SceKernelThreadInfo);
sceKernelReferThreadStatus(threadHandle, &thinfo);
return thinfo.currentPriority;
}
pte_osResult pte_osThreadSetPriority(pte_osThreadHandle threadHandle, int newPriority)
{
sceKernelChangeThreadPriority(threadHandle, newPriority);
return PTE_OS_OK;
}
pte_osResult pte_osThreadCancel(pte_osThreadHandle threadHandle)
{
pspThreadData *pThreadData = getThreadData(threadHandle);
SceUID osResult = sceKernelSignalSema(pThreadData->cancelSem, 1);
if (osResult == SCE_KERNEL_ERROR_OK)
return PTE_OS_OK;
return PTE_OS_GENERAL_FAILURE;
}
pte_osResult pte_osThreadCheckCancel(pte_osThreadHandle threadHandle)
{
SceKernelSemaInfo semInfo;
SceUID osResult;
pte_osResult result;
pspThreadData *pThreadData = getThreadData(threadHandle);
if (pThreadData != NULL)
{
osResult = sceKernelReferSemaStatus(pThreadData->cancelSem, &semInfo);
if (osResult == SCE_KERNEL_ERROR_OK)
{
if (semInfo.currentCount > 0)
result = PTE_OS_INTERRUPTED;
else
result = PTE_OS_OK;
}
/* sceKernelReferSemaStatus returned an error */
else
result = PTE_OS_GENERAL_FAILURE;
}
/* For some reason, we couldn't get thread data */
else
result = PTE_OS_GENERAL_FAILURE;
return result;
}
void pte_osThreadSleep(unsigned int msecs)
{
sceKernelDelayThread(msecs*1000);
}
int pte_osThreadGetMinPriority(void)
{
return 17;
}
int pte_osThreadGetMaxPriority(void)
{
return 30;
}
int pte_osThreadGetDefaultPriority(void)
{
return 18;
}
/****************************************************************************
*
* Mutexes
*
****************************************************************************/
pte_osResult pte_osMutexCreate(pte_osMutexHandle *pHandle)
{
static int mutexCtr = 0;
char mutexName[32];
pte_osMutexHandle handle;
if (mutexCtr++ > MAX_PSP_UID)
mutexCtr = 0;
snprintf(mutexName,sizeof(mutexName),"mutex%d",mutexCtr);
handle = sceKernelCreateSema(mutexName,
0, /* attributes (default) */
1, /* initial value */
1, /* maximum value */
0); /* options (default) */
*pHandle = handle;
return PTE_OS_OK;
}
pte_osResult pte_osMutexDelete(pte_osMutexHandle handle)
{
sceKernelDeleteSema(handle);
return PTE_OS_OK;
}
pte_osResult pte_osMutexLock(pte_osMutexHandle handle)
{
sceKernelWaitSema(handle, 1, NULL);
return PTE_OS_OK;
}
pte_osResult pte_osMutexTimedLock(pte_osMutexHandle handle, unsigned int timeoutMsecs)
{
SceUInt timeoutUsecs = timeoutMsecs*1000;
int status = sceKernelWaitSema(handle, 1, &timeoutUsecs);
/* Assume that any error from sceKernelWaitSema was due to a timeout */
if (status < 0)
return PTE_OS_TIMEOUT;
return PTE_OS_OK;
}
pte_osResult pte_osMutexUnlock(pte_osMutexHandle handle)
{
sceKernelSignalSema(handle, 1);
return PTE_OS_OK;
}
/****************************************************************************
*
* Semaphores
*
***************************************************************************/
pte_osResult pte_osSemaphoreCreate(int initialValue, pte_osSemaphoreHandle *pHandle)
{
pte_osSemaphoreHandle handle;
static int semCtr = 0;
char semName[32];
if (semCtr++ > MAX_PSP_UID)
semCtr = 0;
snprintf(semName,sizeof(semName),"pthread_sem%d",semCtr);
handle = sceKernelCreateSema(semName,
0, /* attributes (default) */
initialValue, /* initial value */
SEM_VALUE_MAX, /* maximum value */
0); /* options (default) */
*pHandle = handle;
return PTE_OS_OK;
}
pte_osResult pte_osSemaphoreDelete(pte_osSemaphoreHandle handle)
{
sceKernelDeleteSema(handle);
return PTE_OS_OK;
}
pte_osResult pte_osSemaphorePost(pte_osSemaphoreHandle handle, int count)
{
sceKernelSignalSema(handle, count);
return PTE_OS_OK;
}
pte_osResult pte_osSemaphorePend(pte_osSemaphoreHandle handle, unsigned int *pTimeoutMsecs)
{
unsigned int timeoutUsecs;
unsigned int *pTimeoutUsecs;
SceUInt result;
pte_osResult osResult;
if (pTimeoutMsecs == NULL)
pTimeoutUsecs = NULL;
else
{
timeoutUsecs = *pTimeoutMsecs * 1000;
pTimeoutUsecs = &timeoutUsecs;
}
result = sceKernelWaitSema(handle, 1, pTimeoutUsecs);
if (result == SCE_KERNEL_ERROR_OK)
return PTE_OS_OK;
if (result == SCE_KERNEL_ERROR_WAIT_TIMEOUT)
return PTE_OS_TIMEOUT;
return PTE_OS_GENERAL_FAILURE;
}
/*
* Pend on a semaphore- and allow the pend to be cancelled.
*
* PSP OS provides no functionality to asynchronously interrupt a blocked call. We simulte
* this by polling on the main semaphore and the cancellation semaphore and sleeping in a loop.
*/
pte_osResult pte_osSemaphoreCancellablePend(pte_osSemaphoreHandle semHandle, unsigned int *pTimeout)
{
pspThreadData *pThreadData;
pThreadData = getThreadData(sceKernelGetThreadId());
clock_t start_time;
pte_osResult result = PTE_OS_OK;
unsigned int timeout;
unsigned char timeoutEnabled;
start_time = clock();
// clock() is in microseconds, timeout as passed in was in milliseconds
if (pTimeout == NULL)
{
timeout = 0;
timeoutEnabled = 0;
}
else
{
timeout = *pTimeout * 1000;
timeoutEnabled = 1;
}
while (1)
{
SceUInt semTimeout;
int status;
/* Poll semaphore */
semTimeout = 0;
status = sceKernelWaitSema(semHandle, 1, &semTimeout);
if (status == SCE_KERNEL_ERROR_OK)
{
/* User semaphore posted to */
result = PTE_OS_OK;
break;
}
else if ((timeoutEnabled) && ((clock() - start_time) > timeout))
{
/* Timeout expired */
result = PTE_OS_TIMEOUT;
break;
}
else
{
SceKernelSemaInfo semInfo;
if (pThreadData != NULL)
{
SceUID osResult;
osResult = sceKernelReferSemaStatus(pThreadData->cancelSem, &semInfo);
if (osResult == SCE_KERNEL_ERROR_OK)
{
if (semInfo.currentCount > 0)
{
result = PTE_OS_INTERRUPTED;
break;
}
/* Nothing found and not timed out yet; let's yield so we're not
* in busy loop.
*/
else
sceKernelDelayThread(POLLING_DELAY_IN_us);
}
else
{
result = PTE_OS_GENERAL_FAILURE;
break;
}
}
}
}
return result;
}
/****************************************************************************
*
* Atomic Operations
*
***************************************************************************/
int pte_osAtomicExchange(int *ptarg, int val)
{
int intc = pspSdkDisableInterrupts();
int origVal = *ptarg;
*ptarg = val;
pspSdkEnableInterrupts(intc);
return origVal;
}
int pte_osAtomicCompareExchange(int *pdest, int exchange, int comp)
{
int intc = pspSdkDisableInterrupts();
int origVal = *pdest;
if (*pdest == comp)
*pdest = exchange;
pspSdkEnableInterrupts(intc);
return origVal;
}
int pte_osAtomicExchangeAdd(int volatile* pAddend, int value)
{
int intc = pspSdkDisableInterrupts();
int origVal = *pAddend;
*pAddend += value;
pspSdkEnableInterrupts(intc);
return origVal;
}
int pte_osAtomicDecrement(int *pdest)
{
int val;
int intc = pspSdkDisableInterrupts();
(*pdest)--;
val = *pdest;
pspSdkEnableInterrupts(intc);
return val;
}
int pte_osAtomicIncrement(int *pdest)
{
int val;
int intc = pspSdkDisableInterrupts();
(*pdest)++;
val = *pdest;
pspSdkEnableInterrupts(intc);
return val;
}
/****************************************************************************
*
* Helper functions
*
***************************************************************************/
static pspThreadData *getThreadData(SceUID threadHandle)
{
void *pTls = getTlsStructFromThread(threadHandle);
pspThreadData *pThreadData = (pspThreadData *)
pteTlsGetValue(pTls, threadDataKey);
return pThreadData;
}
static void *getTlsStructFromThread(SceUID thid)
{
SceKernelThreadInfo thinfo;
unsigned int ptr;
unsigned int thrNum;
int numMatches;
thinfo.size = sizeof(SceKernelThreadInfo);
sceKernelReferThreadStatus(thid, &thinfo);
numMatches = sscanf(thinfo.name,"pthread%04d__%x", &thrNum, &ptr);
/* If we were called from a pthread, use the TLS allocated when the thread
* was created. Otherwise, we were called from a non-pthread, so use the
* "global". This is a pretty bad hack, but necessary due to lack of TLS on PSP.
*/
if (numMatches == 2)
return (void *) ptr;
return globalTls;
}
/****************************************************************************
*
* Thread Local Storage
*
***************************************************************************/
pte_osResult pte_osTlsSetValue(unsigned int key, void * value)
{
void *pTls = getTlsStructFromThread(sceKernelGetThreadId());
return pteTlsSetValue(pTls, key, value);
}
void * pte_osTlsGetValue(unsigned int index)
{
void *pTls = getTlsStructFromThread(sceKernelGetThreadId());
return (void *) pteTlsGetValue(pTls, index);
}
pte_osResult pte_osTlsAlloc(unsigned int *pKey)
{
void *pTls = getTlsStructFromThread(sceKernelGetThreadId());
return pteTlsAlloc(pKey);
}
pte_osResult pte_osTlsFree(unsigned int index)
{
return pteTlsFree(index);
}
/****************************************************************************
*
* Miscellaneous
*
***************************************************************************/
int ftime(struct timeb *tb)
{
struct timeval tv;
struct timezone tz;
gettimeofday(&tv, &tz);
tb->time = tv.tv_sec;
tb->millitm = tv.tv_usec / 1000;
tb->timezone = tz.tz_minuteswest;
tb->dstflag = tz.tz_dsttime;
return 0;
}
-63
View File
@@ -1,63 +0,0 @@
/*
* psp_osal.h
*
* Description:
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <pspsdk.h>
typedef SceUID pte_osThreadHandle;
typedef SceUID pte_osSemaphoreHandle;
typedef SceUID pte_osMutexHandle;
#define OS_IS_HANDLE_VALID(x) ((x) > 0)
#define OS_MAX_SIMUL_THREADS 10
#define OS_DEFAULT_PRIO 11
#define OS_MIN_PRIO 17
#define OS_MAX_PRIO 32
#if 0
#define HAVE_THREAD_SAFE_ERRNO
#endif
#define POLLING_DELAY_IN_us 100
#define OS_MAX_SEM_VALUE 254
int PspInterlockedExchange(int *ptarg, int val);
int PspInterlockedCompareExchange(int *pdest, int exchange, int comp);
int PspInterlockedExchangeAdd(int volatile* pAddend, int value);
int PspInterlockedDecrement(int *pdest);
int PspInterlockedIncrement(int *pdest);
-9
View File
@@ -1,9 +0,0 @@
#ifndef _OS_SUPPORT_H_
#define _OS_SUPPORT_H_
/* Platform specific one must be included first */
#include "psp_osal.h"
#include "pte_generic_osal.h"
#endif /* _OS_SUPPORT_H */
-12
View File
@@ -1,12 +0,0 @@
/* pte_types.h */
#ifndef PTE_TYPES_H
#define PTE_TYPES_H
#include <errno.h>
#include <sys/types.h>
#include <sys/timeb.h>
typedef int pid_t;
#endif /* PTE_TYPES_H */
-64
View File
@@ -1,64 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspsdk.h>
#include <pspctrl.h>
PSP_MODULE_INFO("Pthread Test", 0, 1, 1);
extern void pte_test_main();
#ifdef JNS
#define printf pspDebugScreenPrintf
#endif
/* Exit callback */
int exit_callback(int arg1, int arg2, void *common)
{
sceKernelExitGame();
return 0;
}
/* Callback thread */
int CallbackThread(SceSize args, void *argp)
{
int cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
sceKernelRegisterExitCallback(cbid);
sceKernelSleepThreadCB();
return 0;
}
/* Sets up the callback thread and returns its thread id */
int SetupCallbacks(void)
{
int thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, 0, 0);
if (thid >= 0)
sceKernelStartThread(thid, 0, 0);
return thid;
}
int main(void)
{
SceCtrlData pad;
pspDebugScreenInit();
SetupCallbacks();
pte_test_main();
while (1)
{
sceCtrlReadBufferPositive(&pad, 1);
if (pad.Buttons & PSP_CTRL_UP)
{
printf("Exiting...\n");
return 0;
}
}
return 0;
}
-1059
View File
File diff suppressed because it is too large. Load diff
-449
View File
@@ -1,449 +0,0 @@
/*
* pte_cancellable_wait.c
*
* Description:
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef _GENERIC_OS_SUPPORT_H_
#define _GENERIC_OS_SUPPORT_H_
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/** @name Misc */
//@{
typedef enum pte_osResult
{
/** Operation completed successfully */
PTE_OS_OK = 0,
/** Operation failed because there insufficient resources */
PTE_OS_NO_RESOURCES,
/** Operation failed due to a general failure */
PTE_OS_GENERAL_FAILURE,
/** Operation did not complete because a user specified timeout expired. */
PTE_OS_TIMEOUT,
/** The operation was interrupted before it could complete. */
PTE_OS_INTERRUPTED,
/** An invalid parameter was specified */
PTE_OS_INVALID_PARAM
} pte_osResult;
/**
* Provides a hook for the OSAL to implement any OS specific initialization. This is guaranteed to be
* called before any other OSAL function.
*/
pte_osResult pte_osInit(void);
//@}
/** @name Mutexes */
//@{
/**
* Creates a mutex
*
* @param pHandle Set to the handle of the newly created mutex.
*
* @return PTE_OS_OK - Mutex successfully created
* @return PTE_OS_NO_RESOURCESs - Insufficient resources to create mutex
*/
pte_osResult pte_osMutexCreate(pte_osMutexHandle *pHandle);
/**
* Deletes a mutex and frees any associated resources.
*
* @param handle Handle of mutex to delete.
*
* @return PTE_OS_OK - Mutex successfully deleted.
*/
pte_osResult pte_osMutexDelete(pte_osMutexHandle handle);
/**
* Locks the mutex
*
* @param handle Handle of mutex to lock.
*
* @return PTE_OS_OK - Mutex successfully locked.
*/
pte_osResult pte_osMutexLock(pte_osMutexHandle handle);
/**
* Locks the mutex, returning after @p timeoutMsecs if the resources is not
* available. Can be used for polling mutex by using @p timeoutMsecs of zero.
*
* @param handle Handle of mutex to lock.
* @param timeoutMsecs Number of milliseconds to wait for resource before returning.
*
* @return PTE_OS_OK - Mutex successfully locked.
* @return PTE_OS_TIMEOUT - Timeout expired before lock was obtained.
*/
pte_osResult pte_osMutexTimedLock(pte_osMutexHandle handle, unsigned int timeoutMsecs);
/**
* Unlocks the mutex
*
* @param handle Handle of mutex to unlock
*
* @return PTE_OS_OK - Mutex successfully unlocked.
*/
pte_osResult pte_osMutexUnlock(pte_osMutexHandle handle);
//@}
/** @name Threads */
//@{
typedef int (*pte_osThreadEntryPoint)(void *params);
/**
* Creates a new thread. The thread must be started in a suspended state - it will be
* explicitly started when pte_osThreadStart() is called.
*
* @param entryPoint Entry point to the new thread.
* @param stackSize The initial stack size, in bytes. Note that this can be considered a minimum -
* for instance if the OS requires a larger stack space than what the caller specified.
* @param initialPriority The priority that the new thread should be initially set to.
* @param argv Parameter to pass to the new thread.
* @param ppte_osThreadHandle set to the handle of the new thread.
*
* @return PTE_OS_OK - New thread successfully created.
* @return PTE_OS_NO_RESOURCESs - Insufficient resources to create thread
*/
pte_osResult pte_osThreadCreate(pte_osThreadEntryPoint entryPoint,
int stackSize,
int initialPriority,
void *argv,
pte_osThreadHandle* ppte_osThreadHandle);
/**
* Starts executing the specified thread.
*
* @param osThreadHandle handle of the thread to start.
*
* @return PTE_OS_OK - thread successfully started.
*/
pte_osResult pte_osThreadStart(pte_osThreadHandle osThreadHandle);
/**
* Causes the current thread to stop executing.
*
* @return Never returns (thread terminated)
*/
void pte_osThreadExit();
/**
* Waits for the specified thread to end. If the thread has already terminated, this returns
* immediately.
*
* @param threadHandle Handle fo thread to wait for.
*
* @return PTE_OS_OK - specified thread terminated.
*/
pte_osResult pte_osThreadWaitForEnd(pte_osThreadHandle threadHandle);
/**
* Returns the handle of the currently executing thread.
*/
pte_osThreadHandle pte_osThreadGetHandle(void);
/**
* Returns the priority of the specified thread.
*/
int pte_osThreadGetPriority(pte_osThreadHandle threadHandle);
/**
* Sets the priority of the specified thread.
*
* @return PTE_OS_OK - thread priority successfully set
*/
pte_osResult pte_osThreadSetPriority(pte_osThreadHandle threadHandle, int newPriority);
/**
* Frees resources associated with the specified thread. This is called after the thread has terminated
* and is no longer needed (e.g. after pthread_join returns). This call will always be made
* from a different context than that of the target thread.
*/
pte_osResult pte_osThreadDelete(pte_osThreadHandle handle);
/**
* Frees resources associated with the specified thread and then causes the thread to exit.
* This is called after the thread has terminated and is no longer needed (e.g. after
* pthread_join returns). This call will always be made from the context of the target thread.
*/
pte_osResult pte_osThreadExitAndDelete(pte_osThreadHandle handle);
/**
* Cancels the specified thread. This should cause pte_osSemaphoreCancellablePend() and for pte_osThreadCheckCancel()
* to return @p PTE_OS_INTERRUPTED.
*
* @param threadHandle handle to the thread to cancel.
*
* @return Thread successfully canceled.
*/
pte_osResult pte_osThreadCancel(pte_osThreadHandle threadHandle);
/**
* Check if pte_osThreadCancel() has been called on the specified thread.
*
* @param threadHandle handle of thread to check the state of.
*
* @return PTE_OS_OK - Thread has not been cancelled
* @return PTE_OS_INTERRUPTED - Thread has been cancelled.
*/
pte_osResult pte_osThreadCheckCancel(pte_osThreadHandle threadHandle);
/**
* Causes the current thread to sleep for the specified number of milliseconds.
*/
void pte_osThreadSleep(unsigned int msecs);
/**
* Returns the maximum allowable priority
*/
int pte_osThreadGetMaxPriority();
/**
* Returns the minimum allowable priority
*/
int pte_osThreadGetMinPriority();
/**
* Returns the priority that should be used if the caller to pthread_create doesn't
* explicitly set one.
*/
int pte_osThreadGetDefaultPriority();
//@}
/** @name Semaphores */
//@{
/**
* Creates a semaphore
*
* @param initialValue Initial value of the semaphore
* @param pHandle Set to the handle of the newly created semaphore.
*
* @return PTE_OS_OK - Semaphore successfully created
* @return PTE_OS_NO_RESOURCESs - Insufficient resources to create semaphore
*/
pte_osResult pte_osSemaphoreCreate(int initialValue, pte_osSemaphoreHandle *pHandle);
/**
* Deletes a semaphore and frees any associated resources.
*
* @param handle Handle of semaphore to delete.
*
* @return PTE_OS_OK - Semaphore successfully deleted.
*/
pte_osResult pte_osSemaphoreDelete(pte_osSemaphoreHandle handle);
/**
* Posts to the semaphore
*
* @param handle Semaphore to release
* @param count Amount to increment the semaphore by.
*
* @return PTE_OS_OK - semaphore successfully released.
*/
pte_osResult pte_osSemaphorePost(pte_osSemaphoreHandle handle, int count);
/**
* Acquire a semaphore, returning after @p timeoutMsecs if the semaphore is not
* available. Can be used for polling a semaphore by using @p timeoutMsecs of zero.
*
* @param handle Handle of semaphore to acquire.
* @param pTimeout Pointer to the number of milliseconds to wait to acquire the semaphore
* before returning. If set to NULL, wait forever.
*
* @return PTE_OS_OK - Semaphore successfully acquired.
* @return PTE_OS_TIMEOUT - Timeout expired before semaphore was obtained.
*/
pte_osResult pte_osSemaphorePend(pte_osSemaphoreHandle handle, unsigned int *pTimeout);
/**
* Acquire a semaphore, returning after @p timeoutMsecs if the semaphore is not
* available. Can be used for polling a semaphore by using @p timeoutMsecs of zero.
* Call must return immediately if pte_osThreadCancel() is called on the thread waiting for
* the semaphore.
*
* @param handle Handle of semaphore to acquire.
* @param pTimeout Pointer to the number of milliseconds to wait to acquire the semaphore
* before returning. If set to NULL, wait forever.
*
* @return PTE_OS_OK - Semaphore successfully acquired.
* @return PTE_OS_TIMEOUT - Timeout expired before semaphore was obtained.
*/
pte_osResult pte_osSemaphoreCancellablePend(pte_osSemaphoreHandle handle, unsigned int *pTimeout);
//@}
/** @name Thread Local Storage */
//@{
/**
* Sets the thread specific value for the specified key for the
* currently executing thread.
*
* @param index The TLS key for the value.
* @param value The value to save
*/
pte_osResult pte_osTlsSetValue(unsigned int key, void * value);
/**
* Retrieves the thread specific value for the specified key for
* the currently executing thread. If a value has not been set
* for this key, NULL should be returned (i.e. TLS values default
* to NULL).
*
* @param index The TLS key for the value.
*
* @return The value associated with @p key for the current thread.
*/
void * pte_osTlsGetValue(unsigned int key);
/**
* Initializes the OS TLS support. This is called by the PTE library
* prior to performing ANY TLS operation.
*/
void pte_osTlsInit(void);
/**
* Allocates a new TLS key.
*
* @param pKey On success will be set to the newly allocated key.
*
* @return PTE_OS_OK - TLS key successfully allocated.
* @return PTE_OS_NO_RESOURCESs - Insufficient resources to allocate key (e.g.
* maximum number of keys reached).
*/
pte_osResult pte_osTlsAlloc(unsigned int *pKey);
/**
* Frees the specified TLS key.
*
* @param index TLS key to free
*
* @return PTE_OS_OK - TLS key was successfully freed.
*/
pte_osResult pte_osTlsFree(unsigned int key);
//@}
/** @name Atomic operations */
//@{
/**
* Sets the target to the specified value as an atomic operation.
*
* \code
* origVal = *ptarg
* *ptarg = val
* return origVal
* \endcode
*
* @param pTarg Pointer to the value to be exchanged.
* @param val Value to be exchanged
*
* @return original value of destination
*/
int pte_osAtomicExchange(int *pTarg, int val);
/**
* Performs an atomic compare-and-exchange oepration on the specified
* value. That is:
*
* \code
* origVal = *pdest
* if (*pdest == comp)
* then *pdest = exchange
* return origVal
* \endcode
*
* @param pdest Pointer to the destination value.
* @param exchange Exchange value (value to set destination to if destination == comparand)
* @param comp The value to compare to destination.
*
* @return Original value of destination
*/
int pte_osAtomicCompareExchange(int *pdest, int exchange, int comp);
/**
* Adds the value to target as an atomic operation
*
* \code
* origVal = *pdest
* *pAddend += value
* return origVal
* \endcode
*
* @param pdest Pointer to the variable to be updated.
* @param value Value to be added to the variable.
*
* @return Original value of destination
*/
int pte_osAtomicExchangeAdd(int volatile* pdest, int value);
/**
* Decrements the destination.
*
* \code
* origVal = *pdest
* *pdest++
* return origVal
* \endcode
*
* @param pdest Destination value to decrement
*
* @return Original destination value
*/
int pte_osAtomicDecrement(int *pdest);
/**
* Increments the destination value
*
* \code
* origVal = *pdest;
* *pdest++;
* return origVal;
*/
int pte_osAtomicIncrement(int *pdest);
//@}
struct timeb;
int ftime(struct timeb *tb);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _OS_SUPPORT_H_
-396
View File
@@ -1,396 +0,0 @@
/*
* pte_main.c
*
* Description:
* This translation unit instantiates data associated with the implementation
* as a whole.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include "pte_osal.h"
#include "pthread.h"
#include "implement.h"
int pte_processInitialized = PTE_FALSE;
pte_thread_t * pte_threadReuseTop = PTE_THREAD_REUSE_EMPTY;
pte_thread_t * pte_threadReuseBottom = PTE_THREAD_REUSE_EMPTY;
pthread_key_t pte_selfThreadKey = NULL;
pthread_key_t pte_cleanupKey = NULL;
pthread_cond_t pte_cond_list_head = NULL;
pthread_cond_t pte_cond_list_tail = NULL;
int pte_concurrency = 0;
/* What features have been auto-detaected */
int pte_features = 0;
unsigned char pte_smp_system = PTE_TRUE; /* Safer if assumed true initially. */
/*
* Global lock for managing pthread_t struct reuse.
*/
pte_osMutexHandle pte_thread_reuse_lock;
/*
* Global lock for testing internal state of statically declared mutexes.
*/
pte_osMutexHandle pte_mutex_test_init_lock;
/*
* Global lock for testing internal state of PTHREAD_COND_INITIALIZER
* created condition variables.
*/
pte_osMutexHandle pte_cond_test_init_lock;
/*
* Global lock for testing internal state of PTHREAD_RWLOCK_INITIALIZER
* created read/write locks.
*/
pte_osMutexHandle pte_rwlock_test_init_lock;
/*
* Global lock for testing internal state of PTHREAD_SPINLOCK_INITIALIZER
* created spin locks.
*/
pte_osMutexHandle pte_spinlock_test_init_lock;
/*
* Global lock for condition variable linked list. The list exists
* to wake up CVs when a WM_TIMECHANGE message arrives. See
* w32_TimeChangeHandler.c.
*/
pte_osMutexHandle pte_cond_list_lock;
int pthread_create (pthread_t * tid,
const pthread_attr_t * attr,
void *(*start) (void *), void *arg)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function creates a thread running the start function,
* passing it the parameter value, 'arg'. The 'attr'
* argument specifies optional creation attributes.
* The identity of the new thread is returned
* via 'tid', which should not be NULL.
*
* PARAMETERS
* tid
* pointer to an instance of pthread_t
*
* attr
* optional pointer to an instance of pthread_attr_t
*
* start
* pointer to the starting routine for the new thread
*
* arg
* optional parameter passed to 'start'
*
*
* DESCRIPTION
* This function creates a thread running the start function,
* passing it the parameter value, 'arg'. The 'attr'
* argument specifies optional creation attributes.
* The identity of the new thread is returned
* via 'tid', which should not be the NULL pointer.
*
* RESULTS
* 0 successfully created thread,
* EINVAL attr invalid,
* EAGAIN insufficient resources.
*
* ------------------------------------------------------
*/
{
pthread_t thread;
pte_thread_t * tp;
int result = EAGAIN;
int run = PTE_TRUE;
ThreadParms *parms = NULL;
long stackSize;
int priority = 0;
pthread_t self;
pte_osResult osResult;
register pthread_attr_t a = NULL;
/*
* Before doing anything, check that tid can be stored through
* without invoking a memory protection error (segfault).
* Make sure that the assignment below can't be optimised out by the compiler.
* This is assured by conditionally assigning *tid again at the end.
*/
if (attr != NULL)
a = *attr;
if ((thread = pte_new ()) == NULL)
goto FAIL0;
tp = (pte_thread_t *) thread;
priority = tp->sched_priority;
if ((parms = (ThreadParms *) malloc (sizeof (*parms))) == NULL)
goto FAIL0;
parms->tid = thread;
parms->start = start;
parms->arg = arg;
if (a != NULL)
{
stackSize = a->stacksize;
tp->detachState = a->detachstate;
priority = a->param.sched_priority;
if ( (priority > pte_osThreadGetMaxPriority()) ||
(priority < pte_osThreadGetMinPriority()) )
{
result = EINVAL;
goto FAIL0;
}
/* Everything else */
/*
* Thread priority must be set to a valid system level
* without altering the value set by pthread_attr_setschedparam().
*/
if (PTHREAD_INHERIT_SCHED == a->inheritsched)
{
/*
* If the thread that called pthread_create() is an OS thread
* then the inherited priority could be the result of a temporary
* system adjustment. This is not the case for POSIX threads.
*/
self = pthread_self ();
priority = ((pte_thread_t *) self)->sched_priority;
}
}
else
{
/*
* Default stackSize
*/
stackSize = PTHREAD_STACK_MIN;
}
tp->state = run ? PThreadStateInitial : PThreadStateSuspended;
tp->keys = NULL;
/*
* Threads must be started in suspended mode and resumed if necessary
* after _beginthreadex returns us the handle. Otherwise we set up a
* race condition between the creating and the created threads.
* Note that we also retain a local copy of the handle for use
* by us in case thread.p->threadH gets NULLed later but before we've
* finished with it here.
*/
result = pthread_mutex_lock (&tp->threadLock);
if (result == 0)
{
/*
* Must record the thread's sched_priority as given,
* not as finally adjusted.
*/
tp->sched_priority = priority;
(void) pthread_mutex_unlock (&tp->threadLock);
}
osResult = pte_osThreadCreate(pte_threadStart,
stackSize,
priority,
parms,
&(tp->threadId));
if (osResult == PTE_OS_OK)
{
pte_osThreadStart(tp->threadId);
result = 0;
}
else
{
tp->threadId = 0;
result = EAGAIN;
goto FAIL0;
}
/*
* Fall Through Intentionally
*/
/*
* ------------
* Failure Code
* ------------
*/
FAIL0:
if (result != 0)
{
pte_threadDestroy (thread);
tp = NULL;
if (parms != NULL)
free (parms);
}
else
{
if (tid != NULL)
*tid = thread;
}
return (result);
}
/*
* The functions pte_pop_cleanup and pte_push_cleanup
* are implemented here for applications written in C with no
* C++ destructor support.
*/
pte_cleanup_t *pte_pop_cleanup (int execute)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function pops the most recently pushed cleanup
* handler. If execute is nonzero, then the cleanup handler
* is executed if non-null.
*
* PARAMETERS
* execute
* if nonzero, execute the cleanup handler
*
*
* DESCRIPTION
* This function pops the most recently pushed cleanup
* handler. If execute is nonzero, then the cleanup handler
* is executed if non-null.
* NOTE: specify 'execute' as nonzero to avoid duplication
* of common cleanup code.
*
* RESULTS
* N/A
*
* ------------------------------------------------------
*/
{
pte_cleanup_t *cleanup;
cleanup = (pte_cleanup_t *) pthread_getspecific (pte_cleanupKey);
if (cleanup != NULL)
{
if (execute && (cleanup->routine != NULL))
{
(*cleanup->routine) (cleanup->arg);
}
pthread_setspecific (pte_cleanupKey, (void *) cleanup->prev);
}
return (cleanup);
} /* pte_pop_cleanup */
void
pte_push_cleanup (pte_cleanup_t * cleanup,
pte_cleanup_callback_t routine, void *arg)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function pushes a new cleanup handler onto the thread's stack
* of cleanup handlers. Each cleanup handler pushed onto the stack is
* popped and invoked with the argument 'arg' when
* a) the thread exits by calling 'pthread_exit',
* b) when the thread acts on a cancellation request,
* c) or when the thread calls pthread_cleanup_pop with a nonzero
* 'execute' argument
*
* PARAMETERS
* cleanup
* a pointer to an instance of pthread_cleanup_t,
*
* routine
* pointer to a cleanup handler,
*
* arg
* parameter to be passed to the cleanup handler
*
*
* DESCRIPTION
* This function pushes a new cleanup handler onto the thread's stack
* of cleanup handlers. Each cleanup handler pushed onto the stack is
* popped and invoked with the argument 'arg' when
* a) the thread exits by calling 'pthread_exit',
* b) when the thread acts on a cancellation request,
* c) or when the thrad calls pthread_cleanup_pop with a nonzero
* 'execute' argument
* NOTE: pthread_push_cleanup, pte_pop_cleanup must be paired
* in the same lexical scope.
*
* RESULTS
* pthread_cleanup_t *
* pointer to the previous cleanup
*
* ------------------------------------------------------
*/
{
cleanup->routine = routine;
cleanup->arg = arg;
cleanup->prev = (pte_cleanup_t *) pthread_getspecific (pte_cleanupKey);
pthread_setspecific (pte_cleanupKey, (void *) cleanup);
}
-1017
View File
File diff suppressed because it is too large. Load diff
-891
View File
@@ -1,891 +0,0 @@
/* This is an implementation of the threads API of POSIX 1003.1-2001.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined( PTHREAD_H )
#define PTHREAD_H
#include <pte_types.h>
#include <sched.h>
#define PTE_VERSION 2,8,0,0
#define PTE_VERSION_STRING "2, 8, 0, 0\0"
/* There are two implementations of cancel cleanup.
* Note that pthread.h is included in both application
* compilation units and also internally for the library.
* The code here and within the library aims to work
* for all reasonable combinations of environments.
*
* The two implementations are:
*
* C
* C++
*
*/
/*
* Define defaults for cleanup code.
* Note: Unless the build explicitly defines one of the following, then
* we default to standard C style cleanup. This style uses setjmp/longjmp
* in the cancelation and thread exit implementations and therefore won't
* do stack unwinding if linked to applications that have it (e.g.
* C++ apps). This is currently consistent with most/all commercial Unix
* POSIX threads implementations.
*/
#undef PTE_LEVEL
#if defined(_POSIX_SOURCE)
#define PTE_LEVEL 0
/* Early POSIX */
#endif
#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309
#undef PTE_LEVEL
#define PTE_LEVEL 1
/* Include 1b, 1c and 1d */
#endif
#if defined(INCLUDE_NP)
#undef PTE_LEVEL
#define PTE_LEVEL 2
/* Include Non-Portable extensions */
#endif
#define PTE_LEVEL_MAX 3
#if !defined(PTE_LEVEL)
#define PTE_LEVEL PTE_LEVEL_MAX
/* Include everything */
#endif
/*
* -------------------------------------------------------------
*
*
* Module: pthread.h
*
* Purpose:
* Provides an implementation of PThreads based upon the
* standard:
*
* POSIX 1003.1-2001
* and
* The Single Unix Specification version 3
*
* (these two are equivalent)
*
* in order to enhance code portability between Windows,
* various commercial Unix implementations, and Linux.
*
* See the ANNOUNCE file for a full list of conforming
* routines and defined constants, and a list of missing
* routines and constants not defined in this implementation.
*
* Authors:
* There have been many contributors to this library.
* The initial implementation was contributed by
* John Bossom, and several others have provided major
* sections or revisions of parts of the implementation.
* Often significant effort has been contributed to
* find and fix important bugs and other problems to
* improve the reliability of the library, which sometimes
* is not reflected in the amount of code which changed as
* result.
* As much as possible, the contributors are acknowledged
* in the ChangeLog file in the source code distribution
* where their changes are noted in detail.
*
* Contributors are listed in the CONTRIBUTORS file.
*
* As usual, all bouquets go to the contributors, and all
* brickbats go to the project maintainer.
*
* Maintainer:
* The code base for this project is coordinated and
* eventually pre-tested, packaged, and made available by
*
* Ross Johnson <rpj@callisto.canberra.edu.au>
*
* QA Testers:
* Ultimately, the library is tested in the real world by
* a host of competent and demanding scientists and
* engineers who report bugs and/or provide solutions
* which are then fixed or incorporated into subsequent
* versions of the library. Each time a bug is fixed, a
* test case is written to prove the fix and ensure
* that later changes to the code don't reintroduce the
* same error. The number of test cases is slowly growing
* and therefore so is the code reliability.
*
* Compliance:
* See the file ANNOUNCE for the list of implemented
* and not-implemented routines and defined options.
* Of course, these are all defined is this file as well.
*
* Web site:
* The source code and other information about this library
* are available from
*
* http://sources.redhat.com/pthreads-win32/
*
* -------------------------------------------------------------
*/
#include <time.h>
#include <setjmp.h>
#include <limits.h>
/*
* Boolean values to make us independent of system includes.
*/
enum
{
PTE_FALSE = 0,
PTE_TRUE = (! PTE_FALSE)
};
/*
* -------------------------------------------------------------
*
* POSIX 1003.1-2001 Options
* =========================
*
* Options are normally set in <unistd.h>, which is not provided
* with pthreads-embedded.
*
* For conformance with the Single Unix Specification (version 3), all of the
* options below are defined, and have a value of either -1 (not supported)
* or 200112L (supported).
*
* These options can neither be left undefined nor have a value of 0, because
* either indicates that sysconf(), which is not implemented, may be used at
* runtime to check the status of the option.
*
* _POSIX_THREADS (== 200112L)
* If == 200112L, you can use threads
*
* _POSIX_THREAD_ATTR_STACKSIZE (== 200112L)
* If == 200112L, you can control the size of a thread's
* stack
* pthread_attr_getstacksize
* pthread_attr_setstacksize
*
* _POSIX_THREAD_ATTR_STACKADDR (== -1)
* If == 200112L, you can allocate and control a thread's
* stack. If not supported, the following functions
* will return ENOSYS, indicating they are not
* supported:
* pthread_attr_getstackaddr
* pthread_attr_setstackaddr
*
* _POSIX_THREAD_PRIORITY_SCHEDULING (== -1)
* If == 200112L, you can use realtime scheduling.
* This option indicates that the behaviour of some
* implemented functions conforms to the additional TPS
* requirements in the standard. E.g. rwlocks favour
* writers over readers when threads have equal priority.
*
* _POSIX_THREAD_PRIO_INHERIT (== -1)
* If == 200112L, you can create priority inheritance
* mutexes.
* pthread_mutexattr_getprotocol +
* pthread_mutexattr_setprotocol +
*
* _POSIX_THREAD_PRIO_PROTECT (== -1)
* If == 200112L, you can create priority ceiling mutexes
* Indicates the availability of:
* pthread_mutex_getprioceiling
* pthread_mutex_setprioceiling
* pthread_mutexattr_getprioceiling
* pthread_mutexattr_getprotocol +
* pthread_mutexattr_setprioceiling
* pthread_mutexattr_setprotocol +
*
* _POSIX_THREAD_PROCESS_SHARED (== -1)
* If set, you can create mutexes and condition
* variables that can be shared with another
* process.If set, indicates the availability
* of:
* pthread_mutexattr_getpshared
* pthread_mutexattr_setpshared
* pthread_condattr_getpshared
* pthread_condattr_setpshared
*
* _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L)
* If == 200112L you can use the special *_r library
* functions that provide thread-safe behaviour
*
* _POSIX_READER_WRITER_LOCKS (== 200112L)
* If == 200112L, you can use read/write locks
*
* _POSIX_SPIN_LOCKS (== 200112L)
* If == 200112L, you can use spin locks
*
* _POSIX_BARRIERS (== 200112L)
* If == 200112L, you can use barriers
*
* + These functions provide both 'inherit' and/or
* 'protect' protocol, based upon these macro
* settings.
*
* -------------------------------------------------------------
*/
/*
* POSIX Options
*/
#undef _POSIX_THREADS
#define _POSIX_THREADS 200112L
#undef _POSIX_READER_WRITER_LOCKS
#define _POSIX_READER_WRITER_LOCKS 200112L
#undef _POSIX_SPIN_LOCKS
#define _POSIX_SPIN_LOCKS 200112L
#undef _POSIX_BARRIERS
#define _POSIX_BARRIERS 200112L
#undef _POSIX_THREAD_SAFE_FUNCTIONS
#define _POSIX_THREAD_SAFE_FUNCTIONS 200112L
#undef _POSIX_THREAD_ATTR_STACKSIZE
#define _POSIX_THREAD_ATTR_STACKSIZE 200112L
/*
* The following options are not supported
*/
#undef _POSIX_THREAD_ATTR_STACKADDR
#define _POSIX_THREAD_ATTR_STACKADDR -1
#undef _POSIX_THREAD_PRIO_INHERIT
#define _POSIX_THREAD_PRIO_INHERIT -1
#undef _POSIX_THREAD_PRIO_PROTECT
#define _POSIX_THREAD_PRIO_PROTECT -1
/* TPS is not fully supported. */
#undef _POSIX_THREAD_PRIORITY_SCHEDULING
#define _POSIX_THREAD_PRIORITY_SCHEDULING -1
#undef _POSIX_THREAD_PROCESS_SHARED
#define _POSIX_THREAD_PROCESS_SHARED -1
/*
* POSIX 1003.1-2001 Limits
* ===========================
*
* These limits are normally set in <limits.h>, which is not provided with
* pthreads-embedded.
*
* PTHREAD_DESTRUCTOR_ITERATIONS
* Maximum number of attempts to destroy
* a thread's thread-specific data on
* termination (must be at least 4)
*
* PTHREAD_KEYS_MAX
* Maximum number of thread-specific data keys
* available per process (must be at least 128)
*
* PTHREAD_STACK_MIN
* Minimum supported stack size for a thread
*
* PTHREAD_THREADS_MAX
* Maximum number of threads supported per
* process (must be at least 64).
*
* SEM_NSEMS_MAX
* The maximum number of semaphores a process can have.
* (must be at least 256)
*
* SEM_VALUE_MAX
* The maximum value a semaphore can have.
* (must be at least 32767)
*
*/
#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS
#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4
#undef PTHREAD_DESTRUCTOR_ITERATIONS
#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS
#undef _POSIX_THREAD_KEYS_MAX
#define _POSIX_THREAD_KEYS_MAX 128
#undef PTHREAD_KEYS_MAX
#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX
#undef PTHREAD_STACK_MIN
#define PTHREAD_STACK_MIN 0
#undef _POSIX_THREAD_THREADS_MAX
#define _POSIX_THREAD_THREADS_MAX 64
/* Arbitrary value */
#undef PTHREAD_THREADS_MAX
#define PTHREAD_THREADS_MAX 2019
#undef _POSIX_SEM_NSEMS_MAX
#define _POSIX_SEM_NSEMS_MAX 256
/* Arbitrary value */
#undef SEM_NSEMS_MAX
#define SEM_NSEMS_MAX 1024
#undef _POSIX_SEM_VALUE_MAX
#define _POSIX_SEM_VALUE_MAX 32767
#undef SEM_VALUE_MAX
#define SEM_VALUE_MAX INT_MAX
/*
* Generic handle type - intended to extend uniqueness beyond
* that available with a simple pointer. It should scale for either
* IA-32 or IA-64.
*/
typedef struct
{
void * p; /* Pointer to actual object */
unsigned int x; /* Extra information - reuse count etc */
} pte_handle_t;
typedef /* pte_handle_t */ void * pthread_t;
typedef struct pthread_attr_t_ * pthread_attr_t;
typedef struct pthread_once_t_ pthread_once_t;
typedef struct pthread_key_t_ * pthread_key_t;
typedef struct pthread_mutex_t_ * pthread_mutex_t;
typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t;
typedef struct pthread_cond_t_ * pthread_cond_t;
typedef struct pthread_condattr_t_ * pthread_condattr_t;
typedef struct pthread_rwlock_t_ * pthread_rwlock_t;
typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t;
typedef struct pthread_spinlock_t_ * pthread_spinlock_t;
typedef struct pthread_barrier_t_ * pthread_barrier_t;
typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t;
/*
* ====================
* ====================
* POSIX Threads
* ====================
* ====================
*/
enum
{
/*
* pthread_attr_{get,set}detachstate
*/
PTHREAD_CREATE_JOINABLE = 0, /* Default */
PTHREAD_CREATE_DETACHED = 1,
/*
* pthread_attr_{get,set}inheritsched
*/
PTHREAD_INHERIT_SCHED = 0,
PTHREAD_EXPLICIT_SCHED = 1, /* Default */
/*
* pthread_{get,set}scope
*/
PTHREAD_SCOPE_PROCESS = 0,
PTHREAD_SCOPE_SYSTEM = 1, /* Default */
PTHREAD_SCOPE_PROCESS_VFPU = 2, /* PSP specific */
/*
* pthread_setcancelstate paramters
*/
PTHREAD_CANCEL_ENABLE = 0, /* Default */
PTHREAD_CANCEL_DISABLE = 1,
/*
* pthread_setcanceltype parameters
*/
PTHREAD_CANCEL_ASYNCHRONOUS = 0,
PTHREAD_CANCEL_DEFERRED = 1, /* Default */
/*
* pthread_mutexattr_{get,set}pshared
* pthread_condattr_{get,set}pshared
*/
PTHREAD_PROCESS_PRIVATE = 0,
PTHREAD_PROCESS_SHARED = 1,
/*
* pthread_barrier_wait
*/
PTHREAD_BARRIER_SERIAL_THREAD = -1
};
/*
* ====================
* ====================
* Cancelation
* ====================
* ====================
*/
#define PTHREAD_CANCELED ((void *) -1)
/*
* ====================
* ====================
* Once Key
* ====================
* ====================
*/
#define PTHREAD_ONCE_INIT { PTE_FALSE, 0, 0, 0}
struct pthread_once_t_
{
int state;
void * semaphore;
int numSemaphoreUsers;
int done; /* indicates if user function has been executed */
// void * lock;
// int reserved1;
// int reserved2;
};
/*
* ====================
* ====================
* Object initialisers
* ====================
* ====================
*/
#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) -1)
#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t) -2)
#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t) -3)
/*
* Compatibility with LinuxThreads
*/
#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER
#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER
#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) -1)
#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) -1)
#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t) -1)
/*
* Mutex types.
*/
enum
{
/* Compatibility with LinuxThreads */
PTHREAD_MUTEX_FAST_NP,
PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ERRORCHECK_NP,
PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP,
PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP,
/* For compatibility with POSIX */
PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP,
PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
};
typedef struct pte_cleanup_t pte_cleanup_t;
typedef void (* pte_cleanup_callback_t)(void *);
struct pte_cleanup_t
{
pte_cleanup_callback_t routine;
void *arg;
struct pte_cleanup_t *prev;
};
/*
* C implementation of PThreads cancel cleanup
*/
#define pthread_cleanup_push( _rout, _arg ) \
{ \
pte_cleanup_t _cleanup; \
\
pte_push_cleanup( &_cleanup, (pte_cleanup_callback_t) (_rout), (_arg) ); \
#define pthread_cleanup_pop( _execute ) \
(void) pte_pop_cleanup( _execute ); \
}
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/*
* ===============
* ===============
* Methods
* ===============
* ===============
*/
int pthread_init (void);
void pthread_terminate (void);
/*
* PThread Attribute Functions
*/
int pthread_attr_init (pthread_attr_t * attr);
int pthread_attr_destroy (pthread_attr_t * attr);
int pthread_attr_getdetachstate (const pthread_attr_t * attr,
int *detachstate);
int pthread_attr_getstackaddr (const pthread_attr_t * attr,
void **stackaddr);
int pthread_attr_getstacksize (const pthread_attr_t * attr,
size_t * stacksize);
int pthread_attr_setdetachstate (pthread_attr_t * attr,
int detachstate);
int pthread_attr_setstackaddr (pthread_attr_t * attr,
void *stackaddr);
int pthread_attr_setstacksize (pthread_attr_t * attr,
size_t stacksize);
int pthread_attr_getschedparam (const pthread_attr_t *attr,
struct sched_param *param);
int pthread_attr_setschedparam (pthread_attr_t *attr,
const struct sched_param *param);
int pthread_attr_setschedpolicy (pthread_attr_t *,
int);
int pthread_attr_getschedpolicy (pthread_attr_t *,
int *);
int pthread_attr_setinheritsched(pthread_attr_t * attr,
int inheritsched);
int pthread_attr_getinheritsched(pthread_attr_t * attr,
int * inheritsched);
int pthread_attr_setscope (pthread_attr_t *,
int);
int pthread_attr_getscope (const pthread_attr_t *,
int *);
/*
* PThread Functions
*/
int pthread_create (pthread_t * tid,
const pthread_attr_t * attr,
void *(*start) (void *),
void *arg);
int pthread_detach (pthread_t tid);
int pthread_equal (pthread_t t1,
pthread_t t2);
void pthread_exit (void *value_ptr);
int pthread_join (pthread_t thread,
void **value_ptr);
pthread_t pthread_self (void);
int pthread_cancel (pthread_t thread);
int pthread_setcancelstate (int state,
int *oldstate);
int pthread_setcanceltype (int type,
int *oldtype);
void pthread_testcancel (void);
int pthread_once (pthread_once_t * once_control,
void (*init_routine) (void));
#if PTE_LEVEL >= PTE_LEVEL_MAX
pte_cleanup_t * pte_pop_cleanup (int execute);
void pte_push_cleanup (pte_cleanup_t * cleanup,
void (*routine) (void *),
void *arg);
#endif /* PTE_LEVEL >= PTE_LEVEL_MAX */
/*
* Thread Specific Data Functions
*/
int pthread_key_create (pthread_key_t * key,
void (*destructor) (void *));
int pthread_key_delete (pthread_key_t key);
int pthread_setspecific (pthread_key_t key,
const void *value);
void * pthread_getspecific (pthread_key_t key);
/*
* Mutex Attribute Functions
*/
int pthread_mutexattr_init (pthread_mutexattr_t * attr);
int pthread_mutexattr_destroy (pthread_mutexattr_t * attr);
int pthread_mutexattr_getpshared (const pthread_mutexattr_t
* attr,
int *pshared);
int pthread_mutexattr_setpshared (pthread_mutexattr_t * attr,
int pshared);
int pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind);
int pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind);
/*
* Barrier Attribute Functions
*/
int pthread_barrierattr_init (pthread_barrierattr_t * attr);
int pthread_barrierattr_destroy (pthread_barrierattr_t * attr);
int pthread_barrierattr_getpshared (const pthread_barrierattr_t
* attr,
int *pshared);
int pthread_barrierattr_setpshared (pthread_barrierattr_t * attr,
int pshared);
/*
* Mutex Functions
*/
int pthread_mutex_init (pthread_mutex_t * mutex,
const pthread_mutexattr_t * attr);
int pthread_mutex_destroy (pthread_mutex_t * mutex);
int pthread_mutex_lock (pthread_mutex_t * mutex);
int pthread_mutex_timedlock(pthread_mutex_t *mutex,
const struct timespec *abstime);
int pthread_mutex_trylock (pthread_mutex_t * mutex);
int pthread_mutex_unlock (pthread_mutex_t * mutex);
/*
* Spinlock Functions
*/
int pthread_spin_init (pthread_spinlock_t * lock, int pshared);
int pthread_spin_destroy (pthread_spinlock_t * lock);
int pthread_spin_lock (pthread_spinlock_t * lock);
int pthread_spin_trylock (pthread_spinlock_t * lock);
int pthread_spin_unlock (pthread_spinlock_t * lock);
/*
* Barrier Functions
*/
int pthread_barrier_init (pthread_barrier_t * barrier,
const pthread_barrierattr_t * attr,
unsigned int count);
int pthread_barrier_destroy (pthread_barrier_t * barrier);
int pthread_barrier_wait (pthread_barrier_t * barrier);
/*
* Condition Variable Attribute Functions
*/
int pthread_condattr_init (pthread_condattr_t * attr);
int pthread_condattr_destroy (pthread_condattr_t * attr);
int pthread_condattr_getpshared (const pthread_condattr_t * attr,
int *pshared);
int pthread_condattr_setpshared (pthread_condattr_t * attr,
int pshared);
/*
* Condition Variable Functions
*/
int pthread_cond_init (pthread_cond_t * cond,
const pthread_condattr_t * attr);
int pthread_cond_destroy (pthread_cond_t * cond);
int pthread_cond_wait (pthread_cond_t * cond,
pthread_mutex_t * mutex);
int pthread_cond_timedwait (pthread_cond_t * cond,
pthread_mutex_t * mutex,
const struct timespec *abstime);
int pthread_cond_signal (pthread_cond_t * cond);
int pthread_cond_broadcast (pthread_cond_t * cond);
/*
* Scheduling
*/
int pthread_setschedparam (pthread_t thread,
int policy,
const struct sched_param *param);
int pthread_getschedparam (pthread_t thread,
int *policy,
struct sched_param *param);
int pthread_setconcurrency (int);
int pthread_getconcurrency (void);
/*
* Read-Write Lock Functions
*/
int pthread_rwlock_init(pthread_rwlock_t *lock,
const pthread_rwlockattr_t *attr);
int pthread_rwlock_destroy(pthread_rwlock_t *lock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *);
int pthread_rwlock_trywrlock(pthread_rwlock_t *);
int pthread_rwlock_rdlock(pthread_rwlock_t *lock);
int pthread_rwlock_timedrdlock(pthread_rwlock_t *lock,
const struct timespec *abstime);
int pthread_rwlock_wrlock(pthread_rwlock_t *lock);
int pthread_rwlock_timedwrlock(pthread_rwlock_t *lock,
const struct timespec *abstime);
int pthread_rwlock_unlock(pthread_rwlock_t *lock);
int pthread_rwlockattr_init (pthread_rwlockattr_t * attr);
int pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr);
int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr,
int *pshared);
int pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr,
int pshared);
#if PTE_LEVEL >= PTE_LEVEL_MAX - 1
/*
* Signal Functions. Should be defined in <signal.h> but we might
* already have signal.h that don't define these.
*/
int pthread_kill(pthread_t thread, int sig);
/*
* Non-portable functions
*/
/*
* Compatibility with Linux.
*/
int pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr,
int kind);
int pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr,
int *kind);
/*
* Possibly supported by other POSIX threads implementations
*/
int pthread_delay_np (struct timespec * interval);
int pthread_num_processors_np(void);
/*
* Register a system time change with the library.
* Causes the library to perform various functions
* in response to the change. Should be called whenever
* the application's top level window receives a
* WM_TIMECHANGE message. It can be passed directly to
* pthread_create() as a new thread if desired.
*/
void * pthread_timechange_handler_np(void *);
#endif /*PTE_LEVEL >= PTE_LEVEL_MAX - 1 */
#ifdef __cplusplus
}
#endif /* cplusplus */
#if PTE_LEVEL >= PTE_LEVEL_MAX
#endif /* PTE_LEVEL >= PTE_LEVEL_MAX */
/*
* Some compiler environments don't define some things.
*/
# define _ftime ftime
# define _timeb timeb
#undef PTE_LEVEL
#undef PTE_LEVEL_MAX
#endif /* PTHREAD_H */
-581
View File
@@ -1,581 +0,0 @@
/*
* pthread_attr.c
*
* Description:
* This translation unit implements operations on thread attribute objects.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include <string.h>
#include "pthread.h"
#include "implement.h"
#include "sched.h"
int
pthread_attr_destroy (pthread_attr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Destroys a thread attributes object.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_attr_t
*
*
* DESCRIPTION
* Destroys a thread attributes object.
*
* NOTES:
* 1) Does not affect threads created with 'attr'.
*
* RESULTS
* 0 successfully destroyed attr,
* EINVAL 'attr' is invalid.
*
* ------------------------------------------------------
*/
{
if (pte_is_attr (attr) != 0)
return EINVAL;
/*
* Set the attribute object to a specific invalid value.
*/
(*attr)->valid = 0;
free (*attr);
*attr = NULL;
return 0;
}
int pthread_attr_getdetachstate (const pthread_attr_t * attr, int *detachstate)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function determines whether threads created with
* 'attr' will run detached.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_attr_t
*
* detachstate
* pointer to an integer into which is returned one
* of:
*
* PTHREAD_CREATE_JOINABLE
* Thread ID is valid, must be joined
*
* PTHREAD_CREATE_DETACHED
* Thread ID is invalid, cannot be joined,
* canceled, or modified
*
*
* DESCRIPTION
* This function determines whether threads created with
* 'attr' will run detached.
*
* NOTES:
* 1) You cannot join or cancel detached threads.
*
* RESULTS
* 0 successfully retrieved detach state,
* EINVAL 'attr' is invalid
*
* ------------------------------------------------------
*/
{
if (pte_is_attr (attr) != 0 || detachstate == NULL)
{
*detachstate = PTHREAD_CREATE_DETACHED;
return EINVAL;
}
*detachstate = (*attr)->detachstate;
return 0;
}
int pthread_attr_getinheritsched (pthread_attr_t * attr, int *inheritsched)
{
if (pte_is_attr (attr) != 0 || inheritsched == NULL)
return EINVAL;
*inheritsched = (*attr)->inheritsched;
return 0;
}
int pthread_attr_getschedparam (const pthread_attr_t * attr,
struct sched_param *param)
{
if (pte_is_attr (attr) != 0 || param == NULL)
return EINVAL;
memcpy (param, &(*attr)->param, sizeof (*param));
return 0;
}
int pthread_attr_getschedpolicy (pthread_attr_t * attr, int *policy)
{
if (pte_is_attr (attr) != 0 || policy == NULL)
return EINVAL;
/*
* Validate the policy arg.
* Check that a policy constant wasn't passed rather than &policy.
*/
if (policy <= (int *) SCHED_MAX)
return EINVAL;
*policy = SCHED_OTHER;
return 0;
}
int pthread_attr_getscope (const pthread_attr_t * attr, int *contentionscope)
{
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
*contentionscope = (*attr)->contentionscope;
return 0;
#else
return ENOSYS;
#endif
}
int pthread_attr_getstackaddr (const pthread_attr_t * attr, void **stackaddr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function determines the address of the stack
* on which threads created with 'attr' will run.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_attr_t
*
* stackaddr
* pointer into which is returned the stack address.
*
*
* DESCRIPTION
* This function determines the address of the stack
* on which threads created with 'attr' will run.
*
* NOTES:
* 1) Function supported only if this macro is
* defined:
*
* _POSIX_THREAD_ATTR_STACKADDR
*
* 2) Create only one thread for each stack
* address..
*
* RESULTS
* 0 successfully retreived stack address,
* EINVAL 'attr' is invalid
* ENOSYS function not supported
*
* ------------------------------------------------------
*/
{
#if defined( _POSIX_THREAD_ATTR_STACKADDR )
if (pte_is_attr (attr) != 0)
return EINVAL;
*stackaddr = (*attr)->stackaddr;
return 0;
#else
return ENOSYS;
#endif /* _POSIX_THREAD_ATTR_STACKADDR */
}
int
pthread_attr_getstacksize (const pthread_attr_t * attr, size_t * stacksize)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function determines the size of the stack on
* which threads created with 'attr' will run.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_attr_t
*
* stacksize
* pointer to size_t into which is returned the
* stack size, in bytes.
*
*
* DESCRIPTION
* This function determines the size of the stack on
* which threads created with 'attr' will run.
*
* NOTES:
* 1) Function supported only if this macro is
* defined:
*
* _POSIX_THREAD_ATTR_STACKSIZE
*
* 2) Use on newly created attributes object to
* find the default stack size.
*
* RESULTS
* 0 successfully retrieved stack size,
* EINVAL 'attr' is invalid
* ENOSYS function not supported
*
* ------------------------------------------------------
*/
{
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
if (pte_is_attr (attr) != 0)
return EINVAL;
/* Everything is okay. */
*stacksize = (*attr)->stacksize;
return 0;
#else
return ENOSYS;
#endif /* _POSIX_THREAD_ATTR_STACKSIZE */
}
int pthread_attr_init (pthread_attr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Initializes a thread attributes object with default
* attributes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_attr_t
*
*
* DESCRIPTION
* Initializes a thread attributes object with default
* attributes.
*
* NOTES:
* 1) Used to define thread attributes
*
* RESULTS
* 0 successfully initialized attr,
* ENOMEM insufficient memory for attr.
*
* ------------------------------------------------------
*/
{
pthread_attr_t attr_result;
/* This is disallowed. */
if (attr == NULL)
return EINVAL;
attr_result = (pthread_attr_t) malloc (sizeof (*attr_result));
if (attr_result == NULL)
return ENOMEM;
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
/*
* Default to zero size?
*/
attr_result->stacksize = 0;
#endif
#ifdef _POSIX_THREAD_ATTR_STACKADDR
/* FIXME: Set this to something sensible when we support it. */
attr_result->stackaddr = NULL;
#endif
attr_result->detachstate = PTHREAD_CREATE_JOINABLE;
/*
* Win32 sets new threads to THREAD_PRIORITY_NORMAL and
* not to that of the parent thread. We choose to default to
* this arrangement.
*/
attr_result->param.sched_priority = pte_osThreadGetDefaultPriority();
attr_result->inheritsched = PTHREAD_EXPLICIT_SCHED;
attr_result->contentionscope = PTHREAD_SCOPE_SYSTEM;
attr_result->valid = PTE_ATTR_VALID;
*attr = attr_result;
return 0;
}
int pthread_attr_setdetachstate (pthread_attr_t * attr, int detachstate)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function specifies whether threads created with
* 'attr' will run detached.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_attr_t
*
* detachstate
* an integer containing one of:
*
* PTHREAD_CREATE_JOINABLE
* Thread ID is valid, must be joined
*
* PTHREAD_CREATE_DETACHED
* Thread ID is invalid, cannot be joined,
* canceled, or modified
*
*
* DESCRIPTION
* This function specifies whether threads created with
* 'attr' will run detached.
*
* NOTES:
* 1) You cannot join or cancel detached threads.
*
* RESULTS
* 0 successfully set detach state,
* EINVAL 'attr' or 'detachstate' is invalid
*
* ------------------------------------------------------
*/
{
if (pte_is_attr (attr) != 0)
return EINVAL;
if (detachstate != PTHREAD_CREATE_JOINABLE &&
detachstate != PTHREAD_CREATE_DETACHED)
return EINVAL;
(*attr)->detachstate = detachstate;
return 0;
}
int pthread_attr_setinheritsched (pthread_attr_t * attr, int inheritsched)
{
if (pte_is_attr (attr) != 0)
return EINVAL;
if (PTHREAD_INHERIT_SCHED != inheritsched
&& PTHREAD_EXPLICIT_SCHED != inheritsched)
return EINVAL;
(*attr)->inheritsched = inheritsched;
return 0;
}
int pthread_attr_setschedparam (pthread_attr_t * attr,
const struct sched_param *param)
{
int priority;
if (pte_is_attr (attr) != 0 || param == NULL)
return EINVAL;
priority = param->sched_priority;
/* Validate priority level. */
if (priority < sched_get_priority_min (SCHED_OTHER) ||
priority > sched_get_priority_max (SCHED_OTHER))
{
return EINVAL;
}
memcpy (&(*attr)->param, param, sizeof (*param));
return 0;
}
int pthread_attr_setschedpolicy (pthread_attr_t * attr, int policy)
{
if (pte_is_attr (attr) != 0)
return EINVAL;
if (policy != SCHED_OTHER)
return ENOTSUP;
return 0;
}
int pthread_attr_setscope (pthread_attr_t * attr, int contentionscope)
{
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
switch (contentionscope)
{
case PTHREAD_SCOPE_SYSTEM:
(*attr)->contentionscope = contentionscope;
return 0;
case PTHREAD_SCOPE_PROCESS:
return ENOTSUP;
default:
return EINVAL;
}
#else
return ENOSYS;
#endif
}
int pthread_attr_setstackaddr (pthread_attr_t * attr, void *stackaddr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Threads created with 'attr' will run on the stack
* starting at 'stackaddr'.
* Stack must be at least PTHREAD_STACK_MIN bytes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_attr_t
*
* stacksize
* stack size, in bytes.
*
*
* DESCRIPTION
* Threads created with 'attr' will run on the stack
* starting at 'stackaddr'.
* Stack must be at least PTHREAD_STACK_MIN bytes.
*
* NOTES:
* 1) Function supported only if this macro is
* defined:
*
* _POSIX_THREAD_ATTR_STACKADDR
*
* 2) Create only one thread for each stack
* address..
*
* 3) Ensure that stackaddr is aligned.
*
* RESULTS
* 0 successfully set stack address,
* EINVAL 'attr' is invalid
* ENOSYS function not supported
*
* ------------------------------------------------------
*/
{
#if defined( _POSIX_THREAD_ATTR_STACKADDR )
if (pte_is_attr (attr) != 0)
return EINVAL;
(*attr)->stackaddr = stackaddr;
return 0;
#else
return ENOSYS;
#endif /* _POSIX_THREAD_ATTR_STACKADDR */
}
int pthread_attr_setstacksize (pthread_attr_t * attr, size_t stacksize)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function specifies the size of the stack on
* which threads created with 'attr' will run.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_attr_t
*
* stacksize
* stack size, in bytes.
*
*
* DESCRIPTION
* This function specifies the size of the stack on
* which threads created with 'attr' will run.
*
* NOTES:
* 1) Function supported only if this macro is
* defined:
*
* _POSIX_THREAD_ATTR_STACKSIZE
*
* 2) Find the default first (using
* pthread_attr_getstacksize), then increase
* by multiplying.
*
* 3) Only use if thread needs more than the
* default.
*
* RESULTS
* 0 successfully set stack size,
* EINVAL 'attr' is invalid or stacksize too
* small or too big.
* ENOSYS function not supported
*
* ------------------------------------------------------
*/
{
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
#if PTHREAD_STACK_MIN > 0
/* Verify that the stack size is within range. */
if (stacksize < PTHREAD_STACK_MIN)
return EINVAL;
#endif
if (pte_is_attr (attr) != 0)
return EINVAL;
/* Everything is okay. */
(*attr)->stacksize = stacksize;
return 0;
#else
return ENOSYS;
#endif /* _POSIX_THREAD_ATTR_STACKSIZE */
}
-163
View File
@@ -1,163 +0,0 @@
/*
* pthread_barrier.c
*
* Description:
* This translation unit implements barrier primitives.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include "pthread.h"
#include "implement.h"
int pthread_barrier_destroy (pthread_barrier_t * barrier)
{
int result = 0;
pthread_barrier_t b;
if (barrier == NULL || *barrier == (pthread_barrier_t) PTE_OBJECT_INVALID)
return EINVAL;
b = *barrier;
*barrier = NULL;
if (0 == (result = sem_destroy (&(b->semBarrierBreeched[0]))))
{
if (0 == (result = sem_destroy (&(b->semBarrierBreeched[1]))))
{
(void) free (b);
return 0;
}
(void) sem_init (&(b->semBarrierBreeched[0]), b->pshared, 0);
}
*barrier = b;
return (result);
}
int pthread_barrier_init (pthread_barrier_t * barrier,
const pthread_barrierattr_t * attr, unsigned int count)
{
pthread_barrier_t b;
if (barrier == NULL || count == 0)
return EINVAL;
if (NULL != (b = (pthread_barrier_t) calloc (1, sizeof (*b))))
{
b->pshared = (attr != NULL && *attr != NULL
? (*attr)->pshared : PTHREAD_PROCESS_PRIVATE);
b->nCurrentBarrierHeight = b->nInitialBarrierHeight = count;
b->iStep = 0;
/*
* Two semaphores are used in the same way as two stepping
* stones might be used in crossing a stream. Once all
* threads are safely on one stone, the other stone can
* be moved ahead, and the threads can start moving to it.
* If some threads decide to eat their lunch before moving
* then the other threads have to wait.
*/
if (0 == sem_init (&(b->semBarrierBreeched[0]), b->pshared, 0))
{
if (0 == sem_init (&(b->semBarrierBreeched[1]), b->pshared, 0))
{
*barrier = b;
return 0;
}
(void) sem_destroy (&(b->semBarrierBreeched[0]));
}
(void) free (b);
}
return ENOMEM;
}
int pthread_barrier_wait (pthread_barrier_t * barrier)
{
int result;
int step;
pthread_barrier_t b;
if (barrier == NULL || *barrier == (pthread_barrier_t) PTE_OBJECT_INVALID)
return EINVAL;
b = *barrier;
step = b->iStep;
if (0 == PTE_ATOMIC_DECREMENT ((int *) &(b->nCurrentBarrierHeight)))
{
/* Must be done before posting the semaphore. */
b->nCurrentBarrierHeight = b->nInitialBarrierHeight;
/*
* There is no race condition between the semaphore wait and post
* because we are using two alternating semas and all threads have
* entered barrier_wait and checked nCurrentBarrierHeight before this
* barrier's sema can be posted. Any threads that have not quite
* entered sem_wait below when the multiple_post has completed
* will nevertheless continue through the semaphore (barrier)
* and will not be left stranded.
*/
result = (b->nInitialBarrierHeight > 1
? sem_post_multiple (&(b->semBarrierBreeched[step]),
b->nInitialBarrierHeight - 1) : 0);
}
else
{
/*
* Use the non-cancelable version of sem_wait().
*/
result = sem_wait (&(b->semBarrierBreeched[step]));
// result = sem_wait_nocancel (&(b->semBarrierBreeched[step]));
}
/*
* The first thread across will be the PTHREAD_BARRIER_SERIAL_THREAD.
* This also sets up the alternate semaphore as the next barrier.
*/
if (0 == result)
{
result = (step ==
PTE_ATOMIC_COMPARE_EXCHANGE (& (b->iStep),(1L - step),step) ?
PTHREAD_BARRIER_SERIAL_THREAD : 0);
}
return (result);
}
-257
View File
@@ -1,257 +0,0 @@
/*
* pthread_barrier_attr.c
*
* Description:
* This translation unit implements barrier primitives.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include "pthread.h"
#include "implement.h"
int
pthread_barrierattr_destroy (pthread_barrierattr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Destroys a barrier attributes object. The object can
* no longer be used.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_barrierattr_t
*
*
* DESCRIPTION
* Destroys a barrier attributes object. The object can
* no longer be used.
*
* NOTES:
* 1) Does not affect barrieres created using 'attr'
*
* RESULTS
* 0 successfully released attr,
* EINVAL 'attr' is invalid.
*
* ------------------------------------------------------
*/
{
int result = 0;
if (attr == NULL || *attr == NULL)
result = EINVAL;
else
{
pthread_barrierattr_t ba = *attr;
*attr = NULL;
free (ba);
}
return (result);
}
int
pthread_barrierattr_getpshared (const pthread_barrierattr_t * attr,
int *pshared)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Determine whether barriers created with 'attr' can be
* shared between processes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_barrierattr_t
*
* pshared
* will be set to one of:
*
* PTHREAD_PROCESS_SHARED
* May be shared if in shared memory
*
* PTHREAD_PROCESS_PRIVATE
* Cannot be shared.
*
*
* DESCRIPTION
* Mutexes creatd with 'attr' can be shared between
* processes if pthread_barrier_t variable is allocated
* in memory shared by these processes.
* NOTES:
* 1) pshared barriers MUST be allocated in shared
* memory.
* 2) The following macro is defined if shared barriers
* are supported:
* _POSIX_THREAD_PROCESS_SHARED
*
* RESULTS
* 0 successfully retrieved attribute,
* EINVAL 'attr' is invalid,
*
* ------------------------------------------------------
*/
{
int result;
if ((attr != NULL && *attr != NULL) && (pshared != NULL))
{
*pshared = (*attr)->pshared;
result = 0;
}
else
result = EINVAL;
return (result);
}
int pthread_barrierattr_init (pthread_barrierattr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Initializes a barrier attributes object with default
* attributes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_barrierattr_t
*
*
* DESCRIPTION
* Initializes a barrier attributes object with default
* attributes.
*
* NOTES:
* 1) Used to define barrier types
*
* RESULTS
* 0 successfully initialized attr,
* ENOMEM insufficient memory for attr.
*
* ------------------------------------------------------
*/
{
int result = 0;
pthread_barrierattr_t ba = (pthread_barrierattr_t) calloc (1, sizeof (*ba));
if (ba == NULL)
result = ENOMEM;
else
ba->pshared = PTHREAD_PROCESS_PRIVATE;
*attr = ba;
return (result);
}
int pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, int pshared)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Barriers created with 'attr' can be shared between
* processes if pthread_barrier_t variable is allocated
* in memory shared by these processes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_barrierattr_t
*
* pshared
* must be one of:
*
* PTHREAD_PROCESS_SHARED
* May be shared if in shared memory
*
* PTHREAD_PROCESS_PRIVATE
* Cannot be shared.
*
* DESCRIPTION
* Mutexes creatd with 'attr' can be shared between
* processes if pthread_barrier_t variable is allocated
* in memory shared by these processes.
*
* NOTES:
* 1) pshared barriers MUST be allocated in shared
* memory.
*
* 2) The following macro is defined if shared barriers
* are supported:
* _POSIX_THREAD_PROCESS_SHARED
*
* RESULTS
* 0 successfully set attribute,
* EINVAL 'attr' or pshared is invalid,
* ENOSYS PTHREAD_PROCESS_SHARED not supported,
*
* ------------------------------------------------------
*/
{
int result;
if ((attr != NULL && *attr != NULL) &&
((pshared == PTHREAD_PROCESS_SHARED) ||
(pshared == PTHREAD_PROCESS_PRIVATE)))
{
if (pshared == PTHREAD_PROCESS_SHARED)
{
#if !defined( _POSIX_THREAD_PROCESS_SHARED )
result = ENOSYS;
pshared = PTHREAD_PROCESS_PRIVATE;
#else
result = 0;
#endif /* _POSIX_THREAD_PROCESS_SHARED */
}
else
result = 0;
(*attr)->pshared = pshared;
}
else
result = EINVAL;
return (result);
} /* pthread_barrierattr_setpshared */
-807
View File
@@ -1,807 +0,0 @@
/*
* pthread_cond.c
*
* Description:
* This translation unit implements condition variables and their primitives.
*
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include "pthread.h"
#include "implement.h"
/*
* Arguments for cond_wait_cleanup, since we can only pass a
* single void * to it.
*/
typedef struct
{
pthread_mutex_t *mutexPtr;
pthread_cond_t cv;
int *resultPtr;
} pte_cond_wait_cleanup_args_t;
static void pte_cond_wait_cleanup (void *args)
{
pte_cond_wait_cleanup_args_t *cleanup_args =
(pte_cond_wait_cleanup_args_t *) args;
pthread_cond_t cv = cleanup_args->cv;
int *resultPtr = cleanup_args->resultPtr;
int nSignalsWasLeft;
int result;
/*
* Whether we got here as a result of signal/broadcast or because of
* timeout on wait or thread cancellation we indicate that we are no
* longer waiting. The waiter is responsible for adjusting waiters
* (to)unblock(ed) counts (protected by unblock lock).
*/
if ((result = pthread_mutex_lock (&(cv->mtxUnblockLock))) != 0)
{
*resultPtr = result;
return;
}
if (0 != (nSignalsWasLeft = cv->nWaitersToUnblock))
{
--(cv->nWaitersToUnblock);
}
else if (INT_MAX / 2 == ++(cv->nWaitersGone))
{
/* Use the non-cancellable version of sem_wait() */
// if (sem_wait_nocancel (&(cv->semBlockLock)) != 0)
if (sem_wait (&(cv->semBlockLock)) != 0)
{
*resultPtr = errno;
/*
* This is a fatal error for this CV,
* so we deliberately don't unlock
* cv->mtxUnblockLock before returning.
*/
return;
}
cv->nWaitersBlocked -= cv->nWaitersGone;
if (sem_post (&(cv->semBlockLock)) != 0)
{
*resultPtr = errno;
/*
* This is a fatal error for this CV,
* so we deliberately don't unlock
* cv->mtxUnblockLock before returning.
*/
return;
}
cv->nWaitersGone = 0;
}
if ((result = pthread_mutex_unlock (&(cv->mtxUnblockLock))) != 0)
{
*resultPtr = result;
return;
}
if (1 == nSignalsWasLeft)
{
if (sem_post (&(cv->semBlockLock)) != 0)
{
*resultPtr = errno;
return;
}
}
/*
* XSH: Upon successful return, the mutex has been locked and is owned
* by the calling thread.
*/
if ((result = pthread_mutex_lock (cleanup_args->mutexPtr)) != 0)
*resultPtr = result;
}
static int pte_cond_timedwait (pthread_cond_t * cond,
pthread_mutex_t * mutex, const struct timespec *abstime)
{
int result = 0;
pthread_cond_t cv;
pte_cond_wait_cleanup_args_t cleanup_args;
if (cond == NULL || *cond == NULL)
return EINVAL;
/*
* We do a quick check to see if we need to do more work
* to initialise a static condition variable. We check
* again inside the guarded section of pte_cond_check_need_init()
* to avoid race conditions.
*/
if (*cond == PTHREAD_COND_INITIALIZER)
result = pte_cond_check_need_init (cond);
if (result != 0 && result != EBUSY)
return result;
cv = *cond;
/* Thread can be cancelled in sem_wait() but this is OK */
if (sem_wait (&(cv->semBlockLock)) != 0)
return errno;
++(cv->nWaitersBlocked);
if (sem_post (&(cv->semBlockLock)) != 0)
return errno;
/*
* Setup this waiter cleanup handler
*/
cleanup_args.mutexPtr = mutex;
cleanup_args.cv = cv;
cleanup_args.resultPtr = &result;
pthread_cleanup_push (pte_cond_wait_cleanup, (void *) &cleanup_args);
/*
* Now we can release 'mutex' and...
*/
if ((result = pthread_mutex_unlock (mutex)) == 0)
{
/*
* ...wait to be awakened by
* pthread_cond_signal, or
* pthread_cond_broadcast, or
* timeout, or
* thread cancellation
*
* Note:
*
* sem_timedwait is a cancellation point,
* hence providing the mechanism for making
* pthread_cond_wait a cancellation point.
* We use the cleanup mechanism to ensure we
* re-lock the mutex and adjust (to)unblock(ed) waiters
* counts if we are cancelled, timed out or signalled.
*/
if (sem_timedwait (&(cv->semBlockQueue), abstime) != 0)
result = errno;
}
/*
* Always cleanup
*/
pthread_cleanup_pop (1);
/*
* "result" can be modified by the cleanup handler.
*/
return result;
}
int
pthread_cond_destroy (pthread_cond_t * cond)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function destroys a condition variable
*
*
* PARAMETERS
* cond
* pointer to an instance of pthread_cond_t
*
*
* DESCRIPTION
* This function destroys a condition variable.
*
* NOTES:
* 1) A condition variable can be destroyed
* immediately after all the threads that
* are blocked on it are awakened. e.g.
*
* struct list {
* pthread_mutex_t lm;
* ...
* }
*
* struct elt {
* key k;
* int busy;
* pthread_cond_t notbusy;
* ...
* }
*
*
* struct elt *
* list_find(struct list *lp, key k)
* {
* struct elt *ep;
*
* pthread_mutex_lock(&lp->lm);
* while ((ep = find_elt(l,k) != NULL) && ep->busy)
* pthread_cond_wait(&ep->notbusy, &lp->lm);
* if (ep != NULL)
* ep->busy = 1;
* pthread_mutex_unlock(&lp->lm);
* return(ep);
* }
*
* delete_elt(struct list *lp, struct elt *ep)
* {
* pthread_mutex_lock(&lp->lm);
* assert(ep->busy);
* ... remove ep from list ...
* ep->busy = 0;
* (A) pthread_cond_broadcast(&ep->notbusy);
* pthread_mutex_unlock(&lp->lm);
* (B) pthread_cond_destroy(&rp->notbusy);
* free(ep);
* }
*
* In this example, the condition variable
* and its list element may be freed (line B)
* immediately after all threads waiting for
* it are awakened (line A), since the mutex
* and the code ensure that no other thread
* can touch the element to be deleted.
*
* RESULTS
* 0 successfully released condition variable,
* EINVAL 'cond' is invalid,
* EBUSY 'cond' is in use,
*
* ------------------------------------------------------
*/
{
pthread_cond_t cv;
int result = 0, result1 = 0, result2 = 0;
/*
* Assuming any race condition here is harmless.
*/
if (cond == NULL || *cond == NULL)
return EINVAL;
if (*cond != PTHREAD_COND_INITIALIZER)
{
pte_osMutexLock (pte_cond_list_lock);
cv = *cond;
/*
* Close the gate; this will synchronize this thread with
* all already signaled waiters to let them retract their
* waiter status - SEE NOTE 1 ABOVE!!!
*/
if (sem_wait (&(cv->semBlockLock)) != 0)
return errno;
/*
* !TRY! lock mtxUnblockLock; try will detect busy condition
* and will not cause a deadlock with respect to concurrent
* signal/broadcast.
*/
if ((result = pthread_mutex_trylock (&(cv->mtxUnblockLock))) != 0)
{
(void) sem_post (&(cv->semBlockLock));
return result;
}
/*
* Check whether cv is still busy (still has waiters)
*/
if (cv->nWaitersBlocked > cv->nWaitersGone)
{
if (sem_post (&(cv->semBlockLock)) != 0)
result = errno;
result1 = pthread_mutex_unlock (&(cv->mtxUnblockLock));
result2 = EBUSY;
}
else
{
/*
* Now it is safe to destroy
*/
*cond = NULL;
if (sem_destroy (&(cv->semBlockLock)) != 0)
result = errno;
if (sem_destroy (&(cv->semBlockQueue)) != 0)
result1 = errno;
if ((result2 = pthread_mutex_unlock (&(cv->mtxUnblockLock))) == 0)
result2 = pthread_mutex_destroy (&(cv->mtxUnblockLock));
/* Unlink the CV from the list */
if (pte_cond_list_head == cv)
pte_cond_list_head = cv->next;
else
cv->prev->next = cv->next;
if (pte_cond_list_tail == cv)
pte_cond_list_tail = cv->prev;
else
cv->next->prev = cv->prev;
(void) free (cv);
}
pte_osMutexUnlock(pte_cond_list_lock);
}
else
{
/*
* See notes in pte_cond_check_need_init() above also.
*/
pte_osMutexLock (pte_cond_test_init_lock);
/*
* Check again.
*/
if (*cond == PTHREAD_COND_INITIALIZER)
{
/*
* This is all we need to do to destroy a statically
* initialised cond that has not yet been used (initialised).
* If we get to here, another thread waiting to initialise
* this cond will get an EINVAL. That's OK.
*/
*cond = NULL;
}
else
{
/*
* The cv has been initialised while we were waiting
* so assume it's in use.
*/
result = EBUSY;
}
pte_osMutexUnlock(pte_cond_test_init_lock);
}
return ((result != 0) ? result : ((result1 != 0) ? result1 : result2));
}
int pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function initializes a condition variable.
*
* PARAMETERS
* cond
* pointer to an instance of pthread_cond_t
*
* attr
* specifies optional creation attributes.
*
*
* DESCRIPTION
* This function initializes a condition variable.
*
* RESULTS
* 0 successfully created condition variable,
* EINVAL 'attr' is invalid,
* EAGAIN insufficient resources (other than
* memory,
* ENOMEM insufficient memory,
* EBUSY 'cond' is already initialized,
*
* ------------------------------------------------------
*/
{
int result;
pthread_cond_t cv = NULL;
if (cond == NULL)
return EINVAL;
if ((attr != NULL && *attr != NULL) &&
((*attr)->pshared == PTHREAD_PROCESS_SHARED))
{
/*
* Creating condition variable that can be shared between
* processes.
*/
result = ENOSYS;
goto DONE;
}
cv = (pthread_cond_t) calloc (1, sizeof (*cv));
if (cv == NULL)
{
result = ENOMEM;
goto DONE;
}
cv->nWaitersBlocked = 0;
cv->nWaitersToUnblock = 0;
cv->nWaitersGone = 0;
if (sem_init (&(cv->semBlockLock), 0, 1) != 0)
{
result = errno;
goto FAIL0;
}
if (sem_init (&(cv->semBlockQueue), 0, 0) != 0)
{
result = errno;
goto FAIL1;
}
if ((result = pthread_mutex_init (&(cv->mtxUnblockLock), 0)) != 0)
{
goto FAIL2;
}
result = 0;
goto DONE;
/*
* -------------
* Failed...
* -------------
*/
FAIL2:
(void) sem_destroy (&(cv->semBlockQueue));
FAIL1:
(void) sem_destroy (&(cv->semBlockLock));
FAIL0:
(void) free (cv);
cv = NULL;
DONE:
if (0 == result)
{
pte_osMutexLock (pte_cond_list_lock);
cv->next = NULL;
cv->prev = pte_cond_list_tail;
if (pte_cond_list_tail != NULL)
pte_cond_list_tail->next = cv;
pte_cond_list_tail = cv;
if (pte_cond_list_head == NULL)
pte_cond_list_head = cv;
pte_osMutexUnlock(pte_cond_list_lock);
}
*cond = cv;
return result;
}
static int pte_cond_unblock (pthread_cond_t * cond, int unblockAll)
/*
* Notes.
*
* Does not use the external mutex for synchronisation,
* therefore semBlockLock is needed.
* mtxUnblockLock is for LEVEL-2 synch. LEVEL-2 is the
* state where the external mutex is not necessarily locked by
* any thread, ie. between cond_wait unlocking and re-acquiring
* the lock after having been signaled or a timeout or
* cancellation.
*
* Uses the following CV elements:
* nWaitersBlocked
* nWaitersToUnblock
* nWaitersGone
* mtxUnblockLock
* semBlockLock
* semBlockQueue
*/
{
int result;
pthread_cond_t cv;
int nSignalsToIssue;
if (cond == NULL || *cond == NULL)
return EINVAL;
cv = *cond;
/*
* No-op if the CV is static and hasn't been initialised yet.
* Assuming that any race condition is harmless.
*/
if (cv == PTHREAD_COND_INITIALIZER)
return 0;
if ((result = pthread_mutex_lock (&(cv->mtxUnblockLock))) != 0)
return result;
if (0 != cv->nWaitersToUnblock)
{
if (0 == cv->nWaitersBlocked)
return pthread_mutex_unlock (&(cv->mtxUnblockLock));
if (unblockAll)
{
cv->nWaitersToUnblock += (nSignalsToIssue = cv->nWaitersBlocked);
cv->nWaitersBlocked = 0;
}
else
{
nSignalsToIssue = 1;
cv->nWaitersToUnblock++;
cv->nWaitersBlocked--;
}
}
else if (cv->nWaitersBlocked > cv->nWaitersGone)
{
/* Use the non-cancellable version of sem_wait() */
// if (sem_wait_nocancel (&(cv->semBlockLock)) != 0)
if (sem_wait (&(cv->semBlockLock)) != 0)
{
result = errno;
(void) pthread_mutex_unlock (&(cv->mtxUnblockLock));
return result;
}
if (0 != cv->nWaitersGone)
{
cv->nWaitersBlocked -= cv->nWaitersGone;
cv->nWaitersGone = 0;
}
if (unblockAll)
{
nSignalsToIssue = cv->nWaitersToUnblock = cv->nWaitersBlocked;
cv->nWaitersBlocked = 0;
}
else
{
nSignalsToIssue = cv->nWaitersToUnblock = 1;
cv->nWaitersBlocked--;
}
}
else
return pthread_mutex_unlock (&(cv->mtxUnblockLock));
if ((result = pthread_mutex_unlock (&(cv->mtxUnblockLock))) == 0)
{
if (sem_post_multiple (&(cv->semBlockQueue), nSignalsToIssue) != 0)
result = errno;
}
return result;
}
int pthread_cond_signal (pthread_cond_t * cond)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function signals a condition variable, waking
* one waiting thread.
* If SCHED_FIFO or SCHED_RR policy threads are waiting
* the highest priority waiter is awakened; otherwise,
* an unspecified waiter is awakened.
*
* PARAMETERS
* cond
* pointer to an instance of pthread_cond_t
*
*
* DESCRIPTION
* This function signals a condition variable, waking
* one waiting thread.
* If SCHED_FIFO or SCHED_RR policy threads are waiting
* the highest priority waiter is awakened; otherwise,
* an unspecified waiter is awakened.
*
* NOTES:
*
* 1) Use when any waiter can respond and only one need
* respond (all waiters being equal).
*
* RESULTS
* 0 successfully signaled condition,
* EINVAL 'cond' is invalid,
*
* ------------------------------------------------------
*/
{
/*
* The '0'(FALSE) unblockAll arg means unblock ONE waiter.
*/
return (pte_cond_unblock (cond, 0));
} /* pthread_cond_signal */
int
pthread_cond_broadcast (pthread_cond_t * cond)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function broadcasts the condition variable,
* waking all current waiters.
*
* PARAMETERS
* cond
* pointer to an instance of pthread_cond_t
*
*
* DESCRIPTION
* This function signals a condition variable, waking
* all waiting threads.
*
* NOTES:
*
* 1) Use when more than one waiter may respond to
* predicate change or if any waiting thread may
* not be able to respond
*
* RESULTS
* 0 successfully signalled condition to all
* waiting threads,
* EINVAL 'cond' is invalid
* ENOSPC a required resource has been exhausted,
*
* ------------------------------------------------------
*/
{
/*
* The TRUE unblockAll arg means unblock ALL waiters.
*/
return (pte_cond_unblock (cond, PTE_TRUE));
}
int pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function waits on a condition variable until
* awakened by a signal or broadcast.
*
* Caller MUST be holding the mutex lock; the
* lock is released and the caller is blocked waiting
* on 'cond'. When 'cond' is signaled, the mutex
* is re-acquired before returning to the caller.
*
* PARAMETERS
* cond
* pointer to an instance of pthread_cond_t
*
* mutex
* pointer to an instance of pthread_mutex_t
*
*
* DESCRIPTION
* This function waits on a condition variable until
* awakened by a signal or broadcast.
*
* NOTES:
*
* 1) The function must be called with 'mutex' LOCKED
* by the calling thread, or undefined behaviour
* will result.
*
* 2) This routine atomically releases 'mutex' and causes
* the calling thread to block on the condition variable.
* The blocked thread may be awakened by
* pthread_cond_signal or
* pthread_cond_broadcast.
*
* Upon successful completion, the 'mutex' has been locked and
* is owned by the calling thread.
*
*
* RESULTS
* 0 caught condition; mutex released,
* EINVAL 'cond' or 'mutex' is invalid,
* EINVAL different mutexes for concurrent waits,
* EINVAL mutex is not held by the calling thread,
*
* ------------------------------------------------------
*/
{
/*
* The NULL abstime arg means INFINITE waiting.
*/
return (pte_cond_timedwait (cond, mutex, NULL));
} /* pthread_cond_wait */
int
pthread_cond_timedwait (pthread_cond_t * cond,
pthread_mutex_t * mutex,
const struct timespec *abstime)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function waits on a condition variable either until
* awakened by a signal or broadcast; or until the time
* specified by abstime passes.
*
* PARAMETERS
* cond
* pointer to an instance of pthread_cond_t
*
* mutex
* pointer to an instance of pthread_mutex_t
*
* abstime
* pointer to an instance of (const struct timespec)
*
*
* DESCRIPTION
* This function waits on a condition variable either until
* awakened by a signal or broadcast; or until the time
* specified by abstime passes.
*
* NOTES:
* 1) The function must be called with 'mutex' LOCKED
* by the calling thread, or undefined behaviour
* will result.
*
* 2) This routine atomically releases 'mutex' and causes
* the calling thread to block on the condition variable.
* The blocked thread may be awakened by
* pthread_cond_signal or
* pthread_cond_broadcast.
*
*
* RESULTS
* 0 caught condition; mutex released,
* EINVAL 'cond', 'mutex', or abstime is invalid,
* EINVAL different mutexes for concurrent waits,
* EINVAL mutex is not held by the calling thread,
* ETIMEDOUT abstime ellapsed before cond was signaled.
*
* ------------------------------------------------------
*/
{
if (abstime == NULL)
{
return EINVAL;
}
return (pte_cond_timedwait (cond, mutex, abstime));
}
-259
View File
@@ -1,259 +0,0 @@
/*
* condvar_attr_destroy.c
*
* Description:
* This translation unit implements condition variables and their primitives.
*
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include "pthread.h"
#include "implement.h"
int
pthread_condattr_destroy (pthread_condattr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Destroys a condition variable attributes object.
* The object can no longer be used.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_condattr_t
*
*
* DESCRIPTION
* Destroys a condition variable attributes object.
* The object can no longer be used.
*
* NOTES:
* 1) Does not affect condition variables created
* using 'attr'
*
* RESULTS
* 0 successfully released attr,
* EINVAL 'attr' is invalid.
*
* ------------------------------------------------------
*/
{
int result = 0;
if (attr == NULL || *attr == NULL)
result = EINVAL;
else
{
(void) free (*attr);
*attr = NULL;
result = 0;
}
return result;
}
int pthread_condattr_getpshared (const pthread_condattr_t * attr, int *pshared)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Determine whether condition variables created with 'attr'
* can be shared between processes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_condattr_t
*
* pshared
* will be set to one of:
*
* PTHREAD_PROCESS_SHARED
* May be shared if in shared memory
*
* PTHREAD_PROCESS_PRIVATE
* Cannot be shared.
*
*
* DESCRIPTION
* Condition Variables created with 'attr' can be shared
* between processes if pthread_cond_t variable is allocated
* in memory shared by these processes.
* NOTES:
* 1) pshared condition variables MUST be allocated in
* shared memory.
*
* 2) The following macro is defined if shared mutexes
* are supported:
* _POSIX_THREAD_PROCESS_SHARED
*
* RESULTS
* 0 successfully retrieved attribute,
* EINVAL 'attr' or 'pshared' is invalid,
*
* ------------------------------------------------------
*/
{
int result;
if ((attr != NULL && *attr != NULL) && (pshared != NULL))
{
*pshared = (*attr)->pshared;
result = 0;
}
else
result = EINVAL;
return result;
}
int pthread_condattr_init (pthread_condattr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Initializes a condition variable attributes object
* with default attributes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_condattr_t
*
*
* DESCRIPTION
* Initializes a condition variable attributes object
* with default attributes.
*
* NOTES:
* 1) Use to define condition variable types
* 2) It is up to the application to ensure
* that it doesn't re-init an attribute
* without destroying it first. Otherwise
* a memory leak is created.
*
* RESULTS
* 0 successfully initialized attr,
* ENOMEM insufficient memory for attr.
*
* ------------------------------------------------------
*/
{
pthread_condattr_t attr_result;
int result = 0;
attr_result = (pthread_condattr_t) calloc (1, sizeof (*attr_result));
if (attr_result == NULL)
result = ENOMEM;
*attr = attr_result;
return result;
}
int pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Mutexes created with 'attr' can be shared between
* processes if pthread_mutex_t variable is allocated
* in memory shared by these processes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_mutexattr_t
*
* pshared
* must be one of:
*
* PTHREAD_PROCESS_SHARED
* May be shared if in shared memory
*
* PTHREAD_PROCESS_PRIVATE
* Cannot be shared.
*
* DESCRIPTION
* Mutexes creatd with 'attr' can be shared between
* processes if pthread_mutex_t variable is allocated
* in memory shared by these processes.
*
* NOTES:
* 1) pshared mutexes MUST be allocated in shared
* memory.
*
* 2) The following macro is defined if shared mutexes
* are supported:
* _POSIX_THREAD_PROCESS_SHARED
*
* RESULTS
* 0 successfully set attribute,
* EINVAL 'attr' or pshared is invalid,
* ENOSYS PTHREAD_PROCESS_SHARED not supported,
*
* ------------------------------------------------------
*/
{
int result;
if ((attr != NULL && *attr != NULL)
&& ((pshared == PTHREAD_PROCESS_SHARED)
|| (pshared == PTHREAD_PROCESS_PRIVATE)))
{
if (pshared == PTHREAD_PROCESS_SHARED)
{
#if !defined( _POSIX_THREAD_PROCESS_SHARED )
result = ENOSYS;
pshared = PTHREAD_PROCESS_PRIVATE;
#else
result = 0;
#endif /* _POSIX_THREAD_PROCESS_SHARED */
}
else
result = 0;
(*attr)->pshared = pshared;
}
else
result = EINVAL;
return result;
}
-111
View File
@@ -1,111 +0,0 @@
/*
* pthread_get.c
*
* Description:
* This translation unit implements miscellaneous thread functions.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include "pthread.h"
#include "implement.h"
#include "sched.h"
int pthread_getconcurrency (void)
{
return pte_concurrency;
}
int pthread_getschedparam (pthread_t thread, int *policy,
struct sched_param *param)
{
int result;
/* Validate the thread id. */
result = pthread_kill (thread, 0);
if (0 != result)
return result;
/*
* Validate the policy and param args.
* Check that a policy constant wasn't passed rather than &policy.
*/
if (policy <= (int *) SCHED_MAX || param == NULL)
return EINVAL;
/* Fill out the policy. */
*policy = SCHED_OTHER;
/*
* This function must return the priority value set by
* the most recent pthread_setschedparam() or pthread_create()
* for the target thread. It must not return the actual thread
* priority as altered by any system priority adjustments etc.
*/
param->sched_priority = ((pte_thread_t *)thread)->sched_priority;
return 0;
}
void *pthread_getspecific (pthread_key_t key)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function returns the current value of key in the
* calling thread. If no value has been set for 'key' in
* the thread, NULL is returned.
*
* PARAMETERS
* key
* an instance of pthread_key_t
*
*
* DESCRIPTION
* This function returns the current value of key in the
* calling thread. If no value has been set for 'key' in
* the thread, NULL is returned.
*
* RESULTS
* key value or NULL on failure
*
* ------------------------------------------------------
*/
{
if (key == NULL)
return NULL;
return pte_osTlsGetValue (key->key);
}
-204
View File
@@ -1,204 +0,0 @@
/*
* pthread_key.c
*
* Description:
* POSIX thread functions which implement thread-specific data (TSD).
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include "pte_osal.h"
#include "pthread.h"
#include "implement.h"
int
pthread_key_create (pthread_key_t * key, void (*destructor) (void *))
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function creates a thread-specific data key visible
* to all threads. All existing and new threads have a value
* NULL for key until set using pthread_setspecific. When any
* thread with a non-NULL value for key terminates, 'destructor'
* is called with key's current value for that thread.
*
* PARAMETERS
* key
* pointer to an instance of pthread_key_t
*
*
* DESCRIPTION
* This function creates a thread-specific data key visible
* to all threads. All existing and new threads have a value
* NULL for key until set using pthread_setspecific. When any
* thread with a non-NULL value for key terminates, 'destructor'
* is called with key's current value for that thread.
*
* RESULTS
* 0 successfully created semaphore,
* EAGAIN insufficient resources or PTHREAD_KEYS_MAX
* exceeded,
* ENOMEM insufficient memory to create the key,
*
* ------------------------------------------------------
*/
{
int result = 0;
pthread_key_t newkey;
if ((newkey = (pthread_key_t) calloc (1, sizeof (*newkey))) == NULL)
result = ENOMEM;
else
{
pte_osResult osResult = pte_osTlsAlloc(&(newkey->key));
if (osResult != PTE_OS_OK)
{
result = EAGAIN;
free (newkey);
newkey = NULL;
}
else if (destructor != NULL)
{
/*
* Have to manage associations between thread and key;
* Therefore, need a lock that allows multiple threads
* to gain exclusive access to the key->threads list.
*
* The mutex will only be created when it is first locked.
*/
newkey->keyLock = PTHREAD_MUTEX_INITIALIZER;
newkey->destructor = destructor;
}
}
*key = newkey;
return (result);
}
int pthread_key_delete (pthread_key_t key)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function deletes a thread-specific data key. This
* does not change the value of the thread specific data key
* for any thread and does not run the key's destructor
* in any thread so it should be used with caution.
*
* PARAMETERS
* key
* pointer to an instance of pthread_key_t
*
*
* DESCRIPTION
* This function deletes a thread-specific data key. This
* does not change the value of the thread specific data key
* for any thread and does not run the key's destructor
* in any thread so it should be used with caution.
*
* RESULTS
* 0 successfully deleted the key,
* EINVAL key is invalid,
*
* ------------------------------------------------------
*/
{
int result = 0;
if (key != NULL)
{
if (key->threads != NULL &&
key->destructor != NULL &&
pthread_mutex_lock (&(key->keyLock)) == 0)
{
ThreadKeyAssoc *assoc;
/*
* Run through all Thread<-->Key associations
* for this key.
*
* While we hold at least one of the locks guarding
* the assoc, we know that the assoc pointed to by
* key->threads is valid.
*/
while ((assoc = (ThreadKeyAssoc *) key->threads) != NULL)
{
pte_thread_t * thread = assoc->thread;
/* Finished */
if (assoc == NULL)
break;
if (pthread_mutex_lock (&(thread->threadLock)) == 0)
{
/*
* Since we are starting at the head of the key's threads
* chain, this will also point key->threads at the next assoc.
* While we hold key->keyLock, no other thread can insert
* a new assoc via pthread_setspecific.
*/
pte_tkAssocDestroy (assoc);
(void) pthread_mutex_unlock (&(thread->threadLock));
}
else
{
/* Thread or lock is no longer valid? */
pte_tkAssocDestroy (assoc);
}
}
pthread_mutex_unlock (&(key->keyLock));
}
pte_osTlsFree (key->key);
if (key->destructor != NULL)
{
/* A thread could be holding the keyLock */
while (EBUSY == (result = pthread_mutex_destroy (&(key->keyLock))))
pte_osThreadSleep(1); /* Ugly. */
}
free (key);
}
return (result);
}
-500
View File
@@ -1,500 +0,0 @@
/*
* pthread_mutex.c
*
* Description:
* This translation unit implements mutual exclusion (mutex) primitives.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pte_osal.h>
#include "pthread.h"
#include "implement.h"
#define TEST_IE InterlockedExchange
int pthread_mutex_destroy (pthread_mutex_t * mutex)
{
int result = 0;
pthread_mutex_t mx;
/*
* Let the system deal with invalid pointers.
*/
/*
* Check to see if we have something to delete.
*/
if (*mutex < PTHREAD_ERRORCHECK_MUTEX_INITIALIZER)
{
mx = *mutex;
result = pthread_mutex_trylock (&mx);
/*
* If trylock succeeded and the mutex is not recursively locked it
* can be destroyed.
*/
if (result == 0)
{
if (mx->kind != PTHREAD_MUTEX_RECURSIVE || 1 == mx->recursive_count)
{
/*
* FIXME!!!
* The mutex isn't held by another thread but we could still
* be too late invalidating the mutex below since another thread
* may already have entered mutex_lock and the check for a valid
* *mutex != NULL.
*
* Note that this would be an unusual situation because it is not
* common that mutexes are destroyed while they are still in
* use by other threads.
*/
*mutex = NULL;
result = pthread_mutex_unlock (&mx);
if (result == 0)
{
pte_osSemaphoreDelete(mx->handle);
free(mx);
}
else
{
/*
* Restore the mutex before we return the error.
*/
*mutex = mx;
}
}
else /* mx->recursive_count > 1 */
{
/*
* The mutex must be recursive and already locked by us (this thread).
*/
mx->recursive_count--; /* Undo effect of pthread_mutex_trylock() above */
result = EBUSY;
}
}
}
else
{
/*
* See notes in pte_mutex_check_need_init() above also.
*/
pte_osMutexLock (pte_mutex_test_init_lock);
/*
* Check again.
*/
if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER)
{
/*
* This is all we need to do to destroy a statically
* initialised mutex that has not yet been used (initialised).
* If we get to here, another thread
* waiting to initialise this mutex will get an EINVAL.
*/
*mutex = NULL;
}
else
{
/*
* The mutex has been initialised while we were waiting
* so assume it's in use.
*/
result = EBUSY;
}
pte_osMutexUnlock(pte_mutex_test_init_lock);
}
return (result);
}
int pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t * attr)
{
int result = 0;
pthread_mutex_t mx;
if (mutex == NULL)
return EINVAL;
mx = (pthread_mutex_t) calloc (1, sizeof (*mx));
if (mx == NULL)
result = ENOMEM;
else
{
mx->lock_idx = 0;
mx->recursive_count = 0;
mx->kind = (attr == NULL || *attr == NULL
? PTHREAD_MUTEX_DEFAULT : (*attr)->kind);
mx->ownerThread = NULL;
pte_osSemaphoreCreate(0,&mx->handle);
}
*mutex = mx;
return (result);
}
int pthread_mutex_lock (pthread_mutex_t * mutex)
{
int result = 0;
pthread_mutex_t mx;
/*
* Let the system deal with invalid pointers.
*/
if (*mutex == NULL)
return EINVAL;
/*
* We do a quick check to see if we need to do more work
* to initialise a static mutex. We check
* again inside the guarded section of pte_mutex_check_need_init()
* to avoid race conditions.
*/
if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER)
{
if ((result = pte_mutex_check_need_init (mutex)) != 0)
return (result);
}
mx = *mutex;
if (mx->kind == PTHREAD_MUTEX_NORMAL)
{
if (PTE_ATOMIC_EXCHANGE(
&mx->lock_idx,
1) != 0)
{
while (PTE_ATOMIC_EXCHANGE(&mx->lock_idx,-1) != 0)
{
if (pte_osSemaphorePend(mx->handle,NULL) != PTE_OS_OK)
{
result = EINVAL;
break;
}
}
}
}
else
{
pthread_t self = pthread_self();
if (PTE_ATOMIC_COMPARE_EXCHANGE(&mx->lock_idx,1,0) == 0)
{
mx->recursive_count = 1;
mx->ownerThread = self;
}
else
{
if (pthread_equal (mx->ownerThread, self))
{
if (mx->kind == PTHREAD_MUTEX_RECURSIVE)
mx->recursive_count++;
else
result = EDEADLK;
}
else
{
while (PTE_ATOMIC_EXCHANGE(&mx->lock_idx,-1) != 0)
{
if (pte_osSemaphorePend(mx->handle,NULL) != PTE_OS_OK)
{
result = EINVAL;
break;
}
}
if (0 == result)
{
mx->recursive_count = 1;
mx->ownerThread = self;
}
}
}
}
return (result);
}
static int pte_timed_eventwait (pte_osSemaphoreHandle event, const struct timespec *abstime)
/*
* ------------------------------------------------------
* DESCRIPTION
* This function waits on an event until signaled or until
* abstime passes.
* If abstime has passed when this routine is called then
* it returns a result to indicate this.
*
* If 'abstime' is a NULL pointer then this function will
* block until it can successfully decrease the value or
* until interrupted by a signal.
*
* This routine is not a cancelation point.
*
* RESULTS
* 0 successfully signaled,
* ETIMEDOUT abstime passed
* EINVAL 'event' is not a valid event,
*
* ------------------------------------------------------
*/
{
unsigned int milliseconds;
pte_osResult status;
int retval;
if (abstime == NULL)
status = pte_osSemaphorePend(event, NULL);
else
{
/*
* Calculate timeout as milliseconds from current system time.
*/
milliseconds = pte_relmillisecs (abstime);
status = pte_osSemaphorePend(event, &milliseconds);
}
if (status == PTE_OS_TIMEOUT)
{
retval = ETIMEDOUT;
}
else
{
retval = 0;
}
return retval;
}
int pthread_mutex_timedlock (pthread_mutex_t * mutex,
const struct timespec *abstime)
{
int result;
pthread_mutex_t mx;
/*
* Let the system deal with invalid pointers.
*/
/*
* We do a quick check to see if we need to do more work
* to initialise a static mutex. We check
* again inside the guarded section of pte_mutex_check_need_init()
* to avoid race conditions.
*/
if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER)
{
if ((result = pte_mutex_check_need_init (mutex)) != 0)
return (result);
}
mx = *mutex;
if (mx->kind == PTHREAD_MUTEX_NORMAL)
{
if (PTE_ATOMIC_EXCHANGE(&mx->lock_idx,1) != 0)
{
while (PTE_ATOMIC_EXCHANGE(&mx->lock_idx,-1) != 0)
{
if (0 != (result = pte_timed_eventwait (mx->handle, abstime)))
return result;
}
}
}
else
{
pthread_t self = pthread_self();
if (PTE_ATOMIC_COMPARE_EXCHANGE(&mx->lock_idx,1,0) == 0)
{
mx->recursive_count = 1;
mx->ownerThread = self;
}
else
{
if (pthread_equal (mx->ownerThread, self))
{
if (mx->kind == PTHREAD_MUTEX_RECURSIVE)
mx->recursive_count++;
else
return EDEADLK;
}
else
{
while (PTE_ATOMIC_EXCHANGE(&mx->lock_idx,-1) != 0)
{
if (0 != (result = pte_timed_eventwait (mx->handle, abstime)))
return result;
}
mx->recursive_count = 1;
mx->ownerThread = self;
}
}
}
return 0;
}
int pthread_mutex_trylock (pthread_mutex_t * mutex)
{
int result = 0;
pthread_mutex_t mx;
/*
* Let the system deal with invalid pointers.
*/
/*
* We do a quick check to see if we need to do more work
* to initialise a static mutex. We check
* again inside the guarded section of pte_mutex_check_need_init()
* to avoid race conditions.
*/
if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER)
{
if ((result = pte_mutex_check_need_init (mutex)) != 0)
return (result);
}
mx = *mutex;
if (0 == PTE_ATOMIC_COMPARE_EXCHANGE (&mx->lock_idx,1,0))
{
if (mx->kind != PTHREAD_MUTEX_NORMAL)
{
mx->recursive_count = 1;
mx->ownerThread = pthread_self ();
}
}
else
{
if (mx->kind == PTHREAD_MUTEX_RECURSIVE &&
pthread_equal (mx->ownerThread, pthread_self ()))
mx->recursive_count++;
else
result = EBUSY;
}
return (result);
}
int pthread_mutex_unlock (pthread_mutex_t * mutex)
{
int result = 0;
pthread_mutex_t mx = *mutex;
/*
* Let the system deal with invalid pointers.
*/
/*
* If the thread calling us holds the mutex then there is no
* race condition. If another thread holds the
* lock then we shouldn't be in here.
*/
if (mx < PTHREAD_ERRORCHECK_MUTEX_INITIALIZER)
{
if (mx->kind == PTHREAD_MUTEX_NORMAL)
{
int idx;
idx = PTE_ATOMIC_EXCHANGE (&mx->lock_idx,0);
if (idx != 0)
{
if (idx < 0)
{
/*
* Someone may be waiting on that mutex.
*/
if (pte_osSemaphorePost(mx->handle,1) != PTE_OS_OK)
result = EINVAL;
}
}
else
{
/*
* Was not locked (so can't be owned by us).
*/
result = EPERM;
}
}
else
{
if (pthread_equal (mx->ownerThread, pthread_self ()))
{
if (mx->kind != PTHREAD_MUTEX_RECURSIVE
|| 0 == --mx->recursive_count)
{
mx->ownerThread = NULL;
if (PTE_ATOMIC_EXCHANGE (&mx->lock_idx,0) < 0)
{
if (pte_osSemaphorePost(mx->handle,1) != PTE_OS_OK)
result = EINVAL;
}
}
}
else
result = EPERM;
}
}
else
result = EINVAL;
return (result);
}
-377
View File
@@ -1,377 +0,0 @@
/*
* pthread_mutexattr.c
*
* Description:
* This translation unit implements mutual exclusion (mutex) primitives.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include "pthread.h"
#include "implement.h"
int pthread_mutexattr_destroy (pthread_mutexattr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Destroys a mutex attributes object. The object can
* no longer be used.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_mutexattr_t
*
*
* DESCRIPTION
* Destroys a mutex attributes object. The object can
* no longer be used.
*
* NOTES:
* 1) Does not affect mutexes created using 'attr'
*
* RESULTS
* 0 successfully released attr,
* EINVAL 'attr' is invalid.
*
* ------------------------------------------------------
*/
{
int result = 0;
if (attr == NULL || *attr == NULL)
result = EINVAL;
else
{
pthread_mutexattr_t ma = *attr;
*attr = NULL;
free (ma);
}
return (result);
}
int pthread_mutexattr_getkind_np (pthread_mutexattr_t * attr, int *kind)
{
return pthread_mutexattr_gettype (attr, kind);
}
int pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind)
{
int result = 0;
if (attr != NULL && *attr != NULL && kind != NULL)
*kind = (*attr)->kind;
else
result = EINVAL;
return (result);
}
int pthread_mutexattr_getpshared (const pthread_mutexattr_t * attr, int *pshared)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Determine whether mutexes created with 'attr' can be
* shared between processes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_mutexattr_t
*
* pshared
* will be set to one of:
*
* PTHREAD_PROCESS_SHARED
* May be shared if in shared memory
*
* PTHREAD_PROCESS_PRIVATE
* Cannot be shared.
*
*
* DESCRIPTION
* Mutexes creatd with 'attr' can be shared between
* processes if pthread_mutex_t variable is allocated
* in memory shared by these processes.
* NOTES:
* 1) pshared mutexes MUST be allocated in shared
* memory.
* 2) The following macro is defined if shared mutexes
* are supported:
* _POSIX_THREAD_PROCESS_SHARED
*
* RESULTS
* 0 successfully retrieved attribute,
* EINVAL 'attr' is invalid,
*
* ------------------------------------------------------
*/
{
int result;
if ((attr != NULL && *attr != NULL) && (pshared != NULL))
{
*pshared = (*attr)->pshared;
result = 0;
}
else
result = EINVAL;
return (result);
}
int pthread_mutexattr_init (pthread_mutexattr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Initializes a mutex attributes object with default
* attributes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_mutexattr_t
*
*
* DESCRIPTION
* Initializes a mutex attributes object with default
* attributes.
*
* NOTES:
* 1) Used to define mutex types
*
* RESULTS
* 0 successfully initialized attr,
* ENOMEM insufficient memory for attr.
*
* ------------------------------------------------------
*/
{
int result = 0;
pthread_mutexattr_t ma = (pthread_mutexattr_t) calloc (1, sizeof (*ma));
if (ma == NULL)
result = ENOMEM;
else
{
ma->pshared = PTHREAD_PROCESS_PRIVATE;
ma->kind = PTHREAD_MUTEX_DEFAULT;
}
*attr = ma;
return (result);
}
int pthread_mutexattr_setkind_np (pthread_mutexattr_t * attr, int kind)
{
return pthread_mutexattr_settype (attr, kind);
}
int pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, int pshared)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Mutexes created with 'attr' can be shared between
* processes if pthread_mutex_t variable is allocated
* in memory shared by these processes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_mutexattr_t
*
* pshared
* must be one of:
*
* PTHREAD_PROCESS_SHARED
* May be shared if in shared memory
*
* PTHREAD_PROCESS_PRIVATE
* Cannot be shared.
*
* DESCRIPTION
* Mutexes creatd with 'attr' can be shared between
* processes if pthread_mutex_t variable is allocated
* in memory shared by these processes.
*
* NOTES:
* 1) pshared mutexes MUST be allocated in shared
* memory.
*
* 2) The following macro is defined if shared mutexes
* are supported:
* _POSIX_THREAD_PROCESS_SHARED
*
* RESULTS
* 0 successfully set attribute,
* EINVAL 'attr' or pshared is invalid,
* ENOSYS PTHREAD_PROCESS_SHARED not supported,
*
* ------------------------------------------------------
*/
{
int result;
if ((attr != NULL && *attr != NULL) &&
((pshared == PTHREAD_PROCESS_SHARED) ||
(pshared == PTHREAD_PROCESS_PRIVATE)))
{
if (pshared == PTHREAD_PROCESS_SHARED)
{
#if !defined( _POSIX_THREAD_PROCESS_SHARED )
result = ENOSYS;
pshared = PTHREAD_PROCESS_PRIVATE;
#else
result = 0;
#endif /* _POSIX_THREAD_PROCESS_SHARED */
}
else
result = 0;
(*attr)->pshared = pshared;
}
else
result = EINVAL;
return (result);
}
int pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind)
/*
* ------------------------------------------------------
*
* DOCPUBLIC
* The pthread_mutexattr_settype() and
* pthread_mutexattr_gettype() functions respectively set and
* get the mutex type attribute. This attribute is set in the
* type parameter to these functions.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_mutexattr_t
*
* type
* must be one of:
*
* PTHREAD_MUTEX_DEFAULT
*
* PTHREAD_MUTEX_NORMAL
*
* PTHREAD_MUTEX_ERRORCHECK
*
* PTHREAD_MUTEX_RECURSIVE
*
* DESCRIPTION
* The pthread_mutexattr_settype() and
* pthread_mutexattr_gettype() functions respectively set and
* get the mutex type attribute. This attribute is set in the
* type parameter to these functions. The default value of the
* type attribute is PTHREAD_MUTEX_DEFAULT.
*
* The type of mutex is contained in the type attribute of the
* mutex attributes. Valid mutex types include:
*
* PTHREAD_MUTEX_NORMAL
* This type of mutex does not detect deadlock. A
* thread attempting to relock this mutex without
* first unlocking it will deadlock. Attempting to
* unlock a mutex locked by a different thread
* results in undefined behavior. Attempting to
* unlock an unlocked mutex results in undefined
* behavior.
*
* PTHREAD_MUTEX_ERRORCHECK
* This type of mutex provides error checking. A
* thread attempting to relock this mutex without
* first unlocking it will return with an error. A
* thread attempting to unlock a mutex which another
* thread has locked will return with an error. A
* thread attempting to unlock an unlocked mutex will
* return with an error.
*
* PTHREAD_MUTEX_DEFAULT
* Same as PTHREAD_MUTEX_NORMAL.
*
* PTHREAD_MUTEX_RECURSIVE
* A thread attempting to relock this mutex without
* first unlocking it will succeed in locking the
* mutex. The relocking deadlock which can occur with
* mutexes of type PTHREAD_MUTEX_NORMAL cannot occur
* with this type of mutex. Multiple locks of this
* mutex require the same number of unlocks to
* release the mutex before another thread can
* acquire the mutex. A thread attempting to unlock a
* mutex which another thread has locked will return
* with an error. A thread attempting to unlock an
* unlocked mutex will return with an error. This
* type of mutex is only supported for mutexes whose
* process shared attribute is
* PTHREAD_PROCESS_PRIVATE.
*
* RESULTS
* 0 successfully set attribute,
* EINVAL 'attr' or 'type' is invalid,
*
* ------------------------------------------------------
*/
{
int result = 0;
if ((attr != NULL && *attr != NULL))
{
switch (kind)
{
case PTHREAD_MUTEX_FAST_NP:
case PTHREAD_MUTEX_RECURSIVE_NP:
case PTHREAD_MUTEX_ERRORCHECK_NP:
(*attr)->kind = kind;
break;
default:
result = EINVAL;
break;
}
}
else
result = EINVAL;
return (result);
}
-676
View File
@@ -1,676 +0,0 @@
/*
* pthread_rwlock.c
*
* Description:
* This translation unit implements read/write lock primitives.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include "pthread.h"
#include "implement.h"
int pthread_rwlock_destroy (pthread_rwlock_t * rwlock)
{
pthread_rwlock_t rwl;
int result = 0, result1 = 0, result2 = 0;
if (rwlock == NULL || *rwlock == NULL)
return EINVAL;
if (*rwlock != PTHREAD_RWLOCK_INITIALIZER)
{
rwl = *rwlock;
if (rwl->nMagic != PTE_RWLOCK_MAGIC)
return EINVAL;
if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0)
return result;
if ((result =
pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
/*
* Check whether any threads own/wait for the lock (wait for ex.access);
* report "BUSY" if so.
*/
if (rwl->nExclusiveAccessCount > 0
|| rwl->nSharedAccessCount > rwl->nCompletedSharedAccessCount)
{
result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted));
result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
result2 = EBUSY;
}
else
{
rwl->nMagic = 0;
if ((result =
pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
pthread_mutex_unlock (&rwl->mtxExclusiveAccess);
return result;
}
if ((result =
pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))) != 0)
return result;
*rwlock = NULL; /* Invalidate rwlock before anything else */
result = pthread_cond_destroy (&(rwl->cndSharedAccessCompleted));
result1 = pthread_mutex_destroy (&(rwl->mtxSharedAccessCompleted));
result2 = pthread_mutex_destroy (&(rwl->mtxExclusiveAccess));
(void) free (rwl);
}
}
else
{
/*
* See notes in pte_rwlock_check_need_init() above also.
*/
pte_osMutexLock (pte_rwlock_test_init_lock);
/*
* Check again.
*/
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
{
/*
* This is all we need to do to destroy a statically
* initialised rwlock that has not yet been used (initialised).
* If we get to here, another thread
* waiting to initialise this rwlock will get an EINVAL.
*/
*rwlock = NULL;
}
/*
* The rwlock has been initialised while we were waiting
* so assume it's in use.
*/
else
result = EBUSY;
pte_osMutexUnlock(pte_rwlock_test_init_lock);
}
return ((result != 0) ? result : ((result1 != 0) ? result1 : result2));
}
int pthread_rwlock_init (pthread_rwlock_t * rwlock,
const pthread_rwlockattr_t * attr)
{
int result;
pthread_rwlock_t rwl = 0;
if (rwlock == NULL)
return EINVAL;
if (attr != NULL && *attr != NULL)
{
result = EINVAL; /* Not supported */
goto DONE;
}
rwl = (pthread_rwlock_t) calloc (1, sizeof (*rwl));
if (rwl == NULL)
{
result = ENOMEM;
goto DONE;
}
rwl->nSharedAccessCount = 0;
rwl->nExclusiveAccessCount = 0;
rwl->nCompletedSharedAccessCount = 0;
result = pthread_mutex_init (&rwl->mtxExclusiveAccess, NULL);
if (result != 0)
{
goto FAIL0;
}
result = pthread_mutex_init (&rwl->mtxSharedAccessCompleted, NULL);
if (result != 0)
{
goto FAIL1;
}
result = pthread_cond_init (&rwl->cndSharedAccessCompleted, NULL);
if (result != 0)
{
goto FAIL2;
}
rwl->nMagic = PTE_RWLOCK_MAGIC;
result = 0;
goto DONE;
FAIL2:
(void) pthread_mutex_destroy (&(rwl->mtxSharedAccessCompleted));
FAIL1:
(void) pthread_mutex_destroy (&(rwl->mtxExclusiveAccess));
FAIL0:
(void) free (rwl);
rwl = NULL;
DONE:
*rwlock = rwl;
return result;
}
int pthread_rwlock_rdlock (pthread_rwlock_t * rwlock)
{
int result;
pthread_rwlock_t rwl;
if (rwlock == NULL || *rwlock == NULL)
return EINVAL;
/*
* We do a quick check to see if we need to do more work
* to initialise a static rwlock. We check
* again inside the guarded section of pte_rwlock_check_need_init()
* to avoid race conditions.
*/
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
{
result = pte_rwlock_check_need_init (rwlock);
if (result != 0 && result != EBUSY)
return result;
}
rwl = *rwlock;
if (rwl->nMagic != PTE_RWLOCK_MAGIC)
return EINVAL;
if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0)
return result;
if (++rwl->nSharedAccessCount == INT_MAX)
{
if ((result =
pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount;
rwl->nCompletedSharedAccessCount = 0;
if ((result =
pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
}
return (pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)));
}
int pthread_rwlock_timedrdlock (pthread_rwlock_t * rwlock,
const struct timespec *abstime)
{
int result;
pthread_rwlock_t rwl;
if (rwlock == NULL || *rwlock == NULL)
return EINVAL;
/*
* We do a quick check to see if we need to do more work
* to initialise a static rwlock. We check
* again inside the guarded section of pte_rwlock_check_need_init()
* to avoid race conditions.
*/
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
{
result = pte_rwlock_check_need_init (rwlock);
if (result != 0 && result != EBUSY)
{
return result;
}
}
rwl = *rwlock;
if (rwl->nMagic != PTE_RWLOCK_MAGIC)
{
return EINVAL;
}
if ((result =
pthread_mutex_timedlock (&(rwl->mtxExclusiveAccess), abstime)) != 0)
{
return result;
}
if (++rwl->nSharedAccessCount == INT_MAX)
{
if ((result =
pthread_mutex_timedlock (&(rwl->mtxSharedAccessCompleted),
abstime)) != 0)
{
if (result == ETIMEDOUT)
{
++rwl->nCompletedSharedAccessCount;
}
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount;
rwl->nCompletedSharedAccessCount = 0;
if ((result =
pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
}
return (pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)));
}
int pthread_rwlock_timedwrlock (pthread_rwlock_t * rwlock,
const struct timespec *abstime)
{
int result;
pthread_rwlock_t rwl;
if (rwlock == NULL || *rwlock == NULL)
return EINVAL;
/*
* We do a quick check to see if we need to do more work
* to initialise a static rwlock. We check
* again inside the guarded section of pte_rwlock_check_need_init()
* to avoid race conditions.
*/
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
{
result = pte_rwlock_check_need_init (rwlock);
if (result != 0 && result != EBUSY)
{
return result;
}
}
rwl = *rwlock;
if (rwl->nMagic != PTE_RWLOCK_MAGIC)
{
return EINVAL;
}
if ((result =
pthread_mutex_timedlock (&(rwl->mtxExclusiveAccess), abstime)) != 0)
{
return result;
}
if ((result =
pthread_mutex_timedlock (&(rwl->mtxSharedAccessCompleted),
abstime)) != 0)
{
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
if (rwl->nExclusiveAccessCount == 0)
{
if (rwl->nCompletedSharedAccessCount > 0)
{
rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount;
rwl->nCompletedSharedAccessCount = 0;
}
if (rwl->nSharedAccessCount > 0)
{
rwl->nCompletedSharedAccessCount = -rwl->nSharedAccessCount;
/*
* This routine may be a cancelation point
* according to POSIX 1003.1j section 18.1.2.
*/
pthread_cleanup_push (pte_rwlock_cancelwrwait, (void *) rwl);
do
{
result =
pthread_cond_timedwait (&(rwl->cndSharedAccessCompleted),
&(rwl->mtxSharedAccessCompleted),
abstime);
}
while (result == 0 && rwl->nCompletedSharedAccessCount < 0);
pthread_cleanup_pop ((result != 0) ? 1 : 0);
if (result == 0)
{
rwl->nSharedAccessCount = 0;
}
}
}
if (result == 0)
rwl->nExclusiveAccessCount++;
return result;
}
int pthread_rwlock_tryrdlock (pthread_rwlock_t * rwlock)
{
int result;
pthread_rwlock_t rwl;
if (rwlock == NULL || *rwlock == NULL)
return EINVAL;
/*
* We do a quick check to see if we need to do more work
* to initialise a static rwlock. We check
* again inside the guarded section of pte_rwlock_check_need_init()
* to avoid race conditions.
*/
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
{
result = pte_rwlock_check_need_init (rwlock);
if (result != 0 && result != EBUSY)
{
return result;
}
}
rwl = *rwlock;
if (rwl->nMagic != PTE_RWLOCK_MAGIC)
{
return EINVAL;
}
if ((result = pthread_mutex_trylock (&(rwl->mtxExclusiveAccess))) != 0)
{
return result;
}
if (++rwl->nSharedAccessCount == INT_MAX)
{
if ((result =
pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount;
rwl->nCompletedSharedAccessCount = 0;
if ((result =
pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
}
return (pthread_mutex_unlock (&rwl->mtxExclusiveAccess));
}
int pthread_rwlock_trywrlock (pthread_rwlock_t * rwlock)
{
int result, result1;
pthread_rwlock_t rwl;
if (rwlock == NULL || *rwlock == NULL)
return EINVAL;
/*
* We do a quick check to see if we need to do more work
* to initialise a static rwlock. We check
* again inside the guarded section of pte_rwlock_check_need_init()
* to avoid race conditions.
*/
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
{
result = pte_rwlock_check_need_init (rwlock);
if (result != 0 && result != EBUSY)
{
return result;
}
}
rwl = *rwlock;
if (rwl->nMagic != PTE_RWLOCK_MAGIC)
{
return EINVAL;
}
if ((result = pthread_mutex_trylock (&(rwl->mtxExclusiveAccess))) != 0)
{
return result;
}
if ((result =
pthread_mutex_trylock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return ((result1 != 0) ? result1 : result);
}
if (rwl->nExclusiveAccessCount == 0)
{
if (rwl->nCompletedSharedAccessCount > 0)
{
rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount;
rwl->nCompletedSharedAccessCount = 0;
}
if (rwl->nSharedAccessCount > 0)
{
if ((result =
pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
if ((result =
pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))) == 0)
{
result = EBUSY;
}
}
else
{
rwl->nExclusiveAccessCount = 1;
}
}
else
{
result = EBUSY;
}
return result;
}
int pthread_rwlock_unlock (pthread_rwlock_t * rwlock)
{
int result, result1;
pthread_rwlock_t rwl;
if (rwlock == NULL || *rwlock == NULL)
return (EINVAL);
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
{
/*
* Assume any race condition here is harmless.
*/
return 0;
}
rwl = *rwlock;
if (rwl->nMagic != PTE_RWLOCK_MAGIC)
{
return EINVAL;
}
if (rwl->nExclusiveAccessCount == 0)
{
if ((result =
pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
return result;
}
if (++rwl->nCompletedSharedAccessCount == 0)
{
result = pthread_cond_signal (&(rwl->cndSharedAccessCompleted));
}
result1 = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted));
}
else
{
rwl->nExclusiveAccessCount--;
result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted));
result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
}
return ((result != 0) ? result : result1);
}
int pthread_rwlock_wrlock (pthread_rwlock_t * rwlock)
{
int result;
pthread_rwlock_t rwl;
if (rwlock == NULL || *rwlock == NULL)
return EINVAL;
/*
* We do a quick check to see if we need to do more work
* to initialise a static rwlock. We check
* again inside the guarded section of pte_rwlock_check_need_init()
* to avoid race conditions.
*/
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
{
result = pte_rwlock_check_need_init (rwlock);
if (result != 0 && result != EBUSY)
return result;
}
rwl = *rwlock;
if (rwl->nMagic != PTE_RWLOCK_MAGIC)
return EINVAL;
if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0)
return result;
if ((result = pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0)
{
(void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
return result;
}
if (rwl->nExclusiveAccessCount == 0)
{
if (rwl->nCompletedSharedAccessCount > 0)
{
rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount;
rwl->nCompletedSharedAccessCount = 0;
}
if (rwl->nSharedAccessCount > 0)
{
rwl->nCompletedSharedAccessCount = -rwl->nSharedAccessCount;
/*
* This routine may be a cancelation point
* according to POSIX 1003.1j section 18.1.2.
*/
pthread_cleanup_push (pte_rwlock_cancelwrwait, (void *) rwl);
do
{
result = pthread_cond_wait (&(rwl->cndSharedAccessCompleted),
&(rwl->mtxSharedAccessCompleted));
}
while (result == 0 && rwl->nCompletedSharedAccessCount < 0);
pthread_cleanup_pop ((result != 0) ? 1 : 0);
if (result == 0)
rwl->nSharedAccessCount = 0;
}
}
if (result == 0)
rwl->nExclusiveAccessCount++;
return result;
}
-259
View File
@@ -1,259 +0,0 @@
/*
* pthread_rwlockattr_destroy.c
*
* Description:
* This translation unit implements read/write lock primitives.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include "pthread.h"
#include "implement.h"
int
pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Destroys a rwlock attributes object. The object can
* no longer be used.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_rwlockattr_t
*
*
* DESCRIPTION
* Destroys a rwlock attributes object. The object can
* no longer be used.
*
* NOTES:
* 1) Does not affect rwlockss created using 'attr'
*
* RESULTS
* 0 successfully released attr,
* EINVAL 'attr' is invalid.
*
* ------------------------------------------------------
*/
{
int result = 0;
if (attr == NULL || *attr == NULL)
{
result = EINVAL;
}
else
{
pthread_rwlockattr_t rwa = *attr;
*attr = NULL;
free (rwa);
}
return (result);
}
int
pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr,
int *pshared)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Determine whether rwlocks created with 'attr' can be
* shared between processes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_rwlockattr_t
*
* pshared
* will be set to one of:
*
* PTHREAD_PROCESS_SHARED
* May be shared if in shared memory
*
* PTHREAD_PROCESS_PRIVATE
* Cannot be shared.
*
*
* DESCRIPTION
* Rwlocks creatd with 'attr' can be shared between
* processes if pthread_rwlock_t variable is allocated
* in memory shared by these processes.
* NOTES:
* 1) pshared rwlocks MUST be allocated in shared
* memory.
* 2) The following macro is defined if shared rwlocks
* are supported:
* _POSIX_THREAD_PROCESS_SHARED
*
* RESULTS
* 0 successfully retrieved attribute,
* EINVAL 'attr' is invalid,
*
* ------------------------------------------------------
*/
{
int result;
if ((attr != NULL && *attr != NULL) && (pshared != NULL))
{
*pshared = (*attr)->pshared;
result = 0;
}
else
result = EINVAL;
return (result);
}
int pthread_rwlockattr_init (pthread_rwlockattr_t * attr)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Initializes a rwlock attributes object with default
* attributes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_rwlockattr_t
*
*
* DESCRIPTION
* Initializes a rwlock attributes object with default
* attributes.
*
* RESULTS
* 0 successfully initialized attr,
* ENOMEM insufficient memory for attr.
*
* ------------------------------------------------------
*/
{
int result = 0;
pthread_rwlockattr_t rwa;
rwa = (pthread_rwlockattr_t) calloc (1, sizeof (*rwa));
if (rwa == NULL)
result = ENOMEM;
else
rwa->pshared = PTHREAD_PROCESS_PRIVATE;
*attr = rwa;
return (result);
}
int pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, int pshared)
/*
* ------------------------------------------------------
* DOCPUBLIC
* Rwlocks created with 'attr' can be shared between
* processes if pthread_rwlock_t variable is allocated
* in memory shared by these processes.
*
* PARAMETERS
* attr
* pointer to an instance of pthread_rwlockattr_t
*
* pshared
* must be one of:
*
* PTHREAD_PROCESS_SHARED
* May be shared if in shared memory
*
* PTHREAD_PROCESS_PRIVATE
* Cannot be shared.
*
* DESCRIPTION
* Rwlocks creatd with 'attr' can be shared between
* processes if pthread_rwlock_t variable is allocated
* in memory shared by these processes.
*
* NOTES:
* 1) pshared rwlocks MUST be allocated in shared
* memory.
*
* 2) The following macro is defined if shared rwlocks
* are supported:
* _POSIX_THREAD_PROCESS_SHARED
*
* RESULTS
* 0 successfully set attribute,
* EINVAL 'attr' or pshared is invalid,
* ENOSYS PTHREAD_PROCESS_SHARED not supported,
*
* ------------------------------------------------------
*/
{
int result;
if ((attr != NULL && *attr != NULL) &&
((pshared == PTHREAD_PROCESS_SHARED) ||
(pshared == PTHREAD_PROCESS_PRIVATE)))
{
if (pshared == PTHREAD_PROCESS_SHARED)
{
#if !defined( _POSIX_THREAD_PROCESS_SHARED )
result = ENOSYS;
pshared = PTHREAD_PROCESS_PRIVATE;
#else
result = 0;
#endif /* _POSIX_THREAD_PROCESS_SHARED */
}
else
result = 0;
(*attr)->pshared = pshared;
}
else
result = EINVAL;
return (result);
} /* pthread_rwlockattr_setpshared */
-399
View File
@@ -1,399 +0,0 @@
/*
* pthread_set.c
*
* Description:
* POSIX thread functions related to state.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include "pthread.h"
#include "implement.h"
#include "sched.h"
int pthread_setcancelstate (int state, int *oldstate)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function atomically sets the calling thread's
* cancelability state to 'state' and returns the previous
* cancelability state at the location referenced by
* 'oldstate'
*
* PARAMETERS
* state,
* oldstate
* PTHREAD_CANCEL_ENABLE
* cancellation is enabled,
*
* PTHREAD_CANCEL_DISABLE
* cancellation is disabled
*
*
* DESCRIPTION
* This function atomically sets the calling thread's
* cancelability state to 'state' and returns the previous
* cancelability state at the location referenced by
* 'oldstate'.
*
* NOTES:
* 1) Use to disable cancellation around 'atomic' code that
* includes cancellation points
*
* COMPATIBILITY ADDITIONS
* If 'oldstate' is NULL then the previous state is not returned
* but the function still succeeds. (Solaris)
*
* RESULTS
* 0 successfully set cancelability type,
* EINVAL 'state' is invalid
*
* ------------------------------------------------------
*/
{
int result = 0;
pthread_t self = pthread_self ();
pte_thread_t * sp = (pte_thread_t *) self;
if (sp == NULL
|| (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE))
return EINVAL;
/*
* Lock for async-cancel safety.
*/
(void) pthread_mutex_lock (&sp->cancelLock);
if (oldstate != NULL)
*oldstate = sp->cancelState;
sp->cancelState = state;
/*
* Check if there is a pending asynchronous cancel
*/
if (state == PTHREAD_CANCEL_ENABLE
&& (sp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS)
&& (pte_osThreadCheckCancel(sp->threadId) == PTE_OS_INTERRUPTED) )
{
sp->state = PThreadStateCanceling;
sp->cancelState = PTHREAD_CANCEL_DISABLE;
(void) pthread_mutex_unlock (&sp->cancelLock);
pte_throw (PTE_EPS_CANCEL);
/* Never reached */
}
(void) pthread_mutex_unlock (&sp->cancelLock);
return (result);
}
int pthread_setcanceltype (int type, int *oldtype)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function atomically sets the calling thread's
* cancelability type to 'type' and returns the previous
* cancelability type at the location referenced by
* 'oldtype'
*
* PARAMETERS
* type,
* oldtype
* PTHREAD_CANCEL_DEFERRED
* only deferred cancelation is allowed,
*
* PTHREAD_CANCEL_ASYNCHRONOUS
* Asynchronous cancellation is allowed
*
*
* DESCRIPTION
* This function atomically sets the calling thread's
* cancelability type to 'type' and returns the previous
* cancelability type at the location referenced by
* 'oldtype'
*
* NOTES:
* 1) Use with caution; most code is not safe for use
* with asynchronous cancelability.
*
* COMPATIBILITY ADDITIONS
* If 'oldtype' is NULL then the previous type is not returned
* but the function still succeeds. (Solaris)
*
* RESULTS
* 0 successfully set cancelability type,
* EINVAL 'type' is invalid
* EPERM Async cancellation is not supported.
*
* ------------------------------------------------------
*/
{
int result = 0;
pthread_t self = pthread_self ();
pte_thread_t * sp = (pte_thread_t *) self;
#ifndef PTE_SUPPORT_ASYNC_CANCEL
if (type == PTHREAD_CANCEL_ASYNCHRONOUS)
{
/* Async cancellation is not supported at this time. See notes in
* pthread_cancel.
*/
return EPERM;
}
#endif /* PTE_SUPPORT_ASYNC_CANCEL */
if (sp == NULL
|| (type != PTHREAD_CANCEL_DEFERRED
&& type != PTHREAD_CANCEL_ASYNCHRONOUS))
return EINVAL;
/*
* Lock for async-cancel safety.
*/
(void) pthread_mutex_lock (&sp->cancelLock);
if (oldtype != NULL)
*oldtype = sp->cancelType;
sp->cancelType = type;
/*
* Check if there is a pending asynchronous cancel
*/
if (sp->cancelState == PTHREAD_CANCEL_ENABLE
&& (type == PTHREAD_CANCEL_ASYNCHRONOUS)
&& (pte_osThreadCheckCancel(sp->threadId) == PTE_OS_INTERRUPTED) )
{
sp->state = PThreadStateCanceling;
sp->cancelState = PTHREAD_CANCEL_DISABLE;
(void) pthread_mutex_unlock (&sp->cancelLock);
pte_throw (PTE_EPS_CANCEL);
/* Never reached */
}
(void) pthread_mutex_unlock (&sp->cancelLock);
return (result);
}
int pthread_setconcurrency (int level)
{
if (level < 0)
return EINVAL;
pte_concurrency = level;
return 0;
}
int pthread_setschedparam (pthread_t thread, int policy,
const struct sched_param *param)
{
int result;
/* Validate the thread id. */
result = pthread_kill (thread, 0);
if (0 != result)
return result;
/* Validate the scheduling policy. */
if (policy < SCHED_MIN || policy > SCHED_MAX)
return EINVAL;
/* Ensure the policy is SCHED_OTHER. */
if (policy != SCHED_OTHER)
return ENOTSUP;
return (pte_setthreadpriority (thread, policy, param->sched_priority));
}
int
pte_setthreadpriority (pthread_t thread, int policy, int priority)
{
int prio;
int result;
pte_thread_t * tp = (pte_thread_t *) thread;
prio = priority;
/* Validate priority level. */
if (prio < sched_get_priority_min (policy) ||
prio > sched_get_priority_max (policy))
return EINVAL;
result = pthread_mutex_lock (&tp->threadLock);
if (0 == result)
{
/* If this fails, the current priority is unchanged. */
if (0 != pte_osThreadSetPriority(tp->threadId, prio))
result = EINVAL;
else
{
/*
* Must record the thread's sched_priority as given,
* not as finally adjusted.
*/
tp->sched_priority = priority;
}
(void) pthread_mutex_unlock (&tp->threadLock);
}
return result;
}
int pthread_setspecific (pthread_key_t key, const void *value)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function sets the value of the thread specific
* key in the calling thread.
*
* PARAMETERS
* key
* an instance of pthread_key_t
* value
* the value to set key to
*
*
* DESCRIPTION
* This function sets the value of the thread specific
* key in the calling thread.
*
* RESULTS
* 0 successfully set value
* EAGAIN could not set value
* ENOENT SERIOUS!!
*
* ------------------------------------------------------
*/
{
pthread_t self;
int result = 0;
if (key != pte_selfThreadKey)
{
/*
* Using pthread_self will implicitly create
* an instance of pthread_t for the current
* thread if one wasn't explicitly created
*/
self = pthread_self ();
if (self == NULL)
return ENOENT;
}
else
{
/*
* Resolve catch-22 of registering thread with selfThread
* key
*/
pte_thread_t * sp = (pte_thread_t *) pthread_getspecific (pte_selfThreadKey);
if (sp == NULL)
{
if (value == NULL)
return ENOENT;
self = *((pthread_t *) value);
}
else
self = sp;
}
result = 0;
if (key != NULL)
{
if (self != NULL && key->destructor != NULL && value != NULL)
{
/*
* Only require associations if we have to
* call user destroy routine.
* Don't need to locate an existing association
* when setting data to NULL since the
* data is stored with the operating system; not
* on the association; setting assoc to NULL short
* circuits the search.
*/
ThreadKeyAssoc *assoc;
if (pthread_mutex_lock(&(key->keyLock)) == 0)
{
pte_thread_t * sp = (pte_thread_t *) self;
(void) pthread_mutex_lock(&(sp->threadLock));
assoc = (ThreadKeyAssoc *) sp->keys;
/*
* Locate existing association
*/
while (assoc != NULL)
{
/*
* Association already exists
*/
if (assoc->key == key)
break;
assoc = assoc->nextKey;
}
/*
* create an association if not found
*/
if (assoc == NULL)
result = pte_tkAssocCreate (sp, key);
(void) pthread_mutex_unlock(&(sp->threadLock));
}
(void) pthread_mutex_unlock(&(key->keyLock));
}
if (result == 0)
{
if (pte_osTlsSetValue (key->key, (void *) value) != PTE_OS_OK)
result = EAGAIN;
}
}
return (result);
}
-295
View File
@@ -1,295 +0,0 @@
/*
* pthread_spin.c
*
* Description:
* This translation unit implements spin lock primitives.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdlib.h>
#include "pthread.h"
#include "implement.h"
int
pthread_spin_destroy (pthread_spinlock_t * lock)
{
register pthread_spinlock_t s;
int result = 0;
if (lock == NULL || *lock == NULL)
{
return EINVAL;
}
if ((s = *lock) != PTHREAD_SPINLOCK_INITIALIZER)
{
if (s->interlock == PTE_SPIN_USE_MUTEX)
{
result = pthread_mutex_destroy (&(s->u.mutex));
}
else if (PTE_SPIN_UNLOCKED !=
PTE_ATOMIC_COMPARE_EXCHANGE (
& (s->interlock),
(int) PTE_OBJECT_INVALID,
PTE_SPIN_UNLOCKED))
{
result = EINVAL;
}
if (0 == result)
{
/*
* We are relying on the application to ensure that all other threads
* have finished with the spinlock before destroying it.
*/
*lock = NULL;
(void) free (s);
}
}
else
{
/*
* See notes in pte_spinlock_check_need_init() above also.
*/
pte_osMutexLock (pte_spinlock_test_init_lock);
/*
* Check again.
*/
if (*lock == PTHREAD_SPINLOCK_INITIALIZER)
{
/*
* This is all we need to do to destroy a statically
* initialised spinlock that has not yet been used (initialised).
* If we get to here, another thread
* waiting to initialise this mutex will get an EINVAL.
*/
*lock = NULL;
}
else
{
/*
* The spinlock has been initialised while we were waiting
* so assume it's in use.
*/
result = EBUSY;
}
pte_osMutexUnlock(pte_spinlock_test_init_lock);
}
return (result);
}
int pthread_spin_init (pthread_spinlock_t * lock, int pshared)
{
pthread_spinlock_t s;
int cpus = 0;
int result = 0;
if (lock == NULL)
return EINVAL;
if (0 != pte_getprocessors (&cpus))
{
cpus = 1;
}
if (cpus > 1)
{
if (pshared == PTHREAD_PROCESS_SHARED)
{
/*
* Creating spinlock that can be shared between
* processes.
*/
#if _POSIX_THREAD_PROCESS_SHARED >= 0
/*
* Not implemented yet.
*/
#error ERROR [__FILE__, line __LINE__]: Process shared spin locks are not supported yet.
#else
return ENOSYS;
#endif /* _POSIX_THREAD_PROCESS_SHARED */
}
}
s = (pthread_spinlock_t) calloc (1, sizeof (*s));
if (s == NULL)
{
return ENOMEM;
}
if (cpus > 1)
{
s->u.cpus = cpus;
s->interlock = PTE_SPIN_UNLOCKED;
}
else
{
pthread_mutexattr_t ma;
result = pthread_mutexattr_init (&ma);
if (0 == result)
{
ma->pshared = pshared;
result = pthread_mutex_init (&(s->u.mutex), &ma);
if (0 == result)
{
s->interlock = PTE_SPIN_USE_MUTEX;
}
}
(void) pthread_mutexattr_destroy (&ma);
}
if (0 == result)
{
*lock = s;
}
else
{
(void) free (s);
*lock = NULL;
}
return (result);
}
int pthread_spin_lock (pthread_spinlock_t * lock)
{
register pthread_spinlock_t s;
if (NULL == lock || NULL == *lock)
return (EINVAL);
if (*lock == PTHREAD_SPINLOCK_INITIALIZER)
{
int result;
if ((result = pte_spinlock_check_need_init (lock)) != 0)
return (result);
}
s = *lock;
while ( PTE_SPIN_LOCKED ==
PTE_ATOMIC_COMPARE_EXCHANGE (&(s->interlock),
PTE_SPIN_LOCKED,
PTE_SPIN_UNLOCKED))
{
}
if (s->interlock == PTE_SPIN_LOCKED)
return 0;
if (s->interlock == PTE_SPIN_USE_MUTEX)
return pthread_mutex_lock (&(s->u.mutex));
return EINVAL;
}
int pthread_spin_trylock (pthread_spinlock_t * lock)
{
register pthread_spinlock_t s;
if (NULL == lock || NULL == *lock)
return (EINVAL);
if (*lock == PTHREAD_SPINLOCK_INITIALIZER)
{
int result;
if ((result = pte_spinlock_check_need_init (lock)) != 0)
return (result);
}
s = *lock;
switch ((long)
PTE_ATOMIC_COMPARE_EXCHANGE (&(s->interlock),
PTE_SPIN_LOCKED,
PTE_SPIN_UNLOCKED))
{
case PTE_SPIN_UNLOCKED:
return 0;
case PTE_SPIN_LOCKED:
return EBUSY;
case PTE_SPIN_USE_MUTEX:
return pthread_mutex_trylock (&(s->u.mutex));
}
return EINVAL;
}
int pthread_spin_unlock (pthread_spinlock_t * lock)
{
register pthread_spinlock_t s;
if (NULL == lock || NULL == *lock)
return (EINVAL);
s = *lock;
if (s == PTHREAD_SPINLOCK_INITIALIZER)
return EPERM;
switch ((long)
PTE_ATOMIC_COMPARE_EXCHANGE (&(s->interlock),
PTE_SPIN_UNLOCKED,
PTE_SPIN_LOCKED))
{
case PTE_SPIN_LOCKED:
return 0;
case PTE_SPIN_UNLOCKED:
return EPERM;
case PTE_SPIN_USE_MUTEX:
return pthread_mutex_unlock (&(s->u.mutex));
}
return EINVAL;
}
-101
View File
@@ -1,101 +0,0 @@
/*
* sched_setscheduler.c
*
* Description:
* POSIX thread functions that deal with thread scheduling.
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include "pte_osal.h"
#include "pthread.h"
#include "implement.h"
#include "sched.h"
int
sched_setscheduler (pid_t pid, int policy)
{
errno = EPERM;
return -1;
}
int
sched_yield (void)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function indicates that the calling thread is
* willing to give up some time slices to other threads.
*
* PARAMETERS
* N/A
*
*
* DESCRIPTION
* This function indicates that the calling thread is
* willing to give up some time slices to other threads.
* NOTE: Since this is part of POSIX 1003.1b
* (realtime extensions), it is defined as returning
* -1 if an error occurs and sets errno to the actual
* error.
*
* RESULTS
* 0 successfully created semaphore,
* ENOSYS sched_yield not supported,
*
* ------------------------------------------------------
*/
{
pte_osThreadSleep (1);
return 0;
}
int
sched_get_priority_min (int policy)
{
return pte_osThreadGetMinPriority();
}
int
sched_get_priority_max (int policy)
{
return pte_osThreadGetMaxPriority();
}
-137
View File
@@ -1,137 +0,0 @@
/*
* Module: sched.h
*
* Purpose:
* Provides an implementation of POSIX realtime extensions
* as defined in
*
* POSIX 1003.1b-1993 (POSIX.1b)
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef _SCHED_H
#define _SCHED_H
#include <pte_types.h>
#undef PTE_LEVEL
#if defined(_POSIX_SOURCE)
#define PTE_LEVEL 0
/* Early POSIX */
#endif
#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309
#undef PTE_LEVEL
#define PTE_LEVEL 1
/* Include 1b, 1c and 1d */
#endif
#if defined(INCLUDE_NP)
#undef PTE_LEVEL
#define PTE_LEVEL 2
/* Include Non-Portable extensions */
#endif
#define PTE_LEVEL_MAX 3
#if !defined(PTE_LEVEL)
#define PTE_LEVEL PTE_LEVEL_MAX
/* Include everything */
#endif
/*
*
*/
/* Thread scheduling policies */
enum
{
SCHED_OTHER = 0,
SCHED_FIFO,
SCHED_RR,
SCHED_MIN = SCHED_OTHER,
SCHED_MAX = SCHED_RR
};
struct sched_param
{
int sched_priority;
};
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
int sched_yield (void);
int sched_get_priority_min (int policy);
int sched_get_priority_max (int policy);
int sched_setscheduler (pid_t pid, int policy);
/*
* Note that this macro returns ENOTSUP rather than
* ENOSYS as might be expected. However, returning ENOSYS
* should mean that sched_get_priority_{min,max} are
* not implemented as well as sched_rr_get_interval.
* This is not the case, since we just don't support
* round-robin scheduling. Therefore I have chosen to
* return the same value as sched_setscheduler when
* SCHED_RR is passed to it.
*/
#define sched_rr_get_interval(_pid, _interval) \
( errno = ENOTSUP, (int) -1 )
#ifdef __cplusplus
} /* End of extern "C" */
#endif /* __cplusplus */
#undef PTE_LEVEL
#undef PTE_LEVEL_MAX
#endif /* !_SCHED_H */
-895
View File
@@ -1,895 +0,0 @@
/*
* -------------------------------------------------------------
*
* Module: sem.c
*
* Purpose:
* Semaphores aren't actually part of the PThreads standard.
* They are defined by the POSIX Standard:
*
* POSIX 1003.1b-1993 (POSIX.1b)
*
* -------------------------------------------------------------
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include "pte_osal.h"
#include "pthread.h"
#include "semaphore.h"
#include "implement.h"
typedef struct
{
sem_t sem;
int * resultPtr;
} sem_timedwait_cleanup_args_t;
static void pte_sem_wait_cleanup(void * sem)
{
sem_t s = (sem_t) sem;
unsigned int timeout;
if (pthread_mutex_lock (&s->lock) == 0)
{
/*
* If sema is destroyed do nothing, otherwise:-
* If the sema is posted between us being cancelled and us locking
* the sema again above then we need to consume that post but cancel
* anyway. If we don't get the semaphore we indicate that we're no
* longer waiting.
*/
timeout = 0;
if (pte_osSemaphorePend(s->sem, &timeout) != PTE_OS_OK)
{
++s->value;
/*
* Don't release the W32 sema, it doesn't need adjustment
* because it doesn't record the number of waiters.
*/
}
(void) pthread_mutex_unlock (&s->lock);
}
}
static void pte_sem_timedwait_cleanup (void * args)
{
sem_timedwait_cleanup_args_t * a = (sem_timedwait_cleanup_args_t *)args;
sem_t s = a->sem;
if (pthread_mutex_lock (&s->lock) == 0)
{
/*
* We either timed out or were cancelled.
* If someone has posted between then and now we try to take the semaphore.
* Otherwise the semaphore count may be wrong after we
* return. In the case of a cancellation, it is as if we
* were cancelled just before we return (after taking the semaphore)
* which is ok.
*/
unsigned int timeout = 0;
if (pte_osSemaphorePend(s->sem, &timeout) == PTE_OS_OK)
{
/* We got the semaphore on the second attempt */
*(a->resultPtr) = 0;
}
else
{
/* Indicate we're no longer waiting */
s->value++;
/*
* Don't release the OS sema, it doesn't need adjustment
* because it doesn't record the number of waiters.
*/
}
(void) pthread_mutex_unlock (&s->lock);
}
}
int sem_close (sem_t * sem)
{
errno = ENOSYS;
return -1;
}
int sem_destroy (sem_t * sem)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function destroys an unnamed semaphore.
*
* PARAMETERS
* sem
* pointer to an instance of sem_t
*
* DESCRIPTION
* This function destroys an unnamed semaphore.
*
* RESULTS
* 0 successfully destroyed semaphore,
* -1 failed, error in errno
* ERRNO
* EINVAL 'sem' is not a valid semaphore,
* ENOSYS semaphores are not supported,
* EBUSY threads (or processes) are currently
* blocked on 'sem'
*
* ------------------------------------------------------
*/
{
int result = 0;
sem_t s = NULL;
if (sem == NULL || *sem == NULL)
result = EINVAL;
else
{
s = *sem;
if ((result = pthread_mutex_lock (&s->lock)) == 0)
{
if (s->value < 0)
{
(void) pthread_mutex_unlock (&s->lock);
result = EBUSY;
}
else
{
/* There are no threads currently blocked on this semaphore. */
pte_osResult osResult = pte_osSemaphoreDelete(s->sem);
if (osResult != PTE_OS_OK)
{
(void) pthread_mutex_unlock (&s->lock);
result = EINVAL;
}
else
{
/*
* Invalidate the semaphore handle when we have the lock.
* Other sema operations should test this after acquiring the lock
* to check that the sema is still valid, i.e. before performing any
* operations. This may only be necessary before the sema op routine
* returns so that the routine can return EINVAL - e.g. if setting
* s->value to SEM_VALUE_MAX below does force a fall-through.
*/
*sem = NULL;
/* Prevent anyone else actually waiting on or posting this sema.
*/
s->value = SEM_VALUE_MAX;
(void) pthread_mutex_unlock (&s->lock);
do
{
/* Give other threads a chance to run and exit any sema op
* routines. Due to the SEM_VALUE_MAX value, if sem_post or
* sem_wait were blocked by us they should fall through.
*/
pte_osThreadSleep(1);
}
while (pthread_mutex_destroy (&s->lock) == EBUSY);
}
}
}
}
if (result != 0)
{
errno = result;
return -1;
}
free (s);
return 0;
}
int
sem_getvalue (sem_t * sem, int *sval)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function stores the current count value of the
* semaphore.
* RESULTS
*
* Return value
*
* 0 sval has been set.
* -1 failed, error in errno
*
* in global errno
*
* EINVAL 'sem' is not a valid semaphore,
* ENOSYS this function is not supported,
*
*
* PARAMETERS
*
* sem pointer to an instance of sem_t
*
* sval pointer to int.
*
* DESCRIPTION
* This function stores the current count value of the semaphore
* pointed to by sem in the int pointed to by sval.
*/
{
if (sem == NULL || *sem == NULL || sval == NULL)
{
errno = EINVAL;
return -1;
}
else
{
long value;
register sem_t s = *sem;
int result = 0;
if ((result = pthread_mutex_lock(&s->lock)) == 0)
{
if (*sem == NULL)
{
(void) pthread_mutex_unlock (&s->lock);
errno = EINVAL;
return -1;
}
value = s->value;
(void) pthread_mutex_unlock(&s->lock);
*sval = value;
}
return result;
}
}
int
sem_init (sem_t * sem, int pshared, unsigned int value)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function initializes a semaphore. The
* initial value of the semaphore is 'value'
*
* PARAMETERS
* sem
* pointer to an instance of sem_t
*
* pshared
* if zero, this semaphore may only be shared between
* threads in the same process.
* if nonzero, the semaphore can be shared between
* processes
*
* value
* initial value of the semaphore counter
*
* DESCRIPTION
* This function initializes a semaphore. The
* initial value of the semaphore is set to 'value'.
*
* RESULTS
* 0 successfully created semaphore,
* -1 failed, error in errno
* ERRNO
* EINVAL 'sem' is not a valid semaphore, or
* 'value' >= SEM_VALUE_MAX
* ENOMEM out of memory,
* ENOSPC a required resource has been exhausted,
* ENOSYS semaphores are not supported,
* EPERM the process lacks appropriate privilege
*
* ------------------------------------------------------
*/
{
int result = 0;
sem_t s = NULL;
if (pshared != 0)
{
/*
* Creating a semaphore that can be shared between
* processes
*/
result = EPERM;
}
else if (value > (unsigned int)SEM_VALUE_MAX)
{
result = EINVAL;
}
else
{
s = (sem_t) calloc (1, sizeof (*s));
if (NULL == s)
{
result = ENOMEM;
}
else
{
s->value = value;
if (pthread_mutex_init(&s->lock, NULL) == 0)
{
pte_osResult osResult = pte_osSemaphoreCreate(0, &s->sem);
if (osResult != PTE_OS_OK)
{
(void) pthread_mutex_destroy(&s->lock);
result = ENOSPC;
}
}
else
{
result = ENOSPC;
}
if (result != 0)
{
free(s);
}
}
}
if (result != 0)
{
errno = result;
return -1;
}
*sem = s;
return 0;
}
int sem_open (const char *name, int oflag, mode_t mode, unsigned int value)
{
errno = ENOSYS;
return -1;
}
int
sem_post (sem_t * sem)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function posts a wakeup to a semaphore.
*
* PARAMETERS
* sem
* pointer to an instance of sem_t
*
* DESCRIPTION
* This function posts a wakeup to a semaphore. If there
* are waiting threads (or processes), one is awakened;
* otherwise, the semaphore value is incremented by one.
*
* RESULTS
* 0 successfully posted semaphore,
* -1 failed, error in errno
* ERRNO
* EINVAL 'sem' is not a valid semaphore,
* ENOSYS semaphores are not supported,
* ERANGE semaphore count is too big
*
* ------------------------------------------------------
*/
{
int result = 0;
sem_t s = *sem;
if (s == NULL)
result = EINVAL;
else if ((result = pthread_mutex_lock (&s->lock)) == 0)
{
/* See sem_destroy.c
*/
if (*sem == NULL)
{
(void) pthread_mutex_unlock (&s->lock);
result = EINVAL;
return -1;
}
if (s->value < SEM_VALUE_MAX)
{
pte_osResult osResult = pte_osSemaphorePost(s->sem, 1);
if (++s->value <= 0
&& (osResult != PTE_OS_OK))
{
s->value--;
result = EINVAL;
}
}
else
result = ERANGE;
(void) pthread_mutex_unlock (&s->lock);
}
if (result != 0)
{
errno = result;
return -1;
}
return 0;
}
int
sem_post_multiple (sem_t * sem, int count)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function posts multiple wakeups to a semaphore.
*
* PARAMETERS
* sem
* pointer to an instance of sem_t
*
* count
* counter, must be greater than zero.
*
* DESCRIPTION
* This function posts multiple wakeups to a semaphore. If there
* are waiting threads (or processes), n <= count are awakened;
* the semaphore value is incremented by count - n.
*
* RESULTS
* 0 successfully posted semaphore,
* -1 failed, error in errno
* ERRNO
* EINVAL 'sem' is not a valid semaphore
* or count is less than or equal to zero.
* ERANGE semaphore count is too big
*
* ------------------------------------------------------
*/
{
int result = 0;
long waiters;
sem_t s = *sem;
if (s == NULL || count <= 0)
result = EINVAL;
else if ((result = pthread_mutex_lock (&s->lock)) == 0)
{
/* See sem_destroy.c
*/
if (*sem == NULL)
{
(void) pthread_mutex_unlock (&s->lock);
result = EINVAL;
return -1;
}
if (s->value <= (SEM_VALUE_MAX - count))
{
waiters = -s->value;
s->value += count;
if (waiters > 0)
{
pte_osSemaphorePost(s->sem, (waiters<=count)?waiters:count);
result = 0;
}
/*
else
{
s->value -= count;
result = EINVAL;
}
*/
}
else
{
result = ERANGE;
}
(void) pthread_mutex_unlock (&s->lock);
}
if (result != 0)
{
errno = result;
return -1;
}
return 0;
}
int
sem_timedwait (sem_t * sem, const struct timespec *abstime)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function waits on a semaphore possibly until
* 'abstime' time.
*
* PARAMETERS
* sem
* pointer to an instance of sem_t
*
* abstime
* pointer to an instance of struct timespec
*
* DESCRIPTION
* This function waits on a semaphore. If the
* semaphore value is greater than zero, it decreases
* its value by one. If the semaphore value is zero, then
* the calling thread (or process) is blocked until it can
* successfully decrease the value or until interrupted by
* a signal.
*
* If 'abstime' is a NULL pointer then this function will
* block until it can successfully decrease the value or
* until interrupted by a signal.
*
* RESULTS
* 0 successfully decreased semaphore,
* -1 failed, error in errno
* ERRNO
* EINVAL 'sem' is not a valid semaphore,
* ENOSYS semaphores are not supported,
* EINTR the function was interrupted by a signal,
* EDEADLK a deadlock condition was detected.
* ETIMEDOUT abstime elapsed before success.
*
* ------------------------------------------------------
*/
{
int result = 0;
sem_t s = *sem;
pthread_testcancel();
if (sem == NULL)
result = EINVAL;
else
{
unsigned int milliseconds;
unsigned int *pTimeout;
if (abstime == NULL)
{
pTimeout = NULL;
}
else
{
/*
* Calculate timeout as milliseconds from current system time.
*/
milliseconds = pte_relmillisecs (abstime);
pTimeout = &milliseconds;
}
if ((result = pthread_mutex_lock (&s->lock)) == 0)
{
int v;
/* See sem_destroy.c
*/
if (*sem == NULL)
{
(void) pthread_mutex_unlock (&s->lock);
errno = EINVAL;
return -1;
}
v = --s->value;
(void) pthread_mutex_unlock (&s->lock);
if (v < 0)
{
{
sem_timedwait_cleanup_args_t cleanup_args;
cleanup_args.sem = s;
cleanup_args.resultPtr = &result;
/* Must wait */
pthread_cleanup_push(pte_sem_timedwait_cleanup, (void *) &cleanup_args);
result = pte_cancellable_wait(s->sem,pTimeout);
pthread_cleanup_pop(result);
}
}
}
}
if (result != 0)
{
errno = result;
return -1;
}
return 0;
}
int sem_trywait (sem_t * sem)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function tries to wait on a semaphore.
*
* PARAMETERS
* sem
* pointer to an instance of sem_t
*
* DESCRIPTION
* This function tries to wait on a semaphore. If the
* semaphore value is greater than zero, it decreases
* its value by one. If the semaphore value is zero, then
* this function returns immediately with the error EAGAIN
*
* RESULTS
* 0 successfully decreased semaphore,
* -1 failed, error in errno
* ERRNO
* EAGAIN the semaphore was already locked,
* EINVAL 'sem' is not a valid semaphore,
* ENOTSUP sem_trywait is not supported,
* EINTR the function was interrupted by a signal,
* EDEADLK a deadlock condition was detected.
*
* ------------------------------------------------------
*/
{
int result = 0;
sem_t s = *sem;
if (s == NULL)
result = EINVAL;
else if ((result = pthread_mutex_lock (&s->lock)) == 0)
{
/* See sem_destroy.c
*/
if (*sem == NULL)
{
(void) pthread_mutex_unlock (&s->lock);
errno = EINVAL;
return -1;
}
if (s->value > 0)
s->value--;
else
result = EAGAIN;
(void) pthread_mutex_unlock (&s->lock);
}
if (result != 0)
{
errno = result;
return -1;
}
return 0;
}
int sem_unlink (const char *name)
{
errno = ENOSYS;
return -1;
}
int sem_wait (sem_t * sem)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function waits on a semaphore.
*
* PARAMETERS
* sem
* pointer to an instance of sem_t
*
* DESCRIPTION
* This function waits on a semaphore. If the
* semaphore value is greater than zero, it decreases
* its value by one. If the semaphore value is zero, then
* the calling thread (or process) is blocked until it can
* successfully decrease the value or until interrupted by
* a signal.
*
* RESULTS
* 0 successfully decreased semaphore,
* -1 failed, error in errno
* ERRNO
* EINVAL 'sem' is not a valid semaphore,
* ENOSYS semaphores are not supported,
* EINTR the function was interrupted by a signal,
* EDEADLK a deadlock condition was detected.
*
* ------------------------------------------------------
*/
{
int result = 0;
sem_t s = *sem;
pthread_testcancel();
if (s == NULL)
{
result = EINVAL;
}
else
{
if ((result = pthread_mutex_lock (&s->lock)) == 0)
{
int v;
/* See sem_destroy.c
*/
if (*sem == NULL)
{
(void) pthread_mutex_unlock (&s->lock);
errno = EINVAL;
return -1;
}
v = --s->value;
(void) pthread_mutex_unlock (&s->lock);
if (v < 0)
{
/* Must wait */
pthread_cleanup_push(pte_sem_wait_cleanup, (void *) s);
result = pte_cancellable_wait(s->sem,NULL);
/* Cleanup if we're canceled or on any other error */
pthread_cleanup_pop(result);
// Wait was cancelled, indicate that we're no longer waiting on this semaphore.
/*
if (result == PTE_OS_INTERRUPTED)
{
result = EINTR;
++s->value;
}
*/
}
}
}
if (result != 0)
{
errno = result;
return -1;
}
return 0;
} /* sem_wait */
int
sem_wait_nocancel (sem_t * sem)
/*
* ------------------------------------------------------
* DOCPUBLIC
* This function waits on a semaphore, and doesn't
* allow cancellation.
*
* PARAMETERS
* sem
* pointer to an instance of sem_t
*
* DESCRIPTION
* This function waits on a semaphore. If the
* semaphore value is greater than zero, it decreases
* its value by one. If the semaphore value is zero, then
* the calling thread (or process) is blocked until it can
* successfully decrease the value or until interrupted by
* a signal.
*
* RESULTS
* 0 successfully decreased semaphore,
* -1 failed, error in errno
* ERRNO
* EINVAL 'sem' is not a valid semaphore,
* ENOSYS semaphores are not supported,
* EINTR the function was interrupted by a signal,
* EDEADLK a deadlock condition was detected.
*
* ------------------------------------------------------
*/
{
int result = 0;
sem_t s = *sem;
pthread_testcancel();
if (s == NULL)
{
result = EINVAL;
}
else
{
if ((result = pthread_mutex_lock (&s->lock)) == 0)
{
int v;
/* See sem_destroy.c
*/
if (*sem == NULL)
{
(void) pthread_mutex_unlock (&s->lock);
errno = EINVAL;
return -1;
}
v = --s->value;
(void) pthread_mutex_unlock (&s->lock);
if (v < 0)
{
pte_osSemaphorePend(s->sem, NULL);
}
}
}
if (result != 0)
{
errno = result;
return -1;
}
return 0;
}
-114
View File
@@ -1,114 +0,0 @@
/*
* Module: semaphore.h
*
* Purpose:
* Semaphores aren't actually part of the PThreads standard.
* They are defined by the POSIX Standard:
*
* POSIX 1003.1b-1993 (POSIX.1b)
*
* --------------------------------------------------------------------------
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
* Copyright(C) 2008 Jason Schmidlapp
*
* Contact Email: jschmidlapp@users.sourceforge.net
*
*
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2005 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The original list of contributors to the Pthreads-win32 project
* is contained in the file CONTRIBUTORS.ptw32 included with the
* source code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined( SEMAPHORE_H )
#define SEMAPHORE_H
#if defined(_POSIX_SOURCE)
#define PTE_LEVEL 0
/* Early POSIX */
#endif
#if defined(INCLUDE_NP)
#undef PTE_LEVEL
#define PTE_LEVEL 2
/* Include Non-Portable extensions */
#endif
/*
*
*/
#define _POSIX_SEMAPHORES
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
typedef struct sem_t_ * sem_t;
int sem_init (sem_t * sem,
int pshared,
unsigned int value);
int sem_destroy (sem_t * sem);
int sem_trywait (sem_t * sem);
int sem_wait (sem_t * sem);
int sem_timedwait (sem_t * sem,
const struct timespec * abstime);
int sem_post (sem_t * sem);
int sem_post_multiple (sem_t * sem,
int count);
int sem_open (const char * name,
int oflag,
mode_t mode,
unsigned int value);
int sem_close (sem_t * sem);
int sem_unlink (const char * name);
int sem_getvalue (sem_t * sem,
int * sval);
#ifdef __cplusplus
} /* End of extern "C" */
#endif /* __cplusplus */
#endif /* !SEMAPHORE_H */
+50
View File
@@ -1,3 +1,53 @@
# v10.0.0
* add rapi sublibrary for communicating with server (eliminates need for client-side JSON parsing; client must still
provide HTTP functionality). rurl is now deprecated
* renamed 'rhash.h' to 'rc_hash.h' to eliminate conflict with system headers, renamed 'rconsoles.h' and 'rurl.h' for
consistency
* split non-runtime functions out of 'rcheevos.h' as they're not needed by most clients
* allow ranges in rich presence lookups
* add rc_richpresence_size_lines function to fetch line associated to error when processing rich presence script
* add rc_runtime_invalidate_address function to disable achievements when an unknown address is queried
* add RC_CONDITION_RESET_NEXT_IF
* add RC_CONDITION_SUB_HITS
* support MAXOF operator ($) for leaderboard values using trigger syntax
* allow RC_CONDITION_PAUSE_IF and RC_CONDITION_RESET_IF in leaderboard value expression
* changed track parameter of rc_hash_cdreader_open_track_handler to support three virtual tracks:
RC_HASH_CDTRACK_FIRST_DATA, RC_HASH_CDTRACK_LAST and RC_HASH_CDTRACK_LARGEST.
* changed offset parameter of rc_hash_filereader_seek_handler and return value of rc_hash_filereader_tell_handler
from size_t to int64_t to support files larger than 2GB when compiling in 32-bit mode.
* reset to default cd reader if NULL is passed to rc_hash_init_custom_cdreader
* add hash support for RC_CONSOLE_DREAMCAST, RC_CONSOLE_PLAYSTATION_2, RC_CONSOLE_SUPERVISION, and RC_CONSOLE_TIC80
* ignore headers when generating hashs for RC_CONSOLE_PC_ENGINE and RC_CONSOLE_ATARI_7800
* require unique identifier when hashing RC_CONSOLE_SEGA_CD and RC_CONSOLE_SATURN discs
* add expansion memory to RC_CONSOLE_SG1000 memory map
* rename RC_CONSOLE_MAGNAVOX_ODYSSEY -> RC_CONSOLE_MAGNAVOX_ODYSSEY2
* rename RC_CONSOLE_AMIGA_ST -> RC_CONSOLE_ATARI_ST
* add RC_CONSOLE_SUPERVISION, RC_CONSOLE_SHARPX1, RC_CONSOLE_TIC80, RC_CONSOLE_THOMSONTO8
* fix error identifying largest track when track has multiple bins
* fix memory corruption error when cue track has more than 6 INDEXs
* several improvements to data storage for conditions (rc_memref_t and rc_memref_value_t structures have been modified)
# v9.2.0
* fix issue identifying some PC-FX titles where the boot code is not in the first data track
* add enums and labels for RC_CONSOLE_MAGNAVOX_ODYSSEY, RC_CONSOLE_SUPER_CASSETTEVISION, RC_CONSOLE_NEO_GEO_CD,
RC_CONSOLE_FAIRCHILD_CHANNEL_F, RC_CONSOLE_FM_TOWNS, RC_CONSOLE_ZX_SPECTRUM, RC_CONSOLE_GAME_AND_WATCH,
RC_CONSOLE_NOKIA_NGAGE, RC_CONSOLE_NINTENDO_3DS
# v9.1.0
* add hash support and memory map for RC_CONSOLE_MSX
* add hash support and memory map for RC_CONSOLE_PCFX
* include parent directory when hashing non-arcade titles in arcade mode
* support absolute paths in m3u
* make cue scanning case-insensitive
* expand SRAM mapping for RC_CONSOLE_WONDERSWAN
* fix display of measured value when another group has an unmeasured hit count
* fix memory read error when hashing file with no extension
* fix possible divide by zero when using RC_CONDITION_ADD_SOURCE/RC_CONDITION_SUB_SOURCE
* fix classification of secondary RC_CONSOLE_SATURN memory region
# v9.0.0
* new size: RC_MEMSIZE_BITCOUNT
+69 -397
View File
@@ -2,17 +2,19 @@
**rcheevos** is a set of C code, or a library if you will, that tries to make it easier for emulators to process [RetroAchievements](https://retroachievements.org) data, providing support for achievements and leaderboards for their players.
Keep in mind that **rcheevos** does *not* provide HTTP network connections or JSON parsing. Clients must get data from RetroAchievements, parse the JSON payloads and pass the results down to **rcheevos** for processing. (**TODO**: document the server API and JSON schema.)
Keep in mind that **rcheevos** does *not* provide HTTP network connections. Clients must get data from RetroAchievements, and pass the response down to **rcheevos** for processing.
Not all structures defined by **rcheevos** can be created via the public API, but are exposed to allow interactions beyond just creation, destruction, and testing, such as the ones required by UI code that helps to create them.
Finally, **rcheevos** does *not* allocate or manage memory by itself. All structures that can be returned by it have a function to determine the number of bytes needed to hold the structure, and another one that actually builds the structure using a caller-provided buffer to bake it. However, calls to **rcheevos** may allocate and/or free memory as part of the Lua runtime, which is a dependency.
Finally, **rcheevos** does *not* allocate or manage memory by itself. All structures that can be returned by it have a function to determine the number of bytes needed to hold the structure, and another one that actually builds the structure using a caller-provided buffer to bake it.
## Lua
RetroAchievements has decided to support achievements written using the [Lua](https://www.lua.org) language. The current expression-based implementation was too limiting already for the Nintendo 64, and was preventing the support of other systems.
RetroAchievements is considering the use of the [Lua](https://www.lua.org) language to expand the syntax supported for creating achievements. The current expression-based implementation is often limiting on newer systems.
> **rcheevos** does *not* create or maintain a Lua state, you have to create your own state and provide it to **rcheevos** to be used when Lua-coded achievements are found.
At this point, to enable Lua support, you must compile with an additional compilation flag: `HAVE_LUA`, as neither the backend nor the UI for editing achievements are currently Lua-enabled.
> **rcheevos** does *not* create or maintain a Lua state, you have to create your own state and provide it to **rcheevos** to be used when Lua-coded achievements are found. Calls to **rcheevos** may allocate and/or free additional memory as part of the Lua runtime.
Lua functions used in trigger operands receive two parameters: `peek`, which is used to read from the emulated system's memory, and `userdata`, which must be passed to `peek`. `peek`'s signature is the same as its C counterpart:
@@ -22,7 +24,9 @@ function peek(address, num_bytes, userdata)
## API
> An understanding about how achievements are developed may be useful, you can read more about it [here](http://docs.retroachievements.org/Developer-docs/).
An understanding about how achievements are developed may be useful, you can read more about it [here](http://docs.retroachievements.org/Developer-docs/).
Most of the exposed APIs are documented [here](https://github.com/RetroAchievements/rcheevos/wiki)
### User Configuration
@@ -32,7 +36,9 @@ If your platform will benefit from a different value, define a new value for it
### Return values
The functions that compute the amount of memory that something will take return the number of bytes, or a negative value from the following enumeration:
Any function in the rcheevos library that returns a success indicator will return one of the following values.
These are in `rc_error.h`.
```c
enum {
@@ -60,7 +66,9 @@ enum {
RC_MISSING_VALUE_MEASURED = -21,
RC_MULTIPLE_MEASURED = -22,
RC_INVALID_MEASURED_TARGET = -23,
RC_INVALID_COMPARISON = -24
RC_INVALID_COMPARISON = -24,
RC_INVALID_STATE = -25,
RC_INVALID_JSON = -26
};
```
@@ -73,6 +81,8 @@ const char* rc_error_str(int ret);
This enumeration uniquely identifies each of the supported platforms in RetroAchievements.
These are in `rc_consoles.h`.
```c
enum {
RC_CONSOLE_MEGA_DRIVE = 1,
@@ -97,7 +107,7 @@ enum {
RC_CONSOLE_WII_U = 20,
RC_CONSOLE_PLAYSTATION_2 = 21,
RC_CONSOLE_XBOX = 22,
RC_CONSOLE_SKYNET = 23,
RC_CONSOLE_MAGNAVOX_ODYSSEY2 = 23,
RC_CONSOLE_POKEMON_MINI = 24,
RC_CONSOLE_ATARI_2600 = 25,
RC_CONSOLE_MS_DOS = 26,
@@ -110,7 +120,7 @@ enum {
RC_CONSOLE_SG1000 = 33,
RC_CONSOLE_VIC20 = 34,
RC_CONSOLE_AMIGA = 35,
RC_CONSOLE_AMIGA_ST = 36,
RC_CONSOLE_ATARI_ST = 36,
RC_CONSOLE_AMSTRAD_PC = 37,
RC_CONSOLE_APPLE_II = 38,
RC_CONSOLE_SATURN = 39,
@@ -129,338 +139,28 @@ enum {
RC_CONSOLE_X68K = 52,
RC_CONSOLE_WONDERSWAN = 53,
RC_CONSOLE_CASSETTEVISION = 54,
RC_CONSOLE_SUPER_CASSETTEVISION = 55
RC_CONSOLE_SUPER_CASSETTEVISION = 55,
RC_CONSOLE_NEO_GEO_CD = 56,
RC_CONSOLE_FAIRCHILD_CHANNEL_F = 57,
RC_CONSOLE_FM_TOWNS = 58,
RC_CONSOLE_ZX_SPECTRUM = 59,
RC_CONSOLE_GAME_AND_WATCH = 60,
RC_CONSOLE_NOKIA_NGAGE = 61,
RC_CONSOLE_NINTENDO_3DS = 62,
RC_CONSOLE_SUPERVISION = 63,
RC_CONSOLE_SHARPX1 = 64,
RC_CONSOLE_TIC80 = 65,
RC_CONSOLE_THOMSONTO8 = 66
};
```
### `rc_operand_t`
## Runtime support
An operand is the leaf node of RetroAchievements expressions, and can hold one of the following:
The runtime encapsulates a set of achievements, leaderboards, and rich presence for a game and manages processing them for each frame. When important things occur, events are raised for the caller via a callback.
* A constant integer or floating-point value
* A memory address of the system being emulated
* A reference to the Lua function that will be called to provide the value
These are in `rc_runtime.h`.
```c
typedef struct {
union {
/* A value read from memory. */
rc_memref_value_t* memref;
/* An integer value. */
unsigned num;
/* A floating point value. */
double dbl;
/* A reference to the Lua function that provides the value. */
int luafunc;
};
/* specifies which member of the value union is being used */
char type;
/* the actual RC_MEMSIZE of the operand - memref.size may differ */
char size;
}
rc_operand_t;
```
The `size` field, when applicable, holds one of these values:
```c
enum {
RC_MEMSIZE_8_BITS,
RC_MEMSIZE_16_BITS,
RC_MEMSIZE_24_BITS,
RC_MEMSIZE_32_BITS,
RC_MEMSIZE_LOW,
RC_MEMSIZE_HIGH,
RC_MEMSIZE_BIT_0,
RC_MEMSIZE_BIT_1,
RC_MEMSIZE_BIT_2,
RC_MEMSIZE_BIT_3,
RC_MEMSIZE_BIT_4,
RC_MEMSIZE_BIT_5,
RC_MEMSIZE_BIT_6,
RC_MEMSIZE_BIT_7,
RC_MEMSIZE_BITCOUNT
};
```
The `type` field is always valid, and holds one of these values:
```c
enum {
RC_OPERAND_ADDRESS, /* The value of a live address in RAM. */
RC_OPERAND_DELTA, /* The value last known at this address. */
RC_OPERAND_CONST, /* A 32-bit unsigned integer. */
RC_OPERAND_FP, /* A floating point value. */
RC_OPERAND_LUA, /* A Lua function that provides the value. */
RC_OPERAND_PRIOR, /* The last differing value at this address. */
RC_OPERAND_BCD, /* The BCD-decoded value of a live address in RAM */
RC_OPERAND_INVERTED /* The twos-complement value of a live address in RAM */
};
```
`RC_OPERAND_ADDRESS`, `RC_OPERAND_DELTA`, `RC_OPERAND_PRIOR`, `RC_OPERAND_BCD`, and `RC_OPERAND_INVERTED` mean that `memref` is active. `RC_OPERAND_CONST` means that `num` is active. `RC_OPERAND_FP` means that `dbl` is active. `RC_OPERAND_LUA` means `luafunc` is active.
### `rc_condition_t`
A condition compares its two operands according to the defined operator. It also keeps track of other things to make it possible to code more advanced achievements.
```c
typedef struct rc_condition_t rc_condition_t;
struct rc_condition_t {
/* The condition's operands. */
rc_operand_t operand1;
rc_operand_t operand2;
/* Required hits to fire this condition. */
unsigned required_hits;
/* Number of hits so far. */
unsigned current_hits;
/* The next condition in the chain. */
rc_condition_t* next;
/* The type of the condition. */
char type;
/* The comparison operator to use. */
char oper; /* operator is a reserved word in C++. */
/* Set if the condition needs to processed as part of the "check if paused" pass. */
char pause;
/* Whether or not the condition evaluated as true on the last check. */
char is_true;
};
```
`type` can be one of these values:
```c
enum {
RC_CONDITION_STANDARD,
RC_CONDITION_PAUSE_IF,
RC_CONDITION_RESET_IF,
RC_CONDITION_ADD_SOURCE,
RC_CONDITION_SUB_SOURCE,
RC_CONDITION_ADD_HITS,
RC_CONDITION_AND_NEXT,
RC_CONDITION_MEASURED,
RC_CONDITION_ADD_ADDRESS,
RC_CONDITION_TRIGGER,
RC_CONDITION_MEASURED_IF
};
```
`oper` is the comparison operator to be used when comparing the two operands:
```c
enum {
RC_OPERATOR_EQ,
RC_OPERATOR_LT,
RC_OPERATOR_LE,
RC_OPERATOR_GT,
RC_OPERATOR_GE,
RC_OPERATOR_NE,
RC_OPERATOR_NONE,
RC_OPERATOR_MULT,
RC_OPERATOR_DIV,
RC_OPERATOR_AND
};
```
### `rc_condset_t`
Condition sets are an ordered collection of conditions (`rc_condition_t`), which are usually and'ed together to help build complex expressions for achievements.
```c
typedef struct rc_condset_t rc_condset_t;
struct rc_condset_t {
/* The next condition set in the chain. */
rc_condset_t* next;
/* The list of conditions in this condition set. */
rc_condition_t* conditions;
/* True if any condition in the set is a pause condition. */
char has_pause;
};
```
### `rc_trigger_t`
Triggers are the basic blocks of achievements and leaderboards. In fact, achievements are just triggers with some additional information like title, description, a badge, and some state, like whether it has already been awarded or not. All the logic to test if an achievement should be awarded is encapsulated in `rc_trigger_t`.
```c
typedef struct {
/* The main condition set. */
rc_condset_t* requirement;
/* The list of sub condition sets in this test. */
rc_condset_t* alternative;
/* The memory references required by the trigger. */
rc_memref_value_t* memrefs;
}
rc_trigger_t;
```
The size in bytes of memory a trigger needs to be created is given by the `rc_trigger_size` function:
```c
int rc_trigger_size(const char* memaddr);
```
The return value is the size needed for the trigger described by the `memaddr` parameter, or a negative value with an [error code](#return-values).
Once the memory size is known, `rc_parse_trigger` can be called to actually construct a trigger in the caller-provided buffer:
```c
rc_trigger_t* rc_parse_trigger(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx);
```
`buffer` is the caller-allocated buffer, which must have enough space for the trigger. `memaddr` describes the trigger, and must be the same one used to compute the trigger's size with `rc_trigger_size`. `L` must be a valid Lua state, and `funcs_ndx` must be an index to the current Lua stack which contains a table which is a map of names to functions. This map is used to look for operands which are Lua functions.
Once the trigger is created, `rc_evaluate_trigger` can be called to test whether the trigger fires or not.
```c
int rc_evaluate_trigger(rc_trigger_t* trigger, rc_peek_t peek, void* ud, lua_State* L);
```
`trigger` is the trigger to test. `peek` is a callback used to read bytes from the emulated memory. `ud` is an user-provided opaque value that is passed to `peek`. `L` is the Lua state in which context the Lua functions are looked for and called, if necessary.
`rc_peek_t`'s signature is:
```c
typedef unsigned (*rc_peek_t)(unsigned address, unsigned num_bytes, void* ud);
```
where `address` is the starting address to read from, `num_bytes` the number of bytes to read (1, 2, or 4, little-endian), and `ud` is the same value passed to `rc_test_trigger`.
> Addresses passed to `peek` do *not* map 1:1 to the emulated memory. (**TODO**: document the mapping from `peek` addresses to emulated memory for each supported system.)
The return value of `rc_evaluate_trigger` is one of the following:
```c
enum {
RC_TRIGGER_STATE_INACTIVE, /* achievement is not being processed */
RC_TRIGGER_STATE_WAITING, /* achievement cannot trigger until it has been false for at least one frame */
RC_TRIGGER_STATE_ACTIVE, /* achievement is active and may trigger */
RC_TRIGGER_STATE_PAUSED, /* achievement is currently paused and will not trigger */
RC_TRIGGER_STATE_RESET, /* achievement hit counts were reset */
RC_TRIGGER_STATE_TRIGGERED, /* achievement has triggered */
RC_TRIGGER_STATE_PRIMED /* all non-Trigger conditions are true */
};
```
Finally, `rc_reset_trigger` can be used to reset the internal state of a trigger.
```c
void rc_reset_trigger(rc_trigger_t* self);
```
### `rc_value_t`
A value is a collection of conditions that result in a single RC_CONDITION_MEASURED expression. It's used to calculate the value for a leaderboard and for lookups in rich presence.
```c
typedef struct {
/* The list of conditions to evaluate. */
rc_condset_t* conditions;
/* The memory references required by the value. */
rc_memref_value_t* memrefs;
}
rc_value_t;
```
The size in bytes needed to create a value can be computed by `rc_value_size`:
```c
int rc_value_size(const char* memaddr);
```
With the size at hand, the caller can allocate the necessary memory and pass it to `rc_parse_value` to create the value:
```c
rc_value_t* rc_parse_value(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx);
```
`buffer`, `memaddr`, `L`, and `funcs_ndx` are the same as in [`rc_parse_trigger`](#rc_parse_trigger).
To compute the value, use `rc_evaluate_value`:
```c
int rc_evaluate_value(rc_value_t* value, rc_peek_t peek, void* ud, lua_State* L);
```
`value` is the value to compute the value of, and `peek`, `ud`, and `L`, are as in [`rc_test_trigger`](#rc_test_trigger).
### `rc_lboard_t`
Leaderboards track a value over time, starting when a trigger is fired. The leaderboard can be canceled depending on the value of another trigger, and submitted to the RetroAchievements server depending on a third trigger.
The value submitted comes from the `value` field. Values displayed to the player come from the `progress` field unless it's `NULL`, in which case it's the same as `value`.
```c
typedef struct {
rc_trigger_t start;
rc_trigger_t submit;
rc_trigger_t cancel;
rc_value_t value;
rc_value_t* progress;
rc_memref_value_t* memrefs;
char state;
}
rc_lboard_t;
```
Leaderboards are created and parsed just the same as triggers and values:
```c
int rc_lboard_size(const char* memaddr);
rc_lboard_t* rc_parse_lboard(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx);
```
A leaderboard can be evaluated with the `rc_evaluate_lboard` function:
```c
int rc_evaluate_lboard(rc_lboard_t* lboard, int* value, rc_peek_t peek, void* peek_ud, lua_State* L);
```
The function returns an action that must be performed by the caller, and `value` contains the value to be used for that action when the function returns. The action can be one of:
```c
enum {
RC_LBOARD_STATE_INACTIVE, /* leaderboard is not being processed */
RC_LBOARD_STATE_WAITING, /* leaderboard cannot activate until the start condition has been false for at least one frame */
RC_LBOARD_STATE_ACTIVE, /* leaderboard is active and may start */
RC_LBOARD_STATE_STARTED, /* leaderboard attempt in progress */
RC_LBOARD_STATE_CANCELED, /* leaderboard attempt canceled */
RC_LBOARD_STATE_TRIGGERED /* leaderboard attempt complete, value should be submitted */
};
```
The caller must keep track of these values and do the necessary actions:
* `RC_LBOARD_ACTIVE` and `RC_LBOARD_INACTIVE`: just signal that the leaderboard didn't change its state.
* `RC_LBOARD_STARTED`: indicates that the leaderboard has been started, so the caller can i.e. show a message for the player, and start showing its value in the UI.
* `RC_LBOARD_CANCELED`: the leaderboard has been canceled, and the caller can inform the user and stop showing its value.
* `RC_LBOARD_TRIGGERED`: the leaderboard has been finished, and the value must be submitted to the RetroAchievements server; the caller can also notify the player and stop showing the value in the UI.
`rc_reset_lboard` resets the leaderboard:
```c
void rc_reset_lboard(rc_lboard_t* lboard);
```
### `rc_runtime_t`
The runtime encapsulates a set of achievements and leaderboards and manages processing them for each frame. When important things occur, events are raised for the caller via a callback.
The `rc_runtime_t` structure uses several forward-defines. If you need access to the actual contents of any of the forward-defined structures, those definitions are in `rc_runtime_types.h`
```c
typedef struct rc_runtime_t {
@@ -473,11 +173,12 @@ typedef struct rc_runtime_t {
unsigned lboard_capacity;
rc_runtime_richpresence_t* richpresence;
char* richpresence_display_buffer;
char richpresence_update_timer;
rc_memref_value_t* memrefs;
rc_memref_value_t** next_memref;
rc_value_t* variables;
rc_value_t** next_variable;
}
rc_runtime_t;
```
@@ -496,7 +197,7 @@ int rc_runtime_activate_richpresence(rc_runtime_t* runtime, const char* script,
The runtime should be called once per frame to evaluate the state of the active achievements/leaderboards:
```c
void rc_runtime_do_frame(rc_runtime_t* runtime, rc_runtime_event_handler_t event_handler, rc_peek_t peek, void* ud, lua_State* L);
void rc_runtime_do_frame(rc_runtime_t* runtime, rc_runtime_event_handler_t event_handler, rc_runtime_peek_t peek, void* ud, lua_State* L);
```
The `event_handler` is a callback function that is called for each event that occurs when processing the frame.
@@ -531,6 +232,10 @@ The `event.type` field will be one of the following:
The leaderboard value has changed.
* RC_RUNTIME_EVENT_LBOARD_TRIGGERED (id=leaderboard id, value=leaderboard value)
The leaderboard's submit condition has been met and the user should be informed that a leaderboard attempt was successful. The value should be submitted.
* RC_RUNTIME_EVENT_ACHIEVEMENT_DISABLED (id=achievement id)
The achievement has been disabled by a call to `rc_invalidate_address`.
* RC_RUNTIME_EVENT_LBOARD_DISABLED (id=leaderboard id)
The achievement has been disabled by a call to `rc_invalidate_address`.
When an achievement triggers, it should be deactivated so it won't trigger again:
```c
@@ -538,7 +243,13 @@ void rc_runtime_deactivate_achievement(rc_runtime_t* runtime, unsigned id);
```
Additionally, the unlock should be submitted to the server.
When a leaderboard triggers, it should not be deactivated in case the player wants to try again for a better score. The value should be submitted to the server.
When a leaderboard triggers, it should not be deactivated in case the player wants to try again for a better score. The value should be submitted to the server.
For `RC_RUNTIME_EVENT_LBOARD_UPDATED` and `RC_RUNTIME_EVENT_LBOARD_TRIGGERED` events, there is a helper function to call if you wish to display the leaderboard value on screen.
```c
int rc_runtime_format_lboard_value(char* buffer, int size, int value, int format);
```
`rc_runtime_do_frame` also periodically updates the rich presense string (every 60 frames). To get the current value, call
```c
@@ -552,73 +263,34 @@ void rc_runtime_reset(rc_runtime_t* runtime);
This ensures any active achievements/leaderboards are set back to their initial states and prevents unexpected triggers when the memory changes in atypical way.
## Server Communication
### Value Formatting
**rapi** builds URLs to access many RetroAchievements web services. Its purpose it to just to free the developer from having to URL-encode parameters and build correct URLs that are valid for the server.
**rcheevos** includes helper functions to parse formatting strings from RetroAchievements, and format values according to them.
**rapi** does *not* make HTTP requests.
`rc_parse_format` returns the format for the given string:
NOTE: **rapi** is a replacement for **rurl**. **rurl** has been deprecated.
```c
int rc_parse_format(const char* format_str);
```
These are in `rc_api_user.h`, `rc_api_runtime.h` and `rc_api_common.h`.
The returned value is one of:
The basic process of making an **rapi** call is to initialize a params object, call a function to convert it to a URL, send that to the server, then pass the response to a function to convert it into a response object, and handle the response values.
```c
enum {
RC_FORMAT_FRAMES,
RC_FORMAT_SECONDS,
RC_FORMAT_CENTISECS,
RC_FORMAT_SCORE,
RC_FORMAT_VALUE,
RC_FORMAT_MINUTES,
RC_FORMAT_SECONDS_AS_MINUTES
};
```
`RC_FORMAT_VALUE` is returned if `format_str` doesn't contain a valid format.
`rc_format_value` can be used to format the given value into the provided buffer:
```c
int rc_format_value(char* buffer, int size, int value, int format);
```
`buffer` receives `value` formatted according to `format`. No more than `size` characters will be written to `buffer`. 32 characters are enough to hold any valid value with any format. The returned value is the number of characters written.
# **rurl**
**rurl** builds URLs to access many RetroAchievements web services. Its purpose it to just to free the developer from having to URL-encode parameters and build correct URL that are valid for the server.
**rurl** does *not* make HTTP requests.
## API
### Return values
All functions return `0` if successful, or `-1` in case of errors. Errors are usually because the provided buffer is too small to hold the URL. If your buffer is large and you're still receiving errors, please open an issue.
An example can be found on the [rc_api_init_login_request](https://github.com/RetroAchievements/rcheevos/wiki/rc_api_init_login_request#example) page.
### Functions
All functions take a `buffer`, where the URL will be written into, and `size` with the size of the buffer. The other parameters are particular to the desired URL.
Please see the [wiki](https://github.com/RetroAchievements/rcheevos/wiki) for details on the functions exposed for **rapi**.
## Game Identification
**rhash** provides logic for generating a RetroAchievements hash for a given game. There are two ways to use the API - you can pass the filename and let rhash open and process the file, or you can pass the buffered copy of the file to rhash if you've already loaded it into memory.
These are in `rc_hash.h`.
```c
int rc_url_award_cheevo(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned cheevo_id, int hardcore);
int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned lboard_id, unsigned value, unsigned char hash[16]);
int rc_url_get_gameid(char* buffer, size_t size, unsigned char hash[16]);
int rc_url_get_patch(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned gameid);
int rc_url_get_badge_image(char* buffer, size_t size, const char* badge_name);
int rc_url_login_with_password(char* buffer, size_t size, const char* user_name, const char* password);
int rc_url_login_with_token(char* buffer, size_t size, const char* user_name, const char* login_token);
int rc_url_get_unlock_list(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned gameid, int hardcore);
int rc_url_post_playing(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned gameid);
int rc_hash_generate_from_buffer(char hash[33], int console_id, uint8_t* buffer, size_t buffer_size);
int rc_hash_generate_from_file(char hash[33], int console_id, const char* path);
```
+63
View File
@@ -0,0 +1,63 @@
#ifndef RC_API_REQUEST_H
#define RC_API_REQUEST_H
#include "rc_error.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* A block of memory for variable length data (like strings and arrays).
*/
typedef struct rc_api_buffer_t {
/* The current location where data is being written */
char* write;
/* The first byte past the end of data where writing cannot occur */
char* end;
/* The next block in the allocated memory chain */
struct rc_api_buffer_t* next;
/* The buffer containing the data. The actual size may be larger than 256 bytes for buffers allocated in
* the next chain. The 256 byte size specified is for the initial allocation within the container object. */
char data[256];
}
rc_api_buffer_t;
/**
* A constructed request to send to the retroachievements server.
*/
typedef struct rc_api_request_t {
/* The URL to send the request to (contains protocol, host, path, and query args) */
const char* url;
/* Additional query args that should be sent via a POST command. If null, GET may be used */
const char* post_data;
/* Storage for the url and post_data */
rc_api_buffer_t buffer;
}
rc_api_request_t;
/**
* Common attributes for all server responses.
*/
typedef struct rc_api_response_t {
/* Server-provided success indicator (non-zero on failure) */
int succeeded;
/* Server-provided message associated to the failure */
const char* error_message;
/* Storage for the response data */
rc_api_buffer_t buffer;
}
rc_api_response_t;
void rc_api_destroy_request(rc_api_request_t* request);
void rc_api_set_host(const char* hostname);
void rc_api_set_image_host(const char* hostname);
#ifdef __cplusplus
}
#endif
#endif /* RC_API_REQUEST_H */
+284
View File
@@ -0,0 +1,284 @@
#ifndef RC_API_RUNTIME_H
#define RC_API_RUNTIME_H
#include "rc_api_request.h"
#include <time.h>
#ifdef __cplusplus
extern "C" {
#endif
/* --- Fetch Image --- */
/**
* API parameters for a fetch image request.
* NOTE: fetch image server response is the raw image data. There is no rc_api_process_fetch_image_response function.
*/
typedef struct rc_api_fetch_image_request_t {
/* The name of the image to fetch */
const char* image_name;
/* The type of image to fetch */
int image_type;
}
rc_api_fetch_image_request_t;
#define RC_IMAGE_TYPE_GAME 1
#define RC_IMAGE_TYPE_ACHIEVEMENT 2
#define RC_IMAGE_TYPE_ACHIEVEMENT_LOCKED 3
#define RC_IMAGE_TYPE_USER 4
int rc_api_init_fetch_image_request(rc_api_request_t* request, const rc_api_fetch_image_request_t* api_params);
/* --- Resolve Hash --- */
/**
* API parameters for a resolve hash request.
*/
typedef struct rc_api_resolve_hash_request_t {
/* The username of the player */
const char* username;
/* The API token from the login request */
const char* api_token;
/* The generated hash of the game to be identified */
const char* game_hash;
}
rc_api_resolve_hash_request_t;
/**
* Response data for a resolve hash request.
*/
typedef struct rc_api_resolve_hash_response_t {
/* The unique identifier of the game, 0 if no match was found */
unsigned game_id;
/* Common server-provided response information */
rc_api_response_t response;
}
rc_api_resolve_hash_response_t;
int rc_api_init_resolve_hash_request(rc_api_request_t* request, const rc_api_resolve_hash_request_t* api_params);
int rc_api_process_resolve_hash_response(rc_api_resolve_hash_response_t* response, const char* server_response);
void rc_api_destroy_resolve_hash_response(rc_api_resolve_hash_response_t* response);
/* --- Fetch Game Data --- */
/**
* API parameters for a fetch game data request.
*/
typedef struct rc_api_fetch_game_data_request_t {
/* The username of the player */
const char* username;
/* The API token from the login request */
const char* api_token;
/* The unique identifier of the game */
unsigned game_id;
}
rc_api_fetch_game_data_request_t;
/* A leaderboard definition */
typedef struct rc_api_leaderboard_definition_t {
/* The unique identifier of the leaderboard */
unsigned id;
/* The format to pass to rc_format_value to format the leaderboard value */
int format;
/* The title of the leaderboard */
const char* title;
/* The description of the leaderboard */
const char* description;
/* The definition of the leaderboard to be passed to rc_runtime_activate_lboard */
const char* definition;
}
rc_api_leaderboard_definition_t;
/* An achievement definition */
typedef struct rc_api_achievement_definition_t {
/* The unique identifier of the achievement */
unsigned id;
/* The number of points the achievement is worth */
unsigned points;
/* The achievement category (core, unofficial) */
unsigned category;
/* The title of the achievement */
const char* title;
/* The dscription of the achievement */
const char* description;
/* The definition of the achievement to be passed to rc_runtime_activate_achievement */
const char* definition;
/* The author of the achievment */
const char* author;
/* The image name for the achievement badge */
const char* badge_name;
/* When the achievement was first uploaded to the server */
time_t created;
/* When the achievement was last modified on the server */
time_t updated;
}
rc_api_achievement_definition_t;
#define RC_ACHIEVEMENT_CATEGORY_CORE 3
#define RC_ACHIEVEMENT_CATEGORY_UNOFFICIAL 5
/**
* Response data for a fetch game data request.
*/
typedef struct rc_api_fetch_game_data_response_t {
/* The unique identifier of the game */
unsigned id;
/* The console associated to the game */
unsigned console_id;
/* The title of the game */
const char* title;
/* The image name for the game badge */
const char* image_name;
/* The rich presence script for the game to be passed to rc_runtime_activate_richpresence */
const char* rich_presence_script;
/* An array of achievements for the game */
rc_api_achievement_definition_t* achievements;
/* The number of items in the achievements array */
unsigned num_achievements;
/* An array of leaderboards for the game */
rc_api_leaderboard_definition_t* leaderboards;
/* The number of items in the leaderboards array */
unsigned num_leaderboards;
/* Common server-provided response information */
rc_api_response_t response;
}
rc_api_fetch_game_data_response_t;
int rc_api_init_fetch_game_data_request(rc_api_request_t* request, const rc_api_fetch_game_data_request_t* api_params);
int rc_api_process_fetch_game_data_response(rc_api_fetch_game_data_response_t* response, const char* server_response);
void rc_api_destroy_fetch_game_data_response(rc_api_fetch_game_data_response_t* response);
/* --- Ping --- */
/**
* API parameters for a ping request.
*/
typedef struct rc_api_ping_request_t {
/* The username of the player */
const char* username;
/* The API token from the login request */
const char* api_token;
/* The unique identifier of the game */
unsigned game_id;
/* (optional) The current rich presence evaluation for the user */
const char* rich_presence;
}
rc_api_ping_request_t;
/**
* Response data for a ping request.
*/
typedef struct rc_api_ping_response_t {
/* Common server-provided response information */
rc_api_response_t response;
}
rc_api_ping_response_t;
int rc_api_init_ping_request(rc_api_request_t* request, const rc_api_ping_request_t* api_params);
int rc_api_process_ping_response(rc_api_ping_response_t* response, const char* server_response);
void rc_api_destroy_ping_response(rc_api_ping_response_t* response);
/* --- Award Achievement --- */
/**
* API parameters for an award achievement request.
*/
typedef struct rc_api_award_achievement_request_t {
/* The username of the player */
const char* username;
/* The API token from the login request */
const char* api_token;
/* The unique identifier of the achievement */
unsigned achievement_id;
/* Non-zero if the achievement was earned in hardcore */
int hardcore;
/* The hash associated to the game being played */
const char* game_hash;
}
rc_api_award_achievement_request_t;
/**
* Response data for an award achievement request.
*/
typedef struct rc_api_award_achievement_response_t {
/* The unique identifier of the achievement that was awarded */
unsigned awarded_achievement_id;
/* The updated player score */
unsigned new_player_score;
/* Common server-provided response information */
rc_api_response_t response;
}
rc_api_award_achievement_response_t;
int rc_api_init_award_achievement_request(rc_api_request_t* request, const rc_api_award_achievement_request_t* api_params);
int rc_api_process_award_achievement_response(rc_api_award_achievement_response_t* response, const char* server_response);
void rc_api_destroy_award_achievement_response(rc_api_award_achievement_response_t* response);
/* --- Submit Leaderboard Entry --- */
/**
* API parameters for a submit lboard entry request.
*/
typedef struct rc_api_submit_lboard_entry_request_t {
/* The username of the player */
const char* username;
/* The API token from the login request */
const char* api_token;
/* The unique identifier of the leaderboard */
unsigned leaderboard_id;
/* The value being submitted */
int score;
/* The hash associated to the game being played */
const char* game_hash;
}
rc_api_submit_lboard_entry_request_t;
/* A leaderboard entry */
typedef struct rc_api_lboard_entry_t {
/* The user associated to the entry */
const char* username;
/* The rank of the entry */
unsigned rank;
/* The value of the entry */
int score;
}
rc_api_lboard_entry_t;
/**
* Response data for a submit lboard entry request.
*/
typedef struct rc_api_submit_lboard_entry_response_t {
/* The value that was submitted */
int submitted_score;
/* The player's best submitted value */
int best_score;
/* The player's new rank within the leaderboard */
unsigned new_rank;
/* The total number of entries in the leaderboard */
unsigned num_entries;
/* An array of the top entries for the leaderboard */
rc_api_lboard_entry_t* top_entries;
/* The number of items in the top_entries array */
unsigned num_top_entries;
/* Common server-provided response information */
rc_api_response_t response;
}
rc_api_submit_lboard_entry_response_t;
int rc_api_init_submit_lboard_entry_request(rc_api_request_t* request, const rc_api_submit_lboard_entry_request_t* api_params);
int rc_api_process_submit_lboard_entry_response(rc_api_submit_lboard_entry_response_t* response, const char* server_response);
void rc_api_destroy_submit_lboard_entry_response(rc_api_submit_lboard_entry_response_t* response);
#ifdef __cplusplus
}
#endif
#endif /* RC_API_RUNTIME_H */
+115
View File
@@ -0,0 +1,115 @@
#ifndef RC_API_USER_H
#define RC_API_USER_H
#include "rc_api_request.h"
#ifdef __cplusplus
extern "C" {
#endif
/* --- Login --- */
/**
* API parameters for a login request.
* If both password and api_token are provided, api_token will be ignored.
*/
typedef struct rc_api_login_request_t {
/* The username of the player being logged in */
const char* username;
/* The API token from a previous login */
const char* api_token;
/* The player's password */
const char* password;
}
rc_api_login_request_t;
/**
* Response data for a login request.
*/
typedef struct rc_api_login_response_t {
/* The case-corrected username of the player */
const char* username;
/* The API token to use for all future requests */
const char* api_token;
/* The current score of the player */
unsigned score;
/* The number of unread messages waiting for the player on the web site */
unsigned num_unread_messages;
/* Common server-provided response information */
rc_api_response_t response;
}
rc_api_login_response_t;
int rc_api_init_login_request(rc_api_request_t* request, const rc_api_login_request_t* api_params);
int rc_api_process_login_response(rc_api_login_response_t* response, const char* server_response);
void rc_api_destroy_login_response(rc_api_login_response_t* response);
/* --- Start Session --- */
/**
* API parameters for a start session request.
*/
typedef struct rc_api_start_session_request_t {
/* The username of the player */
const char* username;
/* The API token from the login request */
const char* api_token;
/* The unique identifier of the game */
unsigned game_id;
}
rc_api_start_session_request_t;
/**
* Response data for a start session request.
*/
typedef struct rc_api_start_session_response_t {
/* Common server-provided response information */
rc_api_response_t response;
}
rc_api_start_session_response_t;
int rc_api_init_start_session_request(rc_api_request_t* request, const rc_api_start_session_request_t* api_params);
int rc_api_process_start_session_response(rc_api_start_session_response_t* response, const char* server_response);
void rc_api_destroy_start_session_response(rc_api_start_session_response_t* response);
/* --- Fetch User Unlocks --- */
/**
* API parameters for a fetch user unlocks request.
*/
typedef struct rc_api_fetch_user_unlocks_request_t {
/* The username of the player */
const char* username;
/* The API token from the login request */
const char* api_token;
/* The unique identifier of the game */
unsigned game_id;
/* Non-zero to fetch hardcore unlocks, 0 to fetch non-hardcore unlocks */
int hardcore;
}
rc_api_fetch_user_unlocks_request_t;
/**
* Response data for a fetch user unlocks request.
*/
typedef struct rc_api_fetch_user_unlocks_response_t {
/* An array of achievement IDs previously unlocked by the user */
unsigned* achievement_ids;
/* The number of items in the achievement_ids array */
unsigned num_achievement_ids;
/* Common server-provided response information */
rc_api_response_t response;
}
rc_api_fetch_user_unlocks_response_t;
int rc_api_init_fetch_user_unlocks_request(rc_api_request_t* request, const rc_api_fetch_user_unlocks_request_t* api_params);
int rc_api_process_fetch_user_unlocks_response(rc_api_fetch_user_unlocks_response_t* response, const char* server_response);
void rc_api_destroy_fetch_user_unlocks_response(rc_api_fetch_user_unlocks_response_t* response);
#ifdef __cplusplus
}
#endif
#endif /* RC_API_H */
+32
View File
@@ -83,6 +83,38 @@ enum {
const char* rc_console_name(int console_id);
/*****************************************************************************\
| Memory mapping |
\*****************************************************************************/
enum {
RC_MEMORY_TYPE_SYSTEM_RAM, /* normal system memory */
RC_MEMORY_TYPE_SAVE_RAM, /* memory that persists between sessions */
RC_MEMORY_TYPE_VIDEO_RAM, /* memory reserved for graphical processing */
RC_MEMORY_TYPE_READONLY, /* memory that maps to read only data */
RC_MEMORY_TYPE_HARDWARE_CONTROLLER, /* memory for interacting with system components */
RC_MEMORY_TYPE_VIRTUAL_RAM, /* secondary address space that maps to real memory in system RAM */
RC_MEMORY_TYPE_UNUSED /* these addresses don't really exist */
};
typedef struct rc_memory_region_t {
unsigned start_address; /* first address of block as queried by RetroAchievements */
unsigned end_address; /* last address of block as queried by RetroAchievements */
unsigned real_address; /* real address for first address of block */
char type; /* RC_MEMORY_TYPE_ for block */
const char* description; /* short description of block */
}
rc_memory_region_t;
typedef struct rc_memory_regions_t {
const rc_memory_region_t* region;
unsigned num_regions;
}
rc_memory_regions_t;
const rc_memory_regions_t* rc_console_memory_regions(int console_id);
#ifdef __cplusplus
}
#endif
+48
View File
@@ -0,0 +1,48 @@
#ifndef RC_ERROR_H
#define RC_ERROR_H
#ifdef __cplusplus
extern "C" {
#endif
/*****************************************************************************\
| Return values |
\*****************************************************************************/
enum {
RC_OK = 0,
RC_INVALID_LUA_OPERAND = -1,
RC_INVALID_MEMORY_OPERAND = -2,
RC_INVALID_CONST_OPERAND = -3,
RC_INVALID_FP_OPERAND = -4,
RC_INVALID_CONDITION_TYPE = -5,
RC_INVALID_OPERATOR = -6,
RC_INVALID_REQUIRED_HITS = -7,
RC_DUPLICATED_START = -8,
RC_DUPLICATED_CANCEL = -9,
RC_DUPLICATED_SUBMIT = -10,
RC_DUPLICATED_VALUE = -11,
RC_DUPLICATED_PROGRESS = -12,
RC_MISSING_START = -13,
RC_MISSING_CANCEL = -14,
RC_MISSING_SUBMIT = -15,
RC_MISSING_VALUE = -16,
RC_INVALID_LBOARD_FIELD = -17,
RC_MISSING_DISPLAY_STRING = -18,
RC_OUT_OF_MEMORY = -19,
RC_INVALID_VALUE_FLAG = -20,
RC_MISSING_VALUE_MEASURED = -21,
RC_MULTIPLE_MEASURED = -22,
RC_INVALID_MEASURED_TARGET = -23,
RC_INVALID_COMPARISON = -24,
RC_INVALID_STATE = -25,
RC_INVALID_JSON = -26
};
const char* rc_error_str(int ret);
#ifdef __cplusplus
}
#endif
#endif /* RC_ERROR_H */
+17 -9
View File
@@ -1,5 +1,5 @@
#ifndef RHASH_H
#define RHASH_H
#ifndef RC_HASH_H
#define RC_HASH_H
#include <stddef.h>
#include <stdio.h>
@@ -66,10 +66,10 @@ extern "C" {
typedef void* (*rc_hash_filereader_open_file_handler)(const char* path_utf8);
/* moves the file pointer - standard fseek parameters */
typedef void (*rc_hash_filereader_seek_handler)(void* file_handle, size_t offset, int origin);
typedef void (*rc_hash_filereader_seek_handler)(void* file_handle, int64_t offset, int origin);
/* locates the file pointer */
typedef size_t (*rc_hash_filereader_tell_handler)(void* file_handle);
typedef int64_t (*rc_hash_filereader_tell_handler)(void* file_handle);
/* reads the specified number of bytes from the file starting at the read pointer.
* returns the number of bytes actually read.
@@ -92,7 +92,11 @@ extern "C" {
/* ===================================================== */
/* opens a track from the specified file. track 0 indicates the first data track should be opened.
#define RC_HASH_CDTRACK_FIRST_DATA ((uint32_t)-1)
#define RC_HASH_CDTRACK_LAST ((uint32_t)-2)
#define RC_HASH_CDTRACK_LARGEST ((uint32_t)-3)
/* opens a track from the specified file. track 0 indicates the largest data track should be opened.
* returns a handle to be passed to the other functions, or NULL if the track could not be opened.
*/
typedef void* (*rc_hash_cdreader_open_track_handler)(const char* path, uint32_t track);
@@ -105,11 +109,15 @@ extern "C" {
/* closes the track handle */
typedef void (*rc_hash_cdreader_close_track_handler)(void* track_handle);
/* convert absolute sector to track sector */
typedef uint32_t(*rc_hash_cdreader_absolute_sector_to_track_sector)(void* track_handle, uint32_t sector);
struct rc_hash_cdreader
{
rc_hash_cdreader_open_track_handler open_track;
rc_hash_cdreader_read_sector_handler read_sector;
rc_hash_cdreader_close_track_handler close_track;
rc_hash_cdreader_open_track_handler open_track;
rc_hash_cdreader_read_sector_handler read_sector;
rc_hash_cdreader_close_track_handler close_track;
rc_hash_cdreader_absolute_sector_to_track_sector absolute_sector_to_track_sector;
};
void rc_hash_init_default_cdreader(void);
@@ -121,4 +129,4 @@ extern "C" {
}
#endif
#endif /* RHASH_H */
#endif /* RC_HASH_H */
+146
View File
@@ -0,0 +1,146 @@
#ifndef RC_RUNTIME_H
#define RC_RUNTIME_H
#ifdef __cplusplus
extern "C" {
#endif
#include "rc_error.h"
/*****************************************************************************\
| Forward Declarations (defined in rc_runtime_types.h) |
\*****************************************************************************/
#ifndef RC_RUNTIME_TYPES_H /* prevents pedantic redefinition error */
typedef struct lua_State lua_State;
typedef struct rc_trigger_t rc_trigger_t;
typedef struct rc_lboard_t rc_lboard_t;
typedef struct rc_richpresence_t rc_richpresence_t;
typedef struct rc_memref_t rc_memref_t;
typedef struct rc_value_t rc_value_t;
#endif
/*****************************************************************************\
| Callbacks |
\*****************************************************************************/
/**
* Callback used to read num_bytes bytes from memory starting at address. If
* num_bytes is greater than 1, the value is read in little-endian from
* memory.
*/
typedef unsigned (*rc_runtime_peek_t)(unsigned address, unsigned num_bytes, void* ud);
/*****************************************************************************\
| Runtime |
\*****************************************************************************/
typedef struct rc_runtime_trigger_t {
unsigned id;
rc_trigger_t* trigger;
void* buffer;
rc_memref_t* invalid_memref;
unsigned char md5[16];
int serialized_size;
char owns_memrefs;
}
rc_runtime_trigger_t;
typedef struct rc_runtime_lboard_t {
unsigned id;
int value;
rc_lboard_t* lboard;
void* buffer;
rc_memref_t* invalid_memref;
unsigned char md5[16];
char owns_memrefs;
}
rc_runtime_lboard_t;
typedef struct rc_runtime_richpresence_t {
rc_richpresence_t* richpresence;
void* buffer;
struct rc_runtime_richpresence_t* previous;
char owns_memrefs;
}
rc_runtime_richpresence_t;
typedef struct rc_runtime_t {
rc_runtime_trigger_t* triggers;
unsigned trigger_count;
unsigned trigger_capacity;
rc_runtime_lboard_t* lboards;
unsigned lboard_count;
unsigned lboard_capacity;
rc_runtime_richpresence_t* richpresence;
rc_memref_t* memrefs;
rc_memref_t** next_memref;
rc_value_t* variables;
rc_value_t** next_variable;
}
rc_runtime_t;
void rc_runtime_init(rc_runtime_t* runtime);
void rc_runtime_destroy(rc_runtime_t* runtime);
int rc_runtime_activate_achievement(rc_runtime_t* runtime, unsigned id, const char* memaddr, lua_State* L, int funcs_idx);
void rc_runtime_deactivate_achievement(rc_runtime_t* runtime, unsigned id);
rc_trigger_t* rc_runtime_get_achievement(const rc_runtime_t* runtime, unsigned id);
int rc_runtime_get_achievement_measured(const rc_runtime_t* runtime, unsigned id, unsigned* measured_value, unsigned* measured_target);
int rc_runtime_activate_lboard(rc_runtime_t* runtime, unsigned id, const char* memaddr, lua_State* L, int funcs_idx);
void rc_runtime_deactivate_lboard(rc_runtime_t* runtime, unsigned id);
rc_lboard_t* rc_runtime_get_lboard(const rc_runtime_t* runtime, unsigned id);
int rc_runtime_format_lboard_value(char* buffer, int size, int value, int format);
int rc_runtime_activate_richpresence(rc_runtime_t* runtime, const char* script, lua_State* L, int funcs_idx);
int rc_runtime_get_richpresence(const rc_runtime_t* runtime, char* buffer, unsigned buffersize, rc_runtime_peek_t peek, void* peek_ud, lua_State* L);
enum {
RC_RUNTIME_EVENT_ACHIEVEMENT_ACTIVATED, /* from WAITING, PAUSED, or PRIMED to ACTIVE */
RC_RUNTIME_EVENT_ACHIEVEMENT_PAUSED,
RC_RUNTIME_EVENT_ACHIEVEMENT_RESET,
RC_RUNTIME_EVENT_ACHIEVEMENT_TRIGGERED,
RC_RUNTIME_EVENT_ACHIEVEMENT_PRIMED,
RC_RUNTIME_EVENT_LBOARD_STARTED,
RC_RUNTIME_EVENT_LBOARD_CANCELED,
RC_RUNTIME_EVENT_LBOARD_UPDATED,
RC_RUNTIME_EVENT_LBOARD_TRIGGERED,
RC_RUNTIME_EVENT_ACHIEVEMENT_DISABLED,
RC_RUNTIME_EVENT_LBOARD_DISABLED,
RC_RUNTIME_EVENT_ACHIEVEMENT_UNPRIMED
};
typedef struct rc_runtime_event_t {
unsigned id;
int value;
char type;
}
rc_runtime_event_t;
typedef void (*rc_runtime_event_handler_t)(const rc_runtime_event_t* runtime_event);
void rc_runtime_do_frame(rc_runtime_t* runtime, rc_runtime_event_handler_t event_handler, rc_runtime_peek_t peek, void* ud, lua_State* L);
void rc_runtime_reset(rc_runtime_t* runtime);
typedef int (*rc_runtime_validate_address_t)(unsigned address);
void rc_runtime_validate_addresses(rc_runtime_t* runtime, rc_runtime_event_handler_t event_handler, rc_runtime_validate_address_t validate_handler);
void rc_runtime_invalidate_address(rc_runtime_t* runtime, unsigned address);
int rc_runtime_progress_size(const rc_runtime_t* runtime, lua_State* L);
int rc_runtime_serialize_progress(void* buffer, const rc_runtime_t* runtime, lua_State* L);
int rc_runtime_deserialize_progress(rc_runtime_t* runtime, const unsigned char* serialized, lua_State* L);
#ifdef __cplusplus
}
#endif
#endif /* RC_RUNTIME_H */
+400
View File
@@ -0,0 +1,400 @@
#ifndef RC_RUNTIME_TYPES_H
#define RC_RUNTIME_TYPES_H
#ifdef __cplusplus
extern "C" {
#endif
#include "rc_error.h"
#ifndef RC_RUNTIME_H /* prevents pedantic redefiniton error */
typedef struct lua_State lua_State;
typedef struct rc_trigger_t rc_trigger_t;
typedef struct rc_lboard_t rc_lboard_t;
typedef struct rc_richpresence_t rc_richpresence_t;
typedef struct rc_memref_t rc_memref_t;
typedef struct rc_value_t rc_value_t;
#endif
/*****************************************************************************\
| Callbacks |
\*****************************************************************************/
/**
* Callback used to read num_bytes bytes from memory starting at address. If
* num_bytes is greater than 1, the value is read in little-endian from
* memory.
*/
typedef unsigned (*rc_peek_t)(unsigned address, unsigned num_bytes, void* ud);
/*****************************************************************************\
| Memory References |
\*****************************************************************************/
/* Sizes. */
enum {
RC_MEMSIZE_8_BITS,
RC_MEMSIZE_16_BITS,
RC_MEMSIZE_24_BITS,
RC_MEMSIZE_32_BITS,
RC_MEMSIZE_LOW,
RC_MEMSIZE_HIGH,
RC_MEMSIZE_BIT_0,
RC_MEMSIZE_BIT_1,
RC_MEMSIZE_BIT_2,
RC_MEMSIZE_BIT_3,
RC_MEMSIZE_BIT_4,
RC_MEMSIZE_BIT_5,
RC_MEMSIZE_BIT_6,
RC_MEMSIZE_BIT_7,
RC_MEMSIZE_BITCOUNT,
RC_MEMSIZE_VARIABLE
};
typedef struct rc_memref_value_t {
/* The current value of this memory reference. */
unsigned value;
/* The last differing value of this memory reference. */
unsigned prior;
/* The size of the value. */
char size;
/* True if the value changed this frame. */
char changed;
/* True if the reference will be used in indirection.
* NOTE: This is actually a property of the rc_memref_t, but we put it here to save space */
char is_indirect;
}
rc_memref_value_t;
struct rc_memref_t {
/* The current value at the specified memory address. */
rc_memref_value_t value;
/* The memory address of this variable. */
unsigned address;
/* The next memory reference in the chain. */
rc_memref_t* next;
};
/*****************************************************************************\
| Operands |
\*****************************************************************************/
/* types */
enum {
RC_OPERAND_ADDRESS, /* The value of a live address in RAM. */
RC_OPERAND_DELTA, /* The value last known at this address. */
RC_OPERAND_CONST, /* A 32-bit unsigned integer. */
RC_OPERAND_FP, /* A floating point value. */
RC_OPERAND_LUA, /* A Lua function that provides the value. */
RC_OPERAND_PRIOR, /* The last differing value at this address. */
RC_OPERAND_BCD, /* The BCD-decoded value of a live address in RAM. */
RC_OPERAND_INVERTED /* The twos-complement value of a live address in RAM. */
};
typedef struct rc_operand_t {
union {
/* A value read from memory. */
rc_memref_t* memref;
/* An integer value. */
unsigned num;
/* A floating point value. */
double dbl;
/* A reference to the Lua function that provides the value. */
int luafunc;
} value;
/* specifies which member of the value union is being used */
char type;
/* the actual RC_MEMSIZE of the operand - memref.size may differ */
char size;
}
rc_operand_t;
int rc_operand_is_memref(rc_operand_t* operand);
/*****************************************************************************\
| Conditions |
\*****************************************************************************/
/* types */
enum {
/* NOTE: this enum is ordered to optimize the switch statements in rc_test_condset_internal. the values may change between releases */
/* non-combining conditions (third switch) */
RC_CONDITION_STANDARD, /* this should always be 0 */
RC_CONDITION_PAUSE_IF,
RC_CONDITION_RESET_IF,
RC_CONDITION_MEASURED_IF,
RC_CONDITION_TRIGGER,
RC_CONDITION_MEASURED, /* measured also appears in the first switch, so place it at the border between them */
/* modifiers (first switch) */
RC_CONDITION_ADD_SOURCE, /* everything from this point on affects the condition after it */
RC_CONDITION_SUB_SOURCE,
RC_CONDITION_ADD_ADDRESS,
/* logic flags (second switch) */
RC_CONDITION_ADD_HITS,
RC_CONDITION_SUB_HITS,
RC_CONDITION_RESET_NEXT_IF,
RC_CONDITION_AND_NEXT,
RC_CONDITION_OR_NEXT
};
/* operators */
enum {
RC_OPERATOR_EQ,
RC_OPERATOR_LT,
RC_OPERATOR_LE,
RC_OPERATOR_GT,
RC_OPERATOR_GE,
RC_OPERATOR_NE,
RC_OPERATOR_NONE,
RC_OPERATOR_MULT,
RC_OPERATOR_DIV,
RC_OPERATOR_AND
};
typedef struct rc_condition_t rc_condition_t;
struct rc_condition_t {
/* The condition's operands. */
rc_operand_t operand1;
rc_operand_t operand2;
/* Required hits to fire this condition. */
unsigned required_hits;
/* Number of hits so far. */
unsigned current_hits;
/* The next condition in the chain. */
rc_condition_t* next;
/* The type of the condition. */
char type;
/* The comparison operator to use. */
char oper; /* operator is a reserved word in C++. */
/* Set if the condition needs to processed as part of the "check if paused" pass. */
char pause;
/* Whether or not the condition evaluated true on the last check */
char is_true;
};
/*****************************************************************************\
| Condition sets |
\*****************************************************************************/
typedef struct rc_condset_t rc_condset_t;
struct rc_condset_t {
/* The next condition set in the chain. */
rc_condset_t* next;
/* The list of conditions in this condition set. */
rc_condition_t* conditions;
/* True if any condition in the set is a pause condition. */
char has_pause;
/* True if the set is currently paused. */
char is_paused;
/* True if the set has indirect memory references. */
char has_indirect_memrefs;
};
/*****************************************************************************\
| Trigger |
\*****************************************************************************/
enum {
RC_TRIGGER_STATE_INACTIVE, /* achievement is not being processed */
RC_TRIGGER_STATE_WAITING, /* achievement cannot trigger until it has been false for at least one frame */
RC_TRIGGER_STATE_ACTIVE, /* achievement is active and may trigger */
RC_TRIGGER_STATE_PAUSED, /* achievement is currently paused and will not trigger */
RC_TRIGGER_STATE_RESET, /* achievement hit counts were reset */
RC_TRIGGER_STATE_TRIGGERED, /* achievement has triggered */
RC_TRIGGER_STATE_PRIMED, /* all non-Trigger conditions are true */
RC_TRIGGER_STATE_DISABLED /* achievement cannot be processed at this time */
};
struct rc_trigger_t {
/* The main condition set. */
rc_condset_t* requirement;
/* The list of sub condition sets in this test. */
rc_condset_t* alternative;
/* The memory references required by the trigger. */
rc_memref_t* memrefs;
/* The current state of the MEASURED condition. */
unsigned measured_value;
/* The target state of the MEASURED condition */
unsigned measured_target;
/* The current state of the trigger */
char state;
/* True if at least one condition has a non-zero hit count */
char has_hits;
/* True if at least one condition has a non-zero required hit count */
char has_required_hits;
};
int rc_trigger_size(const char* memaddr);
rc_trigger_t* rc_parse_trigger(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx);
int rc_evaluate_trigger(rc_trigger_t* trigger, rc_peek_t peek, void* ud, lua_State* L);
int rc_test_trigger(rc_trigger_t* trigger, rc_peek_t peek, void* ud, lua_State* L);
void rc_reset_trigger(rc_trigger_t* self);
/*****************************************************************************\
| Values |
\*****************************************************************************/
struct rc_value_t {
/* The current value of the variable. */
rc_memref_value_t value;
/* The list of conditions to evaluate. */
rc_condset_t* conditions;
/* The memory references required by the value. */
rc_memref_t* memrefs;
/* The name of the variable. */
const char* name;
/* The next variable in the chain. */
rc_value_t* next;
};
int rc_value_size(const char* memaddr);
rc_value_t* rc_parse_value(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx);
int rc_evaluate_value(rc_value_t* value, rc_peek_t peek, void* ud, lua_State* L);
/*****************************************************************************\
| Leaderboards |
\*****************************************************************************/
/* Return values for rc_evaluate_lboard. */
enum {
RC_LBOARD_STATE_INACTIVE, /* leaderboard is not being processed */
RC_LBOARD_STATE_WAITING, /* leaderboard cannot activate until the start condition has been false for at least one frame */
RC_LBOARD_STATE_ACTIVE, /* leaderboard is active and may start */
RC_LBOARD_STATE_STARTED, /* leaderboard attempt in progress */
RC_LBOARD_STATE_CANCELED, /* leaderboard attempt canceled */
RC_LBOARD_STATE_TRIGGERED, /* leaderboard attempt complete, value should be submitted */
RC_LBOARD_STATE_DISABLED /* leaderboard cannot be processed at this time */
};
struct rc_lboard_t {
rc_trigger_t start;
rc_trigger_t submit;
rc_trigger_t cancel;
rc_value_t value;
rc_value_t* progress;
rc_memref_t* memrefs;
char state;
};
int rc_lboard_size(const char* memaddr);
rc_lboard_t* rc_parse_lboard(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx);
int rc_evaluate_lboard(rc_lboard_t* lboard, int* value, rc_peek_t peek, void* peek_ud, lua_State* L);
void rc_reset_lboard(rc_lboard_t* lboard);
/*****************************************************************************\
| Value formatting |
\*****************************************************************************/
/* Supported formats. */
enum {
RC_FORMAT_FRAMES,
RC_FORMAT_SECONDS,
RC_FORMAT_CENTISECS,
RC_FORMAT_SCORE,
RC_FORMAT_VALUE,
RC_FORMAT_MINUTES,
RC_FORMAT_SECONDS_AS_MINUTES
};
int rc_parse_format(const char* format_str);
int rc_format_value(char* buffer, int size, int value, int format);
/*****************************************************************************\
| Rich Presence |
\*****************************************************************************/
typedef struct rc_richpresence_lookup_item_t rc_richpresence_lookup_item_t;
struct rc_richpresence_lookup_item_t {
unsigned first;
unsigned last;
rc_richpresence_lookup_item_t* left;
rc_richpresence_lookup_item_t* right;
const char* label;
};
typedef struct rc_richpresence_lookup_t rc_richpresence_lookup_t;
struct rc_richpresence_lookup_t {
rc_richpresence_lookup_item_t* root;
rc_richpresence_lookup_t* next;
const char* name;
const char* default_label;
unsigned short format;
};
typedef struct rc_richpresence_display_part_t rc_richpresence_display_part_t;
struct rc_richpresence_display_part_t {
rc_richpresence_display_part_t* next;
const char* text;
rc_richpresence_lookup_t* lookup;
rc_memref_value_t *value;
unsigned short display_type;
};
typedef struct rc_richpresence_display_t rc_richpresence_display_t;
struct rc_richpresence_display_t {
rc_trigger_t trigger;
rc_richpresence_display_t* next;
rc_richpresence_display_part_t* display;
};
struct rc_richpresence_t {
rc_richpresence_display_t* first_display;
rc_richpresence_lookup_t* first_lookup;
rc_memref_t* memrefs;
rc_value_t* variables;
};
int rc_richpresence_size(const char* script);
int rc_richpresence_size_lines(const char* script, int* lines_read);
rc_richpresence_t* rc_parse_richpresence(void* buffer, const char* script, lua_State* L, int funcs_ndx);
int rc_evaluate_richpresence(rc_richpresence_t* richpresence, char* buffer, unsigned buffersize, rc_peek_t peek, void* peek_ud, lua_State* L);
void rc_update_richpresence(rc_richpresence_t* richpresence, rc_peek_t peek, void* peek_ud, lua_State* L);
int rc_get_richpresence_display_string(rc_richpresence_t* richpresence, char* buffer, unsigned buffersize, rc_peek_t peek, void* peek_ud, lua_State* L);
#ifdef __cplusplus
}
#endif
#endif /* RC_RUNTIME_TYPES_H */
@@ -1,5 +1,5 @@
#ifndef RURL_H
#define RURL_H
#ifndef RC_URL_H
#define RC_URL_H
#include <stddef.h>
@@ -32,4 +32,4 @@ int rc_url_ping(char* url_buffer, size_t url_buffer_size, char* post_buffer, siz
}
#endif
#endif /* RURL_H */
#endif /* RC_URL_H */
+3 -508
View File
@@ -1,513 +1,8 @@
#ifndef RCHEEVOS_H
#define RCHEEVOS_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct lua_State lua_State;
/*****************************************************************************\
| Return values |
\*****************************************************************************/
enum {
RC_OK = 0,
RC_INVALID_LUA_OPERAND = -1,
RC_INVALID_MEMORY_OPERAND = -2,
RC_INVALID_CONST_OPERAND = -3,
RC_INVALID_FP_OPERAND = -4,
RC_INVALID_CONDITION_TYPE = -5,
RC_INVALID_OPERATOR = -6,
RC_INVALID_REQUIRED_HITS = -7,
RC_DUPLICATED_START = -8,
RC_DUPLICATED_CANCEL = -9,
RC_DUPLICATED_SUBMIT = -10,
RC_DUPLICATED_VALUE = -11,
RC_DUPLICATED_PROGRESS = -12,
RC_MISSING_START = -13,
RC_MISSING_CANCEL = -14,
RC_MISSING_SUBMIT = -15,
RC_MISSING_VALUE = -16,
RC_INVALID_LBOARD_FIELD = -17,
RC_MISSING_DISPLAY_STRING = -18,
RC_OUT_OF_MEMORY = -19,
RC_INVALID_VALUE_FLAG = -20,
RC_MISSING_VALUE_MEASURED = -21,
RC_MULTIPLE_MEASURED = -22,
RC_INVALID_MEASURED_TARGET = -23,
RC_INVALID_COMPARISON = -24,
RC_INVALID_STATE = -25
};
const char* rc_error_str(int ret);
/*****************************************************************************\
| Callbacks |
\*****************************************************************************/
/**
* Callback used to read num_bytes bytes from memory starting at address. If
* num_bytes is greater than 1, the value is read in little-endian from
* memory.
*/
typedef unsigned (*rc_peek_t)(unsigned address, unsigned num_bytes, void* ud);
/*****************************************************************************\
| Memory References |
\*****************************************************************************/
/* Sizes. */
enum {
RC_MEMSIZE_8_BITS,
RC_MEMSIZE_16_BITS,
RC_MEMSIZE_24_BITS,
RC_MEMSIZE_32_BITS,
RC_MEMSIZE_LOW,
RC_MEMSIZE_HIGH,
RC_MEMSIZE_BIT_0,
RC_MEMSIZE_BIT_1,
RC_MEMSIZE_BIT_2,
RC_MEMSIZE_BIT_3,
RC_MEMSIZE_BIT_4,
RC_MEMSIZE_BIT_5,
RC_MEMSIZE_BIT_6,
RC_MEMSIZE_BIT_7,
RC_MEMSIZE_BITCOUNT
};
typedef struct {
/* The memory address of this variable. */
unsigned address;
/* The size of the variable. */
char size;
/* True if the reference will be used in indirection */
char is_indirect;
} rc_memref_t;
typedef struct rc_memref_value_t rc_memref_value_t;
struct rc_memref_value_t {
/* The value of this memory reference. */
unsigned value;
/* The previous value of this memory reference. */
unsigned previous;
/* The last differing value of this memory reference. */
unsigned prior;
/* The referenced memory */
rc_memref_t memref;
/* The next memory reference in the chain */
rc_memref_value_t* next;
};
/*****************************************************************************\
| Operands |
\*****************************************************************************/
/* types */
enum {
RC_OPERAND_ADDRESS, /* The value of a live address in RAM. */
RC_OPERAND_DELTA, /* The value last known at this address. */
RC_OPERAND_CONST, /* A 32-bit unsigned integer. */
RC_OPERAND_FP, /* A floating point value. */
RC_OPERAND_LUA, /* A Lua function that provides the value. */
RC_OPERAND_PRIOR, /* The last differing value at this address. */
RC_OPERAND_BCD, /* The BCD-decoded value of a live address in RAM */
RC_OPERAND_INVERTED /* The twos-complement value of a live address in RAM */
};
typedef struct {
union {
/* A value read from memory. */
rc_memref_value_t* memref;
/* An integer value. */
unsigned num;
/* A floating point value. */
double dbl;
/* A reference to the Lua function that provides the value. */
int luafunc;
} value;
/* specifies which member of the value union is being used */
char type;
/* the actual RC_MEMSIZE of the operand - memref.size may differ */
char size;
}
rc_operand_t;
/*****************************************************************************\
| Conditions |
\*****************************************************************************/
/* types */
enum {
RC_CONDITION_STANDARD,
RC_CONDITION_PAUSE_IF,
RC_CONDITION_RESET_IF,
RC_CONDITION_ADD_SOURCE,
RC_CONDITION_SUB_SOURCE,
RC_CONDITION_ADD_HITS,
RC_CONDITION_AND_NEXT,
RC_CONDITION_MEASURED,
RC_CONDITION_ADD_ADDRESS,
RC_CONDITION_OR_NEXT,
RC_CONDITION_TRIGGER,
RC_CONDITION_MEASURED_IF
};
/* operators */
enum {
RC_OPERATOR_EQ,
RC_OPERATOR_LT,
RC_OPERATOR_LE,
RC_OPERATOR_GT,
RC_OPERATOR_GE,
RC_OPERATOR_NE,
RC_OPERATOR_NONE,
RC_OPERATOR_MULT,
RC_OPERATOR_DIV,
RC_OPERATOR_AND
};
typedef struct rc_condition_t rc_condition_t;
struct rc_condition_t {
/* The condition's operands. */
rc_operand_t operand1;
rc_operand_t operand2;
/* Required hits to fire this condition. */
unsigned required_hits;
/* Number of hits so far. */
unsigned current_hits;
/* The next condition in the chain. */
rc_condition_t* next;
/* The type of the condition. */
char type;
/* The comparison operator to use. */
char oper; /* operator is a reserved word in C++. */
/* Set if the condition needs to processed as part of the "check if paused" pass. */
char pause;
/* Whether or not the condition evaluated true on the last check */
char is_true;
};
/*****************************************************************************\
| Condition sets |
\*****************************************************************************/
typedef struct rc_condset_t rc_condset_t;
struct rc_condset_t {
/* The next condition set in the chain. */
rc_condset_t* next;
/* The list of conditions in this condition set. */
rc_condition_t* conditions;
/* True if any condition in the set is a pause condition. */
char has_pause;
/* True if the set is currently paused. */
char is_paused;
};
/*****************************************************************************\
| Trigger |
\*****************************************************************************/
enum {
RC_TRIGGER_STATE_INACTIVE, /* achievement is not being processed */
RC_TRIGGER_STATE_WAITING, /* achievement cannot trigger until it has been false for at least one frame */
RC_TRIGGER_STATE_ACTIVE, /* achievement is active and may trigger */
RC_TRIGGER_STATE_PAUSED, /* achievement is currently paused and will not trigger */
RC_TRIGGER_STATE_RESET, /* achievement hit counts were reset */
RC_TRIGGER_STATE_TRIGGERED, /* achievement has triggered */
RC_TRIGGER_STATE_PRIMED /* all non-Trigger conditions are true */
};
typedef struct {
/* The main condition set. */
rc_condset_t* requirement;
/* The list of sub condition sets in this test. */
rc_condset_t* alternative;
/* The memory references required by the trigger. */
rc_memref_value_t* memrefs;
/* The current state of the MEASURED condition. */
unsigned measured_value;
/* The target state of the MEASURED condition */
unsigned measured_target;
/* The current state of the trigger */
char state;
/* True if at least one condition has a non-zero hit count */
char has_hits;
}
rc_trigger_t;
int rc_trigger_size(const char* memaddr);
rc_trigger_t* rc_parse_trigger(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx);
int rc_evaluate_trigger(rc_trigger_t* trigger, rc_peek_t peek, void* ud, lua_State* L);
int rc_test_trigger(rc_trigger_t* trigger, rc_peek_t peek, void* ud, lua_State* L);
void rc_reset_trigger(rc_trigger_t* self);
/*****************************************************************************\
| Values |
\*****************************************************************************/
typedef struct {
/* The list of conditions to evaluate. */
rc_condset_t* conditions;
/* The memory references required by the value. */
rc_memref_value_t* memrefs;
}
rc_value_t;
int rc_value_size(const char* memaddr);
rc_value_t* rc_parse_value(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx);
int rc_evaluate_value(rc_value_t* value, rc_peek_t peek, void* ud, lua_State* L);
/*****************************************************************************\
| Leaderboards |
\*****************************************************************************/
/* Return values for rc_evaluate_lboard. */
enum {
RC_LBOARD_STATE_INACTIVE, /* leaderboard is not being processed */
RC_LBOARD_STATE_WAITING, /* leaderboard cannot activate until the start condition has been false for at least one frame */
RC_LBOARD_STATE_ACTIVE, /* leaderboard is active and may start */
RC_LBOARD_STATE_STARTED, /* leaderboard attempt in progress */
RC_LBOARD_STATE_CANCELED, /* leaderboard attempt canceled */
RC_LBOARD_STATE_TRIGGERED /* leaderboard attempt complete, value should be submitted */
};
typedef struct {
rc_trigger_t start;
rc_trigger_t submit;
rc_trigger_t cancel;
rc_value_t value;
rc_value_t* progress;
rc_memref_value_t* memrefs;
char state;
}
rc_lboard_t;
int rc_lboard_size(const char* memaddr);
rc_lboard_t* rc_parse_lboard(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx);
int rc_evaluate_lboard(rc_lboard_t* lboard, int* value, rc_peek_t peek, void* peek_ud, lua_State* L);
void rc_reset_lboard(rc_lboard_t* lboard);
/*****************************************************************************\
| Value formatting |
\*****************************************************************************/
/* Supported formats. */
enum {
RC_FORMAT_FRAMES,
RC_FORMAT_SECONDS,
RC_FORMAT_CENTISECS,
RC_FORMAT_SCORE,
RC_FORMAT_VALUE,
RC_FORMAT_MINUTES,
RC_FORMAT_SECONDS_AS_MINUTES
};
int rc_parse_format(const char* format_str);
int rc_format_value(char* buffer, int size, int value, int format);
/*****************************************************************************\
| Rich Presence |
\*****************************************************************************/
typedef struct rc_richpresence_lookup_item_t rc_richpresence_lookup_item_t;
struct rc_richpresence_lookup_item_t {
unsigned value;
rc_richpresence_lookup_item_t* next_item;
const char* label;
};
typedef struct rc_richpresence_lookup_t rc_richpresence_lookup_t;
struct rc_richpresence_lookup_t {
rc_richpresence_lookup_item_t* first_item;
rc_richpresence_lookup_t* next;
const char* name;
unsigned short format;
};
typedef struct rc_richpresence_display_part_t rc_richpresence_display_part_t;
struct rc_richpresence_display_part_t {
rc_richpresence_display_part_t* next;
const char* text;
rc_richpresence_lookup_item_t* first_lookup_item;
rc_value_t value;
unsigned short display_type;
};
typedef struct rc_richpresence_display_t rc_richpresence_display_t;
struct rc_richpresence_display_t {
rc_trigger_t trigger;
rc_richpresence_display_t* next;
rc_richpresence_display_part_t* display;
};
typedef struct {
rc_richpresence_display_t* first_display;
rc_richpresence_lookup_t* first_lookup;
rc_memref_value_t* memrefs;
}
rc_richpresence_t;
int rc_richpresence_size(const char* script);
rc_richpresence_t* rc_parse_richpresence(void* buffer, const char* script, lua_State* L, int funcs_ndx);
int rc_evaluate_richpresence(rc_richpresence_t* richpresence, char* buffer, unsigned buffersize, rc_peek_t peek, void* peek_ud, lua_State* L);
/*****************************************************************************\
| Runtime |
\*****************************************************************************/
typedef struct rc_runtime_trigger_t {
unsigned id;
rc_trigger_t* trigger;
void* buffer;
unsigned char md5[16];
int serialized_size;
char owns_memrefs;
}
rc_runtime_trigger_t;
typedef struct rc_runtime_lboard_t {
unsigned id;
int value;
rc_lboard_t* lboard;
void* buffer;
unsigned char md5[16];
char owns_memrefs;
}
rc_runtime_lboard_t;
typedef struct rc_runtime_richpresence_t {
rc_richpresence_t* richpresence;
void* buffer;
struct rc_runtime_richpresence_t* previous;
char owns_memrefs;
}
rc_runtime_richpresence_t;
typedef struct rc_runtime_t {
rc_runtime_trigger_t* triggers;
unsigned trigger_count;
unsigned trigger_capacity;
rc_runtime_lboard_t* lboards;
unsigned lboard_count;
unsigned lboard_capacity;
rc_runtime_richpresence_t* richpresence;
char* richpresence_display_buffer;
char richpresence_update_timer;
rc_memref_value_t* memrefs;
rc_memref_value_t** next_memref;
}
rc_runtime_t;
void rc_runtime_init(rc_runtime_t* runtime);
void rc_runtime_destroy(rc_runtime_t* runtime);
int rc_runtime_activate_achievement(rc_runtime_t* runtime, unsigned id, const char* memaddr, lua_State* L, int funcs_idx);
void rc_runtime_deactivate_achievement(rc_runtime_t* runtime, unsigned id);
rc_trigger_t* rc_runtime_get_achievement(const rc_runtime_t* runtime, unsigned id);
int rc_runtime_activate_lboard(rc_runtime_t* runtime, unsigned id, const char* memaddr, lua_State* L, int funcs_idx);
void rc_runtime_deactivate_lboard(rc_runtime_t* runtime, unsigned id);
rc_lboard_t* rc_runtime_get_lboard(const rc_runtime_t* runtime, unsigned id);
int rc_runtime_activate_richpresence(rc_runtime_t* runtime, const char* script, lua_State* L, int funcs_idx);
const char* rc_runtime_get_richpresence(const rc_runtime_t* runtime);
enum {
RC_RUNTIME_EVENT_ACHIEVEMENT_ACTIVATED, /* from WAITING, PAUSED, or PRIMED to ACTIVE */
RC_RUNTIME_EVENT_ACHIEVEMENT_PAUSED,
RC_RUNTIME_EVENT_ACHIEVEMENT_RESET,
RC_RUNTIME_EVENT_ACHIEVEMENT_TRIGGERED,
RC_RUNTIME_EVENT_ACHIEVEMENT_PRIMED,
RC_RUNTIME_EVENT_LBOARD_STARTED,
RC_RUNTIME_EVENT_LBOARD_CANCELED,
RC_RUNTIME_EVENT_LBOARD_UPDATED,
RC_RUNTIME_EVENT_LBOARD_TRIGGERED
};
typedef struct rc_runtime_event_t {
unsigned id;
int value;
char type;
}
rc_runtime_event_t;
typedef void (*rc_runtime_event_handler_t)(const rc_runtime_event_t* runtime_event);
void rc_runtime_do_frame(rc_runtime_t* runtime, rc_runtime_event_handler_t event_handler, rc_peek_t peek, void* ud, lua_State* L);
void rc_runtime_reset(rc_runtime_t* runtime);
int rc_runtime_progress_size(const rc_runtime_t* runtime, lua_State* L);
int rc_runtime_serialize_progress(void* buffer, const rc_runtime_t* runtime, lua_State* L);
int rc_runtime_deserialize_progress(rc_runtime_t* runtime, const unsigned char* serialized, lua_State* L);
/*****************************************************************************\
| Memory mapping |
\*****************************************************************************/
enum {
RC_MEMORY_TYPE_SYSTEM_RAM, /* normal system memory */
RC_MEMORY_TYPE_SAVE_RAM, /* memory that persists between sessions */
RC_MEMORY_TYPE_VIDEO_RAM, /* memory reserved for graphical processing */
RC_MEMORY_TYPE_READONLY, /* memory that maps to read only data */
RC_MEMORY_TYPE_HARDWARE_CONTROLLER, /* memory for interacting with system components */
RC_MEMORY_TYPE_VIRTUAL_RAM, /* secondary address space that maps to real memory in system RAM */
RC_MEMORY_TYPE_UNUSED /* these addresses don't really exist */
};
typedef struct rc_memory_region_t {
unsigned start_address; /* first address of block as queried by RetroAchievements */
unsigned end_address; /* last address of block as queried by RetroAchievements */
unsigned real_address; /* real address for first address of block */
char type; /* RC_MEMORY_TYPE_ for block */
const char* description; /* short description of block */
}
rc_memory_region_t;
typedef struct rc_memory_regions_t {
const rc_memory_region_t* region;
unsigned num_regions;
}
rc_memory_regions_t;
const rc_memory_regions_t* rc_console_memory_regions(int console_id);
#ifdef __cplusplus
}
#endif
#include "rc_runtime.h"
#include "rc_runtime_types.h"
#include "rc_consoles.h"
#endif /* RCHEEVOS_H */
File diff suppressed because it is too large. Load diff
+70
View File
@@ -0,0 +1,70 @@
#ifndef RC_API_COMMON_H
#define RC_API_COMMON_H
#include "rc_api_request.h"
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct rc_api_url_builder_t {
char* write;
char* start;
char* end;
rc_api_buffer_t* buffer;
int result;
}
rc_api_url_builder_t;
void rc_url_builder_init(rc_api_url_builder_t* builder, rc_api_buffer_t* buffer, size_t estimated_size);
void rc_url_builder_append(rc_api_url_builder_t* builder, const char* data, size_t len);
const char* rc_url_builder_finalize(rc_api_url_builder_t* builder);
typedef struct rc_json_field_t {
const char* name;
const char* value_start;
const char* value_end;
unsigned array_size;
}
rc_json_field_t;
int rc_json_parse_response(rc_api_response_t* response, const char* json, rc_json_field_t* fields, size_t field_count);
int rc_json_get_string(const char** out, rc_api_buffer_t* buffer, const rc_json_field_t* field, const char* field_name);
int rc_json_get_num(int* out, const rc_json_field_t* field, const char* field_name);
int rc_json_get_unum(unsigned* out, const rc_json_field_t* field, const char* field_name);
int rc_json_get_bool(int* out, const rc_json_field_t* field, const char* field_name);
void rc_json_get_optional_string(const char** out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name, const char* default_value);
void rc_json_get_optional_num(int* out, const rc_json_field_t* field, const char* field_name, int default_value);
void rc_json_get_optional_unum(unsigned* out, const rc_json_field_t* field, const char* field_name, int default_value);
void rc_json_get_optional_bool(int* out, const rc_json_field_t* field, const char* field_name, int default_value);
int rc_json_get_required_string(const char** out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
int rc_json_get_required_num(int* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
int rc_json_get_required_unum(unsigned* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
int rc_json_get_required_bool(int* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
int rc_json_get_required_object(rc_json_field_t* fields, size_t field_count, rc_api_response_t* response, rc_json_field_t* field, const char* field_name);
int rc_json_get_required_unum_array(unsigned** entries, unsigned* num_entries, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
int rc_json_get_required_array(unsigned* num_entries, rc_json_field_t* iterator, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
int rc_json_get_array_entry_object(rc_json_field_t* fields, size_t field_count, rc_json_field_t* iterator);
void rc_buf_init(rc_api_buffer_t* buffer);
void rc_buf_destroy(rc_api_buffer_t* buffer);
char* rc_buf_reserve(rc_api_buffer_t* buffer, size_t amount);
void rc_buf_consume(rc_api_buffer_t* buffer, const char* start, char* end);
void* rc_buf_alloc(rc_api_buffer_t* buffer, size_t amount);
void rc_url_builder_append_encoded_str(rc_api_url_builder_t* builder, const char* str);
void rc_url_builder_append_num_param(rc_api_url_builder_t* builder, const char* param, int value);
void rc_url_builder_append_unum_param(rc_api_url_builder_t* builder, const char* param, unsigned value);
void rc_url_builder_append_str_param(rc_api_url_builder_t* builder, const char* param, const char* value);
void rc_api_url_build_dorequest_url(rc_api_request_t* request);
int rc_api_url_build_dorequest(rc_api_url_builder_t* builder, const char* api, const char* username, const char* api_token);
void rc_api_generate_checksum(char checksum[33], const char* data);
#ifdef __cplusplus
}
#endif
#endif /* RC_API_COMMON_H */
+506
View File
@@ -0,0 +1,506 @@
#include "rc_api_runtime.h"
#include "rc_api_common.h"
#include "rc_runtime.h"
#include "rc_runtime_types.h"
#include "../rcheevos/rc_compat.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* --- Resolve Hash --- */
int rc_api_init_resolve_hash_request(rc_api_request_t* request, const rc_api_resolve_hash_request_t* api_params) {
rc_api_url_builder_t builder;
rc_api_url_build_dorequest_url(request);
if (!api_params->game_hash || !*api_params->game_hash)
return RC_INVALID_STATE;
rc_url_builder_init(&builder, &request->buffer, 48);
if (rc_api_url_build_dorequest(&builder, "gameid", api_params->username, api_params->api_token)) {
rc_url_builder_append_str_param(&builder, "m", api_params->game_hash);
request->post_data = rc_url_builder_finalize(&builder);
}
return builder.result;
}
int rc_api_process_resolve_hash_response(rc_api_resolve_hash_response_t* response, const char* server_response) {
int result;
rc_json_field_t fields[] = {
{"Success"},
{"Error"},
{"GameID"},
};
memset(response, 0, sizeof(*response));
rc_buf_init(&response->response.buffer);
result = rc_json_parse_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
if (result != RC_OK)
return result;
rc_json_get_required_unum(&response->game_id, &response->response, &fields[2], "GameID");
return RC_OK;
}
void rc_api_destroy_resolve_hash_response(rc_api_resolve_hash_response_t* response) {
rc_buf_destroy(&response->response.buffer);
}
/* --- Fetch Game Data --- */
int rc_api_init_fetch_game_data_request(rc_api_request_t* request, const rc_api_fetch_game_data_request_t* api_params) {
rc_api_url_builder_t builder;
rc_api_url_build_dorequest_url(request);
if (api_params->game_id == 0)
return RC_INVALID_STATE;
rc_url_builder_init(&builder, &request->buffer, 48);
if (rc_api_url_build_dorequest(&builder, "patch", api_params->username, api_params->api_token)) {
rc_url_builder_append_unum_param(&builder, "g", api_params->game_id);
request->post_data = rc_url_builder_finalize(&builder);
}
return builder.result;
}
int rc_api_process_fetch_game_data_response(rc_api_fetch_game_data_response_t* response, const char* server_response) {
rc_api_achievement_definition_t* achievement;
rc_api_leaderboard_definition_t* leaderboard;
rc_json_field_t iterator;
const char* str;
const char* last_author = "";
size_t last_author_len = 0;
size_t len;
unsigned timet;
int result;
char format[16];
rc_json_field_t fields[] = {
{"Success"},
{"Error"},
{"PatchData"} /* nested object */
};
rc_json_field_t patchdata_fields[] = {
{"ID"},
{"Title"},
{"ConsoleID"},
{"ImageIcon"},
{"RichPresencePatch"},
{"Achievements"}, /* array */
{"Leaderboards"} /* array */
/* unused fields
{"ForumTopicID"},
{"Flags"},
* unused fields */
};
rc_json_field_t achievement_fields[] = {
{"ID"},
{"Title"},
{"Description"},
{"Flags"},
{"Points"},
{"MemAddr"},
{"Author"},
{"BadgeName"},
{"Created"},
{"Modified"}
};
rc_json_field_t leaderboard_fields[] = {
{"ID"},
{"Title"},
{"Description"},
{"Mem"},
{"Format"}
};
memset(response, 0, sizeof(*response));
rc_buf_init(&response->response.buffer);
result = rc_json_parse_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
if (result != RC_OK)
return result;
if (!rc_json_get_required_object(patchdata_fields, sizeof(patchdata_fields) / sizeof(patchdata_fields[0]), &response->response, &fields[2], "Response"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_unum(&response->id, &response->response, &patchdata_fields[0], "ID"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_string(&response->title, &response->response, &patchdata_fields[1], "Title"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_unum(&response->console_id, &response->response, &patchdata_fields[2], "ConsoleID"))
return RC_MISSING_VALUE;
/* ImageIcon will be '/Images/0123456.png' - only return the '0123456' */
if (patchdata_fields[3].value_end) {
str = patchdata_fields[3].value_end - 5;
if (memcmp(str, ".png\"", 5) == 0) {
patchdata_fields[3].value_end -= 5;
while (str > patchdata_fields[3].value_start && str[-1] != '/')
--str;
patchdata_fields[3].value_start = str;
}
}
rc_json_get_optional_string(&response->image_name, &response->response, &patchdata_fields[3], "ImageIcon", "");
/* estimate the amount of space necessary to store the rich presence script, achievements, and leaderboards.
determine how much space each takes as a string in the JSON, then subtract out the non-data (field names, punctuation)
and add space for the structures. */
len = patchdata_fields[4].value_end - patchdata_fields[4].value_start; /* rich presence */
len += (patchdata_fields[5].value_end - patchdata_fields[5].value_start) - /* achievements */
patchdata_fields[5].array_size * (130 - sizeof(rc_api_achievement_definition_t));
len += (patchdata_fields[6].value_end - patchdata_fields[6].value_start) - /* leaderboards */
patchdata_fields[6].array_size * (60 - sizeof(rc_api_leaderboard_definition_t));
rc_buf_reserve(&response->response.buffer, len);
/* end estimation */
rc_json_get_optional_string(&response->rich_presence_script, &response->response, &patchdata_fields[4], "RichPresencePatch", "");
if (!response->rich_presence_script)
response->rich_presence_script = "";
if (!rc_json_get_required_array(&response->num_achievements, &iterator, &response->response, &patchdata_fields[5], "Achievements"))
return RC_MISSING_VALUE;
if (response->num_achievements) {
response->achievements = (rc_api_achievement_definition_t*)rc_buf_alloc(&response->response.buffer, response->num_achievements * sizeof(rc_api_achievement_definition_t));
if (!response->achievements)
return RC_OUT_OF_MEMORY;
achievement = response->achievements;
while (rc_json_get_array_entry_object(achievement_fields, sizeof(achievement_fields) / sizeof(achievement_fields[0]), &iterator)) {
if (!rc_json_get_required_unum(&achievement->id, &response->response, &achievement_fields[0], "ID"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_string(&achievement->title, &response->response, &achievement_fields[1], "Title"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_string(&achievement->description, &response->response, &achievement_fields[2], "Description"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_unum(&achievement->category, &response->response, &achievement_fields[3], "Flags"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_unum(&achievement->points, &response->response, &achievement_fields[4], "Points"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_string(&achievement->definition, &response->response, &achievement_fields[5], "MemAddr"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_string(&achievement->badge_name, &response->response, &achievement_fields[7], "BadgeName"))
return RC_MISSING_VALUE;
len = achievement_fields[7].value_end - achievement_fields[7].value_start;
if (len == last_author_len && memcmp(achievement_fields[7].value_start, last_author, len) == 0) {
achievement->author = last_author;
}
else {
if (!rc_json_get_required_string(&achievement->author, &response->response, &achievement_fields[6], "Author"))
return RC_MISSING_VALUE;
last_author = achievement->author;
last_author_len = len;
}
if (!rc_json_get_required_unum(&timet, &response->response, &achievement_fields[8], "Created"))
return RC_MISSING_VALUE;
achievement->created = (time_t)timet;
if (!rc_json_get_required_unum(&timet, &response->response, &achievement_fields[9], "Modified"))
return RC_MISSING_VALUE;
achievement->updated = (time_t)timet;
++achievement;
}
}
if (!rc_json_get_required_array(&response->num_leaderboards, &iterator, &response->response, &patchdata_fields[6], "Leaderboards"))
return RC_MISSING_VALUE;
if (response->num_leaderboards) {
response->leaderboards = (rc_api_leaderboard_definition_t*)rc_buf_alloc(&response->response.buffer, response->num_leaderboards * sizeof(rc_api_leaderboard_definition_t));
if (!response->leaderboards)
return RC_OUT_OF_MEMORY;
leaderboard = response->leaderboards;
while (rc_json_get_array_entry_object(leaderboard_fields, sizeof(leaderboard_fields) / sizeof(leaderboard_fields[0]), &iterator)) {
if (!rc_json_get_required_unum(&leaderboard->id, &response->response, &leaderboard_fields[0], "ID"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_string(&leaderboard->title, &response->response, &leaderboard_fields[1], "Title"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_string(&leaderboard->description, &response->response, &leaderboard_fields[2], "Description"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_string(&leaderboard->definition, &response->response, &leaderboard_fields[3], "Mem"))
return RC_MISSING_VALUE;
if (!leaderboard_fields[4].value_end)
return RC_MISSING_VALUE;
len = leaderboard_fields[4].value_end - leaderboard_fields[4].value_start - 2;
if (len < sizeof(format) - 1) {
memcpy(format, leaderboard_fields[4].value_start + 1, len);
format[len] = '\0';
leaderboard->format = rc_parse_format(format);
}
else {
leaderboard->format = RC_FORMAT_VALUE;
}
++leaderboard;
}
}
return RC_OK;
}
void rc_api_destroy_fetch_game_data_response(rc_api_fetch_game_data_response_t* response) {
rc_buf_destroy(&response->response.buffer);
}
/* --- Ping --- */
int rc_api_init_ping_request(rc_api_request_t* request, const rc_api_ping_request_t* api_params) {
rc_api_url_builder_t builder;
rc_api_url_build_dorequest_url(request);
if (api_params->game_id == 0)
return RC_INVALID_STATE;
rc_url_builder_init(&builder, &request->buffer, 48);
if (rc_api_url_build_dorequest(&builder, "ping", api_params->username, api_params->api_token)) {
rc_url_builder_append_unum_param(&builder, "g", api_params->game_id);
if (api_params->rich_presence && *api_params->rich_presence)
rc_url_builder_append_str_param(&builder, "m", api_params->rich_presence);
request->post_data = rc_url_builder_finalize(&builder);
}
return builder.result;
}
int rc_api_process_ping_response(rc_api_ping_response_t* response, const char* server_response) {
rc_json_field_t fields[] = {
{"Success"},
{"Error"}
};
memset(response, 0, sizeof(*response));
rc_buf_init(&response->response.buffer);
return rc_json_parse_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
}
void rc_api_destroy_ping_response(rc_api_ping_response_t* response) {
rc_buf_destroy(&response->response.buffer);
}
/* --- Award Achievement --- */
int rc_api_init_award_achievement_request(rc_api_request_t* request, const rc_api_award_achievement_request_t* api_params) {
rc_api_url_builder_t builder;
char signature[128];
char checksum[33];
rc_api_url_build_dorequest_url(request);
if (api_params->achievement_id == 0)
return RC_INVALID_STATE;
rc_url_builder_init(&builder, &request->buffer, 96);
if (rc_api_url_build_dorequest(&builder, "awardachievement", api_params->username, api_params->api_token)) {
rc_url_builder_append_unum_param(&builder, "a", api_params->achievement_id);
rc_url_builder_append_unum_param(&builder, "h", api_params->hardcore ? 1 : 0);
if (api_params->game_hash && *api_params->game_hash)
rc_url_builder_append_str_param(&builder, "m", api_params->game_hash);
/* Evaluate the signature. */
snprintf(signature, sizeof(signature), "%u%s%u", api_params->achievement_id, api_params->username, api_params->hardcore ? 1 : 0);
rc_api_generate_checksum(checksum, signature);
rc_url_builder_append_str_param(&builder, "v", checksum);
request->post_data = rc_url_builder_finalize(&builder);
}
return builder.result;
}
int rc_api_process_award_achievement_response(rc_api_award_achievement_response_t* response, const char* server_response) {
int result;
rc_json_field_t fields[] = {
{"Success"},
{"Error"},
{"Score"},
{"AchievementID"}
};
memset(response, 0, sizeof(*response));
rc_buf_init(&response->response.buffer);
result = rc_json_parse_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
if (result != RC_OK)
return result;
if (!response->response.succeeded) {
if (response->response.error_message &&
memcmp(response->response.error_message, "User already has", 16) == 0) {
/* not really an error, the achievement is unlocked, just not by the current call.
* hardcore: User already has hardcore and regular achievements awarded.
* non-hardcore: User already has this achievement awarded.
*/
response->response.succeeded = 1;
} else {
return result;
}
}
rc_json_get_optional_unum(&response->new_player_score, &fields[2], "Score", 0);
rc_json_get_optional_unum(&response->awarded_achievement_id, &fields[3], "AchievementID", 0);
return RC_OK;
}
void rc_api_destroy_award_achievement_response(rc_api_award_achievement_response_t* response) {
rc_buf_destroy(&response->response.buffer);
}
/* --- Submit Leaderboard Entry --- */
int rc_api_init_submit_lboard_entry_request(rc_api_request_t* request, const rc_api_submit_lboard_entry_request_t* api_params) {
rc_api_url_builder_t builder;
char signature[128];
char checksum[33];
rc_api_url_build_dorequest_url(request);
if (api_params->leaderboard_id == 0)
return RC_INVALID_STATE;
rc_url_builder_init(&builder, &request->buffer, 96);
if (rc_api_url_build_dorequest(&builder, "submitlbentry", api_params->username, api_params->api_token)) {
rc_url_builder_append_unum_param(&builder, "i", api_params->leaderboard_id);
rc_url_builder_append_num_param(&builder, "s", api_params->score);
if (api_params->game_hash && *api_params->game_hash)
rc_url_builder_append_str_param(&builder, "m", api_params->game_hash);
/* Evaluate the signature. */
snprintf(signature, sizeof(signature), "%u%s%d", api_params->leaderboard_id, api_params->username, api_params->score);
rc_api_generate_checksum(checksum, signature);
rc_url_builder_append_str_param(&builder, "v", checksum);
request->post_data = rc_url_builder_finalize(&builder);
}
return builder.result;
}
int rc_api_process_submit_lboard_entry_response(rc_api_submit_lboard_entry_response_t* response, const char* server_response) {
rc_api_lboard_entry_t* entry;
rc_json_field_t iterator;
const char* str;
int result;
rc_json_field_t fields[] = {
{"Success"},
{"Error"},
{"Response"} /* nested object */
};
rc_json_field_t response_fields[] = {
{"Score"},
{"BestScore"},
{"RankInfo"}, /* nested object */
{"TopEntries"} /* array */
/* unused fields
{"LBData"}, / * array * /
{"ScoreFormatted"},
{"TopEntriesFriends"}, / * array * /
* unused fields */
};
/* unused fields
rc_json_field_t lbdata_fields[] = {
{"Format"},
{"LeaderboardID"},
{"GameID"},
{"Title"},
{"LowerIsBetter"}
};
* unused fields */
rc_json_field_t entry_fields[] = {
{"User"},
{"Rank"},
{"Score"}
/* unused fields
{ "DateSumitted" },
* unused fields */
};
rc_json_field_t rank_info_fields[] = {
{"Rank"},
{"NumEntries"}
/* unused fields
{"LowerIsBetter"},
{"UserRank"},
* unused fields */
};
memset(response, 0, sizeof(*response));
rc_buf_init(&response->response.buffer);
result = rc_json_parse_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
if (result != RC_OK)
return result;
if (!rc_json_get_required_object(response_fields, sizeof(response_fields) / sizeof(response_fields[0]), &response->response, &fields[2], "Response"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_num(&response->submitted_score, &response->response, &response_fields[0], "Score"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_num(&response->best_score, &response->response, &response_fields[1], "BestScore"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_object(rank_info_fields, sizeof(rank_info_fields) / sizeof(rank_info_fields[0]), &response->response, &response_fields[2], "RankInfo"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_unum(&response->new_rank, &response->response, &rank_info_fields[0], "Rank"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_string(&str, &response->response, &rank_info_fields[1], "NumEntries"))
return RC_MISSING_VALUE;
response->num_entries = (unsigned)atoi(str);
if (!rc_json_get_required_array(&response->num_top_entries, &iterator, &response->response, &response_fields[3], "TopEntries"))
return RC_MISSING_VALUE;
if (response->num_top_entries) {
response->top_entries = (rc_api_lboard_entry_t*)rc_buf_alloc(&response->response.buffer, response->num_top_entries * sizeof(rc_api_lboard_entry_t));
if (!response->top_entries)
return RC_OUT_OF_MEMORY;
entry = response->top_entries;
while (rc_json_get_array_entry_object(entry_fields, sizeof(entry_fields) / sizeof(entry_fields[0]), &iterator)) {
if (!rc_json_get_required_string(&entry->username, &response->response, &entry_fields[0], "User"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_unum(&entry->rank, &response->response, &entry_fields[1], "Rank"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_num(&entry->score, &response->response, &entry_fields[2], "Score"))
return RC_MISSING_VALUE;
++entry;
}
}
return RC_OK;
}
void rc_api_destroy_submit_lboard_entry_response(rc_api_submit_lboard_entry_response_t* response) {
rc_buf_destroy(&response->response.buffer);
}
+150
View File
@@ -0,0 +1,150 @@
#include "rc_api_user.h"
#include "rc_api_common.h"
#include <string.h>
/* --- Login --- */
int rc_api_init_login_request(rc_api_request_t* request, const rc_api_login_request_t* api_params) {
rc_api_url_builder_t builder;
rc_api_url_build_dorequest_url(request);
if (!api_params->username || !*api_params->username)
return RC_INVALID_STATE;
rc_url_builder_init(&builder, &request->buffer, 48);
rc_url_builder_append_str_param(&builder, "r", "login");
rc_url_builder_append_str_param(&builder, "u", api_params->username);
if (api_params->password && api_params->password[0])
rc_url_builder_append_str_param(&builder, "p", api_params->password);
else if (api_params->api_token && api_params->api_token[0])
rc_url_builder_append_str_param(&builder, "t", api_params->api_token);
else
return RC_INVALID_STATE;
request->post_data = rc_url_builder_finalize(&builder);
return builder.result;
}
int rc_api_process_login_response(rc_api_login_response_t* response, const char* server_response) {
int result;
rc_json_field_t fields[] = {
{"Success"},
{"Error"},
{"User"},
{"Token"},
{"Score"},
{"Messages"}
};
memset(response, 0, sizeof(*response));
rc_buf_init(&response->response.buffer);
result = rc_json_parse_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
if (result != RC_OK || !response->response.succeeded)
return result;
if (!rc_json_get_required_string(&response->username, &response->response, &fields[2], "User"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_string(&response->api_token, &response->response, &fields[3], "Token"))
return RC_MISSING_VALUE;
rc_json_get_optional_unum(&response->score, &fields[4], "Score", 0);
rc_json_get_optional_unum(&response->num_unread_messages, &fields[5], "Messages", 0);
return RC_OK;
}
void rc_api_destroy_login_response(rc_api_login_response_t* response) {
rc_buf_destroy(&response->response.buffer);
}
/* --- Start Session --- */
int rc_api_init_start_session_request(rc_api_request_t* request, const rc_api_start_session_request_t* api_params) {
rc_api_url_builder_t builder;
rc_api_url_build_dorequest_url(request);
if (api_params->game_id == 0)
return RC_INVALID_STATE;
rc_url_builder_init(&builder, &request->buffer, 48);
if (rc_api_url_build_dorequest(&builder, "postactivity", api_params->username, api_params->api_token)) {
/* activity type enum (only 3 is used )
* 1 = earned achievement - handled by awardachievement
* 2 = logged in - handled by login
* 3 = started playing
* 4 = uploaded achievement - handled by uploadachievement
* 5 = modified achievement - handled by uploadachievement
*/
rc_url_builder_append_unum_param(&builder, "a", 3);
rc_url_builder_append_unum_param(&builder, "m", api_params->game_id);
request->post_data = rc_url_builder_finalize(&builder);
}
return builder.result;
}
int rc_api_process_start_session_response(rc_api_start_session_response_t* response, const char* server_response) {
rc_json_field_t fields[] = {
{"Success"},
{"Error"}
};
memset(response, 0, sizeof(*response));
rc_buf_init(&response->response.buffer);
return rc_json_parse_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
}
void rc_api_destroy_start_session_response(rc_api_start_session_response_t* response) {
rc_buf_destroy(&response->response.buffer);
}
/* --- Fetch User Unlocks --- */
int rc_api_init_fetch_user_unlocks_request(rc_api_request_t* request, const rc_api_fetch_user_unlocks_request_t* api_params) {
rc_api_url_builder_t builder;
rc_api_url_build_dorequest_url(request);
rc_url_builder_init(&builder, &request->buffer, 48);
if (rc_api_url_build_dorequest(&builder, "unlocks", api_params->username, api_params->api_token)) {
rc_url_builder_append_unum_param(&builder, "g", api_params->game_id);
rc_url_builder_append_unum_param(&builder, "h", api_params->hardcore ? 1 : 0);
request->post_data = rc_url_builder_finalize(&builder);
}
return builder.result;
}
int rc_api_process_fetch_user_unlocks_response(rc_api_fetch_user_unlocks_response_t* response, const char* server_response) {
int result;
rc_json_field_t fields[] = {
{"Success"},
{"Error"},
{"UserUnlocks"}
/* unused fields
{ "GameID" },
{ "HardcoreMode" }
* unused fields */
};
memset(response, 0, sizeof(*response));
rc_buf_init(&response->response.buffer);
result = rc_json_parse_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
if (result != RC_OK)
return result;
result = rc_json_get_required_unum_array(&response->achievement_ids, &response->num_achievement_ids, &response->response, &fields[2], "UserUnlocks");
return result;
}
void rc_api_destroy_fetch_user_unlocks_response(rc_api_fetch_user_unlocks_response_t* response) {
rc_buf_destroy(&response->response.buffer);
}
+120 -14
View File
@@ -1,21 +1,88 @@
#include "internal.h"
#include "rc_internal.h"
#include <stdlib.h>
#include <string.h>
void* rc_alloc(void* pointer, int* offset, int size, int alignment, rc_scratch_t* scratch) {
void* rc_alloc_scratch(void* pointer, int* offset, int size, int alignment, rc_scratch_t* scratch, int scratch_object_pointer_offset)
{
rc_scratch_buffer_t* buffer;
/* if we have a real buffer, then allocate the data there */
if (pointer)
return rc_alloc(pointer, offset, size, alignment, NULL, scratch_object_pointer_offset);
/* update how much space will be required in the real buffer */
{
const int aligned_offset = (*offset + alignment - 1) & ~(alignment - 1);
*offset += (aligned_offset - *offset);
*offset += size;
}
/* find a scratch buffer to hold the temporary data */
buffer = &scratch->buffer;
do {
const int aligned_buffer_offset = (buffer->offset + alignment - 1) & ~(alignment - 1);
const int remaining = sizeof(buffer->buffer) - aligned_buffer_offset;
if (remaining >= size) {
/* claim the required space from an existing buffer */
return rc_alloc(buffer->buffer, &buffer->offset, size, alignment, NULL, -1);
}
if (!buffer->next)
break;
buffer = buffer->next;
} while (1);
/* not enough space in any existing buffer, allocate more */
if (size > (int)sizeof(buffer->buffer)) {
/* caller is asking for more than we can fit in a standard rc_scratch_buffer_t.
* leverage the fact that the buffer is the last field and extend its size.
* this chunk will be exactly large enough to hold the needed data, and since offset
* will exceed sizeof(buffer->buffer), it will never be eligible to hold anything else.
*/
const int needed = sizeof(rc_scratch_buffer_t) - sizeof(buffer->buffer) + size;
buffer->next = (rc_scratch_buffer_t*)malloc(needed);
}
else {
buffer->next = (rc_scratch_buffer_t*)malloc(sizeof(rc_scratch_buffer_t));
}
if (!buffer->next) {
*offset = RC_OUT_OF_MEMORY;
return NULL;
}
buffer = buffer->next;
buffer->offset = 0;
buffer->next = NULL;
/* claim the required space from the new buffer */
return rc_alloc(buffer->buffer, &buffer->offset, size, alignment, NULL, -1);
}
void* rc_alloc(void* pointer, int* offset, int size, int alignment, rc_scratch_t* scratch, int scratch_object_pointer_offset) {
void* ptr;
*offset = (*offset + alignment - 1) & ~(alignment - 1);
if (pointer != 0) {
/* valid buffer, grab the next chunk */
ptr = (void*)((char*)pointer + *offset);
}
else if (scratch != 0) {
ptr = &scratch->obj;
else if (scratch != 0 && scratch_object_pointer_offset >= 0) {
/* only allocate one instance of each object type (indentified by scratch_object_pointer_offset) */
void** scratch_object_pointer = (void**)((char*)&scratch->objs + scratch_object_pointer_offset);
ptr = *scratch_object_pointer;
if (!ptr) {
int used;
ptr = *scratch_object_pointer = rc_alloc_scratch(NULL, &used, size, alignment, scratch, -1);
}
}
else {
ptr = 0;
/* nowhere to get memory from, return NULL */
ptr = NULL;
}
*offset += size;
@@ -23,34 +90,72 @@ void* rc_alloc(void* pointer, int* offset, int size, int alignment, rc_scratch_t
}
char* rc_alloc_str(rc_parse_state_t* parse, const char* text, int length) {
int used = 0;
char* ptr;
ptr = (char*)rc_alloc(parse->buffer, &parse->offset, length + 1, RC_ALIGNOF(char), 0);
if (ptr) {
memcpy(ptr, text, length);
ptr[length] = '\0';
rc_scratch_string_t** next = &parse->scratch.strings;
while (*next) {
int diff = strncmp(text, (*next)->value, length);
if (diff == 0) {
diff = (*next)->value[length];
if (diff == 0)
return (*next)->value;
}
if (diff < 0)
next = &(*next)->left;
else
next = &(*next)->right;
}
*next = (rc_scratch_string_t*)rc_alloc_scratch(NULL, &used, sizeof(rc_scratch_string_t), RC_ALIGNOF(rc_scratch_string_t), &parse->scratch, RC_OFFSETOF(parse->scratch.objs, __rc_scratch_string_t));
ptr = (char*)rc_alloc_scratch(parse->buffer, &parse->offset, length + 1, RC_ALIGNOF(char), &parse->scratch, -1);
if (!ptr || !*next) {
if (parse->offset >= 0)
parse->offset = RC_OUT_OF_MEMORY;
return NULL;
}
memcpy(ptr, text, length);
ptr[length] = '\0';
(*next)->left = NULL;
(*next)->right = NULL;
(*next)->value = ptr;
return ptr;
}
void rc_init_parse_state(rc_parse_state_t* parse, void* buffer, lua_State* L, int funcs_ndx)
{
/* could use memset here, but rc_parse_state_t contains a 512 byte buffer that doesn't need to be initialized */
parse->offset = 0;
parse->L = L;
parse->funcs_ndx = funcs_ndx;
parse->buffer = buffer;
parse->scratch.memref = parse->scratch.memref_buffer;
parse->scratch.memref_size = sizeof(parse->scratch.memref_buffer) / sizeof(parse->scratch.memref_buffer[0]);
parse->scratch.memref_count = 0;
parse->scratch.buffer.offset = 0;
parse->scratch.buffer.next = NULL;
parse->scratch.strings = NULL;
memset(&parse->scratch.objs, 0, sizeof(parse->scratch.objs));
parse->first_memref = 0;
parse->variables = 0;
parse->measured_target = 0;
parse->lines_read = 0;
parse->has_required_hits = 0;
}
void rc_destroy_parse_state(rc_parse_state_t* parse)
{
if (parse->scratch.memref != parse->scratch.memref_buffer)
free(parse->scratch.memref);
rc_scratch_buffer_t* buffer = parse->scratch.buffer.next;
rc_scratch_buffer_t* next;
while (buffer) {
next = buffer->next;
free(buffer);
buffer = next;
}
}
const char* rc_error_str(int ret)
@@ -82,6 +187,7 @@ const char* rc_error_str(int ret)
case RC_INVALID_MEASURED_TARGET: return "Invalid measured target";
case RC_INVALID_COMPARISON: return "Invalid comparison";
case RC_INVALID_STATE: return "Invalid state";
case RC_INVALID_JSON: return "Invalid JSON";
default: return "Unknown error";
}
+1 -1
View File
@@ -1,4 +1,4 @@
#include "compat.h"
#include "rc_compat.h"
#include <ctype.h>
#include <stdarg.h>
+105 -63
View File
@@ -1,7 +1,65 @@
#include "internal.h"
#include "rc_internal.h"
#include <stdlib.h>
char rc_parse_operator(const char** memaddr) {
const char* oper = *memaddr;
switch (*oper) {
case '=':
++(*memaddr);
(*memaddr) += (**memaddr == '=');
return RC_OPERATOR_EQ;
case '!':
if (oper[1] == '=') {
(*memaddr) += 2;
return RC_OPERATOR_NE;
}
/* fall through */
default:
return RC_INVALID_OPERATOR;
case '<':
if (oper[1] == '=') {
(*memaddr) += 2;
return RC_OPERATOR_LE;
}
++(*memaddr);
return RC_OPERATOR_LT;
case '>':
if (oper[1] == '=') {
(*memaddr) += 2;
return RC_OPERATOR_GE;
}
++(*memaddr);
return RC_OPERATOR_GT;
case '*':
++(*memaddr);
return RC_OPERATOR_MULT;
case '/':
++(*memaddr);
return RC_OPERATOR_DIV;
case '&':
++(*memaddr);
return RC_OPERATOR_AND;
case '\0':/* end of string */
case '_': /* next condition */
case 'S': /* next condset */
case ')': /* end of macro */
case '$': /* maximum of values */
/* valid condition separator, condition may not have an operator */
return RC_OPERATOR_NONE;
}
}
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse, int is_indirect) {
rc_condition_t* self;
const char* aux;
@@ -11,6 +69,7 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
aux = *memaddr;
self = RC_ALLOC(rc_condition_t, parse);
self->current_hits = 0;
self->is_true = 0;
if (*aux != 0 && aux[1] == ':') {
switch (*aux) {
@@ -19,12 +78,14 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
case 'a': case 'A': self->type = RC_CONDITION_ADD_SOURCE; can_modify = 1; break;
case 'b': case 'B': self->type = RC_CONDITION_SUB_SOURCE; can_modify = 1; break;
case 'c': case 'C': self->type = RC_CONDITION_ADD_HITS; break;
case 'd': case 'D': self->type = RC_CONDITION_SUB_HITS; break;
case 'n': case 'N': self->type = RC_CONDITION_AND_NEXT; break;
case 'o': case 'O': self->type = RC_CONDITION_OR_NEXT; break;
case 'm': case 'M': self->type = RC_CONDITION_MEASURED; break;
case 'q': case 'Q': self->type = RC_CONDITION_MEASURED_IF; break;
case 'i': case 'I': self->type = RC_CONDITION_ADD_ADDRESS; can_modify = 1; break;
case 't': case 'T': self->type = RC_CONDITION_TRIGGER; break;
case 'z': case 'Z': self->type = RC_CONDITION_RESET_NEXT_IF; break;
default: parse->offset = RC_INVALID_CONDITION_TYPE; return 0;
}
@@ -46,76 +107,37 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
return 0;
}
switch (*aux++) {
case '=':
self->oper = RC_OPERATOR_EQ;
aux += *aux == '=';
break;
case '!':
if (*aux++ != '=') {
/* fall through */
default:
parse->offset = RC_INVALID_OPERATOR;
return 0;
self->oper = rc_parse_operator(&aux);
switch (self->oper) {
case RC_OPERATOR_NONE:
/* non-modifying statements must have a second operand */
if (!can_modify) {
/* measured does not require a second operand when used in a value */
if (self->type != RC_CONDITION_MEASURED) {
parse->offset = RC_INVALID_OPERATOR;
return 0;
}
}
self->oper = RC_OPERATOR_NE;
break;
case '<':
self->oper = RC_OPERATOR_LT;
if (*aux == '=') {
self->oper = RC_OPERATOR_LE;
aux++;
}
break;
case '>':
self->oper = RC_OPERATOR_GT;
if (*aux == '=') {
self->oper = RC_OPERATOR_GE;
aux++;
}
break;
case '*':
self->oper = RC_OPERATOR_MULT;
break;
case '/':
self->oper = RC_OPERATOR_DIV;
break;
case '&':
self->oper = RC_OPERATOR_AND;
break;
case '_':
case ')':
case '\0':
self->oper = RC_OPERATOR_NONE;
/* provide dummy operand of '1' and no required hits */
self->operand2.type = RC_OPERAND_CONST;
self->operand2.value.num = 1;
self->required_hits = 0;
*memaddr = aux - 1;
*memaddr = aux;
return self;
}
switch (self->oper) {
case RC_OPERATOR_MULT:
case RC_OPERATOR_DIV:
case RC_OPERATOR_AND:
/* modifying operators are only valid on modifying statements */
if (!can_modify) {
parse->offset = RC_INVALID_OPERATOR;
return 0;
}
break;
if (can_modify)
break;
/* fallthrough */
case RC_INVALID_OPERATOR:
parse->offset = RC_INVALID_OPERATOR;
return 0;
default:
/* comparison operators are not valid on modifying statements */
@@ -145,7 +167,7 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
if (self->oper == RC_OPERATOR_NONE) {
/* if operator is none, explicitly clear out the right side */
self->operand2.type = RC_INVALID_CONST_OPERAND;
self->operand2.type = RC_OPERAND_CONST;
self->operand2.value.num = 0;
}
@@ -163,6 +185,12 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
return 0;
}
/* if operator is none, explicitly clear out the required hits */
if (self->oper == RC_OPERATOR_NONE)
self->required_hits = 0;
else
parse->has_required_hits = 1;
aux = end + 1;
}
else if (*aux == '.') {
@@ -174,6 +202,12 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
return 0;
}
/* if operator is none, explicitly clear out the required hits */
if (self->oper == RC_OPERATOR_NONE)
self->required_hits = 0;
else
parse->has_required_hits = 1;
aux = end + 1;
}
else {
@@ -205,10 +239,18 @@ int rc_evaluate_condition_value(rc_condition_t* self, rc_eval_state_t* eval_stat
switch (self->oper) {
case RC_OPERATOR_MULT:
if (self->operand2.type == RC_OPERAND_FP)
if (self->operand2.type == RC_OPERAND_FP) {
value = (int)((double)value * self->operand2.value.dbl);
else
}
else {
/* the c standard for unsigned multiplication is well defined as non-overflowing truncation
* to the type's size. this allows negative multiplication through twos-complements. i.e.
* 1 * -1 (0xFFFFFFFF) = 0xFFFFFFFF = -1
* 3 * -2 (0xFFFFFFFE) = 0x2FFFFFFFA & 0xFFFFFFFF = 0xFFFFFFFA = -6
* 10 * -5 (0xFFFFFFFB) = 0x9FFFFFFCE & 0xFFFFFFFF = 0xFFFFFFCE = -50
*/
value *= rc_evaluate_operand(&self->operand2, eval_state);
}
break;
case RC_OPERATOR_DIV:
+109 -22
View File
@@ -1,4 +1,4 @@
#include "internal.h"
#include "rc_internal.h"
static void rc_update_condition_pause(rc_condition_t* condition, int* in_pause) {
if (condition->next != 0) {
@@ -13,9 +13,11 @@ static void rc_update_condition_pause(rc_condition_t* condition, int* in_pause)
case RC_CONDITION_ADD_SOURCE:
case RC_CONDITION_SUB_SOURCE:
case RC_CONDITION_ADD_HITS:
case RC_CONDITION_SUB_HITS:
case RC_CONDITION_AND_NEXT:
case RC_CONDITION_OR_NEXT:
case RC_CONDITION_ADD_ADDRESS:
case RC_CONDITION_RESET_NEXT_IF:
condition->pause = *in_pause;
break;
@@ -25,14 +27,15 @@ static void rc_update_condition_pause(rc_condition_t* condition, int* in_pause)
}
}
rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse) {
rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse, int is_value) {
rc_condset_t* self;
rc_condition_t** next;
int in_pause;
int in_add_address;
unsigned measured_target = 0;
self = RC_ALLOC(rc_condset_t, parse);
self->has_pause = self->is_paused = 0;
self->has_pause = self->is_paused = self->has_indirect_memrefs = 0;
next = &self->conditions;
if (**memaddr == 'S' || **memaddr == 's' || !**memaddr) {
@@ -52,12 +55,16 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse) {
if ((*next)->oper == RC_OPERATOR_NONE) {
switch ((*next)->type) {
case RC_CONDITION_ADD_ADDRESS:
case RC_CONDITION_ADD_HITS:
case RC_CONDITION_ADD_SOURCE:
case RC_CONDITION_SUB_SOURCE:
case RC_CONDITION_AND_NEXT:
case RC_CONDITION_OR_NEXT:
/* these conditions don't require a right hand size (implied *1) */
break;
case RC_CONDITION_MEASURED:
/* right hand side is not required when Measured is used in a value */
if (is_value)
break;
/* fallthrough to default */
default:
parse->offset = RC_INVALID_OPERATOR;
@@ -67,27 +74,51 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse) {
self->has_pause |= (*next)->type == RC_CONDITION_PAUSE_IF;
in_add_address = (*next)->type == RC_CONDITION_ADD_ADDRESS;
self->has_indirect_memrefs |= in_add_address;
if ((*next)->type == RC_CONDITION_MEASURED) {
unsigned measured_target = 0;
if ((*next)->required_hits == 0) {
if ((*next)->operand2.type != RC_OPERAND_CONST) {
parse->offset = RC_INVALID_MEASURED_TARGET;
return 0;
}
switch ((*next)->type) {
case RC_CONDITION_MEASURED:
if (measured_target != 0) {
/* multiple Measured flags cannot exist in the same group */
parse->offset = RC_MULTIPLE_MEASURED;
return 0;
}
else if (is_value) {
measured_target = (unsigned)-1;
if ((*next)->oper != RC_OPERATOR_NONE)
(*next)->required_hits = measured_target;
}
else if ((*next)->required_hits != 0) {
measured_target = (*next)->required_hits;
}
else if ((*next)->operand2.type == RC_OPERAND_CONST) {
measured_target = (*next)->operand2.value.num;
}
else {
measured_target = (*next)->required_hits;
parse->offset = RC_INVALID_MEASURED_TARGET;
return 0;
}
if (parse->measured_target && measured_target != parse->measured_target) {
/* multiple Measured flags in separate groups must have the same target */
parse->offset = RC_MULTIPLE_MEASURED;
return 0;
}
parse->measured_target = measured_target;
break;
case RC_CONDITION_STANDARD:
case RC_CONDITION_TRIGGER:
/* these flags are not allowed in value expressions */
if (is_value) {
parse->offset = RC_INVALID_VALUE_FLAG;
return 0;
}
break;
default:
break;
}
next = &(*next)->next;
@@ -101,7 +132,6 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse) {
*next = 0;
if (parse->buffer != 0) {
in_pause = 0;
rc_update_condition_pause(self->conditions, &in_pause);
@@ -110,9 +140,33 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse) {
return self;
}
static void rc_condset_update_indirect_memrefs(rc_condset_t* self, rc_condition_t* condition, int processing_pause, rc_eval_state_t* eval_state) {
for (; condition != 0; condition = condition->next) {
if (condition->pause != processing_pause)
continue;
if (condition->type == RC_CONDITION_ADD_ADDRESS) {
eval_state->add_address = rc_evaluate_condition_value(condition, eval_state);
continue;
}
/* call rc_get_memref_value to update the indirect memrefs. it won't do anything with non-indirect
* memrefs and avoids a second check of is_indirect. also, we ignore the response, so it doesn't
* matter what operand type we pass. assume RC_OPERAND_ADDRESS is the quickest. */
if (rc_operand_is_memref(&condition->operand1))
rc_get_memref_value(condition->operand1.value.memref, RC_OPERAND_ADDRESS, eval_state);
if (rc_operand_is_memref(&condition->operand2))
rc_get_memref_value(condition->operand2.value.memref, RC_OPERAND_ADDRESS, eval_state);
eval_state->add_address = 0;
}
}
static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc_eval_state_t* eval_state) {
rc_condition_t* condition;
int set_valid, cond_valid, and_next, or_next;
int set_valid, cond_valid, and_next, or_next, reset_next;
unsigned measured_value = 0;
unsigned total_hits = 0;
int can_measure = 1, measured_from_hits = 0;
@@ -121,12 +175,12 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc
set_valid = 1;
and_next = 1;
or_next = 0;
reset_next = 0;
eval_state->add_value = eval_state->add_hits = eval_state->add_address = 0;
for (condition = self->conditions; condition != 0; condition = condition->next) {
if (condition->pause != processing_pause) {
if (condition->pause != processing_pause)
continue;
}
/* STEP 1: process modifier conditions */
switch (condition->type) {
@@ -167,8 +221,16 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc
and_next = 1;
or_next = 0;
/* true conditions should update hit count */
if (cond_valid) {
if (reset_next) {
/* previous ResetNextIf resets the hit count on this condition and prevents it from being true */
if (condition->current_hits)
eval_state->was_cond_reset = 1;
condition->current_hits = 0;
cond_valid = 0;
}
else if (cond_valid) {
/* true conditions should update hit count */
eval_state->has_hits = 1;
if (condition->required_hits == 0) {
@@ -194,6 +256,16 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc
switch (condition->type) {
case RC_CONDITION_ADD_HITS:
eval_state->add_hits += condition->current_hits;
reset_next = 0; /* ResetNextIf was applied to this AddHits condition; don't apply it to future conditions */
continue;
case RC_CONDITION_SUB_HITS:
eval_state->add_hits -= condition->current_hits;
reset_next = 0; /* ResetNextIf was applied to this AddHits condition; don't apply it to future conditions */
continue;
case RC_CONDITION_RESET_NEXT_IF:
reset_next = cond_valid;
continue;
case RC_CONDITION_AND_NEXT:
@@ -208,13 +280,17 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc
break;
}
/* reset logic flags for next condition */
reset_next = 0;
/* STEP 4: calculate total hits */
total_hits = condition->current_hits;
if (eval_state->add_hits) {
if (condition->required_hits != 0) {
/* if the condition has a target hit count, we have to recalculate cond_valid including the AddHits counter */
total_hits = condition->current_hits + eval_state->add_hits;
const int signed_hits = (int)condition->current_hits + eval_state->add_hits;
total_hits = (signed_hits >= 0) ? (unsigned)signed_hits : 0;
cond_valid = (total_hits >= condition->required_hits);
}
else {
@@ -230,6 +306,17 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc
case RC_CONDITION_PAUSE_IF:
/* as soon as we find a PauseIf that evaluates to true, stop processing the rest of the group */
if (cond_valid) {
/* indirect memrefs are not updated as part of the rc_update_memref_values call.
* an active pause aborts processing of the remaining part of the pause subset and the entire non-pause subset.
* if the set has any indirect memrefs, manually update them now so the deltas are correct */
if (self->has_indirect_memrefs) {
/* first, update any indirect memrefs in the remaining part of the pause subset */
rc_condset_update_indirect_memrefs(self, condition->next, 1, eval_state);
/* then, update all indirect memrefs in the non-pause subset */
rc_condset_update_indirect_memrefs(self, self->conditions, 0, eval_state);
}
return 1;
}
+9 -5
View File
@@ -1,4 +1,3 @@
#include "rcheevos.h"
#include "rc_consoles.h"
#include <ctype.h>
@@ -339,10 +338,14 @@ static const rc_memory_region_t _rc_memory_regions_intellivision[] = {
static const rc_memory_regions_t rc_memory_regions_intellivision = { _rc_memory_regions_intellivision, 9 };
/* ===== Magnavox Odyssey 2 ===== */
/* https://sudonull.com/post/76885-Architecture-and-programming-Philips-Videopac-Magnavox-Odyssey-2 */
static const rc_memory_region_t _rc_memory_regions_magnavox_odyssey_2[] = {
{ 0x000000U, 0x00003FU, 0x000040U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
/* Internal and external RAMs are reachable using unique instructions.
* The real addresses provided are virtual and for mapping purposes only. */
{ 0x000000U, 0x00003FU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Internal RAM" },
{ 0x000040U, 0x00013FU, 0x000040U, RC_MEMORY_TYPE_SYSTEM_RAM, "External RAM" }
};
static const rc_memory_regions_t rc_memory_regions_magnavox_odyssey_2 = { _rc_memory_regions_magnavox_odyssey_2, 1 };
static const rc_memory_regions_t rc_memory_regions_magnavox_odyssey_2 = { _rc_memory_regions_magnavox_odyssey_2, 2 };
/* ===== Master System ===== */
/* http://www.smspower.org/Development/MemoryMap */
@@ -375,8 +378,9 @@ static const rc_memory_regions_t rc_memory_regions_msx = { _rc_memory_regions_ms
/* ===== Neo Geo Pocket ===== */
/* http://neopocott.emuunlim.com/docs/tech-11.txt */
static const rc_memory_region_t _rc_memory_regions_neo_geo_pocket[] = {
/* MednafenNGP exposes 16KB, but the doc suggests there's 24-32KB */
{ 0x000000U, 0x003FFFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
/* The docs suggest there's Work RAM exposed from $0000-$6FFF, Sound RAM from $7000-$7FFF, and Video
* RAM from $8000-$BFFF, but both MednafenNGP and FBNeo only expose system RAM from $4000-$7FFF */
{ 0x000000U, 0x003FFFU, 0x004000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
};
static const rc_memory_regions_t rc_memory_regions_neo_geo_pocket = { _rc_memory_regions_neo_geo_pocket, 1 };
Loaded 100 of 406 files, more files were not shown because too many files have changed in this diff. Show more