1 2#ifdef OS2 3#define INCL_DOSPROCESS 4#else 5#include <unistd.h> 6#include <time.h> 7#include <stdlib.h> 8#include <sys/types.h> 9#include <sys/wait.h> 10#endif 11 12#include "forkit.h" 13 14 15Fork::Fork() 16 : m_read(-1) 17 , m_write(-1) 18 , m_numThreads(0) 19{ 20} 21 22#ifdef OS2 23// for the benefit of this function and the new Fork class it may create 24// the Fork class must do nothing of note in it's constructor or it's 25// go() member function. 26VOID APIENTRY thread_func(ULONG param) 27{ 28 THREAD_DATA *td = (THREAD_DATA *)param; 29 td->f = new Fork; 30 td->f->startit(td); 31} 32#endif 33 34void Fork::startit(THREAD_DATA *td) 35{ 36 m_read = td->child_read; 37 m_write = td->child_write; 38 td->func(this, td->param, td->threadNum); 39 delete td->f; // delete ourself if td->f is not NULL 40 delete td; 41 exit(0); 42} 43 44void Fork::go(FUNCTION func, PVOID param, int num) 45{ 46 m_numThreads = num; 47 FILE_TYPE control[2]; 48 FILE_TYPE feedback[2]; 49 if (pipe(feedback) || pipe(control)) 50 { 51 fprintf(stderr, "Can't open pipes.\n"); 52 exit(1); 53 } 54#ifndef OS2 55 m_readPoll.events = POLLIN | POLLERR | POLLHUP | POLLNVAL; 56 m_writePoll.events = POLLOUT | POLLERR | POLLHUP | POLLNVAL; 57#endif 58 59 THREAD_DATA *td = new THREAD_DATA; 60 td->child_read = control[0]; 61 td->child_write = feedback[1]; 62 td->f = NULL; 63 td->param = param; 64 td->func = func; 65 for(int i = 0; i < num; i++) 66 { 67#ifdef OS2 68 THREAD_DATA *tmp = new THREAD_DATA; 69 memcpy(tmp, td, sizeof(THREAD_DATA)); 70#endif 71 td->threadNum = i; 72#ifdef OS2 73 // yes I know I am casting a pointer to an unsigned long 74 // it's the way you're supposed to do things in OS/2 75 TID id = 0; 76 if(DosCreateThread(&id, thread_func, ULONG(td), CREATE_READY, 32*1024)) 77 { 78 fprintf(stderr, "Can't create a thread.\n"); 79 exit(1); 80 } 81#else 82 int p = fork(); 83 if(p == -1) 84 { 85 fprintf(stderr, "Can't fork.\n"); 86 exit(1); 87 } 88 if(p == 0) // child 89 { 90 m_readPoll.fd = td->child_read; 91 m_writePoll.fd = td->child_write; 92 file_close(control[1]); 93 file_close(feedback[0]); 94 srand(getpid() ^ time(NULL)); 95 startit(td); 96 } 97#endif 98 } 99 // now we're in the parent thread/process 100 m_write = control[1]; 101 m_read = feedback[0]; 102#ifndef OS2 103 m_readPoll.fd = m_read; 104 m_writePoll.fd = m_write; 105 file_close(control[0]); 106 file_close(feedback[1]); 107#endif 108} 109 110int Fork::wait() 111{ 112#ifdef OS2 113 TID status = 0; 114 if(DosWaitThread(&status, DCWW_WAIT)) 115 { 116 fprintf(stderr, "Can't wait for thread.\n"); 117 return 1; 118 } 119#else 120 int status = 0; 121 if(::wait(&status) == -1) 122 { 123 fprintf(stderr, "Can't wait for thread.\n"); 124 return 1; 125 } 126#endif 127 return 0; 128} 129 130int Fork::Read(PVOID buf, int size, int timeout) 131{ 132#ifndef OS2 133 if(timeout) 134 { 135 int rc = poll(&m_readPoll, 1, timeout * 1000); 136 if(rc < 0) 137 { 138 fprintf(stderr, "Can't poll.\n"); 139 return -1; 140 } 141 if(!rc) 142 return 0; 143 } 144#endif 145#ifdef OS2 146 unsigned long actual; 147 int rc = DosRead(m_read, buf, size, &actual); 148 if(rc || actual != size) 149#else 150 if(size != read(m_read, buf, size) ) 151#endif 152 { 153 fprintf(stderr, "Can't read data from IPC pipe.\n"); 154 return -1; 155 } 156 return size; 157} 158 159int Fork::Write(PVOID buf, int size, int timeout) 160{ 161#ifndef OS2 162 if(timeout) 163 { 164 int rc = poll(&m_writePoll, 1, timeout * 1000); 165 if(rc < 0) 166 { 167 fprintf(stderr, "Can't poll for write.\n"); 168 return -1; 169 } 170 if(!rc) 171 return 0; 172 } 173#endif 174#ifdef OS2 175 unsigned long actual; 176 int rc = DosWrite(m_write, buf, size, &actual); 177 if(rc || actual != size) 178#else 179 if(size != write(m_write, buf, size)) 180#endif 181 { 182 fprintf(stderr, "Can't write data to IPC pipe.\n"); 183 return -1; 184 } 185 return size; 186} 187 188