Retrieving the total number of Jobs in process from cupsd

Sebastian James seb at esfnet.co.uk
Sun Apr 22 02:55:19 PDT 2007


> Hi,
>
> I'm trying to write a way to retrieve both the MaxJobs parameter (as set in cupsd.conf) and the total number of jobs in process in cupsd, across all queues.
>
> I added an extra IPP operation which I called CUPS_GET_MAXJOBS.
>
> This operation is designed to return two integer attributes which I called cupsd-maxjobs and cupsd-numjobs. I chose the type IPP_TAG_EVENT_NOTIFICATION for these attributes, slightly unsurely.
>
> The client code, to request this operation (the code running on the same host as cupsd in this case) is:
>
> int
> check_cupsd_for_maxjobs (void)
> {
>   /* Find what MaxJobs is. This is held in the scheduler as a global
>    * variable */
>   /* Find what current number of jobs is */
>   /* If we're within 10 of MaxJobs, return 0 */
>   /* Any errors, return -1 */
>
>   http_t * connection;
>   ipp_t * rqst;
>   ipp_t * rtn;
>   ipp_attribute_t * ipp_attributes;
>   cups_lang_t * lang;
>
>   int MyMaxJobs = 0;
>   int MyNumJobs = 0;
>
>   static const char * jobinfo_attributes[] = {
>     "cupsd-maxjobs",
>     "cupsd-numjobs"
>   };
>   int n_attributes = 2; // Should match the above number of entries
>
>   //syslog (LOG_INFO, "At start of %s", __FUNCTION__);
>
>   /*
>    * Setup a connection and request data...
>    */
>
>   if ((connection = httpConnectEncrypt(cupsServer(), ippPort(),
> 				       cupsEncryption())) == NULL)
>   {
>     syslog(LOG_ERR, "%s: Unable to connect to server %s: %s",
> 	   __FUNCTION__, cupsServer(), strerror(errno));
>     return -1;
>   }
>
>   rqst = ippNew();
>   rqst->request.op.operation_id = CUPS_GET_MAXJOBS;
>   rqst->request.op.request_id   = 1;
>   lang = cupsLangDefault();
>
>   ippAddString(rqst,
> 	       IPP_TAG_OPERATION,
> 	       IPP_TAG_CHARSET,
> 	       "attributes-charset",
> 	       NULL,
> 	       cupsLangEncoding(lang));
>
>   ippAddString(rqst,
> 	       IPP_TAG_OPERATION,
> 	       IPP_TAG_LANGUAGE,
> 	       "attributes-natural-language",
> 	       NULL,
> 	       lang->language);
>
>   ippAddStrings(rqst,
> 		IPP_TAG_OPERATION,
> 		IPP_TAG_KEYWORD,
> 		"requested-attributes",
> 		n_attributes,
> 		NULL,
> 		jobinfo_attributes);
>
>   rtn = cupsDoRequest (connection, rqst, "/");
>
>   if (!rtn) {
>     syslog (LOG_ERR, "%s: cupsDoRequest() failed: '%s'\n", __FUNCTION__, ippErrorString(cupsLastError()));
>     cupsLangFree (lang);
>     return -1;
>   }
>
>   for (ipp_attributes = rtn->attrs; ipp_attributes != NULL; ipp_attributes = ipp_attributes->next) {
>
>     while (ipp_attributes != NULL && ipp_attributes->group_tag != IPP_TAG_EVENT_NOTIFICATION) {
>       // Move on to the next one.
>       ipp_attributes = ipp_attributes->next;
>     }
>
>     while (ipp_attributes != NULL && ipp_attributes->group_tag == IPP_TAG_EVENT_NOTIFICATION) {
>
>       if (!strcmp(ipp_attributes->name, "cupsd-maxjobs") &&
> 	  ipp_attributes->value_tag == IPP_TAG_INTEGER) {
> 	MyMaxJobs = ipp_attributes->values[0].integer;
> 	syslog (LOG_DEBUG, "Got MaxJobs (%d)", MyMaxJobs);
>       }
>
>       if (!strcmp(ipp_attributes->name, "cupsd-numjobs") &&
> 	  ipp_attributes->value_tag == IPP_TAG_INTEGER) {
> 	MyNumJobs = ipp_attributes->values[0].integer;
> 	syslog (LOG_DEBUG, "Got NumJobs (%d)", MyNumJobs);
>       }
>
>       ipp_attributes = ipp_attributes->next;
>     }
>   }
>
>   cupsLangFree (lang);
>
>   if (MyMaxJobs - MyNumJobs > 0) {
>     /* All is well, cupsd has space to receive the job, return 1 */
>     return 1;
>   } else {
>     return 0;
>   }
> }
>
> The server code, in scheduler/ipp.c is:
>
> /*
>  * 'get_maxjobs()' - Get the maximum number of jobs that the
>  * configuration says can be concurrently processed. This is the
>  * MaxJobs parameter in cupds.conf. We find it here in the global
>  * variable MaxJobs. Also return the number of jobs currently being
>  * processed by all queues.
>  */
>
> static void
> get_maxjobs(client_t *con)		/* I - Client connection */
> {
>   job_t *thisJob;
>   int jobCount = 0;
>
>   /* to be L_DEBUG2 */
>   LogMessage(L_DEBUG2, "get_maxjobs(%p[%d], %x)\n", con, con->http.fd, type);
>
>   /* Write MaxJobs global variable contents into cupsd-maxjobs attribute */
>   ippAddInteger(con->response, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER,
> 		"cupsd-maxjobs", MaxJobs);
>
>
>   /* Count all the jobs: */
>   for (thisJob = Jobs, jobCount = 0; thisJob != NULL; thisJob = thisJob->next) {
>     if (thisJob->state->values[0].integer <= IPP_JOB_PROCESSING) {
>       jobCount ++;
>     }
>   }
>   LogMessage (L_INFO, "%s: jobCount = %d", __FUNCTION__, jobCount);
>
>   /* And write jobCount into cupsd-numjobs attribute */
>   ippAddInteger(con->response, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER,
> 		"cupsd-numjobs", jobCount);
>
>   con->response->request.status.status_code = IPP_OK;
> }
>
> The code works in sending the MaxJobs number to the client, but my job counting code fails - it never counts any jobs.
>
> I copied the job count code from scheduler/job.c, GetPrinterJobCount() and just removed the test for destination, so that jobs for all destinations would be counted. (I did this after I tried just returning the global variable "NumJobs" which was always 0. Does anyone know why this doesn't have the value in it?)
>
> This must mean than the global list of jobs "Jobs" hasn't been initialised, but if I place the same counting loop in the function print_job() (also in scheduler/ipp.c) then it correctly counts the jobs when print_job() is called.
>
> I don't see why Jobs would be empty when I call my get_maxjobs() function in the scheduler - there's only one cupsd process. Looking at scheduler/job.c, the global list "Jobs" is added to when AddJob() is called and also when LoadAllJobs() is called when cupsd is started. Shouldn't "Jobs" always be accessible?
>

I've answered some of my questions and got closer to the problem:

I had been getting print_job() (with successful page counts) to run by sending my job to cupsd using lp.c. My page counting was failing when I had jobs spooling to cupsd via cups-lpd.c.

lp.c calls cupsPrintFile[s]() which calls cupsPrintFiles2(). This first sends an ipp request of either IPP_PRINT_JOB (if there is 1 file to print) or IPP_CREATE_JOB (if >1 file to print).

The IPP_PRINT_JOB request causes scheduler/ipp.c:print_job() to be called which calls job.c:AddJob() and hence updates the Jobs global. The IPP_CREATE_JOB request causes create_job() to be called in scheduler/ipp.c which calls job.c:AddJob() so this also updates the Jobs global.

However, cups-lpd.c also seems to send an IPP_PRINT_JOB request to print the file - from reading the code in the function print_file(). It should therefore also be causing the AddJob() function to be called in cupsd. But right now I can't see that happening...

Seb




More information about the cups-devel mailing list