7127 remove -Wno-missing-braces from Makefile.uts
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 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 30 /* 31 * Inter-Process Communication Message Facility. 32 * 33 * See os/ipc.c for a description of common IPC functionality. 34 * 35 * Resource controls 36 * ----------------- 37 * 38 * Control: zone.max-msg-ids (rc_zone_msgmni) 39 * Description: Maximum number of message queue ids allowed a zone. 40 * 41 * When msgget() is used to allocate a message queue, one id is 42 * allocated. If the id allocation doesn't succeed, msgget() fails 43 * and errno is set to ENOSPC. Upon successful msgctl(, IPC_RMID) 44 * the id is deallocated. 45 * 46 * Control: project.max-msg-ids (rc_project_msgmni) 47 * Description: Maximum number of message queue ids allowed a project. 48 * 49 * When msgget() is used to allocate a message queue, one id is 50 * allocated. If the id allocation doesn't succeed, msgget() fails 51 * and errno is set to ENOSPC. Upon successful msgctl(, IPC_RMID) 52 * the id is deallocated. 53 * 54 * Control: process.max-msg-qbytes (rc_process_msgmnb) 55 * Description: Maximum number of bytes of messages on a message queue. 56 * 57 * When msgget() successfully allocates a message queue, the minimum 58 * enforced value of this limit is used to initialize msg_qbytes. 59 * 60 * Control: process.max-msg-messages (rc_process_msgtql) 61 * Description: Maximum number of messages on a message queue. 62 * 63 * When msgget() successfully allocates a message queue, the minimum 64 * enforced value of this limit is used to initialize a per-queue 65 * limit on the number of messages. 66 */ 67 68 #include <sys/types.h> 69 #include <sys/t_lock.h> 70 #include <sys/param.h> 71 #include <sys/cred.h> 72 #include <sys/user.h> 73 #include <sys/proc.h> 74 #include <sys/time.h> 75 #include <sys/ipc.h> 76 #include <sys/ipc_impl.h> 77 #include <sys/msg.h> 78 #include <sys/msg_impl.h> 79 #include <sys/list.h> 80 #include <sys/systm.h> 81 #include <sys/sysmacros.h> 82 #include <sys/cpuvar.h> 83 #include <sys/kmem.h> 84 #include <sys/ddi.h> 85 #include <sys/errno.h> 86 #include <sys/cmn_err.h> 87 #include <sys/debug.h> 88 #include <sys/project.h> 89 #include <sys/modctl.h> 90 #include <sys/syscall.h> 91 #include <sys/policy.h> 92 #include <sys/zone.h> 93 94 #include <c2/audit.h> 95 96 /* 97 * The following tunables are obsolete. Though for compatibility we 98 * still read and interpret msginfo_msgmnb, msginfo_msgmni, and 99 * msginfo_msgtql (see os/project.c and os/rctl_proc.c), the preferred 100 * mechanism for administrating the IPC Message facility is through the 101 * resource controls described at the top of this file. 102 */ 103 size_t msginfo_msgmax = 2048; /* (obsolete) */ 104 size_t msginfo_msgmnb = 4096; /* (obsolete) */ 105 int msginfo_msgmni = 50; /* (obsolete) */ 106 int msginfo_msgtql = 40; /* (obsolete) */ 107 int msginfo_msgssz = 8; /* (obsolete) */ 108 int msginfo_msgmap = 0; /* (obsolete) */ 109 ushort_t msginfo_msgseg = 1024; /* (obsolete) */ 110 111 extern rctl_hndl_t rc_zone_msgmni; 112 extern rctl_hndl_t rc_project_msgmni; 113 extern rctl_hndl_t rc_process_msgmnb; 114 extern rctl_hndl_t rc_process_msgtql; 115 static ipc_service_t *msq_svc; 116 static zone_key_t msg_zone_key; 117 118 static void msg_dtor(kipc_perm_t *); 119 static void msg_rmid(kipc_perm_t *); 120 static void msg_remove_zone(zoneid_t, void *); 121 122 /* 123 * Module linkage information for the kernel. 124 */ 125 static ssize_t msgsys(int opcode, uintptr_t a0, uintptr_t a1, uintptr_t a2, 126 uintptr_t a4, uintptr_t a5); 127 128 static struct sysent ipcmsg_sysent = { 129 6, 130 #ifdef _LP64 131 SE_ARGC | SE_NOUNLOAD | SE_64RVAL, 132 #else 133 SE_ARGC | SE_NOUNLOAD | SE_32RVAL1, 134 #endif 135 (int (*)())msgsys 136 }; 137 138 #ifdef _SYSCALL32_IMPL 139 static ssize32_t msgsys32(int opcode, uint32_t a0, uint32_t a1, uint32_t a2, 140 uint32_t a4, uint32_t a5); 141 142 static struct sysent ipcmsg_sysent32 = { 143 6, 144 SE_ARGC | SE_NOUNLOAD | SE_32RVAL1, 145 (int (*)())msgsys32 146 }; 147 #endif /* _SYSCALL32_IMPL */ 148 149 static struct modlsys modlsys = { 150 &mod_syscallops, "System V message facility", &ipcmsg_sysent 151 }; 152 153 #ifdef _SYSCALL32_IMPL 154 static struct modlsys modlsys32 = { 155 &mod_syscallops32, "32-bit System V message facility", &ipcmsg_sysent32 156 }; 157 #endif 158 159 /* 160 * Big Theory statement for message queue correctness 161 * 162 * The msgrcv and msgsnd functions no longer uses cv_broadcast to wake up 163 * receivers who are waiting for an event. Using the cv_broadcast method 164 * resulted in negative scaling when the number of waiting receivers are large 165 * (the thundering herd problem). Instead, the receivers waiting to receive a 166 * message are now linked in a queue-like fashion and awaken one at a time in 167 * a controlled manner. 168 * 169 * Receivers can block on two different classes of waiting list: 170 * 1) "sendwait" list, which is the more complex list of the two. The 171 * receiver will be awakened by a sender posting a new message. There 172 * are two types of "sendwait" list used: 173 * a) msg_wait_snd: handles all receivers who are looking for 174 * a message type >= 0, but was unable to locate a match. 175 * 176 * slot 0: reserved for receivers that have designated they 177 * will take any message type. 178 * rest: consist of receivers requesting a specific type 179 * but the type was not present. The entries are 180 * hashed into a bucket in an attempt to keep 181 * any list search relatively short. 182 * b) msg_wait_snd_ngt: handles all receivers that have designated 183 * a negative message type. Unlike msg_wait_snd, the hash bucket 184 * serves a range of negative message types (-1 to -5, -6 to -10 185 * and so forth), where the last bucket is reserved for all the 186 * negative message types that hash outside of MSG_MAX_QNUM - 1. 187 * This is done this way to simplify the operation of locating a 188 * negative message type. 189 * 190 * 2) "copyout" list, where the receiver is awakened by another 191 * receiver after a message is copied out. This is a linked list 192 * of waiters that are awakened one at a time. Although the solution is 193 * not optimal, the complexity that would be added in for waking 194 * up the right entry far exceeds any potential pay back (too many 195 * correctness and corner case issues). 196 * 197 * The lists are doubly linked. In the case of the "sendwait" 198 * list, this allows the thread to remove itself from the list without having 199 * to traverse the list. In the case of the "copyout" list it simply allows 200 * us to use common functions with the "sendwait" list. 201 * 202 * To make sure receivers are not hung out to dry, we must guarantee: 203 * 1. If any queued message matches any receiver, then at least one 204 * matching receiver must be processing the request. 205 * 2. Blocking on the copyout queue is only temporary while messages 206 * are being copied out. The process is guaranted to wakeup 207 * when it gets to front of the queue (copyout is a FIFO). 208 * 209 * Rules for blocking and waking up: 210 * 1. A receiver entering msgrcv must examine all messages for a match 211 * before blocking on a sendwait queue. 212 * 2. If the receiver blocks because the message it chose is already 213 * being copied out, then when it wakes up needs to start start 214 * checking the messages from the beginning. 215 * 3) When ever a process returns from msgrcv for any reason, if it 216 * had attempted to copy a message or blocked waiting for a copy 217 * to complete it needs to wakeup the next receiver blocked on 218 * a copy out. 219 * 4) When a message is sent, the sender selects a process waiting 220 * for that type of message. This selection process rotates between 221 * receivers types of 0, negative and positive to prevent starvation of 222 * any one particular receiver type. 223 * 5) The following are the scenarios for processes that are awakened 224 * by a msgsnd: 225 * a) The process finds the message and is able to copy 226 * it out. Once complete, the process returns. 227 * b) The message that was sent that triggered the wakeup is no 228 * longer available (another process found the message first). 229 * We issue a wakeup on copy queue and then go back to 230 * sleep waiting for another matching message to be sent. 231 * c) The message that was supposed to be processed was 232 * already serviced by another process. However a different 233 * message is present which we can service. The message 234 * is copied and the process returns. 235 * d) The message is found, but some sort of error occurs that 236 * prevents the message from being copied. The receiver 237 * wakes up the next sender that can service this message 238 * type and returns an error to the caller. 239 * e) The message is found, but it is marked as being copied 240 * out. The receiver then goes to sleep on the copyout 241 * queue where it will be awakened again sometime in the future. 242 * 243 * 244 * 6) Whenever a message is found that matches the message type designated, 245 * but is being copied out we have to block on the copyout queue. 246 * After process copying finishes the copy out, it must wakeup (either 247 * directly or indirectly) all receivers who blocked on its copyout, 248 * so they are guaranteed a chance to examine the remaining messages. 249 * This is implemented via a chain of wakeups: Y wakes X, who wakes Z, 250 * and so on. The chain cannot be broken. This leads to the following 251 * cases: 252 * a) A receiver is finished copying the message (or encountered) 253 * an error), the first entry on the copyout queue is woken 254 * up. 255 * b) When the receiver is woken up, it attempts to locate 256 * a message type match. 257 * c) If a message type is found and 258 * -- MSG_RCVCOPY flag is not set, the message is 259 * marked for copying out. Regardless of the copyout 260 * success the next entry on the copyout queue is 261 * awakened and the operation is completed. 262 * -- MSG_RCVCOPY is set, we simply go back to sleep again 263 * on the copyout queue. 264 * d) If the message type is not found then we wakeup the next 265 * process on the copyout queue. 266 * 7) If a msgsnd is unable to complete for of any of the following reasons 267 * a) the msgq has no space for the message 268 * b) the maximum number of messages allowed has been reached 269 * then one of two things happen: 270 * 1) If the passed in msg_flag has IPC_NOWAIT set, then 271 * an error is returned. 272 * 2) The IPC_NOWAIT bit is not set in msg_flag, then the 273 * the thread is placed to sleep until the request can be 274 * serviced. 275 * 8) When waking a thread waiting to send a message, a check is done to 276 * verify that the operation being asked for by the thread will complete. 277 * This decision making process is done in a loop where the oldest request 278 * is checked first. The search will continue until there is no more 279 * room on the msgq or we have checked all the waiters. 280 */ 281 282 static uint_t msg_type_hash(long); 283 static int msgq_check_err(kmsqid_t *qp, int cvres); 284 static int msg_rcvq_sleep(list_t *, msgq_wakeup_t *, kmutex_t **, 285 kmsqid_t *); 286 static int msg_copyout(kmsqid_t *, long, kmutex_t **, size_t *, size_t, 287 struct msg *, struct ipcmsgbuf *, int); 288 static void msg_rcvq_wakeup_all(list_t *); 289 static void msg_wakeup_senders(kmsqid_t *); 290 static void msg_wakeup_rdr(kmsqid_t *, msg_select_t **, long); 291 static msgq_wakeup_t *msg_fnd_any_snd(kmsqid_t *, int, long); 292 static msgq_wakeup_t *msg_fnd_any_rdr(kmsqid_t *, int, long); 293 static msgq_wakeup_t *msg_fnd_neg_snd(kmsqid_t *, int, long); 294 static msgq_wakeup_t *msg_fnd_spc_snd(kmsqid_t *, int, long); 295 static struct msg *msgrcv_lookup(kmsqid_t *, long); 296 297 msg_select_t msg_fnd_sndr[] = { 298 { msg_fnd_any_snd, &msg_fnd_sndr[1] }, 299 { msg_fnd_spc_snd, &msg_fnd_sndr[2] }, 300 { msg_fnd_neg_snd, &msg_fnd_sndr[0] } 301 }; 302 303 msg_select_t msg_fnd_rdr[1] = { 304 { msg_fnd_any_rdr, &msg_fnd_rdr[0] }, 305 }; 306 307 static struct modlinkage modlinkage = { 308 MODREV_1, 309 { &modlsys, 310 #ifdef _SYSCALL32_IMPL 311 &modlsys32, 312 #endif 313 NULL 314 } 315 }; 316 317 #define MSG_SMALL_INIT (size_t)-1 318 int 319 _init(void) 320 { 321 int result; 322 323 msq_svc = ipcs_create("msqids", rc_project_msgmni, rc_zone_msgmni, 324 sizeof (kmsqid_t), msg_dtor, msg_rmid, AT_IPC_MSG, 325 offsetof(ipc_rqty_t, ipcq_msgmni)); 326 zone_key_create(&msg_zone_key, NULL, msg_remove_zone, NULL); 327 328 if ((result = mod_install(&modlinkage)) == 0) 329 return (0); 330 331 (void) zone_key_delete(msg_zone_key); 332 ipcs_destroy(msq_svc); 333 334 return (result); 335 } 336 337 int 338 _fini(void) 339 { 340 return (EBUSY); 341 } 342 343 int 344 _info(struct modinfo *modinfop) 345 { 346 return (mod_info(&modlinkage, modinfop)); 347 } 348 349 static void 350 msg_dtor(kipc_perm_t *perm) 351 { 352 kmsqid_t *qp = (kmsqid_t *)perm; 353 int ii; 354 355 for (ii = 0; ii <= MSG_MAX_QNUM; ii++) { 356 ASSERT(list_is_empty(&qp->msg_wait_snd[ii])); 357 ASSERT(list_is_empty(&qp->msg_wait_snd_ngt[ii])); 358 list_destroy(&qp->msg_wait_snd[ii]); 359 list_destroy(&qp->msg_wait_snd_ngt[ii]); 360 } 361 ASSERT(list_is_empty(&qp->msg_cpy_block)); 362 ASSERT(list_is_empty(&qp->msg_wait_rcv)); 363 list_destroy(&qp->msg_cpy_block); 364 ASSERT(qp->msg_snd_cnt == 0); 365 ASSERT(qp->msg_cbytes == 0); 366 list_destroy(&qp->msg_list); 367 list_destroy(&qp->msg_wait_rcv); 368 } 369 370 371 #define msg_hold(mp) (mp)->msg_copycnt++ 372 373 /* 374 * msg_rele - decrement the reference count on the message. When count 375 * reaches zero, free message header and contents. 376 */ 377 static void 378 msg_rele(struct msg *mp) 379 { 380 ASSERT(mp->msg_copycnt > 0); 381 if (mp->msg_copycnt-- == 1) { 382 if (mp->msg_addr) 383 kmem_free(mp->msg_addr, mp->msg_size); 384 kmem_free(mp, sizeof (struct msg)); 385 } 386 } 387 388 /* 389 * msgunlink - Unlink msg from queue, decrement byte count and wake up anyone 390 * waiting for free bytes on queue. 391 * 392 * Called with queue locked. 393 */ 394 static void 395 msgunlink(kmsqid_t *qp, struct msg *mp) 396 { 397 list_remove(&qp->msg_list, mp); 398 qp->msg_qnum--; 399 qp->msg_cbytes -= mp->msg_size; 400 msg_rele(mp); 401 402 /* Wake up waiting writers */ 403 msg_wakeup_senders(qp); 404 } 405 406 static void 407 msg_rmid(kipc_perm_t *perm) 408 { 409 kmsqid_t *qp = (kmsqid_t *)perm; 410 struct msg *mp; 411 int ii; 412 413 414 while ((mp = list_head(&qp->msg_list)) != NULL) 415 msgunlink(qp, mp); 416 ASSERT(qp->msg_cbytes == 0); 417 418 /* 419 * Wake up everyone who is in a wait state of some sort 420 * for this message queue. 421 */ 422 for (ii = 0; ii <= MSG_MAX_QNUM; ii++) { 423 msg_rcvq_wakeup_all(&qp->msg_wait_snd[ii]); 424 msg_rcvq_wakeup_all(&qp->msg_wait_snd_ngt[ii]); 425 } 426 msg_rcvq_wakeup_all(&qp->msg_cpy_block); 427 msg_rcvq_wakeup_all(&qp->msg_wait_rcv); 428 } 429 430 /* 431 * msgctl system call. 432 * 433 * gets q lock (via ipc_lookup), releases before return. 434 * may call users of msg_lock 435 */ 436 static int 437 msgctl(int msgid, int cmd, void *arg) 438 { 439 STRUCT_DECL(msqid_ds, ds); /* SVR4 queue work area */ 440 kmsqid_t *qp; /* ptr to associated q */ 441 int error; 442 struct cred *cr; 443 model_t mdl = get_udatamodel(); 444 struct msqid_ds64 ds64; 445 kmutex_t *lock; 446 proc_t *pp = curproc; 447 448 STRUCT_INIT(ds, mdl); 449 cr = CRED(); 450 451 /* 452 * Perform pre- or non-lookup actions (e.g. copyins, RMID). 453 */ 454 switch (cmd) { 455 case IPC_SET: 456 if (copyin(arg, STRUCT_BUF(ds), STRUCT_SIZE(ds))) 457 return (set_errno(EFAULT)); 458 break; 459 460 case IPC_SET64: 461 if (copyin(arg, &ds64, sizeof (struct msqid_ds64))) 462 return (set_errno(EFAULT)); 463 break; 464 465 case IPC_RMID: 466 if (error = ipc_rmid(msq_svc, msgid, cr)) 467 return (set_errno(error)); 468 return (0); 469 } 470 471 /* 472 * get msqid_ds for this msgid 473 */ 474 if ((lock = ipc_lookup(msq_svc, msgid, (kipc_perm_t **)&qp)) == NULL) 475 return (set_errno(EINVAL)); 476 477 switch (cmd) { 478 case IPC_SET: 479 if (STRUCT_FGET(ds, msg_qbytes) > qp->msg_qbytes && 480 secpolicy_ipc_config(cr) != 0) { 481 mutex_exit(lock); 482 return (set_errno(EPERM)); 483 } 484 if (error = ipcperm_set(msq_svc, cr, &qp->msg_perm, 485 &STRUCT_BUF(ds)->msg_perm, mdl)) { 486 mutex_exit(lock); 487 return (set_errno(error)); 488 } 489 qp->msg_qbytes = STRUCT_FGET(ds, msg_qbytes); 490 qp->msg_ctime = gethrestime_sec(); 491 break; 492 493 case IPC_STAT: 494 if (error = ipcperm_access(&qp->msg_perm, MSG_R, cr)) { 495 mutex_exit(lock); 496 return (set_errno(error)); 497 } 498 499 if (qp->msg_rcv_cnt) 500 qp->msg_perm.ipc_mode |= MSG_RWAIT; 501 if (qp->msg_snd_cnt) 502 qp->msg_perm.ipc_mode |= MSG_WWAIT; 503 ipcperm_stat(&STRUCT_BUF(ds)->msg_perm, &qp->msg_perm, mdl); 504 qp->msg_perm.ipc_mode &= ~(MSG_RWAIT|MSG_WWAIT); 505 STRUCT_FSETP(ds, msg_first, NULL); /* kernel addr */ 506 STRUCT_FSETP(ds, msg_last, NULL); 507 STRUCT_FSET(ds, msg_cbytes, qp->msg_cbytes); 508 STRUCT_FSET(ds, msg_qnum, qp->msg_qnum); 509 STRUCT_FSET(ds, msg_qbytes, qp->msg_qbytes); 510 STRUCT_FSET(ds, msg_lspid, qp->msg_lspid); 511 STRUCT_FSET(ds, msg_lrpid, qp->msg_lrpid); 512 STRUCT_FSET(ds, msg_stime, qp->msg_stime); 513 STRUCT_FSET(ds, msg_rtime, qp->msg_rtime); 514 STRUCT_FSET(ds, msg_ctime, qp->msg_ctime); 515 break; 516 517 case IPC_SET64: 518 mutex_enter(&pp->p_lock); 519 if ((ds64.msgx_qbytes > qp->msg_qbytes) && 520 secpolicy_ipc_config(cr) != 0 && 521 rctl_test(rc_process_msgmnb, pp->p_rctls, pp, 522 ds64.msgx_qbytes, RCA_SAFE) & RCT_DENY) { 523 mutex_exit(&pp->p_lock); 524 mutex_exit(lock); 525 return (set_errno(EPERM)); 526 } 527 mutex_exit(&pp->p_lock); 528 if (error = ipcperm_set64(msq_svc, cr, &qp->msg_perm, 529 &ds64.msgx_perm)) { 530 mutex_exit(lock); 531 return (set_errno(error)); 532 } 533 qp->msg_qbytes = ds64.msgx_qbytes; 534 qp->msg_ctime = gethrestime_sec(); 535 break; 536 537 case IPC_STAT64: 538 if (qp->msg_rcv_cnt) 539 qp->msg_perm.ipc_mode |= MSG_RWAIT; 540 if (qp->msg_snd_cnt) 541 qp->msg_perm.ipc_mode |= MSG_WWAIT; 542 ipcperm_stat64(&ds64.msgx_perm, &qp->msg_perm); 543 qp->msg_perm.ipc_mode &= ~(MSG_RWAIT|MSG_WWAIT); 544 ds64.msgx_cbytes = qp->msg_cbytes; 545 ds64.msgx_qnum = qp->msg_qnum; 546 ds64.msgx_qbytes = qp->msg_qbytes; 547 ds64.msgx_lspid = qp->msg_lspid; 548 ds64.msgx_lrpid = qp->msg_lrpid; 549 ds64.msgx_stime = qp->msg_stime; 550 ds64.msgx_rtime = qp->msg_rtime; 551 ds64.msgx_ctime = qp->msg_ctime; 552 break; 553 554 default: 555 mutex_exit(lock); 556 return (set_errno(EINVAL)); 557 } 558 559 mutex_exit(lock); 560 561 /* 562 * Do copyout last (after releasing mutex). 563 */ 564 switch (cmd) { 565 case IPC_STAT: 566 if (copyout(STRUCT_BUF(ds), arg, STRUCT_SIZE(ds))) 567 return (set_errno(EFAULT)); 568 break; 569 570 case IPC_STAT64: 571 if (copyout(&ds64, arg, sizeof (struct msqid_ds64))) 572 return (set_errno(EFAULT)); 573 break; 574 } 575 576 return (0); 577 } 578 579 /* 580 * Remove all message queues associated with a given zone. Called by 581 * zone_shutdown when the zone is halted. 582 */ 583 /*ARGSUSED1*/ 584 static void 585 msg_remove_zone(zoneid_t zoneid, void *arg) 586 { 587 ipc_remove_zone(msq_svc, zoneid); 588 } 589 590 /* 591 * msgget system call. 592 */ 593 static int 594 msgget(key_t key, int msgflg) 595 { 596 kmsqid_t *qp; 597 kmutex_t *lock; 598 int id, error; 599 int ii; 600 proc_t *pp = curproc; 601 602 top: 603 if (error = ipc_get(msq_svc, key, msgflg, (kipc_perm_t **)&qp, &lock)) 604 return (set_errno(error)); 605 606 if (IPC_FREE(&qp->msg_perm)) { 607 mutex_exit(lock); 608 mutex_exit(&pp->p_lock); 609 610 list_create(&qp->msg_list, sizeof (struct msg), 611 offsetof(struct msg, msg_node)); 612 qp->msg_qnum = 0; 613 qp->msg_lspid = qp->msg_lrpid = 0; 614 qp->msg_stime = qp->msg_rtime = 0; 615 qp->msg_ctime = gethrestime_sec(); 616 qp->msg_ngt_cnt = 0; 617 qp->msg_neg_copy = 0; 618 for (ii = 0; ii <= MSG_MAX_QNUM; ii++) { 619 list_create(&qp->msg_wait_snd[ii], 620 sizeof (msgq_wakeup_t), 621 offsetof(msgq_wakeup_t, msgw_list)); 622 list_create(&qp->msg_wait_snd_ngt[ii], 623 sizeof (msgq_wakeup_t), 624 offsetof(msgq_wakeup_t, msgw_list)); 625 } 626 /* 627 * The proper initialization of msg_lowest_type is to the 628 * highest possible value. By doing this we guarantee that 629 * when the first send happens, the lowest type will be set 630 * properly. 631 */ 632 qp->msg_lowest_type = MSG_SMALL_INIT; 633 list_create(&qp->msg_cpy_block, 634 sizeof (msgq_wakeup_t), 635 offsetof(msgq_wakeup_t, msgw_list)); 636 list_create(&qp->msg_wait_rcv, 637 sizeof (msgq_wakeup_t), 638 offsetof(msgq_wakeup_t, msgw_list)); 639 qp->msg_fnd_sndr = &msg_fnd_sndr[0]; 640 qp->msg_fnd_rdr = &msg_fnd_rdr[0]; 641 qp->msg_rcv_cnt = 0; 642 qp->msg_snd_cnt = 0; 643 qp->msg_snd_smallest = MSG_SMALL_INIT; 644 645 if (error = ipc_commit_begin(msq_svc, key, msgflg, 646 (kipc_perm_t *)qp)) { 647 if (error == EAGAIN) 648 goto top; 649 return (set_errno(error)); 650 } 651 qp->msg_qbytes = rctl_enforced_value(rc_process_msgmnb, 652 pp->p_rctls, pp); 653 qp->msg_qmax = rctl_enforced_value(rc_process_msgtql, 654 pp->p_rctls, pp); 655 lock = ipc_commit_end(msq_svc, &qp->msg_perm); 656 } 657 658 if (AU_AUDITING()) 659 audit_ipcget(AT_IPC_MSG, (void *)qp); 660 661 id = qp->msg_perm.ipc_id; 662 mutex_exit(lock); 663 return (id); 664 } 665 666 static ssize_t 667 msgrcv(int msqid, struct ipcmsgbuf *msgp, size_t msgsz, long msgtyp, int msgflg) 668 { 669 struct msg *smp; /* ptr to best msg on q */ 670 kmsqid_t *qp; /* ptr to associated q */ 671 kmutex_t *lock; 672 size_t xtsz; /* transfer byte count */ 673 int error = 0; 674 int cvres; 675 uint_t msg_hash; 676 msgq_wakeup_t msg_entry; 677 678 CPU_STATS_ADDQ(CPU, sys, msg, 1); /* bump msg send/rcv count */ 679 680 msg_hash = msg_type_hash(msgtyp); 681 if ((lock = ipc_lookup(msq_svc, msqid, (kipc_perm_t **)&qp)) == NULL) { 682 return ((ssize_t)set_errno(EINVAL)); 683 } 684 ipc_hold(msq_svc, (kipc_perm_t *)qp); 685 686 if (error = ipcperm_access(&qp->msg_perm, MSG_R, CRED())) { 687 goto msgrcv_out; 688 } 689 690 /* 691 * Various information (including the condvar_t) required for the 692 * process to sleep is provided by it's stack. 693 */ 694 msg_entry.msgw_thrd = curthread; 695 msg_entry.msgw_snd_wake = 0; 696 msg_entry.msgw_type = msgtyp; 697 findmsg: 698 smp = msgrcv_lookup(qp, msgtyp); 699 700 if (smp) { 701 /* 702 * We found a possible message to copy out. 703 */ 704 if ((smp->msg_flags & MSG_RCVCOPY) == 0) { 705 long t = msg_entry.msgw_snd_wake; 706 long copy_type = smp->msg_type; 707 708 /* 709 * It is available, attempt to copy it. 710 */ 711 error = msg_copyout(qp, msgtyp, &lock, &xtsz, msgsz, 712 smp, msgp, msgflg); 713 714 /* 715 * It is possible to consume a different message 716 * type then what originally awakened for (negative 717 * types). If this happens a check must be done to 718 * to determine if another receiver is available 719 * for the waking message type, Failure to do this 720 * can result in a message on the queue that can be 721 * serviced by a sleeping receiver. 722 */ 723 if (!error && t && (copy_type != t)) 724 msg_wakeup_rdr(qp, &qp->msg_fnd_sndr, t); 725 726 /* 727 * Don't forget to wakeup a sleeper that blocked because 728 * we were copying things out. 729 */ 730 msg_wakeup_rdr(qp, &qp->msg_fnd_rdr, 0); 731 goto msgrcv_out; 732 } 733 /* 734 * The selected message is being copied out, so block. We do 735 * not need to wake the next person up on the msg_cpy_block list 736 * due to the fact some one is copying out and they will get 737 * things moving again once the copy is completed. 738 */ 739 cvres = msg_rcvq_sleep(&qp->msg_cpy_block, 740 &msg_entry, &lock, qp); 741 error = msgq_check_err(qp, cvres); 742 if (error) { 743 goto msgrcv_out; 744 } 745 goto findmsg; 746 } 747 /* 748 * There isn't a message to copy out that matches the designated 749 * criteria. 750 */ 751 if (msgflg & IPC_NOWAIT) { 752 error = ENOMSG; 753 goto msgrcv_out; 754 } 755 msg_wakeup_rdr(qp, &qp->msg_fnd_rdr, 0); 756 757 /* 758 * Wait for new message. We keep the negative and positive types 759 * separate for performance reasons. 760 */ 761 msg_entry.msgw_snd_wake = 0; 762 if (msgtyp >= 0) { 763 cvres = msg_rcvq_sleep(&qp->msg_wait_snd[msg_hash], 764 &msg_entry, &lock, qp); 765 } else { 766 qp->msg_ngt_cnt++; 767 cvres = msg_rcvq_sleep(&qp->msg_wait_snd_ngt[msg_hash], 768 &msg_entry, &lock, qp); 769 qp->msg_ngt_cnt--; 770 } 771 772 if (!(error = msgq_check_err(qp, cvres))) { 773 goto findmsg; 774 } 775 776 msgrcv_out: 777 if (error) { 778 msg_wakeup_rdr(qp, &qp->msg_fnd_rdr, 0); 779 if (msg_entry.msgw_snd_wake) { 780 msg_wakeup_rdr(qp, &qp->msg_fnd_sndr, 781 msg_entry.msgw_snd_wake); 782 } 783 ipc_rele(msq_svc, (kipc_perm_t *)qp); 784 return ((ssize_t)set_errno(error)); 785 } 786 ipc_rele(msq_svc, (kipc_perm_t *)qp); 787 return ((ssize_t)xtsz); 788 } 789 790 static int 791 msgq_check_err(kmsqid_t *qp, int cvres) 792 { 793 if (IPC_FREE(&qp->msg_perm)) { 794 return (EIDRM); 795 } 796 797 if (cvres == 0) { 798 return (EINTR); 799 } 800 801 return (0); 802 } 803 804 static int 805 msg_copyout(kmsqid_t *qp, long msgtyp, kmutex_t **lock, size_t *xtsz_ret, 806 size_t msgsz, struct msg *smp, struct ipcmsgbuf *msgp, int msgflg) 807 { 808 size_t xtsz; 809 STRUCT_HANDLE(ipcmsgbuf, umsgp); 810 model_t mdl = get_udatamodel(); 811 int copyerror = 0; 812 813 STRUCT_SET_HANDLE(umsgp, mdl, msgp); 814 if (msgsz < smp->msg_size) { 815 if ((msgflg & MSG_NOERROR) == 0) { 816 return (E2BIG); 817 } else { 818 xtsz = msgsz; 819 } 820 } else { 821 xtsz = smp->msg_size; 822 } 823 *xtsz_ret = xtsz; 824 825 /* 826 * To prevent a DOS attack we mark the message as being 827 * copied out and release mutex. When the copy is completed 828 * we need to acquire the mutex and make the appropriate updates. 829 */ 830 ASSERT((smp->msg_flags & MSG_RCVCOPY) == 0); 831 smp->msg_flags |= MSG_RCVCOPY; 832 msg_hold(smp); 833 if (msgtyp < 0) { 834 ASSERT(qp->msg_neg_copy == 0); 835 qp->msg_neg_copy = 1; 836 } 837 mutex_exit(*lock); 838 839 if (mdl == DATAMODEL_NATIVE) { 840 copyerror = copyout(&smp->msg_type, msgp, 841 sizeof (smp->msg_type)); 842 } else { 843 /* 844 * 32-bit callers need an imploded msg type. 845 */ 846 int32_t msg_type32 = smp->msg_type; 847 848 copyerror = copyout(&msg_type32, msgp, 849 sizeof (msg_type32)); 850 } 851 852 if (copyerror == 0 && xtsz) { 853 copyerror = copyout(smp->msg_addr, 854 STRUCT_FADDR(umsgp, mtext), xtsz); 855 } 856 857 /* 858 * Reclaim the mutex and make sure the message queue still exists. 859 */ 860 861 *lock = ipc_lock(msq_svc, qp->msg_perm.ipc_id); 862 if (msgtyp < 0) { 863 qp->msg_neg_copy = 0; 864 } 865 ASSERT(smp->msg_flags & MSG_RCVCOPY); 866 smp->msg_flags &= ~MSG_RCVCOPY; 867 msg_rele(smp); 868 if (IPC_FREE(&qp->msg_perm)) { 869 return (EIDRM); 870 } 871 if (copyerror) { 872 return (EFAULT); 873 } 874 qp->msg_lrpid = ttoproc(curthread)->p_pid; 875 qp->msg_rtime = gethrestime_sec(); 876 msgunlink(qp, smp); 877 return (0); 878 } 879 880 static struct msg * 881 msgrcv_lookup(kmsqid_t *qp, long msgtyp) 882 { 883 struct msg *smp = NULL; 884 long qp_low; 885 struct msg *mp; /* ptr to msg on q */ 886 long low_msgtype; 887 static struct msg neg_copy_smp; 888 889 mp = list_head(&qp->msg_list); 890 if (msgtyp == 0) { 891 smp = mp; 892 } else { 893 qp_low = qp->msg_lowest_type; 894 if (msgtyp > 0) { 895 /* 896 * If our lowest possible message type is larger than 897 * the message type desired, then we know there is 898 * no entry present. 899 */ 900 if (qp_low > msgtyp) { 901 return (NULL); 902 } 903 904 for (; mp; mp = list_next(&qp->msg_list, mp)) { 905 if (msgtyp == mp->msg_type) { 906 smp = mp; 907 break; 908 } 909 } 910 } else { 911 /* 912 * We have kept track of the lowest possible message 913 * type on the send queue. This allows us to terminate 914 * the search early if we find a message type of that 915 * type. Note, the lowest type may not be the actual 916 * lowest value in the system, it is only guaranteed 917 * that there isn't a value lower than that. 918 */ 919 low_msgtype = -msgtyp; 920 if (low_msgtype < qp_low) { 921 return (NULL); 922 } 923 if (qp->msg_neg_copy) { 924 neg_copy_smp.msg_flags = MSG_RCVCOPY; 925 return (&neg_copy_smp); 926 } 927 for (; mp; mp = list_next(&qp->msg_list, mp)) { 928 if (mp->msg_type <= low_msgtype && 929 !(smp && smp->msg_type <= mp->msg_type)) { 930 smp = mp; 931 low_msgtype = mp->msg_type; 932 if (low_msgtype == qp_low) { 933 break; 934 } 935 } 936 } 937 if (smp) { 938 /* 939 * Update the lowest message type. 940 */ 941 qp->msg_lowest_type = smp->msg_type; 942 } 943 } 944 } 945 return (smp); 946 } 947 948 /* 949 * msgids system call. 950 */ 951 static int 952 msgids(int *buf, uint_t nids, uint_t *pnids) 953 { 954 int error; 955 956 if (error = ipc_ids(msq_svc, buf, nids, pnids)) 957 return (set_errno(error)); 958 959 return (0); 960 } 961 962 #define RND(x) roundup((x), sizeof (size_t)) 963 #define RND32(x) roundup((x), sizeof (size32_t)) 964 965 /* 966 * msgsnap system call. 967 */ 968 static int 969 msgsnap(int msqid, caddr_t buf, size_t bufsz, long msgtyp) 970 { 971 struct msg *mp; /* ptr to msg on q */ 972 kmsqid_t *qp; /* ptr to associated q */ 973 kmutex_t *lock; 974 size_t size; 975 size_t nmsg; 976 struct msg **snaplist; 977 int error, i; 978 model_t mdl = get_udatamodel(); 979 STRUCT_DECL(msgsnap_head, head); 980 STRUCT_DECL(msgsnap_mhead, mhead); 981 982 STRUCT_INIT(head, mdl); 983 STRUCT_INIT(mhead, mdl); 984 985 if (bufsz < STRUCT_SIZE(head)) 986 return (set_errno(EINVAL)); 987 988 if ((lock = ipc_lookup(msq_svc, msqid, (kipc_perm_t **)&qp)) == NULL) 989 return (set_errno(EINVAL)); 990 991 if (error = ipcperm_access(&qp->msg_perm, MSG_R, CRED())) { 992 mutex_exit(lock); 993 return (set_errno(error)); 994 } 995 ipc_hold(msq_svc, (kipc_perm_t *)qp); 996 997 /* 998 * First compute the required buffer size and 999 * the number of messages on the queue. 1000 */ 1001 size = nmsg = 0; 1002 for (mp = list_head(&qp->msg_list); mp; 1003 mp = list_next(&qp->msg_list, mp)) { 1004 if (msgtyp == 0 || 1005 (msgtyp > 0 && msgtyp == mp->msg_type) || 1006 (msgtyp < 0 && mp->msg_type <= -msgtyp)) { 1007 nmsg++; 1008 if (mdl == DATAMODEL_NATIVE) 1009 size += RND(mp->msg_size); 1010 else 1011 size += RND32(mp->msg_size); 1012 } 1013 } 1014 1015 size += STRUCT_SIZE(head) + nmsg * STRUCT_SIZE(mhead); 1016 if (size > bufsz) 1017 nmsg = 0; 1018 1019 if (nmsg > 0) { 1020 /* 1021 * Mark the messages as being copied. 1022 */ 1023 snaplist = (struct msg **)kmem_alloc(nmsg * 1024 sizeof (struct msg *), KM_SLEEP); 1025 i = 0; 1026 for (mp = list_head(&qp->msg_list); mp; 1027 mp = list_next(&qp->msg_list, mp)) { 1028 if (msgtyp == 0 || 1029 (msgtyp > 0 && msgtyp == mp->msg_type) || 1030 (msgtyp < 0 && mp->msg_type <= -msgtyp)) { 1031 msg_hold(mp); 1032 snaplist[i] = mp; 1033 i++; 1034 } 1035 } 1036 } 1037 mutex_exit(lock); 1038 1039 /* 1040 * Copy out the buffer header. 1041 */ 1042 STRUCT_FSET(head, msgsnap_size, size); 1043 STRUCT_FSET(head, msgsnap_nmsg, nmsg); 1044 if (copyout(STRUCT_BUF(head), buf, STRUCT_SIZE(head))) 1045 error = EFAULT; 1046 1047 buf += STRUCT_SIZE(head); 1048 1049 /* 1050 * Now copy out the messages one by one. 1051 */ 1052 for (i = 0; i < nmsg; i++) { 1053 mp = snaplist[i]; 1054 if (error == 0) { 1055 STRUCT_FSET(mhead, msgsnap_mlen, mp->msg_size); 1056 STRUCT_FSET(mhead, msgsnap_mtype, mp->msg_type); 1057 if (copyout(STRUCT_BUF(mhead), buf, STRUCT_SIZE(mhead))) 1058 error = EFAULT; 1059 buf += STRUCT_SIZE(mhead); 1060 1061 if (error == 0 && 1062 mp->msg_size != 0 && 1063 copyout(mp->msg_addr, buf, mp->msg_size)) 1064 error = EFAULT; 1065 if (mdl == DATAMODEL_NATIVE) 1066 buf += RND(mp->msg_size); 1067 else 1068 buf += RND32(mp->msg_size); 1069 } 1070 lock = ipc_lock(msq_svc, qp->msg_perm.ipc_id); 1071 msg_rele(mp); 1072 /* Check for msg q deleted or reallocated */ 1073 if (IPC_FREE(&qp->msg_perm)) 1074 error = EIDRM; 1075 mutex_exit(lock); 1076 } 1077 1078 (void) ipc_lock(msq_svc, qp->msg_perm.ipc_id); 1079 ipc_rele(msq_svc, (kipc_perm_t *)qp); 1080 1081 if (nmsg > 0) 1082 kmem_free(snaplist, nmsg * sizeof (struct msg *)); 1083 1084 if (error) 1085 return (set_errno(error)); 1086 return (0); 1087 } 1088 1089 #define MSG_PREALLOC_LIMIT 8192 1090 1091 /* 1092 * msgsnd system call. 1093 */ 1094 static int 1095 msgsnd(int msqid, struct ipcmsgbuf *msgp, size_t msgsz, int msgflg) 1096 { 1097 kmsqid_t *qp; 1098 kmutex_t *lock = NULL; 1099 struct msg *mp = NULL; 1100 long type; 1101 int error = 0, wait_wakeup = 0; 1102 msgq_wakeup_t msg_entry; 1103 model_t mdl = get_udatamodel(); 1104 STRUCT_HANDLE(ipcmsgbuf, umsgp); 1105 1106 CPU_STATS_ADDQ(CPU, sys, msg, 1); /* bump msg send/rcv count */ 1107 STRUCT_SET_HANDLE(umsgp, mdl, msgp); 1108 1109 if (mdl == DATAMODEL_NATIVE) { 1110 if (copyin(msgp, &type, sizeof (type))) 1111 return (set_errno(EFAULT)); 1112 } else { 1113 int32_t type32; 1114 if (copyin(msgp, &type32, sizeof (type32))) 1115 return (set_errno(EFAULT)); 1116 type = type32; 1117 } 1118 1119 if (type < 1) 1120 return (set_errno(EINVAL)); 1121 1122 /* 1123 * We want the value here large enough that most of the 1124 * the message operations will use the "lockless" path, 1125 * but small enough that a user can not reserve large 1126 * chunks of kernel memory unless they have a valid 1127 * reason to. 1128 */ 1129 if (msgsz <= MSG_PREALLOC_LIMIT) { 1130 /* 1131 * We are small enough that we can afford to do the 1132 * allocation now. This saves dropping the lock 1133 * and then reacquiring the lock. 1134 */ 1135 mp = kmem_zalloc(sizeof (struct msg), KM_SLEEP); 1136 mp->msg_copycnt = 1; 1137 mp->msg_size = msgsz; 1138 if (msgsz) { 1139 mp->msg_addr = kmem_alloc(msgsz, KM_SLEEP); 1140 if (copyin(STRUCT_FADDR(umsgp, mtext), 1141 mp->msg_addr, msgsz) == -1) { 1142 error = EFAULT; 1143 goto msgsnd_out; 1144 } 1145 } 1146 } 1147 1148 if ((lock = ipc_lookup(msq_svc, msqid, (kipc_perm_t **)&qp)) == NULL) { 1149 error = EINVAL; 1150 goto msgsnd_out; 1151 } 1152 1153 ipc_hold(msq_svc, (kipc_perm_t *)qp); 1154 1155 if (msgsz > qp->msg_qbytes) { 1156 error = EINVAL; 1157 goto msgsnd_out; 1158 } 1159 1160 if (error = ipcperm_access(&qp->msg_perm, MSG_W, CRED())) 1161 goto msgsnd_out; 1162 1163 top: 1164 /* 1165 * Allocate space on q, message header, & buffer space. 1166 */ 1167 ASSERT(qp->msg_qnum <= qp->msg_qmax); 1168 while ((msgsz > qp->msg_qbytes - qp->msg_cbytes) || 1169 (qp->msg_qnum == qp->msg_qmax)) { 1170 int cvres; 1171 1172 if (msgflg & IPC_NOWAIT) { 1173 error = EAGAIN; 1174 goto msgsnd_out; 1175 } 1176 1177 wait_wakeup = 0; 1178 qp->msg_snd_cnt++; 1179 msg_entry.msgw_snd_size = msgsz; 1180 msg_entry.msgw_thrd = curthread; 1181 msg_entry.msgw_type = type; 1182 cv_init(&msg_entry.msgw_wake_cv, NULL, 0, NULL); 1183 list_insert_tail(&qp->msg_wait_rcv, &msg_entry); 1184 if (qp->msg_snd_smallest > msgsz) 1185 qp->msg_snd_smallest = msgsz; 1186 cvres = cv_wait_sig(&msg_entry.msgw_wake_cv, lock); 1187 lock = ipc_relock(msq_svc, qp->msg_perm.ipc_id, lock); 1188 qp->msg_snd_cnt--; 1189 if (list_link_active(&msg_entry.msgw_list)) 1190 list_remove(&qp->msg_wait_rcv, &msg_entry); 1191 if (error = msgq_check_err(qp, cvres)) { 1192 goto msgsnd_out; 1193 } 1194 wait_wakeup = 1; 1195 } 1196 1197 if (mp == NULL) { 1198 int failure; 1199 1200 mutex_exit(lock); 1201 ASSERT(msgsz > 0); 1202 mp = kmem_zalloc(sizeof (struct msg), KM_SLEEP); 1203 mp->msg_addr = kmem_alloc(msgsz, KM_SLEEP); 1204 mp->msg_size = msgsz; 1205 mp->msg_copycnt = 1; 1206 1207 failure = (copyin(STRUCT_FADDR(umsgp, mtext), 1208 mp->msg_addr, msgsz) == -1); 1209 lock = ipc_lock(msq_svc, qp->msg_perm.ipc_id); 1210 if (IPC_FREE(&qp->msg_perm)) { 1211 error = EIDRM; 1212 goto msgsnd_out; 1213 } 1214 if (failure) { 1215 error = EFAULT; 1216 goto msgsnd_out; 1217 } 1218 goto top; 1219 } 1220 1221 /* 1222 * Everything is available, put msg on q. 1223 */ 1224 qp->msg_qnum++; 1225 qp->msg_cbytes += msgsz; 1226 qp->msg_lspid = curproc->p_pid; 1227 qp->msg_stime = gethrestime_sec(); 1228 mp->msg_type = type; 1229 if (qp->msg_lowest_type > type) 1230 qp->msg_lowest_type = type; 1231 list_insert_tail(&qp->msg_list, mp); 1232 /* 1233 * Get the proper receiver going. 1234 */ 1235 msg_wakeup_rdr(qp, &qp->msg_fnd_sndr, type); 1236 1237 msgsnd_out: 1238 /* 1239 * We were woken up from the send wait list, but an 1240 * an error occured on placing the message onto the 1241 * msg queue. Given that, we need to do the wakeup 1242 * dance again. 1243 */ 1244 1245 if (wait_wakeup && error) { 1246 msg_wakeup_senders(qp); 1247 } 1248 if (lock) 1249 ipc_rele(msq_svc, (kipc_perm_t *)qp); /* drops lock */ 1250 1251 if (error) { 1252 if (mp) 1253 msg_rele(mp); 1254 return (set_errno(error)); 1255 } 1256 1257 return (0); 1258 } 1259 1260 static void 1261 msg_wakeup_rdr(kmsqid_t *qp, msg_select_t **flist, long type) 1262 { 1263 msg_select_t *walker = *flist; 1264 msgq_wakeup_t *wakeup; 1265 uint_t msg_hash; 1266 1267 msg_hash = msg_type_hash(type); 1268 1269 do { 1270 wakeup = walker->selection(qp, msg_hash, type); 1271 walker = walker->next_selection; 1272 } while (!wakeup && walker != *flist); 1273 1274 *flist = (*flist)->next_selection; 1275 if (wakeup) { 1276 if (type) { 1277 wakeup->msgw_snd_wake = type; 1278 } 1279 cv_signal(&wakeup->msgw_wake_cv); 1280 } 1281 } 1282 1283 static uint_t 1284 msg_type_hash(long msg_type) 1285 { 1286 if (msg_type < 0) { 1287 long hash = -msg_type / MSG_NEG_INTERVAL; 1288 /* 1289 * Negative message types are hashed over an 1290 * interval. Any message type that hashes 1291 * beyond MSG_MAX_QNUM is automatically placed 1292 * in the last bucket. 1293 */ 1294 if (hash > MSG_MAX_QNUM) 1295 hash = MSG_MAX_QNUM; 1296 return (hash); 1297 } 1298 1299 /* 1300 * 0 or positive message type. The first bucket is reserved for 1301 * message receivers of type 0, the other buckets we hash into. 1302 */ 1303 if (msg_type) 1304 return (1 + (msg_type % MSG_MAX_QNUM)); 1305 return (0); 1306 } 1307 1308 /* 1309 * Routines to see if we have a receiver of type 0 either blocked waiting 1310 * for a message. Simply return the first guy on the list. 1311 */ 1312 1313 static msgq_wakeup_t * 1314 /* ARGSUSED */ 1315 msg_fnd_any_snd(kmsqid_t *qp, int msg_hash, long type) 1316 { 1317 msgq_wakeup_t *walker; 1318 1319 walker = list_head(&qp->msg_wait_snd[0]); 1320 1321 if (walker) 1322 list_remove(&qp->msg_wait_snd[0], walker); 1323 return (walker); 1324 } 1325 1326 static msgq_wakeup_t * 1327 /* ARGSUSED */ 1328 msg_fnd_any_rdr(kmsqid_t *qp, int msg_hash, long type) 1329 { 1330 msgq_wakeup_t *walker; 1331 1332 walker = list_head(&qp->msg_cpy_block); 1333 if (walker) 1334 list_remove(&qp->msg_cpy_block, walker); 1335 return (walker); 1336 } 1337 1338 static msgq_wakeup_t * 1339 msg_fnd_spc_snd(kmsqid_t *qp, int msg_hash, long type) 1340 { 1341 msgq_wakeup_t *walker; 1342 1343 walker = list_head(&qp->msg_wait_snd[msg_hash]); 1344 1345 while (walker && walker->msgw_type != type) 1346 walker = list_next(&qp->msg_wait_snd[msg_hash], walker); 1347 if (walker) 1348 list_remove(&qp->msg_wait_snd[msg_hash], walker); 1349 return (walker); 1350 } 1351 1352 /* ARGSUSED */ 1353 static msgq_wakeup_t * 1354 msg_fnd_neg_snd(kmsqid_t *qp, int msg_hash, long type) 1355 { 1356 msgq_wakeup_t *qptr; 1357 int count; 1358 int check_index; 1359 int neg_index; 1360 int nbuckets; 1361 1362 if (!qp->msg_ngt_cnt) { 1363 return (NULL); 1364 } 1365 neg_index = msg_type_hash(-type); 1366 1367 /* 1368 * Check for a match among the negative type queues. Any buckets 1369 * at neg_index or larger can match the type. Use the last send 1370 * time to randomize the starting bucket to prevent starvation. 1371 * Search all buckets from neg_index to MSG_MAX_QNUM, starting 1372 * from the random starting point, and wrapping around after 1373 * MSG_MAX_QNUM. 1374 */ 1375 1376 nbuckets = MSG_MAX_QNUM - neg_index + 1; 1377 check_index = neg_index + (qp->msg_stime % nbuckets); 1378 1379 for (count = nbuckets; count > 0; count--) { 1380 qptr = list_head(&qp->msg_wait_snd_ngt[check_index]); 1381 while (qptr) { 1382 /* 1383 * The lowest hash bucket may actually contain 1384 * message types that are not valid for this 1385 * request. This can happen due to the fact that 1386 * the message buckets actually contain a consecutive 1387 * range of types. 1388 */ 1389 if (-qptr->msgw_type >= type) { 1390 list_remove(&qp->msg_wait_snd_ngt[check_index], 1391 qptr); 1392 return (qptr); 1393 } 1394 qptr = list_next(&qp->msg_wait_snd_ngt[check_index], 1395 qptr); 1396 } 1397 if (++check_index > MSG_MAX_QNUM) { 1398 check_index = neg_index; 1399 } 1400 } 1401 return (NULL); 1402 } 1403 1404 static int 1405 msg_rcvq_sleep(list_t *queue, msgq_wakeup_t *entry, kmutex_t **lock, 1406 kmsqid_t *qp) 1407 { 1408 int cvres; 1409 1410 cv_init(&entry->msgw_wake_cv, NULL, 0, NULL); 1411 1412 list_insert_tail(queue, entry); 1413 1414 qp->msg_rcv_cnt++; 1415 cvres = cv_wait_sig(&entry->msgw_wake_cv, *lock); 1416 *lock = ipc_relock(msq_svc, qp->msg_perm.ipc_id, *lock); 1417 qp->msg_rcv_cnt--; 1418 1419 if (list_link_active(&entry->msgw_list)) { 1420 /* 1421 * We woke up unexpectedly, remove ourself. 1422 */ 1423 list_remove(queue, entry); 1424 } 1425 1426 return (cvres); 1427 } 1428 1429 static void 1430 msg_rcvq_wakeup_all(list_t *q_ptr) 1431 { 1432 msgq_wakeup_t *q_walk; 1433 1434 while (q_walk = list_head(q_ptr)) { 1435 list_remove(q_ptr, q_walk); 1436 cv_signal(&q_walk->msgw_wake_cv); 1437 } 1438 } 1439 1440 /* 1441 * msgsys - System entry point for msgctl, msgget, msgrcv, and msgsnd 1442 * system calls. 1443 */ 1444 static ssize_t 1445 msgsys(int opcode, uintptr_t a1, uintptr_t a2, uintptr_t a3, 1446 uintptr_t a4, uintptr_t a5) 1447 { 1448 ssize_t error; 1449 1450 switch (opcode) { 1451 case MSGGET: 1452 error = msgget((key_t)a1, (int)a2); 1453 break; 1454 case MSGCTL: 1455 error = msgctl((int)a1, (int)a2, (void *)a3); 1456 break; 1457 case MSGRCV: 1458 error = msgrcv((int)a1, (struct ipcmsgbuf *)a2, 1459 (size_t)a3, (long)a4, (int)a5); 1460 break; 1461 case MSGSND: 1462 error = msgsnd((int)a1, (struct ipcmsgbuf *)a2, 1463 (size_t)a3, (int)a4); 1464 break; 1465 case MSGIDS: 1466 error = msgids((int *)a1, (uint_t)a2, (uint_t *)a3); 1467 break; 1468 case MSGSNAP: 1469 error = msgsnap((int)a1, (caddr_t)a2, (size_t)a3, (long)a4); 1470 break; 1471 default: 1472 error = set_errno(EINVAL); 1473 break; 1474 } 1475 1476 return (error); 1477 } 1478 1479 /* 1480 * Determine if a writer who is waiting can process its message. If so 1481 * wake it up. 1482 */ 1483 static void 1484 msg_wakeup_senders(kmsqid_t *qp) 1485 1486 { 1487 struct msgq_wakeup *ptr, *optr; 1488 size_t avail, smallest; 1489 int msgs_out; 1490 1491 /* 1492 * Is there a writer waiting, and if so, can it be serviced? If 1493 * not return back to the caller. 1494 */ 1495 if (IPC_FREE(&qp->msg_perm) || qp->msg_qnum >= qp->msg_qmax) 1496 return; 1497 1498 avail = qp->msg_qbytes - qp->msg_cbytes; 1499 if (avail < qp->msg_snd_smallest) 1500 return; 1501 1502 ptr = list_head(&qp->msg_wait_rcv); 1503 if (ptr == NULL) { 1504 qp->msg_snd_smallest = MSG_SMALL_INIT; 1505 return; 1506 } 1507 optr = ptr; 1508 1509 /* 1510 * smallest: minimum message size of all queued writers 1511 * 1512 * avail: amount of space left on the msgq 1513 * if all the writers we have woken up are successful. 1514 * 1515 * msgs_out: is the number of messages on the message queue if 1516 * all the writers we have woken up are successful. 1517 */ 1518 1519 smallest = MSG_SMALL_INIT; 1520 msgs_out = qp->msg_qnum; 1521 while (ptr) { 1522 ptr = list_next(&qp->msg_wait_rcv, ptr); 1523 if (optr->msgw_snd_size <= avail) { 1524 list_remove(&qp->msg_wait_rcv, optr); 1525 avail -= optr->msgw_snd_size; 1526 cv_signal(&optr->msgw_wake_cv); 1527 msgs_out++; 1528 if (msgs_out == qp->msg_qmax || 1529 avail < qp->msg_snd_smallest) 1530 break; 1531 } else { 1532 if (smallest > optr->msgw_snd_size) 1533 smallest = optr->msgw_snd_size; 1534 } 1535 optr = ptr; 1536 } 1537 1538 /* 1539 * Reset the smallest message size if the entire list has been visited 1540 */ 1541 if (ptr == NULL && smallest != MSG_SMALL_INIT) 1542 qp->msg_snd_smallest = smallest; 1543 } 1544 1545 #ifdef _SYSCALL32_IMPL 1546 /* 1547 * msgsys32 - System entry point for msgctl, msgget, msgrcv, and msgsnd 1548 * system calls for 32-bit callers on LP64 kernel. 1549 */ 1550 static ssize32_t 1551 msgsys32(int opcode, uint32_t a1, uint32_t a2, uint32_t a3, 1552 uint32_t a4, uint32_t a5) 1553 { 1554 ssize_t error; 1555 1556 switch (opcode) { 1557 case MSGGET: 1558 error = msgget((key_t)a1, (int)a2); 1559 break; 1560 case MSGCTL: 1561 error = msgctl((int)a1, (int)a2, (void *)(uintptr_t)a3); 1562 break; 1563 case MSGRCV: 1564 error = msgrcv((int)a1, (struct ipcmsgbuf *)(uintptr_t)a2, 1565 (size_t)a3, (long)(int32_t)a4, (int)a5); 1566 break; 1567 case MSGSND: 1568 error = msgsnd((int)a1, (struct ipcmsgbuf *)(uintptr_t)a2, 1569 (size_t)(int32_t)a3, (int)a4); 1570 break; 1571 case MSGIDS: 1572 error = msgids((int *)(uintptr_t)a1, (uint_t)a2, 1573 (uint_t *)(uintptr_t)a3); 1574 break; 1575 case MSGSNAP: 1576 error = msgsnap((int)a1, (caddr_t)(uintptr_t)a2, (size_t)a3, 1577 (long)(int32_t)a4); 1578 break; 1579 default: 1580 error = set_errno(EINVAL); 1581 break; 1582 } 1583 1584 return (error); 1585 } 1586 #endif /* SYSCALL32_IMPL */ --- EOF ---