From 992ea2dab54765ec3a34d3d77da1607f8ec2b00d Mon Sep 17 00:00:00 2001 From: moluopro Date: Fri, 10 Jul 2026 14:53:18 +0800 Subject: [PATCH 01/23] cmake: preserve callback typedefs in generated CBLAS headers --- CMakeLists.txt | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c88d9dd3e1..27aeae1e26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -734,18 +734,46 @@ if(NOT NO_CBLAS) set(CBLAS_H ${CMAKE_BINARY_DIR}/generated/cblas.h) file(READ ${CMAKE_CURRENT_SOURCE_DIR}/cblas.h CBLAS_H_CONTENTS) string(REPLACE "common" "openblas_config" CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS}") + + # Symbol prefix/suffix settings rename exported functions, not C typedefs. + # Protect callback type names from the textual function-name rewriting below. + string(REPLACE "openblas_dojob_callback" "OPENBLAS_DOJOB_CALLBACK_TYPE" + CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS_NEW}") + string(REPLACE "openblas_threads_callback" "OPENBLAS_THREADS_CALLBACK_TYPE" + CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS_NEW}") + string(REPLACE "openblas_xerbla_handler" "OPENBLAS_XERBLA_HANDLER_TYPE" + CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS_NEW}") + if (NOT ${SYMBOLPREFIX} STREQUAL "") - string(REPLACE " cblas" " ${SYMBOLPREFIX}cblas" CBLAS_H_CONTENTS "${CBLAS_H_CONTENTS_NEW}") - string(REPLACE " openblas" " ${SYMBOLPREFIX}openblas" CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS}") - string (REPLACE " ${SYMBOLPREFIX}openblas_complex" " openblas_complex" CBLAS_H_CONTENTS "${CBLAS_H_CONTENTS_NEW}") - string(REPLACE " goto" " ${SYMBOLPREFIX}goto" CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS}") + string(REPLACE " cblas" " ${SYMBOLPREFIX}cblas" + CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS_NEW}") + string(REPLACE " openblas" " ${SYMBOLPREFIX}openblas" + CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS_NEW}") + string(REPLACE " ${SYMBOLPREFIX}openblas_complex" " openblas_complex" + CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS_NEW}") + string(REPLACE " goto" " ${SYMBOLPREFIX}goto" + CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS_NEW}") endif() if (NOT ${SYMBOLSUFFIX} STREQUAL "") - string(REGEX REPLACE "(cblas[^ (]*)" "\\1${SYMBOLSUFFIX}" CBLAS_H_CONTENTS "${CBLAS_H_CONTENTS_NEW}") - string(REGEX REPLACE "(openblas[^ (]*)" "\\1${SYMBOLSUFFIX}" CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS}") - string(REGEX REPLACE "(openblas_complex[^ ]*)${SYMBOLSUFFIX}" "\\1" CBLAS_H_CONTENTS "${CBLAS_H_CONTENTS_NEW}") - string(REGEX REPLACE "(goto[^ (]*)" "\\1${SYMBOLSUFFIX}" CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS}") - endif() + string(REGEX REPLACE "(cblas[A-Za-z0-9_]*)" "\\1${SYMBOLSUFFIX}" + CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS_NEW}") + string(REGEX REPLACE "(openblas[A-Za-z0-9_]*)" "\\1${SYMBOLSUFFIX}" + CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS_NEW}") + string(REPLACE "openblas_config${SYMBOLSUFFIX}" "openblas_config" + CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS_NEW}") + string(REGEX REPLACE "(openblas_complex[A-Za-z0-9_]*)${SYMBOLSUFFIX}" "\\1" + CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS_NEW}") + string(REGEX REPLACE "(goto[A-Za-z0-9_]*)" "\\1${SYMBOLSUFFIX}" + CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS_NEW}") + endif() + + string(REPLACE "OPENBLAS_DOJOB_CALLBACK_TYPE" "openblas_dojob_callback" + CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS_NEW}") + string(REPLACE "OPENBLAS_THREADS_CALLBACK_TYPE" "openblas_threads_callback" + CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS_NEW}") + string(REPLACE "OPENBLAS_XERBLA_HANDLER_TYPE" "openblas_xerbla_handler" + CBLAS_H_CONTENTS_NEW "${CBLAS_H_CONTENTS_NEW}") + file(WRITE ${CBLAS_H} "${CBLAS_H_CONTENTS_NEW}") install (FILES ${CBLAS_H} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) endif() From b2ba228de5af974e3e4649aaf0d1c05bd7f3c757 Mon Sep 17 00:00:00 2001 From: moluopro Date: Fri, 10 Jul 2026 14:54:02 +0800 Subject: [PATCH 02/23] install: preserve callback typedefs in generated CBLAS headers --- Makefile.install | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Makefile.install b/Makefile.install index e656b368a8..cbeab53f81 100644 --- a/Makefile.install +++ b/Makefile.install @@ -73,7 +73,10 @@ install : lib.grd ifneq ($(NO_CBLAS),1) @echo Generating cblas.h in $(DESTDIR)$(OPENBLAS_INCLUDE_DIR) - @cp cblas.h cblas.tmp + @sed -e 's/openblas_dojob_callback/OPENBLAS_DOJOB_CALLBACK_TYPE/g' \ + -e 's/openblas_threads_callback/OPENBLAS_THREADS_CALLBACK_TYPE/g' \ + -e 's/openblas_xerbla_handler/OPENBLAS_XERBLA_HANDLER_TYPE/g' \ + cblas.h > cblas.tmp ifdef SYMBOLPREFIX @sed 's/cblas[^() ]*/$(SYMBOLPREFIX)&/g' cblas.tmp > cblas.tmp2 @sed 's/openblas[^() ]*/$(SYMBOLPREFIX)&/g' cblas.tmp2 > cblas.tmp @@ -88,7 +91,11 @@ ifdef SYMBOLSUFFIX @sed 's/\(openblas_complex_\)\([^ ]*\)$(SYMBOLSUFFIX)/\1\2 /g' cblas.tmp > cblas.tmp2 @sed 's/goto[^() ]*/&$(SYMBOLSUFFIX)/g' cblas.tmp2 > cblas.tmp endif - @sed 's/common/openblas_config/g' cblas.tmp > "$(DESTDIR)$(OPENBLAS_INCLUDE_DIR)/cblas.h" + @sed -e 's/OPENBLAS_DOJOB_CALLBACK_TYPE/openblas_dojob_callback/g' \ + -e 's/OPENBLAS_THREADS_CALLBACK_TYPE/openblas_threads_callback/g' \ + -e 's/OPENBLAS_XERBLA_HANDLER_TYPE/openblas_xerbla_handler/g' \ + -e 's/common/openblas_config/g' \ + cblas.tmp > "$(DESTDIR)$(OPENBLAS_INCLUDE_DIR)/cblas.h" endif ifneq ($(OSNAME), AIX) From 6a04925804565b45d78fabd02df8a36ff54708b9 Mon Sep 17 00:00:00 2001 From: moluopro Date: Fri, 10 Jul 2026 14:55:52 +0800 Subject: [PATCH 03/23] xerbla: add a portable handler API --- cblas.h | 12 ++++++++ common.h | 20 +++++++++++++ driver/others/xerbla.c | 68 ++++++++++++++++++++++++++++++++---------- 3 files changed, 85 insertions(+), 15 deletions(-) diff --git a/cblas.h b/cblas.h index 8395f1b8b2..3d4143256b 100644 --- a/cblas.h +++ b/cblas.h @@ -59,6 +59,18 @@ typedef void (*openblas_dojob_callback)(int thread_num, void *jobdata, int dojob typedef void (*openblas_threads_callback)(int sync, openblas_dojob_callback dojob, int numjobs, size_t jobdata_elsize, void *jobdata, int dojob_data); void openblas_set_threads_callback_function(openblas_threads_callback callback); +/* Set the process-wide error handler called by XERBLA. The callback's routine + * name is valid for name_length bytes and is not necessarily NUL-terminated. + * Installation is thread-safe, returns the previous handler, and accepts NULL + * to restore OpenBLAS' default handler. */ +#ifndef OPENBLAS_XERBLA_HANDLER_DEFINED +#define OPENBLAS_XERBLA_HANDLER_DEFINED +typedef void (*openblas_xerbla_handler)(const char *name, + const blasint *info, + size_t name_length); +#endif +openblas_xerbla_handler openblas_set_xerbla(openblas_xerbla_handler handler); + #ifdef OPENBLAS_OS_LINUX /* Sets thread affinity for OpenBLAS threads. `thread_idx` is in [0, openblas_get_num_threads()-1]. */ int openblas_setaffinity(int thread_idx, size_t cpusetsize, cpu_set_t* cpu_set); diff --git a/common.h b/common.h index a611c9cb07..336cb298e4 100644 --- a/common.h +++ b/common.h @@ -880,6 +880,26 @@ typedef struct { #endif #include "common_interface.h" + +/* Internal declaration of the public C XERBLA callback API. Keep this out of + * common_interface.h, whose contents are copied verbatim into f77blas.h and + * are not adjusted for SYMBOLPREFIX/SYMBOLSUFFIX by the CMake build. */ +#ifndef ASSEMBLER +#ifdef __cplusplus +extern "C" { +#endif +#ifndef OPENBLAS_XERBLA_HANDLER_DEFINED +#define OPENBLAS_XERBLA_HANDLER_DEFINED +typedef void (*openblas_xerbla_handler)(const char *name, + const blasint *info, + size_t name_length); +#endif +openblas_xerbla_handler openblas_set_xerbla(openblas_xerbla_handler handler); +#ifdef __cplusplus +} +#endif +#endif + #ifdef SANITY_CHECK #include "common_reference.h" #endif diff --git a/driver/others/xerbla.c b/driver/others/xerbla.c index 290f2833c3..c7cc69b82b 100644 --- a/driver/others/xerbla.c +++ b/driver/others/xerbla.c @@ -36,8 +36,10 @@ /* or implied, of The University of Texas at Austin. */ /*********************************************************************/ +#include #include #include +#include #include "common.h" #if defined(OS_WINDOWS) && (defined(__MINGW32__) || defined(__MINGW64__)) @@ -46,31 +48,67 @@ #define printf _cprintf #endif -#ifdef INTERFACE64 -#define MSGFMT " ** On entry to %6s parameter number %2ld had an illegal value\n" -#else -#define MSGFMT " ** On entry to %6s parameter number %2d had an illegal value\n" -#endif +#define MSGFMT " ** On entry to %6.*s parameter number %2lld had an illegal value\n" -#ifdef __ELF__ -int __xerbla(char *message, blasint *info, blasint length){ +static size_t openblas_xerbla_name_length(const char *message, + blasint length) { + const char *terminator; - printf(MSGFMT, - message, *info); + if (message == NULL || length <= 0) return 0; - return 0; + terminator = memchr(message, '\0', (size_t)length); + if (terminator != NULL) return (size_t)(terminator - message); + + return (size_t)length; } -int BLASFUNC(xerbla)(char *, blasint *, blasint) __attribute__ ((weak, alias ("__xerbla"))); +static void openblas_xerbla_default(const char *message, const blasint *info, + size_t length) { + int precision = length > INT_MAX ? INT_MAX : (int)length; -#else + printf(MSGFMT, precision, message == NULL ? "" : message, + (long long)*info); +} + +static openblas_xerbla_handler openblas_xerbla = openblas_xerbla_default; +static volatile BLASULONG openblas_xerbla_lock = 0; + +openblas_xerbla_handler +openblas_set_xerbla(openblas_xerbla_handler handler) { + openblas_xerbla_handler previous; -int BLASFUNC(xerbla)(char *message, blasint *info, blasint length){ + if (handler == NULL) handler = openblas_xerbla_default; - printf(MSGFMT, - message, *info); + blas_lock(&openblas_xerbla_lock); + previous = openblas_xerbla; + openblas_xerbla = handler; + blas_unlock(&openblas_xerbla_lock); + return previous; +} + +static int openblas_xerbla_dispatch(char *message, blasint *info, + blasint length) { + openblas_xerbla_handler handler; + size_t name_length = openblas_xerbla_name_length(message, length); + + blas_lock(&openblas_xerbla_lock); + handler = openblas_xerbla; + blas_unlock(&openblas_xerbla_lock); + + handler(message, info, name_length); return 0; } +#ifdef __ELF__ +int __xerbla(char *message, blasint *info, blasint length) { + return openblas_xerbla_dispatch(message, info, length); +} + +int BLASFUNC(xerbla)(char *, blasint *, blasint) + __attribute__ ((weak, alias ("__xerbla"))); +#else +int BLASFUNC(xerbla)(char *message, blasint *info, blasint length) { + return openblas_xerbla_dispatch(message, info, length); +} #endif From 8da645954b5539eb56cc430ae74bb8fd5cbecf9a Mon Sep 17 00:00:00 2001 From: moluopro Date: Fri, 10 Jul 2026 14:56:48 +0800 Subject: [PATCH 04/23] exports: expose the XERBLA handler setter --- exports/gensymbol | 1 + exports/gensymbol.pl | 1 + 2 files changed, 2 insertions(+) diff --git a/exports/gensymbol b/exports/gensymbol index 6284e6b6ae..921aa60eab 100755 --- a/exports/gensymbol +++ b/exports/gensymbol @@ -182,6 +182,7 @@ misc_no_underscore_objs=" openblas_get_config openblas_get_corename openblas_set_threads_callback_function + openblas_set_xerbla " misc_underscore_objs="" diff --git a/exports/gensymbol.pl b/exports/gensymbol.pl index 85a6e9dbf5..0fdaabc225 100644 --- a/exports/gensymbol.pl +++ b/exports/gensymbol.pl @@ -178,6 +178,7 @@ openblas_get_config, openblas_get_corename, openblas_set_threads_callback_function, + openblas_set_xerbla, ); @misc_underscore_objs = ( From d7e007e0fb016b883140fcc2d196958c1f1dd888 Mon Sep 17 00:00:00 2001 From: moluopro Date: Fri, 10 Jul 2026 14:58:35 +0800 Subject: [PATCH 05/23] docs: document XERBLA handler semantics --- docs/extensions.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/extensions.md b/docs/extensions.md index 30db9895d1..fb2dd9c805 100644 --- a/docs/extensions.md +++ b/docs/extensions.md @@ -47,3 +47,8 @@ BLAS-like and conversion functions for `hfloat16` (available when OpenBLAS was c * `int openblas_set_affinity(int thread_index, size_t cpusetsize, cpu_set_t *cpuset)` sets the CPU affinity mask of the given thread to the provided cpuset. Only available on Linux, with semantics identical to `pthread_setaffinity_np`. * `openblas_set_thread_callback_function` overrides the default multithreading backend with the provided argument +* `openblas_set_xerbla(openblas_xerbla_handler handler)` installs a process-wide XERBLA error handler and returns the previous one. + Installation is thread-safe, and passing `NULL` restores the default handler. The callback receives a read-only routine name, + error parameter number and normalized name length (excluding a terminating NUL when present); the name is not guaranteed to be + NUL-terminated. On ELF platforms, a legacy strong `xerbla` definition still takes precedence over this dispatcher. Callback code + must remain loaded until the handler has been replaced and all concurrent BLAS calls have completed. From 29703e52ad07310bf61407a86b1d5f25821fff44 Mon Sep 17 00:00:00 2001 From: moluopro Date: Fri, 10 Jul 2026 14:59:30 +0800 Subject: [PATCH 06/23] utest: cover explicit XERBLA handler registration --- utest/test_extensions/common.h | 1 - utest/test_extensions/xerbla.c | 56 ++++++++++++++++++++++------------ 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/utest/test_extensions/common.h b/utest/test_extensions/common.h index f8c60d2686..c7de83cd77 100644 --- a/utest/test_extensions/common.h +++ b/utest/test_extensions/common.h @@ -45,7 +45,6 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. extern int check_error(void); extern void set_xerbla(char* current_rout, int expected_info); -extern int BLASFUNC(xerbla)(char *name, blasint *info, blasint length); extern void srand_generate(float *alpha, blasint n); extern void drand_generate(double *alpha, blasint n); diff --git a/utest/test_extensions/xerbla.c b/utest/test_extensions/xerbla.c index 8c90d4ce75..046a8c74c7 100644 --- a/utest/test_extensions/xerbla.c +++ b/utest/test_extensions/xerbla.c @@ -31,41 +31,55 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **********************************************************************************/ +#include "utest/openblas_utest.h" #include "common.h" -static int link_xerbla=TRUE; +static int handler_installed = FALSE; static int lerr, _info, ok; static char *rout; -static void F77_xerbla(char *srname, void *vinfo) +static void test_xerbla(const char *srname, const blasint *vinfo, size_t length) { - blasint info=*(blasint*)vinfo; + blasint info = *vinfo; - if (link_xerbla) - { - link_xerbla = 0; - return; - } - - if (rout != NULL && strcmp(rout, srname) != 0){ - printf("***** XERBLA WAS CALLED WITH SRNAME = <%s> INSTEAD OF <%s> *******\n", srname, rout); + if (rout != NULL && + (length != strlen(rout) || memcmp(rout, srname, length) != 0)) { + printf("***** XERBLA WAS CALLED WITH AN UNEXPECTED SRNAME INSTEAD OF <%s> *******\n", + rout); ok = FALSE; } if (info != _info){ - printf("***** XERBLA WAS CALLED WITH INFO = %d INSTEAD OF %d in %s *******\n",info, _info, srname); + printf("***** XERBLA WAS CALLED WITH INFO = %lld INSTEAD OF %d in %s *******\n", + (long long)info, _info, srname); lerr = TRUE; ok = FALSE; } else lerr = FALSE; } -/** -* error function redefinition -*/ -int BLASFUNC(xerbla)(char *name, blasint *info, blasint length) +static void alternate_xerbla(const char *srname, const blasint *vinfo, + size_t length) +{ + (void) srname; + (void) vinfo; + (void) length; +} + +CTEST(openblas_extensions, xerbla_handler_registration) { - F77_xerbla(name, info); - return 0; + openblas_xerbla_handler original; + openblas_xerbla_handler previous; + openblas_xerbla_handler restored; + openblas_xerbla_handler default_handler; + + original = openblas_set_xerbla(test_xerbla); + previous = openblas_set_xerbla(alternate_xerbla); + restored = openblas_set_xerbla(NULL); + default_handler = openblas_set_xerbla(original); + + ASSERT_TRUE(previous == test_xerbla); + ASSERT_TRUE(restored == alternate_xerbla); + ASSERT_TRUE(default_handler != NULL); } int check_error(void) { @@ -78,8 +92,10 @@ int check_error(void) { } void set_xerbla(char* current_rout, int expected_info){ - if (link_xerbla) /* call these first to link */ - F77_xerbla(rout, &_info); + if (!handler_installed) { + openblas_set_xerbla(test_xerbla); + handler_installed = TRUE; + } ok = TRUE; lerr = TRUE; From 99bb32ae596600646ce2cda92f1d1f0f0c4759e9 Mon Sep 17 00:00:00 2001 From: moluopro Date: Fri, 10 Jul 2026 15:00:36 +0800 Subject: [PATCH 07/23] ctest: use explicit XERBLA handlers in error tests --- ctest/c_c2chke.c | 17 +++---------- ctest/c_c3chke.c | 17 +++---------- ctest/c_c3chke_3m.c | 17 +++---------- ctest/c_d2chke.c | 17 +++---------- ctest/c_d3chke.c | 17 +++---------- ctest/c_s2chke.c | 17 +++---------- ctest/c_s3chke.c | 17 +++---------- ctest/c_xerbla.c | 61 +++++++++++---------------------------------- ctest/c_z2chke.c | 17 +++---------- ctest/c_z3chke.c | 17 +++---------- ctest/c_z3chke_3m.c | 17 +++---------- ctest/cblas_test.h | 2 ++ 12 files changed, 46 insertions(+), 187 deletions(-) diff --git a/ctest/c_c2chke.c b/ctest/c_c2chke.c index eb5b99008f..fe982f336d 100644 --- a/ctest/c_c2chke.c +++ b/ctest/c_c2chke.c @@ -4,21 +4,14 @@ #include "cblas_test.h" int cblas_ok, cblas_lerr, cblas_info; -int link_xerbla=TRUE; char *cblas_rout; -#ifdef F77_Char -void F77_xerbla(F77_Char F77_srname, void *vinfo); -#else -void F77_xerbla(char *srname, void *vinfo); -#endif - void chkxer(void) { extern int cblas_ok, cblas_lerr, cblas_info; - extern int link_xerbla; extern char *cblas_rout; if (cblas_lerr == 1 ) { - printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %d NOT DETECTED BY %s *****\n", cblas_info, cblas_rout); + printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %lld NOT DETECTED BY %s *****\n", + (long long)cblas_info, cblas_rout); cblas_ok = 0 ; } cblas_lerr = 1 ; @@ -36,11 +29,7 @@ void F77_c2chke(char *rout) { extern int RowMajorStrg; extern char *cblas_rout; - if (link_xerbla) /* call these first to link */ - { - cblas_xerbla(cblas_info,cblas_rout,""); - F77_xerbla(cblas_rout,&cblas_info); - } + cblas_test_set_xerbla(); cblas_ok = TRUE ; cblas_lerr = PASSED ; diff --git a/ctest/c_c3chke.c b/ctest/c_c3chke.c index 3b4764c4a7..b55ef501eb 100644 --- a/ctest/c_c3chke.c +++ b/ctest/c_c3chke.c @@ -4,21 +4,14 @@ #include "cblas_test.h" int cblas_ok, cblas_lerr, cblas_info; -int link_xerbla=TRUE; char *cblas_rout; -#ifdef F77_Char -void F77_xerbla(F77_Char F77_srname, void *vinfo); -#else -void F77_xerbla(char *srname, void *vinfo); -#endif - void chkxer(void) { extern int cblas_ok, cblas_lerr, cblas_info; - extern int link_xerbla; extern char *cblas_rout; if (cblas_lerr == 1 ) { - printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %d NOT DETECTED BY %s *****\n", cblas_info, cblas_rout); + printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %lld NOT DETECTED BY %s *****\n", + (long long)cblas_info, cblas_rout); cblas_ok = 0 ; } cblas_lerr = 1 ; @@ -39,11 +32,7 @@ void F77_c3chke(char * rout) { cblas_ok = TRUE ; cblas_lerr = PASSED ; - if (link_xerbla) /* call these first to link */ - { - cblas_xerbla(cblas_info,cblas_rout,""); - F77_xerbla(cblas_rout,&cblas_info); - } + cblas_test_set_xerbla(); if (strncmp( sf,"cblas_cgemm" ,11)==0) { diff --git a/ctest/c_c3chke_3m.c b/ctest/c_c3chke_3m.c index 4d5de5150c..782e869ca6 100644 --- a/ctest/c_c3chke_3m.c +++ b/ctest/c_c3chke_3m.c @@ -4,21 +4,14 @@ #include "cblas_test.h" int cblas_ok, cblas_lerr, cblas_info; -int link_xerbla=TRUE; char *cblas_rout; -#ifdef F77_Char -void F77_xerbla(F77_Char F77_srname, void *vinfo); -#else -void F77_xerbla(char *srname, void *vinfo); -#endif - void chkxer(void) { extern int cblas_ok, cblas_lerr, cblas_info; - extern int link_xerbla; extern char *cblas_rout; if (cblas_lerr == 1 ) { - printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %d NOT DETECTED BY %s *****\n", cblas_info, cblas_rout); + printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %lld NOT DETECTED BY %s *****\n", + (long long)cblas_info, cblas_rout); cblas_ok = 0 ; } cblas_lerr = 1 ; @@ -39,11 +32,7 @@ void F77_c3chke(char * rout) { cblas_ok = TRUE ; cblas_lerr = PASSED ; - if (link_xerbla) /* call these first to link */ - { - cblas_xerbla(cblas_info,cblas_rout,""); - F77_xerbla(cblas_rout,&cblas_info); - } + cblas_test_set_xerbla(); if (strncmp( sf,"cblas_cgemm3m" ,13)==0) { diff --git a/ctest/c_d2chke.c b/ctest/c_d2chke.c index 7cdd04135c..dde71323d5 100644 --- a/ctest/c_d2chke.c +++ b/ctest/c_d2chke.c @@ -4,21 +4,14 @@ #include "cblas_test.h" int cblas_ok, cblas_lerr, cblas_info; -int link_xerbla=TRUE; char *cblas_rout; -#ifdef F77_Char -void F77_xerbla(F77_Char F77_srname, void *vinfo); -#else -void F77_xerbla(char *srname, void *vinfo); -#endif - void chkxer(void) { extern int cblas_ok, cblas_lerr, cblas_info; - extern int link_xerbla; extern char *cblas_rout; if (cblas_lerr == 1 ) { - printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %d NOT DETECTED BY %s *****\n", cblas_info, cblas_rout); + printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %lld NOT DETECTED BY %s *****\n", + (long long)cblas_info, cblas_rout); cblas_ok = 0 ; } cblas_lerr = 1 ; @@ -34,11 +27,7 @@ void F77_d2chke(char *rout) { extern int RowMajorStrg; extern char *cblas_rout; - if (link_xerbla) /* call these first to link */ - { - cblas_xerbla(cblas_info,cblas_rout,""); - F77_xerbla(cblas_rout,&cblas_info); - } + cblas_test_set_xerbla(); cblas_ok = TRUE ; cblas_lerr = PASSED ; diff --git a/ctest/c_d3chke.c b/ctest/c_d3chke.c index 700cff28f6..29a5316eec 100644 --- a/ctest/c_d3chke.c +++ b/ctest/c_d3chke.c @@ -4,21 +4,14 @@ #include "cblas_test.h" int cblas_ok, cblas_lerr, cblas_info; -int link_xerbla=TRUE; char *cblas_rout; -#ifdef F77_Char -void F77_xerbla(F77_Char F77_srname, void *vinfo); -#else -void F77_xerbla(char *srname, void *vinfo); -#endif - void chkxer(void) { extern int cblas_ok, cblas_lerr, cblas_info; - extern int link_xerbla; extern char *cblas_rout; if (cblas_lerr == 1 ) { - printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %d NOT DETECTED BY %s *****\n", cblas_info, cblas_rout); + printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %lld NOT DETECTED BY %s *****\n", + (long long)cblas_info, cblas_rout); cblas_ok = 0 ; } cblas_lerr = 1 ; @@ -34,11 +27,7 @@ void F77_d3chke(char *rout) { extern int RowMajorStrg; extern char *cblas_rout; - if (link_xerbla) /* call these first to link */ - { - cblas_xerbla(cblas_info,cblas_rout,""); - F77_xerbla(cblas_rout,&cblas_info); - } + cblas_test_set_xerbla(); cblas_ok = TRUE ; cblas_lerr = PASSED ; diff --git a/ctest/c_s2chke.c b/ctest/c_s2chke.c index 1455153005..8e1d739006 100644 --- a/ctest/c_s2chke.c +++ b/ctest/c_s2chke.c @@ -4,21 +4,14 @@ #include "cblas_test.h" int cblas_ok, cblas_lerr, cblas_info; -int link_xerbla=TRUE; char *cblas_rout; -#ifdef F77_Char -void F77_xerbla(F77_Char F77_srname, void *vinfo); -#else -void F77_xerbla(char *srname, void *vinfo); -#endif - void chkxer(void) { extern int cblas_ok, cblas_lerr, cblas_info; - extern int link_xerbla; extern char *cblas_rout; if (cblas_lerr == 1 ) { - printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %d NOT DETECTED BY %s *****\n", cblas_info, cblas_rout); + printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %lld NOT DETECTED BY %s *****\n", + (long long)cblas_info, cblas_rout); cblas_ok = 0 ; } cblas_lerr = 1 ; @@ -34,11 +27,7 @@ void F77_s2chke(char *rout) { extern int RowMajorStrg; extern char *cblas_rout; - if (link_xerbla) /* call these first to link */ - { - cblas_xerbla(cblas_info,cblas_rout,""); - F77_xerbla(cblas_rout,&cblas_info); - } + cblas_test_set_xerbla(); cblas_ok = TRUE ; cblas_lerr = PASSED ; diff --git a/ctest/c_s3chke.c b/ctest/c_s3chke.c index 632eaae30e..ab4034c931 100644 --- a/ctest/c_s3chke.c +++ b/ctest/c_s3chke.c @@ -4,21 +4,14 @@ #include "cblas_test.h" int cblas_ok, cblas_lerr, cblas_info; -int link_xerbla=TRUE; char *cblas_rout; -#ifdef F77_Char -void F77_xerbla(F77_Char F77_srname, void *vinfo); -#else -void F77_xerbla(char *srname, void *vinfo); -#endif - void chkxer(void) { extern int cblas_ok, cblas_lerr, cblas_info; - extern int link_xerbla; extern char *cblas_rout; if (cblas_lerr == 1 ) { - printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %d NOT DETECTED BY %s *****\n", cblas_info, cblas_rout); + printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %lld NOT DETECTED BY %s *****\n", + (long long)cblas_info, cblas_rout); cblas_ok = 0 ; } cblas_lerr = 1 ; @@ -34,11 +27,7 @@ void F77_s3chke(char *rout) { extern int RowMajorStrg; extern char *cblas_rout; - if (link_xerbla) /* call these first to link */ - { - cblas_xerbla(cblas_info,cblas_rout,""); - F77_xerbla(cblas_rout,&cblas_info); - } + cblas_test_set_xerbla(); cblas_ok = TRUE ; cblas_lerr = PASSED ; diff --git a/ctest/c_xerbla.c b/ctest/c_xerbla.c index 9c53576536..67d62701f1 100644 --- a/ctest/c_xerbla.c +++ b/ctest/c_xerbla.c @@ -8,17 +8,9 @@ void cblas_xerbla(blasint info, char *rout, char *form, ...) { extern int cblas_lerr, cblas_info, cblas_ok; - extern int link_xerbla; extern int RowMajorStrg; extern char *cblas_rout; - /* Initially, c__3chke will call this routine with - * global variable link_xerbla=1, and F77_xerbla will set link_xerbla=0. - * This is done to fool the linker into loading these subroutines first - * instead of ones in the CBLAS or the legacy BLAS library. - */ - if (link_xerbla) return; - if (cblas_rout != NULL && strcmp(cblas_rout, rout) != 0){ printf("***** XERBLA WAS CALLED WITH SRNAME = <%s> INSTEAD OF <%s> *******\n", rout, cblas_rout); cblas_ok = FALSE; @@ -78,44 +70,27 @@ void cblas_xerbla(blasint info, char *rout, char *form, ...) } if (info != cblas_info){ - printf("***** XERBLA WAS CALLED WITH INFO = %d INSTEAD OF %d in %s *******\n",info, cblas_info, rout); + printf("***** XERBLA WAS CALLED WITH INFO = %lld INSTEAD OF %lld in %s *******\n", + (long long)info, (long long)cblas_info, rout); cblas_lerr = PASSED; cblas_ok = FALSE; } else cblas_lerr = FAILED; } -#ifdef F77_Char -void F77_xerbla(F77_Char F77_srname, void *vinfo) -#else -void F77_xerbla(char *srname, void *vinfo) -#endif +static void cblas_test_xerbla(const char *srname, const blasint *info, + size_t length) { -#ifdef F77_Char - char *srname; -#endif - + extern int cblas_ok; char rout[] = {'c','b','l','a','s','_','\0','\0','\0','\0','\0','\0','\0'}; + blasint i; -#ifdef F77_Integer - F77_Integer *info=vinfo; - F77_Integer i; - extern F77_Integer link_xerbla; -#else - int *info=vinfo; - int i; - extern int link_xerbla; -#endif -#ifdef F77_Char - srname = F2C_STR(F77_srname, XerblaStrLen); -#endif - - /* See the comment in cblas_xerbla() above */ - if (link_xerbla) - { - link_xerbla = 0; + if (length < 6) { + printf("***** XERBLA WAS CALLED WITH AN INVALID ROUTINE NAME LENGTH *******\n"); + cblas_ok = FALSE; return; } - for(i=0; i < 6; i++) rout[i+6] = tolower(srname[i]); + + for(i=0; i < 6; i++) rout[i+6] = tolower((unsigned char)srname[i]); for(i=11; i >= 9; i--) if (rout[i] == ' ') rout[i] = '\0'; /* We increment *info by 1 since the CBLAS interface adds one more @@ -124,14 +99,6 @@ void F77_xerbla(char *srname, void *vinfo) cblas_xerbla(*info+1,rout,""); } -#ifdef USE64BITINT -#undef int -#endif - -int BLASFUNC(xerbla)(char *name, blasint *info, blasint length) { - - F77_xerbla(name, info); - return 0; -}; - - +void cblas_test_set_xerbla(void) { + openblas_set_xerbla(cblas_test_xerbla); +} diff --git a/ctest/c_z2chke.c b/ctest/c_z2chke.c index 8767b5201a..e036e10a4e 100644 --- a/ctest/c_z2chke.c +++ b/ctest/c_z2chke.c @@ -4,21 +4,14 @@ #include "cblas_test.h" int cblas_ok, cblas_lerr, cblas_info; -int link_xerbla=TRUE; char *cblas_rout; -#ifdef F77_Char -void F77_xerbla(F77_Char F77_srname, void *vinfo); -#else -void F77_xerbla(char *srname, void *vinfo); -#endif - void chkxer(void) { extern int cblas_ok, cblas_lerr, cblas_info; - extern int link_xerbla; extern char *cblas_rout; if (cblas_lerr == 1 ) { - printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %d NOT DETECTED BY %s *****\n", cblas_info, cblas_rout); + printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %lld NOT DETECTED BY %s *****\n", + (long long)cblas_info, cblas_rout); cblas_ok = 0 ; } cblas_lerr = 1 ; @@ -36,11 +29,7 @@ void F77_z2chke(char *rout) { extern int RowMajorStrg; extern char *cblas_rout; - if (link_xerbla) /* call these first to link */ - { - cblas_xerbla(cblas_info,cblas_rout,""); - F77_xerbla(cblas_rout,&cblas_info); - } + cblas_test_set_xerbla(); cblas_ok = TRUE ; cblas_lerr = PASSED ; diff --git a/ctest/c_z3chke.c b/ctest/c_z3chke.c index 054e723603..3e11a91c01 100644 --- a/ctest/c_z3chke.c +++ b/ctest/c_z3chke.c @@ -4,21 +4,14 @@ #include "cblas_test.h" int cblas_ok, cblas_lerr, cblas_info; -int link_xerbla=TRUE; char *cblas_rout; -#ifdef F77_Char -void F77_xerbla(F77_Char F77_srname, void *vinfo); -#else -void F77_xerbla(char *srname, void *vinfo); -#endif - void chkxer(void) { extern int cblas_ok, cblas_lerr, cblas_info; - extern int link_xerbla; extern char *cblas_rout; if (cblas_lerr == 1 ) { - printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %d NOT DETECTED BY %s *****\n", cblas_info, cblas_rout); + printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %lld NOT DETECTED BY %s *****\n", + (long long)cblas_info, cblas_rout); cblas_ok = 0 ; } cblas_lerr = 1 ; @@ -39,11 +32,7 @@ void F77_z3chke(char * rout) { cblas_ok = TRUE ; cblas_lerr = PASSED ; - if (link_xerbla) /* call these first to link */ - { - cblas_xerbla(cblas_info,cblas_rout,""); - F77_xerbla(cblas_rout,&cblas_info); - } + cblas_test_set_xerbla(); diff --git a/ctest/c_z3chke_3m.c b/ctest/c_z3chke_3m.c index 4be4457b41..3074837697 100644 --- a/ctest/c_z3chke_3m.c +++ b/ctest/c_z3chke_3m.c @@ -4,21 +4,14 @@ #include "cblas_test.h" int cblas_ok, cblas_lerr, cblas_info; -int link_xerbla=TRUE; char *cblas_rout; -#ifdef F77_Char -void F77_xerbla(F77_Char F77_srname, void *vinfo); -#else -void F77_xerbla(char *srname, void *vinfo); -#endif - void chkxer(void) { extern int cblas_ok, cblas_lerr, cblas_info; - extern int link_xerbla; extern char *cblas_rout; if (cblas_lerr == 1 ) { - printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %d NOT DETECTED BY %s *****\n", cblas_info, cblas_rout); + printf("***** ILLEGAL VALUE OF PARAMETER NUMBER %lld NOT DETECTED BY %s *****\n", + (long long)cblas_info, cblas_rout); cblas_ok = 0 ; } cblas_lerr = 1 ; @@ -39,11 +32,7 @@ void F77_z3chke(char * rout) { cblas_ok = TRUE ; cblas_lerr = PASSED ; - if (link_xerbla) /* call these first to link */ - { - cblas_xerbla(cblas_info,cblas_rout,""); - F77_xerbla(cblas_rout,&cblas_info); - } + cblas_test_set_xerbla(); diff --git a/ctest/cblas_test.h b/ctest/cblas_test.h index 502a2fee20..426c68b8e5 100644 --- a/ctest/cblas_test.h +++ b/ctest/cblas_test.h @@ -30,6 +30,8 @@ #define INVALID -1 #define UNDEFINED -1 +void cblas_test_set_xerbla(void); + typedef struct { float real; float imag; } CBLAS_TEST_COMPLEX; typedef struct { double real; double imag; } CBLAS_TEST_ZOMPLEX; From 39526d88c9f7cd88030f5ae6411a263343b432f3 Mon Sep 17 00:00:00 2001 From: moluopro Date: Fri, 10 Jul 2026 15:02:17 +0800 Subject: [PATCH 08/23] ctest: add a fatal test failure helper --- ctest/c_xerbla.c | 5 +++++ ctest/cblas_test.h | 1 + 2 files changed, 6 insertions(+) diff --git a/ctest/c_xerbla.c b/ctest/c_xerbla.c index 67d62701f1..6f190b0c4b 100644 --- a/ctest/c_xerbla.c +++ b/ctest/c_xerbla.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -102,3 +103,7 @@ static void cblas_test_xerbla(const char *srname, const blasint *info, void cblas_test_set_xerbla(void) { openblas_set_xerbla(cblas_test_xerbla); } + +void cblas_test_fail(void) { + exit(EXIT_FAILURE); +} diff --git a/ctest/cblas_test.h b/ctest/cblas_test.h index 426c68b8e5..9f86d0f5d7 100644 --- a/ctest/cblas_test.h +++ b/ctest/cblas_test.h @@ -31,6 +31,7 @@ #define UNDEFINED -1 void cblas_test_set_xerbla(void); +void cblas_test_fail(void); typedef struct { float real; float imag; } CBLAS_TEST_COMPLEX; typedef struct { double real; double imag; } CBLAS_TEST_ZOMPLEX; From cd4786dd78b38ff14522864fd4c430f72d76bb56 Mon Sep 17 00:00:00 2001 From: moluopro Date: Fri, 10 Jul 2026 15:03:18 +0800 Subject: [PATCH 09/23] ctest: fail level-2 error-exit mismatches --- ctest/c_c2chke.c | 4 +++- ctest/c_d2chke.c | 4 +++- ctest/c_s2chke.c | 4 +++- ctest/c_z2chke.c | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/ctest/c_c2chke.c b/ctest/c_c2chke.c index fe982f336d..2129aad3fa 100644 --- a/ctest/c_c2chke.c +++ b/ctest/c_c2chke.c @@ -810,6 +810,8 @@ void F77_c2chke(char *rout) { } if (cblas_ok == TRUE) printf(" %-12s PASSED THE TESTS OF ERROR-EXITS\n", cblas_rout); - else + else { printf("******* %s FAILED THE TESTS OF ERROR-EXITS *******\n",cblas_rout); + cblas_test_fail(); + } } diff --git a/ctest/c_d2chke.c b/ctest/c_d2chke.c index dde71323d5..cb4ed8876a 100644 --- a/ctest/c_d2chke.c +++ b/ctest/c_d2chke.c @@ -773,6 +773,8 @@ void F77_d2chke(char *rout) { } if (cblas_ok == TRUE) printf(" %-12s PASSED THE TESTS OF ERROR-EXITS\n", cblas_rout); - else + else { printf("******* %s FAILED THE TESTS OF ERROR-EXITS *******\n",cblas_rout); + cblas_test_fail(); + } } diff --git a/ctest/c_s2chke.c b/ctest/c_s2chke.c index 8e1d739006..69cf042c39 100644 --- a/ctest/c_s2chke.c +++ b/ctest/c_s2chke.c @@ -773,6 +773,8 @@ void F77_s2chke(char *rout) { } if (cblas_ok == TRUE) printf(" %-12s PASSED THE TESTS OF ERROR-EXITS\n", cblas_rout); - else + else { printf("******* %s FAILED THE TESTS OF ERROR-EXITS *******\n",cblas_rout); + cblas_test_fail(); + } } diff --git a/ctest/c_z2chke.c b/ctest/c_z2chke.c index e036e10a4e..872b89fa8e 100644 --- a/ctest/c_z2chke.c +++ b/ctest/c_z2chke.c @@ -810,6 +810,8 @@ void F77_z2chke(char *rout) { } if (cblas_ok == TRUE) printf(" %-12s PASSED THE TESTS OF ERROR-EXITS\n", cblas_rout); - else + else { printf("******* %s FAILED THE TESTS OF ERROR-EXITS *******\n",cblas_rout); + cblas_test_fail(); + } } From 5daa61827ab395ee4570323ccb2c184b548488d9 Mon Sep 17 00:00:00 2001 From: moluopro Date: Fri, 10 Jul 2026 15:04:13 +0800 Subject: [PATCH 10/23] ctest: fail level-3 error-exit mismatches --- ctest/c_c3chke.c | 4 +++- ctest/c_c3chke_3m.c | 4 +++- ctest/c_d3chke.c | 4 +++- ctest/c_s3chke.c | 4 +++- ctest/c_z3chke.c | 4 +++- ctest/c_z3chke_3m.c | 4 +++- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/ctest/c_c3chke.c b/ctest/c_c3chke.c index b55ef501eb..6b6b7684d9 100644 --- a/ctest/c_c3chke.c +++ b/ctest/c_c3chke.c @@ -1692,6 +1692,8 @@ void F77_c3chke(char * rout) { if (cblas_ok == 1 ) printf(" %-12s PASSED THE TESTS OF ERROR-EXITS\n", cblas_rout); - else + else { printf("***** %s FAILED THE TESTS OF ERROR-EXITS *******\n",cblas_rout); + cblas_test_fail(); + } } diff --git a/ctest/c_c3chke_3m.c b/ctest/c_c3chke_3m.c index 782e869ca6..767d0cfeb2 100644 --- a/ctest/c_c3chke_3m.c +++ b/ctest/c_c3chke_3m.c @@ -1920,6 +1920,8 @@ void F77_c3chke(char * rout) { if (cblas_ok == 1 ) printf(" %-12s PASSED THE TESTS OF ERROR-EXITS\n", cblas_rout); - else + else { printf("***** %s FAILED THE TESTS OF ERROR-EXITS *******\n",cblas_rout); + cblas_test_fail(); + } } diff --git a/ctest/c_d3chke.c b/ctest/c_d3chke.c index 29a5316eec..aff8380eb0 100644 --- a/ctest/c_d3chke.c +++ b/ctest/c_d3chke.c @@ -1255,6 +1255,8 @@ void F77_d3chke(char *rout) { } if (cblas_ok == TRUE ) printf(" %-12s PASSED THE TESTS OF ERROR-EXITS\n", cblas_rout); - else + else { printf("***** %s FAILED THE TESTS OF ERROR-EXITS *******\n",cblas_rout); + cblas_test_fail(); + } } diff --git a/ctest/c_s3chke.c b/ctest/c_s3chke.c index ab4034c931..c8eae8c400 100644 --- a/ctest/c_s3chke.c +++ b/ctest/c_s3chke.c @@ -1257,6 +1257,8 @@ void F77_s3chke(char *rout) { } if (cblas_ok == TRUE ) printf(" %-12s PASSED THE TESTS OF ERROR-EXITS\n", cblas_rout); - else + else { printf("***** %s FAILED THE TESTS OF ERROR-EXITS *******\n",cblas_rout); + cblas_test_fail(); + } } diff --git a/ctest/c_z3chke.c b/ctest/c_z3chke.c index 3e11a91c01..3bbb1ce10e 100644 --- a/ctest/c_z3chke.c +++ b/ctest/c_z3chke.c @@ -1694,6 +1694,8 @@ void F77_z3chke(char * rout) { if (cblas_ok == 1 ) printf(" %-12s PASSED THE TESTS OF ERROR-EXITS\n", cblas_rout); - else + else { printf("***** %s FAILED THE TESTS OF ERROR-EXITS *******\n",cblas_rout); + cblas_test_fail(); + } } diff --git a/ctest/c_z3chke_3m.c b/ctest/c_z3chke_3m.c index 3074837697..7834934f59 100644 --- a/ctest/c_z3chke_3m.c +++ b/ctest/c_z3chke_3m.c @@ -1924,6 +1924,8 @@ void F77_z3chke(char * rout) { if (cblas_ok == 1 ) printf(" %-12s PASSED THE TESTS OF ERROR-EXITS\n", cblas_rout); - else + else { printf("***** %s FAILED THE TESTS OF ERROR-EXITS *******\n",cblas_rout); + cblas_test_fail(); + } } From 490721cbd9f290199ed48dae1e1bee17ce043957 Mon Sep 17 00:00:00 2001 From: moluopro Date: Fri, 10 Jul 2026 15:33:44 +0800 Subject: [PATCH 11/23] exports: preserve Windows ordinals for new symbols --- exports/gensymbol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/exports/gensymbol b/exports/gensymbol index 921aa60eab..bd4652b0c0 100755 --- a/exports/gensymbol +++ b/exports/gensymbol @@ -4112,10 +4112,13 @@ case "$p1" in done for obj in $no_underscore_objs; do + [ "$obj" = "openblas_set_xerbla" ] && continue printf '\t%s%s%s=%s @%s\n' \ "$symbolprefix" "$obj" "$symbolsuffix" "$obj" "$count" count=`expr $count + 1` done + printf '\t%sopenblas_set_xerbla%s=openblas_set_xerbla @%s\n' \ + "$symbolprefix" "$symbolsuffix" "$count" ;; win2khpl) From f07e6a3d0d839c5d2dc5be590fffe01f4905e354 Mon Sep 17 00:00:00 2001 From: moluopro Date: Fri, 10 Jul 2026 15:39:22 +0800 Subject: [PATCH 12/23] exports: preserve Windows ordinals in Perl generator --- exports/gensymbol.pl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/exports/gensymbol.pl b/exports/gensymbol.pl index 0fdaabc225..72e30dff2d 100644 --- a/exports/gensymbol.pl +++ b/exports/gensymbol.pl @@ -4054,9 +4054,11 @@ foreach $objs (@no_underscore_objs) { + next if $objs eq "openblas_set_xerbla"; print "\t",$symbolprefix,$objs,$symbolsuffix,"=$objs"," \@", $count, "\n"; $count ++; } + print "\t",$symbolprefix,"openblas_set_xerbla",$symbolsuffix,"=openblas_set_xerbla \@",$count,"\n"; exit(0); } From ed8f1198b2a39b9f8ad1d40039f6831a4a10833a Mon Sep 17 00:00:00 2001 From: moluopro Date: Fri, 10 Jul 2026 15:40:02 +0800 Subject: [PATCH 13/23] utest: bound XERBLA routine name diagnostics --- utest/test_extensions/xerbla.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/utest/test_extensions/xerbla.c b/utest/test_extensions/xerbla.c index 046a8c74c7..6d0b9f2de7 100644 --- a/utest/test_extensions/xerbla.c +++ b/utest/test_extensions/xerbla.c @@ -31,6 +31,7 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **********************************************************************************/ +#include #include "utest/openblas_utest.h" #include "common.h" @@ -41,6 +42,7 @@ static char *rout; static void test_xerbla(const char *srname, const blasint *vinfo, size_t length) { blasint info = *vinfo; + int name_length = length > (size_t)INT_MAX ? INT_MAX : (int)length; if (rout != NULL && (length != strlen(rout) || memcmp(rout, srname, length) != 0)) { @@ -50,8 +52,8 @@ static void test_xerbla(const char *srname, const blasint *vinfo, size_t length) } if (info != _info){ - printf("***** XERBLA WAS CALLED WITH INFO = %lld INSTEAD OF %d in %s *******\n", - (long long)info, _info, srname); + printf("***** XERBLA WAS CALLED WITH INFO = %lld INSTEAD OF %d in %.*s *******\n", + (long long)info, _info, name_length, srname == NULL ? "" : srname); lerr = TRUE; ok = FALSE; } else lerr = FALSE; From d093ab90e9c71e47a7618374d35dfb2cc27a963c Mon Sep 17 00:00:00 2001 From: moluopro Date: Fri, 10 Jul 2026 15:54:19 +0800 Subject: [PATCH 14/23] docs: clarify XERBLA handler concurrency --- docs/extensions.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/extensions.md b/docs/extensions.md index fb2dd9c805..78efc5dc58 100644 --- a/docs/extensions.md +++ b/docs/extensions.md @@ -47,8 +47,9 @@ BLAS-like and conversion functions for `hfloat16` (available when OpenBLAS was c * `int openblas_set_affinity(int thread_index, size_t cpusetsize, cpu_set_t *cpuset)` sets the CPU affinity mask of the given thread to the provided cpuset. Only available on Linux, with semantics identical to `pthread_setaffinity_np`. * `openblas_set_thread_callback_function` overrides the default multithreading backend with the provided argument -* `openblas_set_xerbla(openblas_xerbla_handler handler)` installs a process-wide XERBLA error handler and returns the previous one. - Installation is thread-safe, and passing `NULL` restores the default handler. The callback receives a read-only routine name, - error parameter number and normalized name length (excluding a terminating NUL when present); the name is not guaranteed to be - NUL-terminated. On ELF platforms, a legacy strong `xerbla` definition still takes precedence over this dispatcher. Callback code - must remain loaded until the handler has been replaced and all concurrent BLAS calls have completed. +* `openblas_set_xerbla(openblas_xerbla_handler handler)` installs a process-wide XERBLA error handler and returns the previous handler. + Passing `NULL` restores the default handler. Handler replacement is thread-safe, but callbacks may run concurrently and must + therefore be thread-safe. The routine name and error information are valid only for the duration of the callback. The name is + valid for the supplied length, is not necessarily NUL-terminated, and retains any trailing spaces; when a NUL is present, the + reported length stops before the first NUL. Replacing a handler does not wait for callbacks already in progress. On ELF platforms, + a legacy strong `xerbla` definition takes precedence over this dispatcher. From 97abc61bfc7257e9d750813b070141ae34dc1f2d Mon Sep 17 00:00:00 2001 From: moluopro Date: Fri, 10 Jul 2026 20:40:50 +0800 Subject: [PATCH 15/23] docs: clarify XERBLA handler behavior on ELF --- docs/extensions.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/extensions.md b/docs/extensions.md index 78efc5dc58..db7fad51ec 100644 --- a/docs/extensions.md +++ b/docs/extensions.md @@ -47,9 +47,10 @@ BLAS-like and conversion functions for `hfloat16` (available when OpenBLAS was c * `int openblas_set_affinity(int thread_index, size_t cpusetsize, cpu_set_t *cpuset)` sets the CPU affinity mask of the given thread to the provided cpuset. Only available on Linux, with semantics identical to `pthread_setaffinity_np`. * `openblas_set_thread_callback_function` overrides the default multithreading backend with the provided argument -* `openblas_set_xerbla(openblas_xerbla_handler handler)` installs a process-wide XERBLA error handler and returns the previous handler. - Passing `NULL` restores the default handler. Handler replacement is thread-safe, but callbacks may run concurrently and must - therefore be thread-safe. The routine name and error information are valid only for the duration of the callback. The name is - valid for the supplied length, is not necessarily NUL-terminated, and retains any trailing spaces; when a NUL is present, the - reported length stops before the first NUL. Replacing a handler does not wait for callbacks already in progress. On ELF platforms, - a legacy strong `xerbla` definition takes precedence over this dispatcher. +* `openblas_set_xerbla(openblas_xerbla_handler handler)` installs a process-wide XERBLA error handler and returns the + previous handler. Passing `NULL` restores the default handler. Handlers must be thread-safe because they may be called + concurrently. Replacing a handler is thread-safe but does not wait for in-progress calls to return, so the previous handler's + code must remain loaded until those calls finish. The `name` and `info` pointers are valid only during the callback. `name` + points to `name_length` valid bytes and need not be NUL-terminated; the length stops before the first NUL but otherwise includes + trailing spaces. Handler registration works normally on ELF platforms. For backward compatibility, an application-provided + strong `xerbla` symbol still overrides the OpenBLAS dispatcher and bypasses the registered handler. From 066e9076c30a7dce50c255a1d81b5621d9a56f90 Mon Sep 17 00:00:00 2001 From: moluopro Date: Sat, 11 Jul 2026 19:47:54 +0800 Subject: [PATCH 16/23] test: add a regular BLAS XERBLA bridge --- test/xerbla_test.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 test/xerbla_test.c diff --git a/test/xerbla_test.c b/test/xerbla_test.c new file mode 100644 index 0000000000..76c270f999 --- /dev/null +++ b/test/xerbla_test.c @@ -0,0 +1,51 @@ +/*************************************************************************** +Copyright (c) 2026, The OpenBLAS Project +All rights reserved. + +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. Neither the name of the OpenBLAS project nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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 "common.h" + +#ifdef OPENBLAS_TEST_USE_XERBLA_HANDLER +static void openblas_test_xerbla(const char *name, const blasint *info, + size_t name_length) { + blasint fortran_length = (blasint)name_length; + blasint fortran_info; + + if (name == NULL || info == NULL || fortran_length < 0 || + (size_t)fortran_length != name_length) + return; + + fortran_info = *info; + BLASFUNC(xerbla)((char *)name, &fortran_info, fortran_length); +} +#endif + +void BLASFUNC(openblas_test_set_xerbla)(void) { +#ifdef OPENBLAS_TEST_USE_XERBLA_HANDLER + openblas_set_xerbla(openblas_test_xerbla); +#endif +} From b5fa89f351e8960bfb602f03690174dffd72883d Mon Sep 17 00:00:00 2001 From: moluopro Date: Sat, 11 Jul 2026 19:48:33 +0800 Subject: [PATCH 17/23] cmake: harden regular BLAS error tests --- test/CMakeLists.txt | 63 +++++++++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bcee5ed666..5443b9238e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -31,9 +31,22 @@ if (USE_GEMM3M) endif () endif () +add_library(openblas_test_xerbla OBJECT xerbla_test.c) +# Static test executables provide their own XERBLA and must continue to test +# link-time interposition. Shared-only tests use the explicit handler because +# calls originating in a DLL or dylib cannot portably bind to that definition. +if (BUILD_SHARED_LIBS AND NOT BUILD_STATIC_LIBS) + target_compile_definitions(openblas_test_xerbla PRIVATE + OPENBLAS_TEST_USE_XERBLA_HANDLER) +endif() + foreach(test_bin ${OpenBLAS_Tests}) add_executable(${test_bin} ${test_bin}.f) -target_link_libraries(${test_bin} ${OpenBLAS_LIBNAME}) + if (test_bin MATCHES "blat(2|3)(_3m)?$") + target_sources(${test_bin} PRIVATE + $) + endif() + target_link_libraries(${test_bin} ${OpenBLAS_LIBNAME}) endforeach() if (BUILD_BFLOAT16) @@ -62,29 +75,45 @@ endif() if(WIN32) FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/test_helper.ps1 "[Console]::InputEncoding = New-Object Text.UTF8Encoding $false\n" -"if (Test-Path $args[2]) { Remove-Item -Force $args[2] } \n" "$ErrorActionPreference = \"Stop\"\n" -"Get-Content $args[1] | & $args[0]\n" -"If ((Get-Content $args[2] | %{$_ -match \"FATAL\"}) -contains $true) {\n" -"echo Error in $args[1]:\n" -"Get-Content $args[2] \n" -"exit 1\n" -"} else {\n" -"exit 0\n" +"if (Test-Path -LiteralPath $args[2]) { Remove-Item -LiteralPath $args[2] -Force }\n" +"Get-Content -LiteralPath $args[1] | & $args[0]\n" +"$testExitCode = $LASTEXITCODE\n" +"if ($testExitCode -ne 0) { exit $testExitCode }\n" +"if (-not (Test-Path -LiteralPath $args[2])) {\n" +" Write-Host \"Missing test summary: $($args[2])\"\n" +" exit 1\n" +"}\n" +"if (Select-String -LiteralPath $args[2] -Pattern \"FATAL|FAILED\" -Quiet) {\n" +" Write-Host \"Error in $($args[1]):\"\n" +" Get-Content -LiteralPath $args[2]\n" +" exit 1\n" "}\n" +"exit 0\n" ) set(helper_prefix powershell -ExecutionPolicy Bypass "${CMAKE_CURRENT_BINARY_DIR}/test_helper.ps1") else() FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/test_helper.sh -"rm -f $3\n" -"$1 < $2\n" -"grep -q FATAL $3\n" -"if [ $? -eq 0 ]; then\n" -"echo Error\n" -"exit 1\n" -"else\n" -"exit 0\n" +"rm -f \"$3\"\n" +"remove_status=$?\n" +"if [ $remove_status -ne 0 ]; then\n" +" echo \"Unable to remove stale test summary: $3\"\n" +" exit $remove_status\n" +"fi\n" +"\"$1\" < \"$2\"\n" +"test_exit_code=$?\n" +"if [ $test_exit_code -ne 0 ]; then exit $test_exit_code; fi\n" +"if [ ! -f \"$3\" ]; then\n" +" echo \"Missing test summary: $3\"\n" +" exit 1\n" "fi\n" +"grep -q -e FATAL -e FAILED \"$3\"\n" +"summary_status=$?\n" +"case $summary_status in\n" +" 0) echo \"Error in $2:\"; cat \"$3\"; exit 1 ;;\n" +" 1) exit 0 ;;\n" +" *) echo \"Unable to read test summary: $3\"; exit $summary_status ;;\n" +"esac\n" ) set(helper_prefix sh "${CMAKE_CURRENT_BINARY_DIR}/test_helper.sh") endif() From 7a24cf7a6a7061d8b2687859477d7d9504893a15 Mon Sep 17 00:00:00 2001 From: moluopro Date: Sat, 11 Jul 2026 19:49:33 +0800 Subject: [PATCH 18/23] test: harden Makefile result handling --- test/Makefile | 149 +++++++++++++++++++++++++++----------------------- 1 file changed, 81 insertions(+), 68 deletions(-) diff --git a/test/Makefile b/test/Makefile index be472f03f9..949eb2faec 100644 --- a/test/Makefile +++ b/test/Makefile @@ -37,6 +37,16 @@ endif # override CFLAGS += -std=c11 -Wall -Werror SUPPORT_GEMM3M = 0 +XERBLA_TEST = xerbla_test.$(SUFFIX) + +define CHECK_TEST_SUMMARY +@status=0; $(GREP) -q -e FATAL -e FAILED "$(1)" || status=$$?; \ +case $$status in \ + 0) cat "$(1)"; exit 1 ;; \ + 1) ;; \ + *) echo "Unable to read test summary: $(1)"; exit $$status ;; \ +esac +endef ifeq ($(ARCH), x86) SUPPORT_GEMM3M = 1 @@ -146,85 +156,85 @@ ifneq ($(CROSS), 1) rm -f ?BLAT2.SUMM ifeq ($(BUILD_BFLOAT16),1) OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 ./test_bgemv$(EXE) > BBLAT2.SUMM - @$(GREP) -q FATAL BBLAT2.SUMM && cat BBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,BBLAT2.SUMM) OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 ./test_sbgemv$(EXE) > SBBLAT2.SUMM - @$(GREP) -q FATAL SBBLAT2.SUMM && cat SBBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,SBBLAT2.SUMM) endif ifeq ($(BUILD_HFLOAT16),1) OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 ./test_shgemv$(EXE) > SHBLAT2.SUMM - @$(GREP) -q FATAL SHBLAT2.SUMM && cat SHBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,SHBLAT2.SUMM) endif ifeq ($(BUILD_SINGLE),1) OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 ./sblat2$(EXE) < ./sblat2.dat - @$(GREP) -q FATAL SBLAT2.SUMM && cat SBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,SBLAT2.SUMM) endif ifeq ($(BUILD_DOUBLE),1) OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 ./dblat2$(EXE) < ./dblat2.dat - @$(GREP) -q FATAL DBLAT2.SUMM && cat DBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,DBLAT2.SUMM) endif ifeq ($(BUILD_COMPLEX),1) OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 ./cblat2$(EXE) < ./cblat2.dat - @$(GREP) -q FATAL CBLAT2.SUMM && cat CBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,CBLAT2.SUMM) endif ifeq ($(BUILD_COMPLEX16),1) OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 ./zblat2$(EXE) < ./zblat2.dat - @$(GREP) -q FATAL ZBLAT2.SUMM && cat ZBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,ZBLAT2.SUMM) endif ifdef SMP rm -f ?BLAT2.SUMM ifeq ($(USE_OPENMP), 1) ifeq ($(BUILD_BFLOAT16),1) OMP_NUM_THREADS=2 ./test_bgemv$(EXE) > BBLAT2.SUMM - @$(GREP) -q FATAL BBLAT2.SUMM && cat BBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,BBLAT2.SUMM) OMP_NUM_THREADS=2 ./test_sbgemv$(EXE) > SBBLAT2.SUMM - @$(GREP) -q FATAL SBBLAT2.SUMM && cat SBBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,SBBLAT2.SUMM) endif ifeq ($(BUILD_HFLOAT16),1) OMP_NUM_THREADS=2 ./test_shgemv$(EXE) > SHBLAT2.SUMM - @$(GREP) -q FATAL SHBLAT2.SUMM && cat SHBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,SHBLAT2.SUMM) endif ifeq ($(BUILD_SINGLE),1) OMP_NUM_THREADS=2 ./sblat2$(EXE) < ./sblat2.dat - @$(GREP) -q FATAL SBLAT2.SUMM && cat SBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,SBLAT2.SUMM) endif ifeq ($(BUILD_DOUBLE),1) OMP_NUM_THREADS=2 ./dblat2$(EXE) < ./dblat2.dat - @$(GREP) -q FATAL DBLAT2.SUMM && cat DBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,DBLAT2.SUMM) endif ifeq ($(BUILD_COMPLEX),1) OMP_NUM_THREADS=2 ./cblat2$(EXE) < ./cblat2.dat - @$(GREP) -q FATAL CBLAT2.SUMM && cat CBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,CBLAT2.SUMM) endif ifeq ($(BUILD_COMPLEX16),1) OMP_NUM_THREADS=2 ./zblat2$(EXE) < ./zblat2.dat - @$(GREP) -q FATAL ZBLAT2.SUMM && cat ZBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,ZBLAT2.SUMM) endif else ifeq ($(BUILD_BFLOAT16),1) OMP_NUM_THREADS=2 ./test_bgemv$(EXE) > BBLAT2.SUMM - @$(GREP) -q FATAL BBLAT2.SUMM && cat BBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,BBLAT2.SUMM) OMP_NUM_THREADS=2 ./test_sbgemv$(EXE) > SBBLAT2.SUMM - @$(GREP) -q FATAL SBBLAT2.SUMM && cat SBBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,SBBLAT2.SUMM) endif ifeq ($(BUILD_HFLOAT16),1) OMP_NUM_THREADS=2 ./test_shgemv$(EXE) > SHBLAT2.SUMM - @$(GREP) -q FATAL SHBLAT2.SUMM && cat SHBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,SHBLAT2.SUMM) endif ifeq ($(BUILD_SINGLE),1) OPENBLAS_NUM_THREADS=2 ./sblat2$(EXE) < ./sblat2.dat - @$(GREP) -q FATAL SBLAT2.SUMM && cat SBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,SBLAT2.SUMM) endif ifeq ($(BUILD_DOUBLE),1) OPENBLAS_NUM_THREADS=2 ./dblat2$(EXE) < ./dblat2.dat - @$(GREP) -q FATAL DBLAT2.SUMM && cat DBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,DBLAT2.SUMM) endif ifeq ($(BUILD_COMPLEX),1) OPENBLAS_NUM_THREADS=2 ./cblat2$(EXE) < ./cblat2.dat - @$(GREP) -q FATAL CBLAT2.SUMM && cat CBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,CBLAT2.SUMM) endif ifeq ($(BUILD_COMPLEX16),1) OPENBLAS_NUM_THREADS=2 ./zblat2$(EXE) < ./zblat2.dat - @$(GREP) -q FATAL ZBLAT2.SUMM && cat ZBLAT2.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,ZBLAT2.SUMM) endif endif endif @@ -273,86 +283,86 @@ ifneq ($(CROSS), 1) rm -f ?BLAT3.SUMM ifeq ($(BUILD_BFLOAT16),1) OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 ./test_sbgemm$(EXE) > SBBLAT3.SUMM - @$(GREP) -q FATAL SBBLAT3.SUMM && cat SBBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,SBBLAT3.SUMM) OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 ./test_bgemm$(EXE) > BBLAT3.SUMM - @$(GREP) -q FATAL BBLAT3.SUMM && cat BBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,BBLAT3.SUMM) endif ifeq ($(BUILD_HFLOAT16),1) OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 ./test_shgemm > SHBLAT3.SUMM - @$(GREP) -q FATAL SHBLAT3.SUMM && cat SHBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,SHBLAT3.SUMM) endif ifeq ($(BUILD_SINGLE),1) OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 ./sblat3$(EXE) < ./sblat3.dat - @$(GREP) -q FATAL SBLAT3.SUMM && cat SBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,SBLAT3.SUMM) endif ifeq ($(BUILD_DOUBLE),1) OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 ./dblat3$(EXE) < ./dblat3.dat - @$(GREP) -q FATAL DBLAT3.SUMM && cat DBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,DBLAT3.SUMM) endif ifeq ($(BUILD_COMPLEX),1) OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 ./cblat3$(EXE) < ./cblat3.dat - @$(GREP) -q FATAL CBLAT3.SUMM && cat CBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,CBLAT3.SUMM) endif ifeq ($(BUILD_COMPLEX16),1) OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 ./zblat3$(EXE) < ./zblat3.dat - @$(GREP) -q FATAL ZBLAT3.SUMM && cat ZBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,ZBLAT3.SUMM) endif ifdef SMP rm -f ?BLAT3.SUMM ifeq ($(USE_OPENMP), 1) ifeq ($(BUILD_BFLOAT16),1) OMP_NUM_THREADS=2 ./test_sbgemm$(EXE) > SBBLAT3.SUMM - @$(GREP) -q FATAL SBBLAT3.SUMM && cat SBBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,SBBLAT3.SUMM) OMP_NUM_THREADS=2 ./test_bgemm$(EXE) > BBLAT3.SUMM - @$(GREP) -q FATAL BBLAT3.SUMM && cat BBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,BBLAT3.SUMM) endif ifeq ($(BUILD_HFLOAT16),1) OMP_NUM_THREADS=2 ./test_shgemm > SHBLAT3.SUMM - @$(GREP) -q FATAL SHBLAT3.SUMM && cat SHBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,SHBLAT3.SUMM) endif ifeq ($(BUILD_SINGLE),1) OMP_NUM_THREADS=2 ./sblat3$(EXE) < ./sblat3.dat - @$(GREP) -q FATAL SBLAT3.SUMM && cat SBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,SBLAT3.SUMM) endif ifeq ($(BUILD_DOUBLE),1) OMP_NUM_THREADS=2 ./dblat3$(EXE) < ./dblat3.dat - @$(GREP) -q FATAL DBLAT3.SUMM && cat DBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,DBLAT3.SUMM) endif ifeq ($(BUILD_COMPLEX),1) OMP_NUM_THREADS=2 ./cblat3$(EXE) < ./cblat3.dat - @$(GREP) -q FATAL CBLAT3.SUMM && cat CBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,CBLAT3.SUMM) endif ifeq ($(BUILD_COMPLEX16),1) OMP_NUM_THREADS=2 ./zblat3$(EXE) < ./zblat3.dat - @$(GREP) -q FATAL ZBLAT3.SUMM && cat ZBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,ZBLAT3.SUMM) endif else ifeq ($(BUILD_BFLOAT16),1) OPENBLAS_NUM_THREADS=2 ./test_sbgemm$(EXE) > SBBLAT3.SUMM - @$(GREP) -q FATAL SBBLAT3.SUMM && cat SBBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,SBBLAT3.SUMM) OPENBLAS_NUM_THREADS=2 ./test_bgemm$(EXE) > BBLAT3.SUMM - @$(GREP) -q FATAL BBLAT3.SUMM && cat BBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,BBLAT3.SUMM) endif ifeq ($(BUILD_HFLOAT16),1) OPENBLAS_NUM_THREADS=2 ./test_shgemm > SHBLAT3.SUMM - @$(GREP) -q FATAL SHBLAT3.SUMM && cat SHBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,SHBLAT3.SUMM) endif ifeq ($(BUILD_SINGLE),1) OPENBLAS_NUM_THREADS=2 ./sblat3$(EXE) < ./sblat3.dat - @$(GREP) -q FATAL SBLAT3.SUMM && cat SBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,SBLAT3.SUMM) endif ifeq ($(BUILD_DOUBLE),1) OPENBLAS_NUM_THREADS=2 ./dblat3$(EXE) < ./dblat3.dat - @$(GREP) -q FATAL DBLAT3.SUMM && cat DBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,DBLAT3.SUMM) endif ifeq ($(BUILD_COMPLEX),1) OPENBLAS_NUM_THREADS=2 ./cblat3$(EXE) < ./cblat3.dat - @$(GREP) -q FATAL CBLAT3.SUMM && cat CBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,CBLAT3.SUMM) endif ifeq ($(BUILD_COMPLEX16),1) OPENBLAS_NUM_THREADS=2 ./zblat3$(EXE) < ./zblat3.dat - @$(GREP) -q FATAL ZBLAT3.SUMM && cat ZBLAT3.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,ZBLAT3.SUMM) endif endif endif @@ -364,31 +374,31 @@ ifneq ($(CROSS), 1) rm -f ?BLAT3_3M.SUMM ifeq ($(BUILD_COMPLEX),1) OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 ./cblat3_3m$(EXE) < ./cblat3_3m.dat - @$(GREP) -q FATAL CBLAT3_3M.SUMM && cat CBLAT3_3M.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,CBLAT3_3M.SUMM) endif ifeq ($(BUILD_COMPLEX16),1) OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 ./zblat3_3m$(EXE) < ./zblat3_3m.dat - @$(GREP) -q FATAL ZBLAT3_3M.SUMM && cat ZBLAT3_3M.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,ZBLAT3_3M.SUMM) endif ifdef SMP rm -f ?BLAT3_3M.SUMM ifeq ($(USE_OPENMP), 1) ifeq ($(BUILD_COMPLEX),1) OMP_NUM_THREADS=2 ./cblat3_3m$(EXE) < ./cblat3_3m.dat - @$(GREP) -q FATAL CBLAT3_3M.SUMM && cat CBLAT3_3M.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,CBLAT3_3M.SUMM) endif ifeq ($(BUILD_COMPLEX16),1) OMP_NUM_THREADS=2 ./zblat3_3m$(EXE) < ./zblat3_3m.dat - @$(GREP) -q FATAL ZBLAT3_3M.SUMM && cat ZBLAT3_3M.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,ZBLAT3_3M.SUMM) endif else ifeq ($(BUILD_COMPLEX),1) OPENBLAS_NUM_THREADS=2 ./cblat3_3m$(EXE) < ./cblat3_3m.dat - @$(GREP) -q FATAL CBLAT3_3M.SUMM && cat CBLAT3_3M.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,CBLAT3_3M.SUMM) endif ifeq ($(BUILD_COMPLEX16),1) OPENBLAS_NUM_THREADS=2 ./zblat3_3m$(EXE) < ./zblat3_3m.dat - @$(GREP) -q FATAL ZBLAT3_3M.SUMM && cat ZBLAT3_3M.SUMM || exit 0 + $(call CHECK_TEST_SUMMARY,ZBLAT3_3M.SUMM) endif endif endif @@ -420,26 +430,29 @@ endif endif endif +$(XERBLA_TEST): xerbla_test.c + $(CC) $(CFLAGS) -c $< -o $@ + ifeq ($(BUILD_SINGLE),1) sblat1$(EXE) : sblat1.$(SUFFIX) ../$(LIBNAME) $(FC) $(FLDFLAGS) -o $@ sblat1.$(SUFFIX) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) -sblat2$(EXE) : sblat2.$(SUFFIX) ../$(LIBNAME) - $(FC) $(FLDFLAGS) -o $@ sblat2.$(SUFFIX) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) +sblat2$(EXE) : sblat2.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) + $(FC) $(FLDFLAGS) -o $@ sblat2.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) -sblat3$(EXE) : sblat3.$(SUFFIX) ../$(LIBNAME) - $(FC) $(FLDFLAGS) -o $@ sblat3.$(SUFFIX) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) +sblat3$(EXE) : sblat3.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) + $(FC) $(FLDFLAGS) -o $@ sblat3.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) endif ifeq ($(BUILD_DOUBLE),1) dblat1$(EXE) : dblat1.$(SUFFIX) ../$(LIBNAME) $(FC) $(FLDFLAGS) -o $@ dblat1.$(SUFFIX) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) -dblat2$(EXE) : dblat2.$(SUFFIX) ../$(LIBNAME) - $(FC) $(FLDFLAGS) -o $@ dblat2.$(SUFFIX) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) +dblat2$(EXE) : dblat2.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) + $(FC) $(FLDFLAGS) -o $@ dblat2.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) -dblat3$(EXE) : dblat3.$(SUFFIX) ../$(LIBNAME) - $(FC) $(FLDFLAGS) -o $@ dblat3.$(SUFFIX) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) +dblat3$(EXE) : dblat3.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) + $(FC) $(FLDFLAGS) -o $@ dblat3.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) else dblat2$(EXE): dblat3$(EXE): @@ -453,22 +466,22 @@ ifeq ($(BUILD_COMPLEX),1) cblat1$(EXE) : cblat1.$(SUFFIX) ../$(LIBNAME) $(FC) $(FLDFLAGS) -o $@ cblat1.$(SUFFIX) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) -cblat2$(EXE) : cblat2.$(SUFFIX) ../$(LIBNAME) - $(FC) $(FLDFLAGS) -o $@ cblat2.$(SUFFIX) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) +cblat2$(EXE) : cblat2.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) + $(FC) $(FLDFLAGS) -o $@ cblat2.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) -cblat3$(EXE) : cblat3.$(SUFFIX) ../$(LIBNAME) - $(FC) $(FLDFLAGS) -o $@ cblat3.$(SUFFIX) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) +cblat3$(EXE) : cblat3.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) + $(FC) $(FLDFLAGS) -o $@ cblat3.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) endif ifeq ($(BUILD_COMPLEX16),1) zblat1$(EXE) : zblat1.$(SUFFIX) ../$(LIBNAME) $(FC) $(FLDFLAGS) -o $@ zblat1.$(SUFFIX) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) -zblat2$(EXE) : zblat2.$(SUFFIX) ../$(LIBNAME) - $(FC) $(FLDFLAGS) -o $@ zblat2.$(SUFFIX) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) +zblat2$(EXE) : zblat2.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) + $(FC) $(FLDFLAGS) -o $@ zblat2.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) -zblat3$(EXE) : zblat3.$(SUFFIX) ../$(LIBNAME) - $(FC) $(FLDFLAGS) -o $@ zblat3.$(SUFFIX) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) +zblat3$(EXE) : zblat3.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) + $(FC) $(FLDFLAGS) -o $@ zblat3.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) endif ifeq ($(BUILD_BFLOAT16),1) @@ -495,13 +508,13 @@ endif ifeq ($(BUILD_COMPLEX),1) -cblat3_3m$(EXE) : cblat3_3m.$(SUFFIX) ../$(LIBNAME) - $(FC) $(FLDFLAGS) -o $@ cblat3_3m.$(SUFFIX) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) +cblat3_3m$(EXE) : cblat3_3m.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) + $(FC) $(FLDFLAGS) -o $@ cblat3_3m.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) endif ifeq ($(BUILD_COMPLEX16),1) -zblat3_3m$(EXE) : zblat3_3m.$(SUFFIX) ../$(LIBNAME) - $(FC) $(FLDFLAGS) -o $@ zblat3_3m.$(SUFFIX) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) +zblat3_3m$(EXE) : zblat3_3m.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) + $(FC) $(FLDFLAGS) -o $@ zblat3_3m.$(SUFFIX) $(XERBLA_TEST) ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) endif From e4891bc055e4e654c2f3df234065fb4750ecac16 Mon Sep 17 00:00:00 2001 From: moluopro Date: Sat, 11 Jul 2026 19:50:56 +0800 Subject: [PATCH 19/23] test: register XERBLA for level 2 BLAS --- test/cblat2.f | 1 + test/dblat2.f | 1 + test/sblat2.f | 1 + test/zblat2.f | 1 + 4 files changed, 4 insertions(+) diff --git a/test/cblat2.f b/test/cblat2.f index 8c7bac48ea..23df40eb0b 100644 --- a/test/cblat2.f +++ b/test/cblat2.f @@ -2401,6 +2401,7 @@ SUBROUTINE CCHKE( ISNUM, SRNAMT, NOUT ) * .. Common blocks .. COMMON /INFOC/INFOT, NOUTC, OK, LERR * .. Executable Statements .. + CALL OPENBLAS_TEST_SET_XERBLA * OK is set to .FALSE. by the special version of XERBLA or by CHKXER * if anything is wrong. OK = .TRUE. diff --git a/test/dblat2.f b/test/dblat2.f index 9bbbe9792b..3481238c3b 100644 --- a/test/dblat2.f +++ b/test/dblat2.f @@ -2351,6 +2351,7 @@ SUBROUTINE DCHKE( ISNUM, SRNAMT, NOUT ) * .. Common blocks .. COMMON /INFOC/INFOT, NOUTC, OK, LERR * .. Executable Statements .. + CALL OPENBLAS_TEST_SET_XERBLA * OK is set to .FALSE. by the special version of XERBLA or by CHKXER * if anything is wrong. OK = .TRUE. diff --git a/test/sblat2.f b/test/sblat2.f index 56ead8640d..91aecd7a64 100644 --- a/test/sblat2.f +++ b/test/sblat2.f @@ -2351,6 +2351,7 @@ SUBROUTINE SCHKE( ISNUM, SRNAMT, NOUT ) * .. Common blocks .. COMMON /INFOC/INFOT, NOUTC, OK, LERR * .. Executable Statements .. + CALL OPENBLAS_TEST_SET_XERBLA * OK is set to .FALSE. by the special version of XERBLA or by CHKXER * if anything is wrong. OK = .TRUE. diff --git a/test/zblat2.f b/test/zblat2.f index 4a20ac5675..f92e983219 100644 --- a/test/zblat2.f +++ b/test/zblat2.f @@ -2408,6 +2408,7 @@ SUBROUTINE ZCHKE( ISNUM, SRNAMT, NOUT ) * .. Common blocks .. COMMON /INFOC/INFOT, NOUTC, OK, LERR * .. Executable Statements .. + CALL OPENBLAS_TEST_SET_XERBLA * OK is set to .FALSE. by the special version of XERBLA or by CHKXER * if anything is wrong. OK = .TRUE. From 8ac41809cf80311baee6a620b2d860c33d1b9391 Mon Sep 17 00:00:00 2001 From: moluopro Date: Sat, 11 Jul 2026 19:52:20 +0800 Subject: [PATCH 20/23] test: register XERBLA for level 3 BLAS --- test/cblat3.f | 1 + test/cblat3_3m.f | 1 + test/dblat3.f | 1 + test/sblat3.f | 1 + test/zblat3.f | 1 + test/zblat3_3m.f | 1 + 6 files changed, 6 insertions(+) diff --git a/test/cblat3.f b/test/cblat3.f index a65e1364cf..316e0ff952 100644 --- a/test/cblat3.f +++ b/test/cblat3.f @@ -2019,6 +2019,7 @@ SUBROUTINE CCHKE( ISNUM, SRNAMT, NOUT ) * .. Common blocks .. COMMON /INFOC/INFOT, NOUTC, OK, LERR * .. Executable Statements .. + CALL OPENBLAS_TEST_SET_XERBLA * OK is set to .FALSE. by the special version of XERBLA or by CHKXER * if anything is wrong. OK = .TRUE. diff --git a/test/cblat3_3m.f b/test/cblat3_3m.f index 6c7d7e1693..b744c514bc 100644 --- a/test/cblat3_3m.f +++ b/test/cblat3_3m.f @@ -1976,6 +1976,7 @@ SUBROUTINE CCHKE( ISNUM, SRNAMT, NOUT ) * .. Common blocks .. COMMON /INFOC/INFOT, NOUTC, OK, LERR * .. Executable Statements .. + CALL OPENBLAS_TEST_SET_XERBLA * OK is set to .FALSE. by the special version of XERBLA or by CHKXER * if anything is wrong. OK = .TRUE. diff --git a/test/dblat3.f b/test/dblat3.f index 1ebec4ffa6..51738036d7 100644 --- a/test/dblat3.f +++ b/test/dblat3.f @@ -1873,6 +1873,7 @@ SUBROUTINE DCHKE( ISNUM, SRNAMT, NOUT ) * .. Common blocks .. COMMON /INFOC/INFOT, NOUTC, OK, LERR * .. Executable Statements .. + CALL OPENBLAS_TEST_SET_XERBLA * OK is set to .FALSE. by the special version of XERBLA or by CHKXER * if anything is wrong. OK = .TRUE. diff --git a/test/sblat3.f b/test/sblat3.f index 66edac14ea..2534d8dc2c 100644 --- a/test/sblat3.f +++ b/test/sblat3.f @@ -1873,6 +1873,7 @@ SUBROUTINE SCHKE( ISNUM, SRNAMT, NOUT ) * .. Common blocks .. COMMON /INFOC/INFOT, NOUTC, OK, LERR * .. Executable Statements .. + CALL OPENBLAS_TEST_SET_XERBLA * OK is set to .FALSE. by the special version of XERBLA or by CHKXER * if anything is wrong. OK = .TRUE. diff --git a/test/zblat3.f b/test/zblat3.f index 0e38334e9a..785ca932c1 100644 --- a/test/zblat3.f +++ b/test/zblat3.f @@ -2026,6 +2026,7 @@ SUBROUTINE ZCHKE( ISNUM, SRNAMT, NOUT ) * .. Common blocks .. COMMON /INFOC/INFOT, NOUTC, OK, LERR * .. Executable Statements .. + CALL OPENBLAS_TEST_SET_XERBLA * OK is set to .FALSE. by the special version of XERBLA or by CHKXER * if anything is wrong. OK = .TRUE. diff --git a/test/zblat3_3m.f b/test/zblat3_3m.f index e65c72b489..4145debdbd 100644 --- a/test/zblat3_3m.f +++ b/test/zblat3_3m.f @@ -1979,6 +1979,7 @@ SUBROUTINE ZCHKE( ISNUM, SRNAMT, NOUT ) * .. Common blocks .. COMMON /INFOC/INFOT, NOUTC, OK, LERR * .. Executable Statements .. + CALL OPENBLAS_TEST_SET_XERBLA * OK is set to .FALSE. by the special version of XERBLA or by CHKXER * if anything is wrong. OK = .TRUE. From 03cfefcdcbf7c048719e4379913b13a538557617 Mon Sep 17 00:00:00 2001 From: moluopro Date: Sat, 11 Jul 2026 19:53:42 +0800 Subject: [PATCH 21/23] cmake: propagate CBLAS test failures on Windows --- ctest/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/ctest/CMakeLists.txt b/ctest/CMakeLists.txt index 83a7150057..bed6a4e1f8 100644 --- a/ctest/CMakeLists.txt +++ b/ctest/CMakeLists.txt @@ -18,6 +18,7 @@ if(WIN32) FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/test_cblas_helper.ps1 "$ErrorActionPreference = \"Stop\"\n" "Get-Content $args[1] | & $args[0]\n" +"exit $LASTEXITCODE\n" ) set(test_helper powershell -ExecutionPolicy Bypass "${CMAKE_CURRENT_BINARY_DIR}/test_cblas_helper.ps1") else() From 477131d54720e8acea9934c5281616d52d598ecc Mon Sep 17 00:00:00 2001 From: moluopro Date: Sat, 11 Jul 2026 20:02:13 +0800 Subject: [PATCH 22/23] cblas: clarify XERBLA handler lifetime --- cblas.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cblas.h b/cblas.h index 3d4143256b..f406c20432 100644 --- a/cblas.h +++ b/cblas.h @@ -59,10 +59,12 @@ typedef void (*openblas_dojob_callback)(int thread_num, void *jobdata, int dojob typedef void (*openblas_threads_callback)(int sync, openblas_dojob_callback dojob, int numjobs, size_t jobdata_elsize, void *jobdata, int dojob_data); void openblas_set_threads_callback_function(openblas_threads_callback callback); -/* Set the process-wide error handler called by XERBLA. The callback's routine - * name is valid for name_length bytes and is not necessarily NUL-terminated. - * Installation is thread-safe, returns the previous handler, and accepts NULL - * to restore OpenBLAS' default handler. */ +/* Replace the XERBLA handler for this OpenBLAS instance and return the + * previous handler. Passing NULL restores the default. Callbacks may run + * concurrently and must be thread-safe. The name and info pointers are valid + * only during the callback; name spans name_length bytes and need not be + * NUL-terminated. Replacement is thread-safe but does not wait for in-flight + * calls, so the previous handler must remain loaded until they complete. */ #ifndef OPENBLAS_XERBLA_HANDLER_DEFINED #define OPENBLAS_XERBLA_HANDLER_DEFINED typedef void (*openblas_xerbla_handler)(const char *name, From 6720959694205cb1a0f94fbea0a6ab523bad99a9 Mon Sep 17 00:00:00 2001 From: moluopro Date: Sat, 11 Jul 2026 20:02:43 +0800 Subject: [PATCH 23/23] docs: summarize XERBLA handler semantics --- docs/extensions.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/docs/extensions.md b/docs/extensions.md index db7fad51ec..d45fb92a48 100644 --- a/docs/extensions.md +++ b/docs/extensions.md @@ -47,10 +47,7 @@ BLAS-like and conversion functions for `hfloat16` (available when OpenBLAS was c * `int openblas_set_affinity(int thread_index, size_t cpusetsize, cpu_set_t *cpuset)` sets the CPU affinity mask of the given thread to the provided cpuset. Only available on Linux, with semantics identical to `pthread_setaffinity_np`. * `openblas_set_thread_callback_function` overrides the default multithreading backend with the provided argument -* `openblas_set_xerbla(openblas_xerbla_handler handler)` installs a process-wide XERBLA error handler and returns the - previous handler. Passing `NULL` restores the default handler. Handlers must be thread-safe because they may be called - concurrently. Replacing a handler is thread-safe but does not wait for in-progress calls to return, so the previous handler's - code must remain loaded until those calls finish. The `name` and `info` pointers are valid only during the callback. `name` - points to `name_length` valid bytes and need not be NUL-terminated; the length stops before the first NUL but otherwise includes - trailing spaces. Handler registration works normally on ELF platforms. For backward compatibility, an application-provided - strong `xerbla` symbol still overrides the OpenBLAS dispatcher and bypasses the registered handler. +* `openblas_set_xerbla(openblas_xerbla_handler handler)` replaces the XERBLA handler for the current OpenBLAS + instance and returns the previous handler; passing `NULL` restores the default. Callbacks may be invoked concurrently + and therefore must be thread-safe. `name` is valid for `name_length` bytes during the callback and need not be + NUL-terminated. On ELF platforms, an application-provided strong `xerbla` symbol bypasses the registered handler.