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