--- a/sem_destroy.c
+++ b/sem_destroy.c
@@ -82,53 +82,51 @@
   else
     {
       s = *sem;
-      *sem = NULL;
 
-      if ((result = pthread_mutex_trylock (&s->lock)) == 0)
+      if ((result = pthread_mutex_lock (&s->lock)) == 0)
         {
-          if (s->value >= 0)
+          if (s->value < 0)
             {
               (void) pthread_mutex_unlock (&s->lock);
+              result = EBUSY;
+            }
+          else
+            {
+              /* There are no threads currently blocked on this semaphore. */
 
               if (!CloseHandle (s->sem))
 	        {
-	          *sem = s;
+                  (void) pthread_mutex_unlock (&s->lock);
 	          result = EINVAL;
 	        }
-              else if ((result = pthread_mutex_destroy (&s->lock)) != 0)
-                {
+	      else
+	        {
+                  /*
+                   * Invalidate the semaphore handle when we have the lock.
+                   * Other sema operations should test this after acquiring the lock
+                   * to check that the sema is still valid, i.e. before performing any
+                   * operations. This may only be necessary before the sema op routine
+                   * returns so that the routine can return EINVAL - e.g. if setting
+                   * s->value to SEM_VALUE_MAX below does force a fall-through.
+                   */
+                  *sem = NULL;
 
-#ifdef NEED_SEM
-		  s->sem = CreateEvent (NULL,
-					PTW32_FALSE,    /* manual reset is false */
-					PTW32_FALSE,    /* initial state is unset */
-					NULL);
-#else
-                  s->sem = CreateSemaphore (NULL,      /* Always NULL */
-                                            (long) 0,  /* Force threads to wait */
-                                            (long) _POSIX_SEM_VALUE_MAX,       /* Maximum value */
-                                            NULL);     /* Name */
-#endif
+                  /* Prevent anyone else actually waiting on or posting this sema.
+                   */
+                  s->value = SEM_VALUE_MAX;
 
-                  if (s->sem == 0)
+                  (void) pthread_mutex_unlock (&s->lock);
+
+                  do
                     {
-                      /* We just have to pretend that we've destroyed the semaphore
-                       * even though we're leaving a mutex around.
+                      /* Give other threads a chance to run and exit any sema op
+                       * routines. Due to the SEM_VALUE_MAX value, if sem_post or
+                       * sem_wait were blocked by us they should fall through.
                        */
-                      result = 0;
+                      Sleep(0);
                     }
-                  else
-                    {
-                      *sem = s;
-                      if (result != EBUSY)
-                        result = EINVAL;
-                    }
+                  while (pthread_mutex_destroy (&s->lock) == EBUSY);
                 }
-            }
-          else
-            {
-              (void) pthread_mutex_unlock (&s->lock);
-              result = EBUSY;
             }
         }
     }