long lx_sched_setparam(uintptr_t pid, uintptr_t param) { int err, policy; pid_t s_pid; lwpid_t s_tid; struct lx_sched_param lp; struct sched_param sp; if (((pid_t)pid < 0) || (param == NULL)) return (-EINVAL); if (lx_lpid_to_spair((pid_t)pid, &s_pid, &s_tid) < 0) return (-ESRCH); if (s_pid == getpid()) { struct sched_param dummy; if ((err = pthread_getschedparam(s_tid, &policy, &dummy)) != 0) return (-err); } else if ((policy = sched_getscheduler(s_pid)) < 0) return (-errno); lx_debug("sched_setparam(): current policy %d", policy); if (uucopy((void *)param, &lp, sizeof (lp)) != 0) return (-errno); /* * In Linux, the only valid SCHED_OTHER scheduler priority is 0 */ if ((policy == SCHED_OTHER) && (lp.lx_sched_prio != 0)) return (-EINVAL); if ((err = ltos_sparam(policy, (struct lx_sched_param *)&lp, &sp)) != 0) return (err); /* * Check if we're allowed to change the scheduler for the process. * * If we're operating on a thread, we can't just call * pthread_setschedparam() because as all threads reside within a * single Solaris process, Solaris will allow the modification * * If we're operating on a process, we can't just call sched_setparam() * because Solaris will allow the call to succeed if the scheduler * parameters do not differ from those being installed, but Linux wants * the call to fail. */ if ((err = check_schedperms(s_pid)) != 0) return (err); if (s_pid == getpid()) return (((err = pthread_setschedparam(s_tid, policy, &sp)) != 0) ? -err : 0); return ((sched_setparam(s_pid, &sp) == -1) ? -errno : 0); }
int lx_sched_getparam(uintptr_t pid, uintptr_t param) { int policy, ret; pid_t s_pid; lwpid_t s_tid; struct sched_param sp; if (((pid_t)pid < 0) || (param == NULL)) return (-EINVAL); if (lx_lpid_to_spair((pid_t)pid, &s_pid, &s_tid) < 0) return (-ESRCH); /* * If we're attempting to get information on our own process, we can * get data on a per-thread basis; if not, punt and use the specified * pid. */ if (s_pid == getpid()) { if ((ret = pthread_getschedparam(s_tid, &policy, &sp)) != 0) return (-ret); } else { if (sched_getparam(s_pid, &sp) == -1) return (-errno); if ((policy = sched_getscheduler(s_pid)) < 0) return (-errno); } return (stol_sparam(policy, &sp, (struct lx_sched_param *)param)); }
long lx_sched_getscheduler(uintptr_t pid) { int policy, rv; pid_t s_pid; lwpid_t s_tid; if ((pid_t)pid < 0) return (-EINVAL); if (lx_lpid_to_spair((pid_t)pid, &s_pid, &s_tid) < 0) return (-ESRCH); if (s_pid == getpid()) { struct sched_param dummy; if ((rv = pthread_getschedparam(s_tid, &policy, &dummy)) != 0) return (-rv); } else if ((policy = sched_getscheduler(s_pid)) < 0) return (-errno); /* * Linux only supports certain policies; avoid confusing apps with * alien policies. */ switch (policy) { case SCHED_FIFO: return (LX_SCHED_FIFO); case SCHED_OTHER: return (LX_SCHED_OTHER); case SCHED_RR: return (LX_SCHED_RR); default: break; } return (LX_SCHED_OTHER); }
long lx_sched_setscheduler(uintptr_t pid, uintptr_t policy, uintptr_t param) { int rt_pol; int rv; pid_t s_pid; lwpid_t s_tid; struct lx_sched_param lp; struct sched_param sp; if (((pid_t)pid < 0) || (param == NULL)) return (-EINVAL); if ((rt_pol = validate_policy((int)policy)) < 0) return (rt_pol); if ((rv = ltos_sparam(policy, (struct lx_sched_param *)param, &sp)) != 0) return (rv); if (uucopy((void *)param, &lp, sizeof (lp)) != 0) return (-errno); if (rt_pol == LX_SCHED_OTHER) { /* * In Linux, the only valid SCHED_OTHER scheduler priority is 0 */ if (lp.lx_sched_prio != 0) return (-EINVAL); /* * If we're already SCHED_OTHER, there's nothing else to do. */ if (lx_sched_getscheduler(pid) == LX_SCHED_OTHER) return (0); } if (lx_lpid_to_spair((pid_t)pid, &s_pid, &s_tid) < 0) return (-ESRCH); /* * Check if we're allowed to change the scheduler for the process. * * If we're operating on a thread, we can't just call * pthread_setschedparam() because as all threads reside within a * single Solaris process, Solaris will allow the modification. * * If we're operating on a process, we can't just call * sched_setscheduler() because Solaris will allow the call to succeed * if the scheduler and scheduler parameters do not differ from those * being installed, but Linux wants the call to fail. */ if ((rv = check_schedperms(s_pid)) != 0) return (rv); if (s_pid == getpid()) { struct sched_param param; int pol; if ((pol = sched_getscheduler(s_pid)) == -1) return (-errno); /* * sched_setscheduler() returns the previous scheduling policy * on success, so call pthread_getschedparam() to get the * current thread's scheduling policy and return that if the * call to pthread_setschedparam() succeeds. */ if ((rv = pthread_getschedparam(s_tid, &pol, ¶m)) != 0) return (-rv); return (((rv = pthread_setschedparam(s_tid, rt_pol, &sp)) != 0) ? -rv : pol); } return (((rv = sched_setscheduler(s_pid, rt_pol, &sp)) == -1) ? -errno : rv); }
/* ARGSUSED */ long lx_sched_setaffinity(uintptr_t pid, uintptr_t len, uintptr_t maskp) { int ret; int sz; int i; int found; ulong_t *lmask; pid_t s_pid; lwpid_t s_tid; processorid_t cpuid = NULL; if ((pid_t)pid < 0) return (-EINVAL); if (lx_lpid_to_spair(pid, &s_pid, &s_tid) < 0) return (-ESRCH); /* * We only support setting affinity masks for threads in * the calling process. */ if (s_pid != getpid()) return (-EPERM); /* * First, get the minimum bitmask size from the kernel. */ sz = syscall(SYS_brand, B_GET_AFFINITY_MASK, 0, 0, 0); if (sz == -1) return (-errno); lmask = SAFE_ALLOCA(sz); if (lmask == NULL) return (-ENOMEM); if (uucopy((void *)maskp, lmask, sz) != 0) return (-EFAULT); /* * Make sure the mask contains at least one processor that is * physically on the system. Reduce the user's mask to the set of * physically present CPUs. Keep track of how many valid * bits are set in the user's mask. */ for (found = 0, i = 0; i < sz * 8; i++) { if (p_online(i, P_STATUS) == -1) { /* * This CPU doesn't exist, so clear this bit from * the user's mask. */ lmask[BITINDEX(i)] &= ~BITSHIFT(i); continue; } if ((lmask[BITINDEX(i)] & BITSHIFT(i)) == BITSHIFT(i)) { found++; cpuid = i; } } if (found == 0) { lx_debug("\tlx_sched_setaffinity: mask has no present CPUs\n"); return (-EINVAL); } /* * If only one bit is set, bind the thread to that procesor; * otherwise, clear the binding. */ if (found == 1) { lx_debug("\tlx_sched_setaffinity: binding thread %d to cpu%d\n", s_tid, cpuid); if (processor_bind(P_LWPID, s_tid, cpuid, NULL) != 0) /* * It could be that the requested processor is offline, * so we'll just abandon our good-natured attempt to * bind to it. */ lx_debug("couldn't bind LWP %d to cpu %d: %s\n", s_tid, cpuid, strerror(errno)); } else { lx_debug("\tlx_sched_setaffinity: clearing thr %d binding\n", s_tid); if (processor_bind(P_LWPID, s_tid, PBIND_NONE, NULL) != 0) { lx_debug("couldn't clear CPU binding for LWP %d: %s\n", s_tid, strerror(errno)); } } /* * Finally, ask the kernel to make a note of our current (though fairly * meaningless) affinity mask. */ ret = syscall(SYS_brand, B_SET_AFFINITY_MASK, pid, sz, lmask); return ((ret == 0) ? 0 : -errno); }