Here 'unsigned long' is just a convenient stand-in for "generic register-sized argument".
A "void * pointing to struct" requires a copy from user space. If a particular prctl() does need a struct, it can certainly stuff a pointer into one of those 'unsigned long' parameters (in the kernel environment, a pointer can be converted to and from an unsigned long without concern).