1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/systm.h> 30 #include <sys/errno.h> 31 #include <sys/proc.h> 32 #include <sys/cpu.h> 33 #include <sys/rtpriocntl.h> 34 #include <sys/tspriocntl.h> 35 #include <sys/processor.h> 36 #include <sys/brand.h> 37 #include <sys/lx_pid.h> 38 #include <sys/lx_sched.h> 39 #include <sys/lx_brand.h> 40 41 extern long priocntl_common(int, procset_t *, int, caddr_t, caddr_t, uio_seg_t); 42 43 int 44 lx_sched_affinity(int cmd, uintptr_t pid, int len, uintptr_t maskp, 45 int64_t *rval) 46 { 47 pid_t s_pid; 48 id_t s_tid; 49 kthread_t *t = curthread; 50 lx_lwp_data_t *lx_lwp; 51 52 if (cmd != B_GET_AFFINITY_MASK && cmd != B_SET_AFFINITY_MASK) 53 return (set_errno(EINVAL)); 54 55 /* 56 * The caller wants to know how large the mask should be. 57 */ 58 if (cmd == B_GET_AFFINITY_MASK && len == 0) { 59 *rval = sizeof (lx_affmask_t); 60 return (0); 61 } 62 63 /* 64 * Otherwise, ensure they have a large enough mask. 65 */ 66 if (cmd == B_GET_AFFINITY_MASK && len < sizeof (lx_affmask_t)) { 67 *rval = -1; 68 return (set_errno(EINVAL)); 69 } 70 71 if (pid == 0) { 72 s_pid = curproc->p_pid; 73 s_tid = curthread->t_tid; 74 } else if (lx_lpid_to_spair((pid_t)pid, &s_pid, &s_tid) == -1) { 75 return (set_errno(ESRCH)); 76 } 77 78 /* 79 * For now, we only support manipulating threads in the 80 * same process. 81 */ 82 if (curproc->p_pid != s_pid) 83 return (set_errno(EPERM)); 84 85 /* 86 * We must hold the process lock so that the thread list 87 * doesn't change while we're looking at it. We'll hold 88 * the lock until we no longer reference the 89 * corresponding lwp. 90 */ 91 92 mutex_enter(&curproc->p_lock); 93 94 do { 95 if (t->t_tid == s_tid) 96 break; 97 t = t->t_forw; 98 } while (t != curthread); 99 100 /* 101 * If the given PID is in the current thread's process, 102 * then we _must_ find it in the process's thread list. 103 */ 104 ASSERT(t->t_tid == s_tid); 105 106 lx_lwp = t->t_lwp->lwp_brand; 107 108 if (cmd == B_SET_AFFINITY_MASK) { 109 if (copyin_nowatch((void *)maskp, &lx_lwp->br_affinitymask, 110 sizeof (lx_affmask_t)) != 0) { 111 mutex_exit(&curproc->p_lock); 112 return (set_errno(EFAULT)); 113 } 114 115 *rval = 0; 116 } else { 117 if (copyout_nowatch(&lx_lwp->br_affinitymask, (void *)maskp, 118 sizeof (lx_affmask_t)) != 0) { 119 mutex_exit(&curproc->p_lock); 120 return (set_errno(EFAULT)); 121 } 122 123 *rval = sizeof (lx_affmask_t); 124 } 125 126 mutex_exit(&curproc->p_lock); 127 return (0); 128 } 129 130 long 131 lx_sched_setscheduler(l_pid_t pid, int policy, struct lx_sched_param *param) 132 { 133 klwp_t *lwp = ttolwp(curthread); 134 procset_t procset; 135 procset_t procset_cid; 136 pcparms_t pcparm; 137 pcinfo_t pcinfo; 138 struct lx_sched_param sched_param; 139 tsparms_t *tsp; 140 int prio, maxupri; 141 int rv; 142 143 if (pid < 0) 144 return (set_errno(ESRCH)); 145 146 if ((rv = sched_setprocset(&procset, pid))) 147 return (rv); 148 149 if (copyin(param, &sched_param, sizeof (sched_param))) 150 return (set_errno(EFAULT)); 151 152 prio = sched_param.lx_sched_prio; 153 154 if (policy < 0) { 155 /* 156 * get the class id 157 */ 158 pcparm.pc_cid = PC_CLNULL; 159 (void) do_priocntlsys(PC_GETPARMS, &procset, &pcparm); 160 if (lwp->lwp_errno) 161 return (lwp->lwp_errno); 162 163 /* 164 * get the current policy 165 */ 166 bzero(&pcinfo, sizeof (pcinfo)); 167 pcinfo.pc_cid = pcparm.pc_cid; 168 (void) do_priocntlsys(PC_GETCLINFO, &procset, &pcinfo); 169 if (lwp->lwp_errno) 170 return (lwp->lwp_errno); 171 172 if (strcmp(pcinfo.pc_clname, "TS") == 0) 173 policy = LX_SCHED_OTHER; 174 else if (strcmp(pcinfo.pc_clname, "RT") == 0) 175 policy = ((rtparms_t *)pcparm.pc_clparms)->rt_tqnsecs == 176 RT_TQINF ? LX_SCHED_FIFO : LX_SCHED_RR; 177 else 178 return (set_errno(EINVAL)); 179 } 180 181 bzero(&pcinfo, sizeof (pcinfo)); 182 bzero(&pcparm, sizeof (pcparm)); 183 setprocset(&procset_cid, POP_AND, P_PID, 0, P_ALL, 0); 184 switch (policy) { 185 case LX_SCHED_FIFO: 186 case LX_SCHED_RR: 187 (void) strcpy(pcinfo.pc_clname, "RT"); 188 (void) do_priocntlsys(PC_GETCID, &procset_cid, &pcinfo); 189 if (lwp->lwp_errno) 190 return (lwp->lwp_errno); 191 192 if (prio < 0 || 193 prio > ((rtinfo_t *)pcinfo.pc_clinfo)->rt_maxpri) 194 return (set_errno(EINVAL)); 195 pcparm.pc_cid = pcinfo.pc_cid; 196 ((rtparms_t *)pcparm.pc_clparms)->rt_pri = prio; 197 ((rtparms_t *)pcparm.pc_clparms)->rt_tqnsecs = 198 policy == LX_SCHED_RR ? RT_TQDEF : RT_TQINF; 199 break; 200 201 case LX_SCHED_OTHER: 202 (void) strcpy(pcinfo.pc_clname, "TS"); 203 (void) do_priocntlsys(PC_GETCID, &procset_cid, &pcinfo); 204 if (lwp->lwp_errno) 205 return (lwp->lwp_errno); 206 207 maxupri = ((tsinfo_t *)pcinfo.pc_clinfo)->ts_maxupri; 208 if (prio > maxupri || prio < -maxupri) 209 return (set_errno(EINVAL)); 210 211 pcparm.pc_cid = pcinfo.pc_cid; 212 tsp = (tsparms_t *)pcparm.pc_clparms; 213 tsp->ts_upri = prio; 214 tsp->ts_uprilim = TS_NOCHANGE; 215 break; 216 217 default: 218 return (set_errno(EINVAL)); 219 } 220 221 /* 222 * finally set scheduling policy and parameters 223 */ 224 (void) do_priocntlsys(PC_SETPARMS, &procset, &pcparm); 225 226 return (0); 227 } 228 229 long 230 lx_sched_getscheduler(l_pid_t pid) 231 { 232 klwp_t *lwp = ttolwp(curthread); 233 procset_t procset; 234 pcparms_t pcparm; 235 pcinfo_t pcinfo; 236 int policy; 237 int rv; 238 239 if (pid < 0) 240 return (set_errno(ESRCH)); 241 242 if ((rv = sched_setprocset(&procset, pid))) 243 return (rv); 244 245 /* 246 * get the class id 247 */ 248 pcparm.pc_cid = PC_CLNULL; 249 (void) do_priocntlsys(PC_GETPARMS, &procset, &pcparm); 250 if (lwp->lwp_errno) 251 return (lwp->lwp_errno); 252 253 /* 254 * get the class info and identify the equivalent linux policy 255 */ 256 bzero(&pcinfo, sizeof (pcinfo)); 257 pcinfo.pc_cid = pcparm.pc_cid; 258 (void) do_priocntlsys(PC_GETCLINFO, &procset, &pcinfo); 259 if (lwp->lwp_errno) 260 return (lwp->lwp_errno); 261 262 if (strcmp(pcinfo.pc_clname, "TS") == 0) 263 policy = LX_SCHED_OTHER; 264 else if (strcmp(pcinfo.pc_clname, "RT") == 0) 265 policy = ((rtparms_t *)pcparm.pc_clparms)->rt_tqnsecs == 266 RT_TQINF ? LX_SCHED_FIFO : LX_SCHED_RR; 267 else 268 policy = set_errno(EINVAL); 269 270 return (policy); 271 } 272 273 long 274 lx_sched_setparam(l_pid_t pid, struct lx_sched_param *param) 275 { 276 klwp_t *lwp = ttolwp(curthread); 277 procset_t procset; 278 procset_t procset_cid; 279 pcparms_t pcparm; 280 pcinfo_t pcinfo; 281 struct lx_sched_param sched_param; 282 tsparms_t *tsp; 283 int policy; 284 int prio, maxupri; 285 int rv; 286 287 if (pid < 0) 288 return (set_errno(ESRCH)); 289 290 if ((rv = sched_setprocset(&procset, pid))) 291 return (rv); 292 293 if (copyin(param, &sched_param, sizeof (sched_param))) 294 return (set_errno(EFAULT)); 295 296 prio = sched_param.lx_sched_prio; 297 298 /* 299 * get the class id 300 */ 301 pcparm.pc_cid = PC_CLNULL; 302 (void) do_priocntlsys(PC_GETPARMS, &procset, &pcparm); 303 if (lwp->lwp_errno) 304 return (lwp->lwp_errno); 305 306 /* 307 * get the current policy 308 */ 309 bzero(&pcinfo, sizeof (pcinfo)); 310 pcinfo.pc_cid = pcparm.pc_cid; 311 (void) do_priocntlsys(PC_GETCLINFO, &procset, &pcinfo); 312 if (lwp->lwp_errno) 313 return (lwp->lwp_errno); 314 315 if (strcmp(pcinfo.pc_clname, "TS") == 0) 316 policy = LX_SCHED_OTHER; 317 else if (strcmp(pcinfo.pc_clname, "RT") == 0) 318 policy = ((rtparms_t *)pcparm.pc_clparms)->rt_tqnsecs == 319 RT_TQINF ? LX_SCHED_FIFO : LX_SCHED_RR; 320 else 321 return (set_errno(EINVAL)); 322 323 bzero(&pcinfo, sizeof (pcinfo)); 324 bzero(&pcparm, sizeof (pcparm)); 325 setprocset(&procset_cid, POP_AND, P_PID, 0, P_ALL, 0); 326 switch (policy) { 327 case LX_SCHED_FIFO: 328 case LX_SCHED_RR: 329 (void) strcpy(pcinfo.pc_clname, "RT"); 330 (void) do_priocntlsys(PC_GETCID, &procset_cid, &pcinfo); 331 if (lwp->lwp_errno) 332 return (lwp->lwp_errno); 333 334 if (prio < 0 || 335 prio > ((rtinfo_t *)pcinfo.pc_clinfo)->rt_maxpri) 336 return (set_errno(EINVAL)); 337 pcparm.pc_cid = pcinfo.pc_cid; 338 ((rtparms_t *)pcparm.pc_clparms)->rt_pri = prio; 339 ((rtparms_t *)pcparm.pc_clparms)->rt_tqnsecs = 340 policy == LX_SCHED_RR ? RT_TQDEF : RT_TQINF; 341 break; 342 343 case LX_SCHED_OTHER: 344 (void) strcpy(pcinfo.pc_clname, "TS"); 345 (void) do_priocntlsys(PC_GETCID, &procset_cid, &pcinfo); 346 if (lwp->lwp_errno) 347 return (lwp->lwp_errno); 348 349 maxupri = ((tsinfo_t *)pcinfo.pc_clinfo)->ts_maxupri; 350 if (prio > maxupri || prio < -maxupri) 351 return (set_errno(EINVAL)); 352 353 pcparm.pc_cid = pcinfo.pc_cid; 354 tsp = (tsparms_t *)pcparm.pc_clparms; 355 tsp->ts_upri = prio; 356 tsp->ts_uprilim = TS_NOCHANGE; 357 break; 358 359 default: 360 return (set_errno(EINVAL)); 361 } 362 363 /* 364 * finally set scheduling policy and parameters 365 */ 366 (void) do_priocntlsys(PC_SETPARMS, &procset, &pcparm); 367 368 return (0); 369 } 370 371 long 372 lx_sched_getparam(l_pid_t pid, struct lx_sched_param *param) 373 { 374 klwp_t *lwp = ttolwp(curthread); 375 struct lx_sched_param local_param; 376 procset_t procset; 377 pcparms_t pcparm; 378 pcinfo_t pcinfo; 379 tsinfo_t *tsi; 380 int prio, scale; 381 int rv; 382 383 if (pid < 0) 384 return (set_errno(ESRCH)); 385 386 if ((rv = sched_setprocset(&procset, pid))) 387 return (rv); 388 389 /* 390 * get the class id 391 */ 392 pcparm.pc_cid = PC_CLNULL; 393 (void) do_priocntlsys(PC_GETPARMS, &procset, &pcparm); 394 if (lwp->lwp_errno) 395 return (lwp->lwp_errno); 396 397 /* 398 * get the class info and identify the equivalent linux policy 399 */ 400 bzero(&pcinfo, sizeof (pcinfo)); 401 pcinfo.pc_cid = pcparm.pc_cid; 402 (void) do_priocntlsys(PC_GETCLINFO, &procset, &pcinfo); 403 if (lwp->lwp_errno) 404 return (lwp->lwp_errno); 405 406 bzero(&local_param, sizeof (local_param)); 407 if (strcmp(pcinfo.pc_clname, "TS") == 0) { 408 /* 409 * I don't know if we need to do this, coz it can't be 410 * changed from zero anyway..... 411 */ 412 tsi = (tsinfo_t *)pcinfo.pc_clinfo; 413 prio = ((tsparms_t *)pcparm.pc_clparms)->ts_upri; 414 scale = tsi->ts_maxupri; 415 if (scale == 0) 416 local_param.lx_sched_prio = 0; 417 else 418 local_param.lx_sched_prio = -(prio * 20) / scale; 419 } else if (strcmp(pcinfo.pc_clname, "RT") == 0) 420 local_param.lx_sched_prio = 421 ((rtparms_t *)pcparm.pc_clparms)->rt_pri; 422 else 423 rv = set_errno(EINVAL); 424 425 if (rv == 0) 426 if (copyout(&local_param, param, sizeof (local_param))) 427 return (set_errno(EFAULT)); 428 429 return (rv); 430 } 431 432 long 433 lx_sched_rr_get_interval(l_pid_t pid, struct timespec *ival) 434 { 435 klwp_t *lwp = ttolwp(curthread); 436 struct timespec interval; 437 procset_t procset; 438 pcparms_t pcparm; 439 pcinfo_t pcinfo; 440 int rv; 441 442 if (pid < 0) 443 return (set_errno(ESRCH)); 444 445 if ((rv = sched_setprocset(&procset, pid))) 446 return (rv); 447 448 /* 449 * get the class id 450 */ 451 pcparm.pc_cid = PC_CLNULL; 452 (void) do_priocntlsys(PC_GETPARMS, &procset, &pcparm); 453 if (lwp->lwp_errno) 454 return (lwp->lwp_errno); 455 456 /* 457 * get the class info and identify the equivalent linux policy 458 */ 459 setprocset(&procset, POP_AND, P_PID, 0, P_ALL, 0); 460 bzero(&pcinfo, sizeof (pcinfo)); 461 (void) strcpy(pcinfo.pc_clname, "RT"); 462 (void) do_priocntlsys(PC_GETCID, &procset, &pcinfo); 463 if (lwp->lwp_errno) 464 return (lwp->lwp_errno); 465 466 if (pcparm.pc_cid == pcinfo.pc_cid && 467 ((rtparms_t *)pcparm.pc_clparms)->rt_tqnsecs != RT_TQINF) { 468 interval.tv_sec = ((rtparms_t *)pcparm.pc_clparms)->rt_tqsecs; 469 interval.tv_nsec = ((rtparms_t *)pcparm.pc_clparms)->rt_tqnsecs; 470 471 if (copyout(&interval, ival, sizeof (interval))) 472 return (set_errno(EFAULT)); 473 474 return (0); 475 } 476 477 return (set_errno(EINVAL)); 478 } 479 480 int 481 sched_setprocset(procset_t *procset, l_pid_t pid) 482 { 483 id_t lid, rid; 484 idtype_t lidtype, ridtype; 485 486 /* 487 * define the target lwp 488 */ 489 if (pid == 0) { 490 ridtype = P_ALL; 491 lidtype = P_PID; 492 rid = 0; 493 lid = P_MYID; 494 } else { 495 if (lx_lpid_to_spair(pid, &pid, &lid) < 0) 496 return (set_errno(ESRCH)); 497 if (pid != curproc->p_pid) 498 return (set_errno(ESRCH)); 499 rid = 0; 500 ridtype = P_ALL; 501 lidtype = P_LWPID; 502 } 503 setprocset(procset, POP_AND, lidtype, lid, ridtype, rid); 504 505 return (0); 506 } 507 508 long 509 do_priocntlsys(int cmd, procset_t *procset, void *arg) 510 { 511 return (priocntl_common(PC_VERSION, procset, cmd, (caddr_t)arg, 0, 512 UIO_SYSSPACE)); 513 }