Changeset 03362fbd in mainline for uspace/lib/c/generic
- Timestamp:
- 2013-02-09T23:14:45Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 22dfd38
- Parents:
- b5d2e57 (diff), 005b765 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - Location:
- uspace/lib/c/generic
- Files:
-
- 16 added
- 1 deleted
- 25 edited
- 2 moved
-
adt/hash_set.c (deleted)
-
adt/hash_table.c (modified) (7 diffs)
-
adt/list.c (modified) (1 diff)
-
async.c (modified) (22 diffs)
-
bd.c (added)
-
bd_srv.c (added)
-
ddi.c (modified) (6 diffs)
-
device/battery_dev.c (added)
-
device/clock_dev.c (moved) (moved from kernel/arch/arm32/include/mach/testarm/testarm.h ) (2 diffs)
-
device/graph_dev.c (added)
-
devman.c (modified) (1 diff)
-
dlfcn.c (modified) (2 diffs)
-
double_to_str.c (added)
-
fibril.c (modified) (6 diffs)
-
fibril_synch.c (modified) (1 diff)
-
ieee_double.c (added)
-
io/chargrid.c (moved) (moved from uspace/lib/fb/screenbuffer.c ) (25 diffs)
-
io/con_srv.c (added)
-
io/console.c (modified) (3 diffs)
-
io/input.c (added)
-
io/io.c (modified) (1 diff)
-
io/klog.c (modified) (3 diffs)
-
io/log.c (modified) (2 diffs)
-
io/logctl.c (added)
-
io/output.c (added)
-
io/printf_core.c (modified) (12 diffs)
-
io/visualizer.c (added)
-
io/window.c (added)
-
ipc.c (modified) (4 diffs)
-
iplink_srv.c (modified) (1 diff)
-
loc.c (modified) (1 diff)
-
malloc.c (modified) (11 diffs)
-
pio_trace.c (added)
-
power_of_ten.c (added)
-
private/async.h (modified) (1 diff)
-
private/power_of_ten.h (added)
-
stack.c (added)
-
stdlib.c (modified) (1 diff)
-
str.c (modified) (7 diffs)
-
sysinfo.c (modified) (1 diff)
-
task.c (modified) (3 diffs)
-
thread.c (modified) (3 diffs)
-
time.c (modified) (8 diffs)
-
tls.c (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/adt/hash_table.c
rb5d2e57 r03362fbd 1 1 /* 2 2 * Copyright (c) 2008 Jakub Jermar 3 * Copyright (c) 2012 Adam Hraska 4 * 3 5 * All rights reserved. 4 6 * … … 34 36 35 37 /* 36 * This is an implementation of generic chained hash table. 38 * This is an implementation of a generic resizable chained hash table. 39 * 40 * The table grows to 2*n+1 buckets each time, starting at n == 89, 41 * per Thomas Wang's recommendation: 42 * http://www.concentric.net/~Ttwang/tech/hashsize.htm 43 * 44 * This policy produces prime table sizes for the first five resizes 45 * and generally produces table sizes which are either prime or 46 * have fairly large (prime/odd) divisors. Having a prime table size 47 * mitigates the use of suboptimal hash functions and distributes 48 * items over the whole table. 37 49 */ 38 50 … … 44 56 #include <str.h> 45 57 58 /* Optimal initial bucket count. See comment above. */ 59 #define HT_MIN_BUCKETS 89 60 /* The table is resized when the average load per bucket exceeds this number. */ 61 #define HT_MAX_LOAD 2 62 63 64 static size_t round_up_size(size_t); 65 static bool alloc_table(size_t, list_t **); 66 static void clear_items(hash_table_t *); 67 static void resize(hash_table_t *, size_t); 68 static void grow_if_needed(hash_table_t *); 69 static void shrink_if_needed(hash_table_t *); 70 71 /* Dummy do nothing callback to invoke in place of remove_callback == NULL. */ 72 static void nop_remove_callback(ht_link_t *item) 73 { 74 /* no-op */ 75 } 76 77 46 78 /** Create chained hash table. 47 79 * 48 80 * @param h Hash table structure. Will be initialized by this call. 49 * @param m Number of hash table buckets. 81 * @param init_size Initial desired number of hash table buckets. Pass zero 82 * if you want the default initial size. 50 83 * @param max_keys Maximal number of keys needed to identify an item. 51 * @param op Hash table operations structure. 84 * @param op Hash table operations structure. remove_callback() 85 * is optional and can be NULL if no action is to be taken 86 * upon removal. equal() is optional if and only if 87 * hash_table_insert_unique() will never be invoked. 88 * All other operations are mandatory. 52 89 * 53 90 * @return True on success 54 91 * 55 92 */ 56 bool hash_table_create(hash_table_t *h, hash_count_t m, hash_count_t max_keys,57 hash_table_op erations_t *op)93 bool hash_table_create(hash_table_t *h, size_t init_size, size_t max_load, 94 hash_table_ops_t *op) 58 95 { 59 96 assert(h); 60 assert(op && op->hash && op->compare); 61 assert(max_keys > 0); 62 63 h->entry = malloc(m * sizeof(list_t)); 64 if (!h->entry) 97 assert(op && op->hash && op->key_hash && op->key_equal); 98 99 /* Check for compulsory ops. */ 100 if (!op || !op->hash || !op->key_hash || !op->key_equal) 65 101 return false; 66 102 67 memset((void *) h->entry, 0, m * sizeof(list_t)); 68 69 hash_count_t i; 70 for (i = 0; i < m; i++) 71 list_initialize(&h->entry[i]); 72 73 h->entries = m; 74 h->max_keys = max_keys; 103 h->bucket_cnt = round_up_size(init_size); 104 105 if (!alloc_table(h->bucket_cnt, &h->bucket)) 106 return false; 107 108 h->max_load = (max_load == 0) ? HT_MAX_LOAD : max_load; 109 h->item_cnt = 0; 75 110 h->op = op; 111 h->full_item_cnt = h->max_load * h->bucket_cnt; 112 h->apply_ongoing = false; 113 114 if (h->op->remove_callback == NULL) { 115 h->op->remove_callback = nop_remove_callback; 116 } 76 117 77 118 return true; 78 119 } 79 120 121 /** Destroy a hash table instance. 122 * 123 * @param h Hash table to be destroyed. 124 * 125 */ 126 void hash_table_destroy(hash_table_t *h) 127 { 128 assert(h && h->bucket); 129 assert(!h->apply_ongoing); 130 131 clear_items(h); 132 133 free(h->bucket); 134 135 h->bucket = 0; 136 h->bucket_cnt = 0; 137 } 138 139 /** Returns true if there are no items in the table. */ 140 bool hash_table_empty(hash_table_t *h) 141 { 142 assert(h && h->bucket); 143 return h->item_cnt == 0; 144 } 145 146 /** Returns the number of items in the table. */ 147 size_t hash_table_size(hash_table_t *h) 148 { 149 assert(h && h->bucket); 150 return h->item_cnt; 151 } 152 80 153 /** Remove all elements from the hash table 81 154 * … … 84 157 void hash_table_clear(hash_table_t *h) 85 158 { 86 for (hash_count_t chain = 0; chain < h->entries; ++chain) { 87 link_t *cur; 88 link_t *next; 89 90 for (cur = h->entry[chain].head.next; 91 cur != &h->entry[chain].head; 92 cur = next) { 93 next = cur->next; 159 assert(h && h->bucket); 160 assert(!h->apply_ongoing); 161 162 clear_items(h); 163 164 /* Shrink the table to its minimum size if possible. */ 165 if (HT_MIN_BUCKETS < h->bucket_cnt) { 166 resize(h, HT_MIN_BUCKETS); 167 } 168 } 169 170 /** Unlinks and removes all items but does not resize. */ 171 static void clear_items(hash_table_t *h) 172 { 173 if (h->item_cnt == 0) 174 return; 175 176 for (size_t idx = 0; idx < h->bucket_cnt; ++idx) { 177 list_foreach_safe(h->bucket[idx], cur, next) { 178 assert(cur); 179 ht_link_t *cur_link = member_to_inst(cur, ht_link_t, link); 180 94 181 list_remove(cur); 95 h->op->remove_callback(cur); 96 } 97 } 98 } 99 100 /** Destroy a hash table instance. 101 * 102 * @param h Hash table to be destroyed. 103 * 104 */ 105 void hash_table_destroy(hash_table_t *h) 106 { 107 assert(h); 108 assert(h->entry); 109 110 free(h->entry); 182 h->op->remove_callback(cur_link); 183 } 184 } 185 186 h->item_cnt = 0; 111 187 } 112 188 … … 117 193 * @param item Item to be inserted into the hash table. 118 194 */ 119 void hash_table_insert(hash_table_t *h, unsigned long key[],link_t *item)195 void hash_table_insert(hash_table_t *h, ht_link_t *item) 120 196 { 121 197 assert(item); 122 assert(h && h->op && h->op->hash && h->op->compare); 123 124 hash_index_t chain = h->op->hash(key); 125 assert(chain < h->entries); 126 127 list_append(item, &h->entry[chain]); 198 assert(h && h->bucket); 199 assert(!h->apply_ongoing); 200 201 size_t idx = h->op->hash(item) % h->bucket_cnt; 202 203 list_append(&item->link, &h->bucket[idx]); 204 ++h->item_cnt; 205 grow_if_needed(h); 206 } 207 208 209 /** Insert item into a hash table if not already present. 210 * 211 * @param h Hash table. 212 * @param key Array of all keys necessary to compute hash index. 213 * @param item Item to be inserted into the hash table. 214 * 215 * @return False if such an item had already been inserted. 216 * @return True if the inserted item was the only item with such a lookup key. 217 */ 218 bool hash_table_insert_unique(hash_table_t *h, ht_link_t *item) 219 { 220 assert(item); 221 assert(h && h->bucket && h->bucket_cnt); 222 assert(h->op && h->op->hash && h->op->equal); 223 assert(!h->apply_ongoing); 224 225 size_t idx = h->op->hash(item) % h->bucket_cnt; 226 227 /* Check for duplicates. */ 228 list_foreach(h->bucket[idx], cur) { 229 /* 230 * We could filter out items using their hashes first, but 231 * calling equal() might very well be just as fast. 232 */ 233 ht_link_t *cur_link = member_to_inst(cur, ht_link_t, link); 234 if (h->op->equal(cur_link, item)) 235 return false; 236 } 237 238 list_append(&item->link, &h->bucket[idx]); 239 ++h->item_cnt; 240 grow_if_needed(h); 241 242 return true; 128 243 } 129 244 … … 136 251 * 137 252 */ 138 link_t *hash_table_find(hash_table_t *h, unsigned long key[]) 139 { 140 assert(h && h->op && h->op->hash && h->op->compare); 141 142 hash_index_t chain = h->op->hash(key); 143 assert(chain < h->entries); 144 145 list_foreach(h->entry[chain], cur) { 146 if (h->op->compare(key, h->max_keys, cur)) { 147 /* 148 * The entry is there. 149 */ 150 return cur; 151 } 152 } 153 253 ht_link_t *hash_table_find(const hash_table_t *h, void *key) 254 { 255 assert(h && h->bucket); 256 257 size_t idx = h->op->key_hash(key) % h->bucket_cnt; 258 259 list_foreach(h->bucket[idx], cur) { 260 ht_link_t *cur_link = member_to_inst(cur, ht_link_t, link); 261 /* 262 * Is this is the item we are looking for? We could have first 263 * checked if the hashes match but op->key_equal() may very well be 264 * just as fast as op->hash(). 265 */ 266 if (h->op->key_equal(key, cur_link)) { 267 return cur_link; 268 } 269 } 270 271 return NULL; 272 } 273 274 /** Find the next item equal to item. */ 275 ht_link_t *hash_table_find_next(const hash_table_t *h, ht_link_t *item) 276 { 277 assert(item); 278 assert(h && h->bucket); 279 280 /* Traverse the circular list until we reach the starting item again. */ 281 for (link_t *cur = item->link.next; cur != &item->link; cur = cur->next) { 282 assert(cur); 283 ht_link_t *cur_link = member_to_inst(cur, ht_link_t, link); 284 /* 285 * Is this is the item we are looking for? We could have first 286 * checked if the hashes match but op->equal() may very well be 287 * just as fast as op->hash(). 288 */ 289 if (h->op->equal(cur_link, item)) { 290 return cur_link; 291 } 292 } 293 154 294 return NULL; 155 295 } … … 163 303 * the hash table. 164 304 * @param keys Number of keys in the 'key' array. 165 * 166 */ 167 void hash_table_remove(hash_table_t *h, unsigned long key[], hash_count_t keys) 168 { 169 assert(h && h->op && h->op->hash && h->op->compare && 170 h->op->remove_callback); 171 assert(keys <= h->max_keys); 172 173 if (keys == h->max_keys) { 174 /* 175 * All keys are known, hash_table_find() can be used to find the 176 * entry. 305 * 306 * @return Returns the number of removed items. 307 */ 308 size_t hash_table_remove(hash_table_t *h, void *key) 309 { 310 assert(h && h->bucket); 311 assert(!h->apply_ongoing); 312 313 size_t idx = h->op->key_hash(key) % h->bucket_cnt; 314 315 size_t removed = 0; 316 317 list_foreach_safe(h->bucket[idx], cur, next) { 318 ht_link_t *cur_link = member_to_inst(cur, ht_link_t, link); 319 320 if (h->op->key_equal(key, cur_link)) { 321 ++removed; 322 list_remove(cur); 323 h->op->remove_callback(cur_link); 324 } 325 } 326 327 h->item_cnt -= removed; 328 shrink_if_needed(h); 329 330 return removed; 331 } 332 333 /** Removes an item already present in the table. The item must be in the table.*/ 334 void hash_table_remove_item(hash_table_t *h, ht_link_t *item) 335 { 336 assert(item); 337 assert(h && h->bucket); 338 assert(link_in_use(&item->link)); 339 340 list_remove(&item->link); 341 --h->item_cnt; 342 h->op->remove_callback(item); 343 shrink_if_needed(h); 344 } 345 346 /** Apply function to all items in hash table. 347 * 348 * @param h Hash table. 349 * @param f Function to be applied. Return false if no more items 350 * should be visited. The functor may only delete the supplied 351 * item. It must not delete the successor of the item passed 352 * in the first argument. 353 * @param arg Argument to be passed to the function. 354 */ 355 void hash_table_apply(hash_table_t *h, bool (*f)(ht_link_t *, void *), void *arg) 356 { 357 assert(f); 358 assert(h && h->bucket); 359 360 if (h->item_cnt == 0) 361 return; 362 363 h->apply_ongoing = true; 364 365 for (size_t idx = 0; idx < h->bucket_cnt; ++idx) { 366 list_foreach_safe(h->bucket[idx], cur, next) { 367 ht_link_t *cur_link = member_to_inst(cur, ht_link_t, link); 368 /* 369 * The next pointer had already been saved. f() may safely 370 * delete cur (but not next!). 371 */ 372 if (!f(cur_link, arg)) 373 return; 374 } 375 } 376 377 h->apply_ongoing = false; 378 379 shrink_if_needed(h); 380 grow_if_needed(h); 381 } 382 383 /** Rounds up size to the nearest suitable table size. */ 384 static size_t round_up_size(size_t size) 385 { 386 size_t rounded_size = HT_MIN_BUCKETS; 387 388 while (rounded_size < size) { 389 rounded_size = 2 * rounded_size + 1; 390 } 391 392 return rounded_size; 393 } 394 395 /** Allocates and initializes the desired number of buckets. True if successful.*/ 396 static bool alloc_table(size_t bucket_cnt, list_t **pbuckets) 397 { 398 assert(pbuckets && HT_MIN_BUCKETS <= bucket_cnt); 399 400 list_t *buckets = malloc(bucket_cnt * sizeof(list_t)); 401 if (!buckets) 402 return false; 403 404 for (size_t i = 0; i < bucket_cnt; i++) 405 list_initialize(&buckets[i]); 406 407 *pbuckets = buckets; 408 return true; 409 } 410 411 412 /** Shrinks the table if the table is only sparely populated. */ 413 static inline void shrink_if_needed(hash_table_t *h) 414 { 415 if (h->item_cnt <= h->full_item_cnt / 4 && HT_MIN_BUCKETS < h->bucket_cnt) { 416 /* 417 * Keep the bucket_cnt odd (possibly also prime). 418 * Shrink from 2n + 1 to n. Integer division discards the +1. 177 419 */ 178 179 link_t *cur = hash_table_find(h, key); 180 if (cur) { 181 list_remove(cur); 182 h->op->remove_callback(cur); 183 } 184 420 size_t new_bucket_cnt = h->bucket_cnt / 2; 421 resize(h, new_bucket_cnt); 422 } 423 } 424 425 /** Grows the table if table load exceeds the maximum allowed. */ 426 static inline void grow_if_needed(hash_table_t *h) 427 { 428 /* Grow the table if the average bucket load exceeds the maximum. */ 429 if (h->full_item_cnt < h->item_cnt) { 430 /* Keep the bucket_cnt odd (possibly also prime). */ 431 size_t new_bucket_cnt = 2 * h->bucket_cnt + 1; 432 resize(h, new_bucket_cnt); 433 } 434 } 435 436 /** Allocates and rehashes items to a new table. Frees the old table. */ 437 static void resize(hash_table_t *h, size_t new_bucket_cnt) 438 { 439 assert(h && h->bucket); 440 assert(HT_MIN_BUCKETS <= new_bucket_cnt); 441 442 /* We are traversing the table and resizing would mess up the buckets. */ 443 if (h->apply_ongoing) 185 444 return; 186 } 187 188 /* 189 * Fewer keys were passed. 190 * Any partially matching entries are to be removed. 191 */ 192 hash_index_t chain; 193 for (chain = 0; chain < h->entries; chain++) { 194 for (link_t *cur = h->entry[chain].head.next; 195 cur != &h->entry[chain].head; 196 cur = cur->next) { 197 if (h->op->compare(key, keys, cur)) { 198 link_t *hlp; 199 200 hlp = cur; 201 cur = cur->prev; 202 203 list_remove(hlp); 204 h->op->remove_callback(hlp); 205 206 continue; 445 446 list_t *new_buckets; 447 448 /* Leave the table as is if we cannot resize. */ 449 if (!alloc_table(new_bucket_cnt, &new_buckets)) 450 return; 451 452 if (0 < h->item_cnt) { 453 /* Rehash all the items to the new table. */ 454 for (size_t old_idx = 0; old_idx < h->bucket_cnt; ++old_idx) { 455 list_foreach_safe(h->bucket[old_idx], cur, next) { 456 ht_link_t *cur_link = member_to_inst(cur, ht_link_t, link); 457 458 size_t new_idx = h->op->hash(cur_link) % new_bucket_cnt; 459 list_remove(cur); 460 list_append(cur, &new_buckets[new_idx]); 207 461 } 208 462 } 209 463 } 210 } 211 212 /** Apply function to all items in hash table. 213 * 214 * @param h Hash table. 215 * @param f Function to be applied. 216 * @param arg Argument to be passed to the function. 217 * 218 */ 219 void hash_table_apply(hash_table_t *h, void (*f)(link_t *, void *), void *arg) 220 { 221 for (hash_index_t bucket = 0; bucket < h->entries; bucket++) { 222 link_t *cur; 223 link_t *next; 224 225 for (cur = h->entry[bucket].head.next; cur != &h->entry[bucket].head; 226 cur = next) { 227 /* 228 * The next pointer must be stored prior to the functor 229 * call to allow using destructor as the functor (the 230 * free function could overwrite the cur->next pointer). 231 */ 232 next = cur->next; 233 f(cur, arg); 234 } 235 } 236 } 464 465 free(h->bucket); 466 h->bucket = new_buckets; 467 h->bucket_cnt = new_bucket_cnt; 468 h->full_item_cnt = h->max_load * h->bucket_cnt; 469 } 470 237 471 238 472 /** @} -
uspace/lib/c/generic/adt/list.c
rb5d2e57 r03362fbd 40 40 41 41 #include <adt/list.h> 42 #include < bool.h>42 #include <stdbool.h> 43 43 44 44 /** Check for membership -
uspace/lib/c/generic/async.c
rb5d2e57 r03362fbd 109 109 #include <sys/time.h> 110 110 #include <libarch/barrier.h> 111 #include < bool.h>111 #include <stdbool.h> 112 112 #include <malloc.h> 113 113 #include <mem.h> 114 114 #include <stdlib.h> 115 115 #include <macros.h> 116 117 #define CLIENT_HASH_TABLE_BUCKETS 32 118 #define CONN_HASH_TABLE_BUCKETS 32 116 #include "private/libc.h" 117 119 118 120 119 /** Session data */ … … 204 203 /* Client connection data */ 205 204 typedef struct { 206 link_t link;205 ht_link_t link; 207 206 208 207 task_id_t in_task_id; … … 216 215 217 216 /** Hash table link. */ 218 link_t link;217 ht_link_t link; 219 218 220 219 /** Incoming client task ID. */ … … 392 391 static LIST_INITIALIZE(timeout_list); 393 392 394 static hash_index_t client_hash(unsigned long key[]) 395 { 396 assert(key); 397 398 return (((key[0]) >> 4) % CLIENT_HASH_TABLE_BUCKETS); 399 } 400 401 static int client_compare(unsigned long key[], hash_count_t keys, link_t *item) 402 { 403 assert(key); 404 assert(keys == 2); 405 assert(item); 406 407 client_t *client = hash_table_get_instance(item, client_t, link); 408 return (key[0] == LOWER32(client->in_task_id) && 409 (key[1] == UPPER32(client->in_task_id))); 410 } 411 412 static void client_remove(link_t *item) 413 { 414 } 393 static size_t client_key_hash(void *k) 394 { 395 task_id_t key = *(task_id_t*)k; 396 return key; 397 } 398 399 static size_t client_hash(const ht_link_t *item) 400 { 401 client_t *client = hash_table_get_inst(item, client_t, link); 402 return client_key_hash(&client->in_task_id); 403 } 404 405 static bool client_key_equal(void *k, const ht_link_t *item) 406 { 407 task_id_t key = *(task_id_t*)k; 408 client_t *client = hash_table_get_inst(item, client_t, link); 409 return key == client->in_task_id; 410 } 411 415 412 416 413 /** Operations for the client hash table. */ 417 static hash_table_op erations_t client_hash_table_ops = {414 static hash_table_ops_t client_hash_table_ops = { 418 415 .hash = client_hash, 419 .compare = client_compare, 420 .remove_callback = client_remove 416 .key_hash = client_key_hash, 417 .key_equal = client_key_equal, 418 .equal = NULL, 419 .remove_callback = NULL 421 420 }; 422 421 … … 428 427 * 429 428 */ 430 static hash_index_t conn_hash(unsigned long key[]) 431 { 432 assert(key); 433 434 return (((key[0]) >> 4) % CONN_HASH_TABLE_BUCKETS); 435 } 436 437 /** Compare hash table item with a key. 438 * 439 * @param key Array containing the source phone hash as the only item. 440 * @param keys Expected 1 but ignored. 441 * @param item Connection hash table item. 442 * 443 * @return True on match, false otherwise. 444 * 445 */ 446 static int conn_compare(unsigned long key[], hash_count_t keys, link_t *item) 447 { 448 assert(key); 449 assert(item); 450 451 connection_t *conn = hash_table_get_instance(item, connection_t, link); 452 return (key[0] == conn->in_phone_hash); 453 } 454 455 static void conn_remove(link_t *item) 456 { 457 } 429 static size_t conn_key_hash(void *key) 430 { 431 sysarg_t in_phone_hash = *(sysarg_t*)key; 432 return in_phone_hash ; 433 } 434 435 static size_t conn_hash(const ht_link_t *item) 436 { 437 connection_t *conn = hash_table_get_inst(item, connection_t, link); 438 return conn_key_hash(&conn->in_phone_hash); 439 } 440 441 static bool conn_key_equal(void *key, const ht_link_t *item) 442 { 443 sysarg_t in_phone_hash = *(sysarg_t*)key; 444 connection_t *conn = hash_table_get_inst(item, connection_t, link); 445 return (in_phone_hash == conn->in_phone_hash); 446 } 447 458 448 459 449 /** Operations for the connection hash table. */ 460 static hash_table_op erations_t conn_hash_table_ops = {450 static hash_table_ops_t conn_hash_table_ops = { 461 451 .hash = conn_hash, 462 .compare = conn_compare, 463 .remove_callback = conn_remove 452 .key_hash = conn_key_hash, 453 .key_equal = conn_key_equal, 454 .equal = NULL, 455 .remove_callback = NULL 464 456 }; 465 457 … … 509 501 futex_down(&async_futex); 510 502 511 unsigned long key = call->in_phone_hash; 512 link_t *hlp = hash_table_find(&conn_hash_table, &key); 503 ht_link_t *hlp = hash_table_find(&conn_hash_table, &call->in_phone_hash); 513 504 514 505 if (!hlp) { … … 517 508 } 518 509 519 connection_t *conn = hash_table_get_inst ance(hlp, connection_t, link);510 connection_t *conn = hash_table_get_inst(hlp, connection_t, link); 520 511 521 512 msg_t *msg = malloc(sizeof(*msg)); … … 637 628 638 629 if (usecs) { 639 get timeofday(&conn->wdata.to_event.expires, NULL);630 getuptime(&conn->wdata.to_event.expires); 640 631 tv_add(&conn->wdata.to_event.expires, usecs); 641 632 } else … … 697 688 static client_t *async_client_get(task_id_t client_id, bool create) 698 689 { 699 unsigned long key[2] = {700 LOWER32(client_id),701 UPPER32(client_id),702 };703 690 client_t *client = NULL; 704 691 705 692 futex_down(&async_futex); 706 link_t *lnk = hash_table_find(&client_hash_table, key);693 ht_link_t *lnk = hash_table_find(&client_hash_table, &client_id); 707 694 if (lnk) { 708 client = hash_table_get_inst ance(lnk, client_t, link);695 client = hash_table_get_inst(lnk, client_t, link); 709 696 atomic_inc(&client->refcnt); 710 697 } else if (create) { … … 715 702 716 703 atomic_set(&client->refcnt, 1); 717 hash_table_insert(&client_hash_table, key,&client->link);704 hash_table_insert(&client_hash_table, &client->link); 718 705 } 719 706 } … … 726 713 { 727 714 bool destroy; 728 unsigned long key[2] = { 729 LOWER32(client->in_task_id), 730 UPPER32(client->in_task_id) 731 }; 732 715 733 716 futex_down(&async_futex); 734 717 735 718 if (atomic_predec(&client->refcnt) == 0) { 736 hash_table_remove(&client_hash_table, key, 2);719 hash_table_remove(&client_hash_table, &client->in_task_id); 737 720 destroy = true; 738 721 } else … … 830 813 */ 831 814 futex_down(&async_futex); 832 unsigned long key = fibril_connection->in_phone_hash; 833 hash_table_remove(&conn_hash_table, &key, 1); 815 hash_table_remove(&conn_hash_table, &fibril_connection->in_phone_hash); 834 816 futex_up(&async_futex); 835 817 … … 915 897 916 898 /* Add connection to the connection hash table */ 917 unsigned long key = conn->in_phone_hash;918 899 919 900 futex_down(&async_futex); 920 hash_table_insert(&conn_hash_table, & key, &conn->link);901 hash_table_insert(&conn_hash_table, &conn->link); 921 902 futex_up(&async_futex); 922 903 … … 966 947 { 967 948 struct timeval tv; 968 get timeofday(&tv, NULL);949 getuptime(&tv); 969 950 970 951 futex_down(&async_futex); … … 1023 1004 1024 1005 struct timeval tv; 1025 get timeofday(&tv, NULL);1006 getuptime(&tv); 1026 1007 1027 1008 if (tv_gteq(&tv, &waiter->to_event.expires)) { … … 1110 1091 void __async_init(void) 1111 1092 { 1112 if (!hash_table_create(&client_hash_table, CLIENT_HASH_TABLE_BUCKETS, 1113 2, &client_hash_table_ops)) 1093 if (!hash_table_create(&client_hash_table, 0, 0, &client_hash_table_ops)) 1114 1094 abort(); 1115 1095 1116 if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_BUCKETS, 1117 1, &conn_hash_table_ops)) 1096 if (!hash_table_create(&conn_hash_table, 0, 0, &conn_hash_table_ops)) 1118 1097 abort(); 1119 1098 … … 1330 1309 timeout = 0; 1331 1310 1332 get timeofday(&msg->wdata.to_event.expires, NULL);1311 getuptime(&msg->wdata.to_event.expires); 1333 1312 tv_add(&msg->wdata.to_event.expires, timeout); 1334 1313 … … 1412 1391 msg->wdata.fid = fibril_get_id(); 1413 1392 1414 get timeofday(&msg->wdata.to_event.expires, NULL);1393 getuptime(&msg->wdata.to_event.expires); 1415 1394 tv_add(&msg->wdata.to_event.expires, timeout); 1416 1395 … … 2166 2145 int async_share_in_finalize(ipc_callid_t callid, void *src, unsigned int flags) 2167 2146 { 2168 return ipc_share_in_finalize(callid, src, flags); 2147 return ipc_answer_3(callid, EOK, (sysarg_t) src, (sysarg_t) flags, 2148 (sysarg_t) __entry); 2169 2149 } 2170 2150 … … 2233 2213 int async_share_out_finalize(ipc_callid_t callid, void **dst) 2234 2214 { 2235 return ipc_ share_out_finalize(callid,dst);2215 return ipc_answer_2(callid, EOK, (sysarg_t) __entry, (sysarg_t) dst); 2236 2216 } 2237 2217 … … 2317 2297 int async_data_read_finalize(ipc_callid_t callid, const void *src, size_t size) 2318 2298 { 2319 return ipc_ data_read_finalize(callid, src,size);2299 return ipc_answer_2(callid, EOK, (sysarg_t) src, (sysarg_t) size); 2320 2300 } 2321 2301 … … 2420 2400 int async_data_write_finalize(ipc_callid_t callid, void *dst, size_t size) 2421 2401 { 2422 return ipc_ data_write_finalize(callid, dst,size);2402 return ipc_answer_2(callid, EOK, (sysarg_t) dst, (sysarg_t) size); 2423 2403 } 2424 2404 -
uspace/lib/c/generic/ddi.c
rb5d2e57 r03362fbd 34 34 35 35 #include <assert.h> 36 #include <atomic.h> 36 37 #include <unistd.h> 38 #include <stdio.h> 37 39 #include <errno.h> 38 40 #include <sys/types.h> … … 47 49 #include "private/libc.h" 48 50 51 49 52 /** Return unique device number. 50 53 * … … 120 123 * 121 124 */ 122 int iospace_enable(task_id_t id, void *ioaddr, unsigned longsize)123 { 124 ddi_ioarg_t arg;125 126 arg.task_id = id;127 arg.ioaddr = ioaddr;128 arg.size = size;125 static int iospace_enable(task_id_t id, void *ioaddr, size_t size) 126 { 127 const ddi_ioarg_t arg = { 128 .task_id = id, 129 .ioaddr = ioaddr, 130 .size = size 131 }; 129 132 130 133 return __SYSCALL1(SYS_IOSPACE_ENABLE, (sysarg_t) &arg); … … 136 139 * @param size Size of the I/O region. 137 140 * @param virt Virtual address for application's 138 * PIO operations. 141 * PIO operations. Can be NULL for PMIO. 139 142 * 140 143 * @return EOK on success. … … 146 149 #ifdef IO_SPACE_BOUNDARY 147 150 if (pio_addr < IO_SPACE_BOUNDARY) { 148 *virt = pio_addr; 151 if (virt) 152 *virt = pio_addr; 149 153 return iospace_enable(task_get_id(), pio_addr, size); 150 154 } 155 #else 156 (void) iospace_enable; 151 157 #endif 152 158 if (!virt) 159 return EINVAL; 160 153 161 void *phys_frame = 154 162 (void *) ALIGN_DOWN((uintptr_t) pio_addr, PAGE_SIZE); … … 166 174 } 167 175 176 void pio_write_8(ioport8_t *reg, uint8_t val) 177 { 178 pio_trace_log(reg, val, true); 179 arch_pio_write_8(reg, val); 180 } 181 182 void pio_write_16(ioport16_t *reg, uint16_t val) 183 { 184 pio_trace_log(reg, val, true); 185 arch_pio_write_16(reg, val); 186 } 187 188 void pio_write_32(ioport32_t *reg, uint32_t val) 189 { 190 pio_trace_log(reg, val, true); 191 arch_pio_write_32(reg, val); 192 } 193 194 uint8_t pio_read_8(const ioport8_t *reg) 195 { 196 const uint8_t val = arch_pio_read_8(reg); 197 pio_trace_log(reg, val, false); 198 return val; 199 } 200 201 uint16_t pio_read_16(const ioport16_t *reg) 202 { 203 const uint16_t val = arch_pio_read_16(reg); 204 pio_trace_log(reg, val, false); 205 return val; 206 } 207 208 uint32_t pio_read_32(const ioport32_t *reg) 209 { 210 const uint32_t val = arch_pio_read_32(reg); 211 pio_trace_log(reg, val, false); 212 return val; 213 } 214 168 215 /** Register IRQ notification. 169 216 * -
uspace/lib/c/generic/device/clock_dev.c
rb5d2e57 r03362fbd 1 1 /* 2 * Copyright (c) 2007 Michal Kebrt 3 * Copyright (c) 2009 Vineeth Pillai 2 * Copyright (c) 2012 Maurizio Lombardi 4 3 * All rights reserved. 5 4 * … … 28 27 */ 29 28 30 /** @addtogroup arm32gxemul GXemul 31 * @brief GXemul machine specific parts. 32 * @ingroup arm32 29 /** @addtogroup libc 33 30 * @{ 34 31 */ 35 32 /** @file 36 * @brief GXemul peripheries drivers declarations.37 33 */ 38 34 39 #ifndef KERN_arm32_testarm_H_ 40 #define KERN_arm32_testarm_H_ 35 #include <ipc/dev_iface.h> 36 #include <device/clock_dev.h> 37 #include <errno.h> 38 #include <async.h> 39 #include <time.h> 41 40 42 #include <arch/machine_func.h> 41 /** Read the current time from the device 42 * 43 * @param sess Session of the device 44 * @param t The current time that will be read from the device 45 * 46 * @return EOK on success or a negative error code 47 */ 48 int 49 clock_dev_time_get(async_sess_t *sess, struct tm *t) 50 { 51 aid_t req; 52 int ret; 43 53 44 /** Size of GXemul IRQ number range (starting from 0) */ 45 #define GXEMUL_IRQ_COUNT 32 46 #define GXEMUL_KBD_IRQ 2 47 #define GXEMUL_TIMER_IRQ 4 54 async_exch_t *exch = async_exchange_begin(sess); 48 55 49 /** Timer frequency */ 50 #define GXEMUL_TIMER_FREQ 100 56 req = async_send_1(exch, DEV_IFACE_ID(CLOCK_DEV_IFACE), 57 CLOCK_DEV_TIME_GET, NULL); 58 ret = async_data_read_start(exch, t, sizeof(*t)); 51 59 52 #define GXEMUL_KBD_ADDRESS 0x10000000 53 #define GXEMUL_MP_ADDRESS 0x11000000 54 #define GXEMUL_FB_ADDRESS 0x12000000 55 #define GXEMUL_RTC_ADDRESS 0x15000000 56 #define GXEMUL_IRQC_ADDRESS 0x16000000 60 async_exchange_end(exch); 57 61 58 extern void *gxemul_kbd; 59 extern void *gxemul_rtc; 60 extern void *gxemul_irqc; 62 sysarg_t rc; 63 if (ret != EOK) { 64 async_forget(req); 65 return ret; 66 } 61 67 62 #define GXEMUL_HALT_OFFSET 0x010 63 #define GXEMUL_RTC_FREQ_OFFSET 0x100 64 #define GXEMUL_MP_MEMSIZE_OFFSET 0x090 65 #define GXEMUL_RTC_ACK_OFFSET 0x110 68 async_wait_for(req, &rc); 69 return (int)rc; 70 } 66 71 67 extern void gxemul_init(void); 68 extern void gxemul_output_init(void); 69 extern void gxemul_input_init(void); 70 extern void gxemul_timer_irq_start(void); 71 extern void gxemul_cpu_halt(void); 72 extern void gxemul_irq_exception(unsigned int, istate_t *); 73 extern void gxemul_get_memory_extents(uintptr_t *, size_t *); 74 extern void gxemul_frame_init(void); 75 extern size_t gxemul_get_irq_count(void); 76 extern const char *gxemul_get_platform_name(void); 72 /** Set the current time 73 * 74 * @param sess Session of the device 75 * @param t The current time that will be written to the device 76 * 77 * @return EOK on success or a negative error code 78 */ 79 int 80 clock_dev_time_set(async_sess_t *sess, struct tm *t) 81 { 82 aid_t req; 83 int ret; 77 84 78 extern struct arm_machine_ops gxemul_machine_ops;85 async_exch_t *exch = async_exchange_begin(sess); 79 86 80 #endif 87 req = async_send_1(exch, DEV_IFACE_ID(CLOCK_DEV_IFACE), 88 CLOCK_DEV_TIME_SET, NULL); 89 ret = async_data_write_start(exch, t, sizeof(*t)); 90 91 async_exchange_end(exch); 92 93 sysarg_t rc; 94 if (ret != EOK) { 95 async_forget(req); 96 return ret; 97 } 98 99 async_wait_for(req, &rc); 100 return (int)rc; 101 } 81 102 82 103 /** @} 83 104 */ 105 -
uspace/lib/c/generic/devman.c
rb5d2e57 r03362fbd 45 45 #include <errno.h> 46 46 #include <malloc.h> 47 #include < bool.h>47 #include <stdbool.h> 48 48 49 49 static FIBRIL_MUTEX_INITIALIZE(devman_driver_block_mutex); -
uspace/lib/c/generic/dlfcn.c
rb5d2e57 r03362fbd 38 38 #include <stdlib.h> 39 39 #include <dlfcn.h> 40 41 #ifdef CONFIG_RTLD 40 42 41 43 #include <rtld/module.h> … … 87 89 } 88 90 91 #else /* CONFIG_RTLD not defined */ 92 93 void *dlopen(const char *path, int flag) 94 { 95 return NULL; 96 } 97 98 void *dlsym(void *mod, const char *sym_name) 99 { 100 return NULL; 101 } 102 103 #endif 104 89 105 /** @} 90 106 */ -
uspace/lib/c/generic/fibril.c
rb5d2e57 r03362fbd 37 37 #include <fibril.h> 38 38 #include <thread.h> 39 #include <stack.h> 39 40 #include <tls.h> 40 41 #include <malloc.h> 42 #include <abi/mm/as.h> 43 #include <as.h> 41 44 #include <unistd.h> 42 45 #include <stdio.h> … … 46 49 #include <assert.h> 47 50 #include <async.h> 48 49 #ifndef FIBRIL_INITIAL_STACK_PAGES_NO50 #define FIBRIL_INITIAL_STACK_PAGES_NO 151 #endif52 51 53 52 /** … … 195 194 * stack member filled. 196 195 */ 197 free(stack);196 as_area_destroy(stack); 198 197 } 199 198 fibril_teardown(srcf->clean_after_me); … … 269 268 return 0; 270 269 271 fibril->stack = 272 (char *) malloc(FIBRIL_INITIAL_STACK_PAGES_NO * getpagesize()); 273 if (!fibril->stack) { 270 size_t stack_size = stack_size_get(); 271 fibril->stack = as_area_create((void *) -1, stack_size, 272 AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE | AS_AREA_GUARD | 273 AS_AREA_LATE_RESERVE); 274 if (fibril->stack == (void *) -1) { 274 275 fibril_teardown(fibril); 275 276 return 0; … … 281 282 context_save(&fibril->ctx); 282 283 context_set(&fibril->ctx, FADDR(fibril_main), fibril->stack, 283 FIBRIL_INITIAL_STACK_PAGES_NO * getpagesize(), fibril->tcb);284 stack_size, fibril->tcb); 284 285 285 286 return (fid_t) fibril; … … 298 299 fibril_t *fibril = (fibril_t *) fid; 299 300 300 free(fibril->stack);301 as_area_destroy(fibril->stack); 301 302 fibril_teardown(fibril); 302 303 } -
uspace/lib/c/generic/fibril_synch.c
rb5d2e57 r03362fbd 379 379 futex_down(&async_futex); 380 380 if (timeout) { 381 get timeofday(&wdata.to_event.expires, NULL);381 getuptime(&wdata.to_event.expires); 382 382 tv_add(&wdata.to_event.expires, timeout); 383 383 async_insert_timeout(&wdata); -
uspace/lib/c/generic/io/chargrid.c
rb5d2e57 r03362fbd 27 27 */ 28 28 29 /** @addtogroup console29 /** @addtogroup libc 30 30 * @{ 31 31 */ … … 37 37 #include <unistd.h> 38 38 #include <assert.h> 39 #include < bool.h>39 #include <stdbool.h> 40 40 #include <as.h> 41 #include "screenbuffer.h" 42 43 /** Structure for buffering state of one virtual console. 44 * 45 */ 46 struct screenbuffer { 47 size_t size; /**< Structure size */ 48 screenbuffer_flag_t flags; /**< Screenbuffer flags */ 49 50 sysarg_t cols; /**< Number of columns */ 51 sysarg_t rows; /**< Number of rows */ 52 53 sysarg_t col; /**< Current column */ 54 sysarg_t row; /**< Current row */ 55 bool cursor_visible; /**< Cursor visibility */ 56 57 char_attrs_t attrs; /**< Current attributes */ 58 59 sysarg_t top_row; /**< The first row in the cyclic buffer */ 60 charfield_t data[]; /**< Screen contents (cyclic buffer) */ 61 }; 62 63 /** Create a screenbuffer. 41 #include <io/chargrid.h> 42 43 /** Create a chargrid. 64 44 * 65 45 * @param[in] cols Number of columns. 66 46 * @param[in] rows Number of rows. 67 * @param[in] flags Screenbufferflags.68 * 69 * @return New screenbuffer.47 * @param[in] flags Chargrid flags. 48 * 49 * @return New chargrid. 70 50 * @return NULL on failure. 71 51 * 72 52 */ 73 screenbuffer_t *screenbuffer_create(sysarg_t cols, sysarg_t rows,74 screenbuffer_flag_t flags)53 chargrid_t *chargrid_create(sysarg_t cols, sysarg_t rows, 54 chargrid_flag_t flags) 75 55 { 76 56 size_t size = 77 sizeof( screenbuffer_t) + cols * rows * sizeof(charfield_t);78 screenbuffer_t *scrbuf;79 80 if ((flags & SCREENBUFFER_FLAG_SHARED) == SCREENBUFFER_FLAG_SHARED) {81 scrbuf = ( screenbuffer_t *) as_area_create(AS_AREA_ANY, size,57 sizeof(chargrid_t) + cols * rows * sizeof(charfield_t); 58 chargrid_t *scrbuf; 59 60 if ((flags & CHARGRID_FLAG_SHARED) == CHARGRID_FLAG_SHARED) { 61 scrbuf = (chargrid_t *) as_area_create(AS_AREA_ANY, size, 82 62 AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE); 83 63 if (scrbuf == AS_MAP_FAILED) 84 64 return NULL; 85 65 } else { 86 scrbuf = ( screenbuffer_t *) malloc(size);66 scrbuf = (chargrid_t *) malloc(size); 87 67 if (scrbuf == NULL) 88 68 return NULL; … … 99 79 100 80 scrbuf->top_row = 0; 101 screenbuffer_clear(scrbuf);81 chargrid_clear(scrbuf); 102 82 103 83 return scrbuf; 104 84 } 105 85 106 /** Return keyfield by coordinates 107 * 108 * The back buffer is organized as a cyclic buffer. 109 * Therefore we must take into account the topmost column. 110 * 111 * @param scrbuf Screenbuffer 112 * @param col Column position on screen 113 * @param row Row position on screen 114 * 115 * @return Keyfield structure on (row, col) 116 * 117 */ 118 charfield_t *screenbuffer_field_at(screenbuffer_t *scrbuf, sysarg_t col, 119 sysarg_t row) 120 { 121 return scrbuf->data + 122 ((row + scrbuf->top_row) % scrbuf->rows) * scrbuf->cols + 123 col; 124 } 125 126 bool screenbuffer_cursor_at(screenbuffer_t *scrbuf, sysarg_t col, sysarg_t row) 86 void chargrid_destroy(chargrid_t *srcbuf) 87 { 88 // TODO 89 } 90 91 bool chargrid_cursor_at(chargrid_t *scrbuf, sysarg_t col, sysarg_t row) 127 92 { 128 93 return ((scrbuf->cursor_visible) && (scrbuf->col == col) && … … 130 95 } 131 96 132 sysarg_t screenbuffer_get_top_row(screenbuffer_t *scrbuf)97 sysarg_t chargrid_get_top_row(chargrid_t *scrbuf) 133 98 { 134 99 return scrbuf->top_row; 135 100 } 136 101 137 static sysarg_t screenbuffer_update_rows(screenbuffer_t *scrbuf)102 static sysarg_t chargrid_update_rows(chargrid_t *scrbuf) 138 103 { 139 104 if (scrbuf->row == scrbuf->rows) { 140 105 scrbuf->row = scrbuf->rows - 1; 141 106 scrbuf->top_row = (scrbuf->top_row + 1) % scrbuf->rows; 142 screenbuffer_clear_row(scrbuf, scrbuf->row);107 chargrid_clear_row(scrbuf, scrbuf->row); 143 108 144 109 return scrbuf->rows; … … 148 113 } 149 114 150 static sysarg_t screenbuffer_update_cols(screenbuffer_t *scrbuf)115 static sysarg_t chargrid_update_cols(chargrid_t *scrbuf) 151 116 { 152 117 /* Column overflow */ … … 154 119 scrbuf->col = 0; 155 120 scrbuf->row++; 156 return screenbuffer_update_rows(scrbuf);121 return chargrid_update_rows(scrbuf); 157 122 } 158 123 … … 160 125 } 161 126 162 /** Store one character to screenbuffer.127 /** Store one character to chargrid. 163 128 * 164 129 * Its position is determined by scrbuf->col 165 130 * and scrbuf->row. 166 131 * 167 * @param scrbuf Screenbuffer.132 * @param scrbuf Chargrid. 168 133 * @param ch Character to store. 169 134 * @param update Update coordinates. … … 174 139 * 175 140 */ 176 sysarg_t screenbuffer_putchar(screenbuffer_t *scrbuf, wchar_t ch, bool update)141 sysarg_t chargrid_putchar(chargrid_t *scrbuf, wchar_t ch, bool update) 177 142 { 178 143 assert(scrbuf->col < scrbuf->cols); … … 180 145 181 146 charfield_t *field = 182 screenbuffer_field_at(scrbuf, scrbuf->col, scrbuf->row);147 chargrid_charfield_at(scrbuf, scrbuf->col, scrbuf->row); 183 148 184 149 field->ch = ch; … … 188 153 if (update) { 189 154 scrbuf->col++; 190 return screenbuffer_update_cols(scrbuf);155 return chargrid_update_cols(scrbuf); 191 156 } 192 157 … … 194 159 } 195 160 196 /** Jump to a new row in screenbuffer.197 * 198 * @param scrbuf Screenbuffer.161 /** Jump to a new row in chargrid. 162 * 163 * @param scrbuf Chargrid. 199 164 * 200 165 * @return Number of rows which have been affected. In usual … … 203 168 * 204 169 */ 205 sysarg_t screenbuffer_newline(screenbuffer_t *scrbuf)170 sysarg_t chargrid_newline(chargrid_t *scrbuf) 206 171 { 207 172 assert(scrbuf->col < scrbuf->cols); … … 211 176 scrbuf->row++; 212 177 213 return screenbuffer_update_rows(scrbuf);214 } 215 216 /** Jump to a new row in screenbuffer.217 * 218 * @param scrbuf Screenbuffer.178 return chargrid_update_rows(scrbuf); 179 } 180 181 /** Jump to a new row in chargrid. 182 * 183 * @param scrbuf Chargrid. 219 184 * @param tab_size Tab size. 220 185 * … … 224 189 * 225 190 */ 226 sysarg_t screenbuffer_tabstop(screenbuffer_t *scrbuf, sysarg_t tab_size)191 sysarg_t chargrid_tabstop(chargrid_t *scrbuf, sysarg_t tab_size) 227 192 { 228 193 assert(scrbuf->col < scrbuf->cols); … … 233 198 234 199 for (sysarg_t i = 0; i < spaces; i++) 235 flush += screenbuffer_putchar(scrbuf, ' ', true) - 1;200 flush += chargrid_putchar(scrbuf, ' ', true) - 1; 236 201 237 202 return flush; 238 203 } 239 204 240 /** Jump to the previous character in screenbuffer.205 /** Jump to the previous character in chargrid. 241 206 * 242 207 * Currently no scrollback is supported. 243 208 * 244 * @param scrbuf Screenbuffer.209 * @param scrbuf Chargrid. 245 210 * 246 211 * @return Number of rows which have been affected. In usual … … 250 215 * 251 216 */ 252 sysarg_t screenbuffer_backspace(screenbuffer_t *scrbuf)217 sysarg_t chargrid_backspace(chargrid_t *scrbuf) 253 218 { 254 219 assert(scrbuf->col < scrbuf->cols); … … 262 227 scrbuf->row--; 263 228 264 screenbuffer_putchar(scrbuf, ' ', false);229 chargrid_putchar(scrbuf, ' ', false); 265 230 return 2; 266 231 } 267 232 268 233 scrbuf->col--; 269 screenbuffer_putchar(scrbuf, ' ', false);234 chargrid_putchar(scrbuf, ' ', false); 270 235 return 1; 271 236 } 272 237 273 /** Clear the screenbuffer.274 * 275 * @param scrbuf Screenbuffer.276 * 277 */ 278 void screenbuffer_clear(screenbuffer_t *scrbuf)238 /** Clear the chargrid. 239 * 240 * @param scrbuf Chargrid. 241 * 242 */ 243 void chargrid_clear(chargrid_t *scrbuf) 279 244 { 280 245 for (size_t pos = 0; pos < (scrbuf->cols * scrbuf->rows); pos++) { … … 288 253 } 289 254 290 /** Update current screenbuffercoordinates291 * 292 * @param scrbuf Screenbuffer.255 /** Update current chargrid coordinates 256 * 257 * @param scrbuf Chargrid. 293 258 * @param col New column. 294 259 * @param row New row. 295 260 * 296 261 */ 297 void screenbuffer_set_cursor(screenbuffer_t *scrbuf, sysarg_t col, sysarg_t row)262 void chargrid_set_cursor(chargrid_t *scrbuf, sysarg_t col, sysarg_t row) 298 263 { 299 264 scrbuf->col = col; … … 301 266 } 302 267 303 void screenbuffer_set_cursor_visibility(screenbuffer_t *scrbuf, bool visible)268 void chargrid_set_cursor_visibility(chargrid_t *scrbuf, bool visible) 304 269 { 305 270 scrbuf->cursor_visible = visible; 306 271 } 307 272 308 /** Get current screenbuffercoordinates309 * 310 * @param scrbuf Screenbuffer.273 /** Get current chargrid coordinates 274 * 275 * @param scrbuf Chargrid. 311 276 * @param col Column. 312 277 * @param row Row. 313 278 * 314 279 */ 315 void screenbuffer_get_cursor(screenbuffer_t *scrbuf, sysarg_t *col,280 void chargrid_get_cursor(chargrid_t *scrbuf, sysarg_t *col, 316 281 sysarg_t *row) 317 282 { … … 323 288 } 324 289 325 bool screenbuffer_get_cursor_visibility(screenbuffer_t *scrbuf)290 bool chargrid_get_cursor_visibility(chargrid_t *scrbuf) 326 291 { 327 292 return scrbuf->cursor_visible; … … 330 295 /** Clear one buffer row. 331 296 * 332 * @param scrbuf Screenbuffer.297 * @param scrbuf Chargrid. 333 298 * @param row Row to clear. 334 299 * 335 300 */ 336 void screenbuffer_clear_row(screenbuffer_t *scrbuf, sysarg_t row)301 void chargrid_clear_row(chargrid_t *scrbuf, sysarg_t row) 337 302 { 338 303 for (sysarg_t col = 0; col < scrbuf->cols; col++) { 339 304 charfield_t *field = 340 screenbuffer_field_at(scrbuf, col, row);305 chargrid_charfield_at(scrbuf, col, row); 341 306 342 307 field->ch = 0; … … 346 311 } 347 312 348 /** Set screenbufferstyle.349 * 350 * @param scrbuf Screenbuffer.313 /** Set chargrid style. 314 * 315 * @param scrbuf Chargrid. 351 316 * @param style Style. 352 317 * 353 318 */ 354 void screenbuffer_set_style(screenbuffer_t *scrbuf, console_style_t style)319 void chargrid_set_style(chargrid_t *scrbuf, console_style_t style) 355 320 { 356 321 scrbuf->attrs.type = CHAR_ATTR_STYLE; … … 358 323 } 359 324 360 /** Set screenbuffercolor.361 * 362 * @param scrbuf Screenbuffer.325 /** Set chargrid color. 326 * 327 * @param scrbuf Chargrid. 363 328 * @param bgcolor Background color. 364 329 * @param fgcolor Foreground color. … … 366 331 * 367 332 */ 368 void screenbuffer_set_color(screenbuffer_t *scrbuf, console_color_t bgcolor,333 void chargrid_set_color(chargrid_t *scrbuf, console_color_t bgcolor, 369 334 console_color_t fgcolor, console_color_attr_t attr) 370 335 { … … 375 340 } 376 341 377 /** Set screenbufferRGB color.378 * 379 * @param scrbuf Screenbuffer.342 /** Set chargrid RGB color. 343 * 344 * @param scrbuf Chargrid. 380 345 * @param bgcolor Background color. 381 346 * @param fgcolor Foreground color. 382 347 * 383 348 */ 384 void screenbuffer_set_rgb_color(screenbuffer_t *scrbuf, pixel_t bgcolor,349 void chargrid_set_rgb_color(chargrid_t *scrbuf, pixel_t bgcolor, 385 350 pixel_t fgcolor) 386 351 { -
uspace/lib/c/generic/io/console.c
rb5d2e57 r03362fbd 38 38 #include <async.h> 39 39 #include <errno.h> 40 #include <stdio.h>41 40 #include <malloc.h> 42 41 #include <vfs/vfs_sess.h> … … 126 125 { 127 126 async_exch_t *exch = async_exchange_begin(ctrl->output_sess); 128 async_req_1_0(exch, CONSOLE_ CURSOR_VISIBILITY, (show != false));127 async_req_1_0(exch, CONSOLE_SET_CURSOR_VISIBILITY, (show != false)); 129 128 async_exchange_end(exch); 130 129 } … … 151 150 { 152 151 async_exch_t *exch = async_exchange_begin(ctrl->output_sess); 153 async_req_2_0(exch, CONSOLE_ GOTO, col, row);152 async_req_2_0(exch, CONSOLE_SET_POS, col, row); 154 153 async_exchange_end(exch); 155 154 } -
uspace/lib/c/generic/io/io.c
rb5d2e57 r03362fbd 39 39 #include <str.h> 40 40 #include <errno.h> 41 #include < bool.h>41 #include <stdbool.h> 42 42 #include <malloc.h> 43 43 #include <async.h> -
uspace/lib/c/generic/io/klog.c
rb5d2e57 r03362fbd 39 39 #include <unistd.h> 40 40 #include <errno.h> 41 #include <abi/klog.h> 41 42 #include <io/klog.h> 42 43 #include <io/printf_core.h> … … 44 45 size_t klog_write(const void *buf, size_t size) 45 46 { 46 ssize_t ret = (ssize_t) __SYSCALL3(SYS_KLOG, 1, (sysarg_t) buf, size);47 ssize_t ret = (ssize_t) __SYSCALL3(SYS_KLOG, KLOG_WRITE, (sysarg_t) buf, size); 47 48 48 49 if (ret >= 0) … … 54 55 void klog_update(void) 55 56 { 56 (void) __SYSCALL3(SYS_KLOG, 1, (uintptr_t) NULL, 0); 57 (void) __SYSCALL3(SYS_KLOG, KLOG_UPDATE, (uintptr_t) NULL, 0); 58 } 59 60 void klog_command(const void *buf, size_t size) 61 { 62 (void) __SYSCALL3(SYS_KLOG, KLOG_COMMAND, (sysarg_t) buf, (sysarg_t) size); 57 63 } 58 64 -
uspace/lib/c/generic/io/log.c
rb5d2e57 r03362fbd 38 38 #include <stdlib.h> 39 39 #include <stdio.h> 40 40 #include <async.h> 41 41 #include <io/log.h> 42 43 /** Serialization mutex for logging functions. */ 44 static FIBRIL_MUTEX_INITIALIZE(log_serializer); 45 46 /** Current log level. */ 47 static log_level_t log_level; 48 49 static FILE *log_stream; 50 42 #include <ipc/logger.h> 43 #include <ns.h> 44 45 /** Id of the first log we create at logger. */ 46 static sysarg_t default_log_id; 47 48 /** Log messages are printed under this name. */ 51 49 static const char *log_prog_name; 52 50 53 /** Prefixes for individual logging levels. */51 /** Names of individual log levels. */ 54 52 static const char *log_level_names[] = { 55 [LVL_FATAL] = "Fatal error", 56 [LVL_ERROR] = "Error", 57 [LVL_WARN] = "Warning", 58 [LVL_NOTE] = "Note", 59 [LVL_DEBUG] = "Debug", 60 [LVL_DEBUG2] = "Debug2" 53 "fatal", 54 "error", 55 "warn", 56 "note", 57 "debug", 58 "debug2", 59 NULL 61 60 }; 62 61 62 /** IPC session with the logger service. */ 63 static async_sess_t *logger_session; 64 65 /** Maximum length of a single log message (in bytes). */ 66 #define MESSAGE_BUFFER_SIZE 4096 67 68 /** Send formatted message to the logger service. 69 * 70 * @param session Initialized IPC session with the logger. 71 * @param log Log to use. 72 * @param level Verbosity level of the message. 73 * @param message The actual message. 74 * @return Error code of the conversion or EOK on success. 75 */ 76 static int logger_message(async_sess_t *session, log_t log, log_level_t level, char *message) 77 { 78 async_exch_t *exchange = async_exchange_begin(session); 79 if (exchange == NULL) { 80 return ENOMEM; 81 } 82 if (log == LOG_DEFAULT) 83 log = default_log_id; 84 85 // FIXME: remove when all USB drivers use libc logging explicitly 86 str_rtrim(message, '\n'); 87 88 aid_t reg_msg = async_send_2(exchange, LOGGER_WRITER_MESSAGE, 89 log, level, NULL); 90 int rc = async_data_write_start(exchange, message, str_size(message)); 91 sysarg_t reg_msg_rc; 92 async_wait_for(reg_msg, ®_msg_rc); 93 94 async_exchange_end(exchange); 95 96 /* 97 * Getting ENAK means no-one wants our message. That is not an 98 * error at all. 99 */ 100 if (rc == ENAK) 101 rc = EOK; 102 103 if (rc != EOK) { 104 return rc; 105 } 106 107 return reg_msg_rc; 108 } 109 110 /** Get name of the log level. 111 * 112 * @param level The log level. 113 * @return String name or "unknown". 114 */ 115 const char *log_level_str(log_level_t level) 116 { 117 if (level >= LVL_LIMIT) 118 return "unknown"; 119 else 120 return log_level_names[level]; 121 } 122 123 /** Convert log level name to the enum. 124 * 125 * @param[in] name Log level name or log level number. 126 * @param[out] level_out Where to store the result (set to NULL to ignore). 127 * @return Error code of the conversion or EOK on success. 128 */ 129 int log_level_from_str(const char *name, log_level_t *level_out) 130 { 131 log_level_t level = LVL_FATAL; 132 133 while (log_level_names[level] != NULL) { 134 if (str_cmp(name, log_level_names[level]) == 0) { 135 if (level_out != NULL) 136 *level_out = level; 137 return EOK; 138 } 139 level++; 140 } 141 142 /* Maybe user specified number directly. */ 143 char *end_ptr; 144 int level_int = strtol(name, &end_ptr, 0); 145 if ((end_ptr == name) || (str_length(end_ptr) != 0)) 146 return EINVAL; 147 if (level_int < 0) 148 return ERANGE; 149 if (level_int >= (int) LVL_LIMIT) 150 return ERANGE; 151 152 if (level_out != NULL) 153 *level_out = (log_level_t) level_int; 154 155 return EOK; 156 } 157 63 158 /** Initialize the logging system. 64 159 * 65 * @param prog_name Program name, will be printed as part of message 66 * @param level Minimum message level to print 67 */ 68 int log_init(const char *prog_name, log_level_t level) 69 { 70 assert(level < LVL_LIMIT); 71 log_level = level; 72 73 log_stream = stdout; 160 * @param prog_name Program name, will be printed as part of message 161 */ 162 int log_init(const char *prog_name) 163 { 74 164 log_prog_name = str_dup(prog_name); 75 165 if (log_prog_name == NULL) 76 166 return ENOMEM; 77 167 168 logger_session = service_connect_blocking(EXCHANGE_SERIALIZE, SERVICE_LOGGER, LOGGER_INTERFACE_WRITER, 0); 169 if (logger_session == NULL) { 170 return ENOMEM; 171 } 172 173 default_log_id = log_create(prog_name, LOG_NO_PARENT); 174 78 175 return EOK; 79 176 } 80 177 178 /** Create a new (sub-) log. 179 * 180 * This function always returns a valid log_t. In case of errors, 181 * @c parent is returned and errors are silently ignored. 182 * 183 * @param name Log name under which message will be reported (appended to parents name). 184 * @param parent Parent log. 185 * @return Opaque identifier of the newly created log. 186 */ 187 log_t log_create(const char *name, log_t parent) 188 { 189 async_exch_t *exchange = async_exchange_begin(logger_session); 190 if (exchange == NULL) 191 return parent; 192 193 if (parent == LOG_DEFAULT) 194 parent = default_log_id; 195 196 ipc_call_t answer; 197 aid_t reg_msg = async_send_1(exchange, LOGGER_WRITER_CREATE_LOG, 198 parent, &answer); 199 int rc = async_data_write_start(exchange, name, str_size(name)); 200 sysarg_t reg_msg_rc; 201 async_wait_for(reg_msg, ®_msg_rc); 202 203 async_exchange_end(exchange); 204 205 if ((rc != EOK) || (reg_msg_rc != EOK)) 206 return parent; 207 208 return IPC_GET_ARG1(answer); 209 } 210 81 211 /** Write an entry to the log. 82 212 * 83 * @param level Message verbosity level. Message is only printed 84 * if verbosity is less than or equal to current 85 * reporting level. 86 * @param fmt Format string (no traling newline). 87 */ 88 void log_msg(log_level_t level, const char *fmt, ...) 213 * The message is printed only if the verbosity level is less than or 214 * equal to currently set reporting level of the log. 215 * 216 * @param ctx Log to use (use LOG_DEFAULT if you have no idea what it means). 217 * @param level Severity level of the message. 218 * @param fmt Format string in printf-like format (without trailing newline). 219 */ 220 void log_msg(log_t ctx, log_level_t level, const char *fmt, ...) 89 221 { 90 222 va_list args; 91 223 92 224 va_start(args, fmt); 93 log_msgv( level, fmt, args);225 log_msgv(ctx, level, fmt, args); 94 226 va_end(args); 95 227 } … … 97 229 /** Write an entry to the log (va_list variant). 98 230 * 99 * @param level Message verbosity level. Message is only printed100 * if verbosity is less than or equal to current101 * reporting level.102 * @param fmt Format string (no trailing newline)103 */ 104 void log_msgv(log_ level_t level, const char *fmt, va_list args)231 * @param ctx Log to use (use LOG_DEFAULT if you have no idea what it means). 232 * @param level Severity level of the message. 233 * @param fmt Format string in printf-like format (without trailing newline). 234 * @param args Arguments. 235 */ 236 void log_msgv(log_t ctx, log_level_t level, const char *fmt, va_list args) 105 237 { 106 238 assert(level < LVL_LIMIT); 107 239 108 /* Higher number means higher verbosity. */ 109 if (level <= log_level) { 110 fibril_mutex_lock(&log_serializer); 111 112 fprintf(log_stream, "%s: %s: ", log_prog_name, 113 log_level_names[level]); 114 vfprintf(log_stream, fmt, args); 115 fputc('\n', log_stream); 116 fflush(log_stream); 117 118 fibril_mutex_unlock(&log_serializer); 119 } 240 char *message_buffer = malloc(MESSAGE_BUFFER_SIZE); 241 if (message_buffer == NULL) 242 return; 243 244 vsnprintf(message_buffer, MESSAGE_BUFFER_SIZE, fmt, args); 245 logger_message(logger_session, ctx, level, message_buffer); 246 free(message_buffer); 120 247 } 121 248 -
uspace/lib/c/generic/io/printf_core.c
rb5d2e57 r03362fbd 42 42 #include <ctype.h> 43 43 #include <str.h> 44 #include <double_to_str.h> 45 #include <ieee_double.h> 46 #include <assert.h> 47 #include <macros.h> 48 44 49 45 50 /** show prefixes 0x or 0 */ 46 51 #define __PRINTF_FLAG_PREFIX 0x00000001 47 52 53 /** show the decimal point even if no fractional digits present */ 54 #define __PRINTF_FLAG_DECIMALPT 0x00000001 55 48 56 /** signed / unsigned number */ 49 57 #define __PRINTF_FLAG_SIGNED 0x00000002 … … 66 74 /** number has - sign */ 67 75 #define __PRINTF_FLAG_NEGATIVE 0x00000100 76 77 /** don't print trailing zeros in the fractional part */ 78 #define __PRINTF_FLAG_NOFRACZEROS 0x00000200 79 68 80 69 81 /** … … 110 122 static const char invalch = U_SPECIAL; 111 123 124 125 126 /** Unformatted double number string representation. */ 127 typedef struct { 128 /** Buffer with len digits, no sign or leading zeros. */ 129 char *str; 130 /** Number of digits in str. */ 131 int len; 132 /** Decimal exponent, ie number = str * 10^dec_exp */ 133 int dec_exp; 134 /** True if negative. */ 135 bool neg; 136 } double_str_t; 137 138 139 140 /** Returns the sign character or 0 if no sign should be printed. */ 141 static int get_sign_char(bool negative, uint32_t flags) 142 { 143 if (negative) { 144 return '-'; 145 } else if (flags & __PRINTF_FLAG_SHOWPLUS) { 146 return '+'; 147 } else if (flags & __PRINTF_FLAG_SPACESIGN) { 148 return ' '; 149 } else { 150 return 0; 151 } 152 } 153 154 /** Prints count times character ch. */ 155 static int print_padding(char ch, int count, printf_spec_t *ps) 156 { 157 for (int i = 0; i < count; ++i) { 158 if (ps->str_write(&ch, 1, ps->data) < 0) { 159 return -1; 160 } 161 } 162 163 return count; 164 } 165 166 112 167 /** Print one or more characters without adding newline. 113 168 * … … 281 336 return printf_putstr(nullstr, ps); 282 337 283 /* Print leading spaces. */284 338 size_t strw = str_length(str); 339 340 /* Precision unspecified - print everything. */ 285 341 if ((precision == 0) || (precision > strw)) 286 342 precision = strw; … … 329 385 return printf_putstr(nullstr, ps); 330 386 331 /* Print leading spaces. */332 387 size_t strw = wstr_length(str); 388 389 /* Precision not specified - print everything. */ 333 390 if ((precision == 0) || (precision > strw)) 334 391 precision = strw; … … 377 434 uint32_t flags, printf_spec_t *ps) 378 435 { 436 /* Precision not specified. */ 437 if (precision < 0) { 438 precision = 0; 439 } 440 379 441 const char *digits; 380 442 if (flags & __PRINTF_FLAG_BIGCHARS) … … 525 587 526 588 return ((int) counter); 589 } 590 591 /** Prints a special double (ie NaN, infinity) padded to width characters. */ 592 static int print_special(ieee_double_t val, int width, uint32_t flags, 593 printf_spec_t *ps) 594 { 595 assert(val.is_special); 596 597 char sign = get_sign_char(val.is_negative, flags); 598 599 const int str_len = 3; 600 const char *str; 601 602 if (flags & __PRINTF_FLAG_BIGCHARS) { 603 str = val.is_infinity ? "INF" : "NAN"; 604 } else { 605 str = val.is_infinity ? "inf" : "nan"; 606 } 607 608 int padding_len = max(0, width - ((sign ? 1 : 0) + str_len)); 609 610 int counter = 0; 611 int ret; 612 613 /* Leading padding. */ 614 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) { 615 if ((ret = print_padding(' ', padding_len, ps)) < 0) 616 return -1; 617 618 counter += ret; 619 } 620 621 if (sign) { 622 if ((ret = ps->str_write(&sign, 1, ps->data)) < 0) 623 return -1; 624 625 counter += ret; 626 } 627 628 if ((ret = ps->str_write(str, str_len, ps->data)) < 0) 629 return -1; 630 631 counter += ret; 632 633 634 /* Trailing padding. */ 635 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 636 if ((ret = print_padding(' ', padding_len, ps)) < 0) 637 return -1; 638 639 counter += ret; 640 } 641 642 return counter; 643 } 644 645 /** Trims trailing zeros but leaves a single "0" intact. */ 646 static void fp_trim_trailing_zeros(char *buf, int *len, int *dec_exp) 647 { 648 /* Cut the zero off by adjusting the exponent. */ 649 while (2 <= *len && '0' == buf[*len - 1]) { 650 --*len; 651 ++*dec_exp; 652 } 653 } 654 655 /** Textually round up the last digit thereby eliminating it. */ 656 static void fp_round_up(char *buf, int *len, int *dec_exp) 657 { 658 assert(1 <= *len); 659 660 char *last_digit = &buf[*len - 1]; 661 662 int carry = ('5' <= *last_digit); 663 664 /* Cut the digit off by adjusting the exponent. */ 665 --*len; 666 ++*dec_exp; 667 --last_digit; 668 669 if (carry) { 670 /* Skip all the digits to cut off/round to zero. */ 671 while (buf <= last_digit && '9' == *last_digit) { 672 --last_digit; 673 } 674 675 /* last_digit points to the last digit to round but not '9' */ 676 if (buf <= last_digit) { 677 *last_digit += 1; 678 int new_len = last_digit - buf + 1; 679 *dec_exp += *len - new_len; 680 *len = new_len; 681 } else { 682 /* All len digits rounded to 0. */ 683 buf[0] = '1'; 684 *dec_exp += *len; 685 *len = 1; 686 } 687 } else { 688 /* The only digit was rounded to 0. */ 689 if (last_digit < buf) { 690 buf[0] = '0'; 691 *dec_exp = 0; 692 *len = 1; 693 } 694 } 695 } 696 697 698 /** Format and print the double string repressentation according 699 * to the %f specifier. 700 */ 701 static int print_double_str_fixed(double_str_t *val_str, int precision, int width, 702 uint32_t flags, printf_spec_t *ps) 703 { 704 int len = val_str->len; 705 char *buf = val_str->str; 706 int dec_exp = val_str->dec_exp; 707 708 assert(0 < len); 709 assert(0 <= precision); 710 assert(0 <= dec_exp || -dec_exp <= precision); 711 712 /* Number of integral digits to print (at least leading zero). */ 713 int int_len = max(1, len + dec_exp); 714 715 char sign = get_sign_char(val_str->neg, flags); 716 717 /* Fractional portion lengths. */ 718 int last_frac_signif_pos = max(0, -dec_exp); 719 int leading_frac_zeros = max(0, last_frac_signif_pos - len); 720 int signif_frac_figs = min(last_frac_signif_pos, len); 721 int trailing_frac_zeros = precision - last_frac_signif_pos; 722 char *buf_frac = buf + len - signif_frac_figs; 723 724 if (flags & __PRINTF_FLAG_NOFRACZEROS) { 725 trailing_frac_zeros = 0; 726 } 727 728 int frac_len = leading_frac_zeros + signif_frac_figs + trailing_frac_zeros; 729 730 bool has_decimal_pt = (0 < frac_len) || (flags & __PRINTF_FLAG_DECIMALPT); 731 732 /* Number of non-padding chars to print. */ 733 int num_len = (sign ? 1 : 0) + int_len + (has_decimal_pt ? 1 : 0) + frac_len; 734 735 int padding_len = max(0, width - num_len); 736 int ret = 0; 737 int counter = 0; 738 739 /* Leading padding and sign. */ 740 741 if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) { 742 if ((ret = print_padding(' ', padding_len, ps)) < 0) 743 return -1; 744 745 counter += ret; 746 } 747 748 if (sign) { 749 if ((ret = ps->str_write(&sign, 1, ps->data)) < 0) 750 return -1; 751 752 counter += ret; 753 } 754 755 if (flags & __PRINTF_FLAG_ZEROPADDED) { 756 if ((ret = print_padding('0', padding_len, ps)) < 0) 757 return -1; 758 759 counter += ret; 760 } 761 762 /* Print the intergral part of the buffer. */ 763 764 int buf_int_len = min(len, len + dec_exp); 765 766 if (0 < buf_int_len) { 767 if ((ret = ps->str_write(buf, buf_int_len, ps->data)) < 0) 768 return -1; 769 770 counter += ret; 771 772 /* Print trailing zeros of the integral part of the number. */ 773 if ((ret = print_padding('0', int_len - buf_int_len, ps)) < 0) 774 return -1; 775 } else { 776 /* Single leading integer 0. */ 777 char ch = '0'; 778 if ((ret = ps->str_write(&ch, 1, ps->data)) < 0) 779 return -1; 780 } 781 782 counter += ret; 783 784 /* Print the decimal point and the fractional part. */ 785 if (has_decimal_pt) { 786 char ch = '.'; 787 788 if ((ret = ps->str_write(&ch, 1, ps->data)) < 0) 789 return -1; 790 791 counter += ret; 792 793 /* Print leading zeros of the fractional part of the number. */ 794 if ((ret = print_padding('0', leading_frac_zeros, ps)) < 0) 795 return -1; 796 797 counter += ret; 798 799 /* Print significant digits of the fractional part of the number. */ 800 if (0 < signif_frac_figs) { 801 if ((ret = ps->str_write(buf_frac, signif_frac_figs, ps->data)) < 0) 802 return -1; 803 804 counter += ret; 805 } 806 807 /* Print trailing zeros of the fractional part of the number. */ 808 if ((ret = print_padding('0', trailing_frac_zeros, ps)) < 0) 809 return -1; 810 811 counter += ret; 812 } 813 814 /* Trailing padding. */ 815 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 816 if ((ret = print_padding(' ', padding_len, ps)) < 0) 817 return -1; 818 819 counter += ret; 820 } 821 822 return counter; 823 } 824 825 826 /** Convert, format and print a double according to the %f specifier. 827 * 828 * @param g Double to print. 829 * @param precision Number of fractional digits to print. If 0 no 830 * decimal point will be printed unless the flag 831 * __PRINTF_FLAG_DECIMALPT is specified. 832 * @param width Minimum number of characters to display. Pads 833 * with '0' or ' ' depending on the set flags; 834 * @param flags Printf flags. 835 * @param ps Printing functions. 836 * 837 * @return The number of characters printed; negative on failure. 838 */ 839 static int print_double_fixed(double g, int precision, int width, uint32_t flags, 840 printf_spec_t *ps) 841 { 842 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 843 flags &= ~__PRINTF_FLAG_ZEROPADDED; 844 } 845 846 if (flags & __PRINTF_FLAG_DECIMALPT) { 847 flags &= ~__PRINTF_FLAG_NOFRACZEROS; 848 } 849 850 ieee_double_t val = extract_ieee_double(g); 851 852 if (val.is_special) { 853 return print_special(val, width, flags, ps); 854 } 855 856 char buf[MAX_DOUBLE_STR_BUF_SIZE]; 857 const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE; 858 double_str_t val_str; 859 860 val_str.str = buf; 861 val_str.neg = val.is_negative; 862 863 if (0 <= precision) { 864 /* 865 * Request one more digit so we can round the result. The last 866 * digit it returns may have an error of at most +/- 1. 867 */ 868 val_str.len = double_to_fixed_str(val, -1, precision + 1, buf, buf_size, 869 &val_str.dec_exp); 870 871 /* 872 * Round using the last digit to produce precision fractional digits. 873 * If less than precision+1 fractional digits were output the last 874 * digit is definitely inaccurate so also round to get rid of it. 875 */ 876 fp_round_up(buf, &val_str.len, &val_str.dec_exp); 877 878 /* Rounding could have introduced trailing zeros. */ 879 if (flags & __PRINTF_FLAG_NOFRACZEROS) { 880 fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp); 881 } 882 } else { 883 /* Let the implementation figure out the proper precision. */ 884 val_str.len = double_to_short_str(val, buf, buf_size, &val_str.dec_exp); 885 886 /* Precision needed for the last significant digit. */ 887 precision = max(0, -val_str.dec_exp); 888 } 889 890 return print_double_str_fixed(&val_str, precision, width, flags, ps); 891 } 892 893 /** Prints the decimal exponent part of a %e specifier formatted number. */ 894 static int print_exponent(int exp_val, uint32_t flags, printf_spec_t *ps) 895 { 896 int counter = 0; 897 int ret; 898 899 char exp_ch = (flags & __PRINTF_FLAG_BIGCHARS) ? 'E' : 'e'; 900 901 if ((ret = ps->str_write(&exp_ch, 1, ps->data)) < 0) 902 return -1; 903 904 counter += ret; 905 906 char exp_sign = (exp_val < 0) ? '-' : '+'; 907 908 if ((ret = ps->str_write(&exp_sign, 1, ps->data)) < 0) 909 return -1; 910 911 counter += ret; 912 913 /* Print the exponent. */ 914 exp_val = abs(exp_val); 915 916 char exp_str[4] = { 0 }; 917 918 exp_str[0] = '0' + exp_val / 100; 919 exp_str[1] = '0' + (exp_val % 100) / 10 ; 920 exp_str[2] = '0' + (exp_val % 10); 921 922 int exp_len = (exp_str[0] == '0') ? 2 : 3; 923 const char *exp_str_start = &exp_str[3] - exp_len; 924 925 if ((ret = ps->str_write(exp_str_start, exp_len, ps->data)) < 0) 926 return -1; 927 928 counter += ret; 929 930 return counter; 931 } 932 933 934 /** Format and print the double string repressentation according 935 * to the %e specifier. 936 */ 937 static int print_double_str_scient(double_str_t *val_str, int precision, 938 int width, uint32_t flags, printf_spec_t *ps) 939 { 940 int len = val_str->len; 941 int dec_exp = val_str->dec_exp; 942 char *buf = val_str->str; 943 944 assert(0 < len); 945 946 char sign = get_sign_char(val_str->neg, flags); 947 bool has_decimal_pt = (0 < precision) || (flags & __PRINTF_FLAG_DECIMALPT); 948 int dec_pt_len = has_decimal_pt ? 1 : 0; 949 950 /* Fractional part lengths. */ 951 int signif_frac_figs = len - 1; 952 int trailing_frac_zeros = precision - signif_frac_figs; 953 954 if (flags & __PRINTF_FLAG_NOFRACZEROS) { 955 trailing_frac_zeros = 0; 956 } 957 958 int frac_len = signif_frac_figs + trailing_frac_zeros; 959 960 int exp_val = dec_exp + len - 1; 961 /* Account for exponent sign and 'e'; minimum 2 digits. */ 962 int exp_len = 2 + (abs(exp_val) >= 100 ? 3 : 2); 963 964 /* Number of non-padding chars to print. */ 965 int num_len = (sign ? 1 : 0) + 1 + dec_pt_len + frac_len + exp_len; 966 967 int padding_len = max(0, width - num_len); 968 int ret = 0; 969 int counter = 0; 970 971 if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) { 972 if ((ret = print_padding(' ', padding_len, ps)) < 0) 973 return -1; 974 975 counter += ret; 976 } 977 978 if (sign) { 979 if ((ret = ps->str_write(&sign, 1, ps->data)) < 0) 980 return -1; 981 982 counter += ret; 983 } 984 985 if (flags & __PRINTF_FLAG_ZEROPADDED) { 986 if ((ret = print_padding('0', padding_len, ps)) < 0) 987 return -1; 988 989 counter += ret; 990 } 991 992 /* Single leading integer. */ 993 if ((ret = ps->str_write(buf, 1, ps->data)) < 0) 994 return -1; 995 996 counter += ret; 997 998 /* Print the decimal point and the fractional part. */ 999 if (has_decimal_pt) { 1000 char ch = '.'; 1001 1002 if ((ret = ps->str_write(&ch, 1, ps->data)) < 0) 1003 return -1; 1004 1005 counter += ret; 1006 1007 /* Print significant digits of the fractional part of the number. */ 1008 if (0 < signif_frac_figs) { 1009 if ((ret = ps->str_write(buf + 1, signif_frac_figs, ps->data)) < 0) 1010 return -1; 1011 1012 counter += ret; 1013 } 1014 1015 /* Print trailing zeros of the fractional part of the number. */ 1016 if ((ret = print_padding('0', trailing_frac_zeros, ps)) < 0) 1017 return -1; 1018 1019 counter += ret; 1020 } 1021 1022 /* Print the exponent. */ 1023 if ((ret = print_exponent(exp_val, flags, ps)) < 0) 1024 return -1; 1025 1026 counter += ret; 1027 1028 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 1029 if ((ret = print_padding(' ', padding_len, ps)) < 0) 1030 return -1; 1031 1032 counter += ret; 1033 } 1034 1035 return counter; 1036 } 1037 1038 1039 /** Convert, format and print a double according to the %e specifier. 1040 * 1041 * Note that if g is large, the output may be huge (3e100 prints 1042 * with at least 100 digits). 1043 * 1044 * %e style: [-]d.dddde+dd 1045 * left-justified: [-]d.dddde+dd[space_pad] 1046 * right-justified: [space_pad][-][zero_pad]d.dddde+dd 1047 * 1048 * @param g Double to print. 1049 * @param precision Number of fractional digits to print, ie 1050 * precision + 1 significant digits to display. If 0 no 1051 * decimal point will be printed unless the flag 1052 * __PRINTF_FLAG_DECIMALPT is specified. If negative 1053 * the shortest accurate number will be printed. 1054 * @param width Minimum number of characters to display. Pads 1055 * with '0' or ' ' depending on the set flags; 1056 * @param flags Printf flags. 1057 * @param ps Printing functions. 1058 * 1059 * @return The number of characters printed; negative on failure. 1060 */ 1061 static int print_double_scientific(double g, int precision, int width, 1062 uint32_t flags, printf_spec_t *ps) 1063 { 1064 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 1065 flags &= ~__PRINTF_FLAG_ZEROPADDED; 1066 } 1067 1068 ieee_double_t val = extract_ieee_double(g); 1069 1070 if (val.is_special) { 1071 return print_special(val, width, flags, ps); 1072 } 1073 1074 char buf[MAX_DOUBLE_STR_BUF_SIZE]; 1075 const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE; 1076 double_str_t val_str; 1077 1078 val_str.str = buf; 1079 val_str.neg = val.is_negative; 1080 1081 if (0 <= precision) { 1082 /* 1083 * Request one more digit (in addition to the leading integer) 1084 * so we can round the result. The last digit it returns may 1085 * have an error of at most +/- 1. 1086 */ 1087 val_str.len = double_to_fixed_str(val, precision + 2, -1, buf, buf_size, 1088 &val_str.dec_exp); 1089 1090 /* 1091 * Round the extra digit to produce precision+1 significant digits. 1092 * If less than precision+2 significant digits were returned the last 1093 * digit is definitely inaccurate so also round to get rid of it. 1094 */ 1095 fp_round_up(buf, &val_str.len, &val_str.dec_exp); 1096 1097 /* Rounding could have introduced trailing zeros. */ 1098 if (flags & __PRINTF_FLAG_NOFRACZEROS) { 1099 fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp); 1100 } 1101 } else { 1102 /* Let the implementation figure out the proper precision. */ 1103 val_str.len = double_to_short_str(val, buf, buf_size, &val_str.dec_exp); 1104 1105 /* Use all produced digits. */ 1106 precision = val_str.len - 1; 1107 } 1108 1109 return print_double_str_scient(&val_str, precision, width, flags, ps); 1110 } 1111 1112 1113 /** Convert, format and print a double according to the %g specifier. 1114 * 1115 * %g style chooses between %f and %e. 1116 * 1117 * @param g Double to print. 1118 * @param precision Number of significant digits to display; excluding 1119 * any leading zeros from this count. If negative 1120 * the shortest accurate number will be printed. 1121 * @param width Minimum number of characters to display. Pads 1122 * with '0' or ' ' depending on the set flags; 1123 * @param flags Printf flags. 1124 * @param ps Printing functions. 1125 * 1126 * @return The number of characters printed; negative on failure. 1127 */ 1128 static int print_double_generic(double g, int precision, int width, 1129 uint32_t flags, printf_spec_t *ps) 1130 { 1131 ieee_double_t val = extract_ieee_double(g); 1132 1133 if (val.is_special) { 1134 return print_special(val, width, flags, ps); 1135 } 1136 1137 char buf[MAX_DOUBLE_STR_BUF_SIZE]; 1138 const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE; 1139 int dec_exp; 1140 int len; 1141 1142 /* Honor the user requested number of significant digits. */ 1143 if (0 <= precision) { 1144 /* 1145 * Do a quick and dirty conversion of a single digit to determine 1146 * the decimal exponent. 1147 */ 1148 len = double_to_fixed_str(val, 1, -1, buf, buf_size, &dec_exp); 1149 assert(0 < len); 1150 1151 precision = max(1, precision); 1152 1153 if (-4 <= dec_exp && dec_exp < precision) { 1154 precision = precision - (dec_exp + 1); 1155 return print_double_fixed(g, precision, width, 1156 flags | __PRINTF_FLAG_NOFRACZEROS, ps); 1157 } else { 1158 --precision; 1159 return print_double_scientific(g, precision, width, 1160 flags | __PRINTF_FLAG_NOFRACZEROS, ps); 1161 } 1162 } else { 1163 /* Convert to get the decimal exponent and digit count.*/ 1164 len = double_to_short_str(val, buf, buf_size, &dec_exp); 1165 assert(0 < len); 1166 1167 if (flags & __PRINTF_FLAG_LEFTALIGNED) { 1168 flags &= ~__PRINTF_FLAG_ZEROPADDED; 1169 } 1170 1171 double_str_t val_str; 1172 val_str.str = buf; 1173 val_str.len = len; 1174 val_str.neg = val.is_negative; 1175 val_str.dec_exp = dec_exp; 1176 1177 int first_digit_pos = len + dec_exp; 1178 int last_digit_pos = dec_exp; 1179 1180 /* The whole number (15 digits max) fits between dec places 15 .. -6 */ 1181 if (len <= 15 && -6 <= last_digit_pos && first_digit_pos <= 15) { 1182 /* Precision needed for the last significant digit. */ 1183 precision = max(0, -val_str.dec_exp); 1184 return print_double_str_fixed(&val_str, precision, width, flags, ps); 1185 } else { 1186 /* Use all produced digits. */ 1187 precision = val_str.len - 1; 1188 return print_double_str_scient(&val_str, precision, width, flags, ps); 1189 } 1190 } 1191 } 1192 1193 1194 /** Convert, format and print a double according to the specifier. 1195 * 1196 * Depending on the specifier it prints the double using the styles 1197 * %g, %f or %e by means of print_double_generic(), print_double_fixed(), 1198 * print_double_scientific(). 1199 * 1200 * @param g Double to print. 1201 * @param spec Specifier of the style to print in; one of: 'g','G','f','F', 1202 * 'e','E'. 1203 * @param precision Number of fractional digits to display. If negative 1204 * the shortest accurate number will be printed for style %g; 1205 * negative precision defaults to 6 for styles %f, %e. 1206 * @param width Minimum number of characters to display. Pads 1207 * with '0' or ' ' depending on the set flags; 1208 * @param flags Printf flags. 1209 * @param ps Printing functions. 1210 * 1211 * @return The number of characters printed; negative on failure. 1212 */ 1213 static int print_double(double g, char spec, int precision, int width, 1214 uint32_t flags, printf_spec_t *ps) 1215 { 1216 switch (spec) { 1217 case 'F': 1218 flags |= __PRINTF_FLAG_BIGCHARS; 1219 /* Fall through.*/ 1220 case 'f': 1221 precision = (precision < 0) ? 6 : precision; 1222 return print_double_fixed(g, precision, width, flags, ps); 1223 1224 case 'E': 1225 flags |= __PRINTF_FLAG_BIGCHARS; 1226 /* Fall through.*/ 1227 case 'e': 1228 precision = (precision < 0) ? 6 : precision; 1229 return print_double_scientific(g, precision, width, flags, ps); 1230 1231 case 'G': 1232 flags |= __PRINTF_FLAG_BIGCHARS; 1233 /* Fall through.*/ 1234 case 'g': 1235 return print_double_generic(g, precision, width, flags, ps); 1236 1237 default: 1238 assert(false); 1239 return -1; 1240 } 527 1241 } 528 1242 … … 656 1370 case '#': 657 1371 flags |= __PRINTF_FLAG_PREFIX; 1372 flags |= __PRINTF_FLAG_DECIMALPT; 658 1373 break; 659 1374 case '-': … … 701 1416 702 1417 /* Precision and '*' operator */ 703 int precision = 0;1418 int precision = -1; 704 1419 if (uc == '.') { 705 1420 i = nxt; 706 1421 uc = str_decode(fmt, &nxt, STR_NO_LIMIT); 707 1422 if (isdigit(uc)) { 1423 precision = 0; 708 1424 while (true) { 709 1425 precision *= 10; … … 723 1439 precision = (int) va_arg(ap, int); 724 1440 if (precision < 0) { 725 /* Ignore negative precision */726 precision = 0;1441 /* Ignore negative precision - use default instead */ 1442 precision = -1; 727 1443 } 728 1444 } … … 774 1490 */ 775 1491 case 's': 1492 precision = max(0, precision); 1493 776 1494 if (qualifier == PrintfQualifierLong) 777 1495 retval = print_wstr(va_arg(ap, wchar_t *), width, precision, flags, ps); … … 797 1515 goto out; 798 1516 }; 1517 1518 counter += retval; 1519 j = nxt; 1520 goto next_char; 1521 1522 /* 1523 * Floating point values 1524 */ 1525 case 'G': 1526 case 'g': 1527 case 'F': 1528 case 'f': 1529 case 'E': 1530 case 'e': 1531 retval = print_double(va_arg(ap, double), uc, precision, 1532 width, flags, ps); 1533 1534 if (retval < 0) { 1535 counter = -counter; 1536 goto out; 1537 } 799 1538 800 1539 counter += retval; -
uspace/lib/c/generic/ipc.c
rb5d2e57 r03362fbd 48 48 #include <fibril.h> 49 49 #include <macros.h> 50 #include "private/libc.h"51 50 52 51 /** … … 83 82 84 83 static atomic_t ipc_futex = FUTEX_INITIALIZER; 85 86 /** Fast synchronous call.87 *88 * Only three payload arguments can be passed using this function. However,89 * this function is faster than the generic ipc_call_sync_slow() because90 * the payload is passed directly in registers.91 *92 * @param phoneid Phone handle for the call.93 * @param method Requested method.94 * @param arg1 Service-defined payload argument.95 * @param arg2 Service-defined payload argument.96 * @param arg3 Service-defined payload argument.97 * @param result1 If non-NULL, the return ARG1 will be stored there.98 * @param result2 If non-NULL, the return ARG2 will be stored there.99 * @param result3 If non-NULL, the return ARG3 will be stored there.100 * @param result4 If non-NULL, the return ARG4 will be stored there.101 * @param result5 If non-NULL, the return ARG5 will be stored there.102 *103 * @return Negative values representing IPC errors.104 * @return Otherwise the RETVAL of the answer.105 *106 */107 int ipc_call_sync_fast(int phoneid, sysarg_t method, sysarg_t arg1,108 sysarg_t arg2, sysarg_t arg3, sysarg_t *result1, sysarg_t *result2,109 sysarg_t *result3, sysarg_t *result4, sysarg_t *result5)110 {111 ipc_call_t resdata;112 int callres = __SYSCALL6(SYS_IPC_CALL_SYNC_FAST, phoneid, method, arg1,113 arg2, arg3, (sysarg_t) &resdata);114 if (callres)115 return callres;116 117 if (result1)118 *result1 = IPC_GET_ARG1(resdata);119 if (result2)120 *result2 = IPC_GET_ARG2(resdata);121 if (result3)122 *result3 = IPC_GET_ARG3(resdata);123 if (result4)124 *result4 = IPC_GET_ARG4(resdata);125 if (result5)126 *result5 = IPC_GET_ARG5(resdata);127 128 return IPC_GET_RETVAL(resdata);129 }130 131 /** Synchronous call transmitting 5 arguments of payload.132 *133 * @param phoneid Phone handle for the call.134 * @param imethod Requested interface and method.135 * @param arg1 Service-defined payload argument.136 * @param arg2 Service-defined payload argument.137 * @param arg3 Service-defined payload argument.138 * @param arg4 Service-defined payload argument.139 * @param arg5 Service-defined payload argument.140 * @param result1 If non-NULL, storage for the first return argument.141 * @param result2 If non-NULL, storage for the second return argument.142 * @param result3 If non-NULL, storage for the third return argument.143 * @param result4 If non-NULL, storage for the fourth return argument.144 * @param result5 If non-NULL, storage for the fifth return argument.145 *146 * @return Negative values representing IPC errors.147 * @return Otherwise the RETVAL of the answer.148 *149 */150 int ipc_call_sync_slow(int phoneid, sysarg_t imethod, sysarg_t arg1,151 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,152 sysarg_t *result1, sysarg_t *result2, sysarg_t *result3, sysarg_t *result4,153 sysarg_t *result5)154 {155 ipc_call_t data;156 157 IPC_SET_IMETHOD(data, imethod);158 IPC_SET_ARG1(data, arg1);159 IPC_SET_ARG2(data, arg2);160 IPC_SET_ARG3(data, arg3);161 IPC_SET_ARG4(data, arg4);162 IPC_SET_ARG5(data, arg5);163 164 int callres = __SYSCALL3(SYS_IPC_CALL_SYNC_SLOW, phoneid,165 (sysarg_t) &data, (sysarg_t) &data);166 if (callres)167 return callres;168 169 if (result1)170 *result1 = IPC_GET_ARG1(data);171 if (result2)172 *result2 = IPC_GET_ARG2(data);173 if (result3)174 *result3 = IPC_GET_ARG3(data);175 if (result4)176 *result4 = IPC_GET_ARG4(data);177 if (result5)178 *result5 = IPC_GET_ARG5(data);179 180 return IPC_GET_RETVAL(data);181 }182 84 183 85 /** Send asynchronous message via syscall. … … 611 513 } 612 514 613 /** Request callback connection.614 *615 * The @a task_id and @a phonehash identifiers returned616 * by the kernel can be used for connection tracking.617 *618 * @param phoneid Phone handle used for contacting the other side.619 * @param arg1 User defined argument.620 * @param arg2 User defined argument.621 * @param arg3 User defined argument.622 * @param task_id Identifier of the client task.623 * @param phonehash Opaque identifier of the phone that will624 * be used for incoming calls.625 *626 * @return Zero on success or a negative error code.627 *628 */629 int ipc_connect_to_me(int phoneid, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,630 task_id_t *task_id, sysarg_t *phonehash)631 {632 ipc_call_t data;633 int rc = __SYSCALL6(SYS_IPC_CALL_SYNC_FAST, phoneid,634 IPC_M_CONNECT_TO_ME, arg1, arg2, arg3, (sysarg_t) &data);635 if (rc == EOK) {636 *task_id = data.in_task_id;637 *phonehash = IPC_GET_ARG5(data);638 }639 return rc;640 }641 642 /** Request cloned connection.643 *644 * @param phoneid Phone handle used for contacting the other side.645 *646 * @return Cloned phone handle on success or a negative error code.647 *648 */649 int ipc_clone_establish(int phoneid)650 {651 sysarg_t newphid;652 int res = ipc_call_sync_0_5(phoneid, IPC_M_CLONE_ESTABLISH, NULL,653 NULL, NULL, NULL, &newphid);654 if (res)655 return res;656 657 return newphid;658 }659 660 /** Request new connection.661 *662 * @param phoneid Phone handle used for contacting the other side.663 * @param arg1 User defined argument.664 * @param arg2 User defined argument.665 * @param arg3 User defined argument.666 *667 * @return New phone handle on success or a negative error code.668 *669 */670 int ipc_connect_me_to(int phoneid, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)671 {672 sysarg_t newphid;673 int res = ipc_call_sync_3_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,674 NULL, NULL, NULL, NULL, &newphid);675 if (res)676 return res;677 678 return newphid;679 }680 681 /** Request new connection (blocking)682 *683 * If the connection is not available at the moment, the684 * call should block. This has to be, however, implemented685 * on the server side.686 *687 * @param phoneid Phone handle used for contacting the other side.688 * @param arg1 User defined argument.689 * @param arg2 User defined argument.690 * @param arg3 User defined argument.691 *692 * @return New phone handle on success or a negative error code.693 *694 */695 int ipc_connect_me_to_blocking(int phoneid, sysarg_t arg1, sysarg_t arg2,696 sysarg_t arg3)697 {698 sysarg_t newphid;699 int res = ipc_call_sync_4_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,700 IPC_FLAG_BLOCKING, NULL, NULL, NULL, NULL, &newphid);701 if (res)702 return res;703 704 return newphid;705 }706 707 515 /** Hang up a phone. 708 516 * … … 758 566 } 759 567 760 /** Wrapper for IPC_M_SHARE_IN calls.761 *762 * @param phoneid Phone that will be used to contact the receiving side.763 * @param size Size of the destination address space area.764 * @param arg User defined argument.765 * @param flags Storage for received flags. Can be NULL.766 * @param dst Destination address space area base. Cannot be NULL.767 *768 * @return Zero on success or a negative error code from errno.h.769 *770 */771 int ipc_share_in_start(int phoneid, size_t size, sysarg_t arg,772 unsigned int *flags, void **dst)773 {774 sysarg_t _flags = 0;775 sysarg_t _dst = (sysarg_t) -1;776 int res = ipc_call_sync_2_4(phoneid, IPC_M_SHARE_IN, (sysarg_t) size,777 arg, NULL, &_flags, NULL, &_dst);778 779 if (flags)780 *flags = (unsigned int) _flags;781 782 *dst = (void *) _dst;783 return res;784 }785 786 /** Wrapper for answering the IPC_M_SHARE_IN calls.787 *788 * This wrapper only makes it more comfortable to answer IPC_M_SHARE_IN789 * calls so that the user doesn't have to remember the meaning of each790 * IPC argument.791 *792 * @param callid Hash of the IPC_M_DATA_READ call to answer.793 * @param src Source address space base.794 * @param flags Flags to be used for sharing. Bits can be only cleared.795 *796 * @return Zero on success or a value from @ref errno.h on failure.797 *798 */799 int ipc_share_in_finalize(ipc_callid_t callid, void *src, unsigned int flags)800 {801 return ipc_answer_3(callid, EOK, (sysarg_t) src, (sysarg_t) flags,802 (sysarg_t) __entry);803 }804 805 /** Wrapper for IPC_M_SHARE_OUT calls.806 *807 * @param phoneid Phone that will be used to contact the receiving side.808 * @param src Source address space area base address.809 * @param flags Flags to be used for sharing. Bits can be only cleared.810 *811 * @return Zero on success or a negative error code from errno.h.812 *813 */814 int ipc_share_out_start(int phoneid, void *src, unsigned int flags)815 {816 return ipc_call_sync_3_0(phoneid, IPC_M_SHARE_OUT, (sysarg_t) src, 0,817 (sysarg_t) flags);818 }819 820 /** Wrapper for answering the IPC_M_SHARE_OUT calls.821 *822 * This wrapper only makes it more comfortable to answer IPC_M_SHARE_OUT823 * calls so that the user doesn't have to remember the meaning of each824 * IPC argument.825 *826 * @param callid Hash of the IPC_M_DATA_WRITE call to answer.827 * @param dst Destination address space area base address.828 *829 * @return Zero on success or a value from @ref errno.h on failure.830 *831 */832 int ipc_share_out_finalize(ipc_callid_t callid, void **dst)833 {834 return ipc_answer_2(callid, EOK, (sysarg_t) __entry, (sysarg_t) dst);835 }836 837 /** Wrapper for IPC_M_DATA_READ calls.838 *839 * @param phoneid Phone that will be used to contact the receiving side.840 * @param dst Address of the beginning of the destination buffer.841 * @param size Size of the destination buffer.842 *843 * @return Zero on success or a negative error code from errno.h.844 *845 */846 int ipc_data_read_start(int phoneid, void *dst, size_t size)847 {848 return ipc_call_sync_2_0(phoneid, IPC_M_DATA_READ, (sysarg_t) dst,849 (sysarg_t) size);850 }851 852 /** Wrapper for answering the IPC_M_DATA_READ calls.853 *854 * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ855 * calls so that the user doesn't have to remember the meaning of each856 * IPC argument.857 *858 * @param callid Hash of the IPC_M_DATA_READ call to answer.859 * @param src Source address for the IPC_M_DATA_READ call.860 * @param size Size for the IPC_M_DATA_READ call. Can be smaller than861 * the maximum size announced by the sender.862 *863 * @return Zero on success or a value from @ref errno.h on failure.864 *865 */866 int ipc_data_read_finalize(ipc_callid_t callid, const void *src, size_t size)867 {868 return ipc_answer_2(callid, EOK, (sysarg_t) src, (sysarg_t) size);869 }870 871 /** Wrapper for IPC_M_DATA_WRITE calls.872 *873 * @param phoneid Phone that will be used to contact the receiving side.874 * @param src Address of the beginning of the source buffer.875 * @param size Size of the source buffer.876 *877 * @return Zero on success or a negative error code from errno.h.878 *879 */880 int ipc_data_write_start(int phoneid, const void *src, size_t size)881 {882 return ipc_call_sync_2_0(phoneid, IPC_M_DATA_WRITE, (sysarg_t) src,883 (sysarg_t) size);884 }885 886 /** Wrapper for answering the IPC_M_DATA_WRITE calls.887 *888 * This wrapper only makes it more comfortable to answer IPC_M_DATA_WRITE889 * calls so that the user doesn't have to remember the meaning of each890 * IPC argument.891 *892 * @param callid Hash of the IPC_M_DATA_WRITE call to answer.893 * @param dst Final destination address for the IPC_M_DATA_WRITE call.894 * @param size Final size for the IPC_M_DATA_WRITE call.895 *896 * @return Zero on success or a value from @ref errno.h on failure.897 *898 */899 int ipc_data_write_finalize(ipc_callid_t callid, void *dst, size_t size)900 {901 return ipc_answer_2(callid, EOK, (sysarg_t) dst, (sysarg_t) size);902 }903 904 568 /** Connect to a task specified by id. 905 569 * -
uspace/lib/c/generic/iplink_srv.c
rb5d2e57 r03362fbd 139 139 if (!method) { 140 140 /* The other side has hung up */ 141 fibril_mutex_lock(&srv->lock); 142 srv->connected = false; 143 fibril_mutex_unlock(&srv->lock); 141 144 async_answer_0(callid, EOK); 142 145 break; -
uspace/lib/c/generic/loc.c
rb5d2e57 r03362fbd 37 37 #include <errno.h> 38 38 #include <malloc.h> 39 #include < bool.h>39 #include <stdbool.h> 40 40 41 41 static FIBRIL_MUTEX_INITIALIZE(loc_supp_block_mutex); -
uspace/lib/c/generic/malloc.c
rb5d2e57 r03362fbd 35 35 36 36 #include <malloc.h> 37 #include < bool.h>37 #include <stdbool.h> 38 38 #include <as.h> 39 39 #include <align.h> … … 109 109 (((uintptr_t) (area)->end) - sizeof(heap_block_foot_t)) 110 110 111 #define AREA_LAST_BLOCK_HEAD(area) \ 112 ((uintptr_t) BLOCK_HEAD(((heap_block_foot_t *) AREA_LAST_BLOCK_FOOT(area)))) 113 111 114 /** Get header in heap block. 112 115 * … … 286 289 size_t asize = ALIGN_UP(size, PAGE_SIZE); 287 290 void *astart = as_area_create(AS_AREA_ANY, asize, 288 AS_AREA_WRITE | AS_AREA_READ );291 AS_AREA_WRITE | AS_AREA_READ | AS_AREA_CACHEABLE); 289 292 if (astart == AS_MAP_FAILED) 290 293 return false; … … 346 349 return false; 347 350 348 /* Add new free block */ 349 size_t net_size = (size_t) (end - area->end); 350 if (net_size > 0) 351 block_init(area->end, net_size, true, area); 351 heap_block_head_t *last_head = 352 (heap_block_head_t *) AREA_LAST_BLOCK_HEAD(area); 353 354 if (last_head->free) { 355 /* Add the new space to the last block. */ 356 size_t net_size = (size_t) (end - area->end) + last_head->size; 357 malloc_assert(net_size > 0); 358 block_init(last_head, net_size, true, area); 359 } else { 360 /* Add new free block */ 361 size_t net_size = (size_t) (end - area->end); 362 if (net_size > 0) 363 block_init(area->end, net_size, true, area); 364 } 352 365 353 366 /* Update heap area parameters */ … … 355 368 356 369 return true; 357 }358 359 /** Try to enlarge any of the heap areas360 *361 * Should be called only inside the critical section.362 *363 * @param size Gross size of item to allocate (bytes).364 *365 */366 static bool heap_grow(size_t size)367 {368 if (size == 0)369 return true;370 371 /* First try to enlarge some existing area */372 for (heap_area_t *area = first_heap_area; area != NULL;373 area = area->next) {374 if (area_grow(area, size))375 return true;376 }377 378 /* Eventually try to create a new area */379 return area_create(AREA_OVERHEAD(size));380 370 } 381 371 … … 661 651 } 662 652 653 /** Try to enlarge any of the heap areas. 654 * 655 * If successful, allocate block of the given size in the area. 656 * Should be called only inside the critical section. 657 * 658 * @param size Gross size of item to allocate (bytes). 659 * @param align Memory address alignment. 660 * 661 * @return Allocated block. 662 * @return NULL on failure. 663 * 664 */ 665 static void *heap_grow_and_alloc(size_t size, size_t align) 666 { 667 if (size == 0) 668 return NULL; 669 670 /* First try to enlarge some existing area */ 671 for (heap_area_t *area = first_heap_area; area != NULL; 672 area = area->next) { 673 674 if (area_grow(area, size + align)) { 675 heap_block_head_t *first = 676 (heap_block_head_t *) AREA_LAST_BLOCK_HEAD(area); 677 678 void *addr = 679 malloc_area(area, first, NULL, size, align); 680 malloc_assert(addr != NULL); 681 return addr; 682 } 683 } 684 685 /* Eventually try to create a new area */ 686 if (area_create(AREA_OVERHEAD(size + align))) { 687 heap_block_head_t *first = 688 (heap_block_head_t *) AREA_FIRST_BLOCK_HEAD(last_heap_area); 689 690 void *addr = 691 malloc_area(last_heap_area, first, NULL, size, align); 692 malloc_assert(addr != NULL); 693 return addr; 694 } 695 696 return NULL; 697 } 698 663 699 /** Allocate a memory block 664 700 * … … 679 715 680 716 size_t falign = lcm(align, BASE_ALIGN); 681 size_t real_size = GROSS_SIZE(ALIGN_UP(size, falign)); 682 683 bool retry = false; 684 heap_block_head_t *split; 685 686 loop: 717 718 /* Check for integer overflow. */ 719 if (falign < align) 720 return NULL; 721 722 /* 723 * The size of the allocated block needs to be naturally 724 * aligned, because the footer structure also needs to reside 725 * on a naturally aligned address in order to avoid unaligned 726 * memory accesses. 727 */ 728 size_t gross_size = GROSS_SIZE(ALIGN_UP(size, BASE_ALIGN)); 687 729 688 730 /* Try the next fit approach */ 689 split = next_fit;731 heap_block_head_t *split = next_fit; 690 732 691 733 if (split != NULL) { 692 void *addr = malloc_area(split->area, split, NULL, real_size,734 void *addr = malloc_area(split->area, split, NULL, gross_size, 693 735 falign); 694 736 … … 703 745 AREA_FIRST_BLOCK_HEAD(area); 704 746 705 void *addr = malloc_area(area, first, split, real_size,747 void *addr = malloc_area(area, first, split, gross_size, 706 748 falign); 707 749 … … 710 752 } 711 753 712 if (!retry) { 713 /* Try to grow the heap space */ 714 if (heap_grow(real_size)) { 715 retry = true; 716 goto loop; 717 } 718 } 719 720 return NULL; 754 /* Finally, try to grow heap space and allocate in the new area. */ 755 return heap_grow_and_alloc(gross_size, falign); 721 756 } 722 757 … … 731 766 void *calloc(const size_t nmemb, const size_t size) 732 767 { 768 // FIXME: Check for overflow 769 733 770 void *block = malloc(nmemb * size); 734 771 if (block == NULL) … … 870 907 if (addr == NULL) 871 908 return; 872 909 873 910 futex_down(&malloc_futex); 874 911 -
uspace/lib/c/generic/private/async.h
rb5d2e57 r03362fbd 41 41 #include <fibril_synch.h> 42 42 #include <sys/time.h> 43 #include < bool.h>43 #include <stdbool.h> 44 44 45 45 /** Structures of this type are used to track the timeout events. */ -
uspace/lib/c/generic/stdlib.c
rb5d2e57 r03362fbd 39 39 long int random(void) 40 40 { 41 return glbl_seed = ((1366 *glbl_seed + 150889) % RAND_MAX);41 return glbl_seed = ((1366 * glbl_seed + 150889) % RAND_MAX); 42 42 } 43 43 44 44 void srandom(unsigned int seed) 45 45 { 46 glbl_seed = seed ;46 glbl_seed = seed % RAND_MAX; 47 47 } 48 48 -
uspace/lib/c/generic/str.c
rb5d2e57 r03362fbd 136 136 } 137 137 138 /** Decode a single character from a string to the left. 139 * 140 * Decode a single character from a string of size @a size. Decoding starts 141 * at @a offset and this offset is moved to the beginning of the previous 142 * character. In case of decoding error, offset generally decreases at least 143 * by one. However, offset is never moved before 0. 144 * 145 * @param str String (not necessarily NULL-terminated). 146 * @param offset Byte offset in string where to start decoding. 147 * @param size Size of the string (in bytes). 148 * 149 * @return Value of decoded character, U_SPECIAL on decoding error or 150 * NULL if attempt to decode beyond @a start of str. 151 * 152 */ 153 wchar_t str_decode_reverse(const char *str, size_t *offset, size_t size) 154 { 155 if (*offset == 0) 156 return 0; 157 158 size_t processed = 0; 159 /* Continue while continuation bytes found */ 160 while (*offset > 0 && processed < 4) { 161 uint8_t b = (uint8_t) str[--(*offset)]; 162 163 if (processed == 0 && (b & 0x80) == 0) { 164 /* 0xxxxxxx (Plain ASCII) */ 165 return b & 0x7f; 166 } 167 else if ((b & 0xe0) == 0xc0 || (b & 0xf0) == 0xe0 || 168 (b & 0xf8) == 0xf0) { 169 /* Start byte */ 170 size_t start_offset = *offset; 171 return str_decode(str, &start_offset, size); 172 } 173 else if ((b & 0xc0) != 0x80) { 174 /* Not a continuation byte */ 175 return U_SPECIAL; 176 } 177 processed++; 178 } 179 /* Too many continuation bytes */ 180 return U_SPECIAL; 181 } 182 138 183 /** Encode a single character to string representation. 139 184 * … … 399 444 } 400 445 446 /** Get character display width on a character cell display. 447 * 448 * @param ch Character 449 * @return Width of character in cells. 450 */ 451 size_t chr_width(wchar_t ch) 452 { 453 return 1; 454 } 455 456 /** Get string display width on a character cell display. 457 * 458 * @param str String 459 * @return Width of string in cells. 460 */ 461 size_t str_width(const char *str) 462 { 463 size_t width = 0; 464 size_t offset = 0; 465 wchar_t ch; 466 467 while ((ch = str_decode(str, &offset, STR_NO_LIMIT)) != 0) 468 width += chr_width(ch); 469 470 return width; 471 } 472 401 473 /** Check whether character is plain ASCII. 402 474 * … … 428 500 * 429 501 * Do a char-by-char comparison of two NULL-terminated strings. 430 * The strings are considered equal iff they consist of the same 431 * characters on the minimum of their lengths. 502 * The strings are considered equal iff their length is equal 503 * and both strings consist of the same sequence of characters. 504 * 505 * A string S1 is less than another string S2 if it has a character with 506 * lower value at the first character position where the strings differ. 507 * If the strings differ in length, the shorter one is treated as if 508 * padded by characters with a value of zero. 432 509 * 433 510 * @param s1 First string to compare. 434 511 * @param s2 Second string to compare. 435 512 * 436 * @return 0 if the strings are equal, -1 if first is smaller,437 * 1 if second smaller.513 * @return 0 if the strings are equal, -1 if the first is less than the second, 514 * 1 if the second is less than the first. 438 515 * 439 516 */ … … 466 543 * 467 544 * Do a char-by-char comparison of two NULL-terminated strings. 468 * The strings are considered equal iff they consist of the same 469 * characters on the minimum of their lengths and the length limit. 545 * The strings are considered equal iff 546 * min(str_length(s1), max_len) == min(str_length(s2), max_len) 547 * and both strings consist of the same sequence of characters, 548 * up to max_len characters. 549 * 550 * A string S1 is less than another string S2 if it has a character with 551 * lower value at the first character position where the strings differ. 552 * If the strings differ in length, the shorter one is treated as if 553 * padded by characters with a value of zero. Only the first max_len 554 * characters are considered. 470 555 * 471 556 * @param s1 First string to compare. … … 473 558 * @param max_len Maximum number of characters to consider. 474 559 * 475 * @return 0 if the strings are equal, -1 if first is smaller,476 * 1 if second smaller.560 * @return 0 if the strings are equal, -1 if the first is less than the second, 561 * 1 if the second is less than the first. 477 562 * 478 563 */ … … 508 593 return 0; 509 594 595 } 596 597 /** Test whether p is a prefix of s. 598 * 599 * Do a char-by-char comparison of two NULL-terminated strings 600 * and determine if p is a prefix of s. 601 * 602 * @param s The string in which to look 603 * @param p The string to check if it is a prefix of s 604 * 605 * @return true iff p is prefix of s else false 606 * 607 */ 608 bool str_test_prefix(const char *s, const char *p) 609 { 610 wchar_t c1 = 0; 611 wchar_t c2 = 0; 612 613 size_t off1 = 0; 614 size_t off2 = 0; 615 616 while (true) { 617 c1 = str_decode(s, &off1, STR_NO_LIMIT); 618 c2 = str_decode(p, &off2, STR_NO_LIMIT); 619 620 if (c2 == 0) 621 return true; 622 623 if (c1 != c2) 624 return false; 625 626 if (c1 == 0) 627 break; 628 } 629 630 return false; 510 631 } 511 632 … … 1085 1206 c = (c >= 'a' ? c - 'a' + 10 : (c >= 'A' ? c - 'A' + 10 : 1086 1207 (c <= '9' ? c - '0' : 0xff))); 1087 if (c > base) {1208 if (c >= base) { 1088 1209 break; 1089 1210 } -
uspace/lib/c/generic/sysinfo.c
rb5d2e57 r03362fbd 38 38 #include <errno.h> 39 39 #include <malloc.h> 40 #include < bool.h>40 #include <stdbool.h> 41 41 #include <unistd.h> 42 42 -
uspace/lib/c/generic/task.c
rb5d2e57 r03362fbd 201 201 * 202 202 * This is really just a convenience wrapper over the more complicated 203 * loader API. Arguments are passed in a va_list. 204 * 205 * @param id If not NULL, the ID of the task is stored here on success. 206 * @param path Pathname of the binary to execute. 207 * @param cnt Number of arguments. 208 * @param ap Command-line arguments. 209 * 210 * @return Zero on success or negative error code. 211 * 212 */ 213 int task_spawn(task_id_t *task_id, const char *path, int cnt, va_list ap) 214 { 215 /* Allocate argument list. */ 216 const char **arglist = malloc(cnt * sizeof(const char *)); 217 if (arglist == NULL) 218 return ENOMEM; 219 220 /* Fill in arguments. */ 221 const char *arg; 222 cnt = 0; 223 do { 224 arg = va_arg(ap, const char *); 225 arglist[cnt++] = arg; 226 } while (arg != NULL); 227 228 /* Spawn task. */ 229 int rc = task_spawnv(task_id, path, arglist); 230 231 /* Free argument list. */ 232 free(arglist); 233 return rc; 234 } 235 236 /** Create a new task by running an executable from the filesystem. 237 * 238 * This is really just a convenience wrapper over the more complicated 203 239 * loader API. Arguments are passed as a null-terminated list of arguments. 204 240 * … … 216 252 va_list ap; 217 253 const char *arg; 218 const char **arglist;219 254 int cnt = 0; 220 255 … … 226 261 va_end(ap); 227 262 228 /* Allocate argument list. */229 arglist = malloc(cnt * sizeof(const char *));230 if (arglist == NULL)231 return ENOMEM;232 233 /* Fill in arguments. */234 cnt = 0;235 263 va_start(ap, path); 236 do { 237 arg = va_arg(ap, const char *); 238 arglist[cnt++] = arg; 239 } while (arg != NULL); 264 int rc = task_spawn(task_id, path, cnt, ap); 240 265 va_end(ap); 241 266 242 /* Spawn task. */243 int rc = task_spawnv(task_id, path, arglist);244 245 /* Free argument list. */246 free(arglist);247 267 return rc; 248 268 } -
uspace/lib/c/generic/thread.c
rb5d2e57 r03362fbd 39 39 #include <abi/proc/uarg.h> 40 40 #include <fibril.h> 41 #include <stack.h> 41 42 #include <str.h> 42 43 #include <async.h> … … 44 45 #include <as.h> 45 46 #include "private/thread.h" 46 47 #ifndef THREAD_INITIAL_STACK_PAGES48 #define THREAD_INITIAL_STACK_PAGES 249 #endif50 47 51 48 /** Main thread function. … … 101 98 return ENOMEM; 102 99 103 size_t stack_size = getpagesize() * THREAD_INITIAL_STACK_PAGES;100 size_t stack_size = stack_size_get(); 104 101 void *stack = as_area_create(AS_AREA_ANY, stack_size, 105 AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE); 102 AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE | AS_AREA_GUARD | 103 AS_AREA_LATE_RESERVE); 106 104 if (stack == AS_MAP_FAILED) { 107 105 free(uarg); -
uspace/lib/c/generic/time.c
rb5d2e57 r03362fbd 1 1 /* 2 2 * Copyright (c) 2006 Ondrej Palkovsky 3 * Copyright (c) 2011 Petr Koupy 4 * Copyright (c) 2011 Jiri Zarevucky 3 5 * All rights reserved. 4 6 * … … 35 37 #include <sys/time.h> 36 38 #include <time.h> 37 #include < bool.h>39 #include <stdbool.h> 38 40 #include <libarch/barrier.h> 39 41 #include <macros.h> … … 43 45 #include <ddi.h> 44 46 #include <libc.h> 47 #include <stdint.h> 48 #include <stdio.h> 49 #include <ctype.h> 50 #include <assert.h> 45 51 #include <unistd.h> 52 #include <loc.h> 53 #include <device/clock_dev.h> 54 #include <malloc.h> 55 56 #define ASCTIME_BUF_LEN 26 46 57 47 58 /** Pointer to kernel shared variables with time */ … … 52 63 } *ktime = NULL; 53 64 65 /* Helper functions ***********************************************************/ 66 67 #define HOURS_PER_DAY (24) 68 #define MINS_PER_HOUR (60) 69 #define SECS_PER_MIN (60) 70 #define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY) 71 #define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR) 72 #define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY) 73 74 /** 75 * Checks whether the year is a leap year. 76 * 77 * @param year Year since 1900 (e.g. for 1970, the value is 70). 78 * @return true if year is a leap year, false otherwise 79 */ 80 static bool _is_leap_year(time_t year) 81 { 82 year += 1900; 83 84 if (year % 400 == 0) 85 return true; 86 if (year % 100 == 0) 87 return false; 88 if (year % 4 == 0) 89 return true; 90 return false; 91 } 92 93 /** 94 * Returns how many days there are in the given month of the given year. 95 * Note that year is only taken into account if month is February. 96 * 97 * @param year Year since 1900 (can be negative). 98 * @param mon Month of the year. 0 for January, 11 for December. 99 * @return Number of days in the specified month. 100 */ 101 static int _days_in_month(time_t year, time_t mon) 102 { 103 assert(mon >= 0 && mon <= 11); 104 105 static int month_days[] = 106 { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 107 108 if (mon == 1) { 109 year += 1900; 110 /* february */ 111 return _is_leap_year(year) ? 29 : 28; 112 } else { 113 return month_days[mon]; 114 } 115 } 116 117 /** 118 * For specified year, month and day of month, returns which day of that year 119 * it is. 120 * 121 * For example, given date 2011-01-03, the corresponding expression is: 122 * _day_of_year(111, 0, 3) == 2 123 * 124 * @param year Year (year 1900 = 0, can be negative). 125 * @param mon Month (January = 0). 126 * @param mday Day of month (First day is 1). 127 * @return Day of year (First day is 0). 128 */ 129 static int _day_of_year(time_t year, time_t mon, time_t mday) 130 { 131 static int mdays[] = 132 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; 133 static int leap_mdays[] = 134 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; 135 136 return (_is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1; 137 } 138 139 /** 140 * Integer division that rounds to negative infinity. 141 * Used by some functions in this file. 142 * 143 * @param op1 Dividend. 144 * @param op2 Divisor. 145 * @return Rounded quotient. 146 */ 147 static time_t _floor_div(time_t op1, time_t op2) 148 { 149 if (op1 >= 0 || op1 % op2 == 0) { 150 return op1 / op2; 151 } else { 152 return op1 / op2 - 1; 153 } 154 } 155 156 /** 157 * Modulo that rounds to negative infinity. 158 * Used by some functions in this file. 159 * 160 * @param op1 Dividend. 161 * @param op2 Divisor. 162 * @return Remainder. 163 */ 164 static time_t _floor_mod(time_t op1, time_t op2) 165 { 166 int div = _floor_div(op1, op2); 167 168 /* (a / b) * b + a % b == a */ 169 /* thus, a % b == a - (a / b) * b */ 170 171 int result = op1 - div * op2; 172 173 /* Some paranoid checking to ensure I didn't make a mistake here. */ 174 assert(result >= 0); 175 assert(result < op2); 176 assert(div * op2 + result == op1); 177 178 return result; 179 } 180 181 /** 182 * Number of days since the Epoch. 183 * Epoch is 1970-01-01, which is also equal to day 0. 184 * 185 * @param year Year (year 1900 = 0, may be negative). 186 * @param mon Month (January = 0). 187 * @param mday Day of month (first day = 1). 188 * @return Number of days since the Epoch. 189 */ 190 static time_t _days_since_epoch(time_t year, time_t mon, time_t mday) 191 { 192 return (year - 70) * 365 + _floor_div(year - 69, 4) - 193 _floor_div(year - 1, 100) + _floor_div(year + 299, 400) + 194 _day_of_year(year, mon, mday); 195 } 196 197 /** 198 * Seconds since the Epoch. see also _days_since_epoch(). 199 * 200 * @param tm Normalized broken-down time. 201 * @return Number of seconds since the epoch, not counting leap seconds. 202 */ 203 static time_t _secs_since_epoch(const struct tm *tm) 204 { 205 return _days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) * 206 SECS_PER_DAY + tm->tm_hour * SECS_PER_HOUR + 207 tm->tm_min * SECS_PER_MIN + tm->tm_sec; 208 } 209 210 /** 211 * Which day of week the specified date is. 212 * 213 * @param year Year (year 1900 = 0). 214 * @param mon Month (January = 0). 215 * @param mday Day of month (first = 1). 216 * @return Day of week (Sunday = 0). 217 */ 218 static int _day_of_week(time_t year, time_t mon, time_t mday) 219 { 220 /* 1970-01-01 is Thursday */ 221 return _floor_mod((_days_since_epoch(year, mon, mday) + 4), 7); 222 } 223 224 /** 225 * Normalizes the broken-down time and optionally adds specified amount of 226 * seconds. 227 * 228 * @param tm Broken-down time to normalize. 229 * @param sec_add Seconds to add. 230 * @return 0 on success, -1 on overflow 231 */ 232 static int _normalize_time(struct tm *tm, time_t sec_add) 233 { 234 // TODO: DST correction 235 236 /* Set initial values. */ 237 time_t sec = tm->tm_sec + sec_add; 238 time_t min = tm->tm_min; 239 time_t hour = tm->tm_hour; 240 time_t day = tm->tm_mday - 1; 241 time_t mon = tm->tm_mon; 242 time_t year = tm->tm_year; 243 244 /* Adjust time. */ 245 min += _floor_div(sec, SECS_PER_MIN); 246 sec = _floor_mod(sec, SECS_PER_MIN); 247 hour += _floor_div(min, MINS_PER_HOUR); 248 min = _floor_mod(min, MINS_PER_HOUR); 249 day += _floor_div(hour, HOURS_PER_DAY); 250 hour = _floor_mod(hour, HOURS_PER_DAY); 251 252 /* Adjust month. */ 253 year += _floor_div(mon, 12); 254 mon = _floor_mod(mon, 12); 255 256 /* Now the difficult part - days of month. */ 257 258 /* First, deal with whole cycles of 400 years = 146097 days. */ 259 year += _floor_div(day, 146097) * 400; 260 day = _floor_mod(day, 146097); 261 262 /* Then, go in one year steps. */ 263 if (mon <= 1) { 264 /* January and February. */ 265 while (day > 365) { 266 day -= _is_leap_year(year) ? 366 : 365; 267 year++; 268 } 269 } else { 270 /* Rest of the year. */ 271 while (day > 365) { 272 day -= _is_leap_year(year + 1) ? 366 : 365; 273 year++; 274 } 275 } 276 277 /* Finally, finish it off month per month. */ 278 while (day >= _days_in_month(year, mon)) { 279 day -= _days_in_month(year, mon); 280 mon++; 281 if (mon >= 12) { 282 mon -= 12; 283 year++; 284 } 285 } 286 287 /* Calculate the remaining two fields. */ 288 tm->tm_yday = _day_of_year(year, mon, day + 1); 289 tm->tm_wday = _day_of_week(year, mon, day + 1); 290 291 /* And put the values back to the struct. */ 292 tm->tm_sec = (int) sec; 293 tm->tm_min = (int) min; 294 tm->tm_hour = (int) hour; 295 tm->tm_mday = (int) day + 1; 296 tm->tm_mon = (int) mon; 297 298 /* Casts to work around libc brain-damage. */ 299 if (year > ((int)INT_MAX) || year < ((int)INT_MIN)) { 300 tm->tm_year = (year < 0) ? ((int)INT_MIN) : ((int)INT_MAX); 301 return -1; 302 } 303 304 tm->tm_year = (int) year; 305 return 0; 306 } 307 308 /** 309 * Which day the week-based year starts on, relative to the first calendar day. 310 * E.g. if the year starts on December 31st, the return value is -1. 311 * 312 * @param Year since 1900. 313 * @return Offset of week-based year relative to calendar year. 314 */ 315 static int _wbyear_offset(int year) 316 { 317 int start_wday = _day_of_week(year, 0, 1); 318 return _floor_mod(4 - start_wday, 7) - 3; 319 } 320 321 /** 322 * Returns week-based year of the specified time. 323 * 324 * @param tm Normalized broken-down time. 325 * @return Week-based year. 326 */ 327 static int _wbyear(const struct tm *tm) 328 { 329 int day = tm->tm_yday - _wbyear_offset(tm->tm_year); 330 if (day < 0) { 331 /* Last week of previous year. */ 332 return tm->tm_year - 1; 333 } 334 if (day > 364 + _is_leap_year(tm->tm_year)) { 335 /* First week of next year. */ 336 return tm->tm_year + 1; 337 } 338 /* All the other days are in the calendar year. */ 339 return tm->tm_year; 340 } 341 342 /** 343 * Week number of the year, assuming weeks start on sunday. 344 * The first Sunday of January is the first day of week 1; 345 * days in the new year before this are in week 0. 346 * 347 * @param tm Normalized broken-down time. 348 * @return The week number (0 - 53). 349 */ 350 static int _sun_week_number(const struct tm *tm) 351 { 352 int first_day = (7 - _day_of_week(tm->tm_year, 0, 1)) % 7; 353 return (tm->tm_yday - first_day + 7) / 7; 354 } 355 356 /** 357 * Week number of the year, assuming weeks start on monday. 358 * If the week containing January 1st has four or more days in the new year, 359 * then it is considered week 1. Otherwise, it is the last week of the previous 360 * year, and the next week is week 1. Both January 4th and the first Thursday 361 * of January are always in week 1. 362 * 363 * @param tm Normalized broken-down time. 364 * @return The week number (1 - 53). 365 */ 366 static int _iso_week_number(const struct tm *tm) 367 { 368 int day = tm->tm_yday - _wbyear_offset(tm->tm_year); 369 if (day < 0) { 370 /* Last week of previous year. */ 371 return 53; 372 } 373 if (day > 364 + _is_leap_year(tm->tm_year)) { 374 /* First week of next year. */ 375 return 1; 376 } 377 /* All the other days give correct answer. */ 378 return (day / 7 + 1); 379 } 380 381 /** 382 * Week number of the year, assuming weeks start on monday. 383 * The first Monday of January is the first day of week 1; 384 * days in the new year before this are in week 0. 385 * 386 * @param tm Normalized broken-down time. 387 * @return The week number (0 - 53). 388 */ 389 static int _mon_week_number(const struct tm *tm) 390 { 391 int first_day = (1 - _day_of_week(tm->tm_year, 0, 1)) % 7; 392 return (tm->tm_yday - first_day + 7) / 7; 393 } 394 395 /******************************************************************************/ 396 397 54 398 /** Add microseconds to given timeval. 55 399 * … … 139 483 */ 140 484 int gettimeofday(struct timeval *tv, struct timezone *tz) 485 { 486 int rc; 487 struct tm t; 488 category_id_t cat_id; 489 size_t svc_cnt; 490 service_id_t *svc_ids = NULL; 491 service_id_t svc_id; 492 char *svc_name = NULL; 493 494 static async_sess_t *clock_conn = NULL; 495 496 if (tz) { 497 tz->tz_minuteswest = 0; 498 tz->tz_dsttime = DST_NONE; 499 } 500 501 if (clock_conn == NULL) { 502 rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING); 503 if (rc != EOK) 504 goto ret_uptime; 505 506 rc = loc_category_get_svcs(cat_id, &svc_ids, &svc_cnt); 507 if (rc != EOK) 508 goto ret_uptime; 509 510 if (svc_cnt == 0) 511 goto ret_uptime; 512 513 rc = loc_service_get_name(svc_ids[0], &svc_name); 514 if (rc != EOK) 515 goto ret_uptime; 516 517 rc = loc_service_get_id(svc_name, &svc_id, 0); 518 if (rc != EOK) 519 goto ret_uptime; 520 521 clock_conn = loc_service_connect(EXCHANGE_SERIALIZE, 522 svc_id, IPC_FLAG_BLOCKING); 523 if (!clock_conn) 524 goto ret_uptime; 525 } 526 527 rc = clock_dev_time_get(clock_conn, &t); 528 if (rc != EOK) 529 goto ret_uptime; 530 531 tv->tv_usec = 0; 532 tv->tv_sec = mktime(&t); 533 534 free(svc_name); 535 free(svc_ids); 536 537 return EOK; 538 539 ret_uptime: 540 541 free(svc_name); 542 free(svc_ids); 543 544 return getuptime(tv); 545 } 546 547 int getuptime(struct timeval *tv) 141 548 { 142 549 if (ktime == NULL) { … … 160 567 } 161 568 162 if (tz) {163 tz->tz_minuteswest = 0;164 tz->tz_dsttime = DST_NONE;165 }166 167 569 sysarg_t s2 = ktime->seconds2; 168 570 … … 178 580 } else 179 581 tv->tv_sec = s1; 180 582 181 583 return 0; 182 584 } … … 229 631 } 230 632 633 /** 634 * This function first normalizes the provided broken-down time 635 * (moves all values to their proper bounds) and then tries to 636 * calculate the appropriate time_t representation. 637 * 638 * @param tm Broken-down time. 639 * @return time_t representation of the time, undefined value on overflow. 640 */ 641 time_t mktime(struct tm *tm) 642 { 643 // TODO: take DST flag into account 644 // TODO: detect overflow 645 646 _normalize_time(tm, 0); 647 return _secs_since_epoch(tm); 648 } 649 650 /** 651 * Convert time and date to a string, based on a specified format and 652 * current locale. 653 * 654 * @param s Buffer to write string to. 655 * @param maxsize Size of the buffer. 656 * @param format Format of the output. 657 * @param tm Broken-down time to format. 658 * @return Number of bytes written. 659 */ 660 size_t strftime(char *restrict s, size_t maxsize, 661 const char *restrict format, const struct tm *restrict tm) 662 { 663 assert(s != NULL); 664 assert(format != NULL); 665 assert(tm != NULL); 666 667 // TODO: use locale 668 static const char *wday_abbr[] = { 669 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 670 }; 671 static const char *wday[] = { 672 "Sunday", "Monday", "Tuesday", "Wednesday", 673 "Thursday", "Friday", "Saturday" 674 }; 675 static const char *mon_abbr[] = { 676 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 677 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 678 }; 679 static const char *mon[] = { 680 "January", "February", "March", "April", "May", "June", "July", 681 "August", "September", "October", "November", "December" 682 }; 683 684 if (maxsize < 1) { 685 return 0; 686 } 687 688 char *ptr = s; 689 size_t consumed; 690 size_t remaining = maxsize; 691 692 #define append(...) { \ 693 /* FIXME: this requires POSIX-correct snprintf */ \ 694 /* otherwise it won't work with non-ascii chars */ \ 695 consumed = snprintf(ptr, remaining, __VA_ARGS__); \ 696 if (consumed >= remaining) { \ 697 return 0; \ 698 } \ 699 ptr += consumed; \ 700 remaining -= consumed; \ 701 } 702 703 #define recurse(fmt) { \ 704 consumed = strftime(ptr, remaining, fmt, tm); \ 705 if (consumed == 0) { \ 706 return 0; \ 707 } \ 708 ptr += consumed; \ 709 remaining -= consumed; \ 710 } 711 712 #define TO_12H(hour) (((hour) > 12) ? ((hour) - 12) : \ 713 (((hour) == 0) ? 12 : (hour))) 714 715 while (*format != '\0') { 716 if (*format != '%') { 717 append("%c", *format); 718 format++; 719 continue; 720 } 721 722 format++; 723 if (*format == '0' || *format == '+') { 724 // TODO: padding 725 format++; 726 } 727 while (isdigit(*format)) { 728 // TODO: padding 729 format++; 730 } 731 if (*format == 'O' || *format == 'E') { 732 // TODO: locale's alternative format 733 format++; 734 } 735 736 switch (*format) { 737 case 'a': 738 append("%s", wday_abbr[tm->tm_wday]); break; 739 case 'A': 740 append("%s", wday[tm->tm_wday]); break; 741 case 'b': 742 append("%s", mon_abbr[tm->tm_mon]); break; 743 case 'B': 744 append("%s", mon[tm->tm_mon]); break; 745 case 'c': 746 // TODO: locale-specific datetime format 747 recurse("%Y-%m-%d %H:%M:%S"); break; 748 case 'C': 749 append("%02d", (1900 + tm->tm_year) / 100); break; 750 case 'd': 751 append("%02d", tm->tm_mday); break; 752 case 'D': 753 recurse("%m/%d/%y"); break; 754 case 'e': 755 append("%2d", tm->tm_mday); break; 756 case 'F': 757 recurse("%+4Y-%m-%d"); break; 758 case 'g': 759 append("%02d", _wbyear(tm) % 100); break; 760 case 'G': 761 append("%d", _wbyear(tm)); break; 762 case 'h': 763 recurse("%b"); break; 764 case 'H': 765 append("%02d", tm->tm_hour); break; 766 case 'I': 767 append("%02d", TO_12H(tm->tm_hour)); break; 768 case 'j': 769 append("%03d", tm->tm_yday); break; 770 case 'k': 771 append("%2d", tm->tm_hour); break; 772 case 'l': 773 append("%2d", TO_12H(tm->tm_hour)); break; 774 case 'm': 775 append("%02d", tm->tm_mon); break; 776 case 'M': 777 append("%02d", tm->tm_min); break; 778 case 'n': 779 append("\n"); break; 780 case 'p': 781 append("%s", tm->tm_hour < 12 ? "AM" : "PM"); break; 782 case 'P': 783 append("%s", tm->tm_hour < 12 ? "am" : "PM"); break; 784 case 'r': 785 recurse("%I:%M:%S %p"); break; 786 case 'R': 787 recurse("%H:%M"); break; 788 case 's': 789 append("%ld", _secs_since_epoch(tm)); break; 790 case 'S': 791 append("%02d", tm->tm_sec); break; 792 case 't': 793 append("\t"); break; 794 case 'T': 795 recurse("%H:%M:%S"); break; 796 case 'u': 797 append("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday); 798 break; 799 case 'U': 800 append("%02d", _sun_week_number(tm)); break; 801 case 'V': 802 append("%02d", _iso_week_number(tm)); break; 803 case 'w': 804 append("%d", tm->tm_wday); break; 805 case 'W': 806 append("%02d", _mon_week_number(tm)); break; 807 case 'x': 808 // TODO: locale-specific date format 809 recurse("%Y-%m-%d"); break; 810 case 'X': 811 // TODO: locale-specific time format 812 recurse("%H:%M:%S"); break; 813 case 'y': 814 append("%02d", tm->tm_year % 100); break; 815 case 'Y': 816 append("%d", 1900 + tm->tm_year); break; 817 case 'z': 818 // TODO: timezone 819 break; 820 case 'Z': 821 // TODO: timezone 822 break; 823 case '%': 824 append("%%"); 825 break; 826 default: 827 /* Invalid specifier, print verbatim. */ 828 while (*format != '%') { 829 format--; 830 } 831 append("%%"); 832 break; 833 } 834 format++; 835 } 836 837 #undef append 838 #undef recurse 839 840 return maxsize - remaining; 841 } 842 843 844 /** Converts a time value to a broken-down UTC time 845 * 846 * @param time Time to convert 847 * @param result Structure to store the result to 848 * 849 * @return EOK or a negative error code 850 */ 851 int time_utc2tm(const time_t time, struct tm *restrict result) 852 { 853 assert(result != NULL); 854 855 /* Set result to epoch. */ 856 result->tm_sec = 0; 857 result->tm_min = 0; 858 result->tm_hour = 0; 859 result->tm_mday = 1; 860 result->tm_mon = 0; 861 result->tm_year = 70; /* 1970 */ 862 863 if (_normalize_time(result, time) == -1) 864 return EOVERFLOW; 865 866 return EOK; 867 } 868 869 /** Converts a time value to a null terminated string of the form 870 * "Wed Jun 30 21:49:08 1993\n" expressed in UTC. 871 * 872 * @param time Time to convert. 873 * @param buf Buffer to store the string to, must be at least 874 * ASCTIME_BUF_LEN bytes long. 875 * 876 * @return EOK or a negative error code. 877 */ 878 int time_utc2str(const time_t time, char *restrict buf) 879 { 880 struct tm t; 881 int r; 882 883 if ((r = time_utc2tm(time, &t)) != EOK) 884 return r; 885 886 time_tm2str(&t, buf); 887 return EOK; 888 } 889 890 891 /** 892 * Converts broken-down time to a string in format 893 * "Sun Jan 1 00:00:00 1970\n". (Obsolete) 894 * 895 * @param timeptr Broken-down time structure. 896 * @param buf Buffer to store string to, must be at least ASCTIME_BUF_LEN 897 * bytes long. 898 */ 899 void time_tm2str(const struct tm *restrict timeptr, char *restrict buf) 900 { 901 assert(timeptr != NULL); 902 assert(buf != NULL); 903 904 static const char *wday[] = { 905 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 906 }; 907 static const char *mon[] = { 908 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 909 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 910 }; 911 912 snprintf(buf, ASCTIME_BUF_LEN, "%s %s %2d %02d:%02d:%02d %d\n", 913 wday[timeptr->tm_wday], 914 mon[timeptr->tm_mon], 915 timeptr->tm_mday, timeptr->tm_hour, 916 timeptr->tm_min, timeptr->tm_sec, 917 1900 + timeptr->tm_year); 918 } 919 920 /** 921 * Converts a time value to a broken-down local time, expressed relative 922 * to the user's specified timezone. 923 * 924 * @param timer Time to convert. 925 * @param result Structure to store the result to. 926 * 927 * @return EOK on success or a negative error code. 928 */ 929 int time_local2tm(const time_t time, struct tm *restrict result) 930 { 931 // TODO: deal with timezone 932 // currently assumes system and all times are in GMT 933 934 /* Set result to epoch. */ 935 result->tm_sec = 0; 936 result->tm_min = 0; 937 result->tm_hour = 0; 938 result->tm_mday = 1; 939 result->tm_mon = 0; 940 result->tm_year = 70; /* 1970 */ 941 942 if (_normalize_time(result, time) == -1) 943 return EOVERFLOW; 944 945 return EOK; 946 } 947 948 /** 949 * Converts the calendar time to a null terminated string 950 * of the form "Wed Jun 30 21:49:08 1993\n" expressed relative to the 951 * user's specified timezone. 952 * 953 * @param timer Time to convert. 954 * @param buf Buffer to store the string to. Must be at least 955 * ASCTIME_BUF_LEN bytes long. 956 * 957 * @return EOK on success or a negative error code. 958 */ 959 int time_local2str(const time_t time, char *buf) 960 { 961 struct tm loctime; 962 int r; 963 964 if ((r = time_local2tm(time, &loctime)) != EOK) 965 return r; 966 967 time_tm2str(&loctime, buf); 968 969 return EOK; 970 } 971 972 /** 973 * Calculate the difference between two times, in seconds. 974 * 975 * @param time1 First time. 976 * @param time0 Second time. 977 * @return Time in seconds. 978 */ 979 double difftime(time_t time1, time_t time0) 980 { 981 return (double) (time1 - time0); 982 } 983 231 984 /** @} 232 985 */ -
uspace/lib/c/generic/tls.c
rb5d2e57 r03362fbd 42 42 #include <str.h> 43 43 #include <align.h> 44 #include <unistd.h> 44 45 45 46 /** Create TLS (Thread Local Storage) data structures. … … 57 58 58 59 tcb = __alloc_tls(&data, tls_size); 60 if (!tcb) 61 return NULL; 59 62 60 63 /* … … 89 92 90 93 result = malloc(sizeof(tcb_t) + size); 94 if (!result) 95 return NULL; 91 96 *data = ((void *)result) + sizeof(tcb_t); 97 92 98 return result; 93 99 } … … 118 124 size = ALIGN_UP(size, &_tls_alignment); 119 125 *data = memalign((uintptr_t) &_tls_alignment, sizeof(tcb_t) + size); 120 126 if (!*data) 127 return NULL; 121 128 tcb = (tcb_t *) (*data + size); 122 129 tcb->self = tcb;
Note:
See TracChangeset
for help on using the changeset viewer.
