fork() and progress bar...



I've got a situation where I need to load information
from a MySQL db and on the screen continuously update
a progress bar. What I'd like to do is while the
db is fetching the information, show a little progress
bar that just goes back and forth. When that finishes,
change to a 1-100% Progress for each fetched item
that is processed. Then, make the progress bar 0%
and say that it is waiting.

I figured the only way to do this is to fork() off
a process and use one to fetch mysql information
and the other one to update the widget. However,
there is a problem. You're not supposed to modify
any widgets while in the child process, but I can't
do the mysql query in the child process because
the rest of my program and the parent process needs
that information and fork() makes a copy of memory
rather than sharing it.

What happening is that it works great while the
child process is running and mysql is fetching
info. As soon as mysql stops fetching from the
database, it kills the child process with
kill(pid, SIGUSR1); The child process exits
with _exit(0); and the parent continues. As soon
as the parent tries to update the progress
bar, the program crashes with:

Gdk-ERROR **: BadPixmap (invalid Pixmap parameter)
  serial 3574 error_code 4 request_code 54 minor_code 0

I'm assuming this is because I used the widget in
my child process and now that my parent is trying
to use it again, it's becoming very unhappy. If I
comment out all references in the parent after the
fork() to update the widget, then it works great.
Below are the functions I'm using to do this.

I'd really appreciate some advice because I would
like to do this, but it seems like the child process
isn't allowed to do either task. I really don't
care which one does which as long as it works. I
first started out doing the query in the child
process, but found out that the results weren't
being passed back because of the whole non-shared
memory thing.

The entire output I get from my program is:

query string is SELECT DISTINCT status,description,time_spent,est_ttc,
priority,scope,owner,filer,reporter,repname,repphone,category,subcategory,
tickets.ctime,close_time,mtime,est_doc,UNIX_TIMESTAMP(tickets.ctime),
mailto,csa FROM tickets,notes WHERE tickets.ctime=notes.ctime
AND status='cancelled'  AND tickets.ctime < 20010906235959  AND
tickets.ctime > 20000906000000

BEGIN
END
BEGIN
Exiting!
data load got 157 rows
Gdk-ERROR **: BadPixmap (invalid Pixmap parameter)
  serial 3574 error_code 4 request_code 54 minor_code 0

Anyway, below is my code. Thanks for any help
you can provide.

Jeff Shipman           E-Mail: jeff nmt edu
Systems Programmer     Phone: (505) 835-5748
NMIMT Computer Center  http://www.nmt.edu/~jeff

-- CODE SNIPPET BEGINS
GtkWidget *query_progressbar()
{
   return appProgressBar;
}

void set_progressbar_value(gfloat val)
{
   gtk_progress_bar_update(GTK_PROGRESS_BAR(appProgressBar), val);
   while(gtk_events_pending()) gtk_main_iteration();
}

void set_progressbar_text(gchar *text)
{
   gtk_progress_set_format_string(GTK_PROGRESS(appProgressBar), text);
   while(gtk_events_pending()) gtk_main_iteration();
}

void kill_child()
{
printf("Exiting!\n");
   _exit(0);
}

int sql_load(char *newest, char *oldest, char *status, char *searchString, char *timeStamp) {
  int testval;
  int numloaded;
  pid_t pid;
  gfloat newval;
  MYSQL_RES *pMysql_res;
  MYSQL_ROW pMysql_row;
	char *escapedSearchString;
  char qBuffer[1024 + strlen(query_exclude_string())];
  char base_query[] =
    "SELECT DISTINCT status,description,time_spent,est_ttc,priority,"
    "scope,owner,filer,reporter,repname,repphone,category,"
    "subcategory,tickets.ctime,close_time,mtime,est_doc,"
		"UNIX_TIMESTAMP(tickets.ctime),mailto,csa FROM tickets,notes "
		"WHERE tickets.ctime=notes.ctime ";
  char status_condition[] =
    " AND status='%s' ";
  char sooner_than_condition[] =
    " AND tickets.ctime < %s ";
  char later_than_condition[] =
    " AND tickets.ctime > %s ";
  char nsearch_condition[] =
		" AND notes.notes LIKE '%%%s%%' ";
  char tsearch_condition[] =
      " AND tickets.ctime LIKE '%%%s%%' ";
  char user_condition[] =
      " AND scope='external'";
  my_ulonglong numRows;
  dataCoreNode node;

  server_check();
  /* form base of query */
  strcpy(qBuffer, base_query);


  if (status != NULL)
    sprintf(qBuffer + strlen(qBuffer), status_condition, status);

  if (newest != NULL)
    sprintf(qBuffer + strlen(qBuffer), sooner_than_condition, newest);

  if (oldest != NULL)
    sprintf(qBuffer + strlen(qBuffer), later_than_condition, oldest);

	if (searchString != NULL) {
		escapedSearchString = malloc( (strlen(searchString) * 2) +1);
		assert(escapedSearchString != NULL);
		mysql_escape_string(escapedSearchString, searchString,strlen(searchString));
		assert( (strlen(qBuffer) + strlen(escapedSearchString)) < 950);
		sprintf(qBuffer + strlen(qBuffer), nsearch_condition, escapedSearchString);
		free (escapedSearchString);
	}
  if (timeStamp != NULL) {
     escapedSearchString = malloc( (strlen(timeStamp) * 2) +1);
     assert(escapedSearchString != NULL);
     mysql_escape_string(escapedSearchString, timeStamp,strlen(timeStamp));
     assert( (strlen(qBuffer) + strlen(escapedSearchString)) < 950);
     sprintf(qBuffer + strlen(qBuffer), tsearch_condition, escapedSearchString);
     free(escapedSearchString);
  }
  if(!permissions_is_worker())
  {
     sprintf(qBuffer + strlen(qBuffer), user_condition);
  }

  if(strlen(query_exclude_string()))
  {
     sprintf(qBuffer + strlen(qBuffer), query_exclude_string());
  }

  DPRINT2("query string is %s\n\n", qBuffer);

   /* Now to load the results and do the spiffy progress bar thing. */
   if((pid = fork()) < 0) /* fork a new process */
   {
      fprintf(stderr, "Error: could not fork process.\n"
              "Reason: %s\n", strerror(errno));
      mysql_close(&mysql);
      exit(0);
   }
   else if(pid == 0) /* child */
   {
      gfloat i;

      signal(SIGUSR1, kill_child);

      while(1)
      {
      printf("BEGIN\n");
         set_progressbar_text("Fetching...");
         for(i=0.0;i<=100.0;i+=5)
         {
            set_progressbar_value(i/100);
            usleep(5);
         }
         gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(query_progressbar()),
                                          GTK_PROGRESS_RIGHT_TO_LEFT);
         for(i=100.0;i>=0.0;i-=5)
         {
            set_progressbar_value(i/100);
            usleep(5);
         }
         for(i=0.0;i<=100.0;i+=5)
         {
            set_progressbar_value(i/100);
            usleep(5);
         }
         gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(query_progressbar()),
                                          GTK_PROGRESS_LEFT_TO_RIGHT);
         for(i=100.0;i>=0.0;i-=5)
         {
            set_progressbar_value(i/100);
            usleep(5);
         }
      printf("END\n");
      }
   }
   else /* parent */
   {
      if (mysql_query(&mysql, qBuffer )) {
         fprintf(stderr,  "query failed: Error %s\n", mysql_error(&mysql));
         mysql_close(&mysql);
         exit(0);
      }
      kill(pid, SIGUSR1); /* Tell the child to stop */

      pMysql_res = mysql_store_result(&mysql);
      if (pMysql_res == NULL) {
         fprintf(stderr,  "store result failed: Error %s\n", mysql_error(&mysql));
         mysql_close(&mysql);
         exit(0);
      }
      numRows = mysql_num_rows(pMysql_res);
      DPRINT2("data load got %lu rows\n", (unsigned long) numRows);

      /* don't flame out if no tickets are found */
      if (! numRows) {
         datacore_init(1);
         memset( (void *)&node, 0, sizeof(dataCoreNode));
         strncpy(node.description, "no tickets within range/type", MAX_DESC);
         datacore_insert(&node);
         mysql_free_result(pMysql_res);
         pMysql_res = NULL;
         return 1;
      }

      numloaded = 0;
      set_progressbar_text("Processing... %p%%");
      set_progressbar_value(0.0);

      datacore_init(numRows);
      pMysql_row = mysql_fetch_row(pMysql_res);
      while (pMysql_row != NULL) {
         if(pMysql_row[0])
            strncpy(node.status, pMysql_row[0], MAX_STATUS);
         else
            strcpy(node.status, "active");
         if(pMysql_row[1])
            strncpy(node.description, pMysql_row[1], MAX_DESC);
         else
            strcpy(node.description, "No description available.");
         if(pMysql_row[2])
            node.timeSpent = (float) atof(pMysql_row[2]);
         else
            node.timeSpent=0.0;
         if(pMysql_row[3])
            node.estTTC = (float) atof(pMysql_row[3]);
         else
            node.estTTC = 1.5;

         if(pMysql_row[4])
            node.priority = (unsigned char) atoi(pMysql_row[4]);
         else
            node.priority = 3;

         if(pMysql_row[5])
            node.is_internal = (strcmp(pMysql_row[5], "internal") == 0) ? 1 : 0;
         else
            node.is_internal = 0;

         if(pMysql_row[6])
            strncpy(node.owner, pMysql_row[6], MAX_USERNAME);
         else
            strcpy(node.owner, "unassigned");
         if(pMysql_row[7])
            strncpy(node.filer, pMysql_row[7], MAX_FILERNAME);
         else
            strcpy(node.filer, "N/A");
         if(pMysql_row[8])
            strncpy(node.reporter, pMysql_row[8], MAX_REPORTERNAME);
         else
            strcpy(node.reporter, "N/A");
         if(pMysql_row[9])
            strncpy(node.repname, pMysql_row[9], MAX_REPORTERNAME);
         else
            strcpy(node.repname, "N/A");
         if(pMysql_row[10])
            strncpy(node.repphone, pMysql_row[10], MAX_PHONE);
         else
            strcpy(node.repphone, "N/A");
         if(pMysql_row[11])
            strncpy(node.category, pMysql_row[11], MAX_CATEGORY);
         else
            strcpy(node.category, "other");
         if(pMysql_row[12])
            strncpy(node.subcategory, pMysql_row[12], MAX_CATEGORY);
         else
            strcpy(node.subcategory, "other");
         if(pMysql_row[13])
            strncpy(node.createStamp, pMysql_row[13], STAMP_LENGTH);
         else
            strcpy(node.createStamp, "00000000000000");
         if(pMysql_row[14])
            strncpy(node.closeStamp, pMysql_row[14], STAMP_LENGTH);
         else
            strcpy(node.closeStamp, "00000000000000");
         if(pMysql_row[15])
            strncpy(node.modStamp, pMysql_row[15], STAMP_LENGTH);
         else
            strcpy(node.modStamp, "00000000000000");
         if(pMysql_row[16])
            strncpy(node.estDOC, pMysql_row[16], STAMP_LENGTH);
         else
            strcpy(node.estDOC, "00000000000000");
         if(pMysql_row[17])
            node.unixStamp = atoi(pMysql_row[17]);
         else
            node.unixStamp = 0;

         if(pMysql_row[18])
            strncpy(node.emailto, pMysql_row[18], MAX_EMAIL_LIST);
         else
            node.emailto[0]='\0';
         if(pMysql_row[19])
            strncpy(node.csa, pMysql_row[19], MAX_CSA);
         else
            strncpy(node.csa, "100", MAX_CSA);
         node.flagged = 0;
         /* Set unread stuffs */
         testval = trt_check(node.createStamp, node.modStamp);
         switch (testval) {
            case TRT_READ:
               node.unread = 0;
               break;
            case TRT_NEW:
               node.unread = 2;
               break;
            case TRT_UPDATED:
               node.unread = 1;
               break;
            default:
               DPRINT3("Unhandled switch in %s, line %d",__FILE__, __LINE__);
         }
         datacore_insert(&node);
         pMysql_row = mysql_fetch_row(pMysql_res);
         newval = (gfloat)(++numloaded)/(gfloat)numRows;
         set_progressbar_value(newval);
      }

      set_progressbar_value(0.0);
      set_progressbar_text("Waiting");

      mysql_free_result(pMysql_res);
      pMysql_res = NULL;
   }
   return (int) numRows;
}





[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]