1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <sys/proc.h>
30
31/*
32 * Install process context ops for the current process.
33 */
34void
35installpctx(
36	proc_t *p,
37	void	*arg,
38	void	(*save)(void *),
39	void	(*restore)(void *),
40	void	(*fork)(void *, void *),
41	void	(*exit)(void *),
42	void	(*free)(void *, int))
43{
44	struct pctxop *pctx;
45
46	pctx = kmem_alloc(sizeof (struct pctxop), KM_SLEEP);
47	pctx->save_op = save;
48	pctx->restore_op = restore;
49	pctx->fork_op = fork;
50	pctx->exit_op = exit;
51	pctx->free_op = free;
52	pctx->arg = arg;
53	pctx->next = p->p_pctx;
54	p->p_pctx = pctx;
55}
56
57/*
58 * Remove a process context ops from the current process.
59 */
60int
61removepctx(
62	proc_t *p,
63	void	*arg,
64	void	(*save)(void *),
65	void	(*restore)(void *),
66	void	(*fork)(void *, void *),
67	void	(*exit)(void *),
68	void	(*free)(void *, int))
69{
70	struct pctxop *pctx, *prev_pctx;
71
72	prev_pctx = NULL;
73	for (pctx = p->p_pctx; pctx != NULL; pctx = pctx->next) {
74		if (pctx->save_op == save && pctx->restore_op == restore &&
75		    pctx->fork_op == fork &&
76		    pctx->exit_op == exit && pctx->free_op == free &&
77		    pctx->arg == arg) {
78			if (prev_pctx)
79				prev_pctx->next = pctx->next;
80			else
81				p->p_pctx = pctx->next;
82			if (pctx->free_op != NULL)
83				(pctx->free_op)(pctx->arg, 0);
84			kmem_free(pctx, sizeof (struct pctxop));
85			return (1);
86		}
87		prev_pctx = pctx;
88	}
89	return (0);
90}
91
92void
93savepctx(proc_t *p)
94{
95	struct pctxop *pctx;
96
97	ASSERT(p == curthread->t_procp);
98	for (pctx = p->p_pctx; pctx != 0; pctx = pctx->next)
99		if (pctx->save_op != NULL)
100			(pctx->save_op)(pctx->arg);
101}
102
103void
104restorepctx(proc_t *p)
105{
106	struct pctxop *pctx;
107
108	ASSERT(p == curthread->t_procp);
109	for (pctx = p->p_pctx; pctx != 0; pctx = pctx->next)
110		if (pctx->restore_op != NULL)
111			(pctx->restore_op)(pctx->arg);
112}
113
114void
115forkpctx(proc_t *p, proc_t *cp)
116{
117	struct pctxop *pctx;
118
119	for (pctx = p->p_pctx; pctx != NULL; pctx = pctx->next)
120		if (pctx->fork_op != NULL)
121			(pctx->fork_op)(p, cp);
122}
123
124/*
125 * exitpctx is called during thread/lwp exit to perform any actions
126 * needed when an LWP in the process leaves the processor for the last
127 * time. This routine is not intended to deal with freeing memory; freepctx()
128 * is used for that purpose during proc_exit(). This routine is provided to
129 * allow for clean-up that can't wait until thread_free().
130 */
131void
132exitpctx(proc_t *p)
133{
134	struct pctxop *pctx;
135
136	for (pctx = p->p_pctx; pctx != NULL; pctx = pctx->next)
137		if (pctx->exit_op != NULL)
138			(pctx->exit_op)(p);
139}
140
141/*
142 * freepctx is called from proc_exit() to get rid of the actual context ops.
143 */
144void
145freepctx(proc_t *p, int isexec)
146{
147	struct pctxop *pctx;
148
149	while ((pctx = p->p_pctx) != NULL) {
150		p->p_pctx = pctx->next;
151		if (pctx->free_op != NULL)
152			(pctx->free_op)(pctx->arg, isexec);
153		kmem_free(pctx, sizeof (struct pctxop));
154	}
155}
156