Skip to content
Snippets Groups Projects
generate_initcall_order.pl 5.95 KiB
#!/usr/bin/env perl
# SPDX-License-Identifier: GPL-2.0
#
# Generates a linker script that specifies the correct initcall order.
#
# Copyright (C) 2019 Google LLC

use strict;
use warnings;
use IO::Handle;
use IO::Select;
use POSIX ":sys_wait_h";

my $nm = $ENV{'NM'} || die "$0: ERROR: NM not set?";
my $objtree = $ENV{'objtree'} || '.';

## currently active child processes
my $jobs = {};		# child process pid -> file handle
## results from child processes
my $results = {};	# object index -> [ { level, secname }, ... ]

## reads _NPROCESSORS_ONLN to determine the maximum number of processes to
## start
sub get_online_processors {
	open(my $fh, "getconf _NPROCESSORS_ONLN 2>/dev/null |")
		or die "$0: ERROR: failed to execute getconf: $!";
	my $procs = <$fh>;
	close($fh);

	if (!($procs =~ /^\d+$/)) {
		return 1;
	}

	return int($procs);
}

## writes results to the parent process
## format: <file index> <initcall level> <base initcall section name>
sub write_results {
	my ($index, $initcalls) = @_;

	# sort by the counter value to ensure the order of initcalls within
	# each object file is correct
	foreach my $counter (sort { $a <=> $b } keys(%{$initcalls})) {
		my $level = $initcalls->{$counter}->{'level'};

		# section name for the initcall function
		my $secname = $initcalls->{$counter}->{'module'} . '__' .
			      $counter . '_' .
			      $initcalls->{$counter}->{'line'} . '_' .
			      $initcalls->{$counter}->{'function'};

		print "$index $level $secname\n";
	}
}

## reads a result line from a child process and adds it to the $results array
sub read_results{
	my ($fh) = @_;

	# each child prints out a full line w/ autoflush and exits after the
	# last line, so even if buffered I/O blocks here, it shouldn't block
	# very long
	my $data = <$fh>;

	if (!defined($data)) {
		return 0;
	}

	chomp($data);