|
fukasawa |
e60969 |
/* contrib/arm-neon/linux-auxv.c
|
|
fukasawa |
e60969 |
*
|
|
fukasawa |
e60969 |
* Copyright (c) 2014 Glenn Randers-Pehrson
|
|
fukasawa |
e60969 |
* Written by Mans Rullgard, 2011.
|
|
fukasawa |
e60969 |
* Last changed in libpng 1.6.10 [March 6, 2014]
|
|
fukasawa |
e60969 |
*
|
|
fukasawa |
e60969 |
* This code is released under the libpng license.
|
|
fukasawa |
e60969 |
* For conditions of distribution and use, see the disclaimer
|
|
fukasawa |
e60969 |
* and license in png.h
|
|
fukasawa |
e60969 |
*
|
|
fukasawa |
e60969 |
* SEE contrib/arm-neon/README before reporting bugs
|
|
fukasawa |
e60969 |
*
|
|
fukasawa |
e60969 |
* STATUS: COMPILED, TESTED
|
|
fukasawa |
e60969 |
* BUG REPORTS: png-mng-implement@sourceforge.net
|
|
fukasawa |
e60969 |
*
|
|
fukasawa |
e60969 |
* png_have_neon implemented for Linux versions which allow access to
|
|
fukasawa |
e60969 |
* /proc/self/auxv. This is probably faster, cleaner and safer than the code to
|
|
fukasawa |
e60969 |
* read /proc/cpuinfo in contrib/arm-neon/linux, however it is yet another piece
|
|
fukasawa |
e60969 |
* of potentially untested code and has more complex dependencies than the code
|
|
fukasawa |
e60969 |
* to read cpuinfo.
|
|
fukasawa |
e60969 |
*
|
|
fukasawa |
e60969 |
* This generic __linux__ implementation requires reading /proc/self/auxv and
|
|
fukasawa |
e60969 |
* looking at each element for one that records NEON capabilities.
|
|
fukasawa |
e60969 |
*/
|
|
fukasawa |
e60969 |
#include <unistd.h> /* for POSIX 1003.1 */</unistd.h>
|
|
fukasawa |
e60969 |
#include <errno.h> /* for EINTR */</errno.h>
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
#include <sys types.h=""></sys>
|
|
fukasawa |
e60969 |
#include <sys stat.h=""></sys>
|
|
fukasawa |
e60969 |
#include <fcntl.h></fcntl.h>
|
|
fukasawa |
e60969 |
#include <elf.h></elf.h>
|
|
fukasawa |
e60969 |
#include <asm hwcap.h=""></asm>
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
/* A read call may be interrupted, in which case it returns -1 and sets errno to
|
|
fukasawa |
e60969 |
* EINTR if nothing was done, otherwise (if something was done) a partial read
|
|
fukasawa |
e60969 |
* may result.
|
|
fukasawa |
e60969 |
*/
|
|
fukasawa |
e60969 |
static size_t
|
|
fukasawa |
e60969 |
safe_read(png_structp png_ptr, int fd, void *buffer_in, size_t nbytes)
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
size_t ntotal = 0;
|
|
fukasawa |
e60969 |
char *buffer = png_voidcast(char*, buffer_in);
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
while (nbytes > 0)
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
unsigned int nread;
|
|
fukasawa |
e60969 |
int iread;
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
/* Passing nread > INT_MAX to read is implementation defined in POSIX
|
|
fukasawa |
e60969 |
* 1003.1, therefore despite the unsigned argument portable code must
|
|
fukasawa |
e60969 |
* limit the value to INT_MAX!
|
|
fukasawa |
e60969 |
*/
|
|
fukasawa |
e60969 |
if (nbytes > INT_MAX)
|
|
fukasawa |
e60969 |
nread = INT_MAX;
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
else
|
|
fukasawa |
e60969 |
nread = (unsigned int)/*SAFE*/nbytes;
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
iread = read(fd, buffer, nread);
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
if (iread == -1)
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
/* This is the devil in the details, a read can terminate early with 0
|
|
fukasawa |
e60969 |
* bytes read because of EINTR, yet it still returns -1 otherwise end
|
|
fukasawa |
e60969 |
* of file cannot be distinguished.
|
|
fukasawa |
e60969 |
*/
|
|
fukasawa |
e60969 |
if (errno != EINTR)
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
png_warning(png_ptr, "/proc read failed");
|
|
fukasawa |
e60969 |
return 0; /* I.e., a permanent failure */
|
|
fukasawa |
e60969 |
}
|
|
fukasawa |
e60969 |
}
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
else if (iread < 0)
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
/* Not a valid 'read' result: */
|
|
fukasawa |
e60969 |
png_warning(png_ptr, "OS /proc read bug");
|
|
fukasawa |
e60969 |
return 0;
|
|
fukasawa |
e60969 |
}
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
else if (iread > 0)
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
/* Continue reading until a permanent failure, or EOF */
|
|
fukasawa |
e60969 |
buffer += iread;
|
|
fukasawa |
e60969 |
nbytes -= (unsigned int)/*SAFE*/iread;
|
|
fukasawa |
e60969 |
ntotal += (unsigned int)/*SAFE*/iread;
|
|
fukasawa |
e60969 |
}
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
else
|
|
fukasawa |
e60969 |
return ntotal;
|
|
fukasawa |
e60969 |
}
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
return ntotal; /* nbytes == 0 */
|
|
fukasawa |
e60969 |
}
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
static int
|
|
fukasawa |
e60969 |
png_have_neon(png_structp png_ptr)
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
int fd = open("/proc/self/auxv", O_RDONLY);
|
|
fukasawa |
e60969 |
Elf32_auxv_t aux;
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
/* Failsafe: failure to open means no NEON */
|
|
fukasawa |
e60969 |
if (fd == -1)
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
png_warning(png_ptr, "/proc/self/auxv open failed");
|
|
fukasawa |
e60969 |
return 0;
|
|
fukasawa |
e60969 |
}
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
while (safe_read(png_ptr, fd, &aux, sizeof aux) == sizeof aux)
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
if (aux.a_type == AT_HWCAP && (aux.a_un.a_val & HWCAP_NEON) != 0)
|
|
fukasawa |
e60969 |
{
|
|
fukasawa |
e60969 |
close(fd);
|
|
fukasawa |
e60969 |
return 1;
|
|
fukasawa |
e60969 |
}
|
|
fukasawa |
e60969 |
}
|
|
fukasawa |
e60969 |
|
|
fukasawa |
e60969 |
close(fd);
|
|
fukasawa |
e60969 |
return 0;
|
|
fukasawa |
e60969 |
}
|