Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
atomic_usage.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2017-2017 ARM Limited 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a copy 00005 * of this software and associated documentation files (the "Software"), to deal 00006 * in the Software without restriction, including without limitation the rights 00007 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00008 * copies of the Software, and to permit persons to whom the Software is 00009 * furnished to do so, subject to the following conditions: 00010 * 00011 * The above copyright notice and this permission notice shall be included in 00012 * all copies or substantial portions of the Software. 00013 * 00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00019 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00020 * SOFTWARE. 00021 */ 00022 00023 00024 /** 00025 * This file contains code which performs various atomic operations using 00026 * littlefs. It is intended for use in tests and test applications to 00027 * validate that the defined behavior below is being met. 00028 * 00029 * # Defined behavior 00030 * - A file rename is atomic (Note - rename can be used to replace a file) 00031 * - Atomic file rename tested by setup/perform/check_file_rename 00032 * - Atomic file replace tested by setup/perform/check_file_rename_replace 00033 * - A directory rename is atomic (Note - rename can be used to replace an empty directory) 00034 * - Tested by setup/perform/check_directory_rename 00035 * - Directory create is atomic 00036 * - Directory delete is atomic 00037 * - File create is atomic 00038 * - File delete is atomic 00039 * - File contents are atomically written on close 00040 * - Tested by setup/perform/check_file_change_contents 00041 */ 00042 00043 00044 #include "mbed.h" 00045 #include "greentea-client/test_env.h" 00046 #include "unity.h" 00047 #include "utest.h" 00048 #include <stdlib.h> 00049 #include <errno.h> 00050 00051 #include "ObservingBlockDevice.h" 00052 #include "ExhaustibleBlockDevice.h" 00053 #include "FileSystem.h" 00054 00055 #include "atomic_usage.h" 00056 00057 // test configuration 00058 #ifndef MBED_TEST_FILESYSTEM 00059 #define MBED_TEST_FILESYSTEM LittleFileSystem 00060 #endif 00061 00062 #ifndef MBED_TEST_FILESYSTEM_DECL 00063 #define MBED_TEST_FILESYSTEM_DECL MBED_TEST_FILESYSTEM fs("fs") 00064 #endif 00065 00066 00067 // declarations 00068 #define STRINGIZE(x) STRINGIZE2(x) 00069 #define STRINGIZE2(x) #x 00070 #define INCLUDE(x) STRINGIZE(x.h) 00071 00072 #include INCLUDE(MBED_TEST_FILESYSTEM) 00073 00074 00075 #define DEBUG(...) 00076 #define DEBUG_CHECK(...) 00077 #define BUFFER_SIZE 64 00078 // Version is written to a file and is used 00079 // to determine if a reformat is required 00080 #define ATOMIC_USAGE_VERSION 1 00081 00082 #define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0])) 00083 00084 #define TEST_ASSERT_OR_EXIT(condition) \ 00085 TEST_ASSERT(condition); if (!(condition)) {error("Assert failed");} 00086 00087 #define TEST_ASSERT_EQUAL_OR_EXIT(expected, actual) \ 00088 TEST_ASSERT_EQUAL(expected, actual); if ((int64_t)(expected) != (int64_t)(actual)) {error("Assert failed");} 00089 00090 using namespace utest::v1; 00091 00092 typedef void (*test_function_t)(FileSystem *fs); 00093 typedef bool (*test_function_bool_t)(FileSystem *fs); 00094 00095 struct TestEntry { 00096 const char *name; 00097 test_function_t setup; 00098 test_function_bool_t perform; 00099 test_function_t check; 00100 }; 00101 00102 /** 00103 * Write data to the file while checking for error conditions 00104 * 00105 * @param file File to write to 00106 * @param data Data to write 00107 * @param size Size of data to write 00108 * @return true if flash has been exhausted, false otherwise 00109 */ 00110 static bool file_write(File *file, uint8_t *data, uint32_t size) 00111 { 00112 int res = file->write(data, size); 00113 if (-ENOSPC == res) { 00114 return true; 00115 } 00116 TEST_ASSERT_EQUAL_OR_EXIT(size, res); 00117 return false; 00118 } 00119 00120 /** 00121 * Write padding data of the given size 00122 * 00123 * @param file Pointer to the file to write to 00124 * @param padding Value to pad 00125 * @param size Size to pad 00126 * @return true if flash has been exhausted, false otherwise 00127 */ 00128 static bool file_pad(File *file, char padding, uint32_t size) 00129 { 00130 uint8_t buf[BUFFER_SIZE]; 00131 memset(buf, padding, sizeof(buf)); 00132 00133 while (size > 0) { 00134 uint32_t write_size = sizeof(buf) <= size ? sizeof(buf) : size; 00135 if (file_write(file, buf, write_size)) { 00136 return true; 00137 } 00138 size -= write_size; 00139 } 00140 00141 return false; 00142 } 00143 00144 /* 00145 * Similar to fscanf but uses and mbed file 00146 * 00147 * @param file File to scan from 00148 * @param format Format string of values to read 00149 * @return the number of arguments read 00150 */ 00151 static int file_scanf(File *file, const char *format, ...) 00152 { 00153 uint8_t buf[BUFFER_SIZE]; 00154 va_list args; 00155 memset(buf, 0, sizeof(buf)); 00156 00157 int res = file->read(buf, sizeof(buf) - 1); 00158 TEST_ASSERT_OR_EXIT(res >= 0); 00159 00160 va_start (args, format); 00161 int count = vsscanf((char*)buf, format, args); 00162 va_end (args); 00163 TEST_ASSERT_OR_EXIT(count >= 0); 00164 00165 return count; 00166 } 00167 00168 /* 00169 * Similar to fprintf but uses and mbed file 00170 * 00171 * @param file File to print to 00172 * @param format Format string of values to write 00173 * @return size written to file or -1 on out of space 00174 */ 00175 static int file_printf(File *file, const char *format, ...) 00176 { 00177 uint8_t buf[BUFFER_SIZE]; 00178 va_list args; 00179 va_start (args, format); 00180 int size = vsprintf((char*)buf, format, args); 00181 va_end (args); 00182 TEST_ASSERT_OR_EXIT((size >= 0) && (size <= (int)sizeof(buf))); 00183 00184 if (file_write(file, buf, size)) { 00185 return -1; 00186 } 00187 00188 return size; 00189 } 00190 00191 00192 static const char FILE_RENAME_A[] = "file_to_rename_a.txt"; 00193 static const char FILE_RENAME_B[] = "file_to_rename_b.txt"; 00194 static const char FILE_RENAME_CONTENTS[] = "Test contents for the file to be renamed"; 00195 static const int FILE_RENAME_LEN = strlen(FILE_RENAME_CONTENTS); 00196 00197 /** 00198 * Setup for the file rename test 00199 * 00200 * Create file FILE_RENAME_A with contents FILE_RENAME_CONTENTS. 00201 */ 00202 static void setup_file_rename(FileSystem *fs) 00203 { 00204 DEBUG("setup_file_rename()\n"); 00205 00206 File file; 00207 00208 int res = file.open(fs, FILE_RENAME_A, O_WRONLY | O_CREAT); 00209 DEBUG(" open result %i\n", res); 00210 TEST_ASSERT_EQUAL_OR_EXIT(0, res); 00211 00212 res = file.write(FILE_RENAME_CONTENTS, FILE_RENAME_LEN); 00213 DEBUG(" write result %i\n", res); 00214 TEST_ASSERT_EQUAL_OR_EXIT(FILE_RENAME_LEN, res); 00215 } 00216 00217 /** 00218 * Change the file name to either FILE_RENAME_A or FILE_RENAME_B 00219 */ 00220 static bool perform_file_rename(FileSystem *fs) 00221 { 00222 DEBUG("perform_file_rename()\n"); 00223 00224 struct stat st; 00225 int res = fs->stat(FILE_RENAME_A, &st); 00226 const char *src = (res == 0) ? FILE_RENAME_A : FILE_RENAME_B; 00227 const char *dst = (res == 0) ? FILE_RENAME_B : FILE_RENAME_A; 00228 00229 DEBUG(" stat result %i\n", res); 00230 TEST_ASSERT_OR_EXIT((res == -ENOENT) || (res == 0)); 00231 00232 DEBUG(" Renaming %s to %s\n", src, dst); 00233 res = fs->rename(src, dst); 00234 if (-ENOSPC == res) { 00235 return true; 00236 } 00237 TEST_ASSERT_EQUAL_OR_EXIT(0, res); 00238 return false; 00239 } 00240 00241 /** 00242 * Check that the file rename is in a good state 00243 * 00244 * Check that there is only one file and that file contains the correct 00245 * contents. 00246 * 00247 * Allowed states: 00248 * - File FILE_RENAME_A exists with contents and FILE_RENAME_B does not 00249 * - File FILE_RENAME_B exists with contents and FILE_RENAME_A does not 00250 * 00251 */ 00252 static void check_file_rename(FileSystem *fs) 00253 { 00254 00255 int files = 0; 00256 int valids = 0; 00257 const char * const filenames[] = {FILE_RENAME_A, FILE_RENAME_B}; 00258 00259 for (int i = 0; i < 2; i++) { 00260 File file; 00261 if (file.open(fs, filenames[i], O_RDONLY) == 0) { 00262 uint8_t buf[BUFFER_SIZE]; 00263 files++; 00264 memset(buf, 0, sizeof(buf)); 00265 int res = file.read(buf, FILE_RENAME_LEN); 00266 if (res != FILE_RENAME_LEN) { 00267 break; 00268 } 00269 if (memcmp(buf, FILE_RENAME_CONTENTS, FILE_RENAME_LEN) != 0) { 00270 break; 00271 } 00272 valids++; 00273 } 00274 } 00275 00276 TEST_ASSERT_EQUAL_OR_EXIT(1, files); 00277 TEST_ASSERT_EQUAL_OR_EXIT(1, valids); 00278 } 00279 00280 00281 static const char FILE_RENAME_REPLACE[] = "rename_replace_file.txt"; 00282 static const char FILE_RENAME_REPLACE_NEW[] = "new_rename_replace_file.txt"; 00283 static const char FILE_RENAME_REPLACE_FMT[] = "file replace count: %lu\n"; 00284 00285 /** 00286 * Create the file FILE_RENAME_REPLACE with initial contents 00287 * 00288 * Create an write an initial count of 0 to the file. 00289 */ 00290 static void setup_file_rename_replace(FileSystem *fs) 00291 { 00292 DEBUG("setup_file_rename_replace()\n"); 00293 File file; 00294 00295 // Write out initial count 00296 00297 int res = file.open(fs, FILE_RENAME_REPLACE, O_WRONLY | O_CREAT); 00298 TEST_ASSERT_EQUAL_OR_EXIT(0, res); 00299 00300 uint32_t count = 0; 00301 uint8_t buf[BUFFER_SIZE]; 00302 memset(buf, 0, sizeof(buf)); 00303 const int length = sprintf((char*)buf, FILE_RENAME_REPLACE_FMT, count); 00304 TEST_ASSERT_OR_EXIT(length > 0); 00305 00306 res = file.write(buf, length); 00307 DEBUG(" write result %i\n", res); 00308 TEST_ASSERT_EQUAL_OR_EXIT(length, res); 00309 } 00310 00311 /** 00312 * Atomically increment the count in FILE_RENAME_REPLACE using a rename 00313 */ 00314 bool perform_file_rename_replace(FileSystem *fs) 00315 { 00316 DEBUG("perform_file_rename_replace()\n"); 00317 File file; 00318 00319 // Read in previous count 00320 00321 int res = file.open(fs, FILE_RENAME_REPLACE, O_RDONLY); 00322 TEST_ASSERT_EQUAL_OR_EXIT(0, res); 00323 00324 uint64_t count; 00325 int args_read = file_scanf(&file, FILE_RENAME_REPLACE_FMT, &count); 00326 TEST_ASSERT_EQUAL_OR_EXIT(1, args_read); 00327 00328 res = file.close(); 00329 if (-ENOSPC == res) { 00330 return true; 00331 } 00332 TEST_ASSERT_EQUAL(0, res); 00333 00334 // Write out new count 00335 00336 count++; 00337 00338 res = file.open(fs, FILE_RENAME_REPLACE_NEW, O_WRONLY | O_CREAT); 00339 if (-ENOSPC == res) { 00340 return true; 00341 } 00342 TEST_ASSERT_EQUAL_OR_EXIT(0, res); 00343 00344 if (file_printf(&file, FILE_RENAME_REPLACE_FMT, count) <= 0) { 00345 return true; 00346 } 00347 00348 res = file.close(); 00349 if (-ENOSPC == res) { 00350 return true; 00351 } 00352 TEST_ASSERT_EQUAL(0, res); 00353 00354 // Rename file 00355 00356 res = fs->rename(FILE_RENAME_REPLACE_NEW, FILE_RENAME_REPLACE); 00357 if (-ENOSPC == res) { 00358 return true; 00359 } 00360 TEST_ASSERT_EQUAL_OR_EXIT(0, res); 00361 DEBUG(" count %llu -> %llu\n", count - 1, count); 00362 00363 return false; 00364 } 00365 00366 /** 00367 * Check that FILE_RENAME_REPLACE always has a valid count 00368 * 00369 * Allowed states: 00370 * - FILE_RENAME_REPLACE exists with valid contents 00371 */ 00372 static void check_file_rename_replace(FileSystem *fs) 00373 { 00374 DEBUG_CHECK("check_file_rename_replace()\n"); 00375 File file; 00376 00377 // Read in previous count 00378 00379 int res = file.open(fs, FILE_RENAME_REPLACE, O_RDONLY); 00380 TEST_ASSERT_EQUAL_OR_EXIT(0, res); 00381 00382 uint64_t count; 00383 int args_read = file_scanf(&file, FILE_RENAME_REPLACE_FMT, &count); 00384 TEST_ASSERT_EQUAL_OR_EXIT(1, args_read); 00385 DEBUG_CHECK(" count %llu\n", count); 00386 } 00387 00388 00389 static const char DIRECTORY_RENAME_A[] = "dir_a"; 00390 static const char DIRECTORY_RENAME_B[] = "dir_b"; 00391 00392 /** 00393 * Create DIRECTORY_RENAME_A with initial contents 00394 */ 00395 static void setup_directory_rename(FileSystem *fs) 00396 { 00397 DEBUG("setup_directory_rename()\n"); 00398 00399 int res = fs->mkdir(DIRECTORY_RENAME_A, 0777); 00400 TEST_ASSERT_EQUAL_OR_EXIT(0, res); 00401 } 00402 00403 /* 00404 * Change the directory name from either DIRECTORY_RENAME_A or DIRECTORY_RENAME_B to the other 00405 */ 00406 static bool perform_directory_rename(FileSystem *fs) 00407 { 00408 DEBUG("perform_directory_rename()\n"); 00409 00410 struct stat st; 00411 int res = fs->stat(DIRECTORY_RENAME_A, &st); 00412 const char *src = (res == 0) ? DIRECTORY_RENAME_A : DIRECTORY_RENAME_B; 00413 const char *dst = (res == 0) ? DIRECTORY_RENAME_B : DIRECTORY_RENAME_A; 00414 00415 DEBUG(" stat result %i\n", res); 00416 TEST_ASSERT_OR_EXIT((res == -ENOENT) || (res == 0)); 00417 00418 DEBUG(" Renaming %s to %s\n", src, dst); 00419 res = fs->rename(src, dst); 00420 if (-ENOSPC == res) { 00421 return true; 00422 } 00423 TEST_ASSERT_EQUAL_OR_EXIT(0, res); 00424 return false; 00425 } 00426 00427 /* 00428 * Change the directory name from either DIRECTORY_RENAME_A or DIRECTORY_RENAME_B to the other 00429 * 00430 * Allowed states: 00431 * - DIRECTORY_RENAME_A exists with valid contents and DIRECTORY_RENAME_B does not exist 00432 * - DIRECTORY_RENAME_B exists with valid contents and DIRECTORY_RENAME_A does not exist 00433 */ 00434 static void check_directory_rename(FileSystem *fs) 00435 { 00436 DEBUG_CHECK("check_directory_rename()\n"); 00437 00438 static const char *directory_names[] = { 00439 DIRECTORY_RENAME_A, 00440 DIRECTORY_RENAME_B 00441 }; 00442 00443 size_t directories = 0; 00444 for (size_t i = 0; i < ARRAY_LENGTH(directory_names); i++) { 00445 Dir dir; 00446 int res = dir.open(fs, directory_names[i]); 00447 TEST_ASSERT_OR_EXIT((res == -ENOENT) || (res == 0)); 00448 if (res == 0) { 00449 directories++; 00450 } 00451 } 00452 TEST_ASSERT_EQUAL_OR_EXIT(1, directories); 00453 } 00454 00455 00456 static const char CHANGE_CONTENTS_NAME[] = "file_changing_contents.txt"; 00457 static const char CHANGE_CONTENTS_FILL = ' '; 00458 static const uint32_t BLOCK_SIZE = 512; 00459 00460 /** 00461 * Create file CHANGE_CONTENTS_NAME with initial contents 00462 * 00463 * File contains three blocks of data each which start 00464 * with a count. 00465 */ 00466 static void setup_file_change_contents(FileSystem *fs) 00467 { 00468 DEBUG("setup_file_change_contents()\n"); 00469 00470 File file; 00471 int res = file.open(fs, CHANGE_CONTENTS_NAME, O_WRONLY | O_CREAT); 00472 TEST_ASSERT_EQUAL_OR_EXIT(0, res); 00473 00474 for (int count = 1; count <= 3; count++) { 00475 int size = file_printf(&file, "%lu\n", count); 00476 TEST_ASSERT_OR_EXIT(size >= 0); 00477 00478 bool dead = file_pad(&file, CHANGE_CONTENTS_FILL, BLOCK_SIZE - size); 00479 TEST_ASSERT_EQUAL_OR_EXIT(false, dead); 00480 } 00481 } 00482 00483 /** 00484 * Atomically increment the counts in the file CHANGE_CONTENTS_NAME 00485 * 00486 * Read in the current counts, increment them and then write them 00487 * back in non-sequential order. 00488 */ 00489 static bool perform_file_change_contents(FileSystem *fs) 00490 { 00491 DEBUG("perform_file_change_contents()\n"); 00492 File file; 00493 00494 int res = file.open(fs, CHANGE_CONTENTS_NAME, O_RDWR); 00495 TEST_ASSERT_EQUAL_OR_EXIT(0, res); 00496 00497 // Read in values 00498 uint32_t values[3]; 00499 for (int i = 0; i < 3; i++) { 00500 file.seek(i * BLOCK_SIZE); 00501 int args_read = file_scanf(&file, "%lu\n", &values[i]); 00502 TEST_ASSERT_EQUAL_OR_EXIT(1, args_read); 00503 } 00504 00505 // Increment values 00506 for (int i = 0; i < 3; i++) { 00507 values[i]++; 00508 } 00509 00510 // Write values out of order 00511 int i; 00512 i = 0; 00513 file.seek(i * BLOCK_SIZE); 00514 if (file_printf(&file, "%lu\n", values[i]) <= 0) { 00515 return true; 00516 } 00517 DEBUG(" value[%i]: %lu -> %lu\n", i, values[i] - 1, values[i]); 00518 00519 i = 2; 00520 file.seek(i * BLOCK_SIZE); 00521 if (file_printf(&file, "%lu\n", values[i]) <= 0) { 00522 return true; 00523 } 00524 DEBUG(" value[%i]: %lu -> %lu\n", i, values[i] - 1, values[i]); 00525 00526 i = 1; 00527 file.seek(i * BLOCK_SIZE); 00528 if (file_printf(&file, "%lu\n", values[i]) <= 0) { 00529 return true; 00530 } 00531 DEBUG(" value[%i]: %lu -> %lu\n", i, values[i] - 1, values[i]); 00532 00533 res = file.close(); 00534 if (-ENOSPC == res) { 00535 return true; 00536 } 00537 TEST_ASSERT_EQUAL(0, res); 00538 00539 return false; 00540 } 00541 00542 /* 00543 * Change the directory name from either DIRECTORY_RENAME_A or DIRECTORY_RENAME_B to the other 00544 * 00545 * Allowed states: 00546 * - CHANGE_CONTENTS_NAME exists and contains 3 counts which are in order 00547 */ 00548 static void check_file_change_contents(FileSystem *fs) 00549 { 00550 DEBUG_CHECK("check_file_change_contents()\n"); 00551 File file; 00552 00553 int res = file.open(fs, CHANGE_CONTENTS_NAME, O_RDONLY); 00554 TEST_ASSERT_EQUAL_OR_EXIT(0, res); 00555 00556 // Read in values 00557 uint32_t values[3]; 00558 for (int i = 0; i < 3; i++) { 00559 file.seek(i * BLOCK_SIZE); 00560 int args_read = file_scanf(&file, "%lu\n", &values[i]); 00561 TEST_ASSERT_EQUAL_OR_EXIT(1, args_read); 00562 DEBUG_CHECK(" value[%i]: %lu\n", i, values[i]); 00563 } 00564 00565 TEST_ASSERT_EQUAL_OR_EXIT(values[0] + 1, values[1]); 00566 TEST_ASSERT_EQUAL_OR_EXIT(values[1] + 1, values[2]); 00567 } 00568 00569 00570 static const TestEntry atomic_test_entries[] = { 00571 {"File rename", setup_file_rename, perform_file_rename, check_file_rename}, 00572 {"File rename replace", setup_file_rename_replace, perform_file_rename_replace, check_file_rename_replace}, 00573 {"Directory rename", setup_directory_rename, perform_directory_rename, check_directory_rename}, 00574 {"File change contents", setup_file_change_contents, perform_file_change_contents, check_file_change_contents}, 00575 }; 00576 00577 static const char FILE_SETUP_COMPLETE[] = "setup_complete.txt"; 00578 static const char FILE_SETUP_COMPLETE_FMT[] = "Test version: %lu\n"; 00579 00580 static bool format_required(BlockDevice *bd) 00581 { 00582 MBED_TEST_FILESYSTEM_DECL; 00583 00584 if (fs.mount(bd) != 0) { 00585 return true; 00586 } 00587 00588 // Check if setup complete file exists 00589 File file; 00590 int res = file.open(&fs, FILE_SETUP_COMPLETE, O_RDONLY); 00591 if (res != 0) { 00592 return true; 00593 } 00594 00595 // Read contents of setup complete file 00596 uint8_t buf[BUFFER_SIZE]; 00597 memset(buf, 0, sizeof(buf)); 00598 int size_read = file.read(buf, sizeof(buf) - 1); 00599 if (size_read <= 0) { 00600 return true; 00601 } 00602 00603 // Get the test version 00604 uint32_t version = 0; 00605 res = sscanf((char*)buf, FILE_SETUP_COMPLETE_FMT, &version); 00606 if (res != 1) { 00607 return true; 00608 } 00609 00610 if (ATOMIC_USAGE_VERSION != version) { 00611 return true; 00612 } 00613 00614 // Setup file exists and is the correct version 00615 return false; 00616 } 00617 00618 static void format(BlockDevice *bd) 00619 { 00620 MBED_TEST_FILESYSTEM_DECL; 00621 00622 int res = fs.format(bd); 00623 TEST_ASSERT_EQUAL_OR_EXIT(0, res); 00624 00625 res = fs.mount(bd); 00626 TEST_ASSERT_EQUAL_OR_EXIT(0, res); 00627 00628 for (size_t i = 0; i < ARRAY_LENGTH(atomic_test_entries); i++) { 00629 atomic_test_entries[i].setup(&fs); 00630 } 00631 00632 File file; 00633 res = file.open(&fs, FILE_SETUP_COMPLETE, O_CREAT | O_WRONLY); 00634 TEST_ASSERT_EQUAL_OR_EXIT(0, res); 00635 00636 int size = file_printf(&file, FILE_SETUP_COMPLETE_FMT, (uint32_t)ATOMIC_USAGE_VERSION); 00637 TEST_ASSERT_OR_EXIT(size >= 0); 00638 } 00639 00640 static int64_t get_cycle_count(FileSystem *fs) 00641 { 00642 File file; 00643 00644 int res = file.open(fs, FILE_RENAME_REPLACE, O_RDONLY); 00645 TEST_ASSERT_EQUAL_OR_EXIT(0, res); 00646 00647 uint64_t count = 0; 00648 int args_read = file_scanf(&file, FILE_RENAME_REPLACE_FMT, &count); 00649 TEST_ASSERT_EQUAL_OR_EXIT(1, args_read); 00650 00651 file.close(); 00652 00653 return (int64_t)count; 00654 } 00655 00656 bool setup_atomic_operations(BlockDevice *bd, bool force_rebuild) 00657 { 00658 if (force_rebuild || format_required(bd)) { 00659 format(bd); 00660 TEST_ASSERT_EQUAL_OR_EXIT(false, format_required(bd)); 00661 return true; 00662 } 00663 return false; 00664 } 00665 00666 int64_t perform_atomic_operations(BlockDevice *bd) 00667 { 00668 MBED_TEST_FILESYSTEM_DECL; 00669 bool out_of_space = false; 00670 00671 fs.mount(bd); 00672 00673 for (size_t i = 0; i < ARRAY_LENGTH(atomic_test_entries); i++) { 00674 out_of_space |= atomic_test_entries[i].perform(&fs); 00675 } 00676 00677 int64_t cycle_count = get_cycle_count(&fs); 00678 00679 fs.unmount(); 00680 00681 if (out_of_space) { 00682 return -1; 00683 } else { 00684 return cycle_count; 00685 } 00686 } 00687 00688 void check_atomic_operations(BlockDevice *bd) 00689 { 00690 MBED_TEST_FILESYSTEM_DECL; 00691 fs.mount(bd); 00692 00693 for (size_t i = 0; i < ARRAY_LENGTH(atomic_test_entries); i++) { 00694 atomic_test_entries[i].check(&fs); 00695 } 00696 00697 fs.unmount(); 00698 }
Generated on Tue Jul 12 2022 14:23:23 by
