Jorrit's ... "progress?"

This commit is contained in:
Jorrit Herder
2006-03-10 16:10:05 +00:00
parent 498e232a5c
commit 021e3234d8
35 changed files with 352 additions and 436 deletions

View File

@@ -133,12 +133,17 @@ PRIVATE void init_clock()
/* Initialize the CLOCK's interrupt hook. */
clock_hook.proc_nr_e = CLOCK;
/* Initialize channel 0 of the 8253A timer to, e.g., 60 Hz. */
/* Initialize channel 0 of the 8253A timer to, e.g., 60 Hz, and register
* the CLOCK task's interrupt handler to be run on every clock tick.
*/
outb(TIMER_MODE, SQUARE_WAVE); /* set timer to run continuously */
outb(TIMER0, TIMER_COUNT); /* load timer low byte */
outb(TIMER0, TIMER_COUNT >> 8); /* load timer high byte */
put_irq_handler(&clock_hook, CLOCK_IRQ, clock_handler);/* register handler */
put_irq_handler(&clock_hook, CLOCK_IRQ, clock_handler);
enable_irq(&clock_hook); /* ready for clock interrupts */
/* Set a watchdog timer to periodically balance the scheduling queues. */
balance_queues(NULL); /* side-effect sets new timer */
}
/*===========================================================================*
@@ -146,7 +151,7 @@ PRIVATE void init_clock()
*===========================================================================*/
PUBLIC void clock_stop()
{
/* Reset the clock to the BIOS rate. (For rebooting) */
/* Reset the clock to the BIOS rate. (For rebooting.) */
outb(TIMER_MODE, 0x36);
outb(TIMER0, 0);
outb(TIMER0, 0);

View File

@@ -7,24 +7,28 @@
#include <minix/com.h>
/* Masks and flags for system calls. */
#define SYSCALL_FUNC 0x0F /* mask for system call function */
#define SYSCALL_FLAGS 0xF0 /* mask for system call flags */
#define NON_BLOCKING 0x10 /* prevent blocking, return error */
#define SYSCALL_FUNC 0x00FF /* mask for system call function */
#define SYSCALL_FLAGS 0xFF00 /* mask for system call flags */
#define NON_BLOCKING 0x0100 /* do not block if target not ready */
/* System call numbers that are passed when trapping to the kernel. The
* numbers are carefully defined so that it can easily be seen (based on
* the bits that are on) which checks should be done in sys_call().
*/
#define SEND 1 /* 0 0 0 1 : blocking send */
#define RECEIVE 2 /* 0 0 1 0 : blocking receive */
#define SENDREC 3 /* 0 0 1 1 : SEND + RECEIVE */
#define NOTIFY 4 /* 0 1 0 0 : nonblocking notify */
#define ECHO 8 /* 1 0 0 0 : echo a message */
#define SEND 1 /* 0000 0001 : blocking send */
#define RECEIVE 2 /* 0000 0010 : blocking receive */
#define SENDREC 3 /* 0000 0011 : SEND + RECEIVE */
#define NOTIFY 4 /* 0000 0100 : nonblocking notify */
#define ECHO 8 /* 0000 1000 : echo a message */
#define IPC_REQUEST 0x10 /* 0001 0000 : blocking request */
#define IPC_REPLY 0x20 /* 0010 0000 : nonblocking reply */
#define IPC_NOTIFY 0x40 /* 0100 0000 : nonblocking notification */
#define IPC_RECEIVE 0x80 /* 1000 0000 : blocking receive */
/* The following bit masks determine what checks that should be done. */
#define CHECK_PTR 0x0B /* 1 0 1 1 : validate message buffer */
#define CHECK_DST 0x05 /* 0 1 0 1 : validate message destination */
#define CHECK_SRC 0x02 /* 0 0 1 0 : validate message source */
#define CHECK_DEADLOCK 0x03 /* 0 0 1 1 : check for deadlock */
#define CHECK_PTR 0xBB /* 1011 1011 : validate message buffer */
#define CHECK_DST 0x55 /* 0101 0101 : validate message destination */
#define CHECK_DEADLOCK 0x93 /* 1001 0011 : check for deadlock */
#endif /* IPC_H */

View File

@@ -203,11 +203,13 @@ int how;
* run their shutdown code, e.g, to synchronize the FS or to let the TTY
* switch to the first console.
*/
#if DEAD_CODE
kprintf("Sending SIGKSTOP to system processes ...\n");
for (rp=BEG_PROC_ADDR; rp<END_PROC_ADDR; rp++) {
if (!isemptyp(rp) && (priv(rp)->s_flags & SYS_PROC) && !iskernelp(rp))
send_sig(proc_nr(rp), SIGKSTOP);
}
#endif
/* Continue after 1 second, to give processes a chance to get scheduled to
* do shutdown work. Set a watchog timer to call shutdown(). The timer

View File

@@ -358,19 +358,20 @@ _p_s_call:
o16 push es
o16 push fs
o16 push gs
mov dx, ss
mov ds, dx
mov es, dx
incb (_k_reenter)
mov si, ss ! ss is kernel data segment
mov ds, si ! load rest of kernel segments
mov es, si ! kernel does not use fs, gs
incb (_k_reenter) ! increment kernel entry count
mov esi, esp ! assumes P_STACKBASE == 0
mov esp, k_stktop
xor ebp, ebp ! for stacktrace
! end of inline save
! now set up parameters for sys_call()
push edx ! event set or flags bit map
push ebx ! pointer to user message
push eax ! src/dest
push ecx ! SEND/RECEIVE/BOTH
call _sys_call ! sys_call(function, src_dest, m_ptr)
push eax ! source / destination
push ecx ! call number (ipc primitive to use)
call _sys_call ! sys_call(call_nr, src_dst, m_ptr, bit_map)
! caller is now explicitly in proc_ptr
mov AXREG(esi), eax ! sys_call MUST PRESERVE si

View File

@@ -43,13 +43,13 @@ struct priv {
struct far_mem s_farmem[NR_REMOTE_SEGS]; /* remote memory map */
reg_t *s_stack_guard; /* stack guard word for kernel tasks */
int s_nr_io_range;
int s_nr_io_range; /* allowed I/O ports */
struct io_range s_io_tab[NR_IO_RANGE];
int s_nr_mem_range;
int s_nr_mem_range; /* allowed memory ranges */
struct mem_range s_mem_tab[NR_MEM_RANGE];
int s_nr_irq;
int s_nr_irq; /* allowed IRQ lines */
int s_irq_tab[NR_IRQ];
};
@@ -57,15 +57,13 @@ struct priv {
#define STACK_GUARD ((reg_t) (sizeof(reg_t) == 2 ? 0xBEEF : 0xDEADBEEF))
/* Bits for the system property flags. */
#define PREEMPTIBLE 0x01 /* kernel tasks are not preemptible */
#define PREEMPTIBLE 0x02 /* kernel tasks are not preemptible */
#define BILLABLE 0x04 /* some processes are not billable */
#define SYS_PROC 0x10 /* system processes are privileged */
#define SENDREC_BUSY 0x20 /* sendrec() in progress */
#define CHECK_IO_PORT 0x40 /* Check whether an I/O request is allowed */
#define CHECK_MEM 0x80 /* Check whether a (vm) memory map request is
* allowed
*/
#define CHECK_IRQ 0x100 /* Check whether an IRQ can be used */
#define SYS_PROC 0x10 /* system processes have own priv structure */
#define CHECK_IO_PORT 0x20 /* check if I/O request is allowed */
#define CHECK_IRQ 0x40 /* check if IRQ can be used */
#define CHECK_MEM 0x80 /* check if (VM) mem map request is allowed */
/* Magic system structure table addresses. */
#define BEG_PRIV_ADDR (&priv[0])

View File

@@ -90,10 +90,11 @@ FORWARD _PROTOTYPE( void pick_proc, (void));
/*===========================================================================*
* sys_call *
*===========================================================================*/
PUBLIC int sys_call(call_nr, src_dst_e, m_ptr)
PUBLIC int sys_call(call_nr, src_dst_e, m_ptr, bit_map)
int call_nr; /* system call number and flags */
int src_dst_e; /* src to receive from or dst to send to */
message *m_ptr; /* pointer to message in the caller's space */
long bit_map; /* notification event set or flags */
{
/* System calls are done by trapping to the kernel with an INT instruction.
* The trap is caught and sys_call() is called to send or receive a message
@@ -195,7 +196,7 @@ message *m_ptr; /* pointer to message in the caller's space */
switch(function) {
case SENDREC:
/* A flag is set so that notifications cannot interrupt SENDREC. */
priv(caller_ptr)->s_flags |= SENDREC_BUSY;
caller_ptr->p_misc_flags |= REPLY_PENDING;
/* fall through */
case SEND:
result = mini_send(caller_ptr, src_dst_e, m_ptr, flags);
@@ -204,7 +205,7 @@ message *m_ptr; /* pointer to message in the caller's space */
} /* fall through for SENDREC */
case RECEIVE:
if (function == RECEIVE)
priv(caller_ptr)->s_flags &= ~SENDREC_BUSY;
caller_ptr->p_misc_flags &= ~REPLY_PENDING;
result = mini_receive(caller_ptr, src_dst_e, m_ptr, flags);
break;
case NOTIFY:
@@ -353,7 +354,7 @@ unsigned flags; /* system call flags */
if (!(caller_ptr->p_rts_flags & SENDING)) {
/* Check if there are pending notifications, except for SENDREC. */
if (! (priv(caller_ptr)->s_flags & SENDREC_BUSY)) {
if (! (caller_ptr->p_misc_flags & REPLY_PENDING)) {
map = &priv(caller_ptr)->s_notify_pending;
for (chunk=&map->chunk[0]; chunk<&map->chunk[NR_SYS_CHUNKS]; chunk++) {
@@ -430,9 +431,9 @@ int dst; /* which process to notify */
* can be both sending and receiving during a SENDREC system call.
*/
if ((dst_ptr->p_rts_flags & (RECEIVING|SENDING)) == RECEIVING &&
! (priv(dst_ptr)->s_flags & SENDREC_BUSY) &&
(dst_ptr->p_getfrom_e == ANY
|| dst_ptr->p_getfrom_e == caller_ptr->p_endpoint)) {
! (dst_ptr->p_misc_flags & REPLY_PENDING) &&
(dst_ptr->p_getfrom_e == ANY ||
dst_ptr->p_getfrom_e == caller_ptr->p_endpoint)) {
/* Destination is indeed waiting for a message. Assemble a notification
* message and deliver it. Copy from pseudo-source HARDWARE, since the
@@ -600,32 +601,17 @@ int *front; /* return: front or back */
* process must be added to one of the scheduling queues to decide where to
* insert it. As a side-effect the process' priority may be updated.
*/
static struct proc *prev_ptr = NIL_PROC; /* previous without time */
int time_left = (rp->p_ticks_left > 0); /* quantum fully consumed */
int penalty = 0; /* change in priority */
/* Check whether the process has time left. Otherwise give a new quantum
* and possibly raise the priority. Processes using multiple quantums
* in a row get a lower priority to catch infinite loops in high priority
* processes (system servers and drivers).
* and lower the process' priority, unless the process already is in the
* lowest queue.
*/
if ( ! time_left) { /* quantum consumed ? */
if (! time_left) { /* quantum consumed ? */
rp->p_ticks_left = rp->p_quantum_size; /* give new quantum */
if (prev_ptr == rp) penalty ++; /* catch infinite loops */
else penalty --; /* give slow way back */
prev_ptr = rp; /* store ptr for next */
}
/* Determine the new priority of this process. The bounds are determined
* by IDLE's queue and the maximum priority of this process. Kernel task
* and the idle process are never changed in priority.
*/
if (penalty != 0 && ! iskernelp(rp)) {
rp->p_priority += penalty; /* update with penalty */
if (rp->p_priority < rp->p_max_priority) /* check upper bound */
rp->p_priority=rp->p_max_priority;
else if (rp->p_priority > IDLE_Q-1) /* check lower bound */
rp->p_priority = IDLE_Q-1;
if (rp->p_priority < (IDLE_Q-1)) {
rp->p_priority += 1; /* lower priority */
}
}
/* If there is time left, the process is added to the front of its queue,
@@ -662,6 +648,47 @@ PRIVATE void pick_proc()
}
}
/*===========================================================================*
* balance_queues *
*===========================================================================*/
#define Q_BALANCE_TICKS 100
PUBLIC void balance_queues(tp)
timer_t *tp; /* watchdog timer pointer */
{
/* Check entire process table and give all process a higher priority. This
* effectively means giving a new quantum. If a process already is at its
* maximum priority, its quantum will be renewed.
*/
static timer_t queue_timer; /* timer structure to use */
register struct proc* rp; /* process table pointer */
clock_t next_period; /* time of next period */
int ticks_added = 0; /* total time added */
for (rp=BEG_PROC_ADDR; rp<END_PROC_ADDR; rp++) {
if (! isemptyp(rp)) { /* check slot use */
lock(5,"balance_queues");
if (rp->p_priority > rp->p_max_priority) { /* update priority? */
if (rp->p_rts_flags == 0) dequeue(rp); /* take off queue */
ticks_added += rp->p_quantum_size; /* do accounting */
rp->p_priority -= 1; /* raise priority */
if (rp->p_rts_flags == 0) enqueue(rp); /* put on queue */
}
else {
ticks_added += rp->p_quantum_size - rp->p_ticks_left;
rp->p_ticks_left = rp->p_quantum_size; /* give new quantum */
}
unlock(5);
}
}
kprintf("ticks_added: %d\n", ticks_added);
/* Now schedule a new watchdog timer to balance the queues again. The
* period depends on the total amount of quantum ticks added.
*/
next_period = MAX(Q_BALANCE_TICKS, ticks_added); /* calculate next */
set_timer(&queue_timer, get_uptime() + next_period, balance_queues);
}
/*===========================================================================*
* lock_send *
*===========================================================================*/
@@ -697,7 +724,7 @@ struct proc *rp; /* this process is no longer runnable */
{
/* Safe gateway to dequeue() for tasks. */
if (k_reenter >= 0) {
/* We're in an exception or interrupt, so don't lock (and..
/* We're in an exception or interrupt, so don't lock (and ...
* don't unlock).
*/
dequeue(rp);

View File

@@ -28,9 +28,8 @@ struct proc {
proc_nr_t p_nr; /* number of this process (for fast access) */
struct priv *p_priv; /* system privileges structure */
char p_rts_flags; /* SENDING, RECEIVING, etc. */
char p_misc_flags; /* Flags that do suspend the process */
short p_rts_flags; /* process is runnable only if zero */
short p_misc_flags; /* flags that do suspend the process */
char p_priority; /* current scheduling priority */
char p_max_priority; /* maximum scheduling priority */
@@ -63,15 +62,17 @@ struct proc {
/* Bits for the runtime flags. A process is runnable iff p_rts_flags == 0. */
#define SLOT_FREE 0x01 /* process slot is free */
#define NO_MAP 0x02 /* keeps unmapped forked child from running */
#define SENDING 0x04 /* process blocked trying to SEND */
#define RECEIVING 0x08 /* process blocked trying to RECEIVE */
#define SENDING 0x04 /* process blocked trying to send */
#define RECEIVING 0x08 /* process blocked trying to receive */
#define SIGNALED 0x10 /* set when new kernel signal arrives */
#define SIG_PENDING 0x20 /* unready while signal being processed */
#define P_STOP 0x40 /* set when process is being traced */
#define NO_PRIV 0x80 /* keep forked system process from running */
#define NO_PRIORITY 0x100 /* process has been stopped */
/* Misc flags */
#define MF_VM 0x01 /* Process uses VM */
#define REPLY_PENDING 0x01 /* reply to IPC_REQUEST is pending */
#define MF_VM 0x08 /* process uses VM */
/* Scheduling priorities for p_priority. Values must start at zero (highest
* priority) and increment. Priorities of the processes in the boot image

View File

@@ -24,11 +24,13 @@ _PROTOTYPE( void kprintf, (const char *fmt, ...) );
_PROTOTYPE( void panic, (_CONST char *s, int n) );
/* proc.c */
_PROTOTYPE( int sys_call, (int function, int src_dest, message *m_ptr) );
_PROTOTYPE( int sys_call, (int call_nr, int src_dst,
message *m_ptr, long bit_map) );
_PROTOTYPE( int lock_notify, (int src, int dst) );
_PROTOTYPE( int lock_send, (int dst, message *m_ptr) );
_PROTOTYPE( void lock_enqueue, (struct proc *rp) );
_PROTOTYPE( void lock_dequeue, (struct proc *rp) );
_PROTOTYPE( void balance_queues, (struct timer *tp) );
#if DEBUG_ENABLE_IPC_WARNINGS
_PROTOTYPE( int isokendpt_f, (char *file, int line, int e, int *p, int f));
#define isokendpt_d(e, p, f) isokendpt_f(__FILE__, __LINE__, (e), (p), (f))

View File

@@ -33,14 +33,8 @@ message *m_ptr; /* pointer to request message */
if (sig_nr > _NSIG) return(EINVAL);
if (iskerneln(proc_nr)) return(EPERM);
if (m_ptr->m_source == PM_PROC_NR) {
/* Directly send signal notification to a system process. */
if (! (priv(proc_addr(proc_nr))->s_flags & SYS_PROC)) return(EPERM);
send_sig(proc_nr, sig_nr);
} else {
/* Set pending signal to be processed by the PM. */
cause_sig(proc_nr, sig_nr);
}
/* Set pending signal to be processed by the PM. */
cause_sig(proc_nr, sig_nr);
return(OK);
}

View File

@@ -17,6 +17,7 @@
*===========================================================================*/
PUBLIC int do_nice(message *m_ptr)
{
/* Change process priority or stop the process. */
int proc_nr, pri, new_q ;
register struct proc *rp;
@@ -24,26 +25,36 @@ PUBLIC int do_nice(message *m_ptr)
if(!isokendpt(m_ptr->PR_ENDPT, &proc_nr)) return EINVAL;
if (iskerneln(proc_nr)) return(EPERM);
pri = m_ptr->PR_PRIORITY;
if (pri < PRIO_MIN || pri > PRIO_MAX) return(EINVAL);
/* The priority is currently between PRIO_MIN and PRIO_MAX. We have to
* scale this between MIN_USER_Q and MAX_USER_Q.
*/
new_q = MAX_USER_Q + (pri-PRIO_MIN) * (MIN_USER_Q-MAX_USER_Q+1) /
(PRIO_MAX-PRIO_MIN+1);
if (new_q < MAX_USER_Q) new_q = MAX_USER_Q; /* shouldn't happen */
if (new_q > MIN_USER_Q) new_q = MIN_USER_Q; /* shouldn't happen */
/* Make sure the process is not running while changing its priority; the
* max_priority is the base priority. Put the process back in its new
* queue if it is runnable.
*/
rp = proc_addr(proc_nr);
lock_dequeue(rp);
rp->p_max_priority = rp->p_priority = new_q;
if (! rp->p_rts_flags) lock_enqueue(rp);
return(OK);
if (pri == PRIO_STOP) {
/* Take process off the scheduling queues. */
lock_dequeue(rp);
rp->p_rts_flags |= NO_PRIORITY;
return(OK);
}
else if (pri >= PRIO_MIN && pri <= PRIO_MAX) {
/* The value passed in is currently between PRIO_MIN and PRIO_MAX.
* We have to scale this between MIN_USER_Q and MAX_USER_Q to match
* the kernel's scheduling queues.
*/
new_q = MAX_USER_Q + (pri-PRIO_MIN) * (MIN_USER_Q-MAX_USER_Q+1) /
(PRIO_MAX-PRIO_MIN+1);
if (new_q < MAX_USER_Q) new_q = MAX_USER_Q; /* shouldn't happen */
if (new_q > MIN_USER_Q) new_q = MIN_USER_Q; /* shouldn't happen */
/* Make sure the process is not running while changing its priority.
* Put the process back in its new queue if it is runnable.
*/
lock_dequeue(rp);
rp->p_max_priority = rp->p_priority = new_q;
if (! rp->p_rts_flags) lock_enqueue(rp);
return(OK);
}
return(EINVAL);
}
#endif /* USE_NICE */

View File

@@ -81,8 +81,7 @@ PUBLIC char *t_stack[TOT_STACK_SPACE / sizeof(char *)];
#define DS_C ~0
#define PM_C ~(c(SYS_DEVIO) | c(SYS_SDEVIO) | c(SYS_VDEVIO) | c(SYS_IRQCTL) | c(SYS_INT86))
#define FS_C (c(SYS_KILL) | c(SYS_VIRCOPY) | c(SYS_VIRVCOPY) | c(SYS_UMAP) | c(SYS_GETINFO) | c(SYS_EXIT) | c(SYS_TIMES) | c(SYS_SETALARM))
#define DRV_C (FS_C | c(SYS_SEGCTL) | c(SYS_IRQCTL) | c(SYS_INT86) | c(SYS_DEVIO) | c(SYS_VDEVIO) | c(SYS_SDEVIO))
#define PCI_C (c(SYS_VIRCOPY) | c(SYS_DEVIO) | c(SYS_VDEVIO) | c(SYS_SDEVIO) | c(SYS_PRIVCTL) | c(SYS_GETINFO))
#define DRV_C (FS_C | c(SYS_SEGCTL) | c(SYS_IRQCTL) | c(SYS_INT86) | c(SYS_DEVIO) | c(SYS_SDEVIO) | c(SYS_VDEVIO))
#define TTY_C (DRV_C | c(SYS_ABORT) | c(SYS_VM_MAP) | c(SYS_IOPENABLE))
#define MEM_C (DRV_C | c(SYS_PHYSCOPY) | c(SYS_PHYSVCOPY) | c(SYS_VM_MAP) | \
c(SYS_IOPENABLE))
@@ -90,27 +89,26 @@ PUBLIC char *t_stack[TOT_STACK_SPACE / sizeof(char *)];
/* The system image table lists all programs that are part of the boot image.
* The order of the entries here MUST agree with the order of the programs
* in the boot image and all kernel tasks must come first.
* Each entry provides the process number, flags, quantum size (qs), scheduling
*
* Each entry provides the process number, flags, quantum size, scheduling
* queue, allowed traps, ipc mask, and a name for the process table. The
* initial program counter and stack size is also provided for kernel tasks.
*
* Note: the quantum size must be positive in all cases!
*/
PUBLIC struct boot_image image[] = {
/* process nr, pc, flags, qs, queue, stack, traps, ipcto, call, name */
{ IDLE, idle_task, IDL_F, 8, IDLE_Q, IDL_S, 0, 0, 0, "IDLE" },
{ CLOCK,clock_task, TSK_F, 0, TASK_Q, TSK_S, TSK_T, 0, 0, "CLOCK" },
{ SYSTEM, sys_task, TSK_F, 0, TASK_Q, TSK_S, TSK_T, 0, 0, "SYSTEM"},
{ HARDWARE, 0, TSK_F, 0, TASK_Q, HRD_S, 0, 0, 0, "KERNEL"},
{ IDLE, idle_task, IDL_F, 8, IDLE_Q, IDL_S, 0, 0, 0, "idle" },
{ CLOCK,clock_task, TSK_F, 8, TASK_Q, TSK_S, TSK_T, 0, 0, "clock" },
{ SYSTEM, sys_task, TSK_F, 8, TASK_Q, TSK_S, TSK_T, 0, 0, "system"},
{ HARDWARE, 0, TSK_F, 8, TASK_Q, HRD_S, 0, 0, 0, "kernel"},
{ PM_PROC_NR, 0, SRV_F, 32, 3, 0, SRV_T, SRV_M, PM_C, "pm" },
{ FS_PROC_NR, 0, SRV_F, 32, 4, 0, SRV_T, SRV_M, FS_C, "fs" },
{ RS_PROC_NR, 0, SRV_F, 4, 3, 0, SRV_T, SYS_M, RS_C, "rs" },
{ DS_PROC_NR, 0, SRV_F, 4, 3, 0, SRV_T, SYS_M, DS_C, "ds" },
{ TTY_PROC_NR, 0, SRV_F, 4, 1, 0, SRV_T, SYS_M, TTY_C, "tty" },
{ MEM_PROC_NR, 0, SRV_F, 4, 2, 0, SRV_T, SYS_M, MEM_C, "memory"},
{ MEM_PROC_NR, 0, SRV_F, 4, 2, 0, SRV_T, SYS_M, MEM_C, "mem" },
{ LOG_PROC_NR, 0, SRV_F, 4, 2, 0, SRV_T, SYS_M, DRV_C, "log" },
#if 0
{ DRVR_PROC_NR, 0, SRV_F, 4, 2, 0, SRV_T, SYS_M, DRV_C, "driver"},
{ PCI_PROC_NR, 0, SRV_F, 4, 2, 0, SRV_T, SYS_M, PCI_C, "pci"},
#endif
{ INIT_PROC_NR, 0, USR_F, 8, USER_Q, 0, USR_T, USR_M, 0, "init" },
};