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