33#define _GNU_SOURCE
44#include <err.h>
55#include <errno.h>
6+ #include <pthread.h>
67#include <setjmp.h>
78#include <stdio.h>
89#include <string.h>
910#include <stdbool.h>
1011#include <unistd.h>
1112#include <x86intrin.h>
1213
13- #include <linux/futex.h>
14-
1514#include <sys/auxv.h>
1615#include <sys/mman.h>
1716#include <sys/shm.h>
@@ -259,7 +258,6 @@ void sig_print(char *msg)
259258
260259static volatile bool noperm_signaled ;
261260static int noperm_errs ;
262-
263261/*
264262 * Signal handler for when AMX is used but
265263 * permission has not been obtained.
@@ -674,6 +672,158 @@ static void test_fork(void)
674672 _exit (0 );
675673}
676674
675+ /* Context switching test */
676+
677+ static struct _ctxtswtest_cfg {
678+ unsigned int iterations ;
679+ unsigned int num_threads ;
680+ } ctxtswtest_config ;
681+
682+ struct futex_info {
683+ pthread_t thread ;
684+ int nr ;
685+ pthread_mutex_t mutex ;
686+ struct futex_info * next ;
687+ };
688+
689+ static void * check_tiledata (void * info )
690+ {
691+ struct futex_info * finfo = (struct futex_info * )info ;
692+ struct xsave_buffer * xbuf ;
693+ int i ;
694+
695+ xbuf = alloc_xbuf ();
696+ if (!xbuf )
697+ fatal_error ("unable to allocate XSAVE buffer" );
698+
699+ /*
700+ * Load random data into 'xbuf' and then restore
701+ * it to the tile registers themselves.
702+ */
703+ load_rand_tiledata (xbuf );
704+ for (i = 0 ; i < ctxtswtest_config .iterations ; i ++ ) {
705+ pthread_mutex_lock (& finfo -> mutex );
706+
707+ /*
708+ * Ensure the register values have not
709+ * diverged from those recorded in 'xbuf'.
710+ */
711+ validate_tiledata_regs_same (xbuf );
712+
713+ /* Load new, random values into xbuf and registers */
714+ load_rand_tiledata (xbuf );
715+
716+ /*
717+ * The last thread's last unlock will be for
718+ * thread 0's mutex. However, thread 0 will
719+ * have already exited the loop and the mutex
720+ * will already be unlocked.
721+ *
722+ * Because this is not an ERRORCHECK mutex,
723+ * that inconsistency will be silently ignored.
724+ */
725+ pthread_mutex_unlock (& finfo -> next -> mutex );
726+ }
727+
728+ free (xbuf );
729+ /*
730+ * Return this thread's finfo, which is
731+ * a unique value for this thread.
732+ */
733+ return finfo ;
734+ }
735+
736+ static int create_threads (int num , struct futex_info * finfo )
737+ {
738+ int i ;
739+
740+ for (i = 0 ; i < num ; i ++ ) {
741+ int next_nr ;
742+
743+ finfo [i ].nr = i ;
744+ /*
745+ * Thread 'i' will wait on this mutex to
746+ * be unlocked. Lock it immediately after
747+ * initialization:
748+ */
749+ pthread_mutex_init (& finfo [i ].mutex , NULL );
750+ pthread_mutex_lock (& finfo [i ].mutex );
751+
752+ next_nr = (i + 1 ) % num ;
753+ finfo [i ].next = & finfo [next_nr ];
754+
755+ if (pthread_create (& finfo [i ].thread , NULL , check_tiledata , & finfo [i ]))
756+ fatal_error ("pthread_create()" );
757+ }
758+ return 0 ;
759+ }
760+
761+ static void affinitize_cpu0 (void )
762+ {
763+ cpu_set_t cpuset ;
764+
765+ CPU_ZERO (& cpuset );
766+ CPU_SET (0 , & cpuset );
767+
768+ if (sched_setaffinity (0 , sizeof (cpuset ), & cpuset ) != 0 )
769+ fatal_error ("sched_setaffinity to CPU 0" );
770+ }
771+
772+ static void test_context_switch (void )
773+ {
774+ struct futex_info * finfo ;
775+ int i ;
776+
777+ /* Affinitize to one CPU to force context switches */
778+ affinitize_cpu0 ();
779+
780+ req_xtiledata_perm ();
781+
782+ printf ("[RUN]\tCheck tiledata context switches, %d iterations, %d threads.\n" ,
783+ ctxtswtest_config .iterations ,
784+ ctxtswtest_config .num_threads );
785+
786+
787+ finfo = malloc (sizeof (* finfo ) * ctxtswtest_config .num_threads );
788+ if (!finfo )
789+ fatal_error ("malloc()" );
790+
791+ create_threads (ctxtswtest_config .num_threads , finfo );
792+
793+ /*
794+ * This thread wakes up thread 0
795+ * Thread 0 will wake up 1
796+ * Thread 1 will wake up 2
797+ * ...
798+ * the last thread will wake up 0
799+ *
800+ * ... this will repeat for the configured
801+ * number of iterations.
802+ */
803+ pthread_mutex_unlock (& finfo [0 ].mutex );
804+
805+ /* Wait for all the threads to finish: */
806+ for (i = 0 ; i < ctxtswtest_config .num_threads ; i ++ ) {
807+ void * thread_retval ;
808+ int rc ;
809+
810+ rc = pthread_join (finfo [i ].thread , & thread_retval );
811+
812+ if (rc )
813+ fatal_error ("pthread_join() failed for thread %d err: %d\n" ,
814+ i , rc );
815+
816+ if (thread_retval != & finfo [i ])
817+ fatal_error ("unexpected thread retval for thread %d: %p\n" ,
818+ i , thread_retval );
819+
820+ }
821+
822+ printf ("[OK]\tNo incorrect case was found.\n" );
823+
824+ free (finfo );
825+ }
826+
677827int main (void )
678828{
679829 /* Check hardware availability at first */
@@ -690,6 +840,10 @@ int main(void)
690840
691841 test_fork ();
692842
843+ ctxtswtest_config .iterations = 10 ;
844+ ctxtswtest_config .num_threads = 5 ;
845+ test_context_switch ();
846+
693847 clearhandler (SIGILL );
694848 free_stashed_xsave ();
695849
0 commit comments