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 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 /* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */ 33 34 #include "lpsched.h" 35 #include "validate.h" 36 37 /* 38 * The routines in this file are used to examine queued requests 39 * to see if something must be done about them. We don't bother 40 * checking requests that are: 41 * 42 * - printing (we could, to allow the administrator to stop 43 * a request by making a configuration change, but that 44 * can lead to trouble (yet another way to terminate a child) 45 * and the administrator can always disable the request to 46 * force it to stop printing and be reevaluated); 47 * 48 * - changing, since once the change is complete the request 49 * will be reevaluated again anyway; 50 * 51 * - notifying, since the request is essentially finished 52 * 53 * - being sent or already sent to a remote machine; 54 * 55 * - done. 56 * 57 * Requests that are being held or are filtering ARE to be considered, 58 * because things may have changed to make them impossible to print. 59 */ 60 #define RS_SKIP ((RS_ACTIVE & ~RS_FILTERING) | RS_DONE) 61 #define SKIP_IT(PRS) ((PRS)->request->outcome & RS_SKIP) 62 63 /** 64 ** queue_attract() - REASSIGN REQUEST(S) TO PRINTER, IF POSSIBLE 65 **/ 66 67 void 68 queue_attract(PSTATUS *pps, int (*qchk_p)(RSTATUS *), int attract_just_one) 69 { 70 register RSTATUS *prs; 71 register CSTATUS *pcs; 72 int called_schedule = 0; 73 74 75 /* 76 * Evaluate requests that: 77 * - meet a criteria set by a function passed. 78 * - are already queued for the printer 79 * - are destined for a class containing this printer 80 * - or are destined for any printer 81 * We stop on the first one that will work on the printer, 82 * and schedule an interface for the printer (which will 83 * find the first request ready, namely the one we stopped on). 84 */ 85 86 #define SAMECLASS(PRS,PPS) \ 87 ( \ 88 ((pcs = search_cstatus(PRS->request->destination)) != NULL) \ 89 && searchlist(PPS->printer->name, pcs->class->members) \ 90 ) 91 92 #define ISANY(PRS) STREQU(PRS->request->destination, NAME_ANY) 93 94 for (prs = Request_List; prs; prs = prs->next) { 95 if ( 96 !SKIP_IT(prs) 97 && (!qchk_p || (*qchk_p)(prs)) 98 && ( 99 prs->printer == pps 100 || ISANY(prs) 101 || SAMECLASS(prs, pps) 102 ) 103 ) 104 /* 105 * Don't need to evaluate the request if it 106 * is already queued! 107 */ 108 if ( 109 prs->printer == pps 110 || evaluate_request(prs, pps, 0) == MOK 111 ) { 112 /* 113 * This request was attracted to the 114 * printer but maybe it now needs to be 115 * filtered. If so, filter it but see if 116 * there's another request all set to go. 117 */ 118 if (NEEDS_FILTERING(prs)) 119 schedule (EV_SLOWF, prs); 120 else { 121 if (!called_schedule) { 122 schedule (EV_INTERF, pps); 123 called_schedule = 1; 124 } 125 if (attract_just_one) 126 break; 127 } 128 } 129 } 130 131 return; 132 } 133 134 /** 135 ** queue_repel() - REASSIGN REQUESTS TO ANOTHER PRINTER, IF POSSIBLE 136 **/ 137 138 int 139 queue_repel(PSTATUS *pps, int move_off, int (*qchk_p)(RSTATUS *)) 140 { 141 register RSTATUS *prs; 142 register int all_can = 1; 143 register PSTATUS *stop_pps = (move_off? pps : 0); 144 145 /* 146 * Reevaluate all requests that are assigned to this 147 * printer, to see if there's another printer that 148 * can handle them. 149 * 150 * If the "move_off" flag is set, don't consider the current 151 * printer when reevaluating, but also don't cancel the request 152 * if it can't be moved off the printer. 153 * (Currently this is only used when deciding if a printer 154 * can be deleted.) 155 */ 156 for (prs = Request_List; prs != NULL; prs = prs->next) { 157 if (prs->printer != pps) 158 continue; 159 160 /* 161 * "all_can" keeps track of whether all of the requests 162 * of interest to the caller (governed by "qchk_p") can 163 * be moved to another printer. Now we don't move certain 164 * requests (active, done, gone remote), and some of those 165 * matter in the ``all can'' consideration. 166 */ 167 if (qchk_p && !(*qchk_p)(prs)) 168 continue; 169 else if (SKIP_IT(prs)) { 170 if ( !(prs->request->outcome & RS_DONE) ) 171 all_can = 0; 172 continue; 173 174 } else 175 176 if (reevaluate_request(prs, stop_pps) == MOK) { 177 178 /* 179 * If this request needs to be filtered, 180 * try to schedule it for filtering, 181 * otherwise schedule it for printing. 182 * We are inefficient here, because we may 183 * try to schedule many requests but the 184 * filtering slot(s) and printers are 185 * busy; but the requests may languish 186 * if we don't check here. 187 */ 188 if (NEEDS_FILTERING(prs)) 189 schedule (EV_SLOWF, prs); 190 else 191 schedule (EV_INTERF, prs->printer); 192 193 } else { 194 all_can = 0; 195 if (!move_off) 196 cancel (prs, 1); 197 else 198 prs->reason = MOK; 199 } 200 } 201 202 return (all_can); 203 } 204 205 /** 206 ** queue_check() - CHECK ALL REQUESTS AGAIN 207 **/ 208 209 void 210 queue_check(int (*qchk_p)( RSTATUS * )) 211 { 212 register RSTATUS *prs; 213 214 215 for (prs = Request_List; prs; prs = prs->next) 216 if (!SKIP_IT(prs) && (!qchk_p || (*qchk_p)(prs))) 217 if (reevaluate_request(prs, (PSTATUS *)0) == MOK) 218 if (NEEDS_FILTERING(prs)) 219 schedule (EV_SLOWF, prs); 220 else 221 schedule (EV_INTERF, prs->printer); 222 else 223 cancel (prs, 1); 224 225 return; 226 } 227 228 /** 229 ** qchk_waiting() - CHECK IF REQUEST IS READY TO PRINT 230 ** qchk_filter() - CHECK IF REQUEST NEEDS A FILTER 231 ** qchk_form() - CHECK IF REQUEST NEEDS A FORM 232 ** qchk_pwheel() - CHECK IF REQUEST NEEDS PRINT A WHEEL 233 **/ 234 235 int 236 qchk_waiting(RSTATUS *prs) 237 { 238 return ( 239 !(prs->request->outcome & (RS_HELD|RS_DONE|RS_ACTIVE)) 240 && !NEEDS_FILTERING(prs) 241 ); 242 } 243 244 int 245 qchk_filter(RSTATUS *prs) 246 { 247 /* 248 * No need to reevaluate this request if it isn't using a filter 249 * or if it is done or is being changed. 250 */ 251 return ( 252 !(prs->request->outcome & (RS_DONE|RS_CHANGING|RS_NOTIFY)) 253 && (prs->slow || prs->fast) 254 ); 255 } 256 257 FSTATUS * form_in_question; 258 259 int 260 qchk_form(RSTATUS *prs) 261 { 262 return (prs->form == form_in_question); 263 } 264 265 char * pwheel_in_question; 266 267 int 268 qchk_pwheel(RSTATUS *prs) 269 { 270 return (SAME(prs->pwheel_name, pwheel_in_question)); 271 } 272