From: Luke D. <cod...@ho...> - 2003-02-17 10:33:57
|
>From: "Steven G. Johnson" <st...@ab...> >Reply-To: "Steven G. Johnson" <st...@al...> >To: min...@li... >Subject: [Mingw-users] using SIMD (SSE etc.) from MinGW: alignment? >Date: Sun, 16 Feb 2003 21:32:04 -0500 (EST) > >Dear MingW folks, > >I've been playing with MingW for cross-compiling a large numerical library >(www.fftw.org), and it is generally fantastic: I can use my unmodified >configure/make scripts from the comfort of Debian GNU/Linux (on PowerPC, >no less)! Of course, one still needs to test under Windows, but this is >relatively easy compared to re-creating the build system. Great job! > >Our library has the capability to use SIMD instructions (SSE, >SSE2, 3DNow!), which are supported by gcc, and it would be nice to enable >this in a Win32 version. However, this seems to be problematic in MinGW >because of the lack of aligned memory allocation routines; see bug #668224: > > http://sourceforge.net/tracker/index.php?func=detail&aid=668224&group_id=2435&atid=102435 > You could download the processor pack, then open it with a zip program and get align.c, which contains _align_malloc(), etc. >Does anyone use MinGW with SIMD? I don't, but... >If so, is there a simple workaround to >malloc 16-byte aligned blocks (as required for SIMD)? Possibly more efficient than _aligned_malloc() would be to do the alignment yourself, because these functions are just implemented using malloc(). You would need to allocate about 15 bytes more than you require, then when storing the data, add a value to the pointer to make it aligned. > >I looked through the mailing list and on Google, and I couldn't find >anything about MinGW+SIMD; I appreciate any pointers. Thanks! > >Cordially, >Steven G. Johnson Luke _________________________________________________________________ Hotmail now available on Australian mobile phones. Go to http://ninemsn.com.au/mobilecentral/hotmail_mobile.asp |
From: Luke D. <cod...@ho...> - 2003-02-18 01:23:11
|
>From: Danny Smith <dan...@ya...> >To: Michael Bester <mic...@gm...> >CC: "Steven G. Johnson" <st...@al...>, >min...@li... >Subject: Re: [Mingw-users] using SIMD (SSE etc.) from MinGW: alignment? >Date: Tue, 18 Feb 2003 09:10:24 +1100 (EST) > >As with Earnie, I get success on mingw/NT4 msvcrt.dll version 6.10.8924.0. It is possible that it succeeds by chance on NT4, so srand(time(NULL)) may give a more reliable result. Anyway, it fails on Win2K like XP so the point is that malloc() is not guaranteed to return any alignment, and is not documented to do so. >Unfortunately cygwin test failed (but I have an older version of >cygwin1.dll on >*this box so maybe that is fixed now.) > >Danny Well it isn't a bug so I wouldn't be surprised if the latest Cygwin is the same. Luke > > --- Earnie Boyd <ear...@ya...> wrote: > Michael Bester wrote: > > > I just ran your example.. > > > it is misalinged. > > > regards > > > michael. > > > > > > > Did you add #include <stdlib.h> and #include <stdio.h>? Did you use > > Steven's modified version? > > > > <file name="aligned.c"> > > #include <stdlib.h> > > #include <stdio.h> > > > > int main(void) > > { > > int i; > > for (i = 0; i < 10000; ++i) { > > void *p; > > p = (void *)malloc(1 + rand() % 32); > > if (((unsigned) p) % 16) { > > printf("Misaligned block!\n"); > > return 1; > > } > > } > > printf("All blocks aligned\n"); > > return 0; > > } > > > > </file> > > > > Earnie. _________________________________________________________________ Hotmail now available on Australian mobile phones. Go to http://ninemsn.com.au/mobilecentral/hotmail_mobile.asp |
From: Wu Y. <ad...@ne...> - 2003-02-18 02:00:23
|
My test (using Earnie's modified test program) confirmed that malloc is only 8-byte aligned. I have the MSVC processor pack. Its _align_malloc works this way: ensures that alignment is a power of 2 (or errno is set to EINVAL); ensures alignment is at least the size of a void pointer (increase it when not); allocates memory with required size plus alignment plus the size of a void pointer; calculates the returned pointer as return value of the previous operation plus alignment plus the size of a void pointer, and AND ~(alignment minus 1); stores the return value of malloc just before the calculated pointer; return the calculated pointer. You can easily figure out how _align_free was written. Best regards, Wu Yongwei --- Original Message from Steven G. Johnson --- malloc() returns 8-byte aligned blocks already (otherwise, double* would be misaligned). You would need to allocate 8 or 16 extra bytes, so that e.g. ((int*)p)-1 can always point to a flag telling whether the initial block was 16-byte aligned. (You must be able to retrieve the initial pointer for free purposes, you can't just increment it and forget it. And I can't store the initial pointer separately, because I need a malloc/memalign-like interface.) Can someone confirm that MS's implementation works this way? If so, I can post a "reverse engineered" _align_malloc for inclusion in MinGW, based on this technique. |
From: Wu Y. <ad...@ne...> - 2003-02-19 02:59:35
|
Your implementation seemed to be OK for _aligned_malloc, although I don't think it necessary to use C99 features (stdint.h/uintptr_t; size_t should suffice), and ptr_align is better implemented as a macro. Last time you did not mention _aligned_offset_malloc, and I told you only about _aligned_malloc, and now I see that your implementation of _aligned_offset_malloc (and also _aligned_free) has the fault that the return value of malloc is not stored four-byte aligned. I also would like that your code only bears a link to my message instead of posting the entire one. Thanks. Did you test your test case? It fails miserably on my Windows 2000 box (a NULL pointer is returned). However, you implementation passed the example in the Microsoft documentation. Best regards, Wu Yongwei --- Original Message from Steven G. Johnson --- I've implemented the MS _aligned_malloc etcetera interfaces, based on MS's online documentation and the algorithm description helpfully provided by Wu Yongwei. See the attached align.c file. I've also attached a short test program tstalign.c, which I ran successfully under Linux (where malloc is also 8-byte aligned), and also under the valgrind memory debugger with no errors, leaks, or thermonuclear meltdowns. I hope that this code, or perhaps some derivation depending on your tastes, can be included in MinGW at some point (closing bug #668224). Cordially, Steven G. Johnson |
From: Steven G. J. <st...@ab...> - 2003-02-19 21:12:36
Attachments:
align.c
tstalign.c
|
Wu Yongwei wrote: > Your implementation seemed to be OK for _aligned_malloc, although I > don't think it necessary to use C99 features (stdint.h/uintptr_t; size_t > should suffice), You're right that it's not necessary for any current system AFAIK. This is not guaranteed by the C standard, though; it seemed like better style to use uintptr_t (and stdint.h is included with mingw32-runtime anyways). However, I've put autoconf-style #ifdef HAVE_STDINT_H guards around stdint.h for now. (Mainly to let me test it with non-C99 compilers.) > and ptr_align is better implemented as a macro. Last That's what inlining is for; gcc -O3 does it automatically. But I guess you're worried about the case when mingw is compiled without optimization; fine. > time you did not mention _aligned_offset_malloc, and I told you only > about _aligned_malloc, and now I see that your implementation of > _aligned_offset_malloc (and also _aligned_free) has the fault that the > return value of malloc is not stored four-byte aligned. Good point. (Current Pentia don't require this, but maybe Itanium? It's needed on Alpha and UltraSPARC.) (I don't personally care about _aligned_offset_malloc, but it doesn't make sense to implement _aligned_malloc by itself.) > I also would like that your code only bears a link to my message instead > of posting the entire one. Thanks. No problem. > Did you test your test case? It fails miserably on my Windows 2000 box > (a NULL pointer is returned). However, you implementation passed the > example in the Microsoft documentation. I ran my test case, albeit under Linux. (I also ran it under valgrind, which would catch dereferencing NULL or anything like that, so it must be that something really different is happening for you.) (I don't suppose you're running out of memory? But I'm not allocating more than a couple of megabytes, at least with the GNU/glibc malloc.) I modified the test program to explicitly check for NULL returns (instead of just relying on it to crash in that case), and still no error. I tried cross-compiling it with mingw and running it under XP, and no error. I've fixed the stored-pointer alignment, and fixed another potential problem (there was some pointer arithmetic with void*, which is nonstandard). With the fixed alignment, the test program now succeeds on AIX, Solaris, and Tru64 as well. Can you give it another try with the modified version, attached? (If it still returns NULL somehow, at least it should at least print more output.) Thanks for your feedback. Steven |
From: Wu Y. <ad...@ne...> - 2003-02-24 07:16:54
|
I had a look at your code and ran your test, and this time all seemed OK and no problems were encountered. I suppose you have done a fine job but since I do not have SSE code to test with, you still need to do a lot of testing. Best regards, Wu Yongwei --- Original Message from Steven G. Johnson --- I modified the test program to explicitly check for NULL returns (instead of just relying on it to crash in that case), and still no error. I tried cross-compiling it with mingw and running it under XP, and no error. I've fixed the stored-pointer alignment, and fixed another potential problem (there was some pointer arithmetic with void*, which is nonstandard). With the fixed alignment, the test program now succeeds on AIX, Solaris, and Tru64 as well. Can you give it another try with the modified version, attached? (If it still returns NULL somehow, at least it should at least print more output.) Thanks for your feedback. Steven |
From: <dan...@ya...> - 2003-02-24 07:28:24
|
--- Wu Yongwei <ad...@ne...> wrote: > I had a look at your code and ran your test, and this time all seemed OK > and no problems were encountered. > > I suppose you have done a fine job but since I do not have SSE code to > test with, you still need to do a lot of testing. > > Best regards, > > Wu Yongwei > > --- Original Message from Steven G. Johnson --- > > I modified the test program to explicitly check for NULL returns > (instead of just relying on it to crash in that case), and still no > error. I tried cross-compiling it with mingw and running it under XP, > and no error. > > I've fixed the stored-pointer alignment, and fixed another potential > problem (there was some pointer arithmetic with void*, which is > nonstandard). With the fixed alignment, the test program now succeeds > on AIX, Solaris, and Tru64 as well. > Since this affects a wide range of targets, I would consider submitting this to libiberty or gcc lists for review and perhaps incorporation into GCC Danny > > Steven > > > > ------------------------------------------------------- > This SF.net email is sponsored by: SlickEdit Inc. Develop an edge. > The most comprehensive and flexible code editor you can use. > Code faster. C/C++, C#, Java, HTML, XML, many more. FREE 30-Day Trial. > www.slickedit.com/sourceforge > _______________________________________________ > MinGW-users mailing list > Min...@li... > > You may change your MinGW Account Options or unsubscribe at: > https://lists.sourceforge.net/lists/listinfo/mingw-users http://mobile.yahoo.com.au - Yahoo! Mobile - Exchange IMs with Messenger friends on your Telstra or Vodafone mobile phone. |
From: Steven G. J. <st...@ab...> - 2003-02-24 22:04:20
|
Wu Yongwei wrote: > I had a look at your code and ran your test, and this time all seemed OK > and no problems were encountered. Great, thanks! I'll attach the revised code to the MinGW bug report for this issue. > I suppose you have done a fine job but since I do not have SSE code to > test with, you still need to do a lot of testing. Well, the _aligned_malloc and friends don't use SSE, or require SSE to test; all that matters is that they produce the requested alignment. I will, of course, test my own SSE code now that I can cross-compile it, and I'll let you guys know if I encounter any further problems. Danny Smith wrote: > Since this affects a wide range of targets, I would consider > submitting this to libiberty or gcc lists for review and perhaps > incorporation into GCC That's an interesting suggestion... but normally a program would want to use the native alignment routine (e.g. memalign) on a particular platform. As far as I know, Windows is the only current system that requires alignment to use certain features (SSE) but does not provide a system-library routine to allocate blocks with that alignment. (The native alignment routine is preferable to a portable routine because the former can likely take advantage of malloc internals to reduce the allocation overhead.) I tested it with a wide variety of OS's and CPU's in order to help expose any bugs, not because I think a portable _aligned_malloc is actually useful on those systems. Steven |
From: Steven G. J. <st...@ab...> - 2003-02-24 22:21:25
|
Wu Yongwei wrote: > I had a look at your code and ran your test, and this time all seemed OK > and no problems were encountered. Great, thanks! I've attached the revised code to the MinGW bug report for this issue. > I suppose you have done a fine job but since I do not have SSE code to > test with, you still need to do a lot of testing. Well, the _aligned_malloc and friends don't technically require SSE to test; all that matters is that they produce the requested alignment. I will, of course, test my own SSE code now that I can cross-compile it, and I'll let you guys know if I encounter any further problems. Danny Smith wrote: > Since this affects a wide range of targets, I would consider > submitting this to libiberty or gcc lists for review and perhaps > incorporation into GCC That's an interesting suggestion... but normally a program would want to use the native alignment routine (e.g. memalign) on a particular platform. As far as I know, Windows is the only current system that requires alignment to use certain features (SSE) but does not provide a system-library routine to allocate blocks with that alignment. (The native alignment routine is preferable to a portable routine because the former can likely take advantage of malloc internals to reduce the allocation overhead, etcetera.) I tested it with a wide variety of OS's and CPU's in order to help expose any bugs, not because I think a portable _aligned_malloc is necessarily useful on those systems. Steven |
From: <dan...@ya...> - 2003-02-17 19:31:10
|
--- Luke Dunstan <cod...@ho...> wrote: > > > >From: "Steven G. Johnson" <st...@ab...> > >Reply-To: "Steven G. Johnson" <st...@al...> > >To: min...@li... > >Subject: [Mingw-users] using SIMD (SSE etc.) from MinGW: alignment? > >Date: Sun, 16 Feb 2003 21:32:04 -0500 (EST) > > > > > >Our library has the capability to use SIMD instructions (SSE, > >SSE2, 3DNow!), which are supported by gcc, and it would be nice to enable > >this in a Win32 version. However, this seems to be problematic in MinGW > >because of the lack of aligned memory allocation routines; see bug #668224: > > > > > http://sourceforge.net/tracker/index.php?func=detail&aid=668224&group_id=2435&atid=102435 > > > > > >Does anyone use MinGW with SIMD? > > I don't, but... > > >If so, is there a simple workaround to > >malloc 16-byte aligned blocks (as required for SIMD)? > > Possibly more efficient than _aligned_malloc() would be to do the alignment > yourself, because these functions are just implemented using malloc(). You > would need to allocate about 15 bytes more than you require, then when > storing the data, add a value to the pointer to make it aligned. > Or: Use the __m128 type (#include <xmmintrinsic.h> in a new union type eg typedef union { __m128 m; float f[4]; } sse4f; and then malloc pointers to the new type. The __m128 field should forse 128 bit alignement and you still have access to the float components without ugly casts. Also look at the new intrinsics in xxmintrin.h. Danny http://mobile.yahoo.com.au - Yahoo! Mobile - Exchange IMs with Messenger friends on your Telstra or Vodafone mobile phone. |
From: Steven G. J. <st...@ab...> - 2003-02-17 19:48:26
|
On Mon, 17 Feb 2003, Luke Dunstan wrote: > You could download the processor pack, then open it with a zip program and > get align.c, which contains _align_malloc(), etc. There are copyright issues with this, I imagine (or MinGW could include align.c itself). On the other hand, reverse engineering may be okay... > >Does anyone use MinGW with SIMD? > > I don't, but... > > >If so, is there a simple workaround to > >malloc 16-byte aligned blocks (as required for SIMD)? > > Possibly more efficient than _aligned_malloc() would be to do the alignment > yourself, because these functions are just implemented using malloc(). You > would need to allocate about 15 bytes more than you require, then when > storing the data, add a value to the pointer to make it aligned. malloc() returns 8-byte aligned blocks already (otherwise, double* would be misaligned). You would need to allocate 8 or 16 extra bytes, so that e.g. ((int*)p)-1 can always point to a flag telling whether the initial block was 16-byte aligned. (You must be able to retrieve the initial pointer for free purposes, you can't just increment it and forget it. And I can't store the initial pointer separately, because I need a malloc/memalign-like interface.) Can someone confirm that MS's implementation works this way? If so, I can post a "reverse engineered" _align_malloc for inclusion in MinGW, based on this technique. (I would have thought that MS's implementation would use some of their malloc internals to avoid the overhead for the case where the initial block is already aligned. This is how glibc's memalign works.) Luke Dunstan <cod...@ho...> wrote: |
From: Steven G. J. <st...@ab...> - 2003-02-17 19:52:21
|
> Luke Dunstan <cod...@ho...> wrote: > Or: > > Use the __m128 type (#include <xmmintrinsic.h> in a new union type > eg > typedef union { > __m128 m; > float f[4]; > } sse4f; This only aligns things on the stack, and has no effect on blocks allocated via malloc. |
From: Earnie B. <ear...@ya...> - 2003-02-17 20:25:18
|
Steven G. Johnson wrote: >>Luke Dunstan <cod...@ho...> wrote: >>Or: >> >>Use the __m128 type (#include <xmmintrinsic.h> in a new union type >>eg >>typedef union { >> __m128 m; >> float f[4]; >>} sse4f; > > > This only aligns things on the stack, and has no effect on blocks > allocated via malloc. > You may want to search google for ``malloc aligned win32''. I find evidence that LocalAlloc and GlobalAlloc pointers are 8 byte aligned. I find evidence that malloc pointers are aligned for storage of any type of object. Earnie. |
From: Steven G. J. <st...@ab...> - 2003-02-17 21:12:42
|
On Mon, 17 Feb 2003, Earnie Boyd wrote: > You may want to search google for ``malloc aligned win32''. I find > evidence that LocalAlloc and GlobalAlloc pointers are 8 byte aligned. I > find evidence that malloc pointers are aligned for storage of any type > of object. Sure, you find statements that malloc returns a pointer that is "aligned for any type of object," but all such statements that I can find make no reference to SIMD (still a relatively exotic case), and so I don't entirely trust them. ...I find it suspicious that MS deemed it necessary to provide an _aligned_malloc in the same processor pack that provides SIMD support, don't you? If you Google for _aligned_malloc or "malloc win32 8-byte align", you find other pages on the web that suggest it is required for SIMD, and that malloc is merely 8-byte aligned for historical reasons. Put another way, I can find many explicit statements that Win32 malloc is at least 8-byte aligned, but I can't find any explicit statements that it is 16-byte aligned, and the price of misalignment for SIMD is a crash. I'd be happy to be corrected, of course, so I could forget about this. A quick test would be if someone with a Windows box sitting in front of them (not me, I'm afraid), could run: int main(void) { int i; for (i = 0; i < 10000; ++i) { void *p; p = malloc(1 + rand(32)); if (((unsigned) p) % 16) { printf("Misaligned block!\n"); return 1; } } printf("All blocks aligned\n"); return 0; } (Yes, the memory leak is intentional; I don't want to free the blocks here in case their alignments interact.) Of course, if this passes, it is not a proof that malloc is always aligned, but if it fails that will settle the question completely (and unfortunately). Steven |
From: Steven G. J. <st...@ab...> - 2003-02-17 21:21:36
|
On Mon, 17 Feb 2003, Steven G. Johnson wrote: > p = malloc(1 + rand(32)); Sorry, that should be rand() % 32, not rand(32). |
From: Earnie B. <ear...@ya...> - 2003-02-17 21:33:37
|
All blocks aligned. Earnie. Steven G. Johnson wrote: > On Mon, 17 Feb 2003, Steven G. Johnson wrote: > >> p = malloc(1 + rand(32)); > > > Sorry, that should be rand() % 32, not rand(32). > > > > ------------------------------------------------------- > This sf.net email is sponsored by:ThinkGeek > Welcome to geek heaven. > http://thinkgeek.com/sf > _______________________________________________ > MinGW-users mailing list > Min...@li... > > You may change your MinGW Account Options or unsubscribe at: > https://lists.sourceforge.net/lists/listinfo/mingw-users > |
From: Michael B. <mic...@gm...> - 2003-02-17 21:48:28
|
Earnie Boyd wrote: > All blocks aligned. > > Earnie. Did you compile with gcc? I get "Misaligned block!" on the 1. malloc. michael. |
From: Earnie B. <ear...@ya...> - 2003-02-17 21:58:51
|
Michael Bester wrote: > Earnie Boyd wrote: > >> All blocks aligned. >> >> Earnie. > > > Did you compile with gcc? > I get "Misaligned block!" on the 1. malloc. > BoydE@DU216771 /adhoc/junk/aligned_malloc $ gcc --version gcc.exe (GCC) 3.2.1 (MinGW special 20021202-2) Copyright (C) 2002 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Earnie. |
From: Michael B. <mic...@gm...> - 2003-02-17 22:01:37
|
Earnie Boyd wrote: > Michael Bester wrote: > >> Earnie Boyd wrote: >> > BoydE@DU216771 /adhoc/junk/aligned_malloc > $ gcc --version > gcc.exe (GCC) 3.2.1 (MinGW special 20021202-2) > Copyright (C) 2002 Free Software Foundation, Inc. > This is free software; see the source for copying conditions. There > is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A > PARTICULAR PURPOSE. > > > Earnie. > I used 3.2.2. michael. |
From: Steven G. J. <st...@ab...> - 2003-02-17 22:10:55
|
(Just to round things out, I used gcc 2.95.3, from the somewhat older version of MinGW in Debian/stable. But malloc shouldn't depend on gcc per se, in any case; I don't think it is a builtin. Yes, I used the header files, although it shouldn't make a difference since C's default int types should be correct on a 32-bit machine.) |
From: Michael B. <mic...@gm...> - 2003-02-17 21:29:45
|
Steven G. Johnson wrote: >On Mon, 17 Feb 2003, Earnie Boyd wrote: > > >>You may want to search google for ``malloc aligned win32''. I find >>evidence that LocalAlloc and GlobalAlloc pointers are 8 byte aligned. I >>find evidence that malloc pointers are aligned for storage of any type >>of object. >> >> > >[snip] >A quick test would be if someone with a Windows box sitting in front of >them (not me, I'm afraid), could run: > >int main(void) >{ > int i; > for (i = 0; i < 10000; ++i) { > void *p; > p = malloc(1 + rand(32)); > if (((unsigned) p) % 16) { > printf("Misaligned block!\n"); > return 1; > } > } > printf("All blocks aligned\n"); > return 0; >} > >(Yes, the memory leak is intentional; I don't want to free the blocks here >in case their alignments interact.) Of course, if this passes, it is not >a proof that malloc is always aligned, but if it fails that will settle >the question completely (and unfortunately). > >Steven > > I just ran your example.. it is misalinged. regards michael. > > |
From: Earnie B. <ear...@ya...> - 2003-02-17 21:52:10
|
Michael Bester wrote: > I just ran your example.. > it is misalinged. > regards > michael. > Did you add #include <stdlib.h> and #include <stdio.h>? Did you use Steven's modified version? <file name="aligned.c"> #include <stdlib.h> #include <stdio.h> int main(void) { int i; for (i = 0; i < 10000; ++i) { void *p; p = (void *)malloc(1 + rand() % 32); if (((unsigned) p) % 16) { printf("Misaligned block!\n"); return 1; } } printf("All blocks aligned\n"); return 0; } </file> Earnie. |
From: Michael B. <mic...@gm...> - 2003-02-17 21:58:36
|
Earnie Boyd wrote: > Michael Bester wrote: > >> I just ran your example.. >> it is misalinged. >> regards >> michael. >> > > Did you add #include <stdlib.h> and #include <stdio.h>? Did you use > Steven's modified version? Yes I did (on XP). Should I send you my binary? michael. |
From: Earnie B. <ear...@ya...> - 2003-02-17 22:02:50
|
Michael Bester wrote: > Should I send you my binary? No. |
From: <dan...@ya...> - 2003-02-17 22:10:24
|
As with Earnie, I get success on mingw/NT4 msvcrt.dll version 6.10.8924.0. Unfortunately cygwin test failed (but I have an older version of cygwin1.dll on *this box so maybe that is fixed now.) Danny --- Earnie Boyd <ear...@ya...> wrote: > Michael Bester wrote: > > I just ran your example.. > > it is misalinged. > > regards > > michael. > > > > Did you add #include <stdlib.h> and #include <stdio.h>? Did you use > Steven's modified version? > > <file name="aligned.c"> > #include <stdlib.h> > #include <stdio.h> > > int main(void) > { > int i; > for (i = 0; i < 10000; ++i) { > void *p; > p = (void *)malloc(1 + rand() % 32); > if (((unsigned) p) % 16) { > printf("Misaligned block!\n"); > return 1; > } > } > printf("All blocks aligned\n"); > return 0; > } > > </file> > > Earnie. > > > > ------------------------------------------------------- > This sf.net email is sponsored by:ThinkGeek > Welcome to geek heaven. > http://thinkgeek.com/sf > _______________________________________________ > MinGW-users mailing list > Min...@li... > > You may change your MinGW Account Options or unsubscribe at: > https://lists.sourceforge.net/lists/listinfo/mingw-users http://mobile.yahoo.com.au - Yahoo! Mobile - Exchange IMs with Messenger friends on your Telstra or Vodafone mobile phone. |