1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 2001-2016. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  */
20 
21 /* to test multiple threads in ei */
22 
23 #include <stdlib.h>
24 #include <stdio.h>
25 
26 #ifdef __WIN32__
27 #include <winsock2.h>
28 #include <windows.h>
29 #include <process.h>
30 #else
31 #ifndef VXWORKS
32 #include <pthread.h>
33 #endif
34 #include <sys/socket.h>
35 #endif
36 
37 #include "ei.h"
38 #include "erl_interface.h"
39 
40 #ifdef VXWORKS
41 #define MAIN cnode
42 #else
43 #define MAIN main
44 #endif
45 
46 /*
47    A small einode.
48    To be called from the test case ei_accept_SUITE:multi_thread
49    usage: einode <cookie> <n> <destnode>
50 
51    - start threads 0..n-1
52    - in each thread
53       - connect to destnode
54       - send a message ("ei0".."ei<n-1>") to mth0..mth<n-1> on destnode
55       - shutdown gracefully
56 */
57 
58 static const char* cookie, * desthost;
59 
60 #ifndef SD_SEND
61 #ifdef SHUTWR
62 #define SD_SEND SHUT_WR
63 #else
64 #define SD_SEND 1
65 #endif
66 #endif
67 
68 #ifndef __WIN32__
69 #define closesocket(fd) close(fd)
70 #endif
71 
72 #ifdef __WIN32__
73 static DWORD WINAPI
74 #else
75 static void*
76 #endif
einode_thread(void * num)77     einode_thread(void* num)
78 {
79     int n = (int)num;
80     ei_cnode ec;
81     char myname[100], destname[100];
82     int r, fd;
83 
84     sprintf(myname, "ei%d", n);
85     sprintf(destname, "mth%d", n);
86     printf("thread %d (%s %s) connecting\n", n, myname, destname);
87     r = ei_connect_init(&ec, myname, cookie, 0);
88     fd = ei_connect(&ec, (char*)desthost);
89     if (r == 0 && fd >= 0) {
90 	ei_x_buff x;
91 	ei_x_new_with_version(&x);
92 	ei_x_encode_string(&x, myname);
93 	ei_reg_send(&ec, fd, destname, x.buff, x.index);
94 	ei_x_free(&x);
95 	//SleepEx(100);
96 	shutdown(fd, SD_SEND);
97 	closesocket(fd);
98     } else {
99 	printf("coudn't connect fd %d r %d\n", fd, r); //	DebugBreak();
100     }
101     printf("done thread %d\n", n);
102     return 0;
103 }
104 
MAIN(int argc,char * argv[])105 MAIN(int argc, char *argv[])
106 {
107     int i, n, no_threads;
108 #ifndef VXWORKS
109 #ifdef __WIN32__
110     HANDLE threads[100];
111 #else
112     pthread_t threads[100];
113 #endif
114 #endif
115 
116     if (argc < 3)
117 	exit(1);
118 
119     erl_init(NULL, 0);
120 
121     cookie = argv[1];
122     n = atoi(argv[2]);
123     if (n > 100)
124 	exit(2);
125     desthost = argv[3];
126 #ifndef VXWORKS
127     no_threads = argv[4] != NULL && strcmp(argv[4], "nothreads") == 0;
128 #else
129     no_threads = 1;
130 #endif
131     for (i = 0; i < n; ++i) {
132 	if (!no_threads) {
133 #ifndef VXWORKS
134 #ifdef __WIN32__
135 	    unsigned tid;
136 	    threads[i] = (HANDLE)_beginthreadex(NULL, 0, einode_thread,
137 						(void*)i, 0, &tid);
138 #else
139 	    pthread_create(&threads[i], NULL, einode_thread, (void*)i);
140 #endif
141 #else
142 	    ;
143 #endif
144 	} else
145 	    einode_thread((void*)i);
146     }
147     if (!no_threads)
148 #ifndef VXWORKS
149 	for (i = 0; i < n; ++i) {
150 #ifdef __WIN32__
151 	    if (WaitForSingleObject(threads[i], INFINITE) != WAIT_OBJECT_0)
152 #else
153 	    if (pthread_join(threads[i], NULL) != 0)
154 #endif
155 		printf("bad wait thread %d\n", i);
156 	}
157 #else
158 	    ;
159 #endif
160     printf("ok\n");
161     return 0;
162 }
163