/* WebDAV locking stress test Copyright (C) 2024, Red Hat, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #define _GNU_SOURCE 1 #include #include #include #include #include #include #include #include #include #include #include #include #define ITERS 20000 #ifndef THREADS #define THREADS (20) #endif struct thrarg { pthread_t thd; ne_uri uri; }; static void *threadfn(void *varg) { struct thrarg *arg = varg; ne_session *sess; unsigned int iter; int fd = open("/dev/zero", O_RDONLY); if (fd < 0) return "open(/dev/zero) failed"; sess = ne_session_create(arg->uri.scheme, arg->uri.host, arg->uri.port); if (ne_put(sess, arg->uri.path, fd) != NE_OK) return ne_concat("PUT: ", ne_get_error(sess), NULL); close(fd); for (iter = 0; iter < ITERS; iter++) { struct ne_lock *lock = ne_lock_create(); int ret; memcpy(&lock->uri, &arg->uri, sizeof lock->uri); ret = ne_lock(sess, lock); if (ret != NE_OK) { return ne_concat("LOCK failure: ", ne_get_error(sess), NULL); } ret = ne_unlock(sess, lock); if (ret != NE_OK) { return ne_concat("UNLOCK failure: ", ne_get_error(sess), NULL); } memset(&lock->uri, 0, sizeof lock->uri); ne_lock_destroy(lock); } ne_session_destroy(sess); return NULL; } int main(int argc, char **argv) { struct thrarg args[THREADS]; int ec = 0; ne_uri uri; #if THREADS > 1 unsigned n; int ret; #endif ne_sock_init(); if (argc < 2) { fprintf(stderr, "%s: needs URL.\n", argv[0]); exit(EXIT_FAILURE); } if (ne_uri_parse(argv[1], &uri)) { fprintf(stderr, "%s: Could not parse URL '%s'.\n", argv[0], argv[1]); exit(EXIT_FAILURE); } if (!uri.port) { uri.port = ne_uri_defaultport(uri.scheme); } #if THREADS == 1 fprintf(stderr, "%s: running single-threaded...\n", argv[0]); { const char *retval; args[0].uri = uri; args[0].uri.path = ne_concat(uri.path, "-single", NULL); retval = threadfn(&args[0]); printf("%s\n", retval ? retval : "PASS"); if (retval) ec = EXIT_FAILURE; } #else for (n = 0; n < THREADS; n++) { char *path = ne_malloc(256); ne_snprintf(path, 256, "%s-lock-%04u", uri.path, n); memcpy(&args[n].uri, &uri, sizeof uri); args[n].uri.path = path; ret = pthread_create(&args[n].thd, NULL, threadfn, &args[n]); if (ret) { perror("pthread_create"); exit(1); } } fprintf(stderr, "%s: spawned %u threads, now waiting...\n", argv[0], (unsigned int)THREADS); for (n = 0; n < THREADS; n++) { const char *retval; ret = pthread_join(args[n].thd, (void **)&retval); if (ret) { perror("pthread_create"); exit(1); } printf("%u: %s\n", n, retval ? retval : "PASS"); if (retval) ec = EXIT_FAILURE; } #endif return ec; }