(root)/
libpng-1.6.40/
contrib/
arm-neon/
linux-auxv.c
       1  /* contrib/arm-neon/linux-auxv.c
       2   *
       3   * Copyright (c) 2014 Glenn Randers-Pehrson
       4   * Written by Mans Rullgard, 2011.
       5   *
       6   * This code is released under the libpng license.
       7   * For conditions of distribution and use, see the disclaimer
       8   * and license in png.h
       9   *
      10   * SEE contrib/arm-neon/README before reporting bugs
      11   *
      12   * STATUS: COMPILED, TESTED
      13   * BUG REPORTS: png-mng-implement@sourceforge.net
      14   *
      15   * png_have_neon implemented for Linux versions which allow access to
      16   * /proc/self/auxv.  This is probably faster, cleaner and safer than the code to
      17   * read /proc/cpuinfo in contrib/arm-neon/linux, however it is yet another piece
      18   * of potentially untested code and has more complex dependencies than the code
      19   * to read cpuinfo.
      20   *
      21   * This generic __linux__ implementation requires reading /proc/self/auxv and
      22   * looking at each element for one that records NEON capabilities.
      23   */
      24  
      25  #include <unistd.h> /* for POSIX 1003.1 */
      26  #include <errno.h>  /* for EINTR */
      27  
      28  #include <sys/types.h>
      29  #include <sys/stat.h>
      30  #include <fcntl.h>
      31  #include <elf.h>
      32  #include <asm/hwcap.h>
      33  
      34  /* A read call may be interrupted, in which case it returns -1 and sets errno to
      35   * EINTR if nothing was done, otherwise (if something was done) a partial read
      36   * may result.
      37   */
      38  static size_t
      39  safe_read(png_structp png_ptr, int fd, void *buffer_in, size_t nbytes)
      40  {
      41     size_t ntotal = 0;
      42     char *buffer = png_voidcast(char*, buffer_in);
      43  
      44     while (nbytes > 0)
      45     {
      46        unsigned int nread;
      47        int iread;
      48  
      49        /* Passing nread > INT_MAX to read is implementation defined in POSIX
      50         * 1003.1, therefore despite the unsigned argument portable code must
      51         * limit the value to INT_MAX!
      52         */
      53        if (nbytes > INT_MAX)
      54           nread = INT_MAX;
      55  
      56        else
      57           nread = (unsigned int)/*SAFE*/nbytes;
      58  
      59        iread = read(fd, buffer, nread);
      60  
      61        if (iread == -1)
      62        {
      63           /* This is the devil in the details, a read can terminate early with 0
      64            * bytes read because of EINTR, yet it still returns -1 otherwise end
      65            * of file cannot be distinguished.
      66            */
      67           if (errno != EINTR)
      68           {
      69              png_warning(png_ptr, "/proc read failed");
      70              return 0; /* I.e., a permanent failure */
      71           }
      72        }
      73  
      74        else if (iread < 0)
      75        {
      76           /* Not a valid 'read' result: */
      77           png_warning(png_ptr, "OS /proc read bug");
      78           return 0;
      79        }
      80  
      81        else if (iread > 0)
      82        {
      83           /* Continue reading until a permanent failure, or EOF */
      84           buffer += iread;
      85           nbytes -= (unsigned int)/*SAFE*/iread;
      86           ntotal += (unsigned int)/*SAFE*/iread;
      87        }
      88  
      89        else
      90           return ntotal;
      91     }
      92  
      93     return ntotal; /* nbytes == 0 */
      94  }
      95  
      96  static int
      97  png_have_neon(png_structp png_ptr)
      98  {
      99     int fd = open("/proc/self/auxv", O_RDONLY);
     100     Elf32_auxv_t aux;
     101  
     102     /* Failsafe: failure to open means no NEON */
     103     if (fd == -1)
     104     {
     105        png_warning(png_ptr, "/proc/self/auxv open failed");
     106        return 0;
     107     }
     108  
     109     while (safe_read(png_ptr, fd, &aux, sizeof aux) == sizeof aux)
     110     {
     111        if (aux.a_type == AT_HWCAP && (aux.a_un.a_val & HWCAP_NEON) != 0)
     112        {
     113           close(fd);
     114           return 1;
     115        }
     116     }
     117  
     118     close(fd);
     119     return 0;
     120  }