Subject: pthread_{suspend,resume}_np
To: None <tech-kern@netbsd.org>
From: Christos Zoulas <christos@zoulas.com>
List: tech-kern
Date: 08/10/2003 19:44:01
Hello,

I need pthread_{suspend,resume}_np for java. I took a stab at their
implementation, but I am missing something because sometimes I get
an assertion failure in pthread__sched_bulk() where qhead == head of
runq. Any ideas?

christos

Index: pthread.c
===================================================================
RCS file: /cvsroot/src/lib/libpthread/pthread.c,v
retrieving revision 1.28
diff -u -u -r1.28 pthread.c
--- pthread.c	2003/07/21 22:24:09	1.28
+++ pthread.c	2003/08/10 23:39:42
@@ -70,6 +70,8 @@
 pthread_spin_t pthread__deadqueue_lock;
 struct pthread_queue_t pthread__deadqueue;
 struct pthread_queue_t pthread__reidlequeue;
+pthread_spin_t pthread__suspqueue_lock;
+struct pthread_queue_t pthread__suspqueue;
 
 static int nthreads;
 static int nextthread;
@@ -354,8 +356,11 @@
 	pthread_spinunlock(self, &pthread__allqueue_lock);
 
 	SDPRINTF(("(pthread_create %p) Created new thread %p (name pointer %p).\n", self, newthread, newthread->pt_name));
-	/* 6. Put on run queue. */
-	pthread__sched(self, newthread);
+	/* 6. Put on appropriate queue. */
+	if (newthread->pt_flags & PT_FLAG_SUSPENDED)
+		pthread__suspend(self, newthread);
+	else
+		pthread__sched(self, newthread);
 
 	*thread = newthread;
 
@@ -376,6 +381,57 @@
 	pthread__abort();
 }
 
+int
+pthread_suspend_np(pthread_t thread)
+{
+	pthread_t self = pthread__self();
+	if (self == thread) {
+		fprintf(stderr, "suspend_np: can't suspend self\n");
+		return EDEADLK;
+	}
+	pthread_spinlock(self, &thread->pt_statelock);
+	switch (thread->pt_state) {
+	case PT_STATE_RUNNING:
+		pthread__abort();	/* XXX */
+		break;
+	case PT_STATE_SUSPENDED:
+		pthread_spinunlock(self, &thread->pt_statelock);
+		return 0;
+	case PT_STATE_RUNNABLE:
+		pthread_spinlock(self, &pthread__runqueue_lock);
+		PTQ_REMOVE(&pthread__runqueue, thread, pt_runq);
+		pthread_spinunlock(self, &pthread__runqueue_lock);
+		break;
+	case PT_STATE_BLOCKED_QUEUE:
+		pthread_spinlock(self, thread->pt_sleeplock);
+		PTQ_REMOVE(thread->pt_sleepq, thread, pt_sleep);
+		pthread_spinunlock(self, thread->pt_sleeplock);
+		break;
+	case PT_STATE_BLOCKED_SYS:
+		break;
+	default:
+		break;			/* XXX */
+	}
+	pthread__suspend(self, thread);
+	pthread_spinunlock(self, &thread->pt_statelock);
+	return 0;
+}
+
+int
+pthread_resume_np(pthread_t thread)
+{
+	pthread_t self = pthread__self();
+	pthread_spinlock(self, &thread->pt_statelock);
+	if (thread->pt_state == PT_STATE_SUSPENDED) {
+		pthread_spinlock(self, &pthread__suspqueue_lock);
+		PTQ_REMOVE(&pthread__suspqueue, thread, pt_runq);
+		pthread_spinunlock(self, &pthread__suspqueue_lock);
+		pthread__sched(self, thread);
+	}
+	pthread_spinunlock(self, &thread->pt_statelock);
+	return 0;
+}
+
 
 /*
  * Other threads will switch to the idle thread so that they
Index: pthread.h
===================================================================
RCS file: /cvsroot/src/lib/libpthread/pthread.h,v
retrieving revision 1.14
diff -u -u -r1.14 pthread.h
--- pthread.h	2003/07/18 22:01:47	1.14
+++ pthread.h	2003/08/10 23:39:42
@@ -119,6 +119,10 @@
 int	pthread_getname_np(pthread_t, char *, size_t);
 int	pthread_setname_np(pthread_t, const char *, void *);
 
+int 	pthread_attr_setcreatesuspend_np(pthread_attr_t *);
+int	pthread_suspend_np(pthread_t);
+int	pthread_resume_np(pthread_t);
+
 struct pthread_cleanup_store {
 	void	*pad[4];
 };
Index: pthread_int.h
===================================================================
RCS file: /cvsroot/src/lib/libpthread/pthread_int.h,v
retrieving revision 1.17
diff -u -u -r1.17 pthread_int.h
--- pthread_int.h	2003/07/21 22:21:07	1.17
+++ pthread_int.h	2003/08/10 23:39:42
@@ -177,6 +177,7 @@
 #define PT_THREAD_IDLE		3
 
 /* Thread states */
+#define PT_STATE_NEWBORN	0
 #define PT_STATE_RUNNING	1
 #define PT_STATE_RUNNABLE	2
 #define PT_STATE_BLOCKED_SYS	3
@@ -184,6 +185,7 @@
 #define PT_STATE_ZOMBIE		5
 #define PT_STATE_DEAD		6
 #define PT_STATE_RECYCLABLE	7
+#define PT_STATE_SUSPENDED	8
 
 /* Flag values */
 
@@ -195,6 +197,7 @@
 #define PT_FLAG_SIGDEFERRED     0x0020	/* There are signals to take */
 #define PT_FLAG_SCOPE_SYSTEM	0x0040
 #define PT_FLAG_EXPLICIT_SCHED	0x0080
+#define	PT_FLAG_SUSPENDED	0x0100	/* In the suspended queue */
 
 #define PT_MAGIC	0x11110001
 #define PT_DEAD		0xDEAD0001
@@ -229,6 +232,8 @@
 
 /* Go do something else. Don't go back on the run queue */
 void	pthread__block(pthread_t self, pthread_spin_t* queuelock);
+/* Put a thread back on the suspended queue */
+void	pthread__suspend(pthread_t self, pthread_t thread);
 /* Put a thread back on the run queue */
 void	pthread__sched(pthread_t self, pthread_t thread);
 void	pthread__sched_sleepers(pthread_t self, struct pthread_queue_t *threadq);
Index: pthread_run.c
===================================================================
RCS file: /cvsroot/src/lib/libpthread/pthread_run.c,v
retrieving revision 1.11
diff -u -u -r1.11 pthread_run.c
--- pthread_run.c	2003/06/26 01:26:39	1.11
+++ pthread_run.c	2003/08/10 23:39:42
@@ -54,6 +54,9 @@
 extern struct pthread_queue_t pthread__runqueue;
 extern struct pthread_queue_t pthread__idlequeue;
 
+extern pthread_spin_t pthread__suspqueue_lock;
+extern struct pthread_queue_t pthread__suspqueue;
+
 extern pthread_spin_t pthread__deadqueue_lock;
 extern struct pthread_queue_t pthread__reidlequeue;
 
@@ -128,6 +131,20 @@
 	return next;
 }
 
+
+/* Put a thread on the suspended queue */
+void
+pthread__suspend(pthread_t self, pthread_t thread)
+{
+
+	SDPRINTF(("(sched %p) suspending %p\n", self, thread));
+	pthread__assert(thread->pt_type == PT_THREAD_NORMAL);
+	pthread__assert(thread->pt_spinlocks == 0);
+	pthread_spinlock(self, &pthread__suspqueue_lock);
+	thread->pt_state = PT_STATE_SUSPENDED;
+	PTQ_INSERT_TAIL(&pthread__suspqueue, thread, pt_runq);
+	pthread_spinunlock(self, &pthread__suspqueue_lock);
+}
 
 /* Put a thread back on the run queue */
 void
Index: pthread_sig.c
===================================================================
RCS file: /cvsroot/src/lib/libpthread/pthread_sig.c,v
retrieving revision 1.16
diff -u -u -r1.16 pthread_sig.c
--- pthread_sig.c	2003/07/21 22:24:09	1.16
+++ pthread_sig.c	2003/08/10 23:39:43
@@ -72,6 +72,9 @@
 extern pthread_spin_t pthread__allqueue_lock;
 extern struct pthread_queue_t pthread__allqueue;
 
+extern pthread_spin_t pthread__suspqueue_lock;
+extern struct pthread_queue_t pthread__suspqueue;
+
 static pthread_spin_t	pt_sigacts_lock;
 static struct sigaction pt_sigacts[_NSIG];
 
@@ -762,6 +765,11 @@
 	 */
 	pthread_spinlock(self, &target->pt_statelock);
 	switch (target->pt_state) {
+	case PT_STATE_SUSPENDED:
+		pthread_spinlock(self, &pthread__suspqueue_lock);
+		PTQ_REMOVE(&pthread__suspqueue, target, pt_runq);
+		pthread_spinunlock(self, &pthread__suspqueue_lock);
+		break;
 	case PT_STATE_RUNNABLE:
 		pthread_spinlock(self, &pthread__runqueue_lock);
 		PTQ_REMOVE(&pthread__runqueue, target, pt_runq);