win32.cc: (_Jv_pipe) Implemented.
[gcc.git] / libjava / win32.cc
1 // win32.cc - Helper functions for Microsoft-flavored OSs.
2
3 /* Copyright (C) 2002, 2003 Free Software Foundation
4
5 This file is part of libgcj.
6
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9 details. */
10
11 #include <config.h>
12 #include <platform.h>
13 #include <sys/timeb.h>
14 #include <stdlib.h>
15 #include <fcntl.h>
16
17 #include <java/lang/ArithmeticException.h>
18 #include <java/lang/UnsupportedOperationException.h>
19 #include <java/io/IOException.h>
20 #include <java/net/SocketException.h>
21 #include <java/util/Properties.h>
22
23 static LONG CALLBACK
24 win32_exception_handler (LPEXCEPTION_POINTERS e)
25 {
26 if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
27 _Jv_ThrowNullPointerException();
28 else if (e->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO)
29 throw new java::lang::ArithmeticException;
30 else
31 return EXCEPTION_CONTINUE_SEARCH;
32 }
33
34 // Platform-specific executable name
35 static char exec_name[MAX_PATH];
36 // initialized in _Jv_platform_initialize()
37
38 const char *_Jv_ThisExecutable (void)
39 {
40 return exec_name;
41 }
42
43 // Helper classes and methods implementation
44
45 // class WSAEventWrapper
46 WSAEventWrapper::WSAEventWrapper (int fd, DWORD dwSelFlags):
47 m_hEvent(0),
48 m_fd(fd),
49 m_dwSelFlags(dwSelFlags)
50 {
51 m_hEvent = WSACreateEvent ();
52 if (dwSelFlags)
53 WSAEventSelect(fd, m_hEvent, dwSelFlags);
54 }
55
56 WSAEventWrapper::~WSAEventWrapper ()
57 {
58 if (m_dwSelFlags)
59 {
60 WSAEventSelect(m_fd, m_hEvent, 0);
61 if (m_dwSelFlags & (FD_ACCEPT | FD_CONNECT))
62 {
63 // Set the socket back to non-blocking mode.
64 // Ignore any error since we're in a destructor.
65 unsigned long lSockOpt = 0L;
66 // blocking mode
67 ::ioctlsocket (m_fd, FIONBIO, &lSockOpt);
68 }
69 }
70 WSACloseEvent (m_hEvent);
71 }
72
73 // Error string text.
74 jstring
75 _Jv_WinStrError (LPCTSTR lpszPrologue, int nErrorCode)
76 {
77 LPTSTR lpMsgBuf = 0;
78
79 DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
80 FORMAT_MESSAGE_FROM_SYSTEM |
81 FORMAT_MESSAGE_IGNORE_INSERTS;
82
83 FormatMessage (dwFlags,
84 NULL,
85 (DWORD) nErrorCode,
86 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
87 (LPTSTR) &lpMsgBuf,
88 0,
89 NULL);
90
91 jstring ret;
92 if (lpszPrologue)
93 {
94 LPTSTR lpszTemp =
95 (LPTSTR) _Jv_Malloc (strlen (lpszPrologue) +
96 strlen (lpMsgBuf) + 3);
97 strcpy (lpszTemp, lpszPrologue);
98 strcat (lpszTemp, ": ");
99 strcat (lpszTemp, lpMsgBuf);
100 ret = JvNewStringLatin1 (lpszTemp);
101 }
102 else
103 {
104 ret = JvNewStringLatin1 (lpMsgBuf);
105 }
106
107 LocalFree(lpMsgBuf);
108 return ret;
109 }
110
111 jstring
112 _Jv_WinStrError (int nErrorCode)
113 {
114 return _Jv_WinStrError (0, nErrorCode);
115 }
116
117 void _Jv_ThrowIOException (DWORD dwErrorCode)
118 {
119 throw new java::io::IOException (_Jv_WinStrError (dwErrorCode));
120 }
121
122 void _Jv_ThrowIOException()
123 {
124 DWORD dwErrorCode = WSAGetLastError ();
125 _Jv_ThrowIOException (dwErrorCode);
126 }
127
128 void _Jv_ThrowSocketException (DWORD dwErrorCode)
129 {
130 throw new java::net::SocketException (_Jv_WinStrError (dwErrorCode));
131 }
132
133 void _Jv_ThrowSocketException()
134 {
135 DWORD dwErrorCode = WSAGetLastError ();
136 _Jv_ThrowSocketException (dwErrorCode);
137 }
138
139 // Platform-specific VM initialization.
140 void
141 _Jv_platform_initialize (void)
142 {
143 // Initialise winsock for networking
144 WSADATA data;
145 if (WSAStartup (MAKEWORD (1, 1), &data))
146 MessageBox (NULL, "Error initialising winsock library.", "Error",
147 MB_OK | MB_ICONEXCLAMATION);
148
149 // Install exception handler
150 SetUnhandledExceptionFilter (win32_exception_handler);
151
152 // Initialize our executable name
153 GetModuleFileName(NULL, exec_name, sizeof(exec_name));
154 }
155
156 // gettimeofday implementation.
157 jlong
158 _Jv_platform_gettimeofday ()
159 {
160 struct timeb t;
161 ftime (&t);
162 return t.time * 1000LL + t.millitm;
163 }
164
165 // The following definitions "fake out" mingw to think that -mthreads
166 // was enabled and that mingwthr.dll was linked. GCJ-compiled
167 // applications don't need this helper library because we can safely
168 // detect thread death (return from Thread.run()).
169
170 int _CRT_MT = 1;
171
172 extern "C" int
173 __mingwthr_key_dtor (DWORD, void (*) (void *))
174 {
175 // FIXME: for now we do nothing; this causes a memory leak of
176 // approximately 24 bytes per thread created.
177 return 0;
178 }
179
180 // Set platform-specific System properties.
181 void
182 _Jv_platform_initProperties (java::util::Properties* newprops)
183 {
184 // A convenience define.
185 #define SET(Prop,Val) \
186 newprops->put(JvNewStringLatin1 (Prop), JvNewStringLatin1 (Val))
187
188 SET ("file.separator", "\\");
189 SET ("path.separator", ";");
190 SET ("line.separator", "\r\n");
191
192 // Use GetCurrentDirectory to set 'user.dir'.
193 DWORD buflen = MAX_PATH;
194 char *buffer = (char *) _Jv_MallocUnchecked (buflen);
195 if (buffer != NULL)
196 {
197 if (GetCurrentDirectory (buflen, buffer))
198 SET ("user.dir", buffer);
199
200 if (GetTempPath (buflen, buffer))
201 SET ("java.io.tmpdir", buffer);
202
203 _Jv_Free (buffer);
204 }
205
206 // Use GetUserName to set 'user.name'.
207 buflen = 257; // UNLEN + 1
208 buffer = (char *) _Jv_MallocUnchecked (buflen);
209 if (buffer != NULL)
210 {
211 if (GetUserName (buffer, &buflen))
212 SET ("user.name", buffer);
213 _Jv_Free (buffer);
214 }
215
216 // According to the api documentation for 'GetWindowsDirectory()', the
217 // environmental variable HOMEPATH always specifies the user's home
218 // directory or a default directory. On the 3 windows machines I checked
219 // only 1 had it set. If it's not set, JDK1.3.1 seems to set it to
220 // the windows directory, so we'll do the same.
221 char *userHome = NULL;
222 if ((userHome = ::getenv ("HOMEPATH")) == NULL )
223 {
224 // Check HOME since it's what I use.
225 if ((userHome = ::getenv ("HOME")) == NULL )
226 {
227 // Not found - use the windows directory like JDK1.3.1 does.
228 char *winHome = (char *) _Jv_MallocUnchecked (MAX_PATH);
229 if (winHome != NULL)
230 {
231 if (GetWindowsDirectory (winHome, MAX_PATH))
232 SET ("user.home", winHome);
233 _Jv_Free (winHome);
234 }
235 }
236 }
237 if (userHome != NULL)
238 SET ("user.home", userHome);
239
240 // Get and set some OS info.
241 OSVERSIONINFO osvi;
242 ZeroMemory (&osvi, sizeof(OSVERSIONINFO));
243 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
244 if (GetVersionEx (&osvi))
245 {
246 char *buffer = (char *) _Jv_MallocUnchecked (30);
247 if (buffer != NULL)
248 {
249 sprintf (buffer, "%d.%d", (int) osvi.dwMajorVersion,
250 (int) osvi.dwMinorVersion);
251 SET ("os.version", buffer);
252 _Jv_Free (buffer);
253 }
254
255 switch (osvi.dwPlatformId)
256 {
257 case VER_PLATFORM_WIN32_WINDOWS:
258 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
259 SET ("os.name", "Windows 95");
260 else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
261 SET ("os.name", "Windows 98");
262 else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
263 SET ("os.name", "Windows Me");
264 else
265 SET ("os.name", "Windows ??");
266 break;
267
268 case VER_PLATFORM_WIN32_NT:
269 if (osvi.dwMajorVersion <= 4 )
270 SET ("os.name", "Windows NT");
271 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
272 SET ("os.name", "Windows 2000");
273 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
274 SET ("os.name", "Windows XP");
275 else
276 SET ("os.name", "Windows NT ??");
277 break;
278
279 default:
280 SET ("os.name", "Windows UNKNOWN");
281 break;
282 }
283 }
284
285 // Set the OS architecture.
286 SYSTEM_INFO si;
287 GetSystemInfo (&si);
288 switch (si.wProcessorArchitecture)
289 {
290 case PROCESSOR_ARCHITECTURE_INTEL:
291 SET ("os.arch", "x86");
292 break;
293 case PROCESSOR_ARCHITECTURE_MIPS:
294 SET ("os.arch", "mips");
295 break;
296 case PROCESSOR_ARCHITECTURE_ALPHA:
297 SET ("os.arch", "alpha");
298 break;
299 case PROCESSOR_ARCHITECTURE_PPC:
300 SET ("os.arch", "ppc");
301 break;
302 case PROCESSOR_ARCHITECTURE_IA64:
303 SET ("os.arch", "ia64");
304 break;
305 case PROCESSOR_ARCHITECTURE_UNKNOWN:
306 default:
307 SET ("os.arch", "unknown");
308 break;
309 }
310 }
311
312 /* Store up to SIZE return address of the current program state in
313 ARRAY and return the exact number of values stored. */
314 int
315 backtrace (void **__array, int __size)
316 {
317 register void *_ebp __asm__ ("ebp");
318 register void *_esp __asm__ ("esp");
319 unsigned int *rfp;
320
321 int i=0;
322 for (rfp = *(unsigned int**)_ebp;
323 rfp && i < __size;
324 rfp = *(unsigned int **)rfp)
325 {
326 int diff = *rfp - (unsigned int)rfp;
327 if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0) break;
328
329 __array[i++] = (void*)(rfp[1]-4);
330 }
331 return i;
332 }
333
334 int
335 _Jv_select (int n, fd_set *readfds, fd_set *writefds,
336 fd_set *exceptfds, struct timeval *timeout)
337 {
338 int r = ::select (n, readfds, writefds, exceptfds, timeout);
339 if (r == SOCKET_ERROR)
340 {
341 DWORD dwErrorCode = WSAGetLastError ();
342 throw new java::io::IOException (_Jv_WinStrError (dwErrorCode));
343 }
344 return r;
345 }
346
347 int
348 _Jv_pipe (int filedes[2])
349 {
350 return _pipe (filedes, 4096, _O_BINARY);
351 }