(root)/
strace-6.5/
src/
affinity.c
       1  /*
       2   * Copyright (c) 2002-2004 Roland McGrath <roland@redhat.com>
       3   * Copyright (c) 2009-2018 Dmitry V. Levin <ldv@strace.io>
       4   * Copyright (c) 2014-2022 The strace developers.
       5   * All rights reserved.
       6   *
       7   * SPDX-License-Identifier: LGPL-2.1-or-later
       8   */
       9  
      10  #include "defs.h"
      11  #include <sched.h>
      12  
      13  static unsigned int
      14  get_cpuset_size(void)
      15  {
      16  	static unsigned int cpuset_size;
      17  
      18  	if (!cpuset_size) {
      19  		/*
      20  		 * If the cpuset size passed to sched_getaffinity is less
      21  		 * than necessary to store the bitmask, the kernel does not
      22  		 * look at the mask pointer and fails with EINVAL.
      23  		 *
      24  		 * If the cpuset size is large enough, the kernel fails with
      25  		 * EFAULT on inaccessible mask pointers.
      26  		 *
      27  		 * This undocumented kernel feature can be used to probe
      28  		 * the kernel and find out the minimal valid cpuset size
      29  		 * without allocating any memory for the CPU affinity mask.
      30  		 */
      31  		cpuset_size = 128;
      32  		while (cpuset_size &&
      33  		       sched_getaffinity(0, cpuset_size, NULL) == -1 &&
      34  		       EINVAL == errno) {
      35  			cpuset_size <<= 1;
      36  		}
      37  		if (!cpuset_size)
      38  			cpuset_size = 128;
      39  	}
      40  
      41  	return cpuset_size;
      42  }
      43  
      44  void
      45  print_affinitylist(struct tcb *const tcp, const kernel_ulong_t addr,
      46  		   const unsigned int len)
      47  {
      48  	const unsigned int max_size = get_cpuset_size();
      49  	const unsigned int umove_size = MIN(len, max_size);
      50  	const unsigned int size = ROUNDUP(umove_size, current_wordsize);
      51  	const unsigned int ncpu = size * 8;
      52  	void *cpu;
      53  
      54  	if (!verbose(tcp) || (exiting(tcp) && syserror(tcp)) ||
      55  	    !addr) {
      56  		printaddr(addr);
      57  		return;
      58  	}
      59  
      60  	if (!len) {
      61  		tprint_array_begin();
      62  		tprint_array_end();
      63  		return;
      64  	}
      65  
      66  	if (!(cpu = calloc(size, 1))) {
      67  		printaddr(addr);
      68  		return;
      69  	}
      70  
      71  	if (!umoven_or_printaddr(tcp, addr, umove_size, cpu)) {
      72  		bool printed = false;
      73  
      74  		tprint_bitset_begin();
      75  		for (int i = 0;; i++) {
      76  			i = next_set_bit(cpu, i, ncpu);
      77  			if (i < 0)
      78  				break;
      79  			if (printed)
      80  				tprint_bitset_next();
      81  			else
      82  				printed = true;
      83  			PRINT_VAL_D(i);
      84  		}
      85  		if (size < len) {
      86  			if (printed)
      87  				tprint_bitset_next();
      88  			tprint_more_data_follows();
      89  		}
      90  		tprint_bitset_end();
      91  	}
      92  
      93  	free(cpu);
      94  }
      95  
      96  SYS_FUNC(sched_setaffinity)
      97  {
      98  	/* pid */
      99  	const int pid = tcp->u_arg[0];
     100  	printpid(tcp, pid, PT_TGID);
     101  	tprint_arg_next();
     102  
     103  	/* cpusetsize */
     104  	const unsigned int len = tcp->u_arg[1];
     105  	PRINT_VAL_U(len);
     106  	tprint_arg_next();
     107  
     108  	/* mask */
     109  	print_affinitylist(tcp, tcp->u_arg[2], len);
     110  
     111  	return RVAL_DECODED;
     112  }
     113  
     114  SYS_FUNC(sched_getaffinity)
     115  {
     116  	if (entering(tcp)) {
     117  		/* pid */
     118  		const int pid = tcp->u_arg[0];
     119  		printpid(tcp, pid, PT_TGID);
     120  		tprint_arg_next();
     121  
     122  		/* cpusetsize */
     123  		const unsigned int len = tcp->u_arg[1];
     124  		PRINT_VAL_U(len);
     125  		tprint_arg_next();
     126  	} else {
     127  		/* mask */
     128  		print_affinitylist(tcp, tcp->u_arg[2], tcp->u_rval);
     129  	}
     130  	return 0;
     131  }