1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
/*
* branch.c -- Create co-processes
*
* branch.c is a part of binkd project
*
* Copyright (C) 1996-1998 Dima Maloff, 5047/13
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. See COPYING.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "sys.h"
#include "common.h"
#include "tools.h"
#include "sem.h"
#ifdef AMIGA
int ix_vfork (void);
void vfork_setup_child (void);
void ix_vfork_resume (void);
#endif
#ifdef WITH_PTHREADS
typedef struct {
void (*F) (void *);
void *args;
MUTEXSEM mutex;
#ifdef HAVE_GETTID
pid_t tid;
#endif
} thread_args_t;
static void *thread_start(void *arg)
{
void (*F) (void*);
void *args;
F = ((thread_args_t *)arg)->F;
args = ((thread_args_t *)arg)->args;
#ifdef HAVE_GETTID
((thread_args_t *)arg)->tid = PID();
#endif
ReleaseSem(&((thread_args_t *)arg)->mutex);
pthread_detach(pthread_self());
F(args);
return NULL;
}
#endif
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;
}
|