/* Release memory from errlist, release semaphore */ void ReleaseErrorList(void){ pStrErrList el; if( err_sem_init ){ if( errlist && !LockSem(&err_sem) ){ while(errlist){ if(errlist->text) free(errlist->text); el = errlist; errlist=errlist->next; free(el); } ReleaseSem(&err_sem); } err_sem_init=0; CleanSem(&err_sem); } }
void rel_grow_handles(int nh) { LONG addfh=0; static ULONG curmaxfh=0; LockSem(&fhsem); if (curmaxfh == 0) { if (DosSetRelMaxFH(&addfh, &curmaxfh)) { Log(1, "Cannot DosSetRelMaxFH"); return; } } #ifdef __WATCOMC__ if ((addfh=_grow_handles((int)(curmaxfh += nh))) < curmaxfh) #else addfh=nh; if (DosSetRelMaxFH(&addfh, &curmaxfh)) #endif Log(1, "Cannot grow handles to %ld (now %ld): %s", curmaxfh, addfh, strerror(errno)); else Log(6, "Set MaxFH to %ld (res %ld)", curmaxfh, addfh); ReleaseSem(&fhsem); }
/* Return error message from errlist */ const char *errorfromlist(int err){ pStrErrList el, sel; const char *errmess=""; for( sel=el=errlist; el; el=el->next ) if( el->code==err ) return el->text; if(!err_sem_init){ err_sem_init=1; InitSem(&err_sem); } if( !LockSem(&err_sem) ){ if(sel!=errlist) /* List changed, check again */ for( el=errlist; el && (el!=sel); el=el->next ) if( el->code==err ){ errmess = el->text; goto skip_newerrortolist; } errmess = newerrortolist(err); skip_newerrortolist: ReleaseSem(&err_sem); } return errmess; }
int branch (register void (*F) (void *), register void *arg, register size_t size) { register int rc; char *tmp; /* We make our own copy of arg for the child as the parent may destroy it * before the child finish to use it. It's not really needed with fork() * but we do not want extra checks for HAVE_FORK before free(arg) in the * child. */ if (size > 0) { if ((tmp = malloc (size)) == NULL) { Log (1, "malloc failed"); return -1; } else { memcpy (tmp, arg, size); arg = tmp; } } else arg = 0; #if defined(HAVE_FORK) && !defined(HAVE_THREADS) && !defined(AMIGA) && !defined(DEBUGCHILD) again: if (!(rc = fork ())) { /* new process */ mypid = getpid(); F (arg); exit (0); } else if (rc < 0) { if (errno == EINTR) goto again; /* parent, error */ Log (1, "fork: %s", strerror (errno)); } else { /* parent, free our copy of args */ xfree (arg); } #endif #if defined(HAVE_THREADS) && !defined(DEBUGCHILD) #ifdef WITH_PTHREADS { thread_args_t args; pthread_t tid; args.F = F; args.args = arg; InitSem(&args.mutex); LockSem(&args.mutex); if ((rc = pthread_create (&tid, NULL, thread_start, &args)) != 0) { Log (1, "pthread_create: %s", strerror (rc)); rc = -1; } else { LockSem(&args.mutex); /* wait until thread releases this mutex */ #ifdef HAVE_GETTID rc = args.tid; #else rc = (int)(0xffff & (long int)tid); #endif } ReleaseSem(&args.mutex); CleanSem(&args.mutex); } #else if ((rc = BEGINTHREAD (F, STACKSIZE, arg)) < 0) Log (1, "_beginthread: %s", strerror (errno)); #endif #endif #ifdef AMIGA /* this is rather bizzare. this function pretends to be a fork and behaves * like one, but actually it's a kind of a thread. so we'll need semaphores */ if (!(rc = ix_vfork ())) { vfork_setup_child (); ix_vfork_resume (); F (arg); exit (0); } else if (rc < 0) { Log (1, "ix_vfork: %s", strerror (errno)); } #endif #if defined(DOS) || defined(DEBUGCHILD) rc = 0; F (arg); #endif return rc; }
/* * Run one client loop. Return -1 to exit */ static int do_client(BINKD_CONFIG *config) { FTN_NODE *r; int pid; if (!config->q_present) { q_free (SCAN_LISTED, config); if (config->printq) Log (-1, "scan\r"); q_scan (SCAN_LISTED, config); config->q_present = 1; if (config->printq) { LockSem (&lsem); q_list (stderr, SCAN_LISTED, config); ReleaseSem (&lsem); Log (-1, "idle\r"); } } if (n_clients < config->max_clients) { if ((r = q_next_node (config)) != 0) { struct call_args args; if (!bsy_test (&r->fa, F_BSY, config) || !bsy_test (&r->fa, F_CSY, config)) { char szDestAddr[FTN_ADDR_SZ + 1]; ftnaddress_to_str (szDestAddr, &r->fa); Log (4, "%s busy, skipping", szDestAddr); return 0; /* go to the next node */ } rel_grow_handles (6); threadsafe(++n_clients); lock_config_structure(config); args.node = r; args.config = config; if ((pid = branch (call, &args, sizeof (args))) < 0) { unlock_config_structure(config, 0); rel_grow_handles (-6); threadsafe(--n_clients); PostSem(&eothread); Log (1, "cannot branch out"); unblocksig(); SLEEP(1); blocksig(); check_child(&n_clients); } #if !defined(DEBUGCHILD) else { Log (5, "started client #%i, id=%i", n_clients, pid); #if defined(HAVE_FORK) && !defined(AMIGA) unlock_config_structure(config, 0); /* Forked child has own copy */ #endif } #endif } else { if (poll_flag) { if (n_clients <= 0 && q_not_empty (config) == 0) { Log (4, "the queue is empty, quitting..."); return -1; } } else config->q_present = 0; unblocksig(); SLEEP (config->rescan_delay); blocksig(); check_child(&n_clients); } } else { unblocksig(); SLEEP (config->call_delay); blocksig(); check_child(&n_clients); } return 0; }