]> granicus.if.org Git - postgresql/commitdiff
[all] Removed call to getppid in SendPostmasterSignal, replacing with a
authorBruce Momjian <bruce@momjian.us>
Mon, 26 Jan 2004 22:59:54 +0000 (22:59 +0000)
committerBruce Momjian <bruce@momjian.us>
Mon, 26 Jan 2004 22:59:54 +0000 (22:59 +0000)
PostmasterPid variable, which gets set (early) in PostmasterMain
getppid would not be the postmaster?

[fork/exec] Implements processCancelRequest by keeping an array of

pid/cancel_key structs in shared mem

[fork/exec] Moves AttachSharedMemoryAndSemaphores call for backends into
SubPostmasterMain

[win32] Implements reaper/waitpid by keeping an arrays of children
pids,handles in postmaster local mem
      - this item is largely untested, for reasons which should be
obvious, but appears sound

[win32/all] Added extern for pgpipe in Win32 case, and changed the second
pipe call (which seems to have been missed earlier) to pgpipe

[win32] #define'd ftruncate to chsize in the Win32 case

[win32] PG_USLEEP for Win32 has a misplaced paren. Fixed.

[win32] DLLIMPORT handling for MingW case

Claudio Natoli

src/backend/postmaster/pgstat.c
src/backend/postmaster/postmaster.c
src/backend/storage/ipc/ipci.c
src/backend/storage/ipc/pmsignal.c
src/backend/tcop/postgres.c
src/backend/utils/init/globals.c
src/include/miscadmin.h
src/include/port/win32.h

index c2b97704cc2dd28b3d584744f7dc5b8505b121e7..b684f01c1199d1fd92f75cab154f480a65b839c3 100644 (file)
@@ -13,7 +13,7 @@
  *
  *     Copyright (c) 2001-2003, PostgreSQL Global Development Group
  *
- *     $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.55 2004/01/26 22:54:56 momjian Exp $
+ *     $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.56 2004/01/26 22:59:53 momjian Exp $
  * ----------
  */
 #include "postgres.h"
@@ -147,7 +147,7 @@ static void pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len);
 #define piperead(a,b,c)                read(a,b,c)
 #define pipewrite(a,b,c)       write(a,b,c)
 #else
-/* pgpipe() is in /src/port */
+extern int pgpipe(int handles[2]); /* pgpipe() is in /src/port */
 #define piperead(a,b,c)                recv(a,b,c,0)
 #define pipewrite(a,b,c)       send(a,b,c,0)
 #endif
@@ -322,7 +322,7 @@ pgstat_init(void)
        /*
         * Create the pipe that controls the statistics collector shutdown
         */
-       if (pipe(pgStatPmPipe) < 0)
+       if (pgpipe(pgStatPmPipe) < 0)
        {
                ereport(LOG,
                                (errcode_for_socket_access(),
index 5fa9590a62c8ac9c2d3552f4f65f472bb030b53c..ccbffab56170e4f2cd47d263e41278d16c9f4564 100644 (file)
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.361 2004/01/26 22:54:56 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.362 2004/01/26 22:59:53 momjian Exp $
  *
  * NOTES
  *
@@ -141,6 +141,11 @@ typedef struct bkend
 
 static Dllist *BackendList;
 
+#ifdef EXEC_BACKEND
+#define NUM_BACKENDARRAY_ELEMS (2*MaxBackends)
+static Backend *ShmemBackendArray;
+#endif
+
 /* The socket number we are listening for connections on */
 int                    PostPortNumber;
 char      *UnixSocketDir;
@@ -299,6 +304,14 @@ __attribute__((format(printf, 1, 2)));
 #ifdef EXEC_BACKEND
 #ifdef WIN32
 pid_t win32_forkexec(const char* path, char *argv[]);
+
+static void  win32_AddChild(pid_t pid, HANDLE handle);
+static void  win32_RemoveChild(pid_t pid);
+static pid_t win32_waitpid(int *exitstatus);
+
+static pid_t  *win32_childPIDArray;
+static HANDLE *win32_childHNDArray;
+static unsigned long win32_numChildren = 0;
 #endif
 
 static pid_t Backend_forkexec(Port *port);
@@ -306,6 +319,11 @@ static pid_t Backend_forkexec(Port *port);
 static unsigned long tmpBackendFileNum = 0;
 void read_backend_variables(unsigned long id, Port *port);
 static bool write_backend_variables(Port *port);
+
+size_t                 ShmemBackendArraySize(void);
+void           ShmemBackendArrayAllocation(void);
+static void    ShmemBackendArrayAdd(Backend *bn);
+static void ShmemBackendArrayRemove(pid_t pid);
 #endif
 
 #define StartupDataBase()              SSDataBase(BS_XLOG_STARTUP)
@@ -430,7 +448,7 @@ PostmasterMain(int argc, char *argv[])
         */
        umask((mode_t) 0077);
 
-       MyProcPid = getpid();
+       MyProcPid = PostmasterPid = getpid();
 
        /*
         * Fire up essential subsystems: memory management
@@ -825,6 +843,21 @@ PostmasterMain(int argc, char *argv[])
         */
        BackendList = DLNewList();
 
+#ifdef WIN32
+       /*
+        * Initialize the child pid/HANDLE arrays
+        */
+       /* FIXME: [fork/exec] Ideally, we would resize these arrays with changes
+        *  in MaxBackends, but this'll do as a first order solution.
+        */
+       win32_childPIDArray = (HANDLE*)malloc(NUM_BACKENDARRAY_ELEMS*sizeof(pid_t));
+       win32_childHNDArray = (HANDLE*)malloc(NUM_BACKENDARRAY_ELEMS*sizeof(HANDLE));
+       if (!win32_childPIDArray || !win32_childHNDArray)
+               ereport(LOG,
+                               (errcode(ERRCODE_OUT_OF_MEMORY),
+                                errmsg("out of memory")));
+#endif
+
        /*
         * Record postmaster options.  We delay this till now to avoid
         * recording bogus options (eg, NBuffers too high for available
@@ -1257,11 +1290,7 @@ ProcessStartupPacket(Port *port, bool SSLdone)
 
        if (proto == CANCEL_REQUEST_CODE)
        {
-#ifdef EXEC_BACKEND
-               abort(); /* FIXME: [fork/exec] Whoops. Not handled... yet */
-#else
                processCancelRequest(port, buf);
-#endif
                return 127;                             /* XXX */
        }
 
@@ -1494,8 +1523,12 @@ processCancelRequest(Port *port, void *pkt)
        CancelRequestPacket *canc = (CancelRequestPacket *) pkt;
        int                     backendPID;
        long            cancelAuthCode;
-       Dlelem     *curr;
        Backend    *bp;
+#ifndef EXEC_BACKEND
+       Dlelem     *curr;
+#else
+       int i;
+#endif
 
        backendPID = (int) ntohl(canc->backendPID);
        cancelAuthCode = (long) ntohl(canc->cancelAuthCode);
@@ -1514,16 +1547,17 @@ processCancelRequest(Port *port, void *pkt)
                                                                 backendPID)));
                return;
        }
-#ifdef EXEC_BACKEND
-       else
-               AttachSharedMemoryAndSemaphores();
-#endif
 
        /* See if we have a matching backend */
-
+#ifndef EXEC_BACKEND
        for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))
        {
                bp = (Backend *) DLE_VAL(curr);
+#else
+       for (i = 0; i < NUM_BACKENDARRAY_ELEMS; i++)
+       {
+               bp = (Backend*) &ShmemBackendArray[i];
+#endif
                if (bp->pid == backendPID)
                {
                        if (bp->cancel_key == cancelAuthCode)
@@ -1846,14 +1880,12 @@ reaper(SIGNAL_ARGS)
 {
        int                     save_errno = errno;
 
-#ifdef WIN32
-#warning fix waidpid for Win32
-#else
 #ifdef HAVE_WAITPID
        int                     status;                 /* backend exit status */
-
 #else
+#ifndef WIN32
        union wait      status;                 /* backend exit status */
+#endif
 #endif
        int                     exitstatus;
        int                     pid;                    /* process id of dead backend */
@@ -1867,9 +1899,21 @@ reaper(SIGNAL_ARGS)
        {
                exitstatus = status;
 #else
+#ifndef WIN32
        while ((pid = wait3(&status, WNOHANG, NULL)) > 0)
        {
                exitstatus = status.w_status;
+#else
+       while ((pid = win32_waitpid(&exitstatus)) > 0)
+       {
+               /*
+                * We need to do this here, and not in CleanupProc, since this
+                * is to be called on all children when we are done with them.
+                * Could move to LogChildExit, but that seems like asking for
+                * future trouble...
+                */
+               win32_RemoveChild(pid);
+#endif
 #endif
 
                /*
@@ -1957,7 +2001,6 @@ reaper(SIGNAL_ARGS)
                CleanupProc(pid, exitstatus);
 
        }                                                       /* loop over pending child-death reports */
-#endif
 
        if (FatalError)
        {
@@ -2022,6 +2065,9 @@ CleanupProc(int pid,
                        bp = (Backend *) DLE_VAL(curr);
                        if (bp->pid == pid)
                        {
+#ifdef EXEC_BACKEND
+                               ShmemBackendArrayRemove(bp->pid);
+#endif
                                DLRemove(curr);
                                free(bp);
                                DLFreeElem(curr);
@@ -2092,6 +2138,9 @@ CleanupProc(int pid,
                        /*
                         * Found entry for freshly-dead backend, so remove it.
                         */
+#ifdef EXEC_BACKEND
+                       ShmemBackendArrayRemove(bp->pid);
+#endif
                        DLRemove(curr);
                        free(bp);
                        DLFreeElem(curr);
@@ -2296,6 +2345,9 @@ BackendStartup(Port *port)
         */
        bn->pid = pid;
        bn->cancel_key = MyCancelKey;
+#ifdef EXEC_BACKEND
+       ShmemBackendArrayAdd(bn);
+#endif
        DLAddHead(BackendList, DLNewElem(bn));
 
        return STATUS_OK;
@@ -2642,6 +2694,9 @@ SubPostmasterMain(int argc, char* argv[])
        memset((void*)&port, 0, sizeof(Port));
        Assert(argc == 2);
 
+       /* Do this sooner rather than later... */
+       IsUnderPostmaster = true;       /* we are a postmaster subprocess now */
+
        /* Setup global context */
        MemoryContextInit();
        InitializeGUCOptions();
@@ -2661,6 +2716,9 @@ SubPostmasterMain(int argc, char* argv[])
        load_user();
        load_group();
 
+       /* Attach process to shared segments */
+       AttachSharedMemoryAndSemaphores();
+
        /* Run backend */
        proc_exit(BackendRun(&port));
 }
@@ -3129,6 +3187,9 @@ SSDataBase(int xlop)
 
                bn->pid = pid;
                bn->cancel_key = PostmasterRandom();
+#ifdef EXEC_BACKEND
+               ShmemBackendArrayAdd(bn);
+#endif
                DLAddHead(BackendList, DLNewElem(bn));
 
                /*
@@ -3278,6 +3339,7 @@ write_backend_variables(Port *port)
        write_var(ShmemIndexLock,fp);
        write_var(ShmemVariableCache,fp);
        write_var(ShmemIndexAlloc,fp);
+       write_var(ShmemBackendArray,fp);
 
        write_var(LWLockArray,fp);
        write_var(ProcStructLock,fp);
@@ -3285,6 +3347,7 @@ write_backend_variables(Port *port)
 
        write_var(PreAuthDelay,fp);
        write_var(debug_flag,fp);
+       write_var(PostmasterPid,fp);
 
        /* Release file */
        if (FreeFile(fp))
@@ -3338,6 +3401,7 @@ read_backend_variables(unsigned long id, Port *port)
        read_var(ShmemIndexLock,fp);
        read_var(ShmemVariableCache,fp);
        read_var(ShmemIndexAlloc,fp);
+       read_var(ShmemBackendArray,fp);
 
        read_var(LWLockArray,fp);
        read_var(ProcStructLock,fp);
@@ -3345,6 +3409,7 @@ read_backend_variables(unsigned long id, Port *port)
 
        read_var(PreAuthDelay,fp);
        read_var(debug_flag,fp);
+       read_var(PostmasterPid,fp);
 
        /* Release file */
        FreeFile(fp);
@@ -3354,6 +3419,55 @@ read_backend_variables(unsigned long id, Port *port)
                                 errmsg("could not remove file \"%s\": %m", filename)));
 }
 
+
+size_t ShmemBackendArraySize(void)
+{
+       return (NUM_BACKENDARRAY_ELEMS*sizeof(Backend));
+}
+
+void ShmemBackendArrayAllocation(void)
+{
+       size_t size = ShmemBackendArraySize();
+       ShmemBackendArray = (Backend*)ShmemAlloc(size);
+       memset(ShmemBackendArray, 0, size);
+}
+
+static void ShmemBackendArrayAdd(Backend *bn)
+{
+       int i;
+       for (i = 0; i < NUM_BACKENDARRAY_ELEMS; i++)
+       {
+               /* Find an empty slot */
+               if (ShmemBackendArray[i].pid == 0)
+               {
+                       ShmemBackendArray[i] = *bn;
+                       return;
+               }
+       }
+
+       /* FIXME: [fork/exec] some sort of error */
+       abort();
+}
+
+static void ShmemBackendArrayRemove(pid_t pid)
+{
+       int i;
+       for (i = 0; i < NUM_BACKENDARRAY_ELEMS; i++)
+       {
+               if (ShmemBackendArray[i].pid == pid)
+               {
+                       /* Mark the slot as empty */
+                       ShmemBackendArray[i].pid = 0;
+                       return;
+               }
+       }
+
+       /* Something stronger than WARNING here? */
+       ereport(WARNING,
+                       (errmsg_internal("unable to find backend entry with pid %d",
+                                                        pid)));
+}
+
 #endif
 
 #ifdef WIN32
@@ -3393,14 +3507,111 @@ pid_t win32_forkexec(const char* path, char *argv[])
                return -1;
        }
 
-       /*
-          FIXME: [fork/exec] we might need to keep the following handle/s,
-          depending on how we implement signalling.
-       */
-       CloseHandle(pi.hProcess);
+       if (!IsUnderPostmaster)
+               /* We are the Postmaster creating a child... */
+               win32_AddChild(pi.dwProcessId,pi.hProcess);
+       else
+               CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
 
        return pi.dwProcessId;
 }
 
+/*
+ * Note: The following three functions must not be interrupted (eg. by signals).
+ *  As the Postgres Win32 signalling architecture (currently) requires polling,
+ *  or APC checking functions which aren't used here, this is not an issue.
+ *
+ *  We keep two separate arrays, instead of a single array of pid/HANDLE structs,
+ *  to avoid having to re-create a handle array for WaitForMultipleObjects on
+ *  each call to win32_waitpid.
+ */
+
+static void win32_AddChild(pid_t pid, HANDLE handle)
+{
+       Assert(win32_childPIDArray && win32_childHNDArray);
+       if (win32_numChildren < NUM_BACKENDARRAY_ELEMS)
+       {
+               win32_childPIDArray[win32_numChildren] = pid;
+               win32_childHNDArray[win32_numChildren] = handle;
+               ++win32_numChildren;
+       }
+       else
+               /* FIXME: [fork/exec] some sort of error */
+               abort();
+}
+
+static void win32_RemoveChild(pid_t pid)
+{
+       int i;
+       Assert(win32_childPIDArray && win32_childHNDArray);
+
+       for (i = 0; i < win32_numChildren; i++)
+       {
+               if (win32_childPIDArray[i] == pid)
+               {
+                       CloseHandle(win32_childHNDArray[i]);
+
+                       /* Swap last entry into the "removed" one */
+                       --win32_numChildren;
+                       win32_childPIDArray[win32_numChildren] = win32_childPIDArray[i];
+                       win32_childHNDArray[win32_numChildren] = win32_childHNDArray[i];
+                       return;
+               }
+       }
+
+       /* Something stronger than WARNING here? */
+       ereport(WARNING,
+                       (errmsg_internal("unable to find child entry with pid %d",
+                                                        pid)));
+}
+
+static pid_t win32_waitpid(int *exitstatus)
+{
+       Assert(win32_childPIDArray && win32_childHNDArray);
+       elog(DEBUG3,"waiting on %d children",win32_numChildren);
+
+       if (win32_numChildren > 0)
+       {
+               /*
+                * Note: Do NOT use WaitForMultipleObjectsEx, as we don't
+                * want to run queued APCs here.
+                */
+               int index;
+               DWORD exitCode;
+               DWORD ret = WaitForMultipleObjects(win32_numChildren,win32_childHNDArray,FALSE,0);
+
+               switch (ret)
+               {
+                       case WAIT_FAILED:
+                               ereport(ERROR,
+                                               (errmsg_internal("failed to wait on %d children",
+                                                                                win32_numChildren)));
+                               /* Fall through to WAIT_TIMEOUTs return */
+
+                       case WAIT_TIMEOUT:
+                               /* No children have finished */
+                               return -1;
+
+                       default:
+                               /* Get the exit code, and return the PID of, the respective process */
+                               index = ret-WAIT_OBJECT_0;
+                               Assert(index >= 0 && index < win32_numChildren);
+                               if (!GetExitCodeProcess(win32_childHNDArray[index],&exitCode))
+                                       /*
+                                        * If we get this far, this should never happen, but, then again...
+                                        * No choice other than to assume a catastrophic failure.
+                                        */
+                                       ereport(FATAL,
+                                                       (errmsg_internal("failed to get exit code for child %d",
+                                                                                        win32_childPIDArray[index])));
+                               *exitstatus = (int)exitCode;
+                               return win32_childPIDArray[index];
+               }
+       }
+
+       /* No children */
+       return -1;
+}
+
 #endif
index 15692684e3b7117c053089aeb9f72e591ee3de59..7de7d85e74d6e87a345634c1f6a9520eccb4bec9 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.62 2004/01/26 22:54:57 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.63 2004/01/26 22:59:53 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -63,6 +63,9 @@ CreateSharedMemoryAndSemaphores(bool makePrivate,
        size += LWLockShmemSize();
        size += SInvalShmemSize(maxBackends);
        size += FreeSpaceShmemSize();
+#ifdef EXEC_BACKEND
+       size += ShmemBackendArraySize();
+#endif
 #ifdef STABLE_MEMORY_STORAGE
        size += MMShmemSize();
 #endif
@@ -132,6 +135,13 @@ CreateSharedMemoryAndSemaphores(bool makePrivate,
         * Set up child-to-postmaster signaling mechanism
         */
        PMSignalInit();
+
+#ifdef EXEC_BACKEND
+       /*
+        * Alloc the win32 shared backend array
+        */
+       ShmemBackendArrayAllocation();
+#endif
 }
 
 
index 2b15f8d444ab74c40d0eeb26e3ba9cb0abb9a207..2d6252b66caa12da3422dcb884286cd48adbba9c 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/storage/ipc/pmsignal.c,v 1.10 2004/01/26 22:54:57 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/storage/ipc/pmsignal.c,v 1.11 2004/01/26 22:59:53 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -63,8 +63,8 @@ SendPostmasterSignal(PMSignalReason reason)
                return;
        /* Atomically set the proper flag */
        PMSignalFlags[reason] = true;
-       /* Send signal to postmaster (assume it is our direct parent) */
-       kill(getppid(), SIGUSR1);
+       /* Send signal to postmaster */
+       kill(PostmasterPid, SIGUSR1);
 }
 
 /*
index f8a3bfd3bd0750d77a2facbbac7e7d06d9e04c07..2a40b34261ec0922eb3c5a8ae0da0724fe884cf0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.385 2004/01/26 22:54:57 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.386 2004/01/26 22:59:53 momjian Exp $
  *
  * NOTES
  *       this is the "main" module of the postgres backend and
@@ -2535,9 +2535,7 @@ PostgresMain(int argc, char *argv[], const char *username)
                                         errmsg("invalid command-line arguments for server process"),
                                         errhint("Try \"%s --help\" for more information.", argv[0])));
                }
-#ifdef EXEC_BACKEND
-               AttachSharedMemoryAndSemaphores();
-#endif
+
                XLOGPathInit();
 
                BaseInit();
index 29d1ebc0c7ee3030db167f4024bd0701f163acba..56058fa05cc687026415a7feb4faa9558a96bc3f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/init/globals.c,v 1.79 2004/01/26 22:54:57 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/init/globals.c,v 1.80 2004/01/26 22:59:53 momjian Exp $
  *
  * NOTES
  *       Globals used all over the place should be declared here and not
@@ -53,6 +53,8 @@ BackendId     MyBackendId;
 char      *DatabasePath = NULL;
 Oid                    MyDatabaseId = InvalidOid;
 
+pid_t PostmasterPid = 0;
+
 /* these are initialized for the bootstrap/standalone case: */
 bool           IsPostmasterEnvironment = false;
 bool           IsUnderPostmaster = false;
index b48345858aeefa6c7a433f127ba61be9b91ab7b3..b44d160c27f206ab592bf643dcf27a19dca6f776 100644 (file)
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.147 2004/01/26 22:54:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.148 2004/01/26 22:59:53 momjian Exp $
  *
  * NOTES
  *       some of the information in this file should be moved to
@@ -109,10 +109,14 @@ do { \
 #else
 #define PG_USLEEP(_usec) \
 do { \
-       Sleep(_usec < 500) ? 1 : (_usec+500)/ 1000); \
+       Sleep((_usec) < 500 ? 1 : ((_usec)+500)/ 1000); \
 } while(0)
 #endif
 
+#ifdef WIN32
+#define ftruncate(a,b) chsize(a,b)
+#endif
+
 /*****************************************************************************
  *       globals.h --                                                                                                                   *
  *****************************************************************************/
@@ -132,6 +136,7 @@ extern void ClosePostmasterPorts(bool pgstat_too);
 /*
  * from utils/init/globals.c
  */
+extern pid_t PostmasterPid;
 extern bool IsPostmasterEnvironment;
 extern bool IsUnderPostmaster;
 
index 6562aa93e8481a225bed5a4a9c8e58e745fbadd4..69cccb2b7a3290c0c09e1b3d9b1986dbf0a79bb9 100644 (file)
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.15 2004/01/26 22:54:58 momjian Exp $ */
+/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.16 2004/01/26 22:59:54 momjian Exp $ */
 
 /* undefine and redefine after #include */
 #undef mkdir
@@ -15,7 +15,7 @@
 #define NOFILE           100
 
 /* defines for dynamic linking on Win32 platform */
-#ifdef __CYGWIN__
+#if defined(__CYGWIN__) || defined(__MINGW32__)
 
 #if __GNUC__ && ! defined (__declspec)
 #error You need egcs 1.1 or newer for compiling!
@@ -27,7 +27,7 @@
 #define DLLIMPORT __declspec (dllimport)
 #endif
 
-#elif defined(WIN32) && defined(_MSC_VER)              /* not CYGWIN */
+#elif defined(WIN32) && defined(_MSC_VER)              /* not CYGWIN or MingW */
 
 #if defined(_DLL)
 #define DLLIMPORT __declspec (dllexport)
@@ -35,7 +35,7 @@
 #define DLLIMPORT __declspec (dllimport)
 #endif
 
-#else                                                  /* not CYGWIN, not MSVC */
+#else                                                  /* not CYGWIN, not MSVC, not MingW */
 
 #define DLLIMPORT
 #endif