From a51b308cc87e10cbe77c8057d3b96130697fa7a5 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 19 Mar 2018 15:25:23 -0700 Subject: [PATCH] ByteBuffer avoid PPC alignment fault --- src/misc/pv/byteBuffer.h | 76 +++++++++++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 12 deletions(-) diff --git a/src/misc/pv/byteBuffer.h b/src/misc/pv/byteBuffer.h index d1e1b38..6ac39cf 100644 --- a/src/misc/pv/byteBuffer.h +++ b/src/misc/pv/byteBuffer.h @@ -148,6 +148,58 @@ struct swap<8> { #undef _PVA_swap32 #undef _PVA_swap64 +/* PVD serialization doesn't pay attention to alignement, + * which some targets really care about and treat unaligned + * access as a fault, or with a heavy penalty (~= to a syscall). + * + * For those targets,, we will have to live with the increase + * in execution time and/or object code size of byte-wise copy. + */ + +#ifdef _ARCH_PPC + +template +union alignu { + T val; + char bytes[sizeof(T)]; +}; + +template +EPICS_ALWAYS_INLINE void store_unaligned(char *buf, T val) +{ + alignu A; + A.val = val; + for(unsigned i=0, N=sizeof(T); i +EPICS_ALWAYS_INLINE T load_unaligned(const char *buf) +{ + alignu A; + for(unsigned i=0, N=sizeof(T); i +EPICS_ALWAYS_INLINE void store_unaligned(char *buf, T val) +{ + *reinterpret_cast(buf) = val; +} + +template +EPICS_ALWAYS_INLINE T load_unaligned(const char *buf) +{ + return *reinterpret_cast(buf); +} + +#endif /* alignement */ + } // namespace detail //! Unconditional byte order swap. @@ -699,8 +751,7 @@ private: if(reverse()) value = swap(value); - //assert(is_aligned(_position, sizeof(T))); - *((T*)_position) = value; + detail::store_unaligned(_position, value); _position += sizeof(T); } @@ -713,7 +764,7 @@ private: value = swap(value); //assert(is_aligned(_buffer+index, sizeof(T))); //TODO: special case for targets which support unaligned access - *((T*)(_buffer+index)) = value; + detail::store_unaligned(_buffer+index, value); } #if defined (__GNUC__) && (__GNUC__ < 3) @@ -727,7 +778,7 @@ private: assert(sizeof(T)<=getRemaining()); //assert(is_aligned(_position, sizeof(T))); - T value = *((T*)_position); + T value = detail::load_unaligned(_position); _position += sizeof(T); if(reverse()) @@ -741,7 +792,7 @@ private: assert(_buffer+index<=_limit); //assert(is_aligned(_position, sizeof(T))); - T value = *((T*)(_buffer + index)); + T value = detail::load_unaligned(_buffer + index); if(reverse()) value = swap(value); @@ -753,15 +804,15 @@ private: { // we require aligned arrays... //assert(is_aligned(_position, sizeof(T))); - T* start = (T*)_position; size_t n = sizeof(T)*count; // bytes assert(n<=getRemaining()); if (reverse()) { - for(std::size_t i=0; i(values[i]); + for(std::size_t i=0; i(values[i])); + } } else { - memcpy(start, values, n); + memcpy(_position, values, n); } _position += n; } @@ -776,10 +827,11 @@ private: assert(n<=getRemaining()); if (reverse()) { - for(std::size_t i=0; i(start[i]); + for(std::size_t i=0; i(detail::load_unaligned(_position+i)); + } } else { - memcpy(values, start, n); + memcpy(values, _position, n); } _position += n; }