mirror of
https://github.com/libretro/RetroArch
synced 2025-02-21 00:40:09 +00:00
Merge branch 'master' into rthreads_audio
This commit is contained in:
commit
599d08fe12
5
.gitignore
vendored
5
.gitignore
vendored
@ -68,6 +68,11 @@ menu/driverspzarch.c
|
|||||||
*.rpx
|
*.rpx
|
||||||
wiiu/wut/elf2rpl/elf2rpl
|
wiiu/wut/elf2rpl/elf2rpl
|
||||||
|
|
||||||
|
# 3ds
|
||||||
|
/.lst
|
||||||
|
*.3dsx
|
||||||
|
*.smdh
|
||||||
|
|
||||||
# Ctags
|
# Ctags
|
||||||
/tags
|
/tags
|
||||||
|
|
||||||
|
28
CHANGES.md
28
CHANGES.md
@ -1,15 +1,28 @@
|
|||||||
# 1.7.0 (future)
|
# 1.7.1 (future)
|
||||||
|
- DINPUT: don't reinitialize input driver on network events / media insertion / network drive connection
|
||||||
|
- KEYMAPPER: prevent a condition that caused input_menu_toggle to stop working when a RETRO_DEVICE_KEYBOARD type device is enabled
|
||||||
|
- PS3: Enable Cheevos.
|
||||||
|
- PSP: Enable threading support through pthreads.
|
||||||
|
- WINDOWS: Improved Unicode support (for cores/directory creation).
|
||||||
|
- WIIU: Overlay support.
|
||||||
|
|
||||||
|
# 1.7.0
|
||||||
- CHEEVOS: Add badges for achievements, shows thumbnail images of achievements.
|
- CHEEVOS: Add badges for achievements, shows thumbnail images of achievements.
|
||||||
- CHEEVOS: Leaderboard support.
|
- CHEEVOS: Leaderboard support.
|
||||||
- CHEEVOS: Only disable savestates on hardcore mode if achievements are not available.
|
- CHEEVOS: Only disable savestates on hardcore mode if achievements are not available.
|
||||||
|
- COMMANDLINE: Fix fullscreen toggle switch.
|
||||||
- COMMON: Add 'Automatically Load Content To Playlist' feature, enabled by default.
|
- COMMON: Add 'Automatically Load Content To Playlist' feature, enabled by default.
|
||||||
- COMMON: Fix slowmotion ratio always being reset back to 1.
|
- COMMON: Fix slowmotion ratio always being reset back to 1.
|
||||||
- COMMON: Optimized NBIO implementations now for Apple, Windows, and Linux. Uses mmap for Linux/Windows/BSD if/when available. File I/O should now be much faster for loading images inside the menu.
|
- COMMON: Optimized NBIO implementations now for Apple, Windows, and Linux. Uses mmap for Linux/Windows/BSD if/when available. File I/O should now be much faster for loading images inside the menu.
|
||||||
- COMMON: Native Blissbox support now for latest firmware as of writing (2.0). Implementation through libusb and/or native Windows HID.
|
- COMMON: Native Blissbox support now for latest firmware as of writing (2.0). Implementation through libusb and/or native Windows HID.
|
||||||
- COMMON: New lightgun API.
|
- COMMON: New lightgun API.
|
||||||
|
- COMMON: New VFS (Virtual File System) API.
|
||||||
- COMMON: Fixed some playlist bugs.
|
- COMMON: Fixed some playlist bugs.
|
||||||
- COMMON: New snow shader.
|
- COMMON: New snow shader.
|
||||||
|
- COMMON: Fix Quick Menu title, no longer shows 'Select File'.
|
||||||
- COMMON: Fix loading cores that require no content one after another.
|
- COMMON: Fix loading cores that require no content one after another.
|
||||||
|
- COMMON: Map Delete key to Y button for non-unified menu keyboard controls.
|
||||||
|
- COMMON: Fix for relative paths being normalised and generating a duplicate history entry.
|
||||||
- EMSCRIPTEN: Fix references to browserfs.
|
- EMSCRIPTEN: Fix references to browserfs.
|
||||||
- FREEBSD: Support libusb HID input driver.
|
- FREEBSD: Support libusb HID input driver.
|
||||||
- HAIKU: Buildfix.
|
- HAIKU: Buildfix.
|
||||||
@ -21,20 +34,31 @@
|
|||||||
- LOCALIZATION: Update Italian translation.
|
- LOCALIZATION: Update Italian translation.
|
||||||
- LOCALIZATION: Update Japanese translation.
|
- LOCALIZATION: Update Japanese translation.
|
||||||
- LOCALIZATION: Update Portuguese-Brazilian translation.
|
- LOCALIZATION: Update Portuguese-Brazilian translation.
|
||||||
|
- LOCALIZATION: Update Polish translation.
|
||||||
- LOCALIZATION: Update Russian translation.
|
- LOCALIZATION: Update Russian translation.
|
||||||
|
- MENU: Snowflake menu shader effect.
|
||||||
- OSX/PPC: Fix the GL2 renderchain, had to use EXT versions of framebuffer/renderbuffer functions.
|
- OSX/PPC: Fix the GL2 renderchain, had to use EXT versions of framebuffer/renderbuffer functions.
|
||||||
|
- PS3: HTTP requests / downloads should now work.
|
||||||
|
- PS3: Core Updater now works.
|
||||||
|
- PS3: Improved font rendering, enable STB Unicode font renderer.
|
||||||
|
- PSP: Make it work with Vita's Adrenaline.
|
||||||
|
- PSP: Fix audio sync.
|
||||||
- PSP: Fix content loading, port should be functional again.
|
- PSP: Fix content loading, port should be functional again.
|
||||||
- PSP: Us 64MB when available.
|
- PSP: Use 64MB when available.
|
||||||
- SCANNER: Fix crash from Windows-incompatible format string.
|
- SCANNER: Fix crash from Windows-incompatible format string.
|
||||||
- VITA: Improve packaging, installation times.
|
- VITA: Improve packaging, installation times.
|
||||||
- WIIU: Disabled the controller patcher for now since it was the source of many stability issues.
|
- WIIU: Disabled the controller patcher for now since it was the source of many stability issues.
|
||||||
|
- VULKAN: Various stability fixes for WSI.
|
||||||
- WINDOWS: Add MSVC 2017 solution.
|
- WINDOWS: Add MSVC 2017 solution.
|
||||||
- WINDOWS: Get rid of the empty console window in MSVC 2010 builds.
|
- WINDOWS: Get rid of the empty console window in MSVC 2010 builds.
|
||||||
- WINDOWS: Raw input driver now supports new lightgun code.
|
- WINDOWS: Raw input driver now supports new lightgun code.
|
||||||
- WINDOWS: Use configured OSD/text message color on GDI driver.
|
- WINDOWS: Use configured OSD/text message color on GDI driver.
|
||||||
- WINDOWS/XINPUT: Populate XInput VID/PID from DInput so autoconfig doesn't rely solely on joypad names
|
- WINDOWS/XINPUT: Populate XInput VID/PID from DInput so autoconfig doesn't rely solely on joypad names
|
||||||
|
- WINDOWS/XINPUT: Fix crash that occurs in some situations with Steam running and a Steam Controller plugged in.
|
||||||
- WINDOWS: Improve version reporting under System Information.
|
- WINDOWS: Improve version reporting under System Information.
|
||||||
- WINDOWS: Support window transparency.
|
- WINDOWS: Support window transparency.
|
||||||
|
- WINDOWS: Correct usage of GetWindowPlacement per MS docs, fixes game window position on Win95/98.
|
||||||
|
- WINDOWS: Added Visual Studio 2017 support.
|
||||||
|
|
||||||
# 1.6.9
|
# 1.6.9
|
||||||
- COMMON: Small memory leak.
|
- COMMON: Small memory leak.
|
||||||
|
@ -1428,13 +1428,14 @@ ifeq ($(HAVE_BUILTINZLIB),1)
|
|||||||
$(DEPS_DIR)/libz/uncompr.o \
|
$(DEPS_DIR)/libz/uncompr.o \
|
||||||
$(DEPS_DIR)/libz/zutil.o
|
$(DEPS_DIR)/libz/zutil.o
|
||||||
else
|
else
|
||||||
ifeq ($(HAVE_ZLIB),1)
|
ifeq ($(HAVE_ZLIB), 1)
|
||||||
OBJ += $(ZLIB_OBJS)
|
OBJ += $(ZLIB_OBJS)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(HAVE_7ZIP),1)
|
ifeq ($(HAVE_7ZIP), 1)
|
||||||
ifeq ($(HAVE_FLAC),1)
|
ifeq ($(HAVE_ZLIB), 1)
|
||||||
|
ifeq ($(HAVE_FLAC), 1)
|
||||||
DEFINES += -DHAVE_CHD -DWANT_SUBCODE -DWANT_RAW_DATA_SECTOR
|
DEFINES += -DHAVE_CHD -DWANT_SUBCODE -DWANT_RAW_DATA_SECTOR
|
||||||
CFLAGS += -I$(LIBRETRO_COMM_DIR)/formats/libchdr
|
CFLAGS += -I$(LIBRETRO_COMM_DIR)/formats/libchdr
|
||||||
OBJ += $(LIBRETRO_COMM_DIR)/formats/libchdr/bitstream.o \
|
OBJ += $(LIBRETRO_COMM_DIR)/formats/libchdr/bitstream.o \
|
||||||
@ -1445,6 +1446,7 @@ ifeq ($(HAVE_FLAC),1)
|
|||||||
$(LIBRETRO_COMM_DIR)/streams/chd_stream.o
|
$(LIBRETRO_COMM_DIR)/streams/chd_stream.o
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
# Video4Linux 2
|
# Video4Linux 2
|
||||||
|
|
||||||
@ -1523,27 +1525,24 @@ ifeq ($(HAVE_NETWORKING), 1)
|
|||||||
cores/libretro-net-retropad/net_retropad_core.o
|
cores/libretro-net-retropad/net_retropad_core.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(HAVE_MINIUPNPC), 1)
|
ifeq ($(HAVE_BUILTINMINIUPNPC), 1)
|
||||||
ifeq ($(HAVE_BUILTINMINIUPNPC), 1)
|
DEFINES += -DHAVE_BUILTINMINIUPNPC -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR
|
||||||
DEFINES += -DHAVE_BUILTINMINIUPNPC -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR
|
DEFINES += -I$(DEPS_DIR)
|
||||||
DEFINES += -I$(DEPS_DIR)
|
OBJ += $(DEPS_DIR)/miniupnpc/igd_desc_parse.o \
|
||||||
OBJ += \
|
$(DEPS_DIR)/miniupnpc/upnpreplyparse.o \
|
||||||
$(DEPS_DIR)/miniupnpc/igd_desc_parse.o \
|
$(DEPS_DIR)/miniupnpc/upnpcommands.o \
|
||||||
$(DEPS_DIR)/miniupnpc/upnpreplyparse.o \
|
$(DEPS_DIR)/miniupnpc/upnperrors.o \
|
||||||
$(DEPS_DIR)/miniupnpc/upnpcommands.o \
|
$(DEPS_DIR)/miniupnpc/connecthostport.o \
|
||||||
$(DEPS_DIR)/miniupnpc/upnperrors.o \
|
$(DEPS_DIR)/miniupnpc/portlistingparse.o \
|
||||||
$(DEPS_DIR)/miniupnpc/connecthostport.o \
|
$(DEPS_DIR)/miniupnpc/receivedata.o \
|
||||||
$(DEPS_DIR)/miniupnpc/portlistingparse.o \
|
$(DEPS_DIR)/miniupnpc/upnpdev.o \
|
||||||
$(DEPS_DIR)/miniupnpc/receivedata.o \
|
$(DEPS_DIR)/miniupnpc/minissdpc.o \
|
||||||
$(DEPS_DIR)/miniupnpc/upnpdev.o \
|
$(DEPS_DIR)/miniupnpc/miniwget.o \
|
||||||
$(DEPS_DIR)/miniupnpc/minissdpc.o \
|
$(DEPS_DIR)/miniupnpc/miniupnpc.o \
|
||||||
$(DEPS_DIR)/miniupnpc/miniwget.o \
|
$(DEPS_DIR)/miniupnpc/minixml.o \
|
||||||
$(DEPS_DIR)/miniupnpc/miniupnpc.o \
|
$(DEPS_DIR)/miniupnpc/minisoap.o
|
||||||
$(DEPS_DIR)/miniupnpc/minixml.o \
|
else ifeq ($(HAVE_MINIUPNPC), 1)
|
||||||
$(DEPS_DIR)/miniupnpc/minisoap.o
|
LIBS += $(MINIUPNPC_LIBS)
|
||||||
else
|
|
||||||
LIBS += $(MINIUPNPC_LIBS)
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -1624,6 +1623,29 @@ OBJ += gfx/video_filters/2xsai.o \
|
|||||||
gfx/video_filters/phosphor2x.o
|
gfx/video_filters/phosphor2x.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(WANT_IOSUHAX), 1)
|
||||||
|
DEFINES += -I$(DEPS_DIR)/libiosuhax
|
||||||
|
CFLAGS += -I$(DEPS_DIR)/libiosuhax
|
||||||
|
OBJ += $(DEPS_DIR)/libiosuhax/iosuhax.o \
|
||||||
|
$(DEPS_DIR)/libiosuhax/iosuhax_devoptab.o \
|
||||||
|
$(DEPS_DIR)/libiosuhax/iosuhax_disc_interface.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(WANT_LIBFAT), 1)
|
||||||
|
DEFINES += -I$(DEPS_DIR)/libfat/include
|
||||||
|
CFLAGS += -I$(DEPS_DIR)/libfat/include
|
||||||
|
OBJ += $(DEPS_DIR)/libfat/cache.o \
|
||||||
|
$(DEPS_DIR)/libfat/directory.o \
|
||||||
|
$(DEPS_DIR)/libfat/disc.o \
|
||||||
|
$(DEPS_DIR)/libfat/fatdir.o \
|
||||||
|
$(DEPS_DIR)/libfat/fatfile.o \
|
||||||
|
$(DEPS_DIR)/libfat/file_allocation_table.o \
|
||||||
|
$(DEPS_DIR)/libfat/filetime.o \
|
||||||
|
$(DEPS_DIR)/libfat/libfat.o \
|
||||||
|
$(DEPS_DIR)/libfat/lock.o \
|
||||||
|
$(DEPS_DIR)/libfat/partition.o
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(HAVE_STATIC_AUDIO_FILTERS), 1)
|
ifeq ($(HAVE_STATIC_AUDIO_FILTERS), 1)
|
||||||
OBJ += libretro-common/audio/dsp_filters/echo.o \
|
OBJ += libretro-common/audio/dsp_filters/echo.o \
|
||||||
libretro-common/audio/dsp_filters/eq.o \
|
libretro-common/audio/dsp_filters/eq.o \
|
||||||
|
14
Makefile.ctr
14
Makefile.ctr
@ -152,7 +152,7 @@ $(TARGET): $(TARGET_3DSX) $(TARGET_3DS) $(TARGET_CIA) $(TARGET).core
|
|||||||
$(TARGET).3dsx: $(TARGET).elf
|
$(TARGET).3dsx: $(TARGET).elf
|
||||||
$(TARGET).elf: $(OBJ) libretro_ctr.a
|
$(TARGET).elf: $(OBJ) libretro_ctr.a
|
||||||
|
|
||||||
PREFIX := $(DEVKITPRO)/devkitARM/bin/arm-none-eabi-
|
PREFIX := $(DEVKITARM)/bin/arm-none-eabi-
|
||||||
|
|
||||||
CC := $(PREFIX)gcc
|
CC := $(PREFIX)gcc
|
||||||
CXX := $(PREFIX)g++
|
CXX := $(PREFIX)g++
|
||||||
@ -175,13 +175,13 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
%.o: %.vsh %.gsh
|
%.o: %.vsh %.gsh
|
||||||
$(DEVKITPRO)/devkitARM/bin/picasso $^ -o $*.shbin
|
$(DEVKITARM)/bin/picasso $^ -o $*.shbin
|
||||||
$(DEVKITPRO)/devkitARM/bin/bin2s $*.shbin | $(PREFIX)as -o $@
|
$(DEVKITARM)/bin/bin2s $*.shbin | $(PREFIX)as -o $@
|
||||||
rm $*.shbin
|
rm $*.shbin
|
||||||
|
|
||||||
%.o: %.vsh
|
%.o: %.vsh
|
||||||
$(DEVKITPRO)/devkitARM/bin/picasso $^ -o $*.shbin
|
$(DEVKITARM)/bin/picasso $^ -o $*.shbin
|
||||||
$(DEVKITPRO)/devkitARM/bin/bin2s $*.shbin | $(PREFIX)as -o $@
|
$(DEVKITARM)/bin/bin2s $*.shbin | $(PREFIX)as -o $@
|
||||||
rm $*.shbin
|
rm $*.shbin
|
||||||
|
|
||||||
%.o: %.cpp
|
%.o: %.cpp
|
||||||
@ -202,7 +202,7 @@ endif
|
|||||||
%.vsh:
|
%.vsh:
|
||||||
|
|
||||||
$(TARGET).smdh: $(APP_ICON)
|
$(TARGET).smdh: $(APP_ICON)
|
||||||
$(DEVKITPRO)/devkitARM/bin/smdhtool --create "$(APP_TITLE)" "$(APP_DESCRIPTION)" "$(APP_AUTHOR)" $(APP_ICON) $@
|
$(DEVKITARM)/bin/smdhtool --create "$(APP_TITLE)" "$(APP_DESCRIPTION)" "$(APP_AUTHOR)" $(APP_ICON) $@
|
||||||
|
|
||||||
$(TARGET).3dsx: $(TARGET).elf
|
$(TARGET).3dsx: $(TARGET).elf
|
||||||
ifeq ($(APP_BIG_TEXT_SECTION), 1)
|
ifeq ($(APP_BIG_TEXT_SECTION), 1)
|
||||||
@ -210,7 +210,7 @@ ifeq ($(APP_BIG_TEXT_SECTION), 1)
|
|||||||
else
|
else
|
||||||
rm -f $(TARGET).xml
|
rm -f $(TARGET).xml
|
||||||
endif
|
endif
|
||||||
$(DEVKITPRO)/devkitARM/bin/3dsxtool $< $@ $(_3DSXFLAGS)
|
$(DEVKITARM)/bin/3dsxtool $< $@ $(_3DSXFLAGS)
|
||||||
|
|
||||||
$(TARGET).elf: ctr/3dsx_custom_crt0.o
|
$(TARGET).elf: ctr/3dsx_custom_crt0.o
|
||||||
$(LD) $(LDFLAGS) $(OBJ) $(LIBDIRS) $(LIBS) -o $@
|
$(LD) $(LDFLAGS) $(OBJ) $(LIBDIRS) $(LIBS) -o $@
|
||||||
|
@ -111,7 +111,7 @@ $(TARGET): $(TARGET_3DSX) $(TARGET_3DS) $(TARGET_CIA)
|
|||||||
$(TARGET).3dsx: $(TARGET).elf
|
$(TARGET).3dsx: $(TARGET).elf
|
||||||
$(TARGET).elf: $(OBJ)
|
$(TARGET).elf: $(OBJ)
|
||||||
|
|
||||||
PREFIX := $(DEVKITPRO)/devkitARM/bin/arm-none-eabi-
|
PREFIX := $(DEVKITARM)/bin/arm-none-eabi-
|
||||||
|
|
||||||
CC := $(PREFIX)gcc
|
CC := $(PREFIX)gcc
|
||||||
CXX := $(PREFIX)g++
|
CXX := $(PREFIX)g++
|
||||||
@ -134,13 +134,13 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
%.o: %.vsh %.gsh
|
%.o: %.vsh %.gsh
|
||||||
$(DEVKITPRO)/devkitARM/bin/picasso $^ -o $*.shbin
|
$(DEVKITARM)/bin/picasso $^ -o $*.shbin
|
||||||
$(DEVKITPRO)/devkitARM/bin/bin2s $*.shbin | $(PREFIX)as -o $@
|
$(DEVKITARM)/bin/bin2s $*.shbin | $(PREFIX)as -o $@
|
||||||
rm $*.shbin
|
rm $*.shbin
|
||||||
|
|
||||||
%.o: %.vsh
|
%.o: %.vsh
|
||||||
$(DEVKITPRO)/devkitARM/bin/picasso $^ -o $*.shbin
|
$(DEVKITARM)/bin/picasso $^ -o $*.shbin
|
||||||
$(DEVKITPRO)/devkitARM/bin/bin2s $*.shbin | $(PREFIX)as -o $@
|
$(DEVKITARM)/bin/bin2s $*.shbin | $(PREFIX)as -o $@
|
||||||
rm $*.shbin
|
rm $*.shbin
|
||||||
|
|
||||||
%.o: %.cpp
|
%.o: %.cpp
|
||||||
@ -161,7 +161,7 @@ endif
|
|||||||
%.vsh:
|
%.vsh:
|
||||||
|
|
||||||
$(TARGET).smdh: $(APP_ICON)
|
$(TARGET).smdh: $(APP_ICON)
|
||||||
$(DEVKITPRO)/devkitARM/bin/smdhtool --create "$(APP_TITLE)" "$(APP_DESCRIPTION)" "$(APP_AUTHOR)" $(APP_ICON) $@
|
$(DEVKITARM)/bin/smdhtool --create "$(APP_TITLE)" "$(APP_DESCRIPTION)" "$(APP_AUTHOR)" $(APP_ICON) $@
|
||||||
|
|
||||||
$(TARGET).3dsx: $(TARGET).elf
|
$(TARGET).3dsx: $(TARGET).elf
|
||||||
ifeq ($(APP_BIG_TEXT_SECTION), 1)
|
ifeq ($(APP_BIG_TEXT_SECTION), 1)
|
||||||
|
@ -844,6 +844,7 @@ else ifeq ($(platform), vita)
|
|||||||
else ifneq (,$(findstring msvc,$(platform)))
|
else ifneq (,$(findstring msvc,$(platform)))
|
||||||
ifeq ($(platform), windows_msvc2003_x86)
|
ifeq ($(platform), windows_msvc2003_x86)
|
||||||
CFLAGS += -Wp64
|
CFLAGS += -Wp64
|
||||||
|
LDFLAGS += -SUBSYSTEM:WINDOWS -ENTRY:mainCRTStartup
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CFLAGS += -O2 -DNDEBUG -MT -TP
|
CFLAGS += -O2 -DNDEBUG -MT -TP
|
||||||
|
16
Makefile.ps3
16
Makefile.ps3
@ -63,7 +63,19 @@ endif
|
|||||||
|
|
||||||
PPU_SRCS = griffin/griffin.c
|
PPU_SRCS = griffin/griffin.c
|
||||||
|
|
||||||
DEFINES += -DHAVE_MENU -DHAVE_RGUI -DHAVE_XMB -DHAVE_LIBRETRODB -DHAVE_MATERIALUI -DHAVE_SHADERPIPELINE -DRARCH_INTERNAL -DMSB_FIRST -DHAVE_OVERLAY -DHAVE_CC_RESAMPLER -DHAVE_STB_VORBIS
|
DEFINES += -DHAVE_MENU -DHAVE_RGUI -DHAVE_XMB -DHAVE_LIBRETRODB -DHAVE_MATERIALUI -DHAVE_SHADERPIPELINE -DRARCH_INTERNAL -DMSB_FIRST -DHAVE_OVERLAY -DHAVE_CC_RESAMPLER -DHAVE_STB_VORBIS -DHAVE_STB_FONT
|
||||||
|
|
||||||
|
ifeq ($(DEX_BUILD), 1)
|
||||||
|
DEFINES += -DDEX_BUILD
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CEX_BUILD), 1)
|
||||||
|
DEFINES += -DCEX_BUILD
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ODE_BUILD), 1)
|
||||||
|
DEFINES += -DODE_BUILD
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(HAVE_GCMGL), 1)
|
ifeq ($(HAVE_GCMGL), 1)
|
||||||
DEFINES += -DHAVE_GCMGL
|
DEFINES += -DHAVE_GCMGL
|
||||||
@ -101,7 +113,7 @@ PPU_LDLIBS = $(FONT_LIBS) $(GL_LIBS) $(WHOLE_START) -lretro_ps3 $(WHOLE_END) -l
|
|||||||
|
|
||||||
PPU_RANLIB = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-ranlib.exe
|
PPU_RANLIB = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-ranlib.exe
|
||||||
|
|
||||||
DEFINES += -DHAVE_THREADS -DRARCH_CONSOLE -DHAVE_OPENGL -DHAVE_HEADSET -DHAVE_LANGEXTRA -DHAVE_OPENGLES -DHAVE_OPENGLES1 -DHAVE_PSGL -DHAVE_CG -DHAVE_CG_RUNTIME_COMPILER -DHAVE_SYSMODULES -DHAVE_SYSUTILS -DHAVE_RARCH_EXEC -DHAVE_RSOUND -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DHAVE_7Z -DWANT_ZLIB -DSINC_LOWER_QUALITY -D__CELLOS_LV2__ -DHAVE_NETWORKING=1 -DHAVE_SOCKET_LEGACY=1 -DHAVE_MOUSE -DHAVE_GRIFFIN=1 -DHAVE_MULTIMAN=1 -DPC_DEVELOPMENT_IP_ADDRESS=\"$(PC_DEVELOPMENT_IP_ADDRESS)\" -DPC_DEVELOPMENT_UDP_PORT=$(PC_DEVELOPMENT_UDP_PORT) -DHAVE_FILTERS_BUILTIN
|
DEFINES += -DHAVE_THREADS -DRARCH_CONSOLE -DHAVE_OPENGL -DHAVE_HEADSET -DHAVE_LANGEXTRA -DHAVE_OPENGLES -DHAVE_OPENGLES1 -DHAVE_PSGL -DHAVE_CG -DHAVE_CG_RUNTIME_COMPILER -DHAVE_SYSMODULES -DHAVE_SYSUTILS -DHAVE_RARCH_EXEC -DHAVE_RSOUND -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DHAVE_7Z -DWANT_ZLIB -DSINC_LOWER_QUALITY -D__CELLOS_LV2__ -DHAVE_NETWORKING=1 -DHAVE_SOCKET_LEGACY=1 -DHAVE_MOUSE -DHAVE_GRIFFIN=1 -DHAVE_MULTIMAN=1 -DPC_DEVELOPMENT_IP_ADDRESS=\"$(PC_DEVELOPMENT_IP_ADDRESS)\" -DPC_DEVELOPMENT_UDP_PORT=$(PC_DEVELOPMENT_UDP_PORT) -DHAVE_FILTERS_BUILTIN -DHAVE_CHEEVOS
|
||||||
|
|
||||||
#DEFINES += -DHAVE_IMAGEVIEWER
|
#DEFINES += -DHAVE_IMAGEVIEWER
|
||||||
|
|
||||||
|
@ -63,6 +63,18 @@ PPU_SRCS = griffin/griffin.c
|
|||||||
|
|
||||||
DEFINES += -DHAVE_RGUI -DHAVE_MATERIALUI -DHAVE_XMB -DHAVE_MENU -DRARCH_INTERNAL
|
DEFINES += -DHAVE_RGUI -DHAVE_MATERIALUI -DHAVE_XMB -DHAVE_MENU -DRARCH_INTERNAL
|
||||||
|
|
||||||
|
ifeq ($(DEX_BUILD), 1)
|
||||||
|
DEFINES += -DDEX_BUILD
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CEX_BUILD), 1)
|
||||||
|
DEFINES += -DCEX_BUILD
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ODE_BUILD), 1)
|
||||||
|
DEFINES += -DODE_BUILD
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(HAVE_GCMGL), 1)
|
ifeq ($(HAVE_GCMGL), 1)
|
||||||
DEFINES += -DHAVE_GCMGL
|
DEFINES += -DHAVE_GCMGL
|
||||||
GL_LIBS := -L. -lrgl_ps3
|
GL_LIBS := -L. -lrgl_ps3
|
||||||
|
@ -27,6 +27,18 @@ STRIP = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-strip.exe
|
|||||||
INCFLAGS = -I. -Idefines -Ilibretro-common/include -Ideps/libz
|
INCFLAGS = -I. -Idefines -Ilibretro-common/include -Ideps/libz
|
||||||
DEFINES = -D__CELLOS_LV2__ -DIS_SALAMANDER -DRARCH_CONSOLE -DHAVE_SYSUTILS -DHAVE_SYSMODULES -DHAVE_RARCH_EXEC
|
DEFINES = -D__CELLOS_LV2__ -DIS_SALAMANDER -DRARCH_CONSOLE -DHAVE_SYSUTILS -DHAVE_SYSMODULES -DHAVE_RARCH_EXEC
|
||||||
|
|
||||||
|
ifeq ($(DEX_BUILD), 1)
|
||||||
|
DEFINES += -DDEX_BUILD
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CEX_BUILD), 1)
|
||||||
|
DEFINES += -DCEX_BUILD
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ODE_BUILD), 1)
|
||||||
|
DEFINES += -DODE_BUILD
|
||||||
|
endif
|
||||||
|
|
||||||
PPU_CFLAGS := $(PPU_OPTIMIZE_LV) $(INCFLAGS) $(DEFINES)
|
PPU_CFLAGS := $(PPU_OPTIMIZE_LV) $(INCFLAGS) $(DEFINES)
|
||||||
PPU_CXXFLAGS := $(PPU_OPTIMIZE_LV) $(INCFLAGS) $(DEFINES)
|
PPU_CXXFLAGS := $(PPU_OPTIMIZE_LV) $(INCFLAGS) $(DEFINES)
|
||||||
|
|
||||||
|
@ -71,14 +71,14 @@ else
|
|||||||
HAVE_NETWORKING = 1
|
HAVE_NETWORKING = 1
|
||||||
HAVE_CHEEVOS = 1
|
HAVE_CHEEVOS = 1
|
||||||
# WANT_IFADDRS = 1
|
# WANT_IFADDRS = 1
|
||||||
|
HAVE_OVERLAY = 1
|
||||||
HAVE_STATIC_VIDEO_FILTERS = 1
|
HAVE_STATIC_VIDEO_FILTERS = 1
|
||||||
HAVE_STATIC_AUDIO_FILTERS = 1
|
HAVE_STATIC_AUDIO_FILTERS = 1
|
||||||
|
WANT_LIBFAT = 1
|
||||||
|
WANT_IOSUHAX = 1
|
||||||
|
|
||||||
include Makefile.common
|
include Makefile.common
|
||||||
BLACKLIST :=
|
BLACKLIST := $(LIBRETRO_COMM_DIR)/net/net_ifinfo.o
|
||||||
BLACKLIST += input/input_overlay.o
|
|
||||||
BLACKLIST += tasks/task_overlay.o
|
|
||||||
BLACKLIST += $(LIBRETRO_COMM_DIR)/net/net_ifinfo.o
|
|
||||||
OBJ := $(filter-out $(BLACKLIST),$(OBJ))
|
OBJ := $(filter-out $(BLACKLIST),$(OBJ))
|
||||||
|
|
||||||
OBJ += gfx/drivers/wiiu_gfx.o
|
OBJ += gfx/drivers/wiiu_gfx.o
|
||||||
@ -141,7 +141,7 @@ CFLAGS += -ffast-math -Werror=implicit-function-declaration
|
|||||||
#CFLAGS += -Wall
|
#CFLAGS += -Wall
|
||||||
|
|
||||||
#todo: remove -DWIIU and use the built-in macros instead (HW_WUP or __wiiu__).
|
#todo: remove -DWIIU and use the built-in macros instead (HW_WUP or __wiiu__).
|
||||||
CFLAGS += -DWIIU -DMSB_FIRST
|
CFLAGS += -DWIIU -DMSB_FIRST -D__WUT__
|
||||||
CFLAGS += -DHAVE_MAIN
|
CFLAGS += -DHAVE_MAIN
|
||||||
CFLAGS += -DHAVE_UPDATE_ASSETS
|
CFLAGS += -DHAVE_UPDATE_ASSETS
|
||||||
CFLAGS += -DRARCH_INTERNAL -DRARCH_CONSOLE
|
CFLAGS += -DRARCH_INTERNAL -DRARCH_CONSOLE
|
||||||
@ -166,7 +166,15 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -D_GNU_SOURCE
|
|||||||
|
|
||||||
LDFLAGS += -Wl,--gc-sections
|
LDFLAGS += -Wl,--gc-sections
|
||||||
|
|
||||||
LIBS := $(WHOLE_START) -lretro_wiiu $(WHOLE_END) -lm -lfat -liosuhax
|
LIBS := $(WHOLE_START) -lretro_wiiu $(WHOLE_END) -lm
|
||||||
|
|
||||||
|
ifneq ($(WANT_LIBFAT), 1)
|
||||||
|
LIBS += -lfat
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(WANT_IOSUHAX), 1)
|
||||||
|
LIBS += -liosuhax
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
RPX_OBJ = wiiu/system/stubs_rpl.o
|
RPX_OBJ = wiiu/system/stubs_rpl.o
|
||||||
|
@ -63,6 +63,7 @@ RetroArch also emphasizes on being easy to integrate into various launcher front
|
|||||||
|
|
||||||
RetroArch has been ported to the following platforms:
|
RetroArch has been ported to the following platforms:
|
||||||
|
|
||||||
|
- DOS
|
||||||
- Windows
|
- Windows
|
||||||
- Linux
|
- Linux
|
||||||
- FreeBSD
|
- FreeBSD
|
||||||
|
@ -45,6 +45,12 @@ typedef struct xaudio2 xaudio2_t;
|
|||||||
|
|
||||||
#define MAX_BUFFERS_MASK (MAX_BUFFERS - 1)
|
#define MAX_BUFFERS_MASK (MAX_BUFFERS - 1)
|
||||||
|
|
||||||
|
#ifndef COINIT_MULTITHREADED
|
||||||
|
#define COINIT_MULTITHREADED 0x00
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define XAUDIO2_WRITE_AVAILABLE(handle) ((handle)->bufsize * (MAX_BUFFERS - (handle)->buffers - 1))
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
xaudio2_t *xa;
|
xaudio2_t *xa;
|
||||||
@ -190,10 +196,6 @@ static void xaudio2_free(xaudio2_t *handle)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef COINIT_MULTITHREADED
|
|
||||||
#define COINIT_MULTITHREADED 0x00
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static xaudio2_t *xaudio2_new(unsigned samplerate, unsigned channels,
|
static xaudio2_t *xaudio2_new(unsigned samplerate, unsigned channels,
|
||||||
size_t size, unsigned device)
|
size_t size, unsigned device)
|
||||||
{
|
{
|
||||||
@ -251,15 +253,9 @@ error:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t xaudio2_write_avail(xaudio2_t *handle)
|
static size_t xaudio2_write(xaudio2_t *handle, const uint8_t *buffer, size_t bytes_)
|
||||||
{
|
|
||||||
return handle->bufsize * (MAX_BUFFERS - handle->buffers - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t xaudio2_write(xaudio2_t *handle, const void *buf, size_t bytes_)
|
|
||||||
{
|
{
|
||||||
unsigned bytes = bytes_;
|
unsigned bytes = bytes_;
|
||||||
const uint8_t *buffer = (const uint8_t*)buf;
|
|
||||||
|
|
||||||
while (bytes)
|
while (bytes)
|
||||||
{
|
{
|
||||||
@ -344,7 +340,7 @@ static ssize_t xa_write(void *data, const void *buf, size_t size)
|
|||||||
|
|
||||||
if (xa->nonblock)
|
if (xa->nonblock)
|
||||||
{
|
{
|
||||||
size_t avail = xaudio2_write_avail(xa->xa);
|
size_t avail = XAUDIO2_WRITE_AVAILABLE(xa->xa);
|
||||||
|
|
||||||
if (avail == 0)
|
if (avail == 0)
|
||||||
return 0;
|
return 0;
|
||||||
@ -352,7 +348,7 @@ static ssize_t xa_write(void *data, const void *buf, size_t size)
|
|||||||
size = avail;
|
size = avail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = xaudio2_write(xa->xa, buf, size);
|
ret = xaudio2_write(xa->xa, (const uint8_t*)buf, size);
|
||||||
if (ret == 0 && size > 0)
|
if (ret == 0 && size > 0)
|
||||||
return -1;
|
return -1;
|
||||||
return ret;
|
return ret;
|
||||||
@ -408,7 +404,7 @@ static void xa_free(void *data)
|
|||||||
static size_t xa_write_avail(void *data)
|
static size_t xa_write_avail(void *data)
|
||||||
{
|
{
|
||||||
xa_t *xa = (xa_t*)data;
|
xa_t *xa = (xa_t*)data;
|
||||||
return xaudio2_write_avail(xa->xa);
|
return XAUDIO2_WRITE_AVAILABLE(xa->xa);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t xa_buffer_size(void *data)
|
static size_t xa_buffer_size(void *data)
|
||||||
|
@ -55,9 +55,10 @@ void exitspawn_kernel(const char *fileName, SceSize args, void *argp)
|
|||||||
game_param.unk4 = 0;
|
game_param.unk4 = 0;
|
||||||
game_param.unk5 = 0x10000;
|
game_param.unk5 = 0x10000;
|
||||||
|
|
||||||
pspSdkSetK1(0);
|
int k1 = pspSdkSetK1(0);
|
||||||
sceKernelSuspendAllUserThreads();
|
//sceKernelSuspendAllUserThreads();
|
||||||
sceKernelLoadExecVSHMs2(fileName, &game_param);
|
int ret = sceKernelLoadExecVSHMs2(fileName, &game_param);
|
||||||
|
pspSdkSetK1(k1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int module_start(SceSize args, void *argp)
|
int module_start(SceSize args, void *argp)
|
||||||
|
16
command.c
16
command.c
@ -1957,6 +1957,10 @@ bool command_event(enum event_command cmd, void *data)
|
|||||||
cheevos_toggle_hardcore_mode();
|
cheevos_toggle_hardcore_mode();
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
/* this fallthrough is on purpose, it should do
|
||||||
|
a CMD_EVENT_REINIT too */
|
||||||
|
case CMD_EVENT_REINIT_FROM_TOGGLE:
|
||||||
|
retroarch_unset_forced_fullscreen();
|
||||||
case CMD_EVENT_REINIT:
|
case CMD_EVENT_REINIT:
|
||||||
video_driver_reinit();
|
video_driver_reinit();
|
||||||
/* Poll input to avoid possibly stale data to corrupt things. */
|
/* Poll input to avoid possibly stale data to corrupt things. */
|
||||||
@ -2567,15 +2571,21 @@ TODO: Add a setting for these tweaks */
|
|||||||
case CMD_EVENT_FULLSCREEN_TOGGLE:
|
case CMD_EVENT_FULLSCREEN_TOGGLE:
|
||||||
{
|
{
|
||||||
settings_t *settings = config_get_ptr();
|
settings_t *settings = config_get_ptr();
|
||||||
bool new_fullscreen_state = !settings->bools.video_fullscreen;
|
bool new_fullscreen_state = !settings->bools.video_fullscreen
|
||||||
|
&& !retroarch_is_forced_fullscreen();
|
||||||
if (!video_driver_has_windowed())
|
if (!video_driver_has_windowed())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* If we go fullscreen we drop all drivers and
|
/* we toggled manually, write the new value to settings */
|
||||||
* reinitialize to be safe. */
|
|
||||||
configuration_set_bool(settings, settings->bools.video_fullscreen,
|
configuration_set_bool(settings, settings->bools.video_fullscreen,
|
||||||
new_fullscreen_state);
|
new_fullscreen_state);
|
||||||
|
|
||||||
|
/* we toggled manually, the cli arg is irrelevant now */
|
||||||
|
if (retroarch_is_forced_fullscreen())
|
||||||
|
retroarch_unset_forced_fullscreen();
|
||||||
|
|
||||||
|
/* If we go fullscreen we drop all drivers and
|
||||||
|
* reinitialize to be safe. */
|
||||||
command_event(CMD_EVENT_REINIT, NULL);
|
command_event(CMD_EVENT_REINIT, NULL);
|
||||||
if (settings->bools.video_fullscreen)
|
if (settings->bools.video_fullscreen)
|
||||||
video_driver_hide_mouse();
|
video_driver_hide_mouse();
|
||||||
|
@ -61,6 +61,8 @@ enum event_command
|
|||||||
/* Quits RetroArch. */
|
/* Quits RetroArch. */
|
||||||
CMD_EVENT_QUIT,
|
CMD_EVENT_QUIT,
|
||||||
/* Reinitialize all drivers. */
|
/* Reinitialize all drivers. */
|
||||||
|
CMD_EVENT_REINIT_FROM_TOGGLE,
|
||||||
|
/* Reinitialize all drivers. */
|
||||||
CMD_EVENT_REINIT,
|
CMD_EVENT_REINIT,
|
||||||
/* Toggles cheevos hardcore mode. */
|
/* Toggles cheevos hardcore mode. */
|
||||||
CMD_EVENT_CHEEVOS_HARDCORE_MODE_TOGGLE,
|
CMD_EVENT_CHEEVOS_HARDCORE_MODE_TOGGLE,
|
||||||
|
10
config.def.h
10
config.def.h
@ -298,11 +298,7 @@ static bool xmb_show_add = true;
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_LIBRETRODB) && !defined(RARCH_CONSOLE) && !defined(EMSCRIPTEN)
|
|
||||||
static bool automatically_add_content_to_playlist = true;
|
|
||||||
#else
|
|
||||||
static bool automatically_add_content_to_playlist = false;
|
static bool automatically_add_content_to_playlist = false;
|
||||||
#endif
|
|
||||||
|
|
||||||
static float menu_framebuffer_opacity = 0.900;
|
static float menu_framebuffer_opacity = 0.900;
|
||||||
|
|
||||||
@ -689,6 +685,12 @@ static char buildbot_server_url[] = "";
|
|||||||
#endif
|
#endif
|
||||||
#elif defined(WIIU)
|
#elif defined(WIIU)
|
||||||
static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/nintendo/wiiu/latest/";
|
static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/nintendo/wiiu/latest/";
|
||||||
|
#elif defined(__CELLOS_LV2__) && defined(DEX_BUILD)
|
||||||
|
static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/playstation/ps3/latest/dex-ps3/";
|
||||||
|
#elif defined(__CELLOS_LV2__) && defined(CEX_BUILD)
|
||||||
|
static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/playstation/ps3/latest/cex-ps3/";
|
||||||
|
#elif defined(__CELLOS_LV2__) && defined(ODE_BUILD)
|
||||||
|
static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/playstation/ps3/latest/ode-ps3/";
|
||||||
#else
|
#else
|
||||||
static char buildbot_server_url[] = "";
|
static char buildbot_server_url[] = "";
|
||||||
#endif
|
#endif
|
||||||
|
@ -1578,11 +1578,6 @@ static void config_set_defaults(void)
|
|||||||
#endif
|
#endif
|
||||||
settings->floats.video_scale = scale;
|
settings->floats.video_scale = scale;
|
||||||
|
|
||||||
if (retroarch_is_forced_fullscreen())
|
|
||||||
{
|
|
||||||
configuration_set_bool(settings, settings->bools.video_fullscreen, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_defaults.settings.video_threaded_enable != video_threaded)
|
if (g_defaults.settings.video_threaded_enable != video_threaded)
|
||||||
video_driver_set_threaded(g_defaults.settings.video_threaded_enable);
|
video_driver_set_threaded(g_defaults.settings.video_threaded_enable);
|
||||||
|
|
||||||
@ -2377,9 +2372,6 @@ static bool config_load_file(const char *path, bool set_defaults,
|
|||||||
*bool_settings[i].ptr = tmp;
|
*bool_settings[i].ptr = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!retroarch_is_forced_fullscreen())
|
|
||||||
CONFIG_GET_BOOL_BASE(conf, settings, bools.video_fullscreen, "video_fullscreen");
|
|
||||||
|
|
||||||
#ifdef HAVE_NETWORKGAMEPAD
|
#ifdef HAVE_NETWORKGAMEPAD
|
||||||
for (i = 0; i < MAX_USERS; i++)
|
for (i = 0; i < MAX_USERS; i++)
|
||||||
{
|
{
|
||||||
|
@ -272,7 +272,7 @@ void CORE_PREFIX(retro_set_environment)(retro_environment_t cb)
|
|||||||
{
|
{
|
||||||
static const struct retro_variable vars[] = {
|
static const struct retro_variable vars[] = {
|
||||||
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
|
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
|
||||||
{ "ffmpeg_temporal_interp", "Temporal Interpolation; enabled|disabled" },
|
{ "ffmpeg_temporal_interp", "Temporal Interpolation; disabled|enabled" },
|
||||||
#ifdef HAVE_GL_FFT
|
#ifdef HAVE_GL_FFT
|
||||||
{ "ffmpeg_fft_resolution", "FFT Resolution; 1280x720|1920x1080|2560x1440|3840x2160|640x360|320x180" },
|
{ "ffmpeg_fft_resolution", "FFT Resolution; 1280x720|1920x1080|2560x1440|3840x2160|640x360|320x180" },
|
||||||
{ "ffmpeg_fft_multisample", "FFT Multisample; 1x|2x|4x" },
|
{ "ffmpeg_fft_multisample", "FFT Multisample; 1x|2x|4x" },
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
image_core.so: image_core.c
|
image_core.so: image_core.c
|
||||||
gcc \
|
gcc \
|
||||||
-g \
|
-g \
|
||||||
|
-DHAVE_STB_IMAGE \
|
||||||
image_core.c \
|
image_core.c \
|
||||||
../../libretro-common/file/file_path.c \
|
-I../../libretro-common/include/ \
|
||||||
../../libretro-common/lists/dir_list.c \
|
-I../../deps/stb/ \
|
||||||
../../libretro-common/compat/compat_strl.c \
|
|
||||||
../../libretro-common/compat/compat_strcasestr.c \
|
../../libretro-common/compat/compat_strcasestr.c \
|
||||||
../../libretro-common/lists/string_list.c \
|
../../libretro-common/compat/compat_strl.c \
|
||||||
|
../../libretro-common/file/file_path.c \
|
||||||
../../libretro-common/file/retro_dirent.c \
|
../../libretro-common/file/retro_dirent.c \
|
||||||
|
../../libretro-common/lists/dir_list.c \
|
||||||
|
../../libretro-common/lists/string_list.c \
|
||||||
../../libretro-common/streams/file_stream.c \
|
../../libretro-common/streams/file_stream.c \
|
||||||
../../libretro-common/vfs/vfs_implementation.c \
|
../../libretro-common/vfs/vfs_implementation.c \
|
||||||
-o image_core.so \
|
|
||||||
-DHAVE_STB_IMAGE \
|
|
||||||
-I ../../libretro-common/include/ \
|
|
||||||
-I../../deps/stb \
|
|
||||||
-Wl,--no-undefined \
|
|
||||||
-shared \
|
-shared \
|
||||||
-fPIC \
|
-fPIC \
|
||||||
-lm
|
-Wl,--no-undefined \
|
||||||
|
-lm \
|
||||||
|
-o image_core.so
|
||||||
|
@ -306,3 +306,18 @@ void GPU_FinishDrawing()
|
|||||||
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_INVALIDATE, 0x00000001);
|
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_INVALIDATE, 0x00000001);
|
||||||
GPUCMD_AddWrite(GPUREG_EARLYDEPTH_CLEAR, 0x00000001);
|
GPUCMD_AddWrite(GPUREG_EARLYDEPTH_CLEAR, 0x00000001);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GPU_Finalize(void)
|
||||||
|
{
|
||||||
|
GPUCMD_AddMaskedWrite(GPUREG_PRIMITIVE_CONFIG, 0x8, 0x00000000);
|
||||||
|
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_FLUSH, 0x00000001);
|
||||||
|
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_INVALIDATE, 0x00000001);
|
||||||
|
#if 0
|
||||||
|
GPUCMD_Split(NULL, NULL);
|
||||||
|
#else
|
||||||
|
GPUCMD_AddWrite(GPUREG_FINALIZE, 0x12345678);
|
||||||
|
//not the cleanest way of guaranteeing 0x10-byte size but whatever good enough for now
|
||||||
|
GPUCMD_AddWrite(GPUREG_FINALIZE,0x12345678);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@ -235,3 +235,5 @@ void GPU_DrawElements(GPU_Primitive_t primitive, u32* indexArray, u32 n) DEPRECA
|
|||||||
* @deprecated
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
void GPU_FinishDrawing() DEPRECATED;
|
void GPU_FinishDrawing() DEPRECATED;
|
||||||
|
|
||||||
|
void GPU_Finalize(void) DEPRECATED;
|
||||||
|
61
deps/libfat/bit_ops.h
vendored
Normal file
61
deps/libfat/bit_ops.h
vendored
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
bit_ops.h
|
||||||
|
Functions for dealing with conversion of data between types
|
||||||
|
|
||||||
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _BIT_OPS_H
|
||||||
|
#define _BIT_OPS_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------
|
||||||
|
Functions to deal with little endian values stored in uint8_t arrays
|
||||||
|
-----------------------------------------------------------------*/
|
||||||
|
static inline uint16_t u8array_to_u16 (const uint8_t* item, int offset)
|
||||||
|
{
|
||||||
|
return ( item[offset] | (item[offset + 1] << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t u8array_to_u32 (const uint8_t* item, int offset)
|
||||||
|
{
|
||||||
|
return ( item[offset] | (item[offset + 1] << 8) | (item[offset + 2] << 16) | (item[offset + 3] << 24));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void u16_to_u8array (uint8_t* item, int offset, uint16_t value)
|
||||||
|
{
|
||||||
|
item[offset] = (uint8_t) value;
|
||||||
|
item[offset + 1] = (uint8_t)(value >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void u32_to_u8array (uint8_t* item, int offset, uint32_t value)
|
||||||
|
{
|
||||||
|
item[offset] = (uint8_t) value;
|
||||||
|
item[offset + 1] = (uint8_t)(value >> 8);
|
||||||
|
item[offset + 2] = (uint8_t)(value >> 16);
|
||||||
|
item[offset + 3] = (uint8_t)(value >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _BIT_OPS_H */
|
336
deps/libfat/cache.c
vendored
Normal file
336
deps/libfat/cache.c
vendored
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
/*
|
||||||
|
cache.c
|
||||||
|
The cache is not visible to the user. It should be flushed
|
||||||
|
when any file is closed or changes are made to the filesystem.
|
||||||
|
|
||||||
|
This cache implements a least-used-page replacement policy. This will
|
||||||
|
distribute sectors evenly over the pages, so if less than the maximum
|
||||||
|
pages are used at once, they should all eventually remain in the cache.
|
||||||
|
This also has the benefit of throwing out old sectors, so as not to keep
|
||||||
|
too many stale pages around.
|
||||||
|
|
||||||
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "cache.h"
|
||||||
|
#include "disc.h"
|
||||||
|
|
||||||
|
#include "mem_allocate.h"
|
||||||
|
#include "bit_ops.h"
|
||||||
|
#include "file_allocation_table.h"
|
||||||
|
|
||||||
|
#define CACHE_FREE UINT_MAX
|
||||||
|
|
||||||
|
CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, unsigned int bytesPerSector)
|
||||||
|
{
|
||||||
|
CACHE* cache;
|
||||||
|
unsigned int i;
|
||||||
|
CACHE_ENTRY* cacheEntries;
|
||||||
|
|
||||||
|
if (numberOfPages < 2)
|
||||||
|
numberOfPages = 2;
|
||||||
|
|
||||||
|
if (sectorsPerPage < 8)
|
||||||
|
sectorsPerPage = 8;
|
||||||
|
|
||||||
|
cache = (CACHE*) _FAT_mem_allocate (sizeof(CACHE));
|
||||||
|
if (cache == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cache->disc = discInterface;
|
||||||
|
cache->endOfPartition = endOfPartition;
|
||||||
|
cache->numberOfPages = numberOfPages;
|
||||||
|
cache->sectorsPerPage = sectorsPerPage;
|
||||||
|
cache->bytesPerSector = bytesPerSector;
|
||||||
|
|
||||||
|
|
||||||
|
cacheEntries = (CACHE_ENTRY*) _FAT_mem_allocate ( sizeof(CACHE_ENTRY) * numberOfPages);
|
||||||
|
if (cacheEntries == NULL)
|
||||||
|
{
|
||||||
|
_FAT_mem_free (cache);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < numberOfPages; i++)
|
||||||
|
{
|
||||||
|
cacheEntries[i].sector = CACHE_FREE;
|
||||||
|
cacheEntries[i].count = 0;
|
||||||
|
cacheEntries[i].last_access = 0;
|
||||||
|
cacheEntries[i].dirty = false;
|
||||||
|
cacheEntries[i].cache = (uint8_t*) _FAT_mem_align ( sectorsPerPage * bytesPerSector );
|
||||||
|
}
|
||||||
|
|
||||||
|
cache->cacheEntries = cacheEntries;
|
||||||
|
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _FAT_cache_destructor (CACHE* cache)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
/* Clear out cache before destroying it */
|
||||||
|
_FAT_cache_flush(cache);
|
||||||
|
|
||||||
|
/* Free memory in reverse allocation order */
|
||||||
|
for (i = 0; i < cache->numberOfPages; i++)
|
||||||
|
_FAT_mem_free (cache->cacheEntries[i].cache);
|
||||||
|
_FAT_mem_free (cache->cacheEntries);
|
||||||
|
_FAT_mem_free (cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static u32 accessCounter = 0;
|
||||||
|
|
||||||
|
static u32 accessTime(){
|
||||||
|
accessCounter++;
|
||||||
|
return accessCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static CACHE_ENTRY* _FAT_cache_getPage(CACHE *cache,sec_t sector)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||||
|
unsigned int numberOfPages = cache->numberOfPages;
|
||||||
|
unsigned int sectorsPerPage = cache->sectorsPerPage;
|
||||||
|
|
||||||
|
bool foundFree = false;
|
||||||
|
unsigned int oldUsed = 0;
|
||||||
|
unsigned int oldAccess = UINT_MAX;
|
||||||
|
|
||||||
|
for(i=0;i<numberOfPages;i++)
|
||||||
|
{
|
||||||
|
if(sector>=cacheEntries[i].sector && sector<(cacheEntries[i].sector + cacheEntries[i].count))
|
||||||
|
{
|
||||||
|
cacheEntries[i].last_access = accessTime();
|
||||||
|
return &(cacheEntries[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(foundFree==false && (cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_access<oldAccess))
|
||||||
|
{
|
||||||
|
if(cacheEntries[i].sector==CACHE_FREE) foundFree = true;
|
||||||
|
oldUsed = i;
|
||||||
|
oldAccess = cacheEntries[i].last_access;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(foundFree==false && cacheEntries[oldUsed].dirty==true)
|
||||||
|
{
|
||||||
|
if(!_FAT_disc_writeSectors(cache->disc,cacheEntries[oldUsed].sector,cacheEntries[oldUsed].count,cacheEntries[oldUsed].cache)) return NULL;
|
||||||
|
cacheEntries[oldUsed].dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sector = (sector/sectorsPerPage)*sectorsPerPage; /* align base sector to page size */
|
||||||
|
sec_t next_page = sector + sectorsPerPage;
|
||||||
|
if(next_page > cache->endOfPartition) next_page = cache->endOfPartition;
|
||||||
|
|
||||||
|
if(!_FAT_disc_readSectors(cache->disc,sector,next_page-sector,cacheEntries[oldUsed].cache)) return NULL;
|
||||||
|
|
||||||
|
cacheEntries[oldUsed].sector = sector;
|
||||||
|
cacheEntries[oldUsed].count = next_page-sector;
|
||||||
|
cacheEntries[oldUsed].last_access = accessTime();
|
||||||
|
|
||||||
|
return &(cacheEntries[oldUsed]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _FAT_cache_readSectors(CACHE *cache,sec_t sector,sec_t numSectors,void *buffer)
|
||||||
|
{
|
||||||
|
sec_t sec;
|
||||||
|
sec_t secs_to_read;
|
||||||
|
CACHE_ENTRY *entry;
|
||||||
|
uint8_t *dest = (uint8_t *)buffer;
|
||||||
|
|
||||||
|
while(numSectors>0)
|
||||||
|
{
|
||||||
|
entry = _FAT_cache_getPage(cache,sector);
|
||||||
|
if(entry==NULL) return false;
|
||||||
|
|
||||||
|
sec = sector - entry->sector;
|
||||||
|
secs_to_read = entry->count - sec;
|
||||||
|
if(secs_to_read>numSectors) secs_to_read = numSectors;
|
||||||
|
|
||||||
|
memcpy(dest,entry->cache + (sec*cache->bytesPerSector),(secs_to_read*cache->bytesPerSector));
|
||||||
|
|
||||||
|
dest += (secs_to_read*cache->bytesPerSector);
|
||||||
|
sector += secs_to_read;
|
||||||
|
numSectors -= secs_to_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reads some data from a cache page, determined by the sector number
|
||||||
|
*/
|
||||||
|
bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||||
|
{
|
||||||
|
sec_t sec;
|
||||||
|
CACHE_ENTRY *entry;
|
||||||
|
|
||||||
|
if (offset + size > cache->bytesPerSector) return false;
|
||||||
|
|
||||||
|
entry = _FAT_cache_getPage(cache,sector);
|
||||||
|
if(entry==NULL) return false;
|
||||||
|
|
||||||
|
sec = sector - entry->sector;
|
||||||
|
memcpy(buffer,entry->cache + ((sec*cache->bytesPerSector) + offset),size);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes)
|
||||||
|
{
|
||||||
|
uint8_t buf[4];
|
||||||
|
if (!_FAT_cache_readPartialSector(cache, buf, sector, offset, num_bytes)) return false;
|
||||||
|
|
||||||
|
switch(num_bytes)
|
||||||
|
{
|
||||||
|
case 1: *value = buf[0]; break;
|
||||||
|
case 2: *value = u8array_to_u16(buf,0); break;
|
||||||
|
case 4: *value = u8array_to_u32(buf,0); break;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Writes some data to a cache page, making sure it is loaded into memory first.
|
||||||
|
*/
|
||||||
|
bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||||
|
{
|
||||||
|
sec_t sec;
|
||||||
|
CACHE_ENTRY *entry;
|
||||||
|
|
||||||
|
if (offset + size > cache->bytesPerSector) return false;
|
||||||
|
|
||||||
|
entry = _FAT_cache_getPage(cache,sector);
|
||||||
|
if(entry==NULL) return false;
|
||||||
|
|
||||||
|
sec = sector - entry->sector;
|
||||||
|
memcpy(entry->cache + ((sec*cache->bytesPerSector) + offset),buffer,size);
|
||||||
|
|
||||||
|
entry->dirty = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size)
|
||||||
|
{
|
||||||
|
uint8_t buf[4] = {0, 0, 0, 0};
|
||||||
|
|
||||||
|
switch(size)
|
||||||
|
{
|
||||||
|
case 1: buf[0] = value; break;
|
||||||
|
case 2: u16_to_u8array(buf, 0, value); break;
|
||||||
|
case 4: u32_to_u8array(buf, 0, value); break;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _FAT_cache_writePartialSector(cache, buf, sector, offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Writes some data to a cache page, zeroing out the page first
|
||||||
|
*/
|
||||||
|
bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||||
|
{
|
||||||
|
sec_t sec;
|
||||||
|
CACHE_ENTRY *entry;
|
||||||
|
|
||||||
|
if (offset + size > cache->bytesPerSector) return false;
|
||||||
|
|
||||||
|
entry = _FAT_cache_getPage(cache,sector);
|
||||||
|
if(entry==NULL) return false;
|
||||||
|
|
||||||
|
sec = sector - entry->sector;
|
||||||
|
memset(entry->cache + (sec*cache->bytesPerSector),0,cache->bytesPerSector);
|
||||||
|
memcpy(entry->cache + ((sec*cache->bytesPerSector) + offset),buffer,size);
|
||||||
|
|
||||||
|
entry->dirty = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer)
|
||||||
|
{
|
||||||
|
sec_t sec;
|
||||||
|
sec_t secs_to_write;
|
||||||
|
CACHE_ENTRY* entry;
|
||||||
|
const uint8_t *src = (const uint8_t *)buffer;
|
||||||
|
|
||||||
|
while(numSectors>0)
|
||||||
|
{
|
||||||
|
entry = _FAT_cache_getPage(cache,sector);
|
||||||
|
if(entry==NULL) return false;
|
||||||
|
|
||||||
|
sec = sector - entry->sector;
|
||||||
|
secs_to_write = entry->count - sec;
|
||||||
|
if(secs_to_write>numSectors) secs_to_write = numSectors;
|
||||||
|
|
||||||
|
memcpy(entry->cache + (sec*cache->bytesPerSector),src,(secs_to_write*cache->bytesPerSector));
|
||||||
|
|
||||||
|
src += (secs_to_write*cache->bytesPerSector);
|
||||||
|
sector += secs_to_write;
|
||||||
|
numSectors -= secs_to_write;
|
||||||
|
|
||||||
|
entry->dirty = true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Flushes all dirty pages to disc, clearing the dirty flag.
|
||||||
|
*/
|
||||||
|
bool _FAT_cache_flush (CACHE* cache)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < cache->numberOfPages; i++)
|
||||||
|
{
|
||||||
|
if (cache->cacheEntries[i].dirty)
|
||||||
|
{
|
||||||
|
if (!_FAT_disc_writeSectors (cache->disc, cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cache->cacheEntries[i].dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _FAT_cache_invalidate (CACHE* cache)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
_FAT_cache_flush(cache);
|
||||||
|
for (i = 0; i < cache->numberOfPages; i++)
|
||||||
|
{
|
||||||
|
cache->cacheEntries[i].sector = CACHE_FREE;
|
||||||
|
cache->cacheEntries[i].last_access = 0;
|
||||||
|
cache->cacheEntries[i].count = 0;
|
||||||
|
cache->cacheEntries[i].dirty = false;
|
||||||
|
}
|
||||||
|
}
|
128
deps/libfat/cache.h
vendored
Normal file
128
deps/libfat/cache.h
vendored
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
cache.h
|
||||||
|
The cache is not visible to the user. It should be flushed
|
||||||
|
when any file is closed or changes are made to the filesystem.
|
||||||
|
|
||||||
|
This cache implements a least-used-page replacement policy. This will
|
||||||
|
distribute sectors evenly over the pages, so if less than the maximum
|
||||||
|
pages are used at once, they should all eventually remain in the cache.
|
||||||
|
This also has the benefit of throwing out old sectors, so as not to keep
|
||||||
|
too many stale pages around.
|
||||||
|
|
||||||
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CACHE_H
|
||||||
|
#define _CACHE_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "disc.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
sec_t sector;
|
||||||
|
unsigned int count;
|
||||||
|
unsigned int last_access;
|
||||||
|
bool dirty;
|
||||||
|
uint8_t* cache;
|
||||||
|
} CACHE_ENTRY;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const DISC_INTERFACE* disc;
|
||||||
|
sec_t endOfPartition;
|
||||||
|
unsigned int numberOfPages;
|
||||||
|
unsigned int sectorsPerPage;
|
||||||
|
unsigned int bytesPerSector;
|
||||||
|
CACHE_ENTRY* cacheEntries;
|
||||||
|
} CACHE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Read data from a sector in the cache
|
||||||
|
If the sector is not in the cache, it will be swapped in
|
||||||
|
offset is the position to start reading from
|
||||||
|
size is the amount of data to read
|
||||||
|
Precondition: offset + size <= BYTES_PER_READ
|
||||||
|
*/
|
||||||
|
bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size);
|
||||||
|
|
||||||
|
bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Write data to a sector in the cache
|
||||||
|
If the sector is not in the cache, it will be swapped in.
|
||||||
|
When the sector is swapped out, the data will be written to the disc
|
||||||
|
offset is the position to start writing to
|
||||||
|
size is the amount of data to write
|
||||||
|
Precondition: offset + size <= BYTES_PER_READ
|
||||||
|
*/
|
||||||
|
bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size);
|
||||||
|
|
||||||
|
bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int num_bytes);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Write data to a sector in the cache, zeroing the sector first
|
||||||
|
If the sector is not in the cache, it will be swapped in.
|
||||||
|
When the sector is swapped out, the data will be written to the disc
|
||||||
|
offset is the position to start writing to
|
||||||
|
size is the amount of data to write
|
||||||
|
Precondition: offset + size <= BYTES_PER_READ
|
||||||
|
*/
|
||||||
|
bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Read several sectors from the cache
|
||||||
|
*/
|
||||||
|
bool _FAT_cache_readSectors (CACHE* cache, sec_t sector, sec_t numSectors, void* buffer);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Read a full sector from the cache
|
||||||
|
*/
|
||||||
|
static inline bool _FAT_cache_readSector (CACHE* cache, void* buffer, sec_t sector) {
|
||||||
|
return _FAT_cache_readPartialSector (cache, buffer, sector, 0, cache->bytesPerSector);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Write a full sector to the cache
|
||||||
|
*/
|
||||||
|
static inline bool _FAT_cache_writeSector (CACHE* cache, const void* buffer, sec_t sector) {
|
||||||
|
return _FAT_cache_writePartialSector (cache, buffer, sector, 0, cache->bytesPerSector);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Write any dirty sectors back to disc and clear out the contents of the cache
|
||||||
|
*/
|
||||||
|
bool _FAT_cache_flush (CACHE* cache);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Clear out the contents of the cache without writing any dirty sectors first
|
||||||
|
*/
|
||||||
|
void _FAT_cache_invalidate (CACHE* cache);
|
||||||
|
|
||||||
|
CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, unsigned int bytesPerSector);
|
||||||
|
|
||||||
|
void _FAT_cache_destructor (CACHE* cache);
|
||||||
|
|
||||||
|
#endif // _CACHE_H
|
||||||
|
|
92
deps/libfat/common.h
vendored
Normal file
92
deps/libfat/common.h
vendored
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
common.h
|
||||||
|
Common definitions and included files for the FATlib
|
||||||
|
|
||||||
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _COMMON_H
|
||||||
|
#define _COMMON_H
|
||||||
|
|
||||||
|
#include <fat.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* When compiling for NDS, make sure NDS is defined */
|
||||||
|
#ifndef NDS
|
||||||
|
#if defined ARM9 || defined ARM7
|
||||||
|
#define NDS
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Platform specific includes */
|
||||||
|
#if defined (__wiiu__)
|
||||||
|
#include <iosuhax_disc_interface.h>
|
||||||
|
typedef uint8_t u8;
|
||||||
|
typedef uint16_t u16;
|
||||||
|
typedef int32_t s32;
|
||||||
|
typedef uint32_t u32;
|
||||||
|
typedef int mutex_t;
|
||||||
|
#elif defined(__gamecube__) || defined (__wii__)
|
||||||
|
#include <gctypes.h>
|
||||||
|
#include <ogc/disc_io.h>
|
||||||
|
#include <gccore.h>
|
||||||
|
#elif defined(NDS)
|
||||||
|
#include <nds/ndstypes.h>
|
||||||
|
#include <nds/system.h>
|
||||||
|
#include <nds/disc_io.h>
|
||||||
|
#elif defined(GBA)
|
||||||
|
#include <gba_types.h>
|
||||||
|
#include <disc_io.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Platform specific options */
|
||||||
|
#if defined (__wiiu__)
|
||||||
|
#define DEFAULT_CACHE_PAGES 4
|
||||||
|
#define DEFAULT_SECTORS_PAGE 64
|
||||||
|
#if 0
|
||||||
|
#define USE_LWP_LOCK
|
||||||
|
#define USE_RTC_TIME
|
||||||
|
#endif
|
||||||
|
#elif defined (__wii__)
|
||||||
|
#define DEFAULT_CACHE_PAGES 4
|
||||||
|
#define DEFAULT_SECTORS_PAGE 64
|
||||||
|
#define USE_LWP_LOCK
|
||||||
|
#define USE_RTC_TIME
|
||||||
|
#elif defined (__gamecube__)
|
||||||
|
#define DEFAULT_CACHE_PAGES 4
|
||||||
|
#define DEFAULT_SECTORS_PAGE 64
|
||||||
|
#define USE_LWP_LOCK
|
||||||
|
#define USE_RTC_TIME
|
||||||
|
#elif defined (NDS)
|
||||||
|
#define DEFAULT_CACHE_PAGES 16
|
||||||
|
#define DEFAULT_SECTORS_PAGE 8
|
||||||
|
#define USE_RTC_TIME
|
||||||
|
#elif defined (GBA)
|
||||||
|
#define DEFAULT_CACHE_PAGES 2
|
||||||
|
#define DEFAULT_SECTORS_PAGE 8
|
||||||
|
#define LIMIT_SECTORS 128
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _COMMON_H */
|
1180
deps/libfat/directory.c
vendored
Normal file
1180
deps/libfat/directory.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
181
deps/libfat/directory.h
vendored
Normal file
181
deps/libfat/directory.h
vendored
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
directory.h
|
||||||
|
Reading, writing and manipulation of the directory structure on
|
||||||
|
a FAT partition
|
||||||
|
|
||||||
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _DIRECTORY_H
|
||||||
|
#define _DIRECTORY_H
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/syslimits.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "partition.h"
|
||||||
|
|
||||||
|
#define DIR_ENTRY_DATA_SIZE 0x20
|
||||||
|
#define MAX_LFN_LENGTH 256
|
||||||
|
#define MAX_ALIAS_LENGTH 13
|
||||||
|
#define LFN_ENTRY_LENGTH 13
|
||||||
|
#define ALIAS_ENTRY_LENGTH 11
|
||||||
|
#define MAX_ALIAS_EXT_LENGTH 3
|
||||||
|
#define MAX_ALIAS_PRI_LENGTH 8
|
||||||
|
#define MAX_NUMERIC_TAIL 999999
|
||||||
|
#define FAT16_ROOT_DIR_CLUSTER 0
|
||||||
|
|
||||||
|
#define DIR_SEPARATOR '/'
|
||||||
|
|
||||||
|
/* File attributes */
|
||||||
|
#define ATTRIB_ARCH 0x20 /* Archive */
|
||||||
|
#define ATTRIB_DIR 0x10 /* Directory */
|
||||||
|
#define ATTRIB_LFN 0x0F /* Long file name */
|
||||||
|
#define ATTRIB_VOL 0x08 /* Volume */
|
||||||
|
#define ATTRIB_SYS 0x04 /* System */
|
||||||
|
#define ATTRIB_HID 0x02 /* Hidden */
|
||||||
|
#define ATTRIB_RO 0x01 /* Read only */
|
||||||
|
|
||||||
|
#define CASE_LOWER_EXT 0x10 /* WinNT lowercase extension */
|
||||||
|
#define CASE_LOWER_BASE 0x08 /* WinNT lowercase basename */
|
||||||
|
|
||||||
|
typedef enum {FT_DIRECTORY, FT_FILE} FILE_TYPE;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t cluster;
|
||||||
|
sec_t sector;
|
||||||
|
int32_t offset;
|
||||||
|
} DIR_ENTRY_POSITION;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t entryData[DIR_ENTRY_DATA_SIZE];
|
||||||
|
DIR_ENTRY_POSITION dataStart; /* Points to the start of the LFN entries of a file, or the alias for no LFN */
|
||||||
|
DIR_ENTRY_POSITION dataEnd; /* Always points to the file/directory's alias entry */
|
||||||
|
char filename[NAME_MAX];
|
||||||
|
} DIR_ENTRY;
|
||||||
|
|
||||||
|
/* Directory entry offsets */
|
||||||
|
enum DIR_ENTRY_offset {
|
||||||
|
DIR_ENTRY_name = 0x00,
|
||||||
|
DIR_ENTRY_extension = 0x08,
|
||||||
|
DIR_ENTRY_attributes = 0x0B,
|
||||||
|
DIR_ENTRY_caseInfo = 0x0C,
|
||||||
|
DIR_ENTRY_cTime_ms = 0x0D,
|
||||||
|
DIR_ENTRY_cTime = 0x0E,
|
||||||
|
DIR_ENTRY_cDate = 0x10,
|
||||||
|
DIR_ENTRY_aDate = 0x12,
|
||||||
|
DIR_ENTRY_clusterHigh = 0x14,
|
||||||
|
DIR_ENTRY_mTime = 0x16,
|
||||||
|
DIR_ENTRY_mDate = 0x18,
|
||||||
|
DIR_ENTRY_cluster = 0x1A,
|
||||||
|
DIR_ENTRY_fileSize = 0x1C
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns true if the file specified by entry is a directory
|
||||||
|
*/
|
||||||
|
static inline bool _FAT_directory_isDirectory (DIR_ENTRY* entry) {
|
||||||
|
return ((entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool _FAT_directory_isWritable (DIR_ENTRY* entry) {
|
||||||
|
return ((entry->entryData[DIR_ENTRY_attributes] & ATTRIB_RO) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool _FAT_directory_isDot (DIR_ENTRY* entry) {
|
||||||
|
return ((entry->filename[0] == '.') && ((entry->filename[1] == '\0') ||
|
||||||
|
((entry->filename[1] == '.') && entry->filename[2] == '\0')));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reads the first directory entry from the directory starting at dirCluster
|
||||||
|
Places result in entry
|
||||||
|
entry will be destroyed even if no directory entry is found
|
||||||
|
Returns true on success, false on failure
|
||||||
|
*/
|
||||||
|
bool _FAT_directory_getFirstEntry (PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reads the next directory entry after the one already pointed to by entry
|
||||||
|
Places result in entry
|
||||||
|
entry will be destroyed even if no directory entry is found
|
||||||
|
Returns true on success, false on failure
|
||||||
|
*/
|
||||||
|
bool _FAT_directory_getNextEntry (PARTITION* partition, DIR_ENTRY* entry);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Gets the directory entry corrsponding to the supplied path
|
||||||
|
entry will be destroyed even if no directory entry is found
|
||||||
|
pathEnd specifies the end of the path string, for cutting strings short if needed
|
||||||
|
specify NULL to use the full length of path
|
||||||
|
pathEnd is only a suggestion, and the path string will be searched up until the next PATH_SEPARATOR
|
||||||
|
after pathEND.
|
||||||
|
Returns true on success, false on failure
|
||||||
|
*/
|
||||||
|
bool _FAT_directory_entryFromPath (PARTITION* partition, DIR_ENTRY* entry, const char* path, const char* pathEnd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Changes the current directory to the one specified by path
|
||||||
|
Returns true on success, false on failure
|
||||||
|
*/
|
||||||
|
bool _FAT_directory_chdir (PARTITION* partition, const char* path);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Removes the directory entry specified by entry
|
||||||
|
Assumes that entry is valid
|
||||||
|
Returns true on success, false on failure
|
||||||
|
*/
|
||||||
|
bool _FAT_directory_removeEntry (PARTITION* partition, DIR_ENTRY* entry);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add a directory entry to the directory specified by dirCluster
|
||||||
|
The fileData, dataStart and dataEnd elements of the DIR_ENTRY struct are
|
||||||
|
updated with the new directory entry position and alias.
|
||||||
|
Returns true on success, false on failure
|
||||||
|
*/
|
||||||
|
bool _FAT_directory_addEntry (PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get the start cluster of a file from it's entry data
|
||||||
|
*/
|
||||||
|
uint32_t _FAT_directory_entryGetCluster (PARTITION* partition, const uint8_t* entryData);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Fill in the file name and entry data of DIR_ENTRY* entry.
|
||||||
|
Assumes that the entry's dataStart and dataEnd are correct
|
||||||
|
Returns true on success, false on failure
|
||||||
|
*/
|
||||||
|
bool _FAT_directory_entryFromPosition (PARTITION* partition, DIR_ENTRY* entry);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Fill in a stat struct based on a file entry
|
||||||
|
*/
|
||||||
|
void _FAT_directory_entryStat (PARTITION* partition, DIR_ENTRY* entry, struct stat *st);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get volume label
|
||||||
|
*/
|
||||||
|
bool _FAT_directory_getVolumeLabel (PARTITION* partition, char *label);
|
||||||
|
|
||||||
|
#endif /* _DIRECTORY_H */
|
139
deps/libfat/disc.c
vendored
Normal file
139
deps/libfat/disc.c
vendored
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
disc.c
|
||||||
|
Interface to the low level disc functions. Used by the higher level
|
||||||
|
file system code.
|
||||||
|
|
||||||
|
Copyright (c) 2008 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "disc.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
The list of interfaces consists of a series of name/interface pairs.
|
||||||
|
The interface is returned via a simple function. This allows for
|
||||||
|
platforms where the interface has to be "assembled" before it can
|
||||||
|
be used, like DLDI on the NDS. For cases where a simple struct
|
||||||
|
is available, wrapper functions are used.
|
||||||
|
The list is terminated by a NULL/NULL entry.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ====================== Wii U ====================== */
|
||||||
|
#if defined (__wiiu__)
|
||||||
|
#include <iosuhax_disc_interface.h>
|
||||||
|
|
||||||
|
static const DISC_INTERFACE* get_io_wiiu_sd (void)
|
||||||
|
{
|
||||||
|
return &IOSUHAX_sdio_disc_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const DISC_INTERFACE* get_io_wiiu_usb (void)
|
||||||
|
{
|
||||||
|
return &IOSUHAX_usb_disc_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
const INTERFACE_ID _FAT_disc_interfaces[] = {
|
||||||
|
{"sd", get_io_wiiu_sd},
|
||||||
|
{"usb", get_io_wiiu_usb},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ====================== Wii ====================== */
|
||||||
|
#elif defined (__wii__)
|
||||||
|
#include <sdcard/wiisd_io.h>
|
||||||
|
#include <ogc/usbstorage.h>
|
||||||
|
#include <sdcard/gcsd.h>
|
||||||
|
|
||||||
|
static const DISC_INTERFACE* get_io_wiisd (void)
|
||||||
|
{
|
||||||
|
return &__io_wiisd;
|
||||||
|
}
|
||||||
|
static const DISC_INTERFACE* get_io_usbstorage (void)
|
||||||
|
{
|
||||||
|
return &__io_usbstorage;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const DISC_INTERFACE* get_io_gcsda (void)
|
||||||
|
{
|
||||||
|
return &__io_gcsda;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const DISC_INTERFACE* get_io_gcsdb (void)
|
||||||
|
{
|
||||||
|
return &__io_gcsdb;
|
||||||
|
}
|
||||||
|
|
||||||
|
const INTERFACE_ID _FAT_disc_interfaces[] = {
|
||||||
|
{"sd", get_io_wiisd},
|
||||||
|
{"usb", get_io_usbstorage},
|
||||||
|
{"carda", get_io_gcsda},
|
||||||
|
{"cardb", get_io_gcsdb},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ==================== Gamecube ==================== */
|
||||||
|
#elif defined (__gamecube__)
|
||||||
|
#include <sdcard/gcsd.h>
|
||||||
|
|
||||||
|
static const DISC_INTERFACE* get_io_gcsda (void)
|
||||||
|
{
|
||||||
|
return &__io_gcsda;
|
||||||
|
}
|
||||||
|
static const DISC_INTERFACE* get_io_gcsdb (void)
|
||||||
|
{
|
||||||
|
return &__io_gcsdb;
|
||||||
|
}
|
||||||
|
|
||||||
|
const INTERFACE_ID _FAT_disc_interfaces[] = {
|
||||||
|
{"carda", get_io_gcsda},
|
||||||
|
{"cardb", get_io_gcsdb},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ====================== NDS ====================== */
|
||||||
|
#elif defined (NDS)
|
||||||
|
#include <nds/system.h>
|
||||||
|
#include <nds/arm9/dldi.h>
|
||||||
|
|
||||||
|
static const DISC_INTERFACE* get_io_dsisd (void)
|
||||||
|
{
|
||||||
|
return isDSiMode() ? &__io_dsisd : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const INTERFACE_ID _FAT_disc_interfaces[] = {
|
||||||
|
{"sd", get_io_dsisd},
|
||||||
|
{"fat", dldiGetInternal},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ====================== GBA ====================== */
|
||||||
|
#elif defined (GBA)
|
||||||
|
#include <disc.h>
|
||||||
|
|
||||||
|
const INTERFACE_ID _FAT_disc_interfaces[] = {
|
||||||
|
{"fat", discGetInterface},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
119
deps/libfat/disc.h
vendored
Normal file
119
deps/libfat/disc.h
vendored
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
disc.h
|
||||||
|
Interface to the low level disc functions. Used by the higher level
|
||||||
|
file system code.
|
||||||
|
|
||||||
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef _DISC_H
|
||||||
|
#define _DISC_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
A list of all default devices to try at startup,
|
||||||
|
terminated by a {NULL,NULL} entry.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const char* name;
|
||||||
|
const DISC_INTERFACE* (*getInterface)(void);
|
||||||
|
} INTERFACE_ID;
|
||||||
|
extern const INTERFACE_ID _FAT_disc_interfaces[];
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check if a disc is inserted
|
||||||
|
Return true if a disc is inserted and ready, false otherwise
|
||||||
|
*/
|
||||||
|
static inline bool _FAT_disc_isInserted (const DISC_INTERFACE* disc)
|
||||||
|
{
|
||||||
|
return disc->isInserted();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Read numSectors sectors from a disc, starting at sector.
|
||||||
|
numSectors is between 1 and LIMIT_SECTORS if LIMIT_SECTORS is defined,
|
||||||
|
else it is at least 1
|
||||||
|
sector is 0 or greater
|
||||||
|
buffer is a pointer to the memory to fill
|
||||||
|
*/
|
||||||
|
static inline bool _FAT_disc_readSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer)
|
||||||
|
{
|
||||||
|
return disc->readSectors (sector, numSectors, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Write numSectors sectors to a disc, starting at sector.
|
||||||
|
numSectors is between 1 and LIMIT_SECTORS if LIMIT_SECTORS is defined,
|
||||||
|
else it is at least 1
|
||||||
|
sector is 0 or greater
|
||||||
|
buffer is a pointer to the memory to read from
|
||||||
|
*/
|
||||||
|
static inline bool _FAT_disc_writeSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer)
|
||||||
|
{
|
||||||
|
return disc->writeSectors (sector, numSectors, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reset the card back to a ready state
|
||||||
|
*/
|
||||||
|
static inline bool _FAT_disc_clearStatus (const DISC_INTERFACE* disc)
|
||||||
|
{
|
||||||
|
return disc->clearStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Initialise the disc to a state ready for data reading or writing
|
||||||
|
*/
|
||||||
|
static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc)
|
||||||
|
{
|
||||||
|
return disc->startup();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Put the disc in a state ready for power down.
|
||||||
|
Complete any pending writes and disable the disc if necessary
|
||||||
|
*/
|
||||||
|
static inline bool _FAT_disc_shutdown (const DISC_INTERFACE* disc)
|
||||||
|
{
|
||||||
|
return disc->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Return a 32 bit value unique to each type of interface
|
||||||
|
*/
|
||||||
|
static inline uint32_t _FAT_disc_hostType (const DISC_INTERFACE* disc)
|
||||||
|
{
|
||||||
|
return disc->ioType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Return a 32 bit value that specifies the capabilities of the disc
|
||||||
|
*/
|
||||||
|
static inline uint32_t _FAT_disc_features (const DISC_INTERFACE* disc)
|
||||||
|
{
|
||||||
|
return disc->features;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _DISC_H */
|
666
deps/libfat/fatdir.c
vendored
Normal file
666
deps/libfat/fatdir.c
vendored
Normal file
@ -0,0 +1,666 @@
|
|||||||
|
/*
|
||||||
|
fatdir.c
|
||||||
|
|
||||||
|
Functions used by the newlib disc stubs to interface with
|
||||||
|
this library
|
||||||
|
|
||||||
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/iosupport.h>
|
||||||
|
|
||||||
|
#include "fatdir.h"
|
||||||
|
|
||||||
|
#include "cache.h"
|
||||||
|
#include "file_allocation_table.h"
|
||||||
|
#include "partition.h"
|
||||||
|
#include "directory.h"
|
||||||
|
#include "bit_ops.h"
|
||||||
|
#include "filetime.h"
|
||||||
|
#include "lock.h"
|
||||||
|
|
||||||
|
|
||||||
|
int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st)
|
||||||
|
{
|
||||||
|
PARTITION* partition = NULL;
|
||||||
|
DIR_ENTRY dirEntry;
|
||||||
|
|
||||||
|
/* Get the partition this file is on */
|
||||||
|
partition = _FAT_partition_getPartitionFromPath (path);
|
||||||
|
if (partition == NULL)
|
||||||
|
{
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move the path pointer to the start of the actual path */
|
||||||
|
if (strchr (path, ':') != NULL)
|
||||||
|
path = strchr (path, ':') + 1;
|
||||||
|
if (strchr (path, ':') != NULL)
|
||||||
|
{
|
||||||
|
r->_errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FAT_lock(&partition->lock);
|
||||||
|
|
||||||
|
/* Search for the file on the disc */
|
||||||
|
if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, NULL))
|
||||||
|
{
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = ENOENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill in the stat struct */
|
||||||
|
_FAT_directory_entryStat (partition, &dirEntry, st);
|
||||||
|
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _FAT_link_r (struct _reent *r, const char *existing, const char *newLink)
|
||||||
|
{
|
||||||
|
r->_errno = ENOTSUP;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _FAT_unlink_r (struct _reent *r, const char *path)
|
||||||
|
{
|
||||||
|
PARTITION* partition = NULL;
|
||||||
|
DIR_ENTRY dirEntry;
|
||||||
|
DIR_ENTRY dirContents;
|
||||||
|
uint32_t cluster;
|
||||||
|
bool nextEntry;
|
||||||
|
bool errorOccured = false;
|
||||||
|
|
||||||
|
/* Get the partition this directory is on */
|
||||||
|
partition = _FAT_partition_getPartitionFromPath (path);
|
||||||
|
if (partition == NULL)
|
||||||
|
{
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure we aren't trying to write to a read-only disc */
|
||||||
|
if (partition->readOnly)
|
||||||
|
{
|
||||||
|
r->_errno = EROFS;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move the path pointer to the start of the actual path */
|
||||||
|
if (strchr (path, ':') != NULL)
|
||||||
|
path = strchr (path, ':') + 1;
|
||||||
|
if (strchr (path, ':') != NULL)
|
||||||
|
{
|
||||||
|
r->_errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FAT_lock(&partition->lock);
|
||||||
|
|
||||||
|
/* Search for the file on the disc */
|
||||||
|
if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, NULL))
|
||||||
|
{
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = ENOENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster = _FAT_directory_entryGetCluster (partition, dirEntry.entryData);
|
||||||
|
|
||||||
|
/* If this is a directory, make sure it is empty */
|
||||||
|
if (_FAT_directory_isDirectory (&dirEntry))
|
||||||
|
{
|
||||||
|
nextEntry = _FAT_directory_getFirstEntry (partition, &dirContents, cluster);
|
||||||
|
|
||||||
|
while (nextEntry)
|
||||||
|
{
|
||||||
|
if (!_FAT_directory_isDot (&dirContents))
|
||||||
|
{
|
||||||
|
/* The directory had something in it that isn't a reference to itself or it's parent */
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = ENOTEMPTY;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
nextEntry = _FAT_directory_getNextEntry (partition, &dirContents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_FAT_fat_isValidCluster(partition, cluster))
|
||||||
|
{
|
||||||
|
/* Remove the cluster chain for this file */
|
||||||
|
if (!_FAT_fat_clearLinks (partition, cluster))
|
||||||
|
{
|
||||||
|
r->_errno = EIO;
|
||||||
|
errorOccured = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the directory entry for this file */
|
||||||
|
if (!_FAT_directory_removeEntry (partition, &dirEntry))
|
||||||
|
{
|
||||||
|
r->_errno = EIO;
|
||||||
|
errorOccured = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush any sectors in the disc cache */
|
||||||
|
if (!_FAT_cache_flush(partition->cache))
|
||||||
|
{
|
||||||
|
r->_errno = EIO;
|
||||||
|
errorOccured = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
if (errorOccured)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _FAT_chdir_r (struct _reent *r, const char *path)
|
||||||
|
{
|
||||||
|
PARTITION* partition = NULL;
|
||||||
|
|
||||||
|
/* Get the partition this directory is on */
|
||||||
|
partition = _FAT_partition_getPartitionFromPath (path);
|
||||||
|
if (partition == NULL)
|
||||||
|
{
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move the path pointer to the start of the actual path */
|
||||||
|
if (strchr (path, ':') != NULL)
|
||||||
|
path = strchr (path, ':') + 1;
|
||||||
|
if (strchr (path, ':') != NULL)
|
||||||
|
{
|
||||||
|
r->_errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FAT_lock(&partition->lock);
|
||||||
|
|
||||||
|
/* Try changing directory */
|
||||||
|
if (_FAT_directory_chdir (partition, path))
|
||||||
|
{
|
||||||
|
/* Successful */
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Failed */
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = ENOTDIR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
||||||
|
{
|
||||||
|
DIR_ENTRY oldDirEntry;
|
||||||
|
DIR_ENTRY newDirEntry;
|
||||||
|
const char *pathEnd;
|
||||||
|
uint32_t dirCluster;
|
||||||
|
|
||||||
|
/* Get the partition this directory is on */
|
||||||
|
PARTITION *partition = _FAT_partition_getPartitionFromPath (oldName);
|
||||||
|
if (partition == NULL)
|
||||||
|
{
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FAT_lock(&partition->lock);
|
||||||
|
|
||||||
|
/* Make sure the same partition is used for the old and new names */
|
||||||
|
if (partition != _FAT_partition_getPartitionFromPath (newName))
|
||||||
|
{
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = EXDEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure we aren't trying to write to a read-only disc */
|
||||||
|
if (partition->readOnly)
|
||||||
|
{
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = EROFS;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move the path pointer to the start of the actual path */
|
||||||
|
if (strchr (oldName, ':') != NULL)
|
||||||
|
oldName = strchr (oldName, ':') + 1;
|
||||||
|
if (strchr (oldName, ':') != NULL)
|
||||||
|
{
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (strchr (newName, ':') != NULL)
|
||||||
|
newName = strchr (newName, ':') + 1;
|
||||||
|
if (strchr (newName, ':') != NULL)
|
||||||
|
{
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search for the file on the disc */
|
||||||
|
if (!_FAT_directory_entryFromPath (partition, &oldDirEntry, oldName, NULL))
|
||||||
|
{
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = ENOENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure there is no existing file / directory with the new name */
|
||||||
|
if (_FAT_directory_entryFromPath (partition, &newDirEntry, newName, NULL))
|
||||||
|
{
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = EEXIST;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the new file entry
|
||||||
|
* Get the directory it has to go in */
|
||||||
|
pathEnd = strrchr (newName, DIR_SEPARATOR);
|
||||||
|
if (pathEnd == NULL)
|
||||||
|
{
|
||||||
|
/* No path was specified */
|
||||||
|
dirCluster = partition->cwdCluster;
|
||||||
|
pathEnd = newName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Path was specified -- get the right dirCluster
|
||||||
|
* Recycling newDirEntry, since it needs to be recreated anyway */
|
||||||
|
if (!_FAT_directory_entryFromPath (partition, &newDirEntry, newName, pathEnd) ||
|
||||||
|
!_FAT_directory_isDirectory(&newDirEntry))
|
||||||
|
{
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = ENOTDIR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
dirCluster = _FAT_directory_entryGetCluster (partition, newDirEntry.entryData);
|
||||||
|
/* Move the pathEnd past the last DIR_SEPARATOR */
|
||||||
|
pathEnd += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the entry data */
|
||||||
|
memcpy (&newDirEntry, &oldDirEntry, sizeof(DIR_ENTRY));
|
||||||
|
|
||||||
|
/* Set the new name */
|
||||||
|
strncpy (newDirEntry.filename, pathEnd, NAME_MAX - 1);
|
||||||
|
|
||||||
|
/* Write the new entry */
|
||||||
|
if (!_FAT_directory_addEntry (partition, &newDirEntry, dirCluster))
|
||||||
|
{
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = ENOSPC;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the old entry */
|
||||||
|
if (!_FAT_directory_removeEntry (partition, &oldDirEntry))
|
||||||
|
{
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = EIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush any sectors in the disc cache */
|
||||||
|
if (!_FAT_cache_flush (partition->cache))
|
||||||
|
{
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = EIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _FAT_mkdir_r (struct _reent *r, const char *path, int mode)
|
||||||
|
{
|
||||||
|
PARTITION* partition = NULL;
|
||||||
|
bool fileExists;
|
||||||
|
DIR_ENTRY dirEntry;
|
||||||
|
const char* pathEnd;
|
||||||
|
uint32_t parentCluster, dirCluster;
|
||||||
|
uint8_t newEntryData[DIR_ENTRY_DATA_SIZE];
|
||||||
|
|
||||||
|
partition = _FAT_partition_getPartitionFromPath (path);
|
||||||
|
if (partition == NULL)
|
||||||
|
{
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move the path pointer to the start of the actual path */
|
||||||
|
if (strchr (path, ':') != NULL)
|
||||||
|
path = strchr (path, ':') + 1;
|
||||||
|
if (strchr (path, ':') != NULL)
|
||||||
|
{
|
||||||
|
r->_errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FAT_lock(&partition->lock);
|
||||||
|
|
||||||
|
/* Search for the file/directory on the disc */
|
||||||
|
fileExists = _FAT_directory_entryFromPath (partition, &dirEntry, path, NULL);
|
||||||
|
|
||||||
|
/* Make sure it doesn't exist */
|
||||||
|
if (fileExists)
|
||||||
|
{
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = EEXIST;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (partition->readOnly)
|
||||||
|
{
|
||||||
|
/* We can't write to a read-only partition */
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = EROFS;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the directory it has to go in */
|
||||||
|
pathEnd = strrchr (path, DIR_SEPARATOR);
|
||||||
|
if (pathEnd == NULL)
|
||||||
|
{
|
||||||
|
/* No path was specified */
|
||||||
|
parentCluster = partition->cwdCluster;
|
||||||
|
pathEnd = path;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Path was specified -- get the right parentCluster
|
||||||
|
* Recycling dirEntry, since it needs to be recreated anyway */
|
||||||
|
if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, pathEnd) ||
|
||||||
|
!_FAT_directory_isDirectory(&dirEntry))
|
||||||
|
{
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = ENOTDIR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
parentCluster = _FAT_directory_entryGetCluster (partition, dirEntry.entryData);
|
||||||
|
/* Move the pathEnd past the last DIR_SEPARATOR */
|
||||||
|
pathEnd += 1;
|
||||||
|
}
|
||||||
|
/* Create the entry data */
|
||||||
|
strncpy (dirEntry.filename, pathEnd, NAME_MAX - 1);
|
||||||
|
memset (dirEntry.entryData, 0, DIR_ENTRY_DATA_SIZE);
|
||||||
|
|
||||||
|
/* Set the creation time and date */
|
||||||
|
dirEntry.entryData[DIR_ENTRY_cTime_ms] = 0;
|
||||||
|
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_cTime, _FAT_filetime_getTimeFromRTC());
|
||||||
|
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_cDate, _FAT_filetime_getDateFromRTC());
|
||||||
|
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_mTime, _FAT_filetime_getTimeFromRTC());
|
||||||
|
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_mDate, _FAT_filetime_getDateFromRTC());
|
||||||
|
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_aDate, _FAT_filetime_getDateFromRTC());
|
||||||
|
|
||||||
|
/* Set the directory attribute */
|
||||||
|
dirEntry.entryData[DIR_ENTRY_attributes] = ATTRIB_DIR;
|
||||||
|
|
||||||
|
/* Get a cluster for the new directory */
|
||||||
|
dirCluster = _FAT_fat_linkFreeClusterCleared (partition, CLUSTER_FREE);
|
||||||
|
if (!_FAT_fat_isValidCluster(partition, dirCluster))
|
||||||
|
{
|
||||||
|
/* No space left on disc for the cluster */
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = ENOSPC;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_cluster, dirCluster);
|
||||||
|
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_clusterHigh, dirCluster >> 16);
|
||||||
|
|
||||||
|
/* Write the new directory's entry to it's parent */
|
||||||
|
if (!_FAT_directory_addEntry (partition, &dirEntry, parentCluster))
|
||||||
|
{
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = ENOSPC;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the dot entry within the directory */
|
||||||
|
memset (newEntryData, 0, DIR_ENTRY_DATA_SIZE);
|
||||||
|
memset (newEntryData, ' ', 11);
|
||||||
|
newEntryData[DIR_ENTRY_name] = '.';
|
||||||
|
newEntryData[DIR_ENTRY_attributes] = ATTRIB_DIR;
|
||||||
|
u16_to_u8array (newEntryData, DIR_ENTRY_cluster, dirCluster);
|
||||||
|
u16_to_u8array (newEntryData, DIR_ENTRY_clusterHigh, dirCluster >> 16);
|
||||||
|
|
||||||
|
/* Write it to the directory, erasing that sector in the process */
|
||||||
|
_FAT_cache_eraseWritePartialSector ( partition->cache, newEntryData,
|
||||||
|
_FAT_fat_clusterToSector (partition, dirCluster), 0, DIR_ENTRY_DATA_SIZE);
|
||||||
|
|
||||||
|
|
||||||
|
/* Create the double dot entry within the directory */
|
||||||
|
|
||||||
|
/* if ParentDir == Rootdir then ".."" always link to Cluster 0 */
|
||||||
|
if(parentCluster == partition->rootDirCluster)
|
||||||
|
parentCluster = FAT16_ROOT_DIR_CLUSTER;
|
||||||
|
|
||||||
|
newEntryData[DIR_ENTRY_name + 1] = '.';
|
||||||
|
u16_to_u8array (newEntryData, DIR_ENTRY_cluster, parentCluster);
|
||||||
|
u16_to_u8array (newEntryData, DIR_ENTRY_clusterHigh, parentCluster >> 16);
|
||||||
|
|
||||||
|
/* Write it to the directory */
|
||||||
|
_FAT_cache_writePartialSector ( partition->cache, newEntryData,
|
||||||
|
_FAT_fat_clusterToSector (partition, dirCluster), DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
|
||||||
|
|
||||||
|
/* Flush any sectors in the disc cache */
|
||||||
|
if (!_FAT_cache_flush(partition->cache))
|
||||||
|
{
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
r->_errno = EIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
|
||||||
|
{
|
||||||
|
PARTITION* partition = NULL;
|
||||||
|
unsigned int freeClusterCount;
|
||||||
|
|
||||||
|
/* Get the partition of the requested path */
|
||||||
|
partition = _FAT_partition_getPartitionFromPath (path);
|
||||||
|
if (partition == NULL)
|
||||||
|
{
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FAT_lock(&partition->lock);
|
||||||
|
|
||||||
|
if(memcmp(&buf->f_flag, "SCAN", 4) == 0)
|
||||||
|
{
|
||||||
|
/* Special command was given to sync the numberFreeCluster */
|
||||||
|
_FAT_partition_createFSinfo(partition);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(partition->filesysType == FS_FAT32)
|
||||||
|
freeClusterCount = partition->fat.numberFreeCluster;
|
||||||
|
else
|
||||||
|
freeClusterCount = _FAT_fat_freeClusterCount (partition);
|
||||||
|
|
||||||
|
/* FAT clusters = POSIX blocks */
|
||||||
|
buf->f_bsize = partition->bytesPerCluster; /* File system block size. */
|
||||||
|
buf->f_frsize = partition->bytesPerCluster; /* Fundamental file system block size. */
|
||||||
|
|
||||||
|
buf->f_blocks = partition->fat.lastCluster - CLUSTER_FIRST + 1; /* Total number of blocks on file system in units of f_frsize. */
|
||||||
|
buf->f_bfree = freeClusterCount; /* Total number of free blocks. */
|
||||||
|
buf->f_bavail = freeClusterCount; /* Number of free blocks available to non-privileged process. */
|
||||||
|
|
||||||
|
/* Treat requests for info on inodes as clusters */
|
||||||
|
buf->f_files = partition->fat.lastCluster - CLUSTER_FIRST + 1; /* Total number of file serial numbers. */
|
||||||
|
buf->f_ffree = freeClusterCount; /* Total number of free file serial numbers. */
|
||||||
|
buf->f_favail = freeClusterCount; /* Number of file serial numbers available to non-privileged process. */
|
||||||
|
|
||||||
|
/* File system ID. 32bit ioType value */
|
||||||
|
buf->f_fsid = _FAT_disc_hostType(partition->disc);
|
||||||
|
|
||||||
|
/* Bit mask of f_flag values. */
|
||||||
|
buf->f_flag = ST_NOSUID /* No support for ST_ISUID and ST_ISGID file mode bits */
|
||||||
|
| (partition->readOnly ? ST_RDONLY /* Read only file system */ : 0 ) ;
|
||||||
|
/* Maximum filename length. */
|
||||||
|
buf->f_namemax = NAME_MAX;
|
||||||
|
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path)
|
||||||
|
{
|
||||||
|
DIR_ENTRY dirEntry;
|
||||||
|
DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
|
||||||
|
bool fileExists;
|
||||||
|
|
||||||
|
state->partition = _FAT_partition_getPartitionFromPath (path);
|
||||||
|
if (state->partition == NULL)
|
||||||
|
{
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move the path pointer to the start of the actual path */
|
||||||
|
if (strchr (path, ':') != NULL)
|
||||||
|
path = strchr (path, ':') + 1;
|
||||||
|
if (strchr (path, ':') != NULL)
|
||||||
|
{
|
||||||
|
r->_errno = EINVAL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FAT_lock(&state->partition->lock);
|
||||||
|
|
||||||
|
/* Get the start cluster of the directory */
|
||||||
|
fileExists = _FAT_directory_entryFromPath (state->partition, &dirEntry, path, NULL);
|
||||||
|
|
||||||
|
if (!fileExists)
|
||||||
|
{
|
||||||
|
_FAT_unlock(&state->partition->lock);
|
||||||
|
r->_errno = ENOENT;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure it is a directory */
|
||||||
|
if (! _FAT_directory_isDirectory (&dirEntry))
|
||||||
|
{
|
||||||
|
_FAT_unlock(&state->partition->lock);
|
||||||
|
r->_errno = ENOTDIR;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the start cluster for use when resetting the directory data */
|
||||||
|
state->startCluster = _FAT_directory_entryGetCluster (state->partition, dirEntry.entryData);
|
||||||
|
|
||||||
|
/* Get the first entry for use with a call to dirnext */
|
||||||
|
state->validEntry =
|
||||||
|
_FAT_directory_getFirstEntry (state->partition, &(state->currentEntry), state->startCluster);
|
||||||
|
|
||||||
|
/* We are now using this entry */
|
||||||
|
state->inUse = true;
|
||||||
|
_FAT_unlock(&state->partition->lock);
|
||||||
|
return (DIR_ITER*) state;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _FAT_dirreset_r (struct _reent *r, DIR_ITER *dirState)
|
||||||
|
{
|
||||||
|
DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
|
||||||
|
|
||||||
|
_FAT_lock(&state->partition->lock);
|
||||||
|
|
||||||
|
/* Make sure we are still using this entry */
|
||||||
|
if (!state->inUse)
|
||||||
|
{
|
||||||
|
_FAT_unlock(&state->partition->lock);
|
||||||
|
r->_errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the first entry for use with a call to dirnext */
|
||||||
|
state->validEntry =
|
||||||
|
_FAT_directory_getFirstEntry (state->partition, &(state->currentEntry), state->startCluster);
|
||||||
|
|
||||||
|
_FAT_unlock(&state->partition->lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat)
|
||||||
|
{
|
||||||
|
DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
|
||||||
|
|
||||||
|
_FAT_lock(&state->partition->lock);
|
||||||
|
|
||||||
|
/* Make sure we are still using this entry */
|
||||||
|
if (!state->inUse)
|
||||||
|
{
|
||||||
|
_FAT_unlock(&state->partition->lock);
|
||||||
|
r->_errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure there is another file to report on */
|
||||||
|
if (! state->validEntry)
|
||||||
|
{
|
||||||
|
_FAT_unlock(&state->partition->lock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the filename */
|
||||||
|
strncpy (filename, state->currentEntry.filename, NAME_MAX);
|
||||||
|
/* Get the stats, if requested */
|
||||||
|
if (filestat != NULL)
|
||||||
|
_FAT_directory_entryStat (state->partition, &(state->currentEntry), filestat);
|
||||||
|
|
||||||
|
/* Look for the next entry for use next time */
|
||||||
|
state->validEntry =
|
||||||
|
_FAT_directory_getNextEntry (state->partition, &(state->currentEntry));
|
||||||
|
|
||||||
|
_FAT_unlock(&state->partition->lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _FAT_dirclose_r (struct _reent *r, DIR_ITER *dirState)
|
||||||
|
{
|
||||||
|
DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
|
||||||
|
|
||||||
|
/* We are no longer using this entry */
|
||||||
|
_FAT_lock(&state->partition->lock);
|
||||||
|
state->inUse = false;
|
||||||
|
_FAT_unlock(&state->partition->lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
73
deps/libfat/fatdir.h
vendored
Normal file
73
deps/libfat/fatdir.h
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
fatdir.h
|
||||||
|
|
||||||
|
Functions used by the newlib disc stubs to interface with
|
||||||
|
this library
|
||||||
|
|
||||||
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _FATDIR_H
|
||||||
|
#define _FATDIR_H
|
||||||
|
|
||||||
|
#include <sys/reent.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
|
#include <sys/iosupport.h>
|
||||||
|
#include "common.h"
|
||||||
|
#include "directory.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PARTITION* partition;
|
||||||
|
DIR_ENTRY currentEntry;
|
||||||
|
uint32_t startCluster;
|
||||||
|
bool inUse;
|
||||||
|
bool validEntry;
|
||||||
|
} DIR_STATE_STRUCT;
|
||||||
|
|
||||||
|
extern int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st);
|
||||||
|
|
||||||
|
extern int _FAT_link_r (struct _reent *r, const char *existing, const char *newLink);
|
||||||
|
|
||||||
|
extern int _FAT_unlink_r (struct _reent *r, const char *name);
|
||||||
|
|
||||||
|
extern int _FAT_chdir_r (struct _reent *r, const char *name);
|
||||||
|
|
||||||
|
extern int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName);
|
||||||
|
|
||||||
|
extern int _FAT_mkdir_r (struct _reent *r, const char *path, int mode);
|
||||||
|
|
||||||
|
extern int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Directory iterator functions
|
||||||
|
*/
|
||||||
|
extern DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path);
|
||||||
|
extern int _FAT_dirreset_r (struct _reent *r, DIR_ITER *dirState);
|
||||||
|
extern int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat);
|
||||||
|
extern int _FAT_dirclose_r (struct _reent *r, DIR_ITER *dirState);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _FATDIR_H
|
1235
deps/libfat/fatfile.c
vendored
Normal file
1235
deps/libfat/fatfile.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
105
deps/libfat/fatfile.h
vendored
Normal file
105
deps/libfat/fatfile.h
vendored
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
fatfile.h
|
||||||
|
|
||||||
|
Functions used by the newlib disc stubs to interface with
|
||||||
|
this library
|
||||||
|
|
||||||
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _FATFILE_H
|
||||||
|
#define _FATFILE_H
|
||||||
|
|
||||||
|
#include <sys/reent.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "partition.h"
|
||||||
|
#include "directory.h"
|
||||||
|
|
||||||
|
#define FILE_MAX_SIZE ((uint32_t)0xFFFFFFFF) /* 4GiB - 1B */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u32 cluster;
|
||||||
|
sec_t sector;
|
||||||
|
s32 byte;
|
||||||
|
} FILE_POSITION;
|
||||||
|
|
||||||
|
struct _FILE_STRUCT;
|
||||||
|
|
||||||
|
struct _FILE_STRUCT {
|
||||||
|
uint32_t filesize;
|
||||||
|
uint32_t startCluster;
|
||||||
|
uint32_t currentPosition;
|
||||||
|
FILE_POSITION rwPosition;
|
||||||
|
FILE_POSITION appendPosition;
|
||||||
|
DIR_ENTRY_POSITION dirEntryStart; /* Points to the start of the LFN entries of a file, or the alias for no LFN */
|
||||||
|
DIR_ENTRY_POSITION dirEntryEnd; /* Always points to the file's alias entry */
|
||||||
|
PARTITION* partition;
|
||||||
|
struct _FILE_STRUCT* prevOpenFile; /* The previous entry in a double-linked list of open files */
|
||||||
|
struct _FILE_STRUCT* nextOpenFile; /* The next entry in a double-linked list of open files */
|
||||||
|
bool read;
|
||||||
|
bool write;
|
||||||
|
bool append;
|
||||||
|
bool inUse;
|
||||||
|
bool modified;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _FILE_STRUCT FILE_STRUCT;
|
||||||
|
|
||||||
|
int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode);
|
||||||
|
|
||||||
|
int _FAT_close_r (struct _reent *r, void *fd);
|
||||||
|
|
||||||
|
ssize_t _FAT_write_r (struct _reent *r,void *fd, const char *ptr, size_t len);
|
||||||
|
|
||||||
|
ssize_t _FAT_read_r (struct _reent *r, void *fd, char *ptr, size_t len);
|
||||||
|
|
||||||
|
off_t _FAT_seek_r (struct _reent *r, void *fd, off_t pos, int dir);
|
||||||
|
|
||||||
|
int _FAT_fstat_r (struct _reent *r, void *fd, struct stat *st);
|
||||||
|
|
||||||
|
int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st);
|
||||||
|
|
||||||
|
int _FAT_link_r (struct _reent *r, const char *existing, const char *newLink);
|
||||||
|
|
||||||
|
int _FAT_unlink_r (struct _reent *r, const char *name);
|
||||||
|
|
||||||
|
int _FAT_chdir_r (struct _reent *r, const char *name);
|
||||||
|
|
||||||
|
int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName);
|
||||||
|
|
||||||
|
int _FAT_ftruncate_r (struct _reent *r, void *fd, off_t len);
|
||||||
|
|
||||||
|
int _FAT_fsync_r (struct _reent *r, void *fd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Synchronizes the file data to disc.
|
||||||
|
Does no locking of its own -- lock the partition before calling.
|
||||||
|
Returns 0 on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
extern int _FAT_syncToDisc (FILE_STRUCT* file);
|
||||||
|
|
||||||
|
#endif /* _FATFILE_H */
|
395
deps/libfat/file_allocation_table.c
vendored
Normal file
395
deps/libfat/file_allocation_table.c
vendored
Normal file
@ -0,0 +1,395 @@
|
|||||||
|
/*
|
||||||
|
file_allocation_table.c
|
||||||
|
Reading, writing and manipulation of the FAT structure on
|
||||||
|
a FAT partition
|
||||||
|
|
||||||
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "file_allocation_table.h"
|
||||||
|
#include "partition.h"
|
||||||
|
#include "mem_allocate.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Gets the cluster linked from input cluster
|
||||||
|
*/
|
||||||
|
uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
|
||||||
|
{
|
||||||
|
uint32_t nextCluster = CLUSTER_FREE;
|
||||||
|
sec_t sector;
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
if (cluster == CLUSTER_FREE)
|
||||||
|
return CLUSTER_FREE;
|
||||||
|
|
||||||
|
switch (partition->filesysType)
|
||||||
|
{
|
||||||
|
case FS_UNKNOWN:
|
||||||
|
return CLUSTER_ERROR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FS_FAT12:
|
||||||
|
{
|
||||||
|
u32 nextCluster_h;
|
||||||
|
sector = partition->fat.fatStart + (((cluster * 3) / 2) / partition->bytesPerSector);
|
||||||
|
offset = ((cluster * 3) / 2) % partition->bytesPerSector;
|
||||||
|
|
||||||
|
|
||||||
|
_FAT_cache_readLittleEndianValue (partition->cache, &nextCluster, sector, offset, sizeof(u8));
|
||||||
|
|
||||||
|
offset++;
|
||||||
|
|
||||||
|
if (offset >= partition->bytesPerSector)
|
||||||
|
{
|
||||||
|
offset = 0;
|
||||||
|
sector++;
|
||||||
|
}
|
||||||
|
nextCluster_h = 0;
|
||||||
|
|
||||||
|
_FAT_cache_readLittleEndianValue (partition->cache, &nextCluster_h, sector, offset, sizeof(u8));
|
||||||
|
nextCluster |= (nextCluster_h << 8);
|
||||||
|
|
||||||
|
if (cluster & 0x01)
|
||||||
|
nextCluster = nextCluster >> 4;
|
||||||
|
else
|
||||||
|
nextCluster &= 0x0FFF;
|
||||||
|
|
||||||
|
if (nextCluster >= 0x0FF7)
|
||||||
|
nextCluster = CLUSTER_EOF;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FS_FAT16:
|
||||||
|
sector = partition->fat.fatStart + ((cluster << 1) / partition->bytesPerSector);
|
||||||
|
offset = (cluster % (partition->bytesPerSector >> 1)) << 1;
|
||||||
|
|
||||||
|
_FAT_cache_readLittleEndianValue (partition->cache, &nextCluster, sector, offset, sizeof(u16));
|
||||||
|
|
||||||
|
if (nextCluster >= 0xFFF7)
|
||||||
|
nextCluster = CLUSTER_EOF;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FS_FAT32:
|
||||||
|
sector = partition->fat.fatStart + ((cluster << 2) / partition->bytesPerSector);
|
||||||
|
offset = (cluster % (partition->bytesPerSector >> 2)) << 2;
|
||||||
|
|
||||||
|
_FAT_cache_readLittleEndianValue (partition->cache, &nextCluster, sector, offset, sizeof(u32));
|
||||||
|
|
||||||
|
if (nextCluster >= 0x0FFFFFF7)
|
||||||
|
nextCluster = CLUSTER_EOF;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return CLUSTER_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextCluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
writes value into the correct offset within a partition's FAT, based
|
||||||
|
on the cluster number.
|
||||||
|
*/
|
||||||
|
static bool _FAT_fat_writeFatEntry (PARTITION* partition, uint32_t cluster, uint32_t value)
|
||||||
|
{
|
||||||
|
sec_t sector;
|
||||||
|
int offset;
|
||||||
|
uint32_t oldValue;
|
||||||
|
|
||||||
|
if ((cluster < CLUSTER_FIRST) || (cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (partition->filesysType)
|
||||||
|
{
|
||||||
|
case FS_UNKNOWN:
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FS_FAT12:
|
||||||
|
sector = partition->fat.fatStart + (((cluster * 3) / 2) / partition->bytesPerSector);
|
||||||
|
offset = ((cluster * 3) / 2) % partition->bytesPerSector;
|
||||||
|
|
||||||
|
if (cluster & 0x01)
|
||||||
|
{
|
||||||
|
|
||||||
|
_FAT_cache_readLittleEndianValue (partition->cache, &oldValue, sector, offset, sizeof(u8));
|
||||||
|
|
||||||
|
value = (value << 4) | (oldValue & 0x0F);
|
||||||
|
|
||||||
|
_FAT_cache_writeLittleEndianValue (partition->cache, value & 0xFF, sector, offset, sizeof(u8));
|
||||||
|
|
||||||
|
offset++;
|
||||||
|
if (offset >= partition->bytesPerSector)
|
||||||
|
{
|
||||||
|
offset = 0;
|
||||||
|
sector++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FAT_cache_writeLittleEndianValue (partition->cache, (value >> 8) & 0xFF, sector, offset, sizeof(u8));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
_FAT_cache_writeLittleEndianValue (partition->cache, value, sector, offset, sizeof(u8));
|
||||||
|
|
||||||
|
offset++;
|
||||||
|
if (offset >= partition->bytesPerSector)
|
||||||
|
{
|
||||||
|
offset = 0;
|
||||||
|
sector++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FAT_cache_readLittleEndianValue (partition->cache, &oldValue, sector, offset, sizeof(u8));
|
||||||
|
|
||||||
|
value = ((value >> 8) & 0x0F) | (oldValue & 0xF0);
|
||||||
|
|
||||||
|
_FAT_cache_writeLittleEndianValue (partition->cache, value, sector, offset, sizeof(u8));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FS_FAT16:
|
||||||
|
sector = partition->fat.fatStart + ((cluster << 1) / partition->bytesPerSector);
|
||||||
|
offset = (cluster % (partition->bytesPerSector >> 1)) << 1;
|
||||||
|
|
||||||
|
_FAT_cache_writeLittleEndianValue (partition->cache, value, sector, offset, sizeof(u16));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FS_FAT32:
|
||||||
|
sector = partition->fat.fatStart + ((cluster << 2) / partition->bytesPerSector);
|
||||||
|
offset = (cluster % (partition->bytesPerSector >> 2)) << 2;
|
||||||
|
|
||||||
|
_FAT_cache_writeLittleEndianValue (partition->cache, value, sector, offset, sizeof(u32));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------
|
||||||
|
gets the first available free cluster, sets it
|
||||||
|
to end of file, links the input cluster to it then returns the
|
||||||
|
cluster number
|
||||||
|
If an error occurs, return CLUSTER_ERROR
|
||||||
|
-----------------------------------------------------------------*/
|
||||||
|
uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster)
|
||||||
|
{
|
||||||
|
uint32_t firstFree;
|
||||||
|
uint32_t curLink;
|
||||||
|
uint32_t lastCluster;
|
||||||
|
bool loopedAroundFAT = false;
|
||||||
|
|
||||||
|
lastCluster = partition->fat.lastCluster;
|
||||||
|
|
||||||
|
if (cluster > lastCluster)
|
||||||
|
return CLUSTER_ERROR;
|
||||||
|
|
||||||
|
/* Check if the cluster already has a link, and return it if so */
|
||||||
|
curLink = _FAT_fat_nextCluster(partition, cluster);
|
||||||
|
if ((curLink >= CLUSTER_FIRST) && (curLink <= lastCluster))
|
||||||
|
return curLink; /* Return the current link - don't allocate a new one */
|
||||||
|
|
||||||
|
/* Get a free cluster */
|
||||||
|
firstFree = partition->fat.firstFree;
|
||||||
|
/* Start at first valid cluster */
|
||||||
|
if (firstFree < CLUSTER_FIRST)
|
||||||
|
firstFree = CLUSTER_FIRST;
|
||||||
|
|
||||||
|
/* Search until a free cluster is found */
|
||||||
|
while (_FAT_fat_nextCluster(partition, firstFree) != CLUSTER_FREE)
|
||||||
|
{
|
||||||
|
firstFree++;
|
||||||
|
if (firstFree > lastCluster)
|
||||||
|
{
|
||||||
|
if (loopedAroundFAT)
|
||||||
|
{
|
||||||
|
/* If couldn't get a free cluster then return an error */
|
||||||
|
partition->fat.firstFree = firstFree;
|
||||||
|
return CLUSTER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try looping back to the beginning of the FAT
|
||||||
|
* This was suggested by loopy */
|
||||||
|
firstFree = CLUSTER_FIRST;
|
||||||
|
loopedAroundFAT = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
partition->fat.firstFree = firstFree;
|
||||||
|
if(partition->fat.numberFreeCluster)
|
||||||
|
partition->fat.numberFreeCluster--;
|
||||||
|
partition->fat.numberLastAllocCluster = firstFree;
|
||||||
|
|
||||||
|
/* Update the linked from FAT entry */
|
||||||
|
if ((cluster >= CLUSTER_FIRST) && (cluster <= lastCluster))
|
||||||
|
_FAT_fat_writeFatEntry (partition, cluster, firstFree);
|
||||||
|
/* Create the linked to FAT entry */
|
||||||
|
_FAT_fat_writeFatEntry (partition, firstFree, CLUSTER_EOF);
|
||||||
|
|
||||||
|
return firstFree;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------
|
||||||
|
gets the first available free cluster, sets it
|
||||||
|
to end of file, links the input cluster to it, clears the new
|
||||||
|
cluster to 0 valued bytes, then returns the cluster number
|
||||||
|
If an error occurs, return CLUSTER_ERROR
|
||||||
|
-----------------------------------------------------------------*/
|
||||||
|
uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
uint8_t *emptySector;
|
||||||
|
|
||||||
|
/* Link the cluster */
|
||||||
|
uint32_t newCluster = _FAT_fat_linkFreeCluster(partition, cluster);
|
||||||
|
|
||||||
|
if (newCluster == CLUSTER_FREE || newCluster == CLUSTER_ERROR)
|
||||||
|
return CLUSTER_ERROR;
|
||||||
|
|
||||||
|
emptySector = (uint8_t*) _FAT_mem_allocate(partition->bytesPerSector);
|
||||||
|
|
||||||
|
/* Clear all the sectors within the cluster */
|
||||||
|
memset (emptySector, 0, partition->bytesPerSector);
|
||||||
|
for (i = 0; i < partition->sectorsPerCluster; i++)
|
||||||
|
{
|
||||||
|
_FAT_cache_writeSectors (partition->cache,
|
||||||
|
_FAT_fat_clusterToSector (partition, newCluster) + i,
|
||||||
|
1, emptySector);
|
||||||
|
}
|
||||||
|
|
||||||
|
_FAT_mem_free(emptySector);
|
||||||
|
|
||||||
|
return newCluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------
|
||||||
|
_FAT_fat_clearLinks
|
||||||
|
frees any cluster used by a file
|
||||||
|
-----------------------------------------------------------------*/
|
||||||
|
bool _FAT_fat_clearLinks (PARTITION* partition, uint32_t cluster)
|
||||||
|
{
|
||||||
|
uint32_t nextCluster;
|
||||||
|
|
||||||
|
if ((cluster < CLUSTER_FIRST) || (cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* If this clears up more space in the FAT before the current free pointer, move it backwards */
|
||||||
|
if (cluster < partition->fat.firstFree)
|
||||||
|
partition->fat.firstFree = cluster;
|
||||||
|
|
||||||
|
while ((cluster != CLUSTER_EOF) && (cluster != CLUSTER_FREE) && (cluster != CLUSTER_ERROR))
|
||||||
|
{
|
||||||
|
/* Store next cluster before erasing the link */
|
||||||
|
nextCluster = _FAT_fat_nextCluster (partition, cluster);
|
||||||
|
|
||||||
|
/* Erase the link */
|
||||||
|
_FAT_fat_writeFatEntry (partition, cluster, CLUSTER_FREE);
|
||||||
|
|
||||||
|
if(partition->fat.numberFreeCluster < (partition->numberOfSectors/partition->sectorsPerCluster))
|
||||||
|
partition->fat.numberFreeCluster++;
|
||||||
|
/* Move onto next cluster */
|
||||||
|
cluster = nextCluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------
|
||||||
|
_FAT_fat_trimChain
|
||||||
|
Drop all clusters past the chainLength.
|
||||||
|
If chainLength is 0, all clusters are dropped.
|
||||||
|
If chainLength is 1, the first cluster is kept and the rest are
|
||||||
|
dropped, and so on.
|
||||||
|
Return the last cluster left in the chain.
|
||||||
|
-----------------------------------------------------------------*/
|
||||||
|
uint32_t _FAT_fat_trimChain (PARTITION* partition, uint32_t startCluster, unsigned int chainLength)
|
||||||
|
{
|
||||||
|
uint32_t nextCluster;
|
||||||
|
|
||||||
|
if (chainLength == 0)
|
||||||
|
{
|
||||||
|
/* Drop the entire chain */
|
||||||
|
_FAT_fat_clearLinks (partition, startCluster);
|
||||||
|
return CLUSTER_FREE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the last cluster in the chain, and the one after it */
|
||||||
|
chainLength--;
|
||||||
|
nextCluster = _FAT_fat_nextCluster (partition, startCluster);
|
||||||
|
while ((chainLength > 0) && (nextCluster != CLUSTER_FREE) && (nextCluster != CLUSTER_EOF))
|
||||||
|
{
|
||||||
|
chainLength--;
|
||||||
|
startCluster = nextCluster;
|
||||||
|
nextCluster = _FAT_fat_nextCluster (partition, startCluster);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drop all clusters after the last in the chain */
|
||||||
|
if (nextCluster != CLUSTER_FREE && nextCluster != CLUSTER_EOF)
|
||||||
|
_FAT_fat_clearLinks (partition, nextCluster);
|
||||||
|
|
||||||
|
/* Mark the last cluster in the chain as the end of the file */
|
||||||
|
_FAT_fat_writeFatEntry (partition, startCluster, CLUSTER_EOF);
|
||||||
|
|
||||||
|
return startCluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------
|
||||||
|
_FAT_fat_lastCluster
|
||||||
|
Trace the cluster links until the last one is found
|
||||||
|
-----------------------------------------------------------------*/
|
||||||
|
uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster)
|
||||||
|
{
|
||||||
|
while ((_FAT_fat_nextCluster(partition, cluster) != CLUSTER_FREE) && (_FAT_fat_nextCluster(partition, cluster) != CLUSTER_EOF))
|
||||||
|
cluster = _FAT_fat_nextCluster(partition, cluster);
|
||||||
|
return cluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------
|
||||||
|
_FAT_fat_freeClusterCount
|
||||||
|
Return the number of free clusters available
|
||||||
|
-----------------------------------------------------------------*/
|
||||||
|
unsigned int _FAT_fat_freeClusterCount (PARTITION* partition)
|
||||||
|
{
|
||||||
|
unsigned int count = 0;
|
||||||
|
uint32_t curCluster;
|
||||||
|
|
||||||
|
for (curCluster = CLUSTER_FIRST; curCluster <= partition->fat.lastCluster; curCluster++)
|
||||||
|
{
|
||||||
|
if (_FAT_fat_nextCluster(partition, curCluster) == CLUSTER_FREE)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
70
deps/libfat/file_allocation_table.h
vendored
Normal file
70
deps/libfat/file_allocation_table.h
vendored
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
file_allocation_table.h
|
||||||
|
Reading, writing and manipulation of the FAT structure on
|
||||||
|
a FAT partition
|
||||||
|
|
||||||
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FAT_H
|
||||||
|
#define _FAT_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "partition.h"
|
||||||
|
|
||||||
|
#define CLUSTER_EOF_16 0xFFFF
|
||||||
|
#define CLUSTER_EOF 0x0FFFFFFF
|
||||||
|
#define CLUSTER_FREE 0x00000000
|
||||||
|
#define CLUSTER_ROOT 0x00000000
|
||||||
|
#define CLUSTER_FIRST 0x00000002
|
||||||
|
#define CLUSTER_ERROR 0xFFFFFFFF
|
||||||
|
|
||||||
|
#define CLUSTERS_PER_FAT12 4085
|
||||||
|
#define CLUSTERS_PER_FAT16 65525
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster);
|
||||||
|
|
||||||
|
uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster);
|
||||||
|
uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster);
|
||||||
|
|
||||||
|
bool _FAT_fat_clearLinks (PARTITION* partition, uint32_t cluster);
|
||||||
|
|
||||||
|
uint32_t _FAT_fat_trimChain (PARTITION* partition, uint32_t startCluster, unsigned int chainLength);
|
||||||
|
|
||||||
|
uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster);
|
||||||
|
|
||||||
|
unsigned int _FAT_fat_freeClusterCount (PARTITION* partition);
|
||||||
|
|
||||||
|
static inline sec_t _FAT_fat_clusterToSector (PARTITION* partition, uint32_t cluster) {
|
||||||
|
return (cluster >= CLUSTER_FIRST) ?
|
||||||
|
((cluster - CLUSTER_FIRST) * (sec_t)partition->sectorsPerCluster) + partition->dataStart :
|
||||||
|
partition->rootDirStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool _FAT_fat_isValidCluster (PARTITION* partition, uint32_t cluster) {
|
||||||
|
return (cluster >= CLUSTER_FIRST) && (cluster <= partition->fat.lastCluster /* This will catch CLUSTER_ERROR */);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _FAT_H */
|
111
deps/libfat/filetime.c
vendored
Normal file
111
deps/libfat/filetime.c
vendored
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
filetime.c
|
||||||
|
Conversion of file time and date values to various other types
|
||||||
|
|
||||||
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include "filetime.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#define MAX_HOUR 23
|
||||||
|
#define MAX_MINUTE 59
|
||||||
|
#define MAX_SECOND 59
|
||||||
|
|
||||||
|
#define MAX_MONTH 11
|
||||||
|
#define MIN_MONTH 0
|
||||||
|
#define MAX_DAY 31
|
||||||
|
#define MIN_DAY 1
|
||||||
|
|
||||||
|
uint16_t _FAT_filetime_getTimeFromRTC (void)
|
||||||
|
{
|
||||||
|
#ifdef USE_RTC_TIME
|
||||||
|
struct tm timeParts;
|
||||||
|
time_t epochTime;
|
||||||
|
|
||||||
|
if (time(&epochTime) == (time_t)-1)
|
||||||
|
return 0;
|
||||||
|
localtime_r(&epochTime, &timeParts);
|
||||||
|
|
||||||
|
/* Check that the values are all in range.
|
||||||
|
* If they are not, return 0 (no timestamp) */
|
||||||
|
if ((timeParts.tm_hour < 0) || (timeParts.tm_hour > MAX_HOUR))
|
||||||
|
return 0;
|
||||||
|
if ((timeParts.tm_min < 0) || (timeParts.tm_min > MAX_MINUTE))
|
||||||
|
return 0;
|
||||||
|
if ((timeParts.tm_sec < 0) || (timeParts.tm_sec > MAX_SECOND))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
((timeParts.tm_hour & 0x1F) << 11) |
|
||||||
|
((timeParts.tm_min & 0x3F) << 5) |
|
||||||
|
((timeParts.tm_sec >> 1) & 0x1F)
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t _FAT_filetime_getDateFromRTC (void)
|
||||||
|
{
|
||||||
|
#ifdef USE_RTC_TIME
|
||||||
|
struct tm timeParts;
|
||||||
|
time_t epochTime;
|
||||||
|
|
||||||
|
if (time(&epochTime) == (time_t)-1)
|
||||||
|
return 0;
|
||||||
|
localtime_r(&epochTime, &timeParts);
|
||||||
|
|
||||||
|
if ((timeParts.tm_mon < MIN_MONTH) || (timeParts.tm_mon > MAX_MONTH)) return 0;
|
||||||
|
if ((timeParts.tm_mday < MIN_DAY) || (timeParts.tm_mday > MAX_DAY)) return 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
(((timeParts.tm_year - 80) & 0x7F) <<9) | /* Adjust for MS-FAT base year (1980 vs 1900 for tm_year) */
|
||||||
|
(((timeParts.tm_mon + 1) & 0xF) << 5) |
|
||||||
|
(timeParts.tm_mday & 0x1F)
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t _FAT_filetime_to_time_t (uint16_t t, uint16_t d)
|
||||||
|
{
|
||||||
|
struct tm timeParts;
|
||||||
|
|
||||||
|
timeParts.tm_hour = t >> 11;
|
||||||
|
timeParts.tm_min = (t >> 5) & 0x3F;
|
||||||
|
timeParts.tm_sec = (t & 0x1F) << 1;
|
||||||
|
|
||||||
|
timeParts.tm_mday = d & 0x1F;
|
||||||
|
timeParts.tm_mon = ((d >> 5) & 0x0F) - 1;
|
||||||
|
timeParts.tm_year = (d >> 9) + 80;
|
||||||
|
|
||||||
|
timeParts.tm_isdst = 0;
|
||||||
|
|
||||||
|
return mktime(&timeParts);
|
||||||
|
}
|
41
deps/libfat/filetime.h
vendored
Normal file
41
deps/libfat/filetime.h
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
filetime.h
|
||||||
|
Conversion of file time and date values to various other types
|
||||||
|
|
||||||
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FILETIME_H
|
||||||
|
#define _FILETIME_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
uint16_t _FAT_filetime_getTimeFromRTC (void);
|
||||||
|
uint16_t _FAT_filetime_getDateFromRTC (void);
|
||||||
|
|
||||||
|
time_t _FAT_filetime_to_time_t (uint16_t t, uint16_t d);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _FILETIME_H */
|
124
deps/libfat/include/fat.h
vendored
Normal file
124
deps/libfat/include/fat.h
vendored
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
fat.h
|
||||||
|
Simple functionality for startup, mounting and unmounting of FAT-based devices.
|
||||||
|
|
||||||
|
Copyright (c) 2006 - 2012
|
||||||
|
Michael "Chishm" Chisholm
|
||||||
|
Dave "WinterMute" Murphy
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _LIBFAT_H
|
||||||
|
#define _LIBFAT_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <libfatversion.h>
|
||||||
|
|
||||||
|
/* When compiling for NDS, make sure NDS is defined */
|
||||||
|
#ifndef NDS
|
||||||
|
#if defined ARM9 || defined ARM7
|
||||||
|
#define NDS
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#if defined (__wiiu__)
|
||||||
|
# include <iosuhax_disc_interface.h>
|
||||||
|
#elif defined(__gamecube__) || defined (__wii__)
|
||||||
|
# include <ogc/disc_io.h>
|
||||||
|
#else
|
||||||
|
# ifdef NDS
|
||||||
|
# include <nds/disc_io.h>
|
||||||
|
# else
|
||||||
|
# include <disc_io.h>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Initialise any inserted block-devices.
|
||||||
|
Add the fat device driver to the devoptab, making it available for standard file functions.
|
||||||
|
cacheSize: The number of pages to allocate for each inserted block-device
|
||||||
|
setAsDefaultDevice: if true, make this the default device driver for file operations
|
||||||
|
*/
|
||||||
|
extern bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Calls fatInit with setAsDefaultDevice = true and cacheSize optimised for the host system.
|
||||||
|
*/
|
||||||
|
extern bool fatInitDefault (void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
|
||||||
|
You can then access the filesystem using "name:/".
|
||||||
|
This will mount the active partition or the first valid partition on the disc,
|
||||||
|
and will use a cache size optimized for the host system.
|
||||||
|
*/
|
||||||
|
extern bool fatMountSimple (const char* name, const DISC_INTERFACE* interface);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
|
||||||
|
You can then access the filesystem using "name:/".
|
||||||
|
If startSector = 0, it will mount the active partition of the first valid partition on
|
||||||
|
the disc. Otherwise it will try to mount the partition starting at startSector.
|
||||||
|
cacheSize specifies the number of pages to allocate for the cache.
|
||||||
|
This will not startup the disc, so you need to call interface->startup(); first.
|
||||||
|
*/
|
||||||
|
extern bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Unmount the partition specified by name.
|
||||||
|
If there are open files, it will attempt to synchronise them to disc.
|
||||||
|
*/
|
||||||
|
extern void fatUnmount (const char* name);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get Volume Label
|
||||||
|
*/
|
||||||
|
extern void fatGetVolumeLabel (const char* name, char *label);
|
||||||
|
|
||||||
|
/* File attributes */
|
||||||
|
#define ATTR_ARCHIVE 0x20 /* Archive */
|
||||||
|
#define ATTR_DIRECTORY 0x10 /* Directory */
|
||||||
|
#define ATTR_VOLUME 0x08 /* Volume */
|
||||||
|
#define ATTR_SYSTEM 0x04 /* System */
|
||||||
|
#define ATTR_HIDDEN 0x02 /* Hidden */
|
||||||
|
#define ATTR_READONLY 0x01 /* Read only */
|
||||||
|
|
||||||
|
/*
|
||||||
|
Methods to modify DOS File Attributes
|
||||||
|
*/
|
||||||
|
int FAT_getAttr(const char *file);
|
||||||
|
int FAT_setAttr(const char *file, uint8_t attr );
|
||||||
|
|
||||||
|
#define LIBFAT_FEOS_MULTICWD
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _LIBFAT_H */
|
10
deps/libfat/include/libfatversion.h
vendored
Normal file
10
deps/libfat/include/libfatversion.h
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef __LIBFATVERSION_H__
|
||||||
|
#define __LIBFATVERSION_H__
|
||||||
|
|
||||||
|
#define _LIBFAT_MAJOR_ 1
|
||||||
|
#define _LIBFAT_MINOR_ 1
|
||||||
|
#define _LIBFAT_PATCH_ 0
|
||||||
|
|
||||||
|
#define _LIBFAT_STRING "libFAT Release 1.1.0"
|
||||||
|
|
||||||
|
#endif /* __LIBFATVERSION_H__ */
|
264
deps/libfat/libfat.c
vendored
Normal file
264
deps/libfat/libfat.c
vendored
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
libfat.c
|
||||||
|
Simple functionality for startup, mounting and unmounting of FAT-based devices.
|
||||||
|
|
||||||
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/iosupport.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "partition.h"
|
||||||
|
#include "fatfile.h"
|
||||||
|
#include "fatdir.h"
|
||||||
|
#include "lock.h"
|
||||||
|
#include "mem_allocate.h"
|
||||||
|
#include "disc.h"
|
||||||
|
|
||||||
|
static const devoptab_t dotab_fat = {
|
||||||
|
"fat",
|
||||||
|
sizeof (FILE_STRUCT),
|
||||||
|
_FAT_open_r,
|
||||||
|
_FAT_close_r,
|
||||||
|
_FAT_write_r,
|
||||||
|
_FAT_read_r,
|
||||||
|
_FAT_seek_r,
|
||||||
|
_FAT_fstat_r,
|
||||||
|
_FAT_stat_r,
|
||||||
|
_FAT_link_r,
|
||||||
|
_FAT_unlink_r,
|
||||||
|
_FAT_chdir_r,
|
||||||
|
_FAT_rename_r,
|
||||||
|
_FAT_mkdir_r,
|
||||||
|
sizeof (DIR_STATE_STRUCT),
|
||||||
|
_FAT_diropen_r,
|
||||||
|
_FAT_dirreset_r,
|
||||||
|
_FAT_dirnext_r,
|
||||||
|
_FAT_dirclose_r,
|
||||||
|
_FAT_statvfs_r,
|
||||||
|
_FAT_ftruncate_r,
|
||||||
|
_FAT_fsync_r,
|
||||||
|
NULL, /* Device data */
|
||||||
|
NULL, /* chmod_r */
|
||||||
|
NULL /* fchmod_r */
|
||||||
|
};
|
||||||
|
|
||||||
|
bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage)
|
||||||
|
{
|
||||||
|
char devname[10];
|
||||||
|
PARTITION* partition;
|
||||||
|
devoptab_t* devops;
|
||||||
|
char* nameCopy;
|
||||||
|
|
||||||
|
if(!name || strlen(name) > 8 || !interface)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!interface->startup())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!interface->isInserted())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
strcpy(devname, name);
|
||||||
|
strcat(devname, ":");
|
||||||
|
if(FindDevice(devname) >= 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
devops = _FAT_mem_allocate (sizeof(devoptab_t) + strlen(name) + 1);
|
||||||
|
if (!devops)
|
||||||
|
return false;
|
||||||
|
/* Use the space allocated at the end of the devoptab struct for storing the name */
|
||||||
|
nameCopy = (char*)(devops+1);
|
||||||
|
|
||||||
|
/* Initialize the file system */
|
||||||
|
partition = _FAT_partition_constructor (interface, cacheSize, SectorsPerPage, startSector);
|
||||||
|
if (!partition)
|
||||||
|
{
|
||||||
|
_FAT_mem_free (devops);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add an entry for this device to the devoptab table */
|
||||||
|
memcpy (devops, &dotab_fat, sizeof(dotab_fat));
|
||||||
|
strcpy (nameCopy, name);
|
||||||
|
devops->name = nameCopy;
|
||||||
|
devops->deviceData = partition;
|
||||||
|
|
||||||
|
AddDevice (devops);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fatMountSimple (const char* name, const DISC_INTERFACE* interface)
|
||||||
|
{
|
||||||
|
return fatMount (name, interface, 0, DEFAULT_CACHE_PAGES, DEFAULT_SECTORS_PAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fatUnmount (const char* name)
|
||||||
|
{
|
||||||
|
devoptab_t *devops;
|
||||||
|
PARTITION* partition;
|
||||||
|
|
||||||
|
if(!name)
|
||||||
|
return;
|
||||||
|
|
||||||
|
devops = (devoptab_t*)GetDeviceOpTab (name);
|
||||||
|
if (!devops)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Perform a quick check to make sure we're dealing with a libfat controlled device */
|
||||||
|
if (devops->open_r != dotab_fat.open_r)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (RemoveDevice (name) == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
partition = (PARTITION*)devops->deviceData;
|
||||||
|
_FAT_partition_destructor (partition);
|
||||||
|
_FAT_mem_free (devops);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int defaultDevice = -1;
|
||||||
|
const DISC_INTERFACE *disc;
|
||||||
|
|
||||||
|
for (i = 0;
|
||||||
|
_FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL;
|
||||||
|
i++)
|
||||||
|
{
|
||||||
|
disc = _FAT_disc_interfaces[i].getInterface();
|
||||||
|
if (!disc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (fatMount (_FAT_disc_interfaces[i].name, disc, 0, cacheSize, DEFAULT_SECTORS_PAGE))
|
||||||
|
{
|
||||||
|
/* The first device to successfully mount is set as the default */
|
||||||
|
if (defaultDevice < 0)
|
||||||
|
defaultDevice = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* None of our devices mounted */
|
||||||
|
if (defaultDevice < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (setAsDefaultDevice)
|
||||||
|
{
|
||||||
|
char filePath[PATH_MAX];
|
||||||
|
strcpy (filePath, _FAT_disc_interfaces[defaultDevice].name);
|
||||||
|
strcat (filePath, ":/");
|
||||||
|
#ifdef ARGV_MAGIC
|
||||||
|
if ( __system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc >= 1 && strrchr( __system_argv->argv[0], '/' )!=NULL )
|
||||||
|
{
|
||||||
|
/* Check the app's path against each of our mounted devices, to see
|
||||||
|
* if we can support it. If so, change to that path. */
|
||||||
|
for (i = 0;
|
||||||
|
_FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL;
|
||||||
|
i++)
|
||||||
|
{
|
||||||
|
if ( !strncasecmp( __system_argv->argv[0], _FAT_disc_interfaces[i].name,
|
||||||
|
strlen(_FAT_disc_interfaces[i].name)))
|
||||||
|
{
|
||||||
|
char *lastSlash;
|
||||||
|
strcpy(filePath, __system_argv->argv[0]);
|
||||||
|
lastSlash = strrchr( filePath, '/' );
|
||||||
|
|
||||||
|
if ( NULL != lastSlash)
|
||||||
|
{
|
||||||
|
if ( *(lastSlash - 1) == ':')
|
||||||
|
lastSlash++;
|
||||||
|
*lastSlash = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
chdir (filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fatInitDefault (void)
|
||||||
|
{
|
||||||
|
return fatInit (DEFAULT_CACHE_PAGES, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fatGetVolumeLabel (const char* name, char *label)
|
||||||
|
{
|
||||||
|
devoptab_t *devops;
|
||||||
|
PARTITION* partition;
|
||||||
|
char *buf;
|
||||||
|
int namelen,i;
|
||||||
|
|
||||||
|
if(!name || !label)
|
||||||
|
return;
|
||||||
|
|
||||||
|
namelen = strlen(name);
|
||||||
|
buf=(char*)_FAT_mem_allocate(sizeof(char)*namelen+2);
|
||||||
|
strcpy(buf,name);
|
||||||
|
|
||||||
|
if (name[namelen-1] == '/')
|
||||||
|
{
|
||||||
|
buf[namelen-1]='\0';
|
||||||
|
namelen--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name[namelen-1] != ':')
|
||||||
|
{
|
||||||
|
buf[namelen]=':';
|
||||||
|
buf[namelen+1]='\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
devops = (devoptab_t*)GetDeviceOpTab(buf);
|
||||||
|
|
||||||
|
for(i=0;buf[i]!='\0' && buf[i]!=':';i++);
|
||||||
|
if (!devops || strncasecmp(buf,devops->name,i))
|
||||||
|
{
|
||||||
|
_FAT_mem_free(buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FAT_mem_free(buf);
|
||||||
|
|
||||||
|
/* Perform a quick check to make sure we're dealing with a libfat controlled device */
|
||||||
|
if (devops->open_r != dotab_fat.open_r)
|
||||||
|
return;
|
||||||
|
|
||||||
|
partition = (PARTITION*)devops->deviceData;
|
||||||
|
|
||||||
|
if(!_FAT_directory_getVolumeLabel(partition, label))
|
||||||
|
{
|
||||||
|
strncpy(label,partition->label,11);
|
||||||
|
label[11]='\0';
|
||||||
|
}
|
||||||
|
if(!strncmp(label, "NO NAME", 7))
|
||||||
|
label[0]='\0';
|
||||||
|
}
|
29
deps/libfat/lock.c
vendored
Normal file
29
deps/libfat/lock.c
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#ifndef USE_LWP_LOCK
|
||||||
|
|
||||||
|
#ifndef mutex_t
|
||||||
|
typedef int mutex_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void __attribute__ ((weak)) _FAT_lock_init(mutex_t *mutex)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__ ((weak)) _FAT_lock_deinit(mutex_t *mutex)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__ ((weak)) _FAT_lock(mutex_t *mutex)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__ ((weak)) _FAT_unlock(mutex_t *mutex)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* USE_LWP_LOCK */
|
72
deps/libfat/lock.h
vendored
Normal file
72
deps/libfat/lock.h
vendored
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
lock.h
|
||||||
|
|
||||||
|
Copyright (c) 2008 Sven Peter <svpe@gmx.net>
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LOCK_H
|
||||||
|
#define _LOCK_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#ifdef USE_LWP_LOCK
|
||||||
|
|
||||||
|
static inline void _FAT_lock_init(mutex_t *mutex)
|
||||||
|
{
|
||||||
|
LWP_MutexInit(mutex, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void _FAT_lock_deinit(mutex_t *mutex)
|
||||||
|
{
|
||||||
|
LWP_MutexDestroy(*mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void _FAT_lock(mutex_t *mutex)
|
||||||
|
{
|
||||||
|
LWP_MutexLock(*mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void _FAT_unlock(mutex_t *mutex)
|
||||||
|
{
|
||||||
|
LWP_MutexUnlock(*mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* We still need a blank lock type */
|
||||||
|
#ifndef mutex_t
|
||||||
|
typedef int mutex_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void _FAT_lock_init(mutex_t *mutex);
|
||||||
|
void _FAT_lock_deinit(mutex_t *mutex);
|
||||||
|
void _FAT_lock(mutex_t *mutex);
|
||||||
|
void _FAT_unlock(mutex_t *mutex);
|
||||||
|
|
||||||
|
#endif /* USE_LWP_LOCK */
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _LOCK_H */
|
||||||
|
|
55
deps/libfat/mem_allocate.h
vendored
Normal file
55
deps/libfat/mem_allocate.h
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
mem_allocate.h
|
||||||
|
Memory allocation and destruction calls
|
||||||
|
Replace these calls with custom allocators if
|
||||||
|
malloc is unavailable
|
||||||
|
|
||||||
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MEM_ALLOCATE_H
|
||||||
|
#define _MEM_ALLOCATE_H
|
||||||
|
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
static inline void* _FAT_mem_allocate (size_t size)
|
||||||
|
{
|
||||||
|
return malloc (size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void* _FAT_mem_align (size_t size)
|
||||||
|
{
|
||||||
|
#ifdef __wii__
|
||||||
|
return memalign (32, size);
|
||||||
|
#else
|
||||||
|
return malloc (size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void _FAT_mem_free (void* mem)
|
||||||
|
{
|
||||||
|
free (mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _MEM_ALLOCATE_H */
|
464
deps/libfat/partition.c
vendored
Normal file
464
deps/libfat/partition.c
vendored
Normal file
@ -0,0 +1,464 @@
|
|||||||
|
/*
|
||||||
|
partition.c
|
||||||
|
Functions for mounting and dismounting partitions
|
||||||
|
on various block devices.
|
||||||
|
|
||||||
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "partition.h"
|
||||||
|
#include "bit_ops.h"
|
||||||
|
#include "file_allocation_table.h"
|
||||||
|
#include "directory.h"
|
||||||
|
#include "mem_allocate.h"
|
||||||
|
#include "fatfile.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <sys/iosupport.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Data offsets
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* BIOS Parameter Block offsets */
|
||||||
|
enum BPB
|
||||||
|
{
|
||||||
|
BPB_jmpBoot = 0x00,
|
||||||
|
BPB_OEMName = 0x03,
|
||||||
|
/* BIOS Parameter Block */
|
||||||
|
BPB_bytesPerSector = 0x0B,
|
||||||
|
BPB_sectorsPerCluster = 0x0D,
|
||||||
|
BPB_reservedSectors = 0x0E,
|
||||||
|
BPB_numFATs = 0x10,
|
||||||
|
BPB_rootEntries = 0x11,
|
||||||
|
BPB_numSectorsSmall = 0x13,
|
||||||
|
BPB_mediaDesc = 0x15,
|
||||||
|
BPB_sectorsPerFAT = 0x16,
|
||||||
|
BPB_sectorsPerTrk = 0x18,
|
||||||
|
BPB_numHeads = 0x1A,
|
||||||
|
BPB_numHiddenSectors = 0x1C,
|
||||||
|
BPB_numSectors = 0x20,
|
||||||
|
/* Ext BIOS Parameter Block for FAT16 */
|
||||||
|
BPB_FAT16_driveNumber = 0x24,
|
||||||
|
BPB_FAT16_reserved1 = 0x25,
|
||||||
|
BPB_FAT16_extBootSig = 0x26,
|
||||||
|
BPB_FAT16_volumeID = 0x27,
|
||||||
|
BPB_FAT16_volumeLabel = 0x2B,
|
||||||
|
BPB_FAT16_fileSysType = 0x36,
|
||||||
|
/* Bootcode */
|
||||||
|
BPB_FAT16_bootCode = 0x3E,
|
||||||
|
/* FAT32 extended block */
|
||||||
|
BPB_FAT32_sectorsPerFAT32 = 0x24,
|
||||||
|
BPB_FAT32_extFlags = 0x28,
|
||||||
|
BPB_FAT32_fsVer = 0x2A,
|
||||||
|
BPB_FAT32_rootClus = 0x2C,
|
||||||
|
BPB_FAT32_fsInfo = 0x30,
|
||||||
|
BPB_FAT32_bkBootSec = 0x32,
|
||||||
|
/* Ext BIOS Parameter Block for FAT32 */
|
||||||
|
BPB_FAT32_driveNumber = 0x40,
|
||||||
|
BPB_FAT32_reserved1 = 0x41,
|
||||||
|
BPB_FAT32_extBootSig = 0x42,
|
||||||
|
BPB_FAT32_volumeID = 0x43,
|
||||||
|
BPB_FAT32_volumeLabel = 0x47,
|
||||||
|
BPB_FAT32_fileSysType = 0x52,
|
||||||
|
/* Bootcode */
|
||||||
|
BPB_FAT32_bootCode = 0x5A,
|
||||||
|
BPB_bootSig_55 = 0x1FE,
|
||||||
|
BPB_bootSig_AA = 0x1FF
|
||||||
|
};
|
||||||
|
|
||||||
|
/* File system information block offsets */
|
||||||
|
enum FSIB
|
||||||
|
{
|
||||||
|
FSIB_SIG1 = 0x00,
|
||||||
|
FSIB_SIG2 = 0x1e4,
|
||||||
|
FSIB_numberOfFreeCluster = 0x1e8,
|
||||||
|
FSIB_numberLastAllocCluster = 0x1ec,
|
||||||
|
FSIB_bootSig_55 = 0x1FE,
|
||||||
|
FSIB_bootSig_AA = 0x1FF
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char FAT_SIG[3] = {'F', 'A', 'T'};
|
||||||
|
static const char FS_INFO_SIG1[4] = {'R', 'R', 'a', 'A'};
|
||||||
|
static const char FS_INFO_SIG2[4] = {'r', 'r', 'A', 'a'};
|
||||||
|
|
||||||
|
sec_t FindFirstValidPartition_buf(const DISC_INTERFACE* disc, uint8_t *sectorBuffer)
|
||||||
|
{
|
||||||
|
uint8_t part_table[16*4];
|
||||||
|
uint8_t *ptr;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Read first sector of disc */
|
||||||
|
if (!_FAT_disc_readSectors (disc, 0, 1, sectorBuffer))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memcpy(part_table,sectorBuffer+0x1BE,16*4);
|
||||||
|
ptr = part_table;
|
||||||
|
|
||||||
|
for(i=0;i<4;i++,ptr+=16)
|
||||||
|
{
|
||||||
|
sec_t part_lba = u8array_to_u32(ptr, 0x8);
|
||||||
|
|
||||||
|
if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) ||
|
||||||
|
!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||||
|
return part_lba;
|
||||||
|
|
||||||
|
if(ptr[4]==0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(ptr[4]==0x0F)
|
||||||
|
{
|
||||||
|
sec_t part_lba2=part_lba;
|
||||||
|
sec_t next_lba2=0;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for(n=0;n<8;n++) /* max 8 logic partitions */
|
||||||
|
{
|
||||||
|
if(!_FAT_disc_readSectors (disc, part_lba+next_lba2, 1, sectorBuffer))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
part_lba2 = part_lba + next_lba2 + u8array_to_u32(sectorBuffer, 0x1C6) ;
|
||||||
|
next_lba2 = u8array_to_u32(sectorBuffer, 0x1D6);
|
||||||
|
|
||||||
|
if(!_FAT_disc_readSectors (disc, part_lba2, 1, sectorBuffer))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) ||
|
||||||
|
!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||||
|
return part_lba2;
|
||||||
|
|
||||||
|
if(next_lba2==0) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!_FAT_disc_readSectors (disc, part_lba, 1, sectorBuffer))
|
||||||
|
return 0;
|
||||||
|
if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) ||
|
||||||
|
!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||||
|
return part_lba;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sec_t FindFirstValidPartition(const DISC_INTERFACE* disc)
|
||||||
|
{
|
||||||
|
uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_align(MAX_SECTOR_SIZE);
|
||||||
|
if (!sectorBuffer)
|
||||||
|
return 0;
|
||||||
|
sec_t ret = FindFirstValidPartition_buf(disc, sectorBuffer);
|
||||||
|
_FAT_mem_free(sectorBuffer);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PARTITION* _FAT_partition_constructor_buf (const DISC_INTERFACE* disc,
|
||||||
|
uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector,
|
||||||
|
uint8_t *sectorBuffer)
|
||||||
|
{
|
||||||
|
PARTITION* partition;
|
||||||
|
uint32_t clusterCount;
|
||||||
|
|
||||||
|
/* Read first sector of disc */
|
||||||
|
if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Make sure it is a valid MBR or boot sector */
|
||||||
|
if ( (sectorBuffer[BPB_bootSig_55] != 0x55) || ((sectorBuffer[BPB_bootSig_AA] != 0xAA)
|
||||||
|
#if defined(__gamecube__) || defined (__wii__) || defined (__wiiu__)
|
||||||
|
&& (sectorBuffer[BPB_bootSig_AA] != 0xAB)
|
||||||
|
#endif
|
||||||
|
))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* We're told where to start the partition, so just accept it */
|
||||||
|
if (startSector != 0) { }
|
||||||
|
/* Check if there is a FAT string, which indicates this is a boot sector */
|
||||||
|
else if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||||
|
startSector = 0;
|
||||||
|
/* Check for FAT32 */
|
||||||
|
else if (!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||||
|
startSector = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
startSector = FindFirstValidPartition_buf(disc, sectorBuffer);
|
||||||
|
if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer))
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now verify that this is indeed a FAT partition */
|
||||||
|
if (memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) &&
|
||||||
|
memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
partition = (PARTITION*) _FAT_mem_allocate (sizeof(PARTITION));
|
||||||
|
if (partition == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Init the partition lock */
|
||||||
|
_FAT_lock_init(&partition->lock);
|
||||||
|
|
||||||
|
if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||||
|
strncpy(partition->label, (char*)(sectorBuffer + BPB_FAT16_volumeLabel), 11);
|
||||||
|
else
|
||||||
|
strncpy(partition->label, (char*)(sectorBuffer + BPB_FAT32_volumeLabel), 11);
|
||||||
|
partition->label[11] = '\0';
|
||||||
|
|
||||||
|
/* Set partition's disc interface */
|
||||||
|
partition->disc = disc;
|
||||||
|
|
||||||
|
/* Store required information about the file system */
|
||||||
|
partition->fat.sectorsPerFat = u8array_to_u16(sectorBuffer, BPB_sectorsPerFAT);
|
||||||
|
if (partition->fat.sectorsPerFat == 0)
|
||||||
|
partition->fat.sectorsPerFat = u8array_to_u32( sectorBuffer, BPB_FAT32_sectorsPerFAT32);
|
||||||
|
|
||||||
|
partition->numberOfSectors = u8array_to_u16( sectorBuffer, BPB_numSectorsSmall);
|
||||||
|
if (partition->numberOfSectors == 0)
|
||||||
|
partition->numberOfSectors = u8array_to_u32( sectorBuffer, BPB_numSectors);
|
||||||
|
|
||||||
|
partition->bytesPerSector = u8array_to_u16(sectorBuffer, BPB_bytesPerSector);
|
||||||
|
if(partition->bytesPerSector < MIN_SECTOR_SIZE || partition->bytesPerSector > MAX_SECTOR_SIZE)
|
||||||
|
{
|
||||||
|
/* Unsupported sector size */
|
||||||
|
_FAT_mem_free(partition);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
partition->sectorsPerCluster = sectorBuffer[BPB_sectorsPerCluster];
|
||||||
|
partition->bytesPerCluster = partition->bytesPerSector * partition->sectorsPerCluster;
|
||||||
|
partition->fat.fatStart = startSector + u8array_to_u16(sectorBuffer, BPB_reservedSectors);
|
||||||
|
|
||||||
|
partition->rootDirStart = partition->fat.fatStart + (sectorBuffer[BPB_numFATs] * partition->fat.sectorsPerFat);
|
||||||
|
partition->dataStart = partition->rootDirStart +
|
||||||
|
(( u8array_to_u16(sectorBuffer, BPB_rootEntries) * DIR_ENTRY_DATA_SIZE) / partition->bytesPerSector);
|
||||||
|
|
||||||
|
partition->totalSize = ((uint64_t)partition->numberOfSectors - (partition->dataStart - startSector)) * (uint64_t)partition->bytesPerSector;
|
||||||
|
|
||||||
|
/* FS info sector */
|
||||||
|
partition->fsInfoSector = startSector + (u8array_to_u16(sectorBuffer, BPB_FAT32_fsInfo) ? u8array_to_u16(sectorBuffer, BPB_FAT32_fsInfo) : 1);
|
||||||
|
|
||||||
|
/* Store info about FAT */
|
||||||
|
clusterCount = (partition->numberOfSectors - (uint32_t)(partition->dataStart - startSector)) / partition->sectorsPerCluster;
|
||||||
|
|
||||||
|
partition->fat.lastCluster = clusterCount + CLUSTER_FIRST - 1;
|
||||||
|
partition->fat.firstFree = CLUSTER_FIRST;
|
||||||
|
partition->fat.numberFreeCluster = 0;
|
||||||
|
partition->fat.numberLastAllocCluster = 0;
|
||||||
|
|
||||||
|
if (clusterCount < CLUSTERS_PER_FAT12)
|
||||||
|
partition->filesysType = FS_FAT12; /* FAT12 volume */
|
||||||
|
else if (clusterCount < CLUSTERS_PER_FAT16)
|
||||||
|
partition->filesysType = FS_FAT16; /* FAT16 volume */
|
||||||
|
else
|
||||||
|
partition->filesysType = FS_FAT32; /* FAT32 volume */
|
||||||
|
|
||||||
|
if (partition->filesysType != FS_FAT32)
|
||||||
|
partition->rootDirCluster = FAT16_ROOT_DIR_CLUSTER;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Set up for the FAT32 way */
|
||||||
|
partition->rootDirCluster = u8array_to_u32(sectorBuffer, BPB_FAT32_rootClus);
|
||||||
|
/* Check if FAT mirroring is enabled */
|
||||||
|
if (!(sectorBuffer[BPB_FAT32_extFlags] & 0x80))
|
||||||
|
{
|
||||||
|
/* Use the active FAT */
|
||||||
|
partition->fat.fatStart = partition->fat.fatStart + ( partition->fat.sectorsPerFat * (sectorBuffer[BPB_FAT32_extFlags] & 0x0F));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a cache to use */
|
||||||
|
partition->cache = _FAT_cache_constructor (cacheSize, sectorsPerPage, partition->disc, startSector+partition->numberOfSectors, partition->bytesPerSector);
|
||||||
|
|
||||||
|
/* Set current directory to the root */
|
||||||
|
partition->cwdCluster = partition->rootDirCluster;
|
||||||
|
|
||||||
|
/* Check if this disc is writable, and set the
|
||||||
|
* readOnly property appropriately */
|
||||||
|
partition->readOnly = !(_FAT_disc_features(disc) & FEATURE_MEDIUM_CANWRITE);
|
||||||
|
|
||||||
|
/* There are currently no open files on this partition */
|
||||||
|
partition->openFileCount = 0;
|
||||||
|
partition->firstOpenFile = NULL;
|
||||||
|
|
||||||
|
_FAT_partition_readFSinfo(partition);
|
||||||
|
|
||||||
|
return partition;
|
||||||
|
}
|
||||||
|
|
||||||
|
PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector)
|
||||||
|
{
|
||||||
|
PARTITION *ret = NULL;
|
||||||
|
uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_align(MAX_SECTOR_SIZE);
|
||||||
|
if (!sectorBuffer)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ret = _FAT_partition_constructor_buf(disc, cacheSize,
|
||||||
|
sectorsPerPage, startSector, sectorBuffer);
|
||||||
|
_FAT_mem_free(sectorBuffer);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void _FAT_partition_destructor (PARTITION* partition)
|
||||||
|
{
|
||||||
|
FILE_STRUCT* nextFile;
|
||||||
|
|
||||||
|
_FAT_lock(&partition->lock);
|
||||||
|
|
||||||
|
/* Synchronize open files */
|
||||||
|
nextFile = partition->firstOpenFile;
|
||||||
|
while (nextFile)
|
||||||
|
{
|
||||||
|
_FAT_syncToDisc (nextFile);
|
||||||
|
nextFile = nextFile->nextOpenFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write out the fs info sector */
|
||||||
|
_FAT_partition_writeFSinfo(partition);
|
||||||
|
|
||||||
|
/* Free memory used by the cache, writing it to disc at the same time */
|
||||||
|
_FAT_cache_destructor (partition->cache);
|
||||||
|
|
||||||
|
/* Unlock the partition and destroy the lock */
|
||||||
|
_FAT_unlock(&partition->lock);
|
||||||
|
_FAT_lock_deinit(&partition->lock);
|
||||||
|
|
||||||
|
/* Free memory used by the partition */
|
||||||
|
_FAT_mem_free (partition);
|
||||||
|
}
|
||||||
|
|
||||||
|
PARTITION* _FAT_partition_getPartitionFromPath (const char* path)
|
||||||
|
{
|
||||||
|
const devoptab_t *devops = GetDeviceOpTab (path);
|
||||||
|
|
||||||
|
if (!devops)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return (PARTITION*)devops->deviceData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _FAT_partition_createFSinfo(PARTITION * partition)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint8_t *sectorBuffer;
|
||||||
|
|
||||||
|
if(partition->readOnly || partition->filesysType != FS_FAT32)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sectorBuffer = (uint8_t*) _FAT_mem_align(partition->bytesPerSector);
|
||||||
|
if (!sectorBuffer)
|
||||||
|
return;
|
||||||
|
memset(sectorBuffer, 0, partition->bytesPerSector);
|
||||||
|
|
||||||
|
for(i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
sectorBuffer[FSIB_SIG1+i] = FS_INFO_SIG1[i];
|
||||||
|
sectorBuffer[FSIB_SIG2+i] = FS_INFO_SIG2[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
partition->fat.numberFreeCluster = _FAT_fat_freeClusterCount(partition);
|
||||||
|
u32_to_u8array(sectorBuffer, FSIB_numberOfFreeCluster, partition->fat.numberFreeCluster);
|
||||||
|
u32_to_u8array(sectorBuffer, FSIB_numberLastAllocCluster, partition->fat.numberLastAllocCluster);
|
||||||
|
|
||||||
|
sectorBuffer[FSIB_bootSig_55] = 0x55;
|
||||||
|
sectorBuffer[FSIB_bootSig_AA] = 0xAA;
|
||||||
|
|
||||||
|
_FAT_disc_writeSectors (partition->disc, partition->fsInfoSector, 1, sectorBuffer);
|
||||||
|
|
||||||
|
_FAT_mem_free(sectorBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _FAT_partition_readFSinfo(PARTITION * partition)
|
||||||
|
{
|
||||||
|
uint8_t *sectorBuffer = NULL;
|
||||||
|
if(partition->filesysType != FS_FAT32)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sectorBuffer = (uint8_t*) _FAT_mem_align(partition->bytesPerSector);
|
||||||
|
if (!sectorBuffer)
|
||||||
|
return;
|
||||||
|
memset(sectorBuffer, 0, partition->bytesPerSector);
|
||||||
|
|
||||||
|
/* Read first sector of disc */
|
||||||
|
if (!_FAT_disc_readSectors (partition->disc, partition->fsInfoSector, 1, sectorBuffer))
|
||||||
|
{
|
||||||
|
_FAT_mem_free(sectorBuffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sector does not yet exist, create one! */
|
||||||
|
if(memcmp(sectorBuffer+FSIB_SIG1, FS_INFO_SIG1, 4) != 0 ||
|
||||||
|
memcmp(sectorBuffer+FSIB_SIG2, FS_INFO_SIG2, 4) != 0 ||
|
||||||
|
u8array_to_u32(sectorBuffer, FSIB_numberOfFreeCluster) == 0)
|
||||||
|
_FAT_partition_createFSinfo(partition);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
partition->fat.numberFreeCluster = u8array_to_u32(sectorBuffer, FSIB_numberOfFreeCluster);
|
||||||
|
partition->fat.numberLastAllocCluster = u8array_to_u32(sectorBuffer, FSIB_numberLastAllocCluster);
|
||||||
|
}
|
||||||
|
_FAT_mem_free(sectorBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _FAT_partition_writeFSinfo(PARTITION * partition)
|
||||||
|
{
|
||||||
|
uint8_t *sectorBuffer = NULL;
|
||||||
|
if(partition->filesysType != FS_FAT32)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sectorBuffer = (uint8_t*) _FAT_mem_align(partition->bytesPerSector);
|
||||||
|
if (!sectorBuffer)
|
||||||
|
return;
|
||||||
|
memset(sectorBuffer, 0, partition->bytesPerSector);
|
||||||
|
/* Read first sector of disc */
|
||||||
|
if (!_FAT_disc_readSectors (partition->disc, partition->fsInfoSector, 1, sectorBuffer))
|
||||||
|
{
|
||||||
|
_FAT_mem_free(sectorBuffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(memcmp(sectorBuffer+FSIB_SIG1, FS_INFO_SIG1, 4) || memcmp(sectorBuffer+FSIB_SIG2, FS_INFO_SIG2, 4))
|
||||||
|
{
|
||||||
|
_FAT_mem_free(sectorBuffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32_to_u8array(sectorBuffer, FSIB_numberOfFreeCluster, partition->fat.numberFreeCluster);
|
||||||
|
u32_to_u8array(sectorBuffer, FSIB_numberLastAllocCluster, partition->fat.numberLastAllocCluster);
|
||||||
|
|
||||||
|
/* Write first sector of disc */
|
||||||
|
_FAT_disc_writeSectors (partition->disc, partition->fsInfoSector, 1, sectorBuffer);
|
||||||
|
_FAT_mem_free(sectorBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t* _FAT_getCwdClusterPtr(const char* name)
|
||||||
|
{
|
||||||
|
PARTITION *partition = _FAT_partition_getPartitionFromPath(name);
|
||||||
|
|
||||||
|
if (!partition)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return &partition->cwdCluster;
|
||||||
|
}
|
107
deps/libfat/partition.h
vendored
Normal file
107
deps/libfat/partition.h
vendored
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
partition.h
|
||||||
|
Functions for mounting and dismounting partitions
|
||||||
|
on various block devices.
|
||||||
|
|
||||||
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PARTITION_H
|
||||||
|
#define _PARTITION_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "cache.h"
|
||||||
|
#include "lock.h"
|
||||||
|
|
||||||
|
#define MIN_SECTOR_SIZE 512
|
||||||
|
#define MAX_SECTOR_SIZE 4096
|
||||||
|
|
||||||
|
/* Filesystem type */
|
||||||
|
typedef enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} FS_TYPE;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
sec_t fatStart;
|
||||||
|
uint32_t sectorsPerFat;
|
||||||
|
uint32_t lastCluster;
|
||||||
|
uint32_t firstFree;
|
||||||
|
uint32_t numberFreeCluster;
|
||||||
|
uint32_t numberLastAllocCluster;
|
||||||
|
} FAT;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const DISC_INTERFACE* disc;
|
||||||
|
CACHE* cache;
|
||||||
|
/* Info about the partition */
|
||||||
|
FS_TYPE filesysType;
|
||||||
|
uint64_t totalSize;
|
||||||
|
sec_t rootDirStart;
|
||||||
|
uint32_t rootDirCluster;
|
||||||
|
uint32_t numberOfSectors;
|
||||||
|
sec_t dataStart;
|
||||||
|
uint32_t bytesPerSector;
|
||||||
|
uint32_t sectorsPerCluster;
|
||||||
|
uint32_t bytesPerCluster;
|
||||||
|
uint32_t fsInfoSector;
|
||||||
|
FAT fat;
|
||||||
|
/* Values that may change after construction */
|
||||||
|
uint32_t cwdCluster; /* Current working directory cluster */
|
||||||
|
int openFileCount;
|
||||||
|
struct _FILE_STRUCT* firstOpenFile; /* The start of a linked list of files */
|
||||||
|
mutex_t lock; /* A lock for partition operations */
|
||||||
|
bool readOnly; /* If this is set, then do not try writing to the disc */
|
||||||
|
char label[12]; /* Volume label */
|
||||||
|
} PARTITION;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Mount the supplied device and return a pointer to the struct necessary to use it
|
||||||
|
*/
|
||||||
|
PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t SectorsPerPage, sec_t startSector);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Dismount the device and free all structures used.
|
||||||
|
Will also attempt to synchronise all open files to disc.
|
||||||
|
*/
|
||||||
|
void _FAT_partition_destructor (PARTITION* partition);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Return the partition specified in a path, as taken from the devoptab.
|
||||||
|
*/
|
||||||
|
PARTITION* _FAT_partition_getPartitionFromPath (const char* path);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create the fs info sector.
|
||||||
|
*/
|
||||||
|
void _FAT_partition_createFSinfo(PARTITION * partition);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Read the fs info sector data.
|
||||||
|
*/
|
||||||
|
void _FAT_partition_readFSinfo(PARTITION * partition);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Write the fs info sector data.
|
||||||
|
*/
|
||||||
|
void _FAT_partition_writeFSinfo(PARTITION * partition);
|
||||||
|
|
||||||
|
#endif /* _PARTITION_H */
|
966
deps/libiosuhax/iosuhax.c
vendored
Normal file
966
deps/libiosuhax/iosuhax.c
vendored
Normal file
@ -0,0 +1,966 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2016
|
||||||
|
* by Dimok
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any
|
||||||
|
* damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any
|
||||||
|
* purpose, including commercial applications, and to alter it and
|
||||||
|
* redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you
|
||||||
|
* must not claim that you wrote the original software. If you use
|
||||||
|
* this software in a product, an acknowledgment in the product
|
||||||
|
* documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and
|
||||||
|
* must not be misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
***************************************************************************/
|
||||||
|
#include <string.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include "os_functions.h"
|
||||||
|
#include "iosuhax.h"
|
||||||
|
|
||||||
|
#define IOSUHAX_MAGIC_WORD 0x4E696365
|
||||||
|
|
||||||
|
#define IOCTL_MEM_WRITE 0x00
|
||||||
|
#define IOCTL_MEM_READ 0x01
|
||||||
|
#define IOCTL_SVC 0x02
|
||||||
|
#define IOCTL_MEMCPY 0x04
|
||||||
|
#define IOCTL_REPEATED_WRITE 0x05
|
||||||
|
#define IOCTL_KERN_READ32 0x06
|
||||||
|
#define IOCTL_KERN_WRITE32 0x07
|
||||||
|
|
||||||
|
#define IOCTL_FSA_OPEN 0x40
|
||||||
|
#define IOCTL_FSA_CLOSE 0x41
|
||||||
|
#define IOCTL_FSA_MOUNT 0x42
|
||||||
|
#define IOCTL_FSA_UNMOUNT 0x43
|
||||||
|
#define IOCTL_FSA_GETDEVICEINFO 0x44
|
||||||
|
#define IOCTL_FSA_OPENDIR 0x45
|
||||||
|
#define IOCTL_FSA_READDIR 0x46
|
||||||
|
#define IOCTL_FSA_CLOSEDIR 0x47
|
||||||
|
#define IOCTL_FSA_MAKEDIR 0x48
|
||||||
|
#define IOCTL_FSA_OPENFILE 0x49
|
||||||
|
#define IOCTL_FSA_READFILE 0x4A
|
||||||
|
#define IOCTL_FSA_WRITEFILE 0x4B
|
||||||
|
#define IOCTL_FSA_STATFILE 0x4C
|
||||||
|
#define IOCTL_FSA_CLOSEFILE 0x4D
|
||||||
|
#define IOCTL_FSA_SETFILEPOS 0x4E
|
||||||
|
#define IOCTL_FSA_GETSTAT 0x4F
|
||||||
|
#define IOCTL_FSA_REMOVE 0x50
|
||||||
|
#define IOCTL_FSA_REWINDDIR 0x51
|
||||||
|
#define IOCTL_FSA_CHDIR 0x52
|
||||||
|
#define IOCTL_FSA_RENAME 0x53
|
||||||
|
#define IOCTL_FSA_RAW_OPEN 0x54
|
||||||
|
#define IOCTL_FSA_RAW_READ 0x55
|
||||||
|
#define IOCTL_FSA_RAW_WRITE 0x56
|
||||||
|
#define IOCTL_FSA_RAW_CLOSE 0x57
|
||||||
|
#define IOCTL_FSA_CHANGEMODE 0x58
|
||||||
|
#define IOCTL_FSA_FLUSHVOLUME 0x59
|
||||||
|
#define IOCTL_CHECK_IF_IOSUHAX 0x5B
|
||||||
|
|
||||||
|
static int iosuhaxHandle = -1;
|
||||||
|
|
||||||
|
int IOSUHAX_Open(const char *dev)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle >= 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
iosuhaxHandle = IOS_Open((char*)(dev ? dev : "/dev/iosuhax"), 0);
|
||||||
|
if(iosuhaxHandle >= 0 && dev) /* make sure device is actually iosuhax */
|
||||||
|
{
|
||||||
|
unsigned int res = 0;
|
||||||
|
IOS_Ioctl(iosuhaxHandle, IOCTL_CHECK_IF_IOSUHAX, (void*)0, 0, &res, 4);
|
||||||
|
if(res != IOSUHAX_MAGIC_WORD)
|
||||||
|
{
|
||||||
|
IOS_Close(iosuhaxHandle);
|
||||||
|
iosuhaxHandle = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return iosuhaxHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_Close(void)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int res = IOS_Close(iosuhaxHandle);
|
||||||
|
iosuhaxHandle = -1;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_memwrite(uint32_t address, const uint8_t * buffer, uint32_t size)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, size + 4);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = address;
|
||||||
|
memcpy(io_buf + 1, buffer, size);
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_MEM_WRITE, io_buf, size + 4, 0, 0);
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_memread(uint32_t address, uint8_t * out_buffer, uint32_t size)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
return IOS_Ioctl(iosuhaxHandle, IOCTL_MEM_READ, &address, sizeof(address), out_buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_memcpy(uint32_t dst, uint32_t src, uint32_t size)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
uint32_t io_buf[3];
|
||||||
|
io_buf[0] = dst;
|
||||||
|
io_buf[1] = src;
|
||||||
|
io_buf[2] = size;
|
||||||
|
|
||||||
|
return IOS_Ioctl(iosuhaxHandle, IOCTL_MEMCPY, io_buf, sizeof(io_buf), 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_SVC(uint32_t svc_id, uint32_t * args, uint32_t arg_cnt)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
uint32_t arguments[9];
|
||||||
|
arguments[0] = svc_id;
|
||||||
|
|
||||||
|
if(args && arg_cnt)
|
||||||
|
{
|
||||||
|
if(arg_cnt > 8)
|
||||||
|
arg_cnt = 8;
|
||||||
|
|
||||||
|
memcpy(arguments + 1, args, arg_cnt * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
int result;
|
||||||
|
int ret = IOS_Ioctl(iosuhaxHandle, IOCTL_SVC, arguments, (1 + arg_cnt) * 4, &result, sizeof(result));
|
||||||
|
if(ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_Open(void)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
int fsaFd;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_OPEN, 0, 0, &fsaFd, sizeof(fsaFd));
|
||||||
|
if(res < 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
return fsaFd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_Close(int fsaFd)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CLOSE, &fsaFd, sizeof(fsaFd), &fsaFd, sizeof(fsaFd));
|
||||||
|
if(res < 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
return fsaFd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_Mount(int fsaFd, const char* device_path, const char* volume_path, uint32_t flags, const char* arg_string, int arg_string_len)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 6;
|
||||||
|
|
||||||
|
int io_buf_size = (sizeof(uint32_t) * input_cnt) + strlen(device_path) + strlen(volume_path) + arg_string_len + 3;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
memset(io_buf, 0, io_buf_size);
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(uint32_t) * input_cnt;
|
||||||
|
io_buf[2] = io_buf[1] + strlen(device_path) + 1;
|
||||||
|
io_buf[3] = flags;
|
||||||
|
io_buf[4] = arg_string_len ? ( io_buf[2] + strlen(volume_path) + 1) : 0;
|
||||||
|
io_buf[5] = arg_string_len;
|
||||||
|
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], device_path);
|
||||||
|
strcpy(((char*)io_buf) + io_buf[2], volume_path);
|
||||||
|
|
||||||
|
if(arg_string_len)
|
||||||
|
memcpy(((char*)io_buf) + io_buf[4], arg_string, arg_string_len);
|
||||||
|
|
||||||
|
int mountRes;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_MOUNT, io_buf, io_buf_size, &mountRes, sizeof(mountRes));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return mountRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_Unmount(int fsaFd, const char* path, uint32_t flags)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 3;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(uint32_t) * input_cnt;
|
||||||
|
io_buf[2] = flags;
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], path);
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_UNMOUNT, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_FlushVolume(int fsaFd, const char *volume_path)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(volume_path) + 1;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(uint32_t) * input_cnt;
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], volume_path);
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_FLUSHVOLUME, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_GetDeviceInfo(int fsaFd, const char* device_path, int type, uint32_t* out_data)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 3;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(device_path) + 1;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(uint32_t) * input_cnt;
|
||||||
|
io_buf[2] = type;
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], device_path);
|
||||||
|
|
||||||
|
uint32_t out_buf[1 + 0x64 / 4];
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_GETDEVICEINFO, io_buf, io_buf_size, out_buf, sizeof(out_buf));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(out_data, out_buf + 1, 0x64);
|
||||||
|
free(io_buf);
|
||||||
|
return out_buf[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_MakeDir(int fsaFd, const char* path, uint32_t flags)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 3;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(uint32_t) * input_cnt;
|
||||||
|
io_buf[2] = flags;
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], path);
|
||||||
|
|
||||||
|
int result;
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_MAKEDIR, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_OpenDir(int fsaFd, const char* path, int* outHandle)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(uint32_t) * input_cnt;
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], path);
|
||||||
|
|
||||||
|
int result_vec[2];
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_OPENDIR, io_buf, io_buf_size, result_vec, sizeof(result_vec));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
*outHandle = result_vec[1];
|
||||||
|
free(io_buf);
|
||||||
|
return result_vec[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_ReadDir(int fsaFd, int handle, directoryEntry_s* out_data)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = handle;
|
||||||
|
|
||||||
|
int result_vec_size = 4 + sizeof(directoryEntry_s);
|
||||||
|
uint8_t *result_vec = (uint8_t*) memalign(0x20, result_vec_size);
|
||||||
|
if(!result_vec)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_READDIR, io_buf, io_buf_size, result_vec, result_vec_size);
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(result_vec);
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = *(int*)result_vec;
|
||||||
|
memcpy(out_data, result_vec + 4, sizeof(directoryEntry_s));
|
||||||
|
free(io_buf);
|
||||||
|
free(result_vec);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_RewindDir(int fsaFd, int dirHandle)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = dirHandle;
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_REWINDDIR, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_CloseDir(int fsaFd, int handle)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = handle;
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CLOSEDIR, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_ChangeDir(int fsaFd, const char *path)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(uint32_t) * input_cnt;
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], path);
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CHDIR, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_OpenFile(int fsaFd, const char* path, const char* mode, int* outHandle)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 3;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + strlen(mode) + 2;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(uint32_t) * input_cnt;
|
||||||
|
io_buf[2] = io_buf[1] + strlen(path) + 1;
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], path);
|
||||||
|
strcpy(((char*)io_buf) + io_buf[2], mode);
|
||||||
|
|
||||||
|
int result_vec[2];
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_OPENFILE, io_buf, io_buf_size, result_vec, sizeof(result_vec));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
*outHandle = result_vec[1];
|
||||||
|
free(io_buf);
|
||||||
|
return result_vec[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_ReadFile(int fsaFd, void* data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 5;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = size;
|
||||||
|
io_buf[2] = cnt;
|
||||||
|
io_buf[3] = fileHandle;
|
||||||
|
io_buf[4] = flags;
|
||||||
|
|
||||||
|
int out_buf_size = ((size * cnt + 0x40) + 0x3F) & ~0x3F;
|
||||||
|
|
||||||
|
uint32_t *out_buffer = (uint32_t*)memalign(0x40, out_buf_size);
|
||||||
|
if(!out_buffer)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_READFILE, io_buf, io_buf_size, out_buffer, out_buf_size);
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(out_buffer);
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ! data is put to offset 0x40 to align the buffer output */
|
||||||
|
memcpy(data, ((uint8_t*)out_buffer) + 0x40, size * cnt);
|
||||||
|
|
||||||
|
int result = out_buffer[0];
|
||||||
|
|
||||||
|
free(out_buffer);
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_WriteFile(int fsaFd, const void* data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 5;
|
||||||
|
|
||||||
|
int io_buf_size = ((sizeof(uint32_t) * input_cnt + size * cnt + 0x40) + 0x3F) & ~0x3F;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = size;
|
||||||
|
io_buf[2] = cnt;
|
||||||
|
io_buf[3] = fileHandle;
|
||||||
|
io_buf[4] = flags;
|
||||||
|
|
||||||
|
/* ! data is put to offset 0x40 to align the buffer input */
|
||||||
|
memcpy(((uint8_t*)io_buf) + 0x40, data, size * cnt);
|
||||||
|
|
||||||
|
int result;
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_WRITEFILE, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, fileStat_s* out_data)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = fileHandle;
|
||||||
|
|
||||||
|
int out_buf_size = 4 + sizeof(fileStat_s);
|
||||||
|
uint32_t *out_buffer = (uint32_t*)memalign(0x20, out_buf_size);
|
||||||
|
if(!out_buffer)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_STATFILE, io_buf, io_buf_size, out_buffer, out_buf_size);
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
free(out_buffer);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = out_buffer[0];
|
||||||
|
memcpy(out_data, out_buffer + 1, sizeof(fileStat_s));
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
free(out_buffer);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_CloseFile(int fsaFd, int fileHandle)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = fileHandle;
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CLOSEFILE, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_SetFilePos(int fsaFd, int fileHandle, uint32_t position)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 3;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = fileHandle;
|
||||||
|
io_buf[2] = position;
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_SETFILEPOS, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, fileStat_s* out_data)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(uint32_t) * input_cnt;
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], path);
|
||||||
|
|
||||||
|
int out_buf_size = 4 + sizeof(fileStat_s);
|
||||||
|
uint32_t *out_buffer = (uint32_t*)memalign(0x20, out_buf_size);
|
||||||
|
if(!out_buffer)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_GETSTAT, io_buf, io_buf_size, out_buffer, out_buf_size);
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
free(out_buffer);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = out_buffer[0];
|
||||||
|
memcpy(out_data, out_buffer + 1, sizeof(fileStat_s));
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
free(out_buffer);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_Remove(int fsaFd, const char *path)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(uint32_t) * input_cnt;
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], path);
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_REMOVE, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_ChangeMode(int fsaFd, const char* path, int mode)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 3;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(uint32_t) * input_cnt;
|
||||||
|
io_buf[2] = mode;
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], path);
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CHANGEMODE, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_RawOpen(int fsaFd, const char* device_path, int* outHandle)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(device_path) + 1;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(uint32_t) * input_cnt;
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], device_path);
|
||||||
|
|
||||||
|
int result_vec[2];
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_RAW_OPEN, io_buf, io_buf_size, result_vec, sizeof(result_vec));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(outHandle)
|
||||||
|
*outHandle = result_vec[1];
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return result_vec[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_RawRead(int fsaFd, void* data, uint32_t block_size, uint32_t block_cnt, uint64_t sector_offset, int device_handle)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 6;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = block_size;
|
||||||
|
io_buf[2] = block_cnt;
|
||||||
|
io_buf[3] = (sector_offset >> 32) & 0xFFFFFFFF;
|
||||||
|
io_buf[4] = sector_offset & 0xFFFFFFFF;
|
||||||
|
io_buf[5] = device_handle;
|
||||||
|
|
||||||
|
int out_buf_size = ((block_size * block_cnt + 0x40) + 0x3F) & ~0x3F;
|
||||||
|
|
||||||
|
uint32_t *out_buffer = (uint32_t*)memalign(0x40, out_buf_size);
|
||||||
|
if(!out_buffer)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_RAW_READ, io_buf, io_buf_size, out_buffer, out_buf_size);
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(out_buffer);
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ! data is put to offset 0x40 to align the buffer output */
|
||||||
|
memcpy(data, ((uint8_t*)out_buffer) + 0x40, block_size * block_cnt);
|
||||||
|
|
||||||
|
int result = out_buffer[0];
|
||||||
|
|
||||||
|
free(out_buffer);
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_RawWrite(int fsaFd, const void* data, uint32_t block_size, uint32_t block_cnt, uint64_t sector_offset, int device_handle)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 6;
|
||||||
|
|
||||||
|
int io_buf_size = ((sizeof(uint32_t) * input_cnt + block_size * block_cnt + 0x40) + 0x3F) & ~0x3F;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = block_size;
|
||||||
|
io_buf[2] = block_cnt;
|
||||||
|
io_buf[3] = (sector_offset >> 32) & 0xFFFFFFFF;
|
||||||
|
io_buf[4] = sector_offset & 0xFFFFFFFF;
|
||||||
|
io_buf[5] = device_handle;
|
||||||
|
|
||||||
|
/* ! data is put to offset 0x40 to align the buffer input */
|
||||||
|
memcpy(((uint8_t*)io_buf) + 0x40, data, block_size * block_cnt);
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_RAW_WRITE, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_RawClose(int fsaFd, int device_handle)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(uint32_t) * input_cnt;
|
||||||
|
|
||||||
|
uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = device_handle;
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_RAW_CLOSE, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
109
deps/libiosuhax/iosuhax.h
vendored
Normal file
109
deps/libiosuhax/iosuhax.h
vendored
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2016
|
||||||
|
* by Dimok
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any
|
||||||
|
* damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any
|
||||||
|
* purpose, including commercial applications, and to alter it and
|
||||||
|
* redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you
|
||||||
|
* must not claim that you wrote the original software. If you use
|
||||||
|
* this software in a product, an acknowledgment in the product
|
||||||
|
* documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and
|
||||||
|
* must not be misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef _LIB_IOSUHAX_H_
|
||||||
|
#define _LIB_IOSUHAX_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define IOS_ERROR_UNKNOWN_VALUE 0xFFFFFFD6
|
||||||
|
#define IOS_ERROR_INVALID_ARG 0xFFFFFFE3
|
||||||
|
#define IOS_ERROR_INVALID_SIZE 0xFFFFFFE9
|
||||||
|
#define IOS_ERROR_UNKNOWN 0xFFFFFFF7
|
||||||
|
#define IOS_ERROR_NOEXISTS 0xFFFFFFFA
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t flag;
|
||||||
|
uint32_t permission;
|
||||||
|
uint32_t owner_id;
|
||||||
|
uint32_t group_id;
|
||||||
|
uint32_t size; // size in bytes
|
||||||
|
uint32_t physsize; // physical size on disk in bytes
|
||||||
|
uint32_t unk[3];
|
||||||
|
uint32_t id;
|
||||||
|
uint32_t ctime;
|
||||||
|
uint32_t mtime;
|
||||||
|
uint32_t unk2[0x0D];
|
||||||
|
}fileStat_s;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
fileStat_s stat;
|
||||||
|
char name[0x100];
|
||||||
|
}directoryEntry_s;
|
||||||
|
|
||||||
|
#define DIR_ENTRY_IS_DIRECTORY 0x80000000
|
||||||
|
|
||||||
|
#define FSA_MOUNTFLAGS_BINDMOUNT (1 << 0)
|
||||||
|
#define FSA_MOUNTFLAGS_GLOBAL (1 << 1)
|
||||||
|
|
||||||
|
int IOSUHAX_Open(const char *dev); // if dev == NULL the default path /dev/iosuhax will be used
|
||||||
|
int IOSUHAX_Close(void);
|
||||||
|
|
||||||
|
int IOSUHAX_memwrite(uint32_t address, const uint8_t * buffer, uint32_t size); // IOSU external input
|
||||||
|
int IOSUHAX_memread(uint32_t address, uint8_t * out_buffer, uint32_t size); // IOSU external output
|
||||||
|
int IOSUHAX_memcpy(uint32_t dst, uint32_t src, uint32_t size); // IOSU internal memcpy only
|
||||||
|
|
||||||
|
int IOSUHAX_SVC(uint32_t svc_id, uint32_t * args, uint32_t arg_cnt);
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_Open();
|
||||||
|
int IOSUHAX_FSA_Close(int fsaFd);
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_Mount(int fsaFd, const char* device_path, const char* volume_path, uint32_t flags, const char* arg_string, int arg_string_len);
|
||||||
|
int IOSUHAX_FSA_Unmount(int fsaFd, const char* path, uint32_t flags);
|
||||||
|
int IOSUHAX_FSA_FlushVolume(int fsaFd, const char* volume_path);
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_GetDeviceInfo(int fsaFd, const char* device_path, int type, uint32_t* out_data);
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_MakeDir(int fsaFd, const char* path, uint32_t flags);
|
||||||
|
int IOSUHAX_FSA_OpenDir(int fsaFd, const char* path, int* outHandle);
|
||||||
|
int IOSUHAX_FSA_ReadDir(int fsaFd, int handle, directoryEntry_s* out_data);
|
||||||
|
int IOSUHAX_FSA_RewindDir(int fsaFd, int dirHandle);
|
||||||
|
int IOSUHAX_FSA_CloseDir(int fsaFd, int handle);
|
||||||
|
int IOSUHAX_FSA_ChangeDir(int fsaFd, const char *path);
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_OpenFile(int fsaFd, const char* path, const char* mode, int* outHandle);
|
||||||
|
int IOSUHAX_FSA_ReadFile(int fsaFd, void* data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags);
|
||||||
|
int IOSUHAX_FSA_WriteFile(int fsaFd, const void* data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags);
|
||||||
|
int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, fileStat_s* out_data);
|
||||||
|
int IOSUHAX_FSA_CloseFile(int fsaFd, int fileHandle);
|
||||||
|
int IOSUHAX_FSA_SetFilePos(int fsaFd, int fileHandle, uint32_t position);
|
||||||
|
int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, fileStat_s* out_data);
|
||||||
|
int IOSUHAX_FSA_Remove(int fsaFd, const char *path);
|
||||||
|
int IOSUHAX_FSA_ChangeMode(int fsaFd, const char* path, int mode);
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_RawOpen(int fsaFd, const char* device_path, int* outHandle);
|
||||||
|
int IOSUHAX_FSA_RawRead(int fsaFd, void* data, uint32_t block_size, uint32_t block_cnt, uint64_t sector_offset, int device_handle);
|
||||||
|
int IOSUHAX_FSA_RawWrite(int fsaFd, const void* data, uint32_t block_size, uint32_t block_cnt, uint64_t sector_offset, int device_handle);
|
||||||
|
int IOSUHAX_FSA_RawClose(int fsaFd, int device_handle);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
974
deps/libiosuhax/iosuhax_devoptab.c
vendored
Normal file
974
deps/libiosuhax/iosuhax_devoptab.c
vendored
Normal file
@ -0,0 +1,974 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2015
|
||||||
|
* by Dimok
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any
|
||||||
|
* damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any
|
||||||
|
* purpose, including commercial applications, and to alter it and
|
||||||
|
* redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you
|
||||||
|
* must not claim that you wrote the original software. If you use
|
||||||
|
* this software in a product, an acknowledgment in the product
|
||||||
|
* documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and
|
||||||
|
* must not be misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
***************************************************************************/
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
|
#include <sys/dirent.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "os_functions.h"
|
||||||
|
#include "iosuhax.h"
|
||||||
|
|
||||||
|
typedef struct _fs_dev_private_t {
|
||||||
|
char *mount_path;
|
||||||
|
int fsaFd;
|
||||||
|
int mounted;
|
||||||
|
void *pMutex;
|
||||||
|
} fs_dev_private_t;
|
||||||
|
|
||||||
|
typedef struct _fs_dev_file_state_t {
|
||||||
|
fs_dev_private_t *dev;
|
||||||
|
int fd; /* File descriptor */
|
||||||
|
int flags; /* Opening flags */
|
||||||
|
int read; /* True if allowed to read from file */
|
||||||
|
int write; /* True if allowed to write to file */
|
||||||
|
int append; /* True if allowed to append to file */
|
||||||
|
uint32_t pos; /* Current position within the file (in bytes) */
|
||||||
|
uint32_t len; /* Total length of the file (in bytes) */
|
||||||
|
struct _fs_dev_file_state_t *prevOpenFile; /* The previous entry in a double-linked FILO list of open files */
|
||||||
|
struct _fs_dev_file_state_t *nextOpenFile; /* The next entry in a double-linked FILO list of open files */
|
||||||
|
} fs_dev_file_state_t;
|
||||||
|
|
||||||
|
typedef struct _fs_dev_dir_entry_t {
|
||||||
|
fs_dev_private_t *dev;
|
||||||
|
int dirHandle;
|
||||||
|
} fs_dev_dir_entry_t;
|
||||||
|
|
||||||
|
static fs_dev_private_t *fs_dev_get_device_data(const char *path)
|
||||||
|
{
|
||||||
|
const devoptab_t *devoptab = NULL;
|
||||||
|
char name[128] = {0};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Get the device name from the path */
|
||||||
|
strncpy(name, path, 127);
|
||||||
|
strtok(name, ":/");
|
||||||
|
|
||||||
|
// Search the devoptab table for the specified device name
|
||||||
|
// NOTE: We do this manually due to a 'bug' in GetDeviceOpTab
|
||||||
|
// which ignores names with suffixes and causes names
|
||||||
|
// like "ntfs" and "ntfs1" to be seen as equals
|
||||||
|
for (i = 3; i < STD_MAX; i++) {
|
||||||
|
devoptab = devoptab_list[i];
|
||||||
|
if (devoptab && devoptab->name) {
|
||||||
|
if (strcmp(name, devoptab->name) == 0) {
|
||||||
|
return (fs_dev_private_t *)devoptab->deviceData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *fs_dev_real_path (const char *path, fs_dev_private_t *dev)
|
||||||
|
{
|
||||||
|
/* Sanity check */
|
||||||
|
if (!path)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Move the path pointer to the start of the actual path */
|
||||||
|
if (strchr(path, ':') != NULL) {
|
||||||
|
path = strchr(path, ':') + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mount_len = strlen(dev->mount_path);
|
||||||
|
|
||||||
|
char *new_name = (char*)malloc(mount_len + strlen(path) + 1);
|
||||||
|
if(new_name) {
|
||||||
|
strcpy(new_name, dev->mount_path);
|
||||||
|
strcpy(new_name + mount_len, path);
|
||||||
|
return new_name;
|
||||||
|
}
|
||||||
|
return new_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode)
|
||||||
|
{
|
||||||
|
fs_dev_private_t *dev = fs_dev_get_device_data(path);
|
||||||
|
if(!dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs_dev_file_state_t *file = (fs_dev_file_state_t *)fileStruct;
|
||||||
|
|
||||||
|
file->dev = dev;
|
||||||
|
/* Determine which mode the file is opened for */
|
||||||
|
file->flags = flags;
|
||||||
|
|
||||||
|
const char *mode_str;
|
||||||
|
|
||||||
|
if ((flags & 0x03) == O_RDONLY) {
|
||||||
|
file->read = 1;
|
||||||
|
file->write = 0;
|
||||||
|
file->append = 0;
|
||||||
|
mode_str = "r";
|
||||||
|
} else if ((flags & 0x03) == O_WRONLY) {
|
||||||
|
file->read = 0;
|
||||||
|
file->write = 1;
|
||||||
|
file->append = (flags & O_APPEND);
|
||||||
|
mode_str = file->append ? "a" : "w";
|
||||||
|
} else if ((flags & 0x03) == O_RDWR) {
|
||||||
|
file->read = 1;
|
||||||
|
file->write = 1;
|
||||||
|
file->append = (flags & O_APPEND);
|
||||||
|
mode_str = file->append ? "a+" : "r+";
|
||||||
|
} else {
|
||||||
|
r->_errno = EACCES;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
|
OSLockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
char *real_path = fs_dev_real_path(path, dev);
|
||||||
|
if(!path) {
|
||||||
|
r->_errno = ENOMEM;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_OpenFile(dev->fsaFd, real_path, mode_str, &fd);
|
||||||
|
|
||||||
|
free(real_path);
|
||||||
|
|
||||||
|
if(result == 0)
|
||||||
|
{
|
||||||
|
fileStat_s stats;
|
||||||
|
result = IOSUHAX_FSA_StatFile(dev->fsaFd, fd, &stats);
|
||||||
|
if(result != 0) {
|
||||||
|
IOSUHAX_FSA_CloseFile(dev->fsaFd, fd);
|
||||||
|
r->_errno = result;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
file->fd = fd;
|
||||||
|
file->pos = 0;
|
||||||
|
file->len = stats.size;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return (int)file;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->_errno = result;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int fs_dev_close_r (struct _reent *r, int fd)
|
||||||
|
{
|
||||||
|
fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd;
|
||||||
|
if(!file->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(file->dev->pMutex);
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_CloseFile(file->dev->fsaFd, file->fd);
|
||||||
|
|
||||||
|
OSUnlockMutex(file->dev->pMutex);
|
||||||
|
|
||||||
|
if(result < 0)
|
||||||
|
{
|
||||||
|
r->_errno = result;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static off_t fs_dev_seek_r (struct _reent *r, int fd, off_t pos, int dir)
|
||||||
|
{
|
||||||
|
fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd;
|
||||||
|
if(!file->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(file->dev->pMutex);
|
||||||
|
|
||||||
|
switch(dir)
|
||||||
|
{
|
||||||
|
case SEEK_SET:
|
||||||
|
file->pos = pos;
|
||||||
|
break;
|
||||||
|
case SEEK_CUR:
|
||||||
|
file->pos += pos;
|
||||||
|
break;
|
||||||
|
case SEEK_END:
|
||||||
|
file->pos = file->len + pos;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
r->_errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_SetFilePos(file->dev->fsaFd, file->fd, file->pos);
|
||||||
|
|
||||||
|
OSUnlockMutex(file->dev->pMutex);
|
||||||
|
|
||||||
|
if(result == 0)
|
||||||
|
{
|
||||||
|
return file->pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t fs_dev_write_r (struct _reent *r, int fd, const char *ptr, size_t len)
|
||||||
|
{
|
||||||
|
fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd;
|
||||||
|
if(!file->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!file->write)
|
||||||
|
{
|
||||||
|
r->_errno = EACCES;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(file->dev->pMutex);
|
||||||
|
|
||||||
|
size_t done = 0;
|
||||||
|
|
||||||
|
while(done < len)
|
||||||
|
{
|
||||||
|
size_t write_size = len - done;
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_WriteFile(file->dev->fsaFd, ptr + done, 0x01, write_size, file->fd, 0);
|
||||||
|
if(result < 0)
|
||||||
|
{
|
||||||
|
r->_errno = result;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(result == 0)
|
||||||
|
{
|
||||||
|
if(write_size > 0)
|
||||||
|
done = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
done += result;
|
||||||
|
file->pos += result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OSUnlockMutex(file->dev->pMutex);
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t fs_dev_read_r (struct _reent *r, int fd, char *ptr, size_t len)
|
||||||
|
{
|
||||||
|
fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd;
|
||||||
|
if(!file->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!file->read)
|
||||||
|
{
|
||||||
|
r->_errno = EACCES;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(file->dev->pMutex);
|
||||||
|
|
||||||
|
size_t done = 0;
|
||||||
|
|
||||||
|
while(done < len)
|
||||||
|
{
|
||||||
|
size_t read_size = len - done;
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_ReadFile(file->dev->fsaFd, ptr + done, 0x01, read_size, file->fd, 0);
|
||||||
|
if(result < 0)
|
||||||
|
{
|
||||||
|
r->_errno = result;
|
||||||
|
done = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(result == 0)
|
||||||
|
{
|
||||||
|
/*! TODO: error on read_size > 0 */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
done += result;
|
||||||
|
file->pos += result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OSUnlockMutex(file->dev->pMutex);
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int fs_dev_fstat_r (struct _reent *r, int fd, struct stat *st)
|
||||||
|
{
|
||||||
|
fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd;
|
||||||
|
if(!file->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(file->dev->pMutex);
|
||||||
|
|
||||||
|
/* Zero out the stat buffer */
|
||||||
|
memset(st, 0, sizeof(struct stat));
|
||||||
|
|
||||||
|
fileStat_s stats;
|
||||||
|
int result = IOSUHAX_FSA_StatFile(file->dev->fsaFd, fd, &stats);
|
||||||
|
if(result != 0) {
|
||||||
|
r->_errno = result;
|
||||||
|
OSUnlockMutex(file->dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
st->st_mode = S_IFREG;
|
||||||
|
st->st_size = stats.size;
|
||||||
|
st->st_blocks = (stats.size + 511) >> 9;
|
||||||
|
st->st_nlink = 1;
|
||||||
|
|
||||||
|
/* Fill in the generic entry stats */
|
||||||
|
st->st_dev = stats.id;
|
||||||
|
st->st_uid = stats.owner_id;
|
||||||
|
st->st_gid = stats.group_id;
|
||||||
|
st->st_ino = stats.id;
|
||||||
|
st->st_atime = stats.mtime;
|
||||||
|
st->st_ctime = stats.ctime;
|
||||||
|
st->st_mtime = stats.mtime;
|
||||||
|
OSUnlockMutex(file->dev->pMutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_ftruncate_r (struct _reent *r, int fd, off_t len)
|
||||||
|
{
|
||||||
|
fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd;
|
||||||
|
if(!file->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->_errno = ENOTSUP;
|
||||||
|
/* TODO */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_fsync_r (struct _reent *r, int fd)
|
||||||
|
{
|
||||||
|
fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd;
|
||||||
|
if(!file->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->_errno = ENOTSUP;
|
||||||
|
/* TODO */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_stat_r (struct _reent *r, const char *path, struct stat *st)
|
||||||
|
{
|
||||||
|
fs_dev_private_t *dev = fs_dev_get_device_data(path);
|
||||||
|
if(!dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
// Zero out the stat buffer
|
||||||
|
memset(st, 0, sizeof(struct stat));
|
||||||
|
|
||||||
|
char *real_path = fs_dev_real_path(path, dev);
|
||||||
|
if(!real_path) {
|
||||||
|
r->_errno = ENOMEM;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileStat_s stats;
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_GetStat(dev->fsaFd, real_path, &stats);
|
||||||
|
|
||||||
|
free(real_path);
|
||||||
|
|
||||||
|
if(result < 0) {
|
||||||
|
r->_errno = result;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark root also as directory
|
||||||
|
st->st_mode = ((stats.flag & 0x80000000) || (strlen(dev->mount_path) + 1 == strlen(real_path)))? S_IFDIR : S_IFREG;
|
||||||
|
st->st_nlink = 1;
|
||||||
|
st->st_size = stats.size;
|
||||||
|
st->st_blocks = (stats.size + 511) >> 9;
|
||||||
|
// Fill in the generic entry stats
|
||||||
|
st->st_dev = stats.id;
|
||||||
|
st->st_uid = stats.owner_id;
|
||||||
|
st->st_gid = stats.group_id;
|
||||||
|
st->st_ino = stats.id;
|
||||||
|
st->st_atime = stats.mtime;
|
||||||
|
st->st_ctime = stats.ctime;
|
||||||
|
st->st_mtime = stats.mtime;
|
||||||
|
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_link_r (struct _reent *r, const char *existing, const char *newLink)
|
||||||
|
{
|
||||||
|
r->_errno = ENOTSUP;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_unlink_r (struct _reent *r, const char *name)
|
||||||
|
{
|
||||||
|
fs_dev_private_t *dev = fs_dev_get_device_data(name);
|
||||||
|
if(!dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
char *real_path = fs_dev_real_path(name, dev);
|
||||||
|
if(!real_path) {
|
||||||
|
r->_errno = ENOMEM;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_Remove(dev->fsaFd, real_path);
|
||||||
|
|
||||||
|
free(real_path);
|
||||||
|
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
if(result < 0) {
|
||||||
|
r->_errno = result;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_chdir_r (struct _reent *r, const char *name)
|
||||||
|
{
|
||||||
|
fs_dev_private_t *dev = fs_dev_get_device_data(name);
|
||||||
|
if(!dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
char *real_path = fs_dev_real_path(name, dev);
|
||||||
|
if(!real_path) {
|
||||||
|
r->_errno = ENOMEM;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_ChangeDir(dev->fsaFd, real_path);
|
||||||
|
|
||||||
|
free(real_path);
|
||||||
|
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
if(result < 0) {
|
||||||
|
r->_errno = result;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
||||||
|
{
|
||||||
|
fs_dev_private_t *dev = fs_dev_get_device_data(oldName);
|
||||||
|
if(!dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
char *real_oldpath = fs_dev_real_path(oldName, dev);
|
||||||
|
if(!real_oldpath) {
|
||||||
|
r->_errno = ENOMEM;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
char *real_newpath = fs_dev_real_path(newName, dev);
|
||||||
|
if(!real_newpath) {
|
||||||
|
r->_errno = ENOMEM;
|
||||||
|
free(real_oldpath);
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! TODO
|
||||||
|
int result = -ENOTSUP;
|
||||||
|
|
||||||
|
free(real_oldpath);
|
||||||
|
free(real_newpath);
|
||||||
|
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
if(result < 0) {
|
||||||
|
r->_errno = result;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_mkdir_r (struct _reent *r, const char *path, int mode)
|
||||||
|
{
|
||||||
|
fs_dev_private_t *dev = fs_dev_get_device_data(path);
|
||||||
|
if(!dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
char *real_path = fs_dev_real_path(path, dev);
|
||||||
|
if(!real_path) {
|
||||||
|
r->_errno = ENOMEM;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_MakeDir(dev->fsaFd, real_path, mode);
|
||||||
|
|
||||||
|
free(real_path);
|
||||||
|
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
if(result < 0) {
|
||||||
|
r->_errno = result;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_chmod_r (struct _reent *r, const char *path, int mode)
|
||||||
|
{
|
||||||
|
fs_dev_private_t *dev = fs_dev_get_device_data(path);
|
||||||
|
if(!dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
char *real_path = fs_dev_real_path(path, dev);
|
||||||
|
if(!real_path) {
|
||||||
|
r->_errno = ENOMEM;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_ChangeMode(dev->fsaFd, real_path, mode);
|
||||||
|
|
||||||
|
free(real_path);
|
||||||
|
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
if(result < 0) {
|
||||||
|
r->_errno = result;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
|
||||||
|
{
|
||||||
|
fs_dev_private_t *dev = fs_dev_get_device_data(path);
|
||||||
|
if(!dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
// Zero out the stat buffer
|
||||||
|
memset(buf, 0, sizeof(struct statvfs));
|
||||||
|
|
||||||
|
char *real_path = fs_dev_real_path(path, dev);
|
||||||
|
if(!real_path) {
|
||||||
|
r->_errno = ENOMEM;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t size;
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_GetDeviceInfo(dev->fsaFd, real_path, 0x00, (uint32_t*)&size);
|
||||||
|
|
||||||
|
free(real_path);
|
||||||
|
|
||||||
|
if(result < 0) {
|
||||||
|
r->_errno = result;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// File system block size
|
||||||
|
buf->f_bsize = 512;
|
||||||
|
|
||||||
|
// Fundamental file system block size
|
||||||
|
buf->f_frsize = 512;
|
||||||
|
|
||||||
|
// Total number of blocks on file system in units of f_frsize
|
||||||
|
buf->f_blocks = size >> 9; // this is unknown
|
||||||
|
|
||||||
|
// Free blocks available for all and for non-privileged processes
|
||||||
|
buf->f_bfree = buf->f_bavail = size >> 9;
|
||||||
|
|
||||||
|
// Number of inodes at this point in time
|
||||||
|
buf->f_files = 0xffffffff;
|
||||||
|
|
||||||
|
// Free inodes available for all and for non-privileged processes
|
||||||
|
buf->f_ffree = 0xffffffff;
|
||||||
|
|
||||||
|
// File system id
|
||||||
|
buf->f_fsid = (int)dev;
|
||||||
|
|
||||||
|
// Bit mask of f_flag values.
|
||||||
|
buf->f_flag = 0;
|
||||||
|
|
||||||
|
// Maximum length of filenames
|
||||||
|
buf->f_namemax = 255;
|
||||||
|
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DIR_ITER *fs_dev_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path)
|
||||||
|
{
|
||||||
|
fs_dev_private_t *dev = fs_dev_get_device_data(path);
|
||||||
|
if(!dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs_dev_dir_entry_t *dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct;
|
||||||
|
|
||||||
|
OSLockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
char *real_path = fs_dev_real_path(path, dev);
|
||||||
|
if(!real_path) {
|
||||||
|
r->_errno = ENOMEM;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dirHandle;
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_OpenDir(dev->fsaFd, real_path, &dirHandle);
|
||||||
|
|
||||||
|
free(real_path);
|
||||||
|
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
if(result < 0)
|
||||||
|
{
|
||||||
|
r->_errno = result;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dirIter->dev = dev;
|
||||||
|
dirIter->dirHandle = dirHandle;
|
||||||
|
|
||||||
|
return dirState;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_dirclose_r (struct _reent *r, DIR_ITER *dirState)
|
||||||
|
{
|
||||||
|
fs_dev_dir_entry_t *dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct;
|
||||||
|
if(!dirIter->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(dirIter->dev->pMutex);
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_CloseDir(dirIter->dev->fsaFd, dirIter->dirHandle);
|
||||||
|
|
||||||
|
OSUnlockMutex(dirIter->dev->pMutex);
|
||||||
|
|
||||||
|
if(result < 0)
|
||||||
|
{
|
||||||
|
r->_errno = result;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_dirreset_r (struct _reent *r, DIR_ITER *dirState)
|
||||||
|
{
|
||||||
|
fs_dev_dir_entry_t *dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct;
|
||||||
|
if(!dirIter->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(dirIter->dev->pMutex);
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_RewindDir(dirIter->dev->fsaFd, dirIter->dirHandle);
|
||||||
|
|
||||||
|
OSUnlockMutex(dirIter->dev->pMutex);
|
||||||
|
|
||||||
|
if(result < 0)
|
||||||
|
{
|
||||||
|
r->_errno = result;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *st)
|
||||||
|
{
|
||||||
|
fs_dev_dir_entry_t *dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct;
|
||||||
|
if(!dirIter->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(dirIter->dev->pMutex);
|
||||||
|
|
||||||
|
directoryEntry_s * dir_entry = malloc(sizeof(directoryEntry_s));
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_ReadDir(dirIter->dev->fsaFd, dirIter->dirHandle, dir_entry);
|
||||||
|
if(result < 0)
|
||||||
|
{
|
||||||
|
free(dir_entry);
|
||||||
|
r->_errno = result;
|
||||||
|
OSUnlockMutex(dirIter->dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the current entry
|
||||||
|
strcpy(filename, dir_entry->name);
|
||||||
|
|
||||||
|
if(st)
|
||||||
|
{
|
||||||
|
memset(st, 0, sizeof(struct stat));
|
||||||
|
st->st_mode = (dir_entry->stat.flag & 0x80000000) ? S_IFDIR : S_IFREG;
|
||||||
|
st->st_nlink = 1;
|
||||||
|
st->st_size = dir_entry->stat.size;
|
||||||
|
st->st_blocks = (dir_entry->stat.size + 511) >> 9;
|
||||||
|
st->st_dev = dir_entry->stat.id;
|
||||||
|
st->st_uid = dir_entry->stat.owner_id;
|
||||||
|
st->st_gid = dir_entry->stat.group_id;
|
||||||
|
st->st_ino = dir_entry->stat.id;
|
||||||
|
st->st_atime = dir_entry->stat.mtime;
|
||||||
|
st->st_ctime = dir_entry->stat.ctime;
|
||||||
|
st->st_mtime = dir_entry->stat.mtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(dir_entry);
|
||||||
|
OSUnlockMutex(dirIter->dev->pMutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NTFS device driver devoptab
|
||||||
|
static const devoptab_t devops_fs = {
|
||||||
|
NULL, /* Device name */
|
||||||
|
sizeof (fs_dev_file_state_t),
|
||||||
|
fs_dev_open_r,
|
||||||
|
fs_dev_close_r,
|
||||||
|
fs_dev_write_r,
|
||||||
|
fs_dev_read_r,
|
||||||
|
fs_dev_seek_r,
|
||||||
|
fs_dev_fstat_r,
|
||||||
|
fs_dev_stat_r,
|
||||||
|
fs_dev_link_r,
|
||||||
|
fs_dev_unlink_r,
|
||||||
|
fs_dev_chdir_r,
|
||||||
|
fs_dev_rename_r,
|
||||||
|
fs_dev_mkdir_r,
|
||||||
|
sizeof (fs_dev_dir_entry_t),
|
||||||
|
fs_dev_diropen_r,
|
||||||
|
fs_dev_dirreset_r,
|
||||||
|
fs_dev_dirnext_r,
|
||||||
|
fs_dev_dirclose_r,
|
||||||
|
fs_dev_statvfs_r,
|
||||||
|
fs_dev_ftruncate_r,
|
||||||
|
fs_dev_fsync_r,
|
||||||
|
fs_dev_chmod_r,
|
||||||
|
NULL, /* fs_dev_fchmod_r */
|
||||||
|
NULL /* Device data */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int fs_dev_add_device (const char *name, const char *mount_path, int fsaFd, int isMounted)
|
||||||
|
{
|
||||||
|
devoptab_t *dev = NULL;
|
||||||
|
char *devname = NULL;
|
||||||
|
char *devpath = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
if (!name) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a devoptab for this device
|
||||||
|
dev = (devoptab_t *) malloc(sizeof(devoptab_t) + strlen(name) + 1);
|
||||||
|
if (!dev) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the space allocated at the end of the devoptab for storing the device name
|
||||||
|
devname = (char*)(dev + 1);
|
||||||
|
strcpy(devname, name);
|
||||||
|
|
||||||
|
// create private data
|
||||||
|
fs_dev_private_t *priv = (fs_dev_private_t *)malloc(sizeof(fs_dev_private_t) + strlen(mount_path) + 1);
|
||||||
|
if(!priv) {
|
||||||
|
free(dev);
|
||||||
|
errno = ENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
devpath = (char*)(priv+1);
|
||||||
|
strcpy(devpath, mount_path);
|
||||||
|
|
||||||
|
// setup private data
|
||||||
|
priv->mount_path = devpath;
|
||||||
|
priv->fsaFd = fsaFd;
|
||||||
|
priv->mounted = isMounted;
|
||||||
|
priv->pMutex = malloc(OS_MUTEX_SIZE);
|
||||||
|
|
||||||
|
if(!priv->pMutex) {
|
||||||
|
free(dev);
|
||||||
|
free(priv);
|
||||||
|
errno = ENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSInitMutex(priv->pMutex);
|
||||||
|
|
||||||
|
// Setup the devoptab
|
||||||
|
memcpy(dev, &devops_fs, sizeof(devoptab_t));
|
||||||
|
dev->name = devname;
|
||||||
|
dev->deviceData = priv;
|
||||||
|
|
||||||
|
// Add the device to the devoptab table (if there is a free slot)
|
||||||
|
for (i = 3; i < STD_MAX; i++) {
|
||||||
|
if (devoptab_list[i] == devoptab_list[0]) {
|
||||||
|
devoptab_list[i] = dev;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// failure, free all memory
|
||||||
|
free(priv);
|
||||||
|
free(dev);
|
||||||
|
|
||||||
|
// If we reach here then there are no free slots in the devoptab table for this device
|
||||||
|
errno = EADDRNOTAVAIL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_remove_device (const char *path)
|
||||||
|
{
|
||||||
|
const devoptab_t *devoptab = NULL;
|
||||||
|
char name[128] = {0};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Get the device name from the path
|
||||||
|
strncpy(name, path, 127);
|
||||||
|
strtok(name, ":/");
|
||||||
|
|
||||||
|
// Find and remove the specified device from the devoptab table
|
||||||
|
// NOTE: We do this manually due to a 'bug' in RemoveDevice
|
||||||
|
// which ignores names with suffixes and causes names
|
||||||
|
// like "ntfs" and "ntfs1" to be seen as equals
|
||||||
|
for (i = 3; i < STD_MAX; i++) {
|
||||||
|
devoptab = devoptab_list[i];
|
||||||
|
if (devoptab && devoptab->name) {
|
||||||
|
if (strcmp(name, devoptab->name) == 0) {
|
||||||
|
devoptab_list[i] = devoptab_list[0];
|
||||||
|
|
||||||
|
if(devoptab->deviceData)
|
||||||
|
{
|
||||||
|
fs_dev_private_t *priv = (fs_dev_private_t *)devoptab->deviceData;
|
||||||
|
|
||||||
|
if(priv->mounted)
|
||||||
|
IOSUHAX_FSA_Unmount(priv->fsaFd, priv->mount_path, 2);
|
||||||
|
|
||||||
|
if(priv->pMutex)
|
||||||
|
free(priv->pMutex);
|
||||||
|
free(devoptab->deviceData);
|
||||||
|
}
|
||||||
|
|
||||||
|
free((devoptab_t*)devoptab);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mount_fs(const char *virt_name, int fsaFd, const char *dev_path, const char *mount_path)
|
||||||
|
{
|
||||||
|
int isMounted = 0;
|
||||||
|
|
||||||
|
if(dev_path)
|
||||||
|
{
|
||||||
|
isMounted = 1;
|
||||||
|
|
||||||
|
int res = IOSUHAX_FSA_Mount(fsaFd, dev_path, mount_path, 2, 0, 0);
|
||||||
|
if(res != 0)
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fs_dev_add_device(virt_name, mount_path, fsaFd, isMounted);
|
||||||
|
}
|
||||||
|
|
||||||
|
int unmount_fs(const char *virt_name)
|
||||||
|
{
|
||||||
|
return fs_dev_remove_device(virt_name);
|
||||||
|
}
|
42
deps/libiosuhax/iosuhax_devoptab.h
vendored
Normal file
42
deps/libiosuhax/iosuhax_devoptab.h
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2015
|
||||||
|
* by Dimok
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any
|
||||||
|
* damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any
|
||||||
|
* purpose, including commercial applications, and to alter it and
|
||||||
|
* redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you
|
||||||
|
* must not claim that you wrote the original software. If you use
|
||||||
|
* this software in a product, an acknowledgment in the product
|
||||||
|
* documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and
|
||||||
|
* must not be misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef __IOSUHAX_DEVOPTAB_H_
|
||||||
|
#define __IOSUHAX_DEVOPTAB_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! virtual name example: sd or odd (for sd:/ or odd:/ access)
|
||||||
|
//! fsaFd: fd received by IOSUHAX_FSA_Open();
|
||||||
|
//! dev_path: (optional) if a device should be mounted to the mount_path. If NULL no IOSUHAX_FSA_Mount is not executed.
|
||||||
|
//! mount_path: path to map to virtual device name
|
||||||
|
int mount_fs(const char *virt_name, int fsaFd, const char *dev_path, const char *mount_path);
|
||||||
|
int unmount_fs(const char *virt_name);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __IOSUHAX_DEVOPTAB_H_
|
262
deps/libiosuhax/iosuhax_disc_interface.c
vendored
Normal file
262
deps/libiosuhax/iosuhax_disc_interface.c
vendored
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2016
|
||||||
|
* by Dimok
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any
|
||||||
|
* damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any
|
||||||
|
* purpose, including commercial applications, and to alter it and
|
||||||
|
* redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you
|
||||||
|
* must not claim that you wrote the original software. If you use
|
||||||
|
* this software in a product, an acknowledgment in the product
|
||||||
|
* documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and
|
||||||
|
* must not be misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
***************************************************************************/
|
||||||
|
#include <string.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include "iosuhax.h"
|
||||||
|
#include "iosuhax_disc_interface.h"
|
||||||
|
|
||||||
|
#define FSA_REF_SD 0x01
|
||||||
|
#define FSA_REF_USB 0x02
|
||||||
|
|
||||||
|
static int initialized = 0;
|
||||||
|
|
||||||
|
static int fsaFdSd = 0;
|
||||||
|
static int fsaFdUsb = 0;
|
||||||
|
static int sdioFd = 0;
|
||||||
|
static int usbFd = 0;
|
||||||
|
|
||||||
|
static void IOSUHAX_disc_io_initialize(void)
|
||||||
|
{
|
||||||
|
if(initialized == 0)
|
||||||
|
{
|
||||||
|
initialized = 1;
|
||||||
|
fsaFdSd = -1;
|
||||||
|
fsaFdUsb = -1;
|
||||||
|
sdioFd = -1;
|
||||||
|
usbFd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IOSUHAX_disc_io_fsa_open(int fsaFd)
|
||||||
|
{
|
||||||
|
IOSUHAX_disc_io_initialize();
|
||||||
|
|
||||||
|
if(IOSUHAX_Open(NULL) < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(fsaFd == FSA_REF_SD)
|
||||||
|
{
|
||||||
|
if(fsaFdSd < 0)
|
||||||
|
{
|
||||||
|
fsaFdSd = IOSUHAX_FSA_Open();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fsaFdSd >= 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(fsaFd == FSA_REF_USB)
|
||||||
|
{
|
||||||
|
if(fsaFdUsb < 0)
|
||||||
|
{
|
||||||
|
fsaFdUsb = IOSUHAX_FSA_Open();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fsaFdUsb >= 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void IOSUHAX_disc_io_fsa_close(int fsaFd)
|
||||||
|
{
|
||||||
|
if(fsaFd == FSA_REF_SD)
|
||||||
|
{
|
||||||
|
if(fsaFdSd >= 0)
|
||||||
|
{
|
||||||
|
IOSUHAX_FSA_Close(fsaFdSd);
|
||||||
|
fsaFdSd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(fsaFd == FSA_REF_USB)
|
||||||
|
{
|
||||||
|
if(fsaFdUsb >= 0)
|
||||||
|
{
|
||||||
|
IOSUHAX_FSA_Close(fsaFdUsb);
|
||||||
|
fsaFdUsb = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IOSUHAX_sdio_startup(void)
|
||||||
|
{
|
||||||
|
if(!IOSUHAX_disc_io_fsa_open(FSA_REF_SD))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(sdioFd < 0)
|
||||||
|
{
|
||||||
|
int res = IOSUHAX_FSA_RawOpen(fsaFdSd, "/dev/sdcard01", &sdioFd);
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
IOSUHAX_disc_io_fsa_close(FSA_REF_SD);
|
||||||
|
sdioFd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (sdioFd >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IOSUHAX_sdio_isInserted(void)
|
||||||
|
{
|
||||||
|
//! TODO: check for SD card inserted with IOSUHAX_FSA_GetDeviceInfo()
|
||||||
|
return initialized && (fsaFdSd >= 0) && (sdioFd >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IOSUHAX_sdio_clearStatus(void)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IOSUHAX_sdio_shutdown(void)
|
||||||
|
{
|
||||||
|
if(!IOSUHAX_sdio_isInserted())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
IOSUHAX_FSA_RawClose(fsaFdSd, sdioFd);
|
||||||
|
IOSUHAX_disc_io_fsa_close(FSA_REF_SD);
|
||||||
|
sdioFd = -1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IOSUHAX_sdio_readSectors(uint32_t sector, uint32_t numSectors, void* buffer)
|
||||||
|
{
|
||||||
|
if(!IOSUHAX_sdio_isInserted())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int res = IOSUHAX_FSA_RawRead(fsaFdSd, buffer, 512, numSectors, sector, sdioFd);
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IOSUHAX_sdio_writeSectors(uint32_t sector, uint32_t numSectors, const void* buffer)
|
||||||
|
{
|
||||||
|
if(!IOSUHAX_sdio_isInserted())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int res = IOSUHAX_FSA_RawWrite(fsaFdSd, buffer, 512, numSectors, sector, sdioFd);
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DISC_INTERFACE IOSUHAX_sdio_disc_interface =
|
||||||
|
{
|
||||||
|
DEVICE_TYPE_WII_U_SD,
|
||||||
|
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_U_SD,
|
||||||
|
IOSUHAX_sdio_startup,
|
||||||
|
IOSUHAX_sdio_isInserted,
|
||||||
|
IOSUHAX_sdio_readSectors,
|
||||||
|
IOSUHAX_sdio_writeSectors,
|
||||||
|
IOSUHAX_sdio_clearStatus,
|
||||||
|
IOSUHAX_sdio_shutdown
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool IOSUHAX_usb_startup(void)
|
||||||
|
{
|
||||||
|
if(!IOSUHAX_disc_io_fsa_open(FSA_REF_USB))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(usbFd < 0)
|
||||||
|
{
|
||||||
|
int res = IOSUHAX_FSA_RawOpen(fsaFdUsb, "/dev/usb01", &usbFd);
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
res = IOSUHAX_FSA_RawOpen(fsaFdUsb, "/dev/usb02", &usbFd);
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
IOSUHAX_disc_io_fsa_close(FSA_REF_USB);
|
||||||
|
usbFd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (usbFd >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IOSUHAX_usb_isInserted(void)
|
||||||
|
{
|
||||||
|
return initialized && (fsaFdUsb >= 0) && (usbFd >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IOSUHAX_usb_clearStatus(void)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IOSUHAX_usb_shutdown(void)
|
||||||
|
{
|
||||||
|
if(!IOSUHAX_usb_isInserted())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
IOSUHAX_FSA_RawClose(fsaFdUsb, usbFd);
|
||||||
|
IOSUHAX_disc_io_fsa_close(FSA_REF_USB);
|
||||||
|
usbFd = -1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IOSUHAX_usb_readSectors(uint32_t sector, uint32_t numSectors, void* buffer)
|
||||||
|
{
|
||||||
|
if(!IOSUHAX_usb_isInserted())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int res = IOSUHAX_FSA_RawRead(fsaFdUsb, buffer, 512, numSectors, sector, usbFd);
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IOSUHAX_usb_writeSectors(uint32_t sector, uint32_t numSectors, const void* buffer)
|
||||||
|
{
|
||||||
|
if(!IOSUHAX_usb_isInserted())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int res = IOSUHAX_FSA_RawWrite(fsaFdUsb, buffer, 512, numSectors, sector, usbFd);
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DISC_INTERFACE IOSUHAX_usb_disc_interface =
|
||||||
|
{
|
||||||
|
DEVICE_TYPE_WII_U_USB,
|
||||||
|
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_U_USB,
|
||||||
|
IOSUHAX_usb_startup,
|
||||||
|
IOSUHAX_usb_isInserted,
|
||||||
|
IOSUHAX_usb_readSectors,
|
||||||
|
IOSUHAX_usb_writeSectors,
|
||||||
|
IOSUHAX_usb_clearStatus,
|
||||||
|
IOSUHAX_usb_shutdown
|
||||||
|
};
|
73
deps/libiosuhax/iosuhax_disc_interface.h
vendored
Normal file
73
deps/libiosuhax/iosuhax_disc_interface.h
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2016
|
||||||
|
* by Dimok
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any
|
||||||
|
* damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any
|
||||||
|
* purpose, including commercial applications, and to alter it and
|
||||||
|
* redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you
|
||||||
|
* must not claim that you wrote the original software. If you use
|
||||||
|
* this software in a product, an acknowledgment in the product
|
||||||
|
* documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and
|
||||||
|
* must not be misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef _IOSUHAX_DISC_INTERFACE_H_
|
||||||
|
#define _IOSUHAX_DISC_INTERFACE_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEVICE_TYPE_WII_U_SD (('W'<<24)|('U'<<16)|('S'<<8)|'D')
|
||||||
|
#define DEVICE_TYPE_WII_U_USB (('W'<<24)|('U'<<16)|('S'<<8)|'B')
|
||||||
|
#define FEATURE_WII_U_SD 0x00001000
|
||||||
|
#define FEATURE_WII_U_USB 0x00002000
|
||||||
|
|
||||||
|
#ifndef OGC_DISC_IO_INCLUDE
|
||||||
|
typedef uint32_t sec_t;
|
||||||
|
|
||||||
|
#define FEATURE_MEDIUM_CANREAD 0x00000001
|
||||||
|
#define FEATURE_MEDIUM_CANWRITE 0x00000002
|
||||||
|
|
||||||
|
typedef bool (* FN_MEDIUM_STARTUP)(void) ;
|
||||||
|
typedef bool (* FN_MEDIUM_ISINSERTED)(void) ;
|
||||||
|
typedef bool (* FN_MEDIUM_READSECTORS)(uint32_t sector, uint32_t numSectors, void* buffer) ;
|
||||||
|
typedef bool (* FN_MEDIUM_WRITESECTORS)(uint32_t sector, uint32_t numSectors, const void* buffer) ;
|
||||||
|
typedef bool (* FN_MEDIUM_CLEARSTATUS)(void) ;
|
||||||
|
typedef bool (* FN_MEDIUM_SHUTDOWN)(void) ;
|
||||||
|
|
||||||
|
struct DISC_INTERFACE_STRUCT {
|
||||||
|
unsigned long ioType ;
|
||||||
|
unsigned long features ;
|
||||||
|
FN_MEDIUM_STARTUP startup ;
|
||||||
|
FN_MEDIUM_ISINSERTED isInserted ;
|
||||||
|
FN_MEDIUM_READSECTORS readSectors ;
|
||||||
|
FN_MEDIUM_WRITESECTORS writeSectors ;
|
||||||
|
FN_MEDIUM_CLEARSTATUS clearStatus ;
|
||||||
|
FN_MEDIUM_SHUTDOWN shutdown ;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
typedef struct DISC_INTERFACE_STRUCT DISC_INTERFACE ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern const DISC_INTERFACE IOSUHAX_sdio_disc_interface;
|
||||||
|
extern const DISC_INTERFACE IOSUHAX_usb_disc_interface;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
44
deps/libiosuhax/os_functions.h
vendored
Normal file
44
deps/libiosuhax/os_functions.h
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#ifndef __OS_FUNCTIONS_H_
|
||||||
|
#define __OS_FUNCTIONS_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define OS_MUTEX_SIZE 44
|
||||||
|
|
||||||
|
#ifndef __WUT__
|
||||||
|
//!----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//! Mutex functions
|
||||||
|
//!----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
extern void (* OSInitMutex)(void* mutex);
|
||||||
|
extern void (* OSLockMutex)(void* mutex);
|
||||||
|
extern void (* OSUnlockMutex)(void* mutex);
|
||||||
|
|
||||||
|
//!----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//! IOS function
|
||||||
|
//!----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
extern int (*IOS_Ioctl)(int fd, unsigned int request, void *input_buffer,unsigned int input_buffer_len, void *output_buffer, unsigned int output_buffer_len);
|
||||||
|
extern int (*IOS_Open)(char *path, unsigned int mode);
|
||||||
|
extern int (*IOS_Close)(int fd);
|
||||||
|
#else
|
||||||
|
//!----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//! Mutex functions
|
||||||
|
//!----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
extern void OSInitMutex(void* mutex);
|
||||||
|
extern void OSLockMutex(void* mutex);
|
||||||
|
extern void OSUnlockMutex(void* mutex);
|
||||||
|
|
||||||
|
//!----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//! IOS function
|
||||||
|
//!----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
extern int IOS_Ioctl(int fd, unsigned int request, void *input_buffer,unsigned int input_buffer_len, void *output_buffer, unsigned int output_buffer_len);
|
||||||
|
extern int IOS_Open(char *path, unsigned int mode);
|
||||||
|
extern int IOS_Close(int fd);
|
||||||
|
#endif // __WUT__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __OS_FUNCTIONS_H_
|
476
deps/pthreads/ANNOUNCE
vendored
Normal file
476
deps/pthreads/ANNOUNCE
vendored
Normal file
@ -0,0 +1,476 @@
|
|||||||
|
PTHREADS-WIN32 RELEASE 2.8.0 (2006-12-22)
|
||||||
|
-----------------------------------------
|
||||||
|
Web Site: http://sources.redhat.com/pthreads-win32/
|
||||||
|
FTP Site: ftp://sources.redhat.com/pub/pthreads-win32
|
||||||
|
Maintainer: Ross Johnson <rpj@callisto.canberra.edu.au>
|
||||||
|
|
||||||
|
|
||||||
|
We are pleased to announce the availability of a new release of
|
||||||
|
Pthreads-win32, an Open Source Software implementation of the
|
||||||
|
Threads component of the POSIX 1003.1 2001 Standard for Microsoft's
|
||||||
|
Win32 environment. Some functions from other sections of POSIX
|
||||||
|
1003.1 2001 are also supported including semaphores and scheduling
|
||||||
|
functions.
|
||||||
|
|
||||||
|
Some common non-portable functions are also implemented for
|
||||||
|
additional compatibility, as are a few functions specific
|
||||||
|
to pthreads-win32 for easier integration with Win32 applications.
|
||||||
|
|
||||||
|
Pthreads-win32 is free software, distributed under the GNU Lesser
|
||||||
|
General Public License (LGPL).
|
||||||
|
|
||||||
|
|
||||||
|
Acknowledgements
|
||||||
|
----------------
|
||||||
|
This library is based originally on a Win32 pthreads
|
||||||
|
implementation contributed by John Bossom <John.Bossom@cognos.com>.
|
||||||
|
|
||||||
|
The implementation of Condition Variables uses algorithms developed
|
||||||
|
by Alexander Terekhov and Louis Thomas.
|
||||||
|
|
||||||
|
The implementation of POSIX mutexes has been improved by Thomas Pfaff
|
||||||
|
and later by Alexander Terekhov.
|
||||||
|
|
||||||
|
The implementation of Spinlocks and Barriers was contributed
|
||||||
|
by Ross Johnson.
|
||||||
|
|
||||||
|
The implementation of read/write locks was contributed by
|
||||||
|
Aurelio Medina and improved by Alexander Terekhov.
|
||||||
|
|
||||||
|
Many others have contributed significant time and effort to solve crutial
|
||||||
|
problems in order to make the library workable, robust and reliable.
|
||||||
|
|
||||||
|
Thanks to Xavier Leroy for granting permission to use and modify his
|
||||||
|
LinuxThreads manual pages.
|
||||||
|
|
||||||
|
Thanks to The Open Group for making the Single Unix Specification
|
||||||
|
publicly available - many of the manual pages included in the package
|
||||||
|
were extracted from it.
|
||||||
|
|
||||||
|
There is also a separate CONTRIBUTORS file. This file and others are
|
||||||
|
on the web site:
|
||||||
|
|
||||||
|
http://sources.redhat.com/pthreads-win32
|
||||||
|
|
||||||
|
As much as possible, the ChangeLog file acknowledges contributions to the
|
||||||
|
code base in more detail.
|
||||||
|
|
||||||
|
|
||||||
|
Changes since the last release
|
||||||
|
------------------------------
|
||||||
|
These are now documented in the NEWS file.
|
||||||
|
See the ChangeLog file also.
|
||||||
|
|
||||||
|
|
||||||
|
Known Bugs
|
||||||
|
----------
|
||||||
|
These are now documented in the BUGS file.
|
||||||
|
|
||||||
|
|
||||||
|
Level of standards conformance
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
The following POSIX 1003.1 2001 options are defined and set to 200112L:
|
||||||
|
|
||||||
|
_POSIX_THREADS
|
||||||
|
_POSIX_THREAD_SAFE_FUNCTIONS
|
||||||
|
_POSIX_THREAD_ATTR_STACKSIZE
|
||||||
|
_POSIX_THREAD_PRIORITY_SCHEDULING
|
||||||
|
_POSIX_SEMAPHORES
|
||||||
|
_POSIX_READER_WRITER_LOCKS
|
||||||
|
_POSIX_SPIN_LOCKS
|
||||||
|
_POSIX_BARRIERS
|
||||||
|
|
||||||
|
|
||||||
|
The following POSIX 1003.1 2001 options are defined and set to -1:
|
||||||
|
|
||||||
|
_POSIX_THREAD_ATTR_STACKADDR
|
||||||
|
_POSIX_THREAD_PRIO_INHERIT
|
||||||
|
_POSIX_THREAD_PRIO_PROTECT
|
||||||
|
_POSIX_THREAD_PROCESS_SHARED
|
||||||
|
|
||||||
|
|
||||||
|
The following POSIX 1003.1 2001 limits are defined and set:
|
||||||
|
|
||||||
|
_POSIX_THREAD_THREADS_MAX
|
||||||
|
_POSIX_SEM_VALUE_MAX
|
||||||
|
_POSIX_SEM_NSEMS_MAX
|
||||||
|
_POSIX_THREAD_KEYS_MAX
|
||||||
|
_POSIX_THREAD_DESTRUCTOR_ITERATIONS
|
||||||
|
PTHREAD_STACK_MIN
|
||||||
|
PTHREAD_THREADS_MAX
|
||||||
|
SEM_VALUE_MAX
|
||||||
|
SEM_NSEMS_MAX
|
||||||
|
PTHREAD_KEYS_MAX
|
||||||
|
PTHREAD_DESTRUCTOR_ITERATIONS
|
||||||
|
|
||||||
|
|
||||||
|
The following functions are implemented:
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
PThreads
|
||||||
|
---------------------------
|
||||||
|
pthread_attr_init
|
||||||
|
pthread_attr_destroy
|
||||||
|
pthread_attr_getdetachstate
|
||||||
|
pthread_attr_getstackaddr
|
||||||
|
pthread_attr_getstacksize
|
||||||
|
pthread_attr_setdetachstate
|
||||||
|
pthread_attr_setstackaddr
|
||||||
|
pthread_attr_setstacksize
|
||||||
|
|
||||||
|
pthread_create
|
||||||
|
pthread_detach
|
||||||
|
pthread_equal
|
||||||
|
pthread_exit
|
||||||
|
pthread_join
|
||||||
|
pthread_once
|
||||||
|
pthread_self
|
||||||
|
|
||||||
|
pthread_cancel
|
||||||
|
pthread_cleanup_pop
|
||||||
|
pthread_cleanup_push
|
||||||
|
pthread_setcancelstate
|
||||||
|
pthread_setcanceltype
|
||||||
|
pthread_testcancel
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
Thread Specific Data
|
||||||
|
---------------------------
|
||||||
|
pthread_key_create
|
||||||
|
pthread_key_delete
|
||||||
|
pthread_setspecific
|
||||||
|
pthread_getspecific
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
Mutexes
|
||||||
|
---------------------------
|
||||||
|
pthread_mutexattr_init
|
||||||
|
pthread_mutexattr_destroy
|
||||||
|
pthread_mutexattr_getpshared
|
||||||
|
pthread_mutexattr_setpshared
|
||||||
|
pthread_mutexattr_gettype
|
||||||
|
pthread_mutexattr_settype (types: PTHREAD_MUTEX_DEFAULT
|
||||||
|
PTHREAD_MUTEX_NORMAL
|
||||||
|
PTHREAD_MUTEX_ERRORCHECK
|
||||||
|
PTHREAD_MUTEX_RECURSIVE )
|
||||||
|
pthread_mutex_init
|
||||||
|
pthread_mutex_destroy
|
||||||
|
pthread_mutex_lock
|
||||||
|
pthread_mutex_trylock
|
||||||
|
pthread_mutex_timedlock
|
||||||
|
pthread_mutex_unlock
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
Condition Variables
|
||||||
|
---------------------------
|
||||||
|
pthread_condattr_init
|
||||||
|
pthread_condattr_destroy
|
||||||
|
pthread_condattr_getpshared
|
||||||
|
pthread_condattr_setpshared
|
||||||
|
|
||||||
|
pthread_cond_init
|
||||||
|
pthread_cond_destroy
|
||||||
|
pthread_cond_wait
|
||||||
|
pthread_cond_timedwait
|
||||||
|
pthread_cond_signal
|
||||||
|
pthread_cond_broadcast
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
Read/Write Locks
|
||||||
|
---------------------------
|
||||||
|
pthread_rwlock_init
|
||||||
|
pthread_rwlock_destroy
|
||||||
|
pthread_rwlock_tryrdlock
|
||||||
|
pthread_rwlock_trywrlock
|
||||||
|
pthread_rwlock_rdlock
|
||||||
|
pthread_rwlock_timedrdlock
|
||||||
|
pthread_rwlock_rwlock
|
||||||
|
pthread_rwlock_timedwrlock
|
||||||
|
pthread_rwlock_unlock
|
||||||
|
pthread_rwlockattr_init
|
||||||
|
pthread_rwlockattr_destroy
|
||||||
|
pthread_rwlockattr_getpshared
|
||||||
|
pthread_rwlockattr_setpshared
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
Spin Locks
|
||||||
|
---------------------------
|
||||||
|
pthread_spin_init
|
||||||
|
pthread_spin_destroy
|
||||||
|
pthread_spin_lock
|
||||||
|
pthread_spin_unlock
|
||||||
|
pthread_spin_trylock
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
Barriers
|
||||||
|
---------------------------
|
||||||
|
pthread_barrier_init
|
||||||
|
pthread_barrier_destroy
|
||||||
|
pthread_barrier_wait
|
||||||
|
pthread_barrierattr_init
|
||||||
|
pthread_barrierattr_destroy
|
||||||
|
pthread_barrierattr_getpshared
|
||||||
|
pthread_barrierattr_setpshared
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
Semaphores
|
||||||
|
---------------------------
|
||||||
|
sem_init
|
||||||
|
sem_destroy
|
||||||
|
sem_post
|
||||||
|
sem_wait
|
||||||
|
sem_trywait
|
||||||
|
sem_timedwait
|
||||||
|
sem_getvalue (# free if +ve, # of waiters if -ve)
|
||||||
|
sem_open (returns an error ENOSYS)
|
||||||
|
sem_close (returns an error ENOSYS)
|
||||||
|
sem_unlink (returns an error ENOSYS)
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
RealTime Scheduling
|
||||||
|
---------------------------
|
||||||
|
pthread_attr_getschedparam
|
||||||
|
pthread_attr_setschedparam
|
||||||
|
pthread_attr_getinheritsched
|
||||||
|
pthread_attr_setinheritsched
|
||||||
|
pthread_attr_getschedpolicy (only supports SCHED_OTHER)
|
||||||
|
pthread_attr_setschedpolicy (only supports SCHED_OTHER)
|
||||||
|
pthread_getschedparam
|
||||||
|
pthread_setschedparam
|
||||||
|
pthread_getconcurrency
|
||||||
|
pthread_setconcurrency
|
||||||
|
pthread_attr_getscope
|
||||||
|
pthread_attr_setscope (only supports PTHREAD_SCOPE_SYSTEM)
|
||||||
|
sched_get_priority_max
|
||||||
|
sched_get_priority_min
|
||||||
|
sched_rr_get_interval (returns an error ENOTSUP)
|
||||||
|
sched_setscheduler (only supports SCHED_OTHER)
|
||||||
|
sched_getscheduler (only supports SCHED_OTHER)
|
||||||
|
sched_yield
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
Signals
|
||||||
|
---------------------------
|
||||||
|
pthread_sigmask
|
||||||
|
pthread_kill (only supports zero sig value,
|
||||||
|
for thread validity checking)
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
Non-portable routines (see the README.NONPORTABLE file for usage)
|
||||||
|
---------------------------
|
||||||
|
pthread_getw32threadhandle_np
|
||||||
|
pthread_timechange_handler_np
|
||||||
|
pthread_delay_np
|
||||||
|
pthread_mutexattr_getkind_np
|
||||||
|
pthread_mutexattr_setkind_np (types: PTHREAD_MUTEX_FAST_NP,
|
||||||
|
PTHREAD_MUTEX_ERRORCHECK_NP,
|
||||||
|
PTHREAD_MUTEX_RECURSIVE_NP,
|
||||||
|
PTHREAD_MUTEX_ADAPTIVE_NP,
|
||||||
|
PTHREAD_MUTEX_TIMED_NP)
|
||||||
|
pthread_num_processors_np
|
||||||
|
pthread_win32_process_attach_np (Required when statically linking
|
||||||
|
the library)
|
||||||
|
pthread_win32_process_detach_np (Required when statically linking
|
||||||
|
the library)
|
||||||
|
pthread_win32_thread_attach_np (Required when statically linking
|
||||||
|
the library)
|
||||||
|
pthread_win32_thread_detach_np (Required when statically linking
|
||||||
|
the library)
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
Static Initializers
|
||||||
|
---------------------------
|
||||||
|
PTHREAD_ONCE_INIT
|
||||||
|
PTHREAD_MUTEX_INITIALIZER
|
||||||
|
PTHREAD_RECURSIVE_MUTEX_INITIALIZER
|
||||||
|
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
|
||||||
|
PTHREAD_ERRORCHECK_MUTEX_INITIALIZER
|
||||||
|
PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
|
||||||
|
PTHREAD_COND_INITIALIZER
|
||||||
|
PTHREAD_RWLOCK_INITIALIZER
|
||||||
|
PTHREAD_SPINLOCK_INITIALIZER
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
Thread-Safe C Runtime Library (macros)
|
||||||
|
---------------------------
|
||||||
|
strtok_r
|
||||||
|
asctime_r
|
||||||
|
ctime_r
|
||||||
|
gmtime_r
|
||||||
|
localtime_r
|
||||||
|
rand_r
|
||||||
|
|
||||||
|
|
||||||
|
The following functions are not implemented:
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
RealTime Scheduling
|
||||||
|
---------------------------
|
||||||
|
pthread_mutex_getprioceiling
|
||||||
|
pthread_mutex_setprioceiling
|
||||||
|
pthread_mutex_attr_getprioceiling
|
||||||
|
pthread_mutex_attr_getprotocol
|
||||||
|
pthread_mutex_attr_setprioceiling
|
||||||
|
pthread_mutex_attr_setprotocol
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
Fork Handlers
|
||||||
|
---------------------------
|
||||||
|
pthread_atfork
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
Stdio
|
||||||
|
---------------------------
|
||||||
|
flockfile
|
||||||
|
ftrylockfile
|
||||||
|
funlockfile
|
||||||
|
getc_unlocked
|
||||||
|
getchar_unlocked
|
||||||
|
putc_unlocked
|
||||||
|
putchar_unlocked
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
Thread-Safe C Runtime Library
|
||||||
|
---------------------------
|
||||||
|
readdir_r
|
||||||
|
getgrgid_r
|
||||||
|
getgrnam_r
|
||||||
|
getpwuid_r
|
||||||
|
getpwnam_r
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
Signals
|
||||||
|
---------------------------
|
||||||
|
sigtimedwait
|
||||||
|
sigwait
|
||||||
|
sigwaitinfo
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
General
|
||||||
|
---------------------------
|
||||||
|
sysconf
|
||||||
|
|
||||||
|
The library includes two non-API functions for creating cancellation
|
||||||
|
points in applications and libraries:
|
||||||
|
|
||||||
|
pthreadCancelableWait
|
||||||
|
pthreadCancelableTimedWait
|
||||||
|
|
||||||
|
|
||||||
|
Availability
|
||||||
|
------------
|
||||||
|
|
||||||
|
The prebuilt DLL, export libs (for both MSVC and Mingw32), and the header
|
||||||
|
files (pthread.h, semaphore.h, sched.h) are available along with the
|
||||||
|
complete source code.
|
||||||
|
|
||||||
|
The source code can be found at:
|
||||||
|
|
||||||
|
ftp://sources.redhat.com/pub/pthreads-win32
|
||||||
|
|
||||||
|
and as individual source code files at
|
||||||
|
|
||||||
|
ftp://sources.redhat.com/pub/pthreads-win32/source
|
||||||
|
|
||||||
|
The pre-built DLL, export libraries and include files can be found at:
|
||||||
|
|
||||||
|
ftp://sources.redhat.com/pub/pthreads-win32/dll-latest
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Mailing List
|
||||||
|
------------
|
||||||
|
|
||||||
|
There is a mailing list for discussing pthreads on Win32. To join,
|
||||||
|
send email to:
|
||||||
|
|
||||||
|
pthreads-win32-subscribe@sourceware.cygnus.com
|
||||||
|
|
||||||
|
|
||||||
|
Application Development Environments
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
See the README file for more information.
|
||||||
|
|
||||||
|
MSVC:
|
||||||
|
MSVC using SEH works. Distribute pthreadVSE.dll with your application.
|
||||||
|
MSVC using C++ EH works. Distribute pthreadVCE.dll with your application.
|
||||||
|
MSVC using C setjmp/longjmp works. Distribute pthreadVC.dll with your application.
|
||||||
|
|
||||||
|
|
||||||
|
Mingw32:
|
||||||
|
See the FAQ, Questions 6 and 10.
|
||||||
|
|
||||||
|
Mingw using C++ EH works. Distribute pthreadGCE.dll with your application.
|
||||||
|
Mingw using C setjmp/longjmp works. Distribute pthreadGC.dll with your application.
|
||||||
|
|
||||||
|
|
||||||
|
Cygwin: (http://sourceware.cygnus.com/cygwin/)
|
||||||
|
Developers using Cygwin will not need pthreads-win32 since it has POSIX threads
|
||||||
|
support. Refer to its documentation for details and extent.
|
||||||
|
|
||||||
|
|
||||||
|
UWIN:
|
||||||
|
UWIN is a complete Unix-like environment for Windows from AT&T. Pthreads-win32
|
||||||
|
doesn't currently support UWIN (and vice versa), but that may change in the
|
||||||
|
future.
|
||||||
|
|
||||||
|
Generally:
|
||||||
|
For convenience, the following pre-built files are available on the FTP site
|
||||||
|
(see Availability above):
|
||||||
|
|
||||||
|
pthread.h - for POSIX 1c threads
|
||||||
|
semaphore.h - for POSIX 1b semaphores
|
||||||
|
sched.h - for POSIX 1b scheduling
|
||||||
|
pthreadVCE.dll - built with MSVC++ compiler using C++ EH
|
||||||
|
pthreadVCE.lib
|
||||||
|
pthreadVC.dll - built with MSVC compiler using C setjmp/longjmp
|
||||||
|
pthreadVC.lib
|
||||||
|
pthreadVSE.dll - built with MSVC compiler using SEH
|
||||||
|
pthreadVSE.lib
|
||||||
|
pthreadGCE.dll - built with Mingw32 G++ 2.95.2-1
|
||||||
|
pthreadGC.dll - built with Mingw32 GCC 2.95.2-1 using setjmp/longjmp
|
||||||
|
libpthreadGCE.a - derived from pthreadGCE.dll
|
||||||
|
libpthreadGC.a - derived from pthreadGC.dll
|
||||||
|
gcc.dll - needed if distributing applications that use
|
||||||
|
pthreadGCE.dll (but see the FAQ Q 10 for the latest
|
||||||
|
related information)
|
||||||
|
|
||||||
|
These are the only files you need in order to build POSIX threads
|
||||||
|
applications for Win32 using either MSVC or Mingw32.
|
||||||
|
|
||||||
|
See the FAQ file in the source tree for additional information.
|
||||||
|
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
For the authoritative reference, see the online POSIX
|
||||||
|
standard reference at:
|
||||||
|
|
||||||
|
http://www.OpenGroup.org
|
||||||
|
|
||||||
|
For POSIX Thread API programming, several reference books are
|
||||||
|
available:
|
||||||
|
|
||||||
|
Programming with POSIX Threads
|
||||||
|
David R. Butenhof
|
||||||
|
Addison-Wesley (pub)
|
||||||
|
|
||||||
|
Pthreads Programming
|
||||||
|
By Bradford Nichols, Dick Buttlar & Jacqueline Proulx Farrell
|
||||||
|
O'Reilly (pub)
|
||||||
|
|
||||||
|
On the web: see the links at the bottom of the pthreads-win32 site:
|
||||||
|
|
||||||
|
http://sources.redhat.com/pthreads-win32/
|
||||||
|
|
||||||
|
Currently, there is no documentation included in the package apart
|
||||||
|
from the copious comments in the source code.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Enjoy!
|
||||||
|
|
||||||
|
Ross Johnson
|
129
deps/pthreads/CONTRIBUTORS.ptw32
vendored
Normal file
129
deps/pthreads/CONTRIBUTORS.ptw32
vendored
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
Contributors (in approximate order of appearance)
|
||||||
|
|
||||||
|
[See also the ChangeLog file where individuals are
|
||||||
|
attributed in log entries. Likewise in the FAQ file.]
|
||||||
|
|
||||||
|
Ben Elliston bje at cygnus dot com
|
||||||
|
Initiated the project;
|
||||||
|
setup the project infrastructure (CVS, web page, etc.);
|
||||||
|
early prototype routines.
|
||||||
|
Ross Johnson rpj at callisto dot canberra dot edu dot au
|
||||||
|
early prototype routines;
|
||||||
|
ongoing project coordination/maintenance;
|
||||||
|
implementation of spin locks and barriers;
|
||||||
|
various enhancements;
|
||||||
|
bug fixes;
|
||||||
|
documentation;
|
||||||
|
testsuite.
|
||||||
|
Robert Colquhoun rjc at trump dot net dot au
|
||||||
|
Early bug fixes.
|
||||||
|
John E. Bossom John dot Bossom at cognos dot com
|
||||||
|
Contributed substantial original working implementation;
|
||||||
|
bug fixes;
|
||||||
|
ongoing guidance and standards interpretation.
|
||||||
|
Anders Norlander anorland at hem2 dot passagen dot se
|
||||||
|
Early enhancements and runtime checking for supported
|
||||||
|
Win32 routines.
|
||||||
|
Tor Lillqvist tml at iki dot fi
|
||||||
|
General enhancements;
|
||||||
|
early bug fixes to condition variables.
|
||||||
|
Scott Lightner scott at curriculum dot com
|
||||||
|
Bug fix.
|
||||||
|
Kevin Ruland Kevin dot Ruland at anheuser-busch dot com
|
||||||
|
Various bug fixes.
|
||||||
|
Mike Russo miker at eai dot com
|
||||||
|
Bug fix.
|
||||||
|
Mark E. Armstrong avail at pacbell dot net
|
||||||
|
Bug fixes.
|
||||||
|
Lorin Hochstein lmh at xiphos dot ca
|
||||||
|
general bug fixes; bug fixes to condition variables.
|
||||||
|
Peter Slacik Peter dot Slacik at tatramed dot sk
|
||||||
|
Bug fixes.
|
||||||
|
Mumit Khan khan at xraylith dot wisc dot edu
|
||||||
|
Fixes to work with Mingw32.
|
||||||
|
Milan Gardian mg at tatramed dot sk
|
||||||
|
Bug fixes and reports/analyses of obscure problems.
|
||||||
|
Aurelio Medina aureliom at crt dot com
|
||||||
|
First implementation of read-write locks.
|
||||||
|
Graham Dumpleton Graham dot Dumpleton at ra dot pad dot otc dot telstra dot com dot au
|
||||||
|
Bug fix in condition variables.
|
||||||
|
Tristan Savatier tristan at mpegtv dot com
|
||||||
|
WinCE port.
|
||||||
|
Erik Hensema erik at hensema dot xs4all dot nl
|
||||||
|
Bug fixes.
|
||||||
|
Rich Peters rpeters at micro-magic dot com
|
||||||
|
Todd Owen towen at lucidcalm dot dropbear dot id dot au
|
||||||
|
Bug fixes to dll loading.
|
||||||
|
Jason Nye jnye at nbnet dot nb dot ca
|
||||||
|
Implementation of async cancelation.
|
||||||
|
Fred Forester fforest at eticomm dot net
|
||||||
|
Kevin D. Clark kclark at cabletron dot com
|
||||||
|
David Baggett dmb at itasoftware dot com
|
||||||
|
Bug fixes.
|
||||||
|
Paul Redondo paul at matchvision dot com
|
||||||
|
Scott McCaskill scott at 3dfx dot com
|
||||||
|
Bug fixes.
|
||||||
|
Jef Gearhart jgearhart at tpssys dot com
|
||||||
|
Bug fix.
|
||||||
|
Arthur Kantor akantor at bexusa dot com
|
||||||
|
Mutex enhancements.
|
||||||
|
Steven Reddie smr at essemer dot com dot au
|
||||||
|
Bug fix.
|
||||||
|
Alexander Terekhov TEREKHOV at de dot ibm dot com
|
||||||
|
Re-implemented and improved read-write locks;
|
||||||
|
(with Louis Thomas) re-implemented and improved
|
||||||
|
condition variables;
|
||||||
|
enhancements to semaphores;
|
||||||
|
enhancements to mutexes;
|
||||||
|
new mutex implementation in 'futex' style;
|
||||||
|
suggested a robust implementation of pthread_once
|
||||||
|
similar to that implemented by V.Kliathcko;
|
||||||
|
system clock change handling re CV timeouts;
|
||||||
|
bug fixes.
|
||||||
|
Thomas Pfaff tpfaff at gmx dot net
|
||||||
|
Changes to make C version usable with C++ applications;
|
||||||
|
re-implemented mutex routines to avoid Win32 mutexes
|
||||||
|
and TryEnterCriticalSection;
|
||||||
|
procedure to fix Mingw32 thread-safety issues.
|
||||||
|
Franco Bez franco dot bez at gmx dot de
|
||||||
|
procedure to fix Mingw32 thread-safety issues.
|
||||||
|
Louis Thomas lthomas at arbitrade dot com
|
||||||
|
(with Alexander Terekhov) re-implemented and improved
|
||||||
|
condition variables.
|
||||||
|
David Korn dgk at research dot att dot com
|
||||||
|
Ported to UWIN.
|
||||||
|
Phil Frisbie, Jr. phil at hawksoft dot com
|
||||||
|
Bug fix.
|
||||||
|
Ralf Brese Ralf dot Brese at pdb4 dot siemens dot de
|
||||||
|
Bug fix.
|
||||||
|
prionx at juno dot com prionx at juno dot com
|
||||||
|
Bug fixes.
|
||||||
|
Max Woodbury mtew at cds dot duke dot edu
|
||||||
|
POSIX versioning conditionals;
|
||||||
|
reduced namespace pollution;
|
||||||
|
idea to separate routines to reduce statically
|
||||||
|
linked image sizes.
|
||||||
|
Rob Fanner rfanner at stonethree dot com
|
||||||
|
Bug fix.
|
||||||
|
Michael Johnson michaelj at maine dot rr dot com
|
||||||
|
Bug fix.
|
||||||
|
Nicolas Barry boozai at yahoo dot com
|
||||||
|
Bug fixes.
|
||||||
|
Piet van Bruggen pietvb at newbridges dot nl
|
||||||
|
Bug fix.
|
||||||
|
Makoto Kato raven at oldskool dot jp
|
||||||
|
AMD64 port.
|
||||||
|
Panagiotis E. Hadjidoukas peh at hpclab dot ceid dot upatras dot gr
|
||||||
|
Contributed the QueueUserAPCEx package which
|
||||||
|
makes preemptive async cancelation possible.
|
||||||
|
Will Bryant will dot bryant at ecosm dot com
|
||||||
|
Borland compiler patch and makefile.
|
||||||
|
Anuj Goyal anuj dot goyal at gmail dot com
|
||||||
|
Port to Digital Mars compiler.
|
||||||
|
Gottlob Frege gottlobfrege at gmail dot com
|
||||||
|
re-implemented pthread_once (version 2)
|
||||||
|
(pthread_once cancellation added by rpj).
|
||||||
|
Vladimir Kliatchko vladimir at kliatchko dot com
|
||||||
|
reimplemented pthread_once with the same form
|
||||||
|
as described by A.Terekhov (later version 2);
|
||||||
|
implementation of MCS (Mellor-Crummey/Scott) locks.
|
150
deps/pthreads/COPYING
vendored
Normal file
150
deps/pthreads/COPYING
vendored
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
pthreads-win32 - a POSIX threads library for Microsoft Windows
|
||||||
|
|
||||||
|
|
||||||
|
This file is Copyrighted
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
This file is covered under the following Copyright:
|
||||||
|
|
||||||
|
Copyright (C) 2001,2006 Ross P. Johnson
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Pthreads-win32 is covered by the GNU Lesser General Public License
|
||||||
|
------------------------------------------------------------------
|
||||||
|
|
||||||
|
Pthreads-win32 is open software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public License
|
||||||
|
as published by the Free Software Foundation version 2.1 of the
|
||||||
|
License.
|
||||||
|
|
||||||
|
Pthreads-win32 is several binary link libraries, several modules,
|
||||||
|
associated interface definition files and scripts used to control
|
||||||
|
its compilation and installation.
|
||||||
|
|
||||||
|
Pthreads-win32 is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
A copy of the GNU Lesser General Public License is distributed with
|
||||||
|
pthreads-win32 under the filename:
|
||||||
|
|
||||||
|
COPYING.LIB
|
||||||
|
|
||||||
|
You should have received a copy of the version 2.1 GNU Lesser General
|
||||||
|
Public License with pthreads-win32; if not, write to:
|
||||||
|
|
||||||
|
Free Software Foundation, Inc.
|
||||||
|
59 Temple Place
|
||||||
|
Suite 330
|
||||||
|
Boston, MA 02111-1307
|
||||||
|
USA
|
||||||
|
|
||||||
|
The contact addresses for pthreads-win32 is as follows:
|
||||||
|
|
||||||
|
Web: http://sources.redhat.com/pthreads-win32
|
||||||
|
Email: Ross Johnson
|
||||||
|
Please use: Firstname.Lastname@homemail.com.au
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Pthreads-win32 copyrights and exception files
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
With the exception of the files listed below, Pthreads-win32
|
||||||
|
is covered under the following GNU Lesser General Public License
|
||||||
|
Copyrights:
|
||||||
|
|
||||||
|
Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
Copyright(C) 1998 John E. Bossom
|
||||||
|
Copyright(C) 1999,2006 Pthreads-win32 contributors
|
||||||
|
|
||||||
|
The current list of contributors is contained
|
||||||
|
in the file CONTRIBUTORS included with the source
|
||||||
|
code distribution. The current list of CONTRIBUTORS
|
||||||
|
can also be seen at the following WWW location:
|
||||||
|
http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
|
||||||
|
Contact Email: Ross Johnson
|
||||||
|
Please use: Firstname.Lastname@homemail.com.au
|
||||||
|
|
||||||
|
These files are not covered under one of the Copyrights listed above:
|
||||||
|
|
||||||
|
COPYING
|
||||||
|
COPYING.LIB
|
||||||
|
tests/rwlock7.c
|
||||||
|
|
||||||
|
This file, COPYING, is distributed under the Copyright found at the
|
||||||
|
top of this file. It is important to note that you may distribute
|
||||||
|
verbatim copies of this file but you may not modify this file.
|
||||||
|
|
||||||
|
The file COPYING.LIB, which contains a copy of the version 2.1
|
||||||
|
GNU Lesser General Public License, is itself copyrighted by the
|
||||||
|
Free Software Foundation, Inc. Please note that the Free Software
|
||||||
|
Foundation, Inc. does NOT have a copyright over Pthreads-win32,
|
||||||
|
only the COPYING.LIB that is supplied with pthreads-win32.
|
||||||
|
|
||||||
|
The file tests/rwlock7.c is derived from code written by
|
||||||
|
Dave Butenhof for his book 'Programming With POSIX(R) Threads'.
|
||||||
|
The original code was obtained by free download from his website
|
||||||
|
http://home.earthlink.net/~anneart/family/Threads/source.html
|
||||||
|
and did not contain a copyright or author notice. It is assumed to
|
||||||
|
be freely distributable.
|
||||||
|
|
||||||
|
In all cases one may use and distribute these exception files freely.
|
||||||
|
And because one may freely distribute the LGPL covered files, the
|
||||||
|
entire pthreads-win32 source may be freely used and distributed.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
General Copyleft and License info
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
For general information on Copylefts, see:
|
||||||
|
|
||||||
|
http://www.gnu.org/copyleft/
|
||||||
|
|
||||||
|
For information on GNU Lesser General Public Licenses, see:
|
||||||
|
|
||||||
|
http://www.gnu.org/copyleft/lesser.html
|
||||||
|
http://www.gnu.org/copyleft/lesser.txt
|
||||||
|
|
||||||
|
|
||||||
|
Why pthreads-win32 did not use the GNU General Public License
|
||||||
|
-------------------------------------------------------------
|
||||||
|
|
||||||
|
The goal of the pthreads-win32 project has been to
|
||||||
|
provide a quality and complete implementation of the POSIX
|
||||||
|
threads API for Microsoft Windows within the limits imposed
|
||||||
|
by virtue of it being a stand-alone library and not
|
||||||
|
linked directly to other POSIX compliant libraries. For
|
||||||
|
example, some functions and features, such as those based
|
||||||
|
on POSIX signals, are missing.
|
||||||
|
|
||||||
|
Pthreads-win32 is a library, available in several different
|
||||||
|
versions depending on supported compilers, and may be used
|
||||||
|
as a dynamically linked module or a statically linked set of
|
||||||
|
binary modules. It is not an application on it's own.
|
||||||
|
|
||||||
|
It was fully intended that pthreads-win32 be usable with
|
||||||
|
commercial software not covered by either the GPL or the LGPL
|
||||||
|
licenses. Pthreads-win32 has many contributors to it's
|
||||||
|
code base, many of whom have done so because they have
|
||||||
|
used the library in commercial or proprietry software
|
||||||
|
projects.
|
||||||
|
|
||||||
|
Releasing pthreads-win32 under the LGPL ensures that the
|
||||||
|
library can be used widely, while at the same time ensures
|
||||||
|
that bug fixes and improvements to the pthreads-win32 code
|
||||||
|
itself is returned to benefit all current and future users
|
||||||
|
of the library.
|
||||||
|
|
||||||
|
Although pthreads-win32 makes it possible for applications
|
||||||
|
that use POSIX threads to be ported to Win32 platforms, the
|
||||||
|
broader goal of the project is to encourage the use of open
|
||||||
|
standards, and in particular, to make it just a little easier
|
||||||
|
for developers writing Win32 applications to consider
|
||||||
|
widening the potential market for their products.
|
504
deps/pthreads/COPYING.LIB
vendored
Normal file
504
deps/pthreads/COPYING.LIB
vendored
Normal file
@ -0,0 +1,504 @@
|
|||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 2.1, February 1999
|
||||||
|
|
||||||
|
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||||
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
[This is the first released version of the Lesser GPL. It also counts
|
||||||
|
as the successor of the GNU Library Public License, version 2, hence
|
||||||
|
the version number 2.1.]
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
Licenses are intended to guarantee your freedom to share and change
|
||||||
|
free software--to make sure the software is free for all its users.
|
||||||
|
|
||||||
|
This license, the Lesser General Public License, applies to some
|
||||||
|
specially designated software packages--typically libraries--of the
|
||||||
|
Free Software Foundation and other authors who decide to use it. You
|
||||||
|
can use it too, but we suggest you first think carefully about whether
|
||||||
|
this license or the ordinary General Public License is the better
|
||||||
|
strategy to use in any particular case, based on the explanations below.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom of use,
|
||||||
|
not price. Our General Public Licenses are designed to make sure that
|
||||||
|
you have the freedom to distribute copies of free software (and charge
|
||||||
|
for this service if you wish); that you receive source code or can get
|
||||||
|
it if you want it; that you can change the software and use pieces of
|
||||||
|
it in new free programs; and that you are informed that you can do
|
||||||
|
these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
distributors to deny you these rights or to ask you to surrender these
|
||||||
|
rights. These restrictions translate to certain responsibilities for
|
||||||
|
you if you distribute copies of the library or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of the library, whether gratis
|
||||||
|
or for a fee, you must give the recipients all the rights that we gave
|
||||||
|
you. You must make sure that they, too, receive or can get the source
|
||||||
|
code. If you link other code with the library, you must provide
|
||||||
|
complete object files to the recipients, so that they can relink them
|
||||||
|
with the library after making changes to the library and recompiling
|
||||||
|
it. And you must show them these terms so they know their rights.
|
||||||
|
|
||||||
|
We protect your rights with a two-step method: (1) we copyright the
|
||||||
|
library, and (2) we offer you this license, which gives you legal
|
||||||
|
permission to copy, distribute and/or modify the library.
|
||||||
|
|
||||||
|
To protect each distributor, we want to make it very clear that
|
||||||
|
there is no warranty for the free library. Also, if the library is
|
||||||
|
modified by someone else and passed on, the recipients should know
|
||||||
|
that what they have is not the original version, so that the original
|
||||||
|
author's reputation will not be affected by problems that might be
|
||||||
|
introduced by others.
|
||||||
|
|
||||||
|
Finally, software patents pose a constant threat to the existence of
|
||||||
|
any free program. We wish to make sure that a company cannot
|
||||||
|
effectively restrict the users of a free program by obtaining a
|
||||||
|
restrictive license from a patent holder. Therefore, we insist that
|
||||||
|
any patent license obtained for a version of the library must be
|
||||||
|
consistent with the full freedom of use specified in this license.
|
||||||
|
|
||||||
|
Most GNU software, including some libraries, is covered by the
|
||||||
|
ordinary GNU General Public License. This license, the GNU Lesser
|
||||||
|
General Public License, applies to certain designated libraries, and
|
||||||
|
is quite different from the ordinary General Public License. We use
|
||||||
|
this license for certain libraries in order to permit linking those
|
||||||
|
libraries into non-free programs.
|
||||||
|
|
||||||
|
When a program is linked with a library, whether statically or using
|
||||||
|
a shared library, the combination of the two is legally speaking a
|
||||||
|
combined work, a derivative of the original library. The ordinary
|
||||||
|
General Public License therefore permits such linking only if the
|
||||||
|
entire combination fits its criteria of freedom. The Lesser General
|
||||||
|
Public License permits more lax criteria for linking other code with
|
||||||
|
the library.
|
||||||
|
|
||||||
|
We call this license the "Lesser" General Public License because it
|
||||||
|
does Less to protect the user's freedom than the ordinary General
|
||||||
|
Public License. It also provides other free software developers Less
|
||||||
|
of an advantage over competing non-free programs. These disadvantages
|
||||||
|
are the reason we use the ordinary General Public License for many
|
||||||
|
libraries. However, the Lesser license provides advantages in certain
|
||||||
|
special circumstances.
|
||||||
|
|
||||||
|
For example, on rare occasions, there may be a special need to
|
||||||
|
encourage the widest possible use of a certain library, so that it becomes
|
||||||
|
a de-facto standard. To achieve this, non-free programs must be
|
||||||
|
allowed to use the library. A more frequent case is that a free
|
||||||
|
library does the same job as widely used non-free libraries. In this
|
||||||
|
case, there is little to gain by limiting the free library to free
|
||||||
|
software only, so we use the Lesser General Public License.
|
||||||
|
|
||||||
|
In other cases, permission to use a particular library in non-free
|
||||||
|
programs enables a greater number of people to use a large body of
|
||||||
|
free software. For example, permission to use the GNU C Library in
|
||||||
|
non-free programs enables many more people to use the whole GNU
|
||||||
|
operating system, as well as its variant, the GNU/Linux operating
|
||||||
|
system.
|
||||||
|
|
||||||
|
Although the Lesser General Public License is Less protective of the
|
||||||
|
users' freedom, it does ensure that the user of a program that is
|
||||||
|
linked with the Library has the freedom and the wherewithal to run
|
||||||
|
that program using a modified version of the Library.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow. Pay close attention to the difference between a
|
||||||
|
"work based on the library" and a "work that uses the library". The
|
||||||
|
former contains code derived from the library, whereas the latter must
|
||||||
|
be combined with the library in order to run.
|
||||||
|
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License Agreement applies to any software library or other
|
||||||
|
program which contains a notice placed by the copyright holder or
|
||||||
|
other authorized party saying it may be distributed under the terms of
|
||||||
|
this Lesser General Public License (also called "this License").
|
||||||
|
Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
A "library" means a collection of software functions and/or data
|
||||||
|
prepared so as to be conveniently linked with application programs
|
||||||
|
(which use some of those functions and data) to form executables.
|
||||||
|
|
||||||
|
The "Library", below, refers to any such software library or work
|
||||||
|
which has been distributed under these terms. A "work based on the
|
||||||
|
Library" means either the Library or any derivative work under
|
||||||
|
copyright law: that is to say, a work containing the Library or a
|
||||||
|
portion of it, either verbatim or with modifications and/or translated
|
||||||
|
straightforwardly into another language. (Hereinafter, translation is
|
||||||
|
included without limitation in the term "modification".)
|
||||||
|
|
||||||
|
"Source code" for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For a library, complete source code means
|
||||||
|
all the source code for all modules it contains, plus any associated
|
||||||
|
interface definition files, plus the scripts used to control compilation
|
||||||
|
and installation of the library.
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running a program using the Library is not restricted, and output from
|
||||||
|
such a program is covered only if its contents constitute a work based
|
||||||
|
on the Library (independent of the use of the Library in a tool for
|
||||||
|
writing it). Whether that is true depends on what the Library does
|
||||||
|
and what the program that uses the Library does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Library's
|
||||||
|
complete source code as you receive it, in any medium, provided that
|
||||||
|
you conspicuously and appropriately publish on each copy an
|
||||||
|
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||||
|
all the notices that refer to this License and to the absence of any
|
||||||
|
warranty; and distribute a copy of this License along with the
|
||||||
|
Library.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy,
|
||||||
|
and you may at your option offer warranty protection in exchange for a
|
||||||
|
fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Library or any portion
|
||||||
|
of it, thus forming a work based on the Library, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The modified work must itself be a software library.
|
||||||
|
|
||||||
|
b) You must cause the files modified to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
c) You must cause the whole of the work to be licensed at no
|
||||||
|
charge to all third parties under the terms of this License.
|
||||||
|
|
||||||
|
d) If a facility in the modified Library refers to a function or a
|
||||||
|
table of data to be supplied by an application program that uses
|
||||||
|
the facility, other than as an argument passed when the facility
|
||||||
|
is invoked, then you must make a good faith effort to ensure that,
|
||||||
|
in the event an application does not supply such function or
|
||||||
|
table, the facility still operates, and performs whatever part of
|
||||||
|
its purpose remains meaningful.
|
||||||
|
|
||||||
|
(For example, a function in a library to compute square roots has
|
||||||
|
a purpose that is entirely well-defined independent of the
|
||||||
|
application. Therefore, Subsection 2d requires that any
|
||||||
|
application-supplied function or table used by this function must
|
||||||
|
be optional: if the application does not supply it, the square
|
||||||
|
root function must still compute square roots.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Library,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Library, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote
|
||||||
|
it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Library.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Library
|
||||||
|
with the Library (or with a work based on the Library) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||||
|
License instead of this License to a given copy of the Library. To do
|
||||||
|
this, you must alter all the notices that refer to this License, so
|
||||||
|
that they refer to the ordinary GNU General Public License, version 2,
|
||||||
|
instead of to this License. (If a newer version than version 2 of the
|
||||||
|
ordinary GNU General Public License has appeared, then you can specify
|
||||||
|
that version instead if you wish.) Do not make any other change in
|
||||||
|
these notices.
|
||||||
|
|
||||||
|
Once this change is made in a given copy, it is irreversible for
|
||||||
|
that copy, so the ordinary GNU General Public License applies to all
|
||||||
|
subsequent copies and derivative works made from that copy.
|
||||||
|
|
||||||
|
This option is useful when you wish to copy part of the code of
|
||||||
|
the Library into a program that is not a library.
|
||||||
|
|
||||||
|
4. You may copy and distribute the Library (or a portion or
|
||||||
|
derivative of it, under Section 2) in object code or executable form
|
||||||
|
under the terms of Sections 1 and 2 above provided that you accompany
|
||||||
|
it with the complete corresponding machine-readable source code, which
|
||||||
|
must be distributed under the terms of Sections 1 and 2 above on a
|
||||||
|
medium customarily used for software interchange.
|
||||||
|
|
||||||
|
If distribution of object code is made by offering access to copy
|
||||||
|
from a designated place, then offering equivalent access to copy the
|
||||||
|
source code from the same place satisfies the requirement to
|
||||||
|
distribute the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
5. A program that contains no derivative of any portion of the
|
||||||
|
Library, but is designed to work with the Library by being compiled or
|
||||||
|
linked with it, is called a "work that uses the Library". Such a
|
||||||
|
work, in isolation, is not a derivative work of the Library, and
|
||||||
|
therefore falls outside the scope of this License.
|
||||||
|
|
||||||
|
However, linking a "work that uses the Library" with the Library
|
||||||
|
creates an executable that is a derivative of the Library (because it
|
||||||
|
contains portions of the Library), rather than a "work that uses the
|
||||||
|
library". The executable is therefore covered by this License.
|
||||||
|
Section 6 states terms for distribution of such executables.
|
||||||
|
|
||||||
|
When a "work that uses the Library" uses material from a header file
|
||||||
|
that is part of the Library, the object code for the work may be a
|
||||||
|
derivative work of the Library even though the source code is not.
|
||||||
|
Whether this is true is especially significant if the work can be
|
||||||
|
linked without the Library, or if the work is itself a library. The
|
||||||
|
threshold for this to be true is not precisely defined by law.
|
||||||
|
|
||||||
|
If such an object file uses only numerical parameters, data
|
||||||
|
structure layouts and accessors, and small macros and small inline
|
||||||
|
functions (ten lines or less in length), then the use of the object
|
||||||
|
file is unrestricted, regardless of whether it is legally a derivative
|
||||||
|
work. (Executables containing this object code plus portions of the
|
||||||
|
Library will still fall under Section 6.)
|
||||||
|
|
||||||
|
Otherwise, if the work is a derivative of the Library, you may
|
||||||
|
distribute the object code for the work under the terms of Section 6.
|
||||||
|
Any executables containing that work also fall under Section 6,
|
||||||
|
whether or not they are linked directly with the Library itself.
|
||||||
|
|
||||||
|
6. As an exception to the Sections above, you may also combine or
|
||||||
|
link a "work that uses the Library" with the Library to produce a
|
||||||
|
work containing portions of the Library, and distribute that work
|
||||||
|
under terms of your choice, provided that the terms permit
|
||||||
|
modification of the work for the customer's own use and reverse
|
||||||
|
engineering for debugging such modifications.
|
||||||
|
|
||||||
|
You must give prominent notice with each copy of the work that the
|
||||||
|
Library is used in it and that the Library and its use are covered by
|
||||||
|
this License. You must supply a copy of this License. If the work
|
||||||
|
during execution displays copyright notices, you must include the
|
||||||
|
copyright notice for the Library among them, as well as a reference
|
||||||
|
directing the user to the copy of this License. Also, you must do one
|
||||||
|
of these things:
|
||||||
|
|
||||||
|
a) Accompany the work with the complete corresponding
|
||||||
|
machine-readable source code for the Library including whatever
|
||||||
|
changes were used in the work (which must be distributed under
|
||||||
|
Sections 1 and 2 above); and, if the work is an executable linked
|
||||||
|
with the Library, with the complete machine-readable "work that
|
||||||
|
uses the Library", as object code and/or source code, so that the
|
||||||
|
user can modify the Library and then relink to produce a modified
|
||||||
|
executable containing the modified Library. (It is understood
|
||||||
|
that the user who changes the contents of definitions files in the
|
||||||
|
Library will not necessarily be able to recompile the application
|
||||||
|
to use the modified definitions.)
|
||||||
|
|
||||||
|
b) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (1) uses at run time a
|
||||||
|
copy of the library already present on the user's computer system,
|
||||||
|
rather than copying library functions into the executable, and (2)
|
||||||
|
will operate properly with a modified version of the library, if
|
||||||
|
the user installs one, as long as the modified version is
|
||||||
|
interface-compatible with the version that the work was made with.
|
||||||
|
|
||||||
|
c) Accompany the work with a written offer, valid for at
|
||||||
|
least three years, to give the same user the materials
|
||||||
|
specified in Subsection 6a, above, for a charge no more
|
||||||
|
than the cost of performing this distribution.
|
||||||
|
|
||||||
|
d) If distribution of the work is made by offering access to copy
|
||||||
|
from a designated place, offer equivalent access to copy the above
|
||||||
|
specified materials from the same place.
|
||||||
|
|
||||||
|
e) Verify that the user has already received a copy of these
|
||||||
|
materials or that you have already sent this user a copy.
|
||||||
|
|
||||||
|
For an executable, the required form of the "work that uses the
|
||||||
|
Library" must include any data and utility programs needed for
|
||||||
|
reproducing the executable from it. However, as a special exception,
|
||||||
|
the materials to be distributed need not include anything that is
|
||||||
|
normally distributed (in either source or binary form) with the major
|
||||||
|
components (compiler, kernel, and so on) of the operating system on
|
||||||
|
which the executable runs, unless that component itself accompanies
|
||||||
|
the executable.
|
||||||
|
|
||||||
|
It may happen that this requirement contradicts the license
|
||||||
|
restrictions of other proprietary libraries that do not normally
|
||||||
|
accompany the operating system. Such a contradiction means you cannot
|
||||||
|
use both them and the Library together in an executable that you
|
||||||
|
distribute.
|
||||||
|
|
||||||
|
7. You may place library facilities that are a work based on the
|
||||||
|
Library side-by-side in a single library together with other library
|
||||||
|
facilities not covered by this License, and distribute such a combined
|
||||||
|
library, provided that the separate distribution of the work based on
|
||||||
|
the Library and of the other library facilities is otherwise
|
||||||
|
permitted, and provided that you do these two things:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work
|
||||||
|
based on the Library, uncombined with any other library
|
||||||
|
facilities. This must be distributed under the terms of the
|
||||||
|
Sections above.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library of the fact
|
||||||
|
that part of it is a work based on the Library, and explaining
|
||||||
|
where to find the accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
8. You may not copy, modify, sublicense, link with, or distribute
|
||||||
|
the Library except as expressly provided under this License. Any
|
||||||
|
attempt otherwise to copy, modify, sublicense, link with, or
|
||||||
|
distribute the Library is void, and will automatically terminate your
|
||||||
|
rights under this License. However, parties who have received copies,
|
||||||
|
or rights, from you under this License will not have their licenses
|
||||||
|
terminated so long as such parties remain in full compliance.
|
||||||
|
|
||||||
|
9. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Library or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Library (or any work based on the
|
||||||
|
Library), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Library or works based on it.
|
||||||
|
|
||||||
|
10. Each time you redistribute the Library (or any work based on the
|
||||||
|
Library), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute, link with or modify the Library
|
||||||
|
subject to these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties with
|
||||||
|
this License.
|
||||||
|
|
||||||
|
11. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Library at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Library by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Library.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under any
|
||||||
|
particular circumstance, the balance of the section is intended to apply,
|
||||||
|
and the section as a whole is intended to apply in other circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
12. If the distribution and/or use of the Library is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Library under this License may add
|
||||||
|
an explicit geographical distribution limitation excluding those countries,
|
||||||
|
so that distribution is permitted only in or among countries not thus
|
||||||
|
excluded. In such case, this License incorporates the limitation as if
|
||||||
|
written in the body of this License.
|
||||||
|
|
||||||
|
13. The Free Software Foundation may publish revised and/or new
|
||||||
|
versions of the Lesser General Public License from time to time.
|
||||||
|
Such new versions will be similar in spirit to the present version,
|
||||||
|
but may differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Library
|
||||||
|
specifies a version number of this License which applies to it and
|
||||||
|
"any later version", you have the option of following the terms and
|
||||||
|
conditions either of that version or of any later version published by
|
||||||
|
the Free Software Foundation. If the Library does not specify a
|
||||||
|
license version number, you may choose any version ever published by
|
||||||
|
the Free Software Foundation.
|
||||||
|
|
||||||
|
14. If you wish to incorporate parts of the Library into other free
|
||||||
|
programs whose distribution conditions are incompatible with these,
|
||||||
|
write to the author to ask for permission. For software which is
|
||||||
|
copyrighted by the Free Software Foundation, write to the Free
|
||||||
|
Software Foundation; we sometimes make exceptions for this. Our
|
||||||
|
decision will be guided by the two goals of preserving the free status
|
||||||
|
of all derivatives of our free software and of promoting the sharing
|
||||||
|
and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||||
|
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||||
|
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||||
|
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||||
|
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||||
|
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||||
|
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||||
|
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||||
|
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||||
|
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||||
|
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||||
|
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||||
|
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||||
|
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||||
|
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Libraries
|
||||||
|
|
||||||
|
If you develop a new library, and you want it to be of the greatest
|
||||||
|
possible use to the public, we recommend making it free software that
|
||||||
|
everyone can redistribute and change. You can do so by permitting
|
||||||
|
redistribution under these terms (or, alternatively, under the terms of the
|
||||||
|
ordinary General Public License).
|
||||||
|
|
||||||
|
To apply these terms, attach the following notices to the library. It is
|
||||||
|
safest to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least the
|
||||||
|
"copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<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
deps/pthreads/implement.h
vendored
Normal file
516
deps/pthreads/implement.h
vendored
Normal file
@ -0,0 +1,516 @@
|
|||||||
|
/*
|
||||||
|
* implement.h
|
||||||
|
*
|
||||||
|
* Definitions that don't need to be public.
|
||||||
|
*
|
||||||
|
* Keeps all the internals out of pthread.h
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _IMPLEMENT_H
|
||||||
|
#define _IMPLEMENT_H
|
||||||
|
|
||||||
|
#include "pte_osal.h"
|
||||||
|
|
||||||
|
/* use local include files during development */
|
||||||
|
#include "semaphore.h"
|
||||||
|
#include "sched.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* This enumeration represents the state of the thread;
|
||||||
|
* The thread is still "alive" if the numeric value of the
|
||||||
|
* state is greater or equal "PThreadStateRunning".
|
||||||
|
*/
|
||||||
|
PThreadStateInitial = 0, /* Thread not running */
|
||||||
|
PThreadStateRunning, /* Thread alive & kicking */
|
||||||
|
PThreadStateSuspended, /* Thread alive but suspended */
|
||||||
|
PThreadStateCancelPending, /* Thread alive but is */
|
||||||
|
/* has cancelation pending. */
|
||||||
|
PThreadStateCanceling, /* Thread alive but is */
|
||||||
|
/* in the process of terminating */
|
||||||
|
/* due to a cancellation request */
|
||||||
|
PThreadStateException, /* Thread alive but exiting */
|
||||||
|
/* due to an exception */
|
||||||
|
PThreadStateLast
|
||||||
|
}
|
||||||
|
PThreadState;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct pte_thread_t_ pte_thread_t;
|
||||||
|
|
||||||
|
struct pte_thread_t_
|
||||||
|
{
|
||||||
|
pte_osThreadHandle threadId; /* OS specific thread handle */
|
||||||
|
// pthread_t ptHandle; /* This thread's permanent pthread_t handle */
|
||||||
|
pte_thread_t * prevReuse; /* Links threads on reuse stack */
|
||||||
|
volatile PThreadState state;
|
||||||
|
void *exitStatus;
|
||||||
|
void *parms;
|
||||||
|
int ptErrno;
|
||||||
|
int detachState;
|
||||||
|
pthread_mutex_t threadLock; /* Used for serialised access to public thread state */
|
||||||
|
int sched_priority; /* As set, not as currently is */
|
||||||
|
pthread_mutex_t cancelLock; /* Used for async-cancel safety */
|
||||||
|
int cancelState;
|
||||||
|
int cancelType;
|
||||||
|
int cancelEvent;
|
||||||
|
jmp_buf start_mark;
|
||||||
|
int implicit:
|
||||||
|
1;
|
||||||
|
void *keys;
|
||||||
|
void *nextAssoc;
|
||||||
|
|
||||||
|
unsigned int x; /* Extra information - reuse count etc */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Special value to mark attribute objects as valid.
|
||||||
|
*/
|
||||||
|
#define PTE_ATTR_VALID ((unsigned long) 0xC4C0FFEE)
|
||||||
|
|
||||||
|
struct pthread_attr_t_
|
||||||
|
{
|
||||||
|
unsigned long valid;
|
||||||
|
void *stackaddr;
|
||||||
|
size_t stacksize;
|
||||||
|
int detachstate;
|
||||||
|
struct sched_param param;
|
||||||
|
int inheritsched;
|
||||||
|
int contentionscope;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ====================
|
||||||
|
* ====================
|
||||||
|
* Semaphores, Mutexes and Condition Variables
|
||||||
|
* ====================
|
||||||
|
* ====================
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct sem_t_
|
||||||
|
{
|
||||||
|
int value;
|
||||||
|
pthread_mutex_t lock;
|
||||||
|
pte_osSemaphoreHandle sem;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PTE_OBJECT_AUTO_INIT ((void *) -1)
|
||||||
|
#define PTE_OBJECT_INVALID 0
|
||||||
|
|
||||||
|
struct pthread_mutex_t_
|
||||||
|
{
|
||||||
|
pte_osSemaphoreHandle handle;
|
||||||
|
int lock_idx;
|
||||||
|
/* Provides exclusive access to mutex state
|
||||||
|
via the Interlocked* mechanism.
|
||||||
|
0: unlocked/free.
|
||||||
|
1: locked - no other waiters.
|
||||||
|
-1: locked - with possible other waiters.
|
||||||
|
*/
|
||||||
|
int recursive_count; /* Number of unlocks a thread needs to perform
|
||||||
|
before the lock is released (recursive
|
||||||
|
mutexes only). */
|
||||||
|
int kind; /* Mutex type. */
|
||||||
|
pthread_t ownerThread;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pthread_mutexattr_t_
|
||||||
|
{
|
||||||
|
int pshared;
|
||||||
|
int kind;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Possible values, other than PTE_OBJECT_INVALID,
|
||||||
|
* for the "interlock" element in a spinlock.
|
||||||
|
*
|
||||||
|
* In this implementation, when a spinlock is initialised,
|
||||||
|
* the number of cpus available to the process is checked.
|
||||||
|
* If there is only one cpu then "interlock" is set equal to
|
||||||
|
* PTE_SPIN_USE_MUTEX and u.mutex is a initialised mutex.
|
||||||
|
* If the number of cpus is greater than 1 then "interlock"
|
||||||
|
* is set equal to PTE_SPIN_UNLOCKED and the number is
|
||||||
|
* stored in u.cpus. This arrangement allows the spinlock
|
||||||
|
* routines to attempt an InterlockedCompareExchange on "interlock"
|
||||||
|
* immediately and, if that fails, to try the inferior mutex.
|
||||||
|
*
|
||||||
|
* "u.cpus" isn't used for anything yet, but could be used at
|
||||||
|
* some point to optimise spinlock behaviour.
|
||||||
|
*/
|
||||||
|
#define PTE_SPIN_UNLOCKED (1)
|
||||||
|
#define PTE_SPIN_LOCKED (2)
|
||||||
|
#define PTE_SPIN_USE_MUTEX (3)
|
||||||
|
|
||||||
|
struct pthread_spinlock_t_
|
||||||
|
{
|
||||||
|
int interlock; /* Locking element for multi-cpus. */
|
||||||
|
union
|
||||||
|
{
|
||||||
|
int cpus; /* No. of cpus if multi cpus, or */
|
||||||
|
pthread_mutex_t mutex; /* mutex if single cpu. */
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pthread_barrier_t_
|
||||||
|
{
|
||||||
|
unsigned int nCurrentBarrierHeight;
|
||||||
|
unsigned int nInitialBarrierHeight;
|
||||||
|
int iStep;
|
||||||
|
int pshared;
|
||||||
|
sem_t semBarrierBreeched[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pthread_barrierattr_t_
|
||||||
|
{
|
||||||
|
int pshared;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pthread_key_t_
|
||||||
|
{
|
||||||
|
unsigned key;
|
||||||
|
void (*destructor) (void *);
|
||||||
|
pthread_mutex_t keyLock;
|
||||||
|
void *threads;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct ThreadParms ThreadParms;
|
||||||
|
typedef struct ThreadKeyAssoc ThreadKeyAssoc;
|
||||||
|
|
||||||
|
struct ThreadParms
|
||||||
|
{
|
||||||
|
pthread_t tid;
|
||||||
|
void *(*start) (void *);
|
||||||
|
void *arg;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pthread_cond_t_
|
||||||
|
{
|
||||||
|
long nWaitersBlocked; /* Number of threads blocked */
|
||||||
|
long nWaitersGone; /* Number of threads timed out */
|
||||||
|
long nWaitersToUnblock; /* Number of threads to unblock */
|
||||||
|
sem_t semBlockQueue; /* Queue up threads waiting for the */
|
||||||
|
/* condition to become signalled */
|
||||||
|
sem_t semBlockLock; /* Semaphore that guards access to */
|
||||||
|
/* | waiters blocked count/block queue */
|
||||||
|
/* +-> Mandatory Sync.LEVEL-1 */
|
||||||
|
pthread_mutex_t mtxUnblockLock; /* Mutex that guards access to */
|
||||||
|
/* | waiters (to)unblock(ed) counts */
|
||||||
|
/* +-> Optional* Sync.LEVEL-2 */
|
||||||
|
pthread_cond_t next; /* Doubly linked list */
|
||||||
|
pthread_cond_t prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct pthread_condattr_t_
|
||||||
|
{
|
||||||
|
int pshared;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PTE_RWLOCK_MAGIC 0xfacade2
|
||||||
|
|
||||||
|
struct pthread_rwlock_t_
|
||||||
|
{
|
||||||
|
pthread_mutex_t mtxExclusiveAccess;
|
||||||
|
pthread_mutex_t mtxSharedAccessCompleted;
|
||||||
|
pthread_cond_t cndSharedAccessCompleted;
|
||||||
|
int nSharedAccessCount;
|
||||||
|
int nExclusiveAccessCount;
|
||||||
|
int nCompletedSharedAccessCount;
|
||||||
|
int nMagic;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pthread_rwlockattr_t_
|
||||||
|
{
|
||||||
|
int pshared;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MCS lock queue node - see pte_MCS_lock.c
|
||||||
|
*/
|
||||||
|
struct pte_mcs_node_t_
|
||||||
|
{
|
||||||
|
struct pte_mcs_node_t_ **lock; /* ptr to tail of queue */
|
||||||
|
struct pte_mcs_node_t_ *next; /* ptr to successor in queue */
|
||||||
|
unsigned int readyFlag; /* set after lock is released by
|
||||||
|
predecessor */
|
||||||
|
unsigned int nextFlag; /* set after 'next' ptr is set by
|
||||||
|
successor */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct pte_mcs_node_t_ pte_mcs_local_node_t;
|
||||||
|
typedef struct pte_mcs_node_t_ *pte_mcs_lock_t;
|
||||||
|
|
||||||
|
|
||||||
|
struct ThreadKeyAssoc
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Purpose:
|
||||||
|
* This structure creates an association between a thread and a key.
|
||||||
|
* It is used to implement the implicit invocation of a user defined
|
||||||
|
* destroy routine for thread specific data registered by a user upon
|
||||||
|
* exiting a thread.
|
||||||
|
*
|
||||||
|
* Graphically, the arrangement is as follows, where:
|
||||||
|
*
|
||||||
|
* K - Key with destructor
|
||||||
|
* (head of chain is key->threads)
|
||||||
|
* T - Thread that has called pthread_setspecific(Kn)
|
||||||
|
* (head of chain is thread->keys)
|
||||||
|
* A - Association. Each association is a node at the
|
||||||
|
* intersection of two doubly-linked lists.
|
||||||
|
*
|
||||||
|
* T1 T2 T3
|
||||||
|
* | | |
|
||||||
|
* | | |
|
||||||
|
* K1 -----+-----A-----A----->
|
||||||
|
* | | |
|
||||||
|
* | | |
|
||||||
|
* K2 -----A-----A-----+----->
|
||||||
|
* | | |
|
||||||
|
* | | |
|
||||||
|
* K3 -----A-----+-----A----->
|
||||||
|
* | | |
|
||||||
|
* | | |
|
||||||
|
* V V V
|
||||||
|
*
|
||||||
|
* Access to the association is guarded by two locks: the key's
|
||||||
|
* general lock (guarding the row) and the thread's general
|
||||||
|
* lock (guarding the column). This avoids the need for a
|
||||||
|
* dedicated lock for each association, which not only consumes
|
||||||
|
* more handles but requires that: before the lock handle can
|
||||||
|
* be released - both the key must be deleted and the thread
|
||||||
|
* must have called the destructor. The two-lock arrangement
|
||||||
|
* allows the resources to be freed as soon as either thread or
|
||||||
|
* key is concluded.
|
||||||
|
*
|
||||||
|
* To avoid deadlock: whenever both locks are required, the key
|
||||||
|
* and thread locks are always acquired in the order: key lock
|
||||||
|
* then thread lock. An exception to this exists when a thread
|
||||||
|
* calls the destructors, however this is done carefully to
|
||||||
|
* avoid deadlock.
|
||||||
|
*
|
||||||
|
* An association is created when a thread first calls
|
||||||
|
* pthread_setspecific() on a key that has a specified
|
||||||
|
* destructor.
|
||||||
|
*
|
||||||
|
* An association is destroyed either immediately after the
|
||||||
|
* thread calls the key destructor function on thread exit, or
|
||||||
|
* when the key is deleted.
|
||||||
|
*
|
||||||
|
* Attributes:
|
||||||
|
* thread
|
||||||
|
* reference to the thread that owns the
|
||||||
|
* association. This is actually the pointer to the
|
||||||
|
* thread struct itself. Since the association is
|
||||||
|
* destroyed before the thread exits, this can never
|
||||||
|
* point to a different logical thread to the one that
|
||||||
|
* created the assoc, i.e. after thread struct reuse.
|
||||||
|
*
|
||||||
|
* key
|
||||||
|
* reference to the key that owns the association.
|
||||||
|
*
|
||||||
|
* nextKey
|
||||||
|
* The pthread_t->keys attribute is the head of a
|
||||||
|
* chain of associations that runs through the nextKey
|
||||||
|
* link. This chain provides the 1 to many relationship
|
||||||
|
* between a pthread_t and all pthread_key_t on which
|
||||||
|
* it called pthread_setspecific.
|
||||||
|
*
|
||||||
|
* prevKey
|
||||||
|
* Similarly.
|
||||||
|
*
|
||||||
|
* nextThread
|
||||||
|
* The pthread_key_t->threads attribute is the head of
|
||||||
|
* a chain of assoctiations that runs through the
|
||||||
|
* nextThreads link. This chain provides the 1 to many
|
||||||
|
* relationship between a pthread_key_t and all the
|
||||||
|
* PThreads that have called pthread_setspecific for
|
||||||
|
* this pthread_key_t.
|
||||||
|
*
|
||||||
|
* prevThread
|
||||||
|
* Similarly.
|
||||||
|
*
|
||||||
|
* Notes:
|
||||||
|
* 1) As soon as either the key or the thread is no longer
|
||||||
|
* referencing the association, it can be destroyed. The
|
||||||
|
* association will be removed from both chains.
|
||||||
|
*
|
||||||
|
* 2) An association is only created by
|
||||||
|
* pthread_setspecific if the user provided a
|
||||||
|
* destroyRoutine when they created the key.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
pte_thread_t * thread;
|
||||||
|
pthread_key_t key;
|
||||||
|
ThreadKeyAssoc *nextKey;
|
||||||
|
ThreadKeyAssoc *nextThread;
|
||||||
|
ThreadKeyAssoc *prevKey;
|
||||||
|
ThreadKeyAssoc *prevThread;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Services available through EXCEPTION_PTE_SERVICES
|
||||||
|
* and also used [as parameters to pte_throw()] as
|
||||||
|
* generic exception selectors.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PTE_EPS_EXIT (1)
|
||||||
|
#define PTE_EPS_CANCEL (2)
|
||||||
|
|
||||||
|
|
||||||
|
/* Useful macros */
|
||||||
|
#define PTE_MAX(a,b) ((a)<(b)?(b):(a))
|
||||||
|
#define PTE_MIN(a,b) ((a)>(b)?(b):(a))
|
||||||
|
|
||||||
|
|
||||||
|
/* Thread Reuse stack bottom marker. Must not be NULL or any valid pointer to memory. */
|
||||||
|
#define PTE_THREAD_REUSE_EMPTY ((pte_thread_t *) 1)
|
||||||
|
|
||||||
|
extern int pte_processInitialized;
|
||||||
|
extern pte_thread_t * pte_threadReuseTop;
|
||||||
|
extern pte_thread_t * pte_threadReuseBottom;
|
||||||
|
extern pthread_key_t pte_selfThreadKey;
|
||||||
|
extern pthread_key_t pte_cleanupKey;
|
||||||
|
extern pthread_cond_t pte_cond_list_head;
|
||||||
|
extern pthread_cond_t pte_cond_list_tail;
|
||||||
|
|
||||||
|
extern int pte_mutex_default_kind;
|
||||||
|
|
||||||
|
extern int pte_concurrency;
|
||||||
|
|
||||||
|
extern int pte_features;
|
||||||
|
|
||||||
|
extern pte_osMutexHandle pte_thread_reuse_lock;
|
||||||
|
extern pte_osMutexHandle pte_mutex_test_init_lock;
|
||||||
|
extern pte_osMutexHandle pte_cond_list_lock;
|
||||||
|
extern pte_osMutexHandle pte_cond_test_init_lock;
|
||||||
|
extern pte_osMutexHandle pte_rwlock_test_init_lock;
|
||||||
|
extern pte_osMutexHandle pte_spinlock_test_init_lock;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* =====================
|
||||||
|
* =====================
|
||||||
|
* Forward Declarations
|
||||||
|
* =====================
|
||||||
|
* =====================
|
||||||
|
*/
|
||||||
|
|
||||||
|
int pte_is_attr (const pthread_attr_t * attr);
|
||||||
|
|
||||||
|
int pte_cond_check_need_init (pthread_cond_t * cond);
|
||||||
|
int pte_mutex_check_need_init (pthread_mutex_t * mutex);
|
||||||
|
int pte_rwlock_check_need_init (pthread_rwlock_t * rwlock);
|
||||||
|
int pte_spinlock_check_need_init (pthread_spinlock_t * lock);
|
||||||
|
|
||||||
|
int pte_processInitialize (void);
|
||||||
|
|
||||||
|
void pte_processTerminate (void);
|
||||||
|
|
||||||
|
void pte_threadDestroy (pthread_t tid);
|
||||||
|
void pte_threadExitAndDestroy (pthread_t tid);
|
||||||
|
|
||||||
|
void pte_pop_cleanup_all (int execute);
|
||||||
|
|
||||||
|
pthread_t pte_new (void);
|
||||||
|
|
||||||
|
pthread_t pte_threadReusePop (void);
|
||||||
|
|
||||||
|
void pte_threadReusePush (pthread_t thread);
|
||||||
|
|
||||||
|
int pte_getprocessors (int *count);
|
||||||
|
|
||||||
|
int pte_setthreadpriority (pthread_t thread, int policy, int priority);
|
||||||
|
|
||||||
|
void pte_rwlock_cancelwrwait (void *arg);
|
||||||
|
|
||||||
|
int pte_threadStart (void *vthreadParms);
|
||||||
|
|
||||||
|
void pte_callUserDestroyRoutines (pthread_t thread);
|
||||||
|
|
||||||
|
int pte_tkAssocCreate (pte_thread_t * thread, pthread_key_t key);
|
||||||
|
|
||||||
|
void pte_tkAssocDestroy (ThreadKeyAssoc * assoc);
|
||||||
|
|
||||||
|
int sem_wait_nocancel (sem_t * sem);
|
||||||
|
|
||||||
|
unsigned int pte_relmillisecs (const struct timespec * abstime);
|
||||||
|
|
||||||
|
void pte_mcs_lock_acquire (pte_mcs_lock_t * lock, pte_mcs_local_node_t * node);
|
||||||
|
|
||||||
|
void pte_mcs_lock_release (pte_mcs_local_node_t * node);
|
||||||
|
|
||||||
|
/* Declared in private.c */
|
||||||
|
void pte_throw (unsigned int exception);
|
||||||
|
|
||||||
|
int pte_cancellable_wait (pte_osSemaphoreHandle semHandle, unsigned int* timeout);
|
||||||
|
|
||||||
|
#define PTE_ATOMIC_EXCHANGE pte_osAtomicExchange
|
||||||
|
#define PTE_ATOMIC_EXCHANGE_ADD pte_osAtomicExchangeAdd
|
||||||
|
#define PTE_ATOMIC_COMPARE_EXCHANGE pte_osAtomicCompareExchange
|
||||||
|
#define PTE_ATOMIC_DECREMENT pte_osAtomicDecrement
|
||||||
|
#define PTE_ATOMIC_INCREMENT pte_osAtomicIncrement
|
||||||
|
|
||||||
|
int pte_thread_detach_np();
|
||||||
|
int pte_thread_detach_and_exit_np();
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _IMPLEMENT_H */
|
90
deps/pthreads/need_errno.h
vendored
Normal file
90
deps/pthreads/need_errno.h
vendored
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/***
|
||||||
|
* errno.h - system wide error numbers (set by system calls)
|
||||||
|
*
|
||||||
|
* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* Purpose:
|
||||||
|
* This file defines the system-wide error numbers (set by
|
||||||
|
* system calls). Conforms to the XENIX standard. Extended
|
||||||
|
* for compatibility with Uniforum standard.
|
||||||
|
* [System V]
|
||||||
|
*
|
||||||
|
* [Public]
|
||||||
|
*
|
||||||
|
****/
|
||||||
|
|
||||||
|
#ifndef _INC_ERRNO
|
||||||
|
#define _INC_ERRNO
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* declare reference to errno */
|
||||||
|
|
||||||
|
extern int errno;
|
||||||
|
|
||||||
|
/* Error Codes */
|
||||||
|
|
||||||
|
#define EPERM 1
|
||||||
|
#define ENOENT 2
|
||||||
|
#define ESRCH 3
|
||||||
|
#define EINTR 4
|
||||||
|
#define EIO 5
|
||||||
|
#define ENXIO 6
|
||||||
|
#define E2BIG 7
|
||||||
|
#define ENOEXEC 8
|
||||||
|
#define EBADF 9
|
||||||
|
#define ECHILD 10
|
||||||
|
#define EAGAIN 11
|
||||||
|
#define ENOMEM 12
|
||||||
|
#define EACCES 13
|
||||||
|
#define EFAULT 14
|
||||||
|
#define EBUSY 16
|
||||||
|
#define EEXIST 17
|
||||||
|
#define EXDEV 18
|
||||||
|
#define ENODEV 19
|
||||||
|
#define ENOTDIR 20
|
||||||
|
#define EISDIR 21
|
||||||
|
#define EINVAL 22
|
||||||
|
#define ENFILE 23
|
||||||
|
#define EMFILE 24
|
||||||
|
#define ENOTTY 25
|
||||||
|
#define EFBIG 27
|
||||||
|
#define ENOSPC 28
|
||||||
|
#define ESPIPE 29
|
||||||
|
#define EROFS 30
|
||||||
|
#define EMLINK 31
|
||||||
|
#define EPIPE 32
|
||||||
|
#define EDOM 33
|
||||||
|
#define ERANGE 34
|
||||||
|
#define EDEADLK 36
|
||||||
|
|
||||||
|
/* defined differently in winsock.h on WinCE */
|
||||||
|
#ifndef ENAMETOOLONG
|
||||||
|
#define ENAMETOOLONG 38
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ENOLCK 39
|
||||||
|
#define ENOSYS 40
|
||||||
|
|
||||||
|
/* defined differently in winsock.h on WinCE */
|
||||||
|
#ifndef ENOTEMPTY
|
||||||
|
#define ENOTEMPTY 41
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define EILSEQ 42
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Support EDEADLOCK for compatibiity with older MS-C versions.
|
||||||
|
*/
|
||||||
|
#define EDEADLOCK EDEADLK
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _INC_ERRNO */
|
163
deps/pthreads/platform/helper/tls-helper.c
vendored
Normal file
163
deps/pthreads/platform/helper/tls-helper.c
vendored
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* tls-helper.c
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <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
deps/pthreads/platform/helper/tls-helper.h
vendored
Normal file
47
deps/pthreads/platform/helper/tls-helper.h
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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
deps/pthreads/platform/psp/Makefile
vendored
Normal file
51
deps/pthreads/platform/psp/Makefile
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
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."
|
||||||
|
|
845
deps/pthreads/platform/psp/psp_osal.c
vendored
Normal file
845
deps/pthreads/platform/psp/psp_osal.c
vendored
Normal file
@ -0,0 +1,845 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Nothing found and not timed out yet; let's yield so we're not
|
||||||
|
* in busy loop.
|
||||||
|
*/
|
||||||
|
sceKernelDelayThread(POLLING_DELAY_IN_us);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = PTE_OS_GENERAL_FAILURE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* Atomic Operations
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
int pte_osAtomicExchange(int *ptarg, int val)
|
||||||
|
{
|
||||||
|
int intc = pspSdkDisableInterrupts();
|
||||||
|
int origVal = *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
deps/pthreads/platform/psp/psp_osal.h
vendored
Normal file
63
deps/pthreads/platform/psp/psp_osal.h
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* 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
deps/pthreads/platform/psp/pte_osal.h
vendored
Normal file
9
deps/pthreads/platform/psp/pte_osal.h
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#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
deps/pthreads/platform/psp/pte_types.h
vendored
Normal file
12
deps/pthreads/platform/psp/pte_types.h
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/* 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
deps/pthreads/platform/psp/pthread_main.c
vendored
Normal file
64
deps/pthreads/platform/psp/pthread_main.c
vendored
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#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;
|
||||||
|
}
|
1116
deps/pthreads/pte.c
vendored
Normal file
1116
deps/pthreads/pte.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
449
deps/pthreads/pte_generic_osal.h
vendored
Normal file
449
deps/pthreads/pte_generic_osal.h
vendored
Normal file
@ -0,0 +1,449 @@
|
|||||||
|
/*
|
||||||
|
* pte_cancellable_wait.c
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _GENERIC_OS_SUPPORT_H_
|
||||||
|
#define _GENERIC_OS_SUPPORT_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
/** @name Misc */
|
||||||
|
//@{
|
||||||
|
typedef enum pte_osResult
|
||||||
|
{
|
||||||
|
|
||||||
|
/** Operation completed successfully */
|
||||||
|
PTE_OS_OK = 0,
|
||||||
|
|
||||||
|
/** Operation failed because there insufficient resources */
|
||||||
|
PTE_OS_NO_RESOURCES,
|
||||||
|
|
||||||
|
/** Operation failed due to a general failure */
|
||||||
|
PTE_OS_GENERAL_FAILURE,
|
||||||
|
|
||||||
|
/** Operation did not complete because a user specified timeout expired. */
|
||||||
|
PTE_OS_TIMEOUT,
|
||||||
|
|
||||||
|
/** The operation was interrupted before it could complete. */
|
||||||
|
PTE_OS_INTERRUPTED,
|
||||||
|
|
||||||
|
/** An invalid parameter was specified */
|
||||||
|
PTE_OS_INVALID_PARAM
|
||||||
|
|
||||||
|
|
||||||
|
} pte_osResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a hook for the OSAL to implement any OS specific initialization. This is guaranteed to be
|
||||||
|
* called before any other OSAL function.
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osInit(void);
|
||||||
|
//@}
|
||||||
|
|
||||||
|
/** @name Mutexes */
|
||||||
|
//@{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a mutex
|
||||||
|
*
|
||||||
|
* @param pHandle Set to the handle of the newly created mutex.
|
||||||
|
*
|
||||||
|
* @return PTE_OS_OK - Mutex successfully created
|
||||||
|
* @return PTE_OS_NO_RESOURCESs - Insufficient resources to create mutex
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osMutexCreate(pte_osMutexHandle *pHandle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a mutex and frees any associated resources.
|
||||||
|
*
|
||||||
|
* @param handle Handle of mutex to delete.
|
||||||
|
*
|
||||||
|
* @return PTE_OS_OK - Mutex successfully deleted.
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osMutexDelete(pte_osMutexHandle handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locks the mutex
|
||||||
|
*
|
||||||
|
* @param handle Handle of mutex to lock.
|
||||||
|
*
|
||||||
|
* @return PTE_OS_OK - Mutex successfully locked.
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osMutexLock(pte_osMutexHandle handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locks the mutex, returning after @p timeoutMsecs if the resources is not
|
||||||
|
* available. Can be used for polling mutex by using @p timeoutMsecs of zero.
|
||||||
|
*
|
||||||
|
* @param handle Handle of mutex to lock.
|
||||||
|
* @param timeoutMsecs Number of milliseconds to wait for resource before returning.
|
||||||
|
*
|
||||||
|
* @return PTE_OS_OK - Mutex successfully locked.
|
||||||
|
* @return PTE_OS_TIMEOUT - Timeout expired before lock was obtained.
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osMutexTimedLock(pte_osMutexHandle handle, unsigned int timeoutMsecs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlocks the mutex
|
||||||
|
*
|
||||||
|
* @param handle Handle of mutex to unlock
|
||||||
|
*
|
||||||
|
* @return PTE_OS_OK - Mutex successfully unlocked.
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osMutexUnlock(pte_osMutexHandle handle);
|
||||||
|
//@}
|
||||||
|
|
||||||
|
/** @name Threads */
|
||||||
|
//@{
|
||||||
|
typedef int (*pte_osThreadEntryPoint)(void *params);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new thread. The thread must be started in a suspended state - it will be
|
||||||
|
* explicitly started when pte_osThreadStart() is called.
|
||||||
|
*
|
||||||
|
* @param entryPoint Entry point to the new thread.
|
||||||
|
* @param stackSize The initial stack size, in bytes. Note that this can be considered a minimum -
|
||||||
|
* for instance if the OS requires a larger stack space than what the caller specified.
|
||||||
|
* @param initialPriority The priority that the new thread should be initially set to.
|
||||||
|
* @param argv Parameter to pass to the new thread.
|
||||||
|
* @param ppte_osThreadHandle set to the handle of the new thread.
|
||||||
|
*
|
||||||
|
* @return PTE_OS_OK - New thread successfully created.
|
||||||
|
* @return PTE_OS_NO_RESOURCESs - Insufficient resources to create thread
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osThreadCreate(pte_osThreadEntryPoint entryPoint,
|
||||||
|
int stackSize,
|
||||||
|
int initialPriority,
|
||||||
|
void *argv,
|
||||||
|
pte_osThreadHandle* ppte_osThreadHandle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts executing the specified thread.
|
||||||
|
*
|
||||||
|
* @param osThreadHandle handle of the thread to start.
|
||||||
|
*
|
||||||
|
* @return PTE_OS_OK - thread successfully started.
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osThreadStart(pte_osThreadHandle osThreadHandle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Causes the current thread to stop executing.
|
||||||
|
*
|
||||||
|
* @return Never returns (thread terminated)
|
||||||
|
*/
|
||||||
|
void pte_osThreadExit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for the specified thread to end. If the thread has already terminated, this returns
|
||||||
|
* immediately.
|
||||||
|
*
|
||||||
|
* @param threadHandle Handle fo thread to wait for.
|
||||||
|
*
|
||||||
|
* @return PTE_OS_OK - specified thread terminated.
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osThreadWaitForEnd(pte_osThreadHandle threadHandle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the handle of the currently executing thread.
|
||||||
|
*/
|
||||||
|
pte_osThreadHandle pte_osThreadGetHandle(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the priority of the specified thread.
|
||||||
|
*/
|
||||||
|
int pte_osThreadGetPriority(pte_osThreadHandle threadHandle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the priority of the specified thread.
|
||||||
|
*
|
||||||
|
* @return PTE_OS_OK - thread priority successfully set
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osThreadSetPriority(pte_osThreadHandle threadHandle, int newPriority);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees resources associated with the specified thread. This is called after the thread has terminated
|
||||||
|
* and is no longer needed (e.g. after pthread_join returns). This call will always be made
|
||||||
|
* from a different context than that of the target thread.
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osThreadDelete(pte_osThreadHandle handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees resources associated with the specified thread and then causes the thread to exit.
|
||||||
|
* This is called after the thread has terminated and is no longer needed (e.g. after
|
||||||
|
* pthread_join returns). This call will always be made from the context of the target thread.
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osThreadExitAndDelete(pte_osThreadHandle handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels the specified thread. This should cause pte_osSemaphoreCancellablePend() and for pte_osThreadCheckCancel()
|
||||||
|
* to return @p PTE_OS_INTERRUPTED.
|
||||||
|
*
|
||||||
|
* @param threadHandle handle to the thread to cancel.
|
||||||
|
*
|
||||||
|
* @return Thread successfully canceled.
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osThreadCancel(pte_osThreadHandle threadHandle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if pte_osThreadCancel() has been called on the specified thread.
|
||||||
|
*
|
||||||
|
* @param threadHandle handle of thread to check the state of.
|
||||||
|
*
|
||||||
|
* @return PTE_OS_OK - Thread has not been cancelled
|
||||||
|
* @return PTE_OS_INTERRUPTED - Thread has been cancelled.
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osThreadCheckCancel(pte_osThreadHandle threadHandle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Causes the current thread to sleep for the specified number of milliseconds.
|
||||||
|
*/
|
||||||
|
void pte_osThreadSleep(unsigned int msecs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum allowable priority
|
||||||
|
*/
|
||||||
|
int pte_osThreadGetMaxPriority();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minimum allowable priority
|
||||||
|
*/
|
||||||
|
int pte_osThreadGetMinPriority();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the priority that should be used if the caller to pthread_create doesn't
|
||||||
|
* explicitly set one.
|
||||||
|
*/
|
||||||
|
int pte_osThreadGetDefaultPriority();
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
|
||||||
|
/** @name Semaphores */
|
||||||
|
//@{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a semaphore
|
||||||
|
*
|
||||||
|
* @param initialValue Initial value of the semaphore
|
||||||
|
* @param pHandle Set to the handle of the newly created semaphore.
|
||||||
|
*
|
||||||
|
* @return PTE_OS_OK - Semaphore successfully created
|
||||||
|
* @return PTE_OS_NO_RESOURCESs - Insufficient resources to create semaphore
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osSemaphoreCreate(int initialValue, pte_osSemaphoreHandle *pHandle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a semaphore and frees any associated resources.
|
||||||
|
*
|
||||||
|
* @param handle Handle of semaphore to delete.
|
||||||
|
*
|
||||||
|
* @return PTE_OS_OK - Semaphore successfully deleted.
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osSemaphoreDelete(pte_osSemaphoreHandle handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Posts to the semaphore
|
||||||
|
*
|
||||||
|
* @param handle Semaphore to release
|
||||||
|
* @param count Amount to increment the semaphore by.
|
||||||
|
*
|
||||||
|
* @return PTE_OS_OK - semaphore successfully released.
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osSemaphorePost(pte_osSemaphoreHandle handle, int count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquire a semaphore, returning after @p timeoutMsecs if the semaphore is not
|
||||||
|
* available. Can be used for polling a semaphore by using @p timeoutMsecs of zero.
|
||||||
|
*
|
||||||
|
* @param handle Handle of semaphore to acquire.
|
||||||
|
* @param pTimeout Pointer to the number of milliseconds to wait to acquire the semaphore
|
||||||
|
* before returning. If set to NULL, wait forever.
|
||||||
|
*
|
||||||
|
* @return PTE_OS_OK - Semaphore successfully acquired.
|
||||||
|
* @return PTE_OS_TIMEOUT - Timeout expired before semaphore was obtained.
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osSemaphorePend(pte_osSemaphoreHandle handle, unsigned int *pTimeout);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquire a semaphore, returning after @p timeoutMsecs if the semaphore is not
|
||||||
|
* available. Can be used for polling a semaphore by using @p timeoutMsecs of zero.
|
||||||
|
* Call must return immediately if pte_osThreadCancel() is called on the thread waiting for
|
||||||
|
* the semaphore.
|
||||||
|
*
|
||||||
|
* @param handle Handle of semaphore to acquire.
|
||||||
|
* @param pTimeout Pointer to the number of milliseconds to wait to acquire the semaphore
|
||||||
|
* before returning. If set to NULL, wait forever.
|
||||||
|
*
|
||||||
|
* @return PTE_OS_OK - Semaphore successfully acquired.
|
||||||
|
* @return PTE_OS_TIMEOUT - Timeout expired before semaphore was obtained.
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osSemaphoreCancellablePend(pte_osSemaphoreHandle handle, unsigned int *pTimeout);
|
||||||
|
//@}
|
||||||
|
|
||||||
|
|
||||||
|
/** @name Thread Local Storage */
|
||||||
|
//@{
|
||||||
|
/**
|
||||||
|
* Sets the thread specific value for the specified key for the
|
||||||
|
* currently executing thread.
|
||||||
|
*
|
||||||
|
* @param index The TLS key for the value.
|
||||||
|
* @param value The value to save
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osTlsSetValue(unsigned int key, void * value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the thread specific value for the specified key for
|
||||||
|
* the currently executing thread. If a value has not been set
|
||||||
|
* for this key, NULL should be returned (i.e. TLS values default
|
||||||
|
* to NULL).
|
||||||
|
*
|
||||||
|
* @param index The TLS key for the value.
|
||||||
|
*
|
||||||
|
* @return The value associated with @p key for the current thread.
|
||||||
|
*/
|
||||||
|
void * pte_osTlsGetValue(unsigned int key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the OS TLS support. This is called by the PTE library
|
||||||
|
* prior to performing ANY TLS operation.
|
||||||
|
*/
|
||||||
|
void pte_osTlsInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates a new TLS key.
|
||||||
|
*
|
||||||
|
* @param pKey On success will be set to the newly allocated key.
|
||||||
|
*
|
||||||
|
* @return PTE_OS_OK - TLS key successfully allocated.
|
||||||
|
* @return PTE_OS_NO_RESOURCESs - Insufficient resources to allocate key (e.g.
|
||||||
|
* maximum number of keys reached).
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osTlsAlloc(unsigned int *pKey);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees the specified TLS key.
|
||||||
|
*
|
||||||
|
* @param index TLS key to free
|
||||||
|
*
|
||||||
|
* @return PTE_OS_OK - TLS key was successfully freed.
|
||||||
|
*/
|
||||||
|
pte_osResult pte_osTlsFree(unsigned int key);
|
||||||
|
//@}
|
||||||
|
|
||||||
|
/** @name Atomic operations */
|
||||||
|
//@{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the target to the specified value as an atomic operation.
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* origVal = *ptarg
|
||||||
|
* *ptarg = val
|
||||||
|
* return origVal
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* @param pTarg Pointer to the value to be exchanged.
|
||||||
|
* @param val Value to be exchanged
|
||||||
|
*
|
||||||
|
* @return original value of destination
|
||||||
|
*/
|
||||||
|
int pte_osAtomicExchange(int *pTarg, int val);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs an atomic compare-and-exchange oepration on the specified
|
||||||
|
* value. That is:
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* origVal = *pdest
|
||||||
|
* if (*pdest == comp)
|
||||||
|
* then *pdest = exchange
|
||||||
|
* return origVal
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* @param pdest Pointer to the destination value.
|
||||||
|
* @param exchange Exchange value (value to set destination to if destination == comparand)
|
||||||
|
* @param comp The value to compare to destination.
|
||||||
|
*
|
||||||
|
* @return Original value of destination
|
||||||
|
*/
|
||||||
|
int pte_osAtomicCompareExchange(int *pdest, int exchange, int comp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the value to target as an atomic operation
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* origVal = *pdest
|
||||||
|
* *pAddend += value
|
||||||
|
* return origVal
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* @param pdest Pointer to the variable to be updated.
|
||||||
|
* @param value Value to be added to the variable.
|
||||||
|
*
|
||||||
|
* @return Original value of destination
|
||||||
|
*/
|
||||||
|
int pte_osAtomicExchangeAdd(int volatile* pdest, int value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrements the destination.
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* origVal = *pdest
|
||||||
|
* *pdest++
|
||||||
|
* return origVal
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* @param pdest Destination value to decrement
|
||||||
|
*
|
||||||
|
* @return Original destination value
|
||||||
|
*/
|
||||||
|
int pte_osAtomicDecrement(int *pdest);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the destination value
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* origVal = *pdest;
|
||||||
|
* *pdest++;
|
||||||
|
* return origVal;
|
||||||
|
*/
|
||||||
|
int pte_osAtomicIncrement(int *pdest);
|
||||||
|
//@}
|
||||||
|
|
||||||
|
struct timeb;
|
||||||
|
|
||||||
|
int ftime(struct timeb *tb);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // _OS_SUPPORT_H_
|
396
deps/pthreads/pte_main.c
vendored
Normal file
396
deps/pthreads/pte_main.c
vendored
Normal file
@ -0,0 +1,396 @@
|
|||||||
|
/*
|
||||||
|
* pte_main.c
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This translation unit instantiates data associated with the implementation
|
||||||
|
* as a whole.
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "pte_osal.h"
|
||||||
|
|
||||||
|
#include "pthread.h"
|
||||||
|
#include "implement.h"
|
||||||
|
|
||||||
|
|
||||||
|
int pte_processInitialized = PTE_FALSE;
|
||||||
|
pte_thread_t * pte_threadReuseTop = PTE_THREAD_REUSE_EMPTY;
|
||||||
|
pte_thread_t * pte_threadReuseBottom = PTE_THREAD_REUSE_EMPTY;
|
||||||
|
pthread_key_t pte_selfThreadKey = NULL;
|
||||||
|
pthread_key_t pte_cleanupKey = NULL;
|
||||||
|
pthread_cond_t pte_cond_list_head = NULL;
|
||||||
|
pthread_cond_t pte_cond_list_tail = NULL;
|
||||||
|
|
||||||
|
int pte_concurrency = 0;
|
||||||
|
|
||||||
|
/* What features have been auto-detaected */
|
||||||
|
int pte_features = 0;
|
||||||
|
|
||||||
|
unsigned char pte_smp_system = PTE_TRUE; /* Safer if assumed true initially. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Global lock for managing pthread_t struct reuse.
|
||||||
|
*/
|
||||||
|
pte_osMutexHandle pte_thread_reuse_lock;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Global lock for testing internal state of statically declared mutexes.
|
||||||
|
*/
|
||||||
|
pte_osMutexHandle pte_mutex_test_init_lock;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Global lock for testing internal state of PTHREAD_COND_INITIALIZER
|
||||||
|
* created condition variables.
|
||||||
|
*/
|
||||||
|
pte_osMutexHandle pte_cond_test_init_lock;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Global lock for testing internal state of PTHREAD_RWLOCK_INITIALIZER
|
||||||
|
* created read/write locks.
|
||||||
|
*/
|
||||||
|
pte_osMutexHandle pte_rwlock_test_init_lock;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Global lock for testing internal state of PTHREAD_SPINLOCK_INITIALIZER
|
||||||
|
* created spin locks.
|
||||||
|
*/
|
||||||
|
pte_osMutexHandle pte_spinlock_test_init_lock;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Global lock for condition variable linked list. The list exists
|
||||||
|
* to wake up CVs when a WM_TIMECHANGE message arrives. See
|
||||||
|
* w32_TimeChangeHandler.c.
|
||||||
|
*/
|
||||||
|
pte_osMutexHandle pte_cond_list_lock;
|
||||||
|
|
||||||
|
int pthread_create (pthread_t * tid,
|
||||||
|
const pthread_attr_t * attr,
|
||||||
|
void *(*start) (void *), void *arg)
|
||||||
|
/*
|
||||||
|
* ------------------------------------------------------
|
||||||
|
* DOCPUBLIC
|
||||||
|
* This function creates a thread running the start function,
|
||||||
|
* passing it the parameter value, 'arg'. The 'attr'
|
||||||
|
* argument specifies optional creation attributes.
|
||||||
|
* The identity of the new thread is returned
|
||||||
|
* via 'tid', which should not be NULL.
|
||||||
|
*
|
||||||
|
* PARAMETERS
|
||||||
|
* tid
|
||||||
|
* pointer to an instance of pthread_t
|
||||||
|
*
|
||||||
|
* attr
|
||||||
|
* optional pointer to an instance of pthread_attr_t
|
||||||
|
*
|
||||||
|
* start
|
||||||
|
* pointer to the starting routine for the new thread
|
||||||
|
*
|
||||||
|
* arg
|
||||||
|
* optional parameter passed to 'start'
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* DESCRIPTION
|
||||||
|
* This function creates a thread running the start function,
|
||||||
|
* passing it the parameter value, 'arg'. The 'attr'
|
||||||
|
* argument specifies optional creation attributes.
|
||||||
|
* The identity of the new thread is returned
|
||||||
|
* via 'tid', which should not be the NULL pointer.
|
||||||
|
*
|
||||||
|
* RESULTS
|
||||||
|
* 0 successfully created thread,
|
||||||
|
* EINVAL attr invalid,
|
||||||
|
* EAGAIN insufficient resources.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
pthread_t thread;
|
||||||
|
pte_thread_t * tp;
|
||||||
|
int result = EAGAIN;
|
||||||
|
int run = PTE_TRUE;
|
||||||
|
ThreadParms *parms = NULL;
|
||||||
|
long stackSize;
|
||||||
|
int priority = 0;
|
||||||
|
pthread_t self;
|
||||||
|
pte_osResult osResult;
|
||||||
|
register pthread_attr_t a = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Before doing anything, check that tid can be stored through
|
||||||
|
* without invoking a memory protection error (segfault).
|
||||||
|
* Make sure that the assignment below can't be optimised out by the compiler.
|
||||||
|
* This is assured by conditionally assigning *tid again at the end.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (attr != NULL)
|
||||||
|
a = *attr;
|
||||||
|
|
||||||
|
if ((thread = pte_new ()) == NULL)
|
||||||
|
goto FAIL0;
|
||||||
|
|
||||||
|
tp = (pte_thread_t *) thread;
|
||||||
|
|
||||||
|
priority = tp->sched_priority;
|
||||||
|
|
||||||
|
if ((parms = (ThreadParms *) malloc (sizeof (*parms))) == NULL)
|
||||||
|
goto FAIL0;
|
||||||
|
|
||||||
|
parms->tid = thread;
|
||||||
|
parms->start = start;
|
||||||
|
parms->arg = arg;
|
||||||
|
|
||||||
|
if (a != NULL)
|
||||||
|
{
|
||||||
|
stackSize = a->stacksize;
|
||||||
|
tp->detachState = a->detachstate;
|
||||||
|
priority = a->param.sched_priority;
|
||||||
|
|
||||||
|
if ( (priority > pte_osThreadGetMaxPriority()) ||
|
||||||
|
(priority < pte_osThreadGetMinPriority()) )
|
||||||
|
{
|
||||||
|
result = EINVAL;
|
||||||
|
goto FAIL0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Everything else */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Thread priority must be set to a valid system level
|
||||||
|
* without altering the value set by pthread_attr_setschedparam().
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (PTHREAD_INHERIT_SCHED == a->inheritsched)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If the thread that called pthread_create() is an OS thread
|
||||||
|
* then the inherited priority could be the result of a temporary
|
||||||
|
* system adjustment. This is not the case for POSIX threads.
|
||||||
|
*/
|
||||||
|
self = pthread_self ();
|
||||||
|
priority = ((pte_thread_t *) self)->sched_priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Default stackSize
|
||||||
|
*/
|
||||||
|
stackSize = PTHREAD_STACK_MIN;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
tp->state = run ? PThreadStateInitial : PThreadStateSuspended;
|
||||||
|
|
||||||
|
tp->keys = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Threads must be started in suspended mode and resumed if necessary
|
||||||
|
* after _beginthreadex returns us the handle. Otherwise we set up a
|
||||||
|
* race condition between the creating and the created threads.
|
||||||
|
* Note that we also retain a local copy of the handle for use
|
||||||
|
* by us in case thread.p->threadH gets NULLed later but before we've
|
||||||
|
* finished with it here.
|
||||||
|
*/
|
||||||
|
result = pthread_mutex_lock (&tp->threadLock);
|
||||||
|
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Must record the thread's sched_priority as given,
|
||||||
|
* not as finally adjusted.
|
||||||
|
*/
|
||||||
|
tp->sched_priority = priority;
|
||||||
|
|
||||||
|
(void) pthread_mutex_unlock (&tp->threadLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
osResult = pte_osThreadCreate(pte_threadStart,
|
||||||
|
stackSize,
|
||||||
|
priority,
|
||||||
|
parms,
|
||||||
|
&(tp->threadId));
|
||||||
|
|
||||||
|
if (osResult == PTE_OS_OK)
|
||||||
|
{
|
||||||
|
pte_osThreadStart(tp->threadId);
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tp->threadId = 0;
|
||||||
|
result = EAGAIN;
|
||||||
|
goto FAIL0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fall Through Intentionally
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ------------
|
||||||
|
* Failure Code
|
||||||
|
* ------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
FAIL0:
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
pte_threadDestroy (thread);
|
||||||
|
tp = NULL;
|
||||||
|
|
||||||
|
if (parms != NULL)
|
||||||
|
free (parms);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (tid != NULL)
|
||||||
|
*tid = thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The functions pte_pop_cleanup and pte_push_cleanup
|
||||||
|
* are implemented here for applications written in C with no
|
||||||
|
* C++ destructor support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pte_cleanup_t *pte_pop_cleanup (int execute)
|
||||||
|
/*
|
||||||
|
* ------------------------------------------------------
|
||||||
|
* DOCPUBLIC
|
||||||
|
* This function pops the most recently pushed cleanup
|
||||||
|
* handler. If execute is nonzero, then the cleanup handler
|
||||||
|
* is executed if non-null.
|
||||||
|
*
|
||||||
|
* PARAMETERS
|
||||||
|
* execute
|
||||||
|
* if nonzero, execute the cleanup handler
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* DESCRIPTION
|
||||||
|
* This function pops the most recently pushed cleanup
|
||||||
|
* handler. If execute is nonzero, then the cleanup handler
|
||||||
|
* is executed if non-null.
|
||||||
|
* NOTE: specify 'execute' as nonzero to avoid duplication
|
||||||
|
* of common cleanup code.
|
||||||
|
*
|
||||||
|
* RESULTS
|
||||||
|
* N/A
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
pte_cleanup_t *cleanup;
|
||||||
|
|
||||||
|
cleanup = (pte_cleanup_t *) pthread_getspecific (pte_cleanupKey);
|
||||||
|
|
||||||
|
if (cleanup != NULL)
|
||||||
|
{
|
||||||
|
if (execute && (cleanup->routine != NULL))
|
||||||
|
{
|
||||||
|
|
||||||
|
(*cleanup->routine) (cleanup->arg);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_setspecific (pte_cleanupKey, (void *) cleanup->prev);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return (cleanup);
|
||||||
|
|
||||||
|
} /* pte_pop_cleanup */
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
pte_push_cleanup (pte_cleanup_t * cleanup,
|
||||||
|
pte_cleanup_callback_t routine, void *arg)
|
||||||
|
/*
|
||||||
|
* ------------------------------------------------------
|
||||||
|
* DOCPUBLIC
|
||||||
|
* This function pushes a new cleanup handler onto the thread's stack
|
||||||
|
* of cleanup handlers. Each cleanup handler pushed onto the stack is
|
||||||
|
* popped and invoked with the argument 'arg' when
|
||||||
|
* a) the thread exits by calling 'pthread_exit',
|
||||||
|
* b) when the thread acts on a cancellation request,
|
||||||
|
* c) or when the thread calls pthread_cleanup_pop with a nonzero
|
||||||
|
* 'execute' argument
|
||||||
|
*
|
||||||
|
* PARAMETERS
|
||||||
|
* cleanup
|
||||||
|
* a pointer to an instance of pthread_cleanup_t,
|
||||||
|
*
|
||||||
|
* routine
|
||||||
|
* pointer to a cleanup handler,
|
||||||
|
*
|
||||||
|
* arg
|
||||||
|
* parameter to be passed to the cleanup handler
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* DESCRIPTION
|
||||||
|
* This function pushes a new cleanup handler onto the thread's stack
|
||||||
|
* of cleanup handlers. Each cleanup handler pushed onto the stack is
|
||||||
|
* popped and invoked with the argument 'arg' when
|
||||||
|
* a) the thread exits by calling 'pthread_exit',
|
||||||
|
* b) when the thread acts on a cancellation request,
|
||||||
|
* c) or when the thrad calls pthread_cleanup_pop with a nonzero
|
||||||
|
* 'execute' argument
|
||||||
|
* NOTE: pthread_push_cleanup, pte_pop_cleanup must be paired
|
||||||
|
* in the same lexical scope.
|
||||||
|
*
|
||||||
|
* RESULTS
|
||||||
|
* pthread_cleanup_t *
|
||||||
|
* pointer to the previous cleanup
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
cleanup->routine = routine;
|
||||||
|
cleanup->arg = arg;
|
||||||
|
|
||||||
|
cleanup->prev = (pte_cleanup_t *) pthread_getspecific (pte_cleanupKey);
|
||||||
|
|
||||||
|
pthread_setspecific (pte_cleanupKey, (void *) cleanup);
|
||||||
|
}
|
1017
deps/pthreads/pthread.c
vendored
Normal file
1017
deps/pthreads/pthread.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
891
deps/pthreads/pthread.h
vendored
Normal file
891
deps/pthreads/pthread.h
vendored
Normal file
@ -0,0 +1,891 @@
|
|||||||
|
/* This is an implementation of the threads API of POSIX 1003.1-2001.
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
#if !defined( PTHREAD_H )
|
||||||
|
#define PTHREAD_H
|
||||||
|
|
||||||
|
#include <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
deps/pthreads/pthread_attr.c
vendored
Normal file
581
deps/pthreads/pthread_attr.c
vendored
Normal file
@ -0,0 +1,581 @@
|
|||||||
|
/*
|
||||||
|
* pthread_attr.c
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This translation unit implements operations on thread attribute objects.
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <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
deps/pthreads/pthread_barrier.c
vendored
Normal file
163
deps/pthreads/pthread_barrier.c
vendored
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* pthread_barrier.c
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This translation unit implements barrier primitives.
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <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
deps/pthreads/pthread_barrierattr.c
vendored
Normal file
257
deps/pthreads/pthread_barrierattr.c
vendored
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
/*
|
||||||
|
* pthread_barrier_attr.c
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This translation unit implements barrier primitives.
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <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
deps/pthreads/pthread_cond.c
vendored
Normal file
807
deps/pthreads/pthread_cond.c
vendored
Normal file
@ -0,0 +1,807 @@
|
|||||||
|
/*
|
||||||
|
* pthread_cond.c
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This translation unit implements condition variables and their primitives.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <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
deps/pthreads/pthread_condattr.c
vendored
Normal file
259
deps/pthreads/pthread_condattr.c
vendored
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
* condvar_attr_destroy.c
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This translation unit implements condition variables and their primitives.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <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
deps/pthreads/pthread_get.c
vendored
Normal file
111
deps/pthreads/pthread_get.c
vendored
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* pthread_get.c
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This translation unit implements miscellaneous thread functions.
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pthread.h"
|
||||||
|
#include "implement.h"
|
||||||
|
#include "sched.h"
|
||||||
|
|
||||||
|
int pthread_getconcurrency (void)
|
||||||
|
{
|
||||||
|
return pte_concurrency;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pthread_getschedparam (pthread_t thread, int *policy,
|
||||||
|
struct sched_param *param)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
/* Validate the thread id. */
|
||||||
|
result = pthread_kill (thread, 0);
|
||||||
|
if (0 != result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validate the policy and param args.
|
||||||
|
* Check that a policy constant wasn't passed rather than &policy.
|
||||||
|
*/
|
||||||
|
if (policy <= (int *) SCHED_MAX || param == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
/* Fill out the policy. */
|
||||||
|
*policy = SCHED_OTHER;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function must return the priority value set by
|
||||||
|
* the most recent pthread_setschedparam() or pthread_create()
|
||||||
|
* for the target thread. It must not return the actual thread
|
||||||
|
* priority as altered by any system priority adjustments etc.
|
||||||
|
*/
|
||||||
|
param->sched_priority = ((pte_thread_t *)thread)->sched_priority;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *pthread_getspecific (pthread_key_t key)
|
||||||
|
/*
|
||||||
|
* ------------------------------------------------------
|
||||||
|
* DOCPUBLIC
|
||||||
|
* This function returns the current value of key in the
|
||||||
|
* calling thread. If no value has been set for 'key' in
|
||||||
|
* the thread, NULL is returned.
|
||||||
|
*
|
||||||
|
* PARAMETERS
|
||||||
|
* key
|
||||||
|
* an instance of pthread_key_t
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* DESCRIPTION
|
||||||
|
* This function returns the current value of key in the
|
||||||
|
* calling thread. If no value has been set for 'key' in
|
||||||
|
* the thread, NULL is returned.
|
||||||
|
*
|
||||||
|
* RESULTS
|
||||||
|
* key value or NULL on failure
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if (key == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return pte_osTlsGetValue (key->key);
|
||||||
|
}
|
204
deps/pthreads/pthread_key.c
vendored
Normal file
204
deps/pthreads/pthread_key.c
vendored
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
/*
|
||||||
|
* pthread_key.c
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* POSIX thread functions which implement thread-specific data (TSD).
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <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
deps/pthreads/pthread_mutex.c
vendored
Normal file
500
deps/pthreads/pthread_mutex.c
vendored
Normal file
@ -0,0 +1,500 @@
|
|||||||
|
/*
|
||||||
|
* pthread_mutex.c
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This translation unit implements mutual exclusion (mutex) primitives.
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <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
deps/pthreads/pthread_mutexattr.c
vendored
Normal file
377
deps/pthreads/pthread_mutexattr.c
vendored
Normal file
@ -0,0 +1,377 @@
|
|||||||
|
/*
|
||||||
|
* pthread_mutexattr.c
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This translation unit implements mutual exclusion (mutex) primitives.
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <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
deps/pthreads/pthread_rwlock.c
vendored
Normal file
676
deps/pthreads/pthread_rwlock.c
vendored
Normal file
@ -0,0 +1,676 @@
|
|||||||
|
/*
|
||||||
|
* pthread_rwlock.c
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This translation unit implements read/write lock primitives.
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <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
deps/pthreads/pthread_rwlockattr.c
vendored
Normal file
259
deps/pthreads/pthread_rwlockattr.c
vendored
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
* pthread_rwlockattr_destroy.c
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This translation unit implements read/write lock primitives.
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <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
deps/pthreads/pthread_set.c
vendored
Normal file
399
deps/pthreads/pthread_set.c
vendored
Normal file
@ -0,0 +1,399 @@
|
|||||||
|
/*
|
||||||
|
* pthread_set.c
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* POSIX thread functions related to state.
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pthread.h"
|
||||||
|
#include "implement.h"
|
||||||
|
#include "sched.h"
|
||||||
|
|
||||||
|
int pthread_setcancelstate (int state, int *oldstate)
|
||||||
|
/*
|
||||||
|
* ------------------------------------------------------
|
||||||
|
* DOCPUBLIC
|
||||||
|
* This function atomically sets the calling thread's
|
||||||
|
* cancelability state to 'state' and returns the previous
|
||||||
|
* cancelability state at the location referenced by
|
||||||
|
* 'oldstate'
|
||||||
|
*
|
||||||
|
* PARAMETERS
|
||||||
|
* state,
|
||||||
|
* oldstate
|
||||||
|
* PTHREAD_CANCEL_ENABLE
|
||||||
|
* cancellation is enabled,
|
||||||
|
*
|
||||||
|
* PTHREAD_CANCEL_DISABLE
|
||||||
|
* cancellation is disabled
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* DESCRIPTION
|
||||||
|
* This function atomically sets the calling thread's
|
||||||
|
* cancelability state to 'state' and returns the previous
|
||||||
|
* cancelability state at the location referenced by
|
||||||
|
* 'oldstate'.
|
||||||
|
*
|
||||||
|
* NOTES:
|
||||||
|
* 1) Use to disable cancellation around 'atomic' code that
|
||||||
|
* includes cancellation points
|
||||||
|
*
|
||||||
|
* COMPATIBILITY ADDITIONS
|
||||||
|
* If 'oldstate' is NULL then the previous state is not returned
|
||||||
|
* but the function still succeeds. (Solaris)
|
||||||
|
*
|
||||||
|
* RESULTS
|
||||||
|
* 0 successfully set cancelability type,
|
||||||
|
* EINVAL 'state' is invalid
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
pthread_t self = pthread_self ();
|
||||||
|
pte_thread_t * sp = (pte_thread_t *) self;
|
||||||
|
|
||||||
|
if (sp == NULL
|
||||||
|
|| (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE))
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lock for async-cancel safety.
|
||||||
|
*/
|
||||||
|
(void) pthread_mutex_lock (&sp->cancelLock);
|
||||||
|
|
||||||
|
if (oldstate != NULL)
|
||||||
|
*oldstate = sp->cancelState;
|
||||||
|
|
||||||
|
sp->cancelState = state;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if there is a pending asynchronous cancel
|
||||||
|
*/
|
||||||
|
if (state == PTHREAD_CANCEL_ENABLE
|
||||||
|
&& (sp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS)
|
||||||
|
&& (pte_osThreadCheckCancel(sp->threadId) == PTE_OS_INTERRUPTED) )
|
||||||
|
{
|
||||||
|
sp->state = PThreadStateCanceling;
|
||||||
|
sp->cancelState = PTHREAD_CANCEL_DISABLE;
|
||||||
|
(void) pthread_mutex_unlock (&sp->cancelLock);
|
||||||
|
pte_throw (PTE_EPS_CANCEL);
|
||||||
|
|
||||||
|
/* Never reached */
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) pthread_mutex_unlock (&sp->cancelLock);
|
||||||
|
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pthread_setcanceltype (int type, int *oldtype)
|
||||||
|
/*
|
||||||
|
* ------------------------------------------------------
|
||||||
|
* DOCPUBLIC
|
||||||
|
* This function atomically sets the calling thread's
|
||||||
|
* cancelability type to 'type' and returns the previous
|
||||||
|
* cancelability type at the location referenced by
|
||||||
|
* 'oldtype'
|
||||||
|
*
|
||||||
|
* PARAMETERS
|
||||||
|
* type,
|
||||||
|
* oldtype
|
||||||
|
* PTHREAD_CANCEL_DEFERRED
|
||||||
|
* only deferred cancelation is allowed,
|
||||||
|
*
|
||||||
|
* PTHREAD_CANCEL_ASYNCHRONOUS
|
||||||
|
* Asynchronous cancellation is allowed
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* DESCRIPTION
|
||||||
|
* This function atomically sets the calling thread's
|
||||||
|
* cancelability type to 'type' and returns the previous
|
||||||
|
* cancelability type at the location referenced by
|
||||||
|
* 'oldtype'
|
||||||
|
*
|
||||||
|
* NOTES:
|
||||||
|
* 1) Use with caution; most code is not safe for use
|
||||||
|
* with asynchronous cancelability.
|
||||||
|
*
|
||||||
|
* COMPATIBILITY ADDITIONS
|
||||||
|
* If 'oldtype' is NULL then the previous type is not returned
|
||||||
|
* but the function still succeeds. (Solaris)
|
||||||
|
*
|
||||||
|
* RESULTS
|
||||||
|
* 0 successfully set cancelability type,
|
||||||
|
* EINVAL 'type' is invalid
|
||||||
|
* EPERM Async cancellation is not supported.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
pthread_t self = pthread_self ();
|
||||||
|
pte_thread_t * sp = (pte_thread_t *) self;
|
||||||
|
|
||||||
|
#ifndef PTE_SUPPORT_ASYNC_CANCEL
|
||||||
|
if (type == PTHREAD_CANCEL_ASYNCHRONOUS)
|
||||||
|
{
|
||||||
|
/* Async cancellation is not supported at this time. See notes in
|
||||||
|
* pthread_cancel.
|
||||||
|
*/
|
||||||
|
return EPERM;
|
||||||
|
}
|
||||||
|
#endif /* PTE_SUPPORT_ASYNC_CANCEL */
|
||||||
|
|
||||||
|
if (sp == NULL
|
||||||
|
|| (type != PTHREAD_CANCEL_DEFERRED
|
||||||
|
&& type != PTHREAD_CANCEL_ASYNCHRONOUS))
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lock for async-cancel safety.
|
||||||
|
*/
|
||||||
|
(void) pthread_mutex_lock (&sp->cancelLock);
|
||||||
|
|
||||||
|
if (oldtype != NULL)
|
||||||
|
*oldtype = sp->cancelType;
|
||||||
|
|
||||||
|
sp->cancelType = type;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if there is a pending asynchronous cancel
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (sp->cancelState == PTHREAD_CANCEL_ENABLE
|
||||||
|
&& (type == PTHREAD_CANCEL_ASYNCHRONOUS)
|
||||||
|
&& (pte_osThreadCheckCancel(sp->threadId) == PTE_OS_INTERRUPTED) )
|
||||||
|
{
|
||||||
|
sp->state = PThreadStateCanceling;
|
||||||
|
sp->cancelState = PTHREAD_CANCEL_DISABLE;
|
||||||
|
(void) pthread_mutex_unlock (&sp->cancelLock);
|
||||||
|
pte_throw (PTE_EPS_CANCEL);
|
||||||
|
|
||||||
|
/* Never reached */
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) pthread_mutex_unlock (&sp->cancelLock);
|
||||||
|
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pthread_setconcurrency (int level)
|
||||||
|
{
|
||||||
|
if (level < 0)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
pte_concurrency = level;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pthread_setschedparam (pthread_t thread, int policy,
|
||||||
|
const struct sched_param *param)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
/* Validate the thread id. */
|
||||||
|
result = pthread_kill (thread, 0);
|
||||||
|
if (0 != result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/* Validate the scheduling policy. */
|
||||||
|
if (policy < SCHED_MIN || policy > SCHED_MAX)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
/* Ensure the policy is SCHED_OTHER. */
|
||||||
|
if (policy != SCHED_OTHER)
|
||||||
|
return ENOTSUP;
|
||||||
|
|
||||||
|
return (pte_setthreadpriority (thread, policy, param->sched_priority));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pte_setthreadpriority (pthread_t thread, int policy, int priority)
|
||||||
|
{
|
||||||
|
int prio;
|
||||||
|
int result;
|
||||||
|
pte_thread_t * tp = (pte_thread_t *) thread;
|
||||||
|
|
||||||
|
prio = priority;
|
||||||
|
|
||||||
|
/* Validate priority level. */
|
||||||
|
if (prio < sched_get_priority_min (policy) ||
|
||||||
|
prio > sched_get_priority_max (policy))
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
result = pthread_mutex_lock (&tp->threadLock);
|
||||||
|
|
||||||
|
if (0 == result)
|
||||||
|
{
|
||||||
|
/* If this fails, the current priority is unchanged. */
|
||||||
|
|
||||||
|
if (0 != pte_osThreadSetPriority(tp->threadId, prio))
|
||||||
|
result = EINVAL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Must record the thread's sched_priority as given,
|
||||||
|
* not as finally adjusted.
|
||||||
|
*/
|
||||||
|
tp->sched_priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) pthread_mutex_unlock (&tp->threadLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pthread_setspecific (pthread_key_t key, const void *value)
|
||||||
|
/*
|
||||||
|
* ------------------------------------------------------
|
||||||
|
* DOCPUBLIC
|
||||||
|
* This function sets the value of the thread specific
|
||||||
|
* key in the calling thread.
|
||||||
|
*
|
||||||
|
* PARAMETERS
|
||||||
|
* key
|
||||||
|
* an instance of pthread_key_t
|
||||||
|
* value
|
||||||
|
* the value to set key to
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* DESCRIPTION
|
||||||
|
* This function sets the value of the thread specific
|
||||||
|
* key in the calling thread.
|
||||||
|
*
|
||||||
|
* RESULTS
|
||||||
|
* 0 successfully set value
|
||||||
|
* EAGAIN could not set value
|
||||||
|
* ENOENT SERIOUS!!
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
pthread_t self;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
if (key != pte_selfThreadKey)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Using pthread_self will implicitly create
|
||||||
|
* an instance of pthread_t for the current
|
||||||
|
* thread if one wasn't explicitly created
|
||||||
|
*/
|
||||||
|
self = pthread_self ();
|
||||||
|
if (self == NULL)
|
||||||
|
return ENOENT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Resolve catch-22 of registering thread with selfThread
|
||||||
|
* key
|
||||||
|
*/
|
||||||
|
pte_thread_t * sp = (pte_thread_t *) pthread_getspecific (pte_selfThreadKey);
|
||||||
|
|
||||||
|
if (sp == NULL)
|
||||||
|
{
|
||||||
|
if (value == NULL)
|
||||||
|
return ENOENT;
|
||||||
|
|
||||||
|
self = *((pthread_t *) value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
self = sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
|
||||||
|
if (key != NULL)
|
||||||
|
{
|
||||||
|
if (self != NULL && key->destructor != NULL && value != NULL)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Only require associations if we have to
|
||||||
|
* call user destroy routine.
|
||||||
|
* Don't need to locate an existing association
|
||||||
|
* when setting data to NULL since the
|
||||||
|
* data is stored with the operating system; not
|
||||||
|
* on the association; setting assoc to NULL short
|
||||||
|
* circuits the search.
|
||||||
|
*/
|
||||||
|
ThreadKeyAssoc *assoc;
|
||||||
|
|
||||||
|
if (pthread_mutex_lock(&(key->keyLock)) == 0)
|
||||||
|
{
|
||||||
|
pte_thread_t * sp = (pte_thread_t *) self;
|
||||||
|
|
||||||
|
(void) pthread_mutex_lock(&(sp->threadLock));
|
||||||
|
|
||||||
|
assoc = (ThreadKeyAssoc *) sp->keys;
|
||||||
|
/*
|
||||||
|
* Locate existing association
|
||||||
|
*/
|
||||||
|
while (assoc != NULL)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Association already exists
|
||||||
|
*/
|
||||||
|
if (assoc->key == key)
|
||||||
|
break;
|
||||||
|
assoc = assoc->nextKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create an association if not found
|
||||||
|
*/
|
||||||
|
if (assoc == NULL)
|
||||||
|
result = pte_tkAssocCreate (sp, key);
|
||||||
|
|
||||||
|
(void) pthread_mutex_unlock(&(sp->threadLock));
|
||||||
|
}
|
||||||
|
(void) pthread_mutex_unlock(&(key->keyLock));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
if (pte_osTlsSetValue (key->key, (void *) value) != PTE_OS_OK)
|
||||||
|
result = EAGAIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (result);
|
||||||
|
}
|
295
deps/pthreads/pthread_spin.c
vendored
Normal file
295
deps/pthreads/pthread_spin.c
vendored
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
/*
|
||||||
|
* pthread_spin.c
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This translation unit implements spin lock primitives.
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "pthread.h"
|
||||||
|
#include "implement.h"
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pthread_spin_destroy (pthread_spinlock_t * lock)
|
||||||
|
{
|
||||||
|
register pthread_spinlock_t s;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
if (lock == NULL || *lock == NULL)
|
||||||
|
{
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((s = *lock) != PTHREAD_SPINLOCK_INITIALIZER)
|
||||||
|
{
|
||||||
|
if (s->interlock == PTE_SPIN_USE_MUTEX)
|
||||||
|
{
|
||||||
|
result = pthread_mutex_destroy (&(s->u.mutex));
|
||||||
|
}
|
||||||
|
else if (PTE_SPIN_UNLOCKED !=
|
||||||
|
PTE_ATOMIC_COMPARE_EXCHANGE (
|
||||||
|
& (s->interlock),
|
||||||
|
(int) PTE_OBJECT_INVALID,
|
||||||
|
PTE_SPIN_UNLOCKED))
|
||||||
|
{
|
||||||
|
result = EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == result)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We are relying on the application to ensure that all other threads
|
||||||
|
* have finished with the spinlock before destroying it.
|
||||||
|
*/
|
||||||
|
*lock = NULL;
|
||||||
|
(void) free (s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* See notes in pte_spinlock_check_need_init() above also.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pte_osMutexLock (pte_spinlock_test_init_lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check again.
|
||||||
|
*/
|
||||||
|
if (*lock == PTHREAD_SPINLOCK_INITIALIZER)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* This is all we need to do to destroy a statically
|
||||||
|
* initialised spinlock that has not yet been used (initialised).
|
||||||
|
* If we get to here, another thread
|
||||||
|
* waiting to initialise this mutex will get an EINVAL.
|
||||||
|
*/
|
||||||
|
*lock = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The spinlock has been initialised while we were waiting
|
||||||
|
* so assume it's in use.
|
||||||
|
*/
|
||||||
|
result = EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
pte_osMutexUnlock(pte_spinlock_test_init_lock);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pthread_spin_init (pthread_spinlock_t * lock, int pshared)
|
||||||
|
{
|
||||||
|
pthread_spinlock_t s;
|
||||||
|
int cpus = 0;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
if (lock == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
if (0 != pte_getprocessors (&cpus))
|
||||||
|
{
|
||||||
|
cpus = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpus > 1)
|
||||||
|
{
|
||||||
|
if (pshared == PTHREAD_PROCESS_SHARED)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Creating spinlock that can be shared between
|
||||||
|
* processes.
|
||||||
|
*/
|
||||||
|
#if _POSIX_THREAD_PROCESS_SHARED >= 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Not implemented yet.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#error ERROR [__FILE__, line __LINE__]: Process shared spin locks are not supported yet.
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
return ENOSYS;
|
||||||
|
|
||||||
|
#endif /* _POSIX_THREAD_PROCESS_SHARED */
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s = (pthread_spinlock_t) calloc (1, sizeof (*s));
|
||||||
|
|
||||||
|
if (s == NULL)
|
||||||
|
{
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpus > 1)
|
||||||
|
{
|
||||||
|
s->u.cpus = cpus;
|
||||||
|
s->interlock = PTE_SPIN_UNLOCKED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pthread_mutexattr_t ma;
|
||||||
|
result = pthread_mutexattr_init (&ma);
|
||||||
|
|
||||||
|
if (0 == result)
|
||||||
|
{
|
||||||
|
ma->pshared = pshared;
|
||||||
|
result = pthread_mutex_init (&(s->u.mutex), &ma);
|
||||||
|
if (0 == result)
|
||||||
|
{
|
||||||
|
s->interlock = PTE_SPIN_USE_MUTEX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void) pthread_mutexattr_destroy (&ma);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == result)
|
||||||
|
{
|
||||||
|
*lock = s;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(void) free (s);
|
||||||
|
*lock = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pthread_spin_lock (pthread_spinlock_t * lock)
|
||||||
|
{
|
||||||
|
register pthread_spinlock_t s;
|
||||||
|
|
||||||
|
if (NULL == lock || NULL == *lock)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
if (*lock == PTHREAD_SPINLOCK_INITIALIZER)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result = pte_spinlock_check_need_init (lock)) != 0)
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
s = *lock;
|
||||||
|
|
||||||
|
while ( PTE_SPIN_LOCKED ==
|
||||||
|
PTE_ATOMIC_COMPARE_EXCHANGE (&(s->interlock),
|
||||||
|
PTE_SPIN_LOCKED,
|
||||||
|
PTE_SPIN_UNLOCKED))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->interlock == PTE_SPIN_LOCKED)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (s->interlock == PTE_SPIN_USE_MUTEX)
|
||||||
|
return pthread_mutex_lock (&(s->u.mutex));
|
||||||
|
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pthread_spin_trylock (pthread_spinlock_t * lock)
|
||||||
|
{
|
||||||
|
register pthread_spinlock_t s;
|
||||||
|
|
||||||
|
if (NULL == lock || NULL == *lock)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
if (*lock == PTHREAD_SPINLOCK_INITIALIZER)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result = pte_spinlock_check_need_init (lock)) != 0)
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
s = *lock;
|
||||||
|
|
||||||
|
switch ((long)
|
||||||
|
PTE_ATOMIC_COMPARE_EXCHANGE (&(s->interlock),
|
||||||
|
PTE_SPIN_LOCKED,
|
||||||
|
PTE_SPIN_UNLOCKED))
|
||||||
|
{
|
||||||
|
case PTE_SPIN_UNLOCKED:
|
||||||
|
return 0;
|
||||||
|
case PTE_SPIN_LOCKED:
|
||||||
|
return EBUSY;
|
||||||
|
case PTE_SPIN_USE_MUTEX:
|
||||||
|
return pthread_mutex_trylock (&(s->u.mutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pthread_spin_unlock (pthread_spinlock_t * lock)
|
||||||
|
{
|
||||||
|
register pthread_spinlock_t s;
|
||||||
|
|
||||||
|
if (NULL == lock || NULL == *lock)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
s = *lock;
|
||||||
|
|
||||||
|
if (s == PTHREAD_SPINLOCK_INITIALIZER)
|
||||||
|
return EPERM;
|
||||||
|
|
||||||
|
switch ((long)
|
||||||
|
PTE_ATOMIC_COMPARE_EXCHANGE (&(s->interlock),
|
||||||
|
PTE_SPIN_UNLOCKED,
|
||||||
|
PTE_SPIN_LOCKED))
|
||||||
|
{
|
||||||
|
case PTE_SPIN_LOCKED:
|
||||||
|
return 0;
|
||||||
|
case PTE_SPIN_UNLOCKED:
|
||||||
|
return EPERM;
|
||||||
|
case PTE_SPIN_USE_MUTEX:
|
||||||
|
return pthread_mutex_unlock (&(s->u.mutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINVAL;
|
||||||
|
}
|
101
deps/pthreads/sched.c
vendored
Normal file
101
deps/pthreads/sched.c
vendored
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* sched_setscheduler.c
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* POSIX thread functions that deal with thread scheduling.
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "pte_osal.h"
|
||||||
|
|
||||||
|
#include "pthread.h"
|
||||||
|
#include "implement.h"
|
||||||
|
#include "sched.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
sched_setscheduler (pid_t pid, int policy)
|
||||||
|
{
|
||||||
|
errno = EPERM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sched_yield (void)
|
||||||
|
/*
|
||||||
|
* ------------------------------------------------------
|
||||||
|
* DOCPUBLIC
|
||||||
|
* This function indicates that the calling thread is
|
||||||
|
* willing to give up some time slices to other threads.
|
||||||
|
*
|
||||||
|
* PARAMETERS
|
||||||
|
* N/A
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* DESCRIPTION
|
||||||
|
* This function indicates that the calling thread is
|
||||||
|
* willing to give up some time slices to other threads.
|
||||||
|
* NOTE: Since this is part of POSIX 1003.1b
|
||||||
|
* (realtime extensions), it is defined as returning
|
||||||
|
* -1 if an error occurs and sets errno to the actual
|
||||||
|
* error.
|
||||||
|
*
|
||||||
|
* RESULTS
|
||||||
|
* 0 successfully created semaphore,
|
||||||
|
* ENOSYS sched_yield not supported,
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
pte_osThreadSleep (1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sched_get_priority_min (int policy)
|
||||||
|
{
|
||||||
|
return pte_osThreadGetMinPriority();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sched_get_priority_max (int policy)
|
||||||
|
{
|
||||||
|
return pte_osThreadGetMaxPriority();
|
||||||
|
}
|
137
deps/pthreads/sched.h
vendored
Normal file
137
deps/pthreads/sched.h
vendored
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
* Module: sched.h
|
||||||
|
*
|
||||||
|
* Purpose:
|
||||||
|
* Provides an implementation of POSIX realtime extensions
|
||||||
|
* as defined in
|
||||||
|
*
|
||||||
|
* POSIX 1003.1b-1993 (POSIX.1b)
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
#ifndef _SCHED_H
|
||||||
|
#define _SCHED_H
|
||||||
|
|
||||||
|
#include <pte_types.h>
|
||||||
|
|
||||||
|
#undef PTE_LEVEL
|
||||||
|
|
||||||
|
#if defined(_POSIX_SOURCE)
|
||||||
|
#define PTE_LEVEL 0
|
||||||
|
/* Early POSIX */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309
|
||||||
|
#undef PTE_LEVEL
|
||||||
|
#define PTE_LEVEL 1
|
||||||
|
/* Include 1b, 1c and 1d */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(INCLUDE_NP)
|
||||||
|
#undef PTE_LEVEL
|
||||||
|
#define PTE_LEVEL 2
|
||||||
|
/* Include Non-Portable extensions */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PTE_LEVEL_MAX 3
|
||||||
|
|
||||||
|
#if !defined(PTE_LEVEL)
|
||||||
|
#define PTE_LEVEL PTE_LEVEL_MAX
|
||||||
|
/* Include everything */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Thread scheduling policies */
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SCHED_OTHER = 0,
|
||||||
|
SCHED_FIFO,
|
||||||
|
SCHED_RR,
|
||||||
|
SCHED_MIN = SCHED_OTHER,
|
||||||
|
SCHED_MAX = SCHED_RR
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sched_param
|
||||||
|
{
|
||||||
|
int sched_priority;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
int sched_yield (void);
|
||||||
|
|
||||||
|
int sched_get_priority_min (int policy);
|
||||||
|
|
||||||
|
int sched_get_priority_max (int policy);
|
||||||
|
|
||||||
|
int sched_setscheduler (pid_t pid, int policy);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that this macro returns ENOTSUP rather than
|
||||||
|
* ENOSYS as might be expected. However, returning ENOSYS
|
||||||
|
* should mean that sched_get_priority_{min,max} are
|
||||||
|
* not implemented as well as sched_rr_get_interval.
|
||||||
|
* This is not the case, since we just don't support
|
||||||
|
* round-robin scheduling. Therefore I have chosen to
|
||||||
|
* return the same value as sched_setscheduler when
|
||||||
|
* SCHED_RR is passed to it.
|
||||||
|
*/
|
||||||
|
#define sched_rr_get_interval(_pid, _interval) \
|
||||||
|
( errno = ENOTSUP, (int) -1 )
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* End of extern "C" */
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#undef PTE_LEVEL
|
||||||
|
#undef PTE_LEVEL_MAX
|
||||||
|
|
||||||
|
#endif /* !_SCHED_H */
|
||||||
|
|
895
deps/pthreads/sem.c
vendored
Normal file
895
deps/pthreads/sem.c
vendored
Normal file
@ -0,0 +1,895 @@
|
|||||||
|
/*
|
||||||
|
* -------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Module: sem.c
|
||||||
|
*
|
||||||
|
* Purpose:
|
||||||
|
* Semaphores aren't actually part of the PThreads standard.
|
||||||
|
* They are defined by the POSIX Standard:
|
||||||
|
*
|
||||||
|
* POSIX 1003.1b-1993 (POSIX.1b)
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <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
deps/pthreads/semaphore.h
vendored
Normal file
114
deps/pthreads/semaphore.h
vendored
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Module: semaphore.h
|
||||||
|
*
|
||||||
|
* Purpose:
|
||||||
|
* Semaphores aren't actually part of the PThreads standard.
|
||||||
|
* They are defined by the POSIX Standard:
|
||||||
|
*
|
||||||
|
* POSIX 1003.1b-1993 (POSIX.1b)
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
|
||||||
|
* Copyright(C) 2008 Jason Schmidlapp
|
||||||
|
*
|
||||||
|
* Contact Email: jschmidlapp@users.sourceforge.net
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Based upon Pthreads-win32 - POSIX Threads Library for Win32
|
||||||
|
* Copyright(C) 1998 John E. Bossom
|
||||||
|
* Copyright(C) 1999,2005 Pthreads-win32 contributors
|
||||||
|
*
|
||||||
|
* Contact Email: rpj@callisto.canberra.edu.au
|
||||||
|
*
|
||||||
|
* The original list of contributors to the Pthreads-win32 project
|
||||||
|
* is contained in the file CONTRIBUTORS.ptw32 included with the
|
||||||
|
* source code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library in the file COPYING.LIB;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined( SEMAPHORE_H )
|
||||||
|
#define SEMAPHORE_H
|
||||||
|
|
||||||
|
#if defined(_POSIX_SOURCE)
|
||||||
|
#define PTE_LEVEL 0
|
||||||
|
/* Early POSIX */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(INCLUDE_NP)
|
||||||
|
#undef PTE_LEVEL
|
||||||
|
#define PTE_LEVEL 2
|
||||||
|
/* Include Non-Portable extensions */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _POSIX_SEMAPHORES
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct sem_t_ * sem_t;
|
||||||
|
|
||||||
|
int sem_init (sem_t * sem,
|
||||||
|
int pshared,
|
||||||
|
unsigned int value);
|
||||||
|
|
||||||
|
int sem_destroy (sem_t * sem);
|
||||||
|
|
||||||
|
int sem_trywait (sem_t * sem);
|
||||||
|
|
||||||
|
int sem_wait (sem_t * sem);
|
||||||
|
|
||||||
|
int sem_timedwait (sem_t * sem,
|
||||||
|
const struct timespec * abstime);
|
||||||
|
|
||||||
|
int sem_post (sem_t * sem);
|
||||||
|
|
||||||
|
int sem_post_multiple (sem_t * sem,
|
||||||
|
int count);
|
||||||
|
|
||||||
|
int sem_open (const char * name,
|
||||||
|
int oflag,
|
||||||
|
mode_t mode,
|
||||||
|
unsigned int value);
|
||||||
|
|
||||||
|
int sem_close (sem_t * sem);
|
||||||
|
|
||||||
|
int sem_unlink (const char * name);
|
||||||
|
|
||||||
|
int sem_getvalue (sem_t * sem,
|
||||||
|
int * sval);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* End of extern "C" */
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif /* !SEMAPHORE_H */
|
5
deps/stb/stb_truetype.h
vendored
5
deps/stb/stb_truetype.h
vendored
@ -2428,8 +2428,9 @@ STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels,
|
|||||||
stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y,
|
stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y,
|
||||||
float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)
|
float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)
|
||||||
{
|
{
|
||||||
float scale = scale_x > scale_y ? scale_y : scale_x;
|
float scale = scale_x > scale_y ? scale_y : scale_x;
|
||||||
int winding_count, *winding_lengths;
|
int winding_count = 0;
|
||||||
|
int *winding_lengths = NULL;
|
||||||
stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
|
stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
|
||||||
if (windings)
|
if (windings)
|
||||||
{
|
{
|
||||||
|
@ -73,6 +73,7 @@ elif [ $PLATFORM = "dex-ps3" ] ; then
|
|||||||
platform=ps3
|
platform=ps3
|
||||||
SALAMANDER=yes
|
SALAMANDER=yes
|
||||||
EXT=a
|
EXT=a
|
||||||
|
OPTS=DEX_BUILD=1
|
||||||
|
|
||||||
EXE_PATH=${CELL_SDK}/host-win32/bin
|
EXE_PATH=${CELL_SDK}/host-win32/bin
|
||||||
MAKE_FSELF_NPDRM=${EXE_PATH}/make_fself_npdrm.exe
|
MAKE_FSELF_NPDRM=${EXE_PATH}/make_fself_npdrm.exe
|
||||||
@ -84,6 +85,7 @@ elif [ $PLATFORM = "cex-ps3" ]; then
|
|||||||
platform=ps3
|
platform=ps3
|
||||||
SALAMANDER=yes
|
SALAMANDER=yes
|
||||||
EXT=a
|
EXT=a
|
||||||
|
OPTS=CEX_BUILD=1
|
||||||
|
|
||||||
EXE_PATH=${CELL_SDK}/host-win32/bin
|
EXE_PATH=${CELL_SDK}/host-win32/bin
|
||||||
SCETOOL_PATH=${PS3TOOLS_PATH}/scetool/scetool.exe
|
SCETOOL_PATH=${PS3TOOLS_PATH}/scetool/scetool.exe
|
||||||
@ -98,6 +100,7 @@ elif [ $PLATFORM = "ode-ps3" ]; then
|
|||||||
platform=ps3
|
platform=ps3
|
||||||
SALAMANDER=yes
|
SALAMANDER=yes
|
||||||
EXT=a
|
EXT=a
|
||||||
|
OPTS=ODE_BUILD=1
|
||||||
|
|
||||||
EXE_PATH=${CELL_SDK}/host-win32/bin
|
EXE_PATH=${CELL_SDK}/host-win32/bin
|
||||||
GENPS3ISO_PATH=${PS3TOOLS_PATH}/ODE/genps3iso_v2.5
|
GENPS3ISO_PATH=${PS3TOOLS_PATH}/ODE/genps3iso_v2.5
|
||||||
@ -124,7 +127,7 @@ fi
|
|||||||
|
|
||||||
# Compile Salamander core
|
# Compile Salamander core
|
||||||
if [ $SALAMANDER = "yes" ]; then
|
if [ $SALAMANDER = "yes" ]; then
|
||||||
make -C ../ -f Makefile.${platform}.salamander || exit 1
|
make -C ../ -f Makefile.${platform}.salamander $OPTS || exit 1
|
||||||
if [ $PLATFORM = "psp1" ] ; then
|
if [ $PLATFORM = "psp1" ] ; then
|
||||||
mv -f ../EBOOT.PBP ../pkg/${platform}/EBOOT.PBP
|
mv -f ../EBOOT.PBP ../pkg/${platform}/EBOOT.PBP
|
||||||
fi
|
fi
|
||||||
@ -193,16 +196,16 @@ for f in `ls -v *_${platform}.${EXT}`; do
|
|||||||
|
|
||||||
# Compile core
|
# Compile core
|
||||||
if [ $MAKEFILE_GRIFFIN = "yes" ]; then
|
if [ $MAKEFILE_GRIFFIN = "yes" ]; then
|
||||||
make -C ../ -f Makefile.griffin platform=${platform} $whole_archive $big_stack -j3 || exit 1
|
make -C ../ -f Makefile.griffin $OPTS platform=${platform} $whole_archive $big_stack -j3 || exit 1
|
||||||
elif [ $PLATFORM = "emscripten" ]; then
|
elif [ $PLATFORM = "emscripten" ]; then
|
||||||
echo "BUILD COMMAND: make -C ../ -f Makefile.emscripten PTHREAD=$pthread ASYNC=$async LTO=$lto -j7 TARGET=${name}_libretro.js"
|
echo "BUILD COMMAND: make -C ../ -f Makefile.emscripten PTHREAD=$pthread ASYNC=$async LTO=$lto -j7 TARGET=${name}_libretro.js"
|
||||||
make -C ../ -f Makefile.emscripten PTHREAD=$pthread ASYNC=$async LTO=$lto -j7 TARGET=${name}_libretro.js || exit 1
|
make -C ../ -f Makefile.emscripten $OPTS PTHREAD=$pthread ASYNC=$async LTO=$lto -j7 TARGET=${name}_libretro.js || exit 1
|
||||||
elif [ $PLATFORM = "unix" ]; then
|
elif [ $PLATFORM = "unix" ]; then
|
||||||
make -C ../ -f Makefile LINK=g++ $whole_archive $big_stack -j3 || exit 1
|
make -C ../ -f Makefile LINK=g++ $whole_archive $big_stack -j3 || exit 1
|
||||||
elif [ $PLATFORM = "ctr" ]; then
|
elif [ $PLATFORM = "ctr" ]; then
|
||||||
make -C ../ -f Makefile.${platform} LIBRETRO=$name $whole_archive $big_stack -j3 || exit 1
|
make -C ../ -f Makefile.${platform} $OPTS LIBRETRO=$name $whole_archive $big_stack -j3 || exit 1
|
||||||
else
|
else
|
||||||
make -C ../ -f Makefile.${platform} $whole_archive $big_stack -j3 || exit 1
|
make -C ../ -f Makefile.${platform} $OPTS $whole_archive $big_stack -j3 || exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Do manual executable step
|
# Do manual executable step
|
||||||
@ -354,17 +357,20 @@ fi
|
|||||||
|
|
||||||
# Packaging
|
# Packaging
|
||||||
if [ $PLATFORM = "dex-ps3" ] ; then
|
if [ $PLATFORM = "dex-ps3" ] ; then
|
||||||
|
rsync -av ../pkg/${platform}/SSNE10000/USRDIR/cores/*.SELF ../pkg/${platform}/${PLATFORM}/
|
||||||
$MAKE_FSELF_NPDRM -c ../retroarch-salamander_${platform}.elf ../pkg/${platform}/SSNE10000/USRDIR/EBOOT.BIN
|
$MAKE_FSELF_NPDRM -c ../retroarch-salamander_${platform}.elf ../pkg/${platform}/SSNE10000/USRDIR/EBOOT.BIN
|
||||||
rm -rf ../retroarch-salamander_${platform}.elf
|
rm -rf ../retroarch-salamander_${platform}.elf
|
||||||
$MAKE_PACKAGE_NPDRM ../pkg/${platform}_dex/package.conf ../pkg/${platform}/SSNE10000
|
$MAKE_PACKAGE_NPDRM ../pkg/${platform}_dex/package.conf ../pkg/${platform}/SSNE10000
|
||||||
mv UP0001-SSNE10000_00-0000000000000001.pkg ../pkg/${platform}/RetroArch.PS3.DEX.PS3.pkg
|
mv UP0001-SSNE10000_00-0000000000000001.pkg ../pkg/${platform}/RetroArch.PS3.DEX.PS3.pkg
|
||||||
elif [ $PLATFORM = "cex-ps3" ] ; then
|
elif [ $PLATFORM = "cex-ps3" ] ; then
|
||||||
|
rsync -av ../pkg/${platform}/SSNE10000/USRDIR/cores/*.SELF ../pkg/${platform}/${PLATFORM}/
|
||||||
$SCETOOL_PATH $SCETOOL_FLAGS_EBOOT ../retroarch-salamander_${platform}.elf ../pkg/${platform}/SSNE10000/USRDIR/EBOOT.BIN
|
$SCETOOL_PATH $SCETOOL_FLAGS_EBOOT ../retroarch-salamander_${platform}.elf ../pkg/${platform}/SSNE10000/USRDIR/EBOOT.BIN
|
||||||
rm -rf ../retroarch-salamander_${platform}.elf
|
rm -rf ../retroarch-salamander_${platform}.elf
|
||||||
(cd ../tools/ps3/ps3py && python2 setup.py build)
|
(cd ../tools/ps3/ps3py && python2 setup.py build)
|
||||||
find ../tools/ps3/ps3py/build -name '*.dll' -exec cp {} ../tools/ps3/ps3py \;
|
find ../tools/ps3/ps3py/build -name '*.dll' -exec cp {} ../tools/ps3/ps3py \;
|
||||||
../tools/ps3/ps3py/pkg.py --contentid UP0001-SSNE10000_00-0000000000000001 ../pkg/${platform}/SSNE10000/ ../pkg/${platform}/RetroArch.PS3.CEX.PS3.pkg
|
../tools/ps3/ps3py/pkg.py --contentid UP0001-SSNE10000_00-0000000000000001 ../pkg/${platform}/SSNE10000/ ../pkg/${platform}/RetroArch.PS3.CEX.PS3.pkg
|
||||||
elif [ $PLATFORM = "ode-ps3" ] ; then
|
elif [ $PLATFORM = "ode-ps3" ] ; then
|
||||||
|
rsync -av ../pkg/${platform}_iso/PS3_GAME/USRDIR/cores/*.SELF ../pkg/${platform}/${PLATFORM}/
|
||||||
$SCETOOL_PATH $SCETOOL_FLAGS_ODE ../retroarch-salamander_${platform}.elf ../pkg/${platform}_iso/PS3_GAME/USRDIR/EBOOT.BIN
|
$SCETOOL_PATH $SCETOOL_FLAGS_ODE ../retroarch-salamander_${platform}.elf ../pkg/${platform}_iso/PS3_GAME/USRDIR/EBOOT.BIN
|
||||||
rm -rf ../retroarch-salamander_${platform}.elf
|
rm -rf ../retroarch-salamander_${platform}.elf
|
||||||
|
|
||||||
|
@ -13,6 +13,14 @@
|
|||||||
* If not, see <http://www.gnu.org/licenses/>.
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Assume W-functions do not work below Win2K and Xbox platforms */
|
||||||
|
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
|
||||||
|
|
||||||
|
#ifndef LEGACY_WIN32
|
||||||
|
#define LEGACY_WIN32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
@ -45,6 +53,7 @@
|
|||||||
#include <compat/posix_string.h>
|
#include <compat/posix_string.h>
|
||||||
#include <retro_assert.h>
|
#include <retro_assert.h>
|
||||||
#include <retro_miscellaneous.h>
|
#include <retro_miscellaneous.h>
|
||||||
|
#include <encodings/utf.h>
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -171,6 +180,7 @@ void fill_pathname_abbreviate_special(char *out_path,
|
|||||||
bool fill_pathname_application_data(char *s, size_t len)
|
bool fill_pathname_application_data(char *s, size_t len)
|
||||||
{
|
{
|
||||||
#if defined(_WIN32) && !defined(_XBOX)
|
#if defined(_WIN32) && !defined(_XBOX)
|
||||||
|
#ifdef LEGACY_WIN32
|
||||||
const char *appdata = getenv("APPDATA");
|
const char *appdata = getenv("APPDATA");
|
||||||
|
|
||||||
if (appdata)
|
if (appdata)
|
||||||
@ -178,6 +188,21 @@ bool fill_pathname_application_data(char *s, size_t len)
|
|||||||
strlcpy(s, appdata, len);
|
strlcpy(s, appdata, len);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
const wchar_t *appdataW = _wgetenv(L"APPDATA");
|
||||||
|
|
||||||
|
if (appdataW)
|
||||||
|
{
|
||||||
|
char *appdata = utf16_to_utf8_string_alloc(appdataW);
|
||||||
|
|
||||||
|
if (appdata)
|
||||||
|
{
|
||||||
|
strlcpy(s, appdata, len);
|
||||||
|
free(appdata);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#elif defined(OSX)
|
#elif defined(OSX)
|
||||||
const char *appdata = getenv("HOME");
|
const char *appdata = getenv("HOME");
|
||||||
@ -224,7 +249,8 @@ void fill_pathname_application_path(char *s, size_t len)
|
|||||||
#endif
|
#endif
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
DWORD ret;
|
DWORD ret;
|
||||||
wchar_t ws[PATH_MAX_LENGTH] = {0};
|
char *str;
|
||||||
|
wchar_t wstr[PATH_MAX_LENGTH] = {0};
|
||||||
#endif
|
#endif
|
||||||
#ifdef __HAIKU__
|
#ifdef __HAIKU__
|
||||||
image_info info;
|
image_info info;
|
||||||
@ -236,7 +262,22 @@ void fill_pathname_application_path(char *s, size_t len)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
ret = GetModuleFileName(GetModuleHandle(NULL), s, len - 1);
|
#ifdef LEGACY_WIN32
|
||||||
|
ret = GetModuleFileNameA(GetModuleHandle(NULL), s, len);
|
||||||
|
#else
|
||||||
|
ret = GetModuleFileNameW(GetModuleHandle(NULL), wstr, ARRAY_SIZE(wstr));
|
||||||
|
|
||||||
|
if (*wstr)
|
||||||
|
{
|
||||||
|
str = utf16_to_utf8_string_alloc(wstr);
|
||||||
|
|
||||||
|
if (str)
|
||||||
|
{
|
||||||
|
strlcpy(s, str, len);
|
||||||
|
free(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
s[ret] = '\0';
|
s[ret] = '\0';
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
if (bundle)
|
if (bundle)
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static enum frontend_fork ctr_fork_mode = FRONTEND_FORK_NONE;
|
static enum frontend_fork ctr_fork_mode = FRONTEND_FORK_NONE;
|
||||||
static const char* elf_path_cst = "sdmc:/retroarch/test.3dsx";
|
static const char* elf_path_cst = "sdmc:/retroarch/test.3dsx";
|
||||||
|
|
||||||
static void frontend_ctr_get_environment_settings(int *argc, char *argv[],
|
static void frontend_ctr_get_environment_settings(int *argc, char *argv[],
|
||||||
void *args, void *params_data)
|
void *args, void *params_data)
|
||||||
@ -151,7 +151,7 @@ static void frontend_ctr_exec(const char *path, bool should_load_game)
|
|||||||
DEBUG_STR(path);
|
DEBUG_STR(path);
|
||||||
|
|
||||||
strlcpy(param.args, elf_path_cst, sizeof(param.args));
|
strlcpy(param.args, elf_path_cst, sizeof(param.args));
|
||||||
len = strlen(param.args) + 1;
|
len = strlen(param.args) + 1;
|
||||||
param.argc = 1;
|
param.argc = 1;
|
||||||
|
|
||||||
RARCH_LOG("Attempt to load core: [%s].\n", path);
|
RARCH_LOG("Attempt to load core: [%s].\n", path);
|
||||||
@ -172,11 +172,13 @@ static void frontend_ctr_exec(const char *path, bool should_load_game)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u32 app_ID_low;
|
|
||||||
char app_ID_str[11];
|
char app_ID_str[11];
|
||||||
FILE* fp = fopen(path, "rb");
|
u32 app_ID_low = 0;
|
||||||
|
FILE* fp = fopen(path, "rb");
|
||||||
size_t bytes_read = fread(app_ID_str, 1, sizeof(app_ID_str), fp);
|
size_t bytes_read = fread(app_ID_str, 1, sizeof(app_ID_str), fp);
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
if(bytes_read <= 0)
|
if(bytes_read <= 0)
|
||||||
{
|
{
|
||||||
RARCH_LOG("error reading APP_ID from: [%s].\n", path);
|
RARCH_LOG("error reading APP_ID from: [%s].\n", path);
|
||||||
@ -356,16 +358,11 @@ static void frontend_ctr_init(void *data)
|
|||||||
}
|
}
|
||||||
osSetSpeedupEnable(true);
|
osSetSpeedupEnable(true);
|
||||||
|
|
||||||
audio_driver_t* dsp_audio_driver = &audio_ctr_dsp;
|
|
||||||
if(csndInit() != 0)
|
if(csndInit() != 0)
|
||||||
{
|
audio_ctr_csnd = audio_null;
|
||||||
dsp_audio_driver = &audio_ctr_csnd;
|
|
||||||
audio_ctr_csnd = audio_ctr_dsp;
|
|
||||||
audio_ctr_dsp = audio_null;
|
|
||||||
}
|
|
||||||
ctr_check_dspfirm();
|
ctr_check_dspfirm();
|
||||||
if(ndspInit() != 0)
|
if(ndspInit() != 0)
|
||||||
*dsp_audio_driver = audio_null;
|
audio_ctr_dsp = audio_null;
|
||||||
cfguInit();
|
cfguInit();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -254,6 +254,15 @@ static void frontend_ps3_get_environment_settings(int *argc, char *argv[],
|
|||||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST],
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST],
|
||||||
g_defaults.dirs[DEFAULT_DIR_CORE],
|
g_defaults.dirs[DEFAULT_DIR_CORE],
|
||||||
"playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST]));
|
"playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST]));
|
||||||
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS],
|
||||||
|
g_defaults.dirs[DEFAULT_DIR_CORE],
|
||||||
|
"downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS]));
|
||||||
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CHEATS],
|
||||||
|
g_defaults.dirs[DEFAULT_DIR_CORE], "cheats",
|
||||||
|
sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS]));
|
||||||
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG],
|
||||||
|
g_defaults.dirs[DEFAULT_DIR_CORE],
|
||||||
|
"autoconfig", sizeof(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG]));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef IS_SALAMANDER
|
#ifndef IS_SALAMANDER
|
||||||
|
@ -124,8 +124,8 @@ static void dol_copy_argv_path(const char *dolpath, const char *argpath)
|
|||||||
* heap memory and are restricted to the stack only. */
|
* heap memory and are restricted to the stack only. */
|
||||||
void system_exec_wii(const char *_path, bool should_load_game)
|
void system_exec_wii(const char *_path, bool should_load_game)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
|
||||||
size_t size, booter_size;
|
size_t size, booter_size;
|
||||||
|
FILE *fp = NULL;
|
||||||
void *dol = NULL;
|
void *dol = NULL;
|
||||||
char path[PATH_MAX_LENGTH] = {0};
|
char path[PATH_MAX_LENGTH] = {0};
|
||||||
char game_path[PATH_MAX_LENGTH] = {0};
|
char game_path[PATH_MAX_LENGTH] = {0};
|
||||||
|
@ -188,8 +188,8 @@ static void frontend_wiiu_exec(const char *path, bool should_load_game)
|
|||||||
u32 argc;
|
u32 argc;
|
||||||
char * argv[3];
|
char * argv[3];
|
||||||
char args[];
|
char args[];
|
||||||
}*param = getApplicationEndAddr();
|
}*param = getApplicationEndAddr();
|
||||||
int len = 0;
|
int len = 0;
|
||||||
param->argc = 0;
|
param->argc = 0;
|
||||||
|
|
||||||
if(!path || !*path)
|
if(!path || !*path)
|
||||||
@ -395,7 +395,7 @@ static devoptab_t dotab_stdout =
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void SaveCallback()
|
void SaveCallback(void)
|
||||||
{
|
{
|
||||||
OSSavesDone_ReadyToRelease();
|
OSSavesDone_ReadyToRelease();
|
||||||
}
|
}
|
||||||
@ -517,7 +517,7 @@ unsigned long _times_r(struct _reent *r, struct tms *tmsbuf)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __eabi()
|
void __eabi(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -556,7 +556,7 @@ void someFunc(void *arg)
|
|||||||
|
|
||||||
static int mcp_hook_fd = -1;
|
static int mcp_hook_fd = -1;
|
||||||
|
|
||||||
int MCPHookOpen()
|
int MCPHookOpen(void)
|
||||||
{
|
{
|
||||||
//take over mcp thread
|
//take over mcp thread
|
||||||
mcp_hook_fd = IOS_Open("/dev/mcp", 0);
|
mcp_hook_fd = IOS_Open("/dev/mcp", 0);
|
||||||
@ -578,7 +578,7 @@ int MCPHookOpen()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MCPHookClose()
|
void MCPHookClose(void)
|
||||||
{
|
{
|
||||||
if (mcp_hook_fd < 0)
|
if (mcp_hook_fd < 0)
|
||||||
return;
|
return;
|
||||||
@ -630,12 +630,14 @@ static void fsdev_exit(void)
|
|||||||
/* HBL elf entry point */
|
/* HBL elf entry point */
|
||||||
int __entry_menu(int argc, char **argv)
|
int __entry_menu(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
InitFunctionPointers();
|
InitFunctionPointers();
|
||||||
memoryInitialize();
|
memoryInitialize();
|
||||||
__init();
|
__init();
|
||||||
fsdev_init();
|
fsdev_init();
|
||||||
|
|
||||||
int ret = main(argc, argv);
|
ret = main(argc, argv);
|
||||||
|
|
||||||
fsdev_exit();
|
fsdev_exit();
|
||||||
__fini();
|
__fini();
|
||||||
@ -654,9 +656,11 @@ void _start(int argc, char **argv)
|
|||||||
|
|
||||||
fsdev_exit();
|
fsdev_exit();
|
||||||
|
|
||||||
/* TODO: fix elf2rpl so it doesn't error with "Could not find matching symbol
|
/* TODO: fix elf2rpl so it doesn't error with "Could not find matching symbol
|
||||||
for relocation" then uncomment this */
|
for relocation" then uncomment this */
|
||||||
// __fini();
|
#if 0
|
||||||
|
__fini();
|
||||||
|
#endif
|
||||||
memoryRelease();
|
memoryRelease();
|
||||||
SYSRelaunchTitle(0, 0);
|
SYSRelaunchTitle(0, 0);
|
||||||
exit(0);
|
exit(0);
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <wiiu/gx2.h>
|
#include <wiiu/gx2.h>
|
||||||
|
|
||||||
#include "wiiu/tex_shader.h"
|
#include "wiiu/tex_shader.h"
|
||||||
|
|
||||||
|
|
||||||
#undef _X
|
#undef _X
|
||||||
#undef _B
|
#undef _B
|
||||||
|
|
||||||
@ -35,13 +32,21 @@ typedef struct
|
|||||||
{
|
{
|
||||||
float x;
|
float x;
|
||||||
float y;
|
float y;
|
||||||
}position_t;
|
} position_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
float u;
|
float u;
|
||||||
float v;
|
float v;
|
||||||
}tex_coord_t;
|
} tex_coord_t;
|
||||||
|
|
||||||
|
struct gx2_overlay_data
|
||||||
|
{
|
||||||
|
GX2Texture tex;
|
||||||
|
float tex_coord[8];
|
||||||
|
float vertex_coord[8];
|
||||||
|
float alpha_mod;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -56,6 +61,13 @@ typedef struct
|
|||||||
tex_coord_t* tex_coord;
|
tex_coord_t* tex_coord;
|
||||||
} menu;
|
} menu;
|
||||||
|
|
||||||
|
#ifdef HAVE_OVERLAY
|
||||||
|
struct gx2_overlay_data *overlay;
|
||||||
|
unsigned overlays;
|
||||||
|
bool overlay_enable;
|
||||||
|
bool overlay_full_screen;
|
||||||
|
#endif
|
||||||
|
|
||||||
GX2Sampler sampler_nearest;
|
GX2Sampler sampler_nearest;
|
||||||
GX2Sampler sampler_linear;
|
GX2Sampler sampler_linear;
|
||||||
GX2Texture texture;
|
GX2Texture texture;
|
||||||
@ -70,7 +82,7 @@ typedef struct
|
|||||||
tex_coord_t* tex_coords;
|
tex_coord_t* tex_coords;
|
||||||
int size;
|
int size;
|
||||||
int current;
|
int current;
|
||||||
}vertex_cache;
|
} vertex_cache;
|
||||||
|
|
||||||
void* drc_scan_buffer;
|
void* drc_scan_buffer;
|
||||||
void* tv_scan_buffer;
|
void* tv_scan_buffer;
|
||||||
@ -89,5 +101,4 @@ typedef struct
|
|||||||
bool keep_aspect;
|
bool keep_aspect;
|
||||||
bool should_resize;
|
bool should_resize;
|
||||||
bool render_msg_enabled;
|
bool render_msg_enabled;
|
||||||
|
|
||||||
} wiiu_video_t;
|
} wiiu_video_t;
|
||||||
|
@ -86,8 +86,8 @@ bool g_restore_desktop = false;
|
|||||||
static bool doubleclick_on_titlebar = false;
|
static bool doubleclick_on_titlebar = false;
|
||||||
bool g_inited = false;
|
bool g_inited = false;
|
||||||
static bool g_quit = false;
|
static bool g_quit = false;
|
||||||
static unsigned g_pos_x = CW_USEDEFAULT;
|
static int g_pos_x = CW_USEDEFAULT;
|
||||||
static unsigned g_pos_y = CW_USEDEFAULT;
|
static int g_pos_y = CW_USEDEFAULT;
|
||||||
static void *curD3D = NULL;
|
static void *curD3D = NULL;
|
||||||
|
|
||||||
ui_window_win32_t main_window;
|
ui_window_win32_t main_window;
|
||||||
@ -513,7 +513,11 @@ static LRESULT CALLBACK WndProcCommon(bool *quit, HWND hwnd, UINT message,
|
|||||||
case WM_QUIT:
|
case WM_QUIT:
|
||||||
{
|
{
|
||||||
WINDOWPLACEMENT placement;
|
WINDOWPLACEMENT placement;
|
||||||
|
memset(&placement, 0, sizeof(placement));
|
||||||
|
placement.length = sizeof(placement);
|
||||||
|
|
||||||
GetWindowPlacement(main_window.hwnd, &placement);
|
GetWindowPlacement(main_window.hwnd, &placement);
|
||||||
|
|
||||||
g_pos_x = placement.rcNormalPosition.left;
|
g_pos_x = placement.rcNormalPosition.left;
|
||||||
g_pos_y = placement.rcNormalPosition.top;
|
g_pos_y = placement.rcNormalPosition.top;
|
||||||
g_quit = true;
|
g_quit = true;
|
||||||
|
@ -109,7 +109,7 @@ void x11_show_mouse(Display *dpy, Window win, bool state)
|
|||||||
|
|
||||||
void x11_windowed_fullscreen(Display *dpy, Window win)
|
void x11_windowed_fullscreen(Display *dpy, Window win)
|
||||||
{
|
{
|
||||||
XEvent xev = {0};
|
XEvent xev = {0};
|
||||||
|
|
||||||
XA_NET_WM_STATE = XInternAtom(dpy, "_NET_WM_STATE", False);
|
XA_NET_WM_STATE = XInternAtom(dpy, "_NET_WM_STATE", False);
|
||||||
XA_NET_WM_STATE_FULLSCREEN = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
|
XA_NET_WM_STATE_FULLSCREEN = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
|
||||||
@ -132,7 +132,7 @@ void x11_windowed_fullscreen(Display *dpy, Window win)
|
|||||||
void x11_move_window(Display *dpy, Window win, int x, int y,
|
void x11_move_window(Display *dpy, Window win, int x, int y,
|
||||||
unsigned width, unsigned height)
|
unsigned width, unsigned height)
|
||||||
{
|
{
|
||||||
XEvent xev = {0};
|
XEvent xev = {0};
|
||||||
|
|
||||||
XA_NET_MOVERESIZE_WINDOW = XInternAtom(dpy, "_NET_MOVERESIZE_WINDOW", False);
|
XA_NET_MOVERESIZE_WINDOW = XInternAtom(dpy, "_NET_MOVERESIZE_WINDOW", False);
|
||||||
|
|
||||||
@ -162,9 +162,9 @@ static void x11_set_window_class(Display *dpy, Window win)
|
|||||||
|
|
||||||
static void x11_set_window_pid(Display *dpy, Window win)
|
static void x11_set_window_pid(Display *dpy, Window win)
|
||||||
{
|
{
|
||||||
long scret;
|
long scret = 0;
|
||||||
char *hostname;
|
char *hostname = NULL;
|
||||||
pid_t pid = getpid();
|
pid_t pid = getpid();
|
||||||
|
|
||||||
XChangeProperty(dpy, win, XInternAtom(dpy, "_NET_WM_PID", False),
|
XChangeProperty(dpy, win, XInternAtom(dpy, "_NET_WM_PID", False),
|
||||||
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&pid, 1);
|
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&pid, 1);
|
||||||
@ -238,9 +238,9 @@ static bool get_video_mode(video_frame_info_t *video_info,
|
|||||||
Display *dpy, unsigned width, unsigned height,
|
Display *dpy, unsigned width, unsigned height,
|
||||||
XF86VidModeModeInfo *mode, XF86VidModeModeInfo *desktop_mode)
|
XF86VidModeModeInfo *mode, XF86VidModeModeInfo *desktop_mode)
|
||||||
{
|
{
|
||||||
float refresh_mod;
|
|
||||||
int i, num_modes = 0;
|
int i, num_modes = 0;
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
float refresh_mod = 0.0f;
|
||||||
float minimum_fps_diff = 0.0f;
|
float minimum_fps_diff = 0.0f;
|
||||||
XF86VidModeModeInfo **modes = NULL;
|
XF86VidModeModeInfo **modes = NULL;
|
||||||
|
|
||||||
@ -386,15 +386,15 @@ bool x11_get_metrics(void *data,
|
|||||||
static void x11_handle_key_event(XEvent *event, XIC ic, bool filter)
|
static void x11_handle_key_event(XEvent *event, XIC ic, bool filter)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned key;
|
|
||||||
uint32_t chars[32];
|
uint32_t chars[32];
|
||||||
|
unsigned key = 0;
|
||||||
uint16_t mod = 0;
|
uint16_t mod = 0;
|
||||||
unsigned state = event->xkey.state;
|
unsigned state = event->xkey.state;
|
||||||
bool down = event->type == KeyPress;
|
bool down = event->type == KeyPress;
|
||||||
int num = 0;
|
int num = 0;
|
||||||
KeySym keysym = 0;
|
KeySym keysym = 0;
|
||||||
|
|
||||||
chars[0] = '\0';
|
chars[0] = '\0';
|
||||||
|
|
||||||
if (!filter)
|
if (!filter)
|
||||||
{
|
{
|
||||||
|
@ -28,6 +28,9 @@ static void* win32_display_server_init(void)
|
|||||||
{
|
{
|
||||||
dispserv_win32_t *dispserv = (dispserv_win32_t*)calloc(1, sizeof(*dispserv));
|
dispserv_win32_t *dispserv = (dispserv_win32_t*)calloc(1, sizeof(*dispserv));
|
||||||
|
|
||||||
|
if (!dispserv)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
return dispserv;
|
return dispserv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,17 +41,17 @@ static void win32_display_server_destroy(void)
|
|||||||
|
|
||||||
static bool win32_set_window_opacity(void *data, unsigned opacity)
|
static bool win32_set_window_opacity(void *data, unsigned opacity)
|
||||||
{
|
{
|
||||||
HWND hwnd = win32_get_window();
|
HWND hwnd = win32_get_window();
|
||||||
dispserv_win32_t *serv = (dispserv_win32_t*)data;
|
dispserv_win32_t *serv = (dispserv_win32_t*)data;
|
||||||
|
|
||||||
serv->opacity = opacity;
|
serv->opacity = opacity;
|
||||||
|
|
||||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
|
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
|
||||||
/* Set window transparency on Windows 2000 and above */
|
/* Set window transparency on Windows 2000 and above */
|
||||||
return SetLayeredWindowAttributes(hwnd, 0, (255 * opacity) / 100, LWA_ALPHA);
|
if (SetLayeredWindowAttributes(hwnd, 0, (255 * opacity) / 100, LWA_ALPHA))
|
||||||
#else
|
return true;
|
||||||
return false;
|
|
||||||
#endif
|
#endif
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const video_display_server_t dispserv_win32 = {
|
const video_display_server_t dispserv_win32 = {
|
||||||
|
@ -28,6 +28,9 @@ static void* x11_display_server_init(void)
|
|||||||
{
|
{
|
||||||
dispserv_x11_t *dispserv = (dispserv_x11_t*)calloc(1, sizeof(*dispserv));
|
dispserv_x11_t *dispserv = (dispserv_x11_t*)calloc(1, sizeof(*dispserv));
|
||||||
|
|
||||||
|
if (!dispserv)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
return dispserv;
|
return dispserv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,13 +42,13 @@ static void x11_display_server_destroy(void)
|
|||||||
static bool x11_set_window_opacity(void *data, unsigned opacity)
|
static bool x11_set_window_opacity(void *data, unsigned opacity)
|
||||||
{
|
{
|
||||||
dispserv_x11_t *serv = (dispserv_x11_t*)data;
|
dispserv_x11_t *serv = (dispserv_x11_t*)data;
|
||||||
Atom net_wm_opacity = XInternAtom(g_x11_dpy, "_NET_WM_WINDOW_OPACITY", False);
|
Atom net_wm_opacity = XInternAtom(g_x11_dpy, "_NET_WM_WINDOW_OPACITY", False);
|
||||||
Atom cardinal = XInternAtom(g_x11_dpy, "CARDINAL", False);
|
Atom cardinal = XInternAtom(g_x11_dpy, "CARDINAL", False);
|
||||||
settings_t *settings = config_get_ptr();
|
settings_t *settings = config_get_ptr();
|
||||||
|
|
||||||
serv->opacity = opacity;
|
serv->opacity = opacity;
|
||||||
|
|
||||||
opacity = opacity * ((unsigned)-1 / 100.0);
|
opacity = opacity * ((unsigned)-1 / 100.0);
|
||||||
|
|
||||||
if (opacity == (unsigned)-1)
|
if (opacity == (unsigned)-1)
|
||||||
XDeleteProperty(g_x11_dpy, g_x11_win, net_wm_opacity);
|
XDeleteProperty(g_x11_dpy, g_x11_win, net_wm_opacity);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user