/************************************************* * Exim - an Internet mail transport agent * *************************************************/ /* Copyright (c) University of Cambridge 1997 - 2016 */ /* See the file NOTICE for conditions of use and distribution. */ /* Linux-specific code. This is concatenated onto the generic src/os.c file. */ /************************************************* * Load average computation * *************************************************/ /*Linux has an apparently unique way of getting the load average, so we provide a unique function here, and define OS_LOAD_AVERAGE to stop src/os.c trying to provide the function. However, when compiling os.c for utilities, we may not want this at all, so check that it isn't set first. */ #if !defined(OS_LOAD_AVERAGE) && defined(__linux__) #define OS_LOAD_AVERAGE /* Linux has 2 ways of returning load average: (1) Do a read on /proc/loadavg (2) Use the sysinfo library function and syscall The latter is simpler but in Linux 2.0 - 2.2 (and probably later releases) is exceptionally slow - 10-50ms per call is not unusual and about 100x slow the first method. This cripples high performance mail servers by increasing CPU utilisation by 3-5x. In Exim's very early days, it used the 1st method. Later, it switched to the 2nd method. Now it tries the 1st method and falls back to the 2nd if /proc is unavailable. */ #include static int linux_slow_getloadavg(void) { struct sysinfo s; double avg; if (sysinfo(&s) < 0) return -1; avg = (double) (s.loads[0]) / (1<next != NULL) last = last->next; while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, &dad_status, devname) != EOF) { struct sockaddr_in6 addr; /* This data has to survive for ever, so use malloc. */ next = store_malloc(sizeof(ip_address_item)); next->next = NULL; next->port = 0; sprintf(CS next->address, "%s:%s:%s:%s:%s:%s:%s:%s", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7]); /* Normalize the representation */ inet_pton(AF_INET6, CS next->address, &addr.sin6_addr); inet_ntop(AF_INET6, &addr.sin6_addr, CS next->address, sizeof(next->address)); if (yield == NULL) yield = last = next; else { last->next = next; last = next; } DEBUG(D_interface) debug_printf("Actual local interface address is %s (%s)\n", last->address, devname); } fclose(f); #endif /* HAVE_IPV6 */ return yield; } #endif /* FIND_RUNNING_INTERFACES */ /* End of os.c-Linux */