Hi Michael, On Thu, Nov 13, 2008 at 15:06, Michael Kerrisk <mtk.manpages@xxxxxxxxxxxxxx> wrote: > Hi Bert, > > I created this page by removing the CPU_*() material from > sched_setscheduler.2 and adding documentation of the many other macros > that have been added in more recent glibc releases. > > I remember looking at a mail thread you pointed at a few days back > where you said the interface of the CPU_*S() macros is somewhat > confusing in its use of bits in some places, and bytes in others. > It's hard to disagree with you -- so I included an example in the > man-pages which hopefully might reduce the confusion. > > Of course, since these are macros, my use of types in the prototypes > in the SYNOPSIS is in many cases invention; let me know if something > looks weird. > > Also, take a look at > http://sourceware.org/bugzilla/show_bug.cgi?id=7029. Unless I'm > confused (which is always possible), this is a real bug. Do you > agree? "It's hard to disagree with you." I can confirm this here on my x86-64 box, a x86-32 exec returns 2048 the x86-64 1024. > > Thanks, > > Michael > > .\" Copyright (C) 2006 Michael Kerrisk > .\" and Copyright (C) 2008 Linux Foundation, written by Michael Kerrisk > .\" <mtk.manpages@xxxxxxxxx> > .\" > .\" Permission is granted to make and distribute verbatim copies of this > .\" manual provided the copyright notice and this permission notice are > .\" preserved on all copies. > .\" > .\" Permission is granted to copy and distribute modified versions of this > .\" manual under the conditions for verbatim copying, provided that the > .\" entire resulting derived work is distributed under the terms of a > .\" permission notice identical to this one. > .\" > .\" Since the Linux kernel and libraries are constantly changing, this > .\" manual page may be incorrect or out-of-date. The author(s) assume no > .\" responsibility for errors or omissions, or for damages resulting from > .\" the use of the information contained herein. The author(s) may not > .\" have taken the same level of care in the production of this manual, > .\" which is licensed free of charge, as they might when working > .\" professionally. > .\" > .\" Formatted or processed versions of this manual, if unaccompanied by > .\" the source, must acknowledge the copyright and authors of this work. > .\" > .TH CPU_SET 2 2008-11-13 "Linux" "Linux Programmer's Manual" > .SH NAME > CPU_SET, CPU_CLR, CPU_ISSET, CPU_ZERO, CPU_COUNT, > CPU_AND, CPU_OR, CPU_XOR, CPU_EQUAL, > CPU_ALLOC, CPU_ALLOC_SIZE, CPU_FREE, > CPU_SET_S, CPU_CLR_S, CPU_ISSET_S, CPU_ZERO_S, > CPU_COUNT_S, CPU_AND_S, CPU_OR_S, CPU_XOR_S, CPU_EQUAL_S \- > macros for manipulating CPU sets > .SH SYNOPSIS > .nf > .B #define _GNU_SOURCE > .B #include <sched.h> > .sp > .BI "void CPU_ZERO(cpu_set_t *" set ); > .sp > .BI "void CPU_SET(int " cpu ", cpu_set_t *" set ); > .BI "void CPU_CLR(int " cpu ", cpu_set_t *" set ); > .BI "int CPU_ISSET(int " cpu ", cpu_set_t *" set ); > .sp > .BI "void CPU_COUNT(cpu_set_t *" set ); > .sp > .BI "void CPU_AND(cpu_set_t *" destset , > .BI " cpu_set_t *" srcset1 ", cpu_set_t *" srcset2 ); > .BI "void CPU_OR(cpu_set_t *" destset , > .BI " cpu_set_t *" srcset1 ", cpu_set_t *" srcset2 ); > .BI "void CPU_XOR(cpu_set_t *" destset , > .BI " cpu_set_t *" srcset1 ", cpu_set_t *" srcset2 ); > .sp > .BI "int CPU_EQUAL(cpu_set_t *" set1 ", cpu_set_t *" set2 ); > .sp > .BI "cpu_set_t *CPU_ALLOC(int " num_cpus ); > .BR "void CPU_FREE(cpu_set_t *" set ); > .BI "size_t CPU_ALLOC_SIZE(int " num_cpus ); > .sp > .BI "void CPU_ZERO_S(size_t " setsize ", cpu_set_t *" set ); > .sp > .BI "void CPU_SET_S(int " cpu ", size_t " setsize ", cpu_set_t *" set ); > .BI "void CPU_CLR_S(int " cpu ", size_t " setsize ", cpu_set_t *" set ); > .BI "int CPU_ISSET_S(int " cpu ", size_t " setsize ", cpu_set_t *" set ); > .sp > .BI "void CPU_COUNT_S(size_t " setsize ", cpu_set_t *" set ); > .sp > .BI "void CPU_AND_S(size_t " setsize ", cpu_set_t *" destset , > .BI " cpu_set_t *" srcset1 ", cpu_set_t *" srcset2 ); > .BI "void CPU_OR_S(size_t " setsize ", cpu_set_t *" destset , > .BI " cpu_set_t *" srcset1 ", cpu_set_t *" srcset2 ); > .BI "void CPU_XOR_S(size_t " setsize ", cpu_set_t *" destset , > .BI " cpu_set_t *" srcset1 ", cpu_set_t *" srcset2 ); > .sp > .BI "int CPU_EQUAL_S(size_t " setsize ", cpu_set_t *" set1 \ > ", cpu_set_t *" set2 ); Even I like to see the equivalent C prototypes, I think this should be noted earlier that these are actually macros. Also, I would like to see a note that the cpu_set_t type is opaque (as from the glibc manual) but there is no official copy operator. The glibc developer suggest using memcpy for this (see the reminder of this thread I posted). And you should not use '=' because of the dynamically allocated ones. Last but not least, because CPU_ALLOC{,_SIZE} rounds the num_cpus argument up (i.e. CPU_ALLOC_SIZE(1) == sizeof(unsigned long)) there are probably more cpus possible in this set than you requested, so these blind bits should be mentioned as undefined. Now to the naming confusion, I think the main problem is CPU_SETSIZE and the setsize arguement to the CPU_*_S macros. The former is in bits the latter in bytes. Either put a note to CPU_SETSIZE that this is in bits and you should not pass this as an setsize argument to any CPU_*_S macro, because of the similar name. Or, rename the setsize argument to something other, and use the setsize name for the CPU_ALLOC{,_SIZE}, too. I think option one should suffice. > .fi > .SH DESCRIPTION > The > .I cpu_set_t > data structure represents a set of CPUs. > CPU sets are used by > .BR sched_setaffinity (2) > and similar interfaces. > > The following macros are provided to operate on the CPU set > .IR set : > .TP 17 > .BR CPU_ZERO () > Clears > .IR set , > so that it contains no CPUs. > .TP > .BR CPU_SET () > Add CPU > .I cpu > to > .IR set . > .TP > .BR CPU_CLR () > Remove CPU > .I cpu > from > .IR set . > .TP > .BR CPU_ISSET () > Test to see if CPU > .I cpu > is a member of > .IR set . > .TP > .BR CPU_COUNT () > Return the number of CPUs in > .IR set . > .PP > Where a > .I cpu > argument is specified, it should not produce side effects, > since the above macros may evaluate the argument more than once. > .PP > The first available CPU on the system corresponds to a > .I cpu > value of 0, the next CPU corresponds to a > .I cpu > value of 1, and so on. > The constant > .B CPU_SETSIZE > (currently 1024) specifies a value one greater than the maximum CPU > number that can be stored in > .IR cpu_set_t . > > The following macros perform logical operations on CPU sets: > .TP 17 > .BR CPU_AND () > Store the logical AND of the sets > .I srcset1 > and > .I srcset2 > in > .I destset > (which may be one of the source sets). > .TP > .BR CPU_OR () > Store the logical OR of the sets > .I srcset1 > and > .I srcset2 > in > .I destset > (which may be one of the source sets). > .TP > .BR CPU_XOR () > Store the logical XOR of the sets > .I srcset1 > and > .I srcset2 > in > .I destset > (which may be one of the source sets). > .TP > .BR CPU_EQUAL () > Test whether two CPU set contain exactly the same CPUs. > .SS Dynamically sized CPU sets > Because some applications may require the ability to dynamically > size CPU sets (e.g., to allocate sets larger than that > defined by the standard > .I cpu_set_t > data type), glibc nowadays provides a set of macros to support this. > > The following macros are used to allocate and deallocate CPU sets: > .TP 17 > .BR CPU_ALLOC () > Allocate a CPU set large enough to hold CPUs > in the range 0 to > .IR num_cpus-1 . > .TP > .BR CPU_ALLOC_SIZE () > Return the size in bytes of the CPU set that would be needed to > hold CPUs in the range 0 to > .IR num_cpus-1 . > .\" FIXME . track this bug > .\" Currently (glibc 2.8), CPU_ALLOC_SIZE() returns double the > .\" value that it should. This also causes CPU_ALLOC() to allocate > .\" twice as much memory as is required. > .\" http://sourceware.org/bugzilla/show_bug.cgi?id=7029 > .\" Eventually, write this up in BUGS. > This macro provides the value that can be used for the > .I setsize argument > in the > .BR CPU_*_S () > macros described below. > .TP > .BR CPU_FREE () > Free a CPU set previously allocated by > .BR CPU_ALLOC (). > .PP > The macros whose names end with "_S" are the analogs of > the similarly named macros without the suffix. > These macros perform the same tasks as their analogs, > but operate on the dynamically allocated CPU set(s) whose size is > .I setsize > bytes. > .SH "RETURN VALUE" > .BR CPU_ISSET () > and > .BR CPU_ISSET_S () > return non-zero if > .I cpu > is in > .IR set ; > otherwise, it returns 0. > > .BR CPU_COUNT () > and > .BR CPU_COUNT_S () > return the number of CPUs in > .IR set . > > .BR CPU_EQUAL () > and > .BR CPU_EQUAL_S () > return non-zero if the two CPU sets are equal; otherwise it returns 0. > > .BR CPU_ALLOC () > returns a pointer on success, or NULL on failure. > (Errors are as for > .BR malloc (3).) > > .BR CPU_ALLOC_SIZE () > returns the number of bytes required to store a > CPU set of the specified cardinality. > > The other functions do not return a value. > .SH VERSIONS > The > .BR CPU_ZERO (), > .BR CPU_SET (), > .BR CPU_CLR (), > and > .BR CPU_ISSET () > macros were added in glibc 2.3.3. > > .BR CPU_COUNT () > first appeared in glibc 2.6. > > .BR CPU_AND (), > .BR CPU_OR (), > .BR CPU_XOR (), > .BR CPU_EQUAL (), > .BR CPU_ALLOC (), > .BR CPU_ALLOC_SIZE (), > .BR CPU_FREE (), > .BR CPU_ZERO_S (), > .BR CPU_SET_S (), > .BR CPU_CLR_S (), > .BR CPU_ISSET_S (), > .BR CPU_AND_S (), > .BR CPU_OR_S (), > .BR CPU_XOR_S (), > and > .BR CPU_EQUAL_S () > first appeared in glibc 2.7. > .SH "CONFORMING TO" > These interfaces are Linux-specific. > .SH EXAMPLE > The following program demonstrates the use of some of the macros > used for dynamically allocated CPU sets. > > .nf > #define _GNU_SOURCE > #include <sched.h> > #include <stdlib.h> > #include <unistd.h> > #include <stdio.h> > #include <assert.h> > > int > main(int argc, char *argv[]) > { > cpu_set_t *cpusetp; > size_t size; > int num_cpus, cpu; > > if (argc < 2) { > fprintf(stderr, "Usage: %s <num\-cpus>\\n", argv[0]); > exit(EXIT_FAILURE); > } > > num_cpus = atoi(argv[1]); > > cpusetp = CPU_ALLOC(num_cpus); > if (cpusetp == NULL) { > perror("CPU_ALLOC"); > exit(EXIT_FAILURE); > } > > size = CPU_ALLOC_SIZE(num_cpus); > > CPU_ZERO_S(size, cpusetp); > for (cpu = 0; cpu < num_cpus; cpu += 2) > CPU_SET_S(cpu, size, cpusetp); > > printf("CPU_COUNT() of set: %d\\n", CPU_COUNT_S(size, cpusetp)); > > CPU_FREE(cpusetp); > exit(EXIT_SUCCESS); > } > .fi > .SH "SEE ALSO" > .BR sched_setaffinity (2), > .BR pthread_attr_setaffinity_np (3), > .BR pthread_setaffinity_np (3), > .BR cpuset (7) > -- To unsubscribe from this list: send the line "unsubscribe linux-man" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html