source: mainline/uspace/app/kio/kio.c@ d5b37b6

Last change on this file since d5b37b6 was d5b37b6, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 months ago

Use a new syscall, SYS_KIO_READ, for reading from KIO buffer

Originally, the buffer memory was shared between kernel and
uspace, presumably to avoid the overhead of syscalls.
However, this makes synchronization with kernel impossible,
so it is not possible to ensure it works reliably without
random glitches. Also, relative to everything else /app/kio
does with the data, the syscall overhead is positively tiny.

  • Property mode set to 100644
File size: 5.3 KB
Line 
1/*
2 * Copyright (c) 2006 Ondrej Palkovsky
3 * Copyright (c) 2025 Jiří Zárevúcky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup kio
31 * @{
32 */
33/**
34 * @file
35 */
36
37#include <_bits/decls.h>
38#include <libarch/config.h>
39#include <stdio.h>
40#include <async.h>
41#include <as.h>
42#include <ddi.h>
43#include <errno.h>
44#include <str_error.h>
45#include <io/kio.h>
46#include <sysinfo.h>
47#include <stdlib.h>
48#include <fibril_synch.h>
49#include <adt/list.h>
50#include <adt/prodcons.h>
51#include <tinput.h>
52#include <uchar.h>
53#include <vfs/vfs.h>
54
55#define NAME "kio"
56#define LOG_FNAME "/log/kio"
57
58/* Producer/consumer buffers */
59typedef struct {
60 link_t link;
61 size_t length;
62 char32_t *data;
63} item_t;
64
65static prodcons_t pc;
66
67/* Notification mutex */
68static FIBRIL_MUTEX_INITIALIZE(mtx);
69
70#define READ_BUFFER_SIZE (PAGE_SIZE / sizeof(char32_t))
71
72static size_t current_at;
73static char32_t read_buffer[READ_BUFFER_SIZE];
74
75/** Klog producer
76 *
77 * Copies the contents of a character buffer to local
78 * producer/consumer queue.
79 *
80 * @param length Number of characters to copy.
81 * @param data Pointer to the kernel kio buffer.
82 *
83 */
84static void producer(size_t length, char32_t *data)
85{
86 item_t *item = (item_t *) malloc(sizeof(item_t));
87 if (item == NULL)
88 return;
89
90 size_t sz = sizeof(char32_t) * length;
91 char32_t *buf = (char32_t *) malloc(sz);
92 if (buf == NULL) {
93 free(item);
94 return;
95 }
96
97 memcpy(buf, data, sz);
98
99 link_initialize(&item->link);
100 item->length = length;
101 item->data = buf;
102 prodcons_produce(&pc, &item->link);
103}
104
105/** Klog consumer
106 *
107 * Waits in an infinite loop for the character data created by
108 * the producer and outputs them to stdout and optionally into
109 * a file.
110 *
111 * @param data Unused.
112 *
113 * @return Always EOK (unreachable).
114 *
115 */
116static errno_t consumer(void *data)
117{
118 FILE *log = fopen(LOG_FNAME, "a");
119 if (log == NULL)
120 printf("%s: Unable to create log file %s (%s)\n", NAME, LOG_FNAME,
121 str_error(errno));
122
123 while (true) {
124 link_t *link = prodcons_consume(&pc);
125 item_t *item = list_get_instance(link, item_t, link);
126
127 for (size_t i = 0; i < item->length; i++)
128 putuchar(item->data[i]);
129
130 if (log != NULL) {
131 for (size_t i = 0; i < item->length; i++)
132 fputuc(item->data[i], log);
133
134 fflush(log);
135 vfs_sync(fileno(log));
136 }
137
138 free(item->data);
139 free(item);
140 }
141
142 fclose(log);
143 return EOK;
144}
145
146/** Kernel notification handler
147 *
148 * Receives kernel kio notifications.
149 *
150 * @param call IPC call structure
151 * @param arg Local argument
152 *
153 */
154static void kio_notification_handler(ipc_call_t *call, void *arg)
155{
156 size_t kio_written = (size_t) ipc_get_arg1(call);
157
158 /*
159 * Make sure we process only a single notification
160 * at any time to limit the chance of the consumer
161 * starving.
162 */
163
164 fibril_mutex_lock(&mtx);
165
166 while (current_at != kio_written) {
167 size_t read = kio_read(read_buffer, READ_BUFFER_SIZE, current_at);
168 if (read == 0)
169 break;
170
171 current_at += read;
172
173 if (read > READ_BUFFER_SIZE) {
174 /* We missed some data. */
175 // TODO: Send a message with the number of lost characters to the consumer.
176 read = READ_BUFFER_SIZE;
177 }
178
179 producer(read, read_buffer);
180 }
181
182 async_event_unmask(EVENT_KIO);
183 fibril_mutex_unlock(&mtx);
184}
185
186int main(int argc, char *argv[])
187{
188 prodcons_initialize(&pc);
189 errno_t rc = async_event_subscribe(EVENT_KIO, kio_notification_handler, NULL);
190 if (rc != EOK) {
191 fprintf(stderr, "%s: Unable to register kio notifications\n",
192 NAME);
193 return rc;
194 }
195
196 fid_t fid = fibril_create(consumer, NULL);
197 if (!fid) {
198 fprintf(stderr, "%s: Unable to create consumer fibril\n",
199 NAME);
200 return ENOMEM;
201 }
202
203 tinput_t *input = tinput_new();
204 if (!input) {
205 fprintf(stderr, "%s: Could not create input\n", NAME);
206 return ENOMEM;
207 }
208
209 fibril_add_ready(fid);
210 async_event_unmask(EVENT_KIO);
211 kio_update();
212
213 tinput_set_prompt(input, "kio> ");
214
215 char *str;
216 while ((rc = tinput_read(input, &str)) == EOK) {
217 if (str_cmp(str, "") == 0) {
218 free(str);
219 continue;
220 }
221
222 kio_command(str, str_size(str));
223 free(str);
224 }
225
226 if (rc == ENOENT)
227 rc = EOK;
228
229 return EOK;
230}
231
232/** @}
233 */
Note: See TracBrowser for help on using the repository browser.