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 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
26 */
27
28 #include <sys/proc.h>
29 #include <sys/cpuvar.h>
30 #include <sys/disp.h>
31
32 /*
33 * Install process context ops for the current process.
34 */
35 void
installpctx(proc_t * p,void * arg,void (* save)(void *),void (* restore)(void *),void (* fork)(void *,void *),void (* exit)(void *),void (* free)(void *,int))36 installpctx(
37 proc_t *p,
38 void *arg,
39 void (*save)(void *),
40 void (*restore)(void *),
41 void (*fork)(void *, void *),
42 void (*exit)(void *),
43 void (*free)(void *, int))
44 {
45 struct pctxop *pctx;
46
47 pctx = kmem_alloc(sizeof (struct pctxop), KM_SLEEP);
48 pctx->save_op = save;
49 pctx->restore_op = restore;
50 pctx->fork_op = fork;
51 pctx->exit_op = exit;
52 pctx->free_op = free;
53 pctx->arg = arg;
54 pctx->next = p->p_pctx;
55 p->p_pctx = pctx;
56 }
57
58 /*
59 * Remove a process context ops from the current process.
60 */
61 int
removepctx(proc_t * p,void * arg,void (* save)(void *),void (* restore)(void *),void (* fork)(void *,void *),void (* exit)(void *),void (* free)(void *,int))62 removepctx(
63 proc_t *p,
64 void *arg,
65 void (*save)(void *),
66 void (*restore)(void *),
67 void (*fork)(void *, void *),
68 void (*exit)(void *),
69 void (*free)(void *, int))
70 {
71 struct pctxop *pctx, *prev_pctx;
72
73 prev_pctx = NULL;
74 kpreempt_disable();
75 for (pctx = p->p_pctx; pctx != NULL; pctx = pctx->next) {
76 if (pctx->save_op == save && pctx->restore_op == restore &&
77 pctx->fork_op == fork &&
78 pctx->exit_op == exit && pctx->free_op == free &&
79 pctx->arg == arg) {
80 if (prev_pctx)
81 prev_pctx->next = pctx->next;
82 else
83 p->p_pctx = pctx->next;
84 if (pctx->free_op != NULL)
85 (pctx->free_op)(pctx->arg, 0);
86 kmem_free(pctx, sizeof (struct pctxop));
87 kpreempt_enable();
88 return (1);
89 }
90 prev_pctx = pctx;
91 }
92 kpreempt_enable();
93 return (0);
94 }
95
96 void
savepctx(proc_t * p)97 savepctx(proc_t *p)
98 {
99 struct pctxop *pctx;
100
101 ASSERT(p == curthread->t_procp);
102 for (pctx = p->p_pctx; pctx != 0; pctx = pctx->next)
103 if (pctx->save_op != NULL)
104 (pctx->save_op)(pctx->arg);
105 }
106
107 void
restorepctx(proc_t * p)108 restorepctx(proc_t *p)
109 {
110 struct pctxop *pctx;
111
112 ASSERT(p == curthread->t_procp);
113 for (pctx = p->p_pctx; pctx != 0; pctx = pctx->next)
114 if (pctx->restore_op != NULL)
115 (pctx->restore_op)(pctx->arg);
116 }
117
118 void
forkpctx(proc_t * p,proc_t * cp)119 forkpctx(proc_t *p, proc_t *cp)
120 {
121 struct pctxop *pctx;
122
123 for (pctx = p->p_pctx; pctx != NULL; pctx = pctx->next)
124 if (pctx->fork_op != NULL)
125 (pctx->fork_op)(p, cp);
126 }
127
128 /*
129 * exitpctx is called during thread/lwp exit to perform any actions
130 * needed when an LWP in the process leaves the processor for the last
131 * time. This routine is not intended to deal with freeing memory; freepctx()
132 * is used for that purpose during proc_exit(). This routine is provided to
133 * allow for clean-up that can't wait until thread_free().
134 */
135 void
exitpctx(proc_t * p)136 exitpctx(proc_t *p)
137 {
138 struct pctxop *pctx;
139
140 for (pctx = p->p_pctx; pctx != NULL; pctx = pctx->next)
141 if (pctx->exit_op != NULL)
142 (pctx->exit_op)(p);
143 }
144
145 /*
146 * freepctx is called from proc_exit() to get rid of the actual context ops.
147 */
148 void
freepctx(proc_t * p,int isexec)149 freepctx(proc_t *p, int isexec)
150 {
151 struct pctxop *pctx;
152
153 kpreempt_disable();
154 while ((pctx = p->p_pctx) != NULL) {
155 p->p_pctx = pctx->next;
156 if (pctx->free_op != NULL)
157 (pctx->free_op)(pctx->arg, isexec);
158 kmem_free(pctx, sizeof (struct pctxop));
159 }
160 kpreempt_enable();
161 }
162