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