Print this page
XXXX update sendmail to 8.14.9

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/sendmail/libmilter/worker.c
          +++ new/usr/src/cmd/sendmail/libmilter/worker.c
   1    1  /*
   2      - *  Copyright (c) 2003-2004, 2007, 2009 Sendmail, Inc. and its suppliers.
        2 + *  Copyright (c) 2003-2004, 2007, 2009-2012 Proofpoint, Inc. and its suppliers.
   3    3   *      All rights reserved.
   4    4   *
   5    5   * By using this file, you agree to the terms and conditions set
   6    6   * forth in the LICENSE file which can be found at the top level of
   7    7   * the sendmail distribution.
   8    8   *
   9    9   * Contributed by Jose Marcio Martins da Cruz - Ecole des Mines de Paris
  10   10   *   Jose-Marcio.Martins@ensmp.fr
  11   11   */
  12   12  
  13   13  #include <sm/gen.h>
  14      -SM_RCSID("@(#)$Id: worker.c,v 8.17 2009/06/15 15:34:54 ca Exp $")
       14 +SM_RCSID("@(#)$Id: worker.c,v 8.25 2013-11-22 20:51:37 ca Exp $")
  15   15  
  16   16  #include "libmilter.h"
  17   17  
  18   18  #if _FFR_WORKERS_POOL
  19   19  
  20   20  typedef struct taskmgr_S taskmgr_T;
  21   21  
  22   22  #define TM_SIGNATURE            0x23021957
  23   23  
  24   24  struct taskmgr_S
↓ open down ↓ 109 lines elided ↑ open up ↑
 134  134                  int r;                                                  \
 135  135                  sthread_t tid;                                          \
 136  136                                                                          \
 137  137                  if ((r = thread_create(&tid, mi_worker, ctx)) != 0)     \
 138  138                          smi_log(SMI_LOG_ERR, "LAUNCH_WORKER error: %s",\
 139  139                                  sm_errstring(r));                       \
 140  140          } while (0)
 141  141  
 142  142  #if POOL_DEBUG
 143  143  # define POOL_LEV_DPRINTF(lev, x)                                       \
 144      -        do {                                                            \
      144 +        do                                                              \
      145 +        {                                                               \
 145  146                  if ((lev) < ctx->ctx_dbg)                               \
 146  147                          sm_dprintf x;                                   \
 147  148          } while (0)
 148  149  #else /* POOL_DEBUG */
 149  150  # define POOL_LEV_DPRINTF(lev, x)
 150  151  #endif /* POOL_DEBUG */
 151  152  
 152  153  /*
 153  154  **  MI_START_SESSION -- Start a session in the pool of workers
 154  155  **
↓ open down ↓ 3 lines elided ↑ open up ↑
 158  159  **      Returns:
 159  160  **              MI_SUCCESS/MI_FAILURE
 160  161  */
 161  162  
 162  163  int
 163  164  mi_start_session(ctx)
 164  165          SMFICTX_PTR ctx;
 165  166  {
 166  167          static long id = 0;
 167  168  
 168      -        SM_ASSERT(Tskmgr.tm_signature == TM_SIGNATURE);
      169 +        /* this can happen if the milter is shutting down */
      170 +        if (Tskmgr.tm_signature != TM_SIGNATURE)
      171 +                return MI_FAILURE;
 169  172          SM_ASSERT(ctx != NULL);
 170  173          POOL_LEV_DPRINTF(4, ("PIPE r=[%d] w=[%d]", RD_PIPE, WR_PIPE));
 171  174          TASKMGR_LOCK();
 172  175  
 173  176          if (mi_list_add_ctx(ctx) != MI_SUCCESS)
 174  177          {
 175  178                  TASKMGR_UNLOCK();
 176  179                  return MI_FAILURE;
 177  180          }
 178  181  
↓ open down ↓ 30 lines elided ↑ open up ↑
 209  212  {
 210  213          SM_ASSERT(ctx != NULL);
 211  214  
 212  215          (void) mi_list_del_ctx(ctx);
 213  216          mi_clr_ctx(ctx);
 214  217  
 215  218          return MI_SUCCESS;
 216  219  }
 217  220  
 218  221  /*
      222 +**  NONBLOCKING -- set nonblocking mode for a file descriptor.
      223 +**
      224 +**      Parameters:
      225 +**              fd -- file descriptor
      226 +**              name -- name for (error) logging
      227 +**
      228 +**      Returns:
      229 +**              MI_SUCCESS/MI_FAILURE
      230 +*/
      231 +
      232 +static int
      233 +nonblocking(int fd, const char *name)
      234 +{
      235 +        int r;
      236 +
      237 +        errno = 0;
      238 +        r = fcntl(fd, F_GETFL, 0);
      239 +        if (r == -1)
      240 +        {
      241 +                smi_log(SMI_LOG_ERR, "fcntl(%s, F_GETFL)=%s",
      242 +                        name, sm_errstring(errno));
      243 +                return MI_FAILURE;
      244 +        }
      245 +        errno = 0;
      246 +        r = fcntl(fd, F_SETFL, r | O_NONBLOCK);
      247 +        if (r == -1)
      248 +        {
      249 +                smi_log(SMI_LOG_ERR, "fcntl(%s, F_SETFL, O_NONBLOCK)=%s",
      250 +                        name, sm_errstring(errno));
      251 +                return MI_FAILURE;
      252 +        }
      253 +        return MI_SUCCESS;
      254 +}
      255 +
      256 +/*
 219  257  **  MI_POOL_CONTROLER_INIT -- Launch the worker pool controller
 220  258  **              Must be called before starting sessions.
 221  259  **
 222  260  **      Parameters:
 223  261  **              none
 224  262  **
 225  263  **      Returns:
 226  264  **              MI_SUCCESS/MI_FAILURE
 227  265  */
 228  266  
↓ open down ↓ 10 lines elided ↑ open up ↑
 239  277          Tskmgr.tm_tid = (sthread_t) -1;
 240  278          Tskmgr.tm_nb_workers = 0;
 241  279          Tskmgr.tm_nb_idle = 0;
 242  280  
 243  281          if (pipe(Tskmgr.tm_p) != 0)
 244  282          {
 245  283                  smi_log(SMI_LOG_ERR, "can't create event pipe: %s",
 246  284                          sm_errstring(errno));
 247  285                  return MI_FAILURE;
 248  286          }
      287 +        r = nonblocking(WR_PIPE, "WR_PIPE");
      288 +        if (r != MI_SUCCESS)
      289 +                return r;
      290 +        r = nonblocking(RD_PIPE, "RD_PIPE");
      291 +        if (r != MI_SUCCESS)
      292 +                return r;
 249  293  
 250  294          (void) smutex_init(&Tskmgr.tm_w_mutex);
 251  295          (void) scond_init(&Tskmgr.tm_w_cond);
 252  296  
 253  297          /* Launch the pool controller */
 254  298          if ((r = thread_create(&tid, mi_pool_controller, (void *) NULL)) != 0)
 255  299          {
 256  300                  smi_log(SMI_LOG_ERR, "can't create controller thread: %s",
 257  301                          sm_errstring(r));
 258  302                  return MI_FAILURE;
↓ open down ↓ 68 lines elided ↑ open up ↑
 327  371                  smi_log(SMI_LOG_ERR, "Failed to malloc pollfd array: %s",
 328  372                          sm_errstring(errno));
 329  373                  return NULL;
 330  374          }
 331  375          dim_pfd = PFD_STEP;
 332  376  
 333  377          lastcheck = time(NULL);
 334  378          for (;;)
 335  379          {
 336  380                  SMFICTX_PTR ctx;
 337      -                int nfd, rfd, i;
      381 +                int nfd, r, i;
 338  382                  time_t now;
 339  383  
 340  384                  POOL_LEV_DPRINTF(4, ("Let's %s again...", WAITFN));
 341  385  
 342  386                  if (mi_stop() != MILTER_CONT)
 343  387                          break;
 344  388  
 345  389                  TASKMGR_LOCK();
 346  390  
 347  391                  now = time(NULL);
↓ open down ↓ 100 lines elided ↑ open up ↑
 448  492                                                  nfd++;
 449  493                                          }
 450  494                                  }
 451  495                          }
 452  496                          rebuild_set = false;
 453  497                  }
 454  498  
 455  499                  TASKMGR_UNLOCK();
 456  500  
 457  501                  /* Everything is ready, let's wait for an event */
 458      -                rfd = poll(pfd, nfd, POLL_TIMEOUT);
      502 +                r = poll(pfd, nfd, POLL_TIMEOUT);
 459  503  
 460  504                  POOL_LEV_DPRINTF(4, ("%s returned: at epoch %d value %d",
 461  505                          WAITFN, now, nfd));
 462  506  
 463  507                  /* timeout */
 464      -                if (rfd == 0)
      508 +                if (r == 0)
 465  509                          continue;
 466  510  
 467  511                  rebuild_set = true;
 468  512  
 469  513                  /* error */
 470      -                if (rfd < 0)
      514 +                if (r < 0)
 471  515                  {
 472  516                          if (errno == EINTR)
 473  517                                  continue;
 474  518                          pcnt++;
 475  519                          smi_log(SMI_LOG_ERR,
 476  520                                  "%s() failed (%s), %s",
 477  521                                  WAITFN, sm_errstring(errno),
 478  522                                  pcnt >= MAX_FAILS_S ? "abort" : "try again");
 479  523  
 480  524                          if (pcnt >= MAX_FAILS_S)
 481  525                                  goto err;
      526 +                        continue;
 482  527                  }
 483  528                  pcnt = 0;
 484  529  
 485  530                  /* something happened */
 486  531                  for (i = 0; i < nfd; i++)
 487  532                  {
 488  533                          if (pfd[i].revents == 0)
 489  534                                  continue;
 490  535  
 491  536                          POOL_LEV_DPRINTF(4, ("%s event on pfd[%d/%d]=%d ",
 492  537                                  WAITFN, i, nfd,
 493  538                          WAIT_FD(i)));
 494  539  
 495      -                        /* has a worker signaled an end of task ? */
      540 +                        /* has a worker signaled an end of task? */
 496  541                          if (WAIT_FD(i) == RD_PIPE)
 497  542                          {
 498      -                                char evt = 0;
 499      -                                int r = 0;
      543 +                                char evts[256];
      544 +                                ssize_t r;
 500  545  
 501  546                                  POOL_LEV_DPRINTF(4,
 502  547                                          ("PIPE WILL READ evt = %08X %08X",
 503  548                                          pfd[i].events, pfd[i].revents));
 504  549  
 505      -                                if ((pfd[i].revents & MI_POLL_RD_FLAGS) != 0)
      550 +                                r = 1;
      551 +                                while ((pfd[i].revents & MI_POLL_RD_FLAGS) != 0
      552 +                                        && r != -1)
 506  553                                  {
 507      -                                        r = read(RD_PIPE, &evt, sizeof(evt));
 508      -                                        if (r == sizeof(evt))
 509      -                                        {
 510      -                                                /* Do nothing */
 511      -                                        }
      554 +                                        r = read(RD_PIPE, evts, sizeof(evts));
 512  555                                  }
 513  556  
 514  557                                  POOL_LEV_DPRINTF(4,
 515  558                                          ("PIPE DONE READ i=[%d] fd=[%d] r=[%d] evt=[%d]",
 516      -                                        i, RD_PIPE, r, evt));
      559 +                                        i, RD_PIPE, (int) r, evts[0]));
 517  560  
 518  561                                  if ((pfd[i].revents & ~MI_POLL_RD_FLAGS) != 0)
 519  562                                  {
 520  563                                          /* Exception handling */
 521  564                                  }
 522  565                                  continue;
 523  566                          }
 524  567  
 525      -                        /* no ! sendmail wants to send a command */
      568 +                        /*
      569 +                        **  Not the pipe for workers waking us,
      570 +                        **  so must be something on an MTA connection.
      571 +                        */
      572 +
      573 +                        TASKMGR_LOCK();
 526  574                          SM_TAILQ_FOREACH(ctx, &WRK_CTX_HEAD, ctx_link)
 527  575                          {
 528  576                                  if (ctx->ctx_wstate != WKST_WAITING)
 529  577                                          continue;
 530  578  
 531  579                                  POOL_LEV_DPRINTF(4,
 532  580                                          ("Checking context sd=%d - fd=%d ",
 533  581                                          ctx->ctx_sd , WAIT_FD(i)));
 534  582  
 535  583                                  if (ctx->ctx_sd == pfd[i].fd)
 536  584                                  {
 537      -                                        TASKMGR_LOCK();
 538  585  
 539  586                                          POOL_LEV_DPRINTF(4,
 540  587                                                  ("TASK: found %d for fd[%d]=%d",
 541  588                                                  ctx->ctx_sid, i, WAIT_FD(i)));
 542  589  
 543  590                                          if (Tskmgr.tm_nb_idle > 0)
 544  591                                          {
 545  592                                                  ctx->ctx_wstate = WKST_READY_TO_RUN;
 546  593                                                  TASKMGR_COND_SIGNAL();
 547  594                                          }
 548  595                                          else
 549  596                                          {
 550  597                                                  ctx->ctx_wstate = WKST_RUNNING;
 551  598                                                  LAUNCH_WORKER(ctx);
 552  599                                          }
 553      -                                        TASKMGR_UNLOCK();
 554  600                                          break;
 555  601                                  }
 556  602                          }
      603 +                        TASKMGR_UNLOCK();
 557  604  
 558  605                          POOL_LEV_DPRINTF(4,
 559  606                                  ("TASK %s FOUND - Checking PIPE for fd[%d]",
 560  607                                  ctx != NULL ? "" : "NOT", WAIT_FD(i)));
 561  608                  }
 562  609          }
 563  610  
 564  611    err:
 565  612          if (pfd != NULL)
 566  613                  free(pfd);
 567  614  
 568  615          Tskmgr.tm_signature = 0;
      616 +#if 0
      617 +        /*
      618 +        **  Do not clean up ctx -- it can cause double-free()s.
      619 +        **  The program is shutting down anyway, so it's not worth the trouble.
      620 +        **  There is a more complex solution that prevents race conditions
      621 +        **  while accessing ctx, but that's maybe for a later version.
      622 +        */
      623 +
 569  624          for (;;)
 570  625          {
 571  626                  SMFICTX_PTR ctx;
 572  627  
 573  628                  ctx = SM_TAILQ_FIRST(&WRK_CTX_HEAD);
 574  629                  if (ctx == NULL)
 575  630                          break;
 576  631                  mi_close_session(ctx);
 577  632          }
      633 +#endif
 578  634  
 579  635          (void) smutex_destroy(&Tskmgr.tm_w_mutex);
 580  636          (void) scond_destroy(&Tskmgr.tm_w_cond);
 581  637  
 582  638          return NULL;
 583  639  }
 584  640  
 585  641  /*
 586  642  **  Look for a task ready to run.
 587  643  **  Value of ctx is NULL or a pointer to a task ready to run.
↓ open down ↓ 188 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX